• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2009 Erwan Velu - All Rights Reserved
4  *
5  *   Permission is hereby granted, free of charge, to any person
6  *   obtaining a copy of this software and associated documentation
7  *   files (the "Software"), to deal in the Software without
8  *   restriction, including without limitation the rights to use,
9  *   copy, modify, merge, publish, distribute, sublicense, and/or
10  *   sell copies of the Software, and to permit persons to whom
11  *   the Software is furnished to do so, subject to the following
12  *   conditions:
13  *
14  *   The above copyright notice and this permission notice shall
15  *   be included in all copies or substantial portions of the Software.
16  *
17  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21  *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22  *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24  *   OTHER DEALINGS IN THE SOFTWARE.
25  *
26  * -----------------------------------------------------------------------
27 */
28 
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <getkey.h>
33 #include "syslinux/config.h"
34 #include "../lib/sys/vesa/vesa.h"
35 #include "hdt-common.h"
36 #include <disk/util.h>
37 #include <disk/mbrs.h>
38 #include <memory.h>
39 
40 /* ISOlinux requires a 8.3 format */
convert_isolinux_filename(char * filename,struct s_hardware * hardware)41 void convert_isolinux_filename(char *filename, struct s_hardware *hardware)
42 {
43     /* Exit if we are not running ISOLINUX */
44     if (hardware->sv->filesystem != SYSLINUX_FS_ISOLINUX)
45 	return;
46     /* Searching the dot */
47     char *dot = strchr(filename, '.');
48     /* Exiting if no dot exists in that string */
49     if (dot == NULL)
50 	return;
51     /* Exiting if the extension is 3 char or less */
52     if (strlen(dot) <= 4)
53 	return;
54 
55     /* We have an extension bigger than .blah
56      * so we have to shorten it to 3*/
57     dot[4] = '\0';
58 }
59 
detect_parameters(const int argc,const char * argv[],struct s_hardware * hardware)60 void detect_parameters(const int argc, const char *argv[],
61 		       struct s_hardware *hardware)
62 {
63     /* Quiet mode - make the output more quiet */
64     quiet = true;
65 
66     /* Silent mode - make not output at all */
67     silent = false;
68 
69     /* Vesa mode isn't set until we explictly call it */
70     vesamode = false;
71 
72     /* Automode isn't the default*/
73     automode = false;
74 
75     /* Menu mode is the default*/
76     menumode = true;
77 
78     for (int i = 1; i < argc; i++) {
79 	if (!strncmp(argv[i], "quiet", 5)) {
80 	    quiet = true;
81 	} else if (!strncmp(argv[i], "silent", 6)) {
82 	    silent = true;
83 	} else	if (!strncmp(argv[i], "verbose", 7)) {
84 	    quiet = false;
85 	} else if (!strncmp(argv[i], "modules_pcimap=", 15)) {
86 	    strlcpy(hardware->modules_pcimap_path, argv[i] + 15,
87 		    sizeof(hardware->modules_pcimap_path));
88 	    convert_isolinux_filename(hardware->modules_pcimap_path, hardware);
89 	} else if (!strncmp(argv[i], "pciids=", 7)) {
90 	    strlcpy(hardware->pciids_path, argv[i] + 7,
91 		    sizeof(hardware->pciids_path));
92 	    convert_isolinux_filename(hardware->pciids_path, hardware);
93 	} else if (!strncmp(argv[i], "modules_alias=", 14)) {
94 	    strlcpy(hardware->modules_alias_path, argv[i] + 14,
95 		    sizeof(hardware->modules_alias_path));
96 	    convert_isolinux_filename(hardware->modules_alias_path, hardware);
97 	} else if (!strncmp(argv[i], "memtest=", 8)) {
98 	    strlcpy(hardware->memtest_label, argv[i] + 8,
99 		    sizeof(hardware->memtest_label));
100 	    convert_isolinux_filename(hardware->memtest_label, hardware);
101 	} else if (!strncmp(argv[i], "vesa", 4)) {
102 	    vesamode = true;
103 	    max_console_lines = MAX_VESA_CLI_LINES;
104 	    /* If the user defines a background image */
105 	    if (!strncmp(argv[i], "vesa=", 5)) {
106 		strlcpy(hardware->vesa_background, argv[i] + 5,
107 			sizeof(hardware->vesa_background));
108 	    }
109 	} else if (!strncmp(argv[i], "novesa", 6)) {
110 	    vesamode = false;
111 	    max_console_lines = MAX_CLI_LINES;
112 	} else if (!strncmp(argv[i], "nomenu", 6)) {
113 	    menumode = false;
114 	} else if (!strncmp(argv[i], "dump_filename=", 14)) {
115 	    strlcpy(hardware->dump_filename, argv[i] + 14,
116 		    sizeof(hardware->dump_filename));
117 	} else if (!strncmp(argv[i], "dump_path=", 10)) {
118 	    strlcpy(hardware->dump_path, argv[i] + 10,
119 		    sizeof(hardware->dump_path));
120 	} else if (!strncmp(argv[i], "tftp_ip=", 8)) {
121 	    strlcpy(hardware->tftp_ip, argv[i] + 8,
122 		    sizeof(hardware->tftp_ip));
123 	} else if (!strncmp(argv[i], "postexec=", 9)) {
124 	    /* The postexec= parameter is separated in several argv[]
125 	     * as it can contains spaces.
126 	     * We use the AUTO_DELIMITER char to define the limits
127 	     * of this parameter.
128 	     * i.e postexec='linux memtest.bin'
129 	     */
130 
131 	    char *argument = (char*)argv[i]+10;
132 	    /* Extracting the first parameter */
133 	    strcpy(hardware->postexec, argument);
134 
135 	    /* While we can't find the other AUTO_DELIMITER, let's process the argv[] */
136 	    while ((strchr(argument, AUTO_DELIMITER) == NULL) && (i+1<argc)) {
137 		i++;
138 	    	argument = (char *)argv[i];
139 		strcat(hardware->postexec, " ");
140 		strcat(hardware->postexec, argument);
141 	    }
142 
143 	     hardware->postexec[strlen(hardware->postexec) - 1] = 0;
144 	} else if (!strncmp(argv[i], "auto=", 5)) {
145 	    /* The auto= parameter is separated in several argv[]
146 	     * as it can contains spaces.
147 	     * We use the AUTO_DELIMITER char to define the limits
148 	     * of this parameter.
149 	     * i.e auto='show dmi; show pci'
150 	     */
151 
152 	    automode=true;
153 	    char *argument = (char*)argv[i]+6;
154 	    /* Extracting the first parameter */
155 	    strcpy(hardware->auto_label, argument);
156 
157 	    /* While we can't find the other AUTO_DELIMITER, let's process the argv[] */
158 	    while ((strchr(argument, AUTO_DELIMITER) == NULL) && (i+1<argc)) {
159 		i++;
160 	    	argument = (char *)argv[i];
161 		strcat(hardware->auto_label, " ");
162 		strcat(hardware->auto_label, argument);
163 	    }
164 
165 	     hardware->auto_label[strlen(hardware->auto_label) - 1] = 0;
166 	}
167     }
168 }
169 
detect_syslinux(struct s_hardware * hardware)170 void detect_syslinux(struct s_hardware *hardware)
171 {
172     hardware->sv = syslinux_version();
173     switch (hardware->sv->filesystem) {
174     case SYSLINUX_FS_SYSLINUX:
175 	strlcpy(hardware->syslinux_fs, "SYSlinux", 9);
176 	break;
177     case SYSLINUX_FS_PXELINUX:
178 	strlcpy(hardware->syslinux_fs, "PXElinux", 9);
179 	break;
180     case SYSLINUX_FS_ISOLINUX:
181 	strlcpy(hardware->syslinux_fs, "ISOlinux", 9);
182 	break;
183     case SYSLINUX_FS_EXTLINUX:
184 	strlcpy(hardware->syslinux_fs, "EXTlinux", 9);
185 	break;
186     case SYSLINUX_FS_UNKNOWN:
187     default:
188 	strlcpy(hardware->syslinux_fs, "Unknown Bootloader",
189 		sizeof hardware->syslinux_fs);
190 	break;
191     }
192 }
193 
init_hardware(struct s_hardware * hardware)194 void init_hardware(struct s_hardware *hardware)
195 {
196     hardware->pci_ids_return_code = 0;
197     hardware->modules_pcimap_return_code = 0;
198     hardware->modules_alias_return_code = 0;
199     hardware->cpu_detection = false;
200     hardware->pci_detection = false;
201     hardware->disk_detection = false;
202     hardware->disks_count = 0;
203     hardware->dmi_detection = false;
204     hardware->pxe_detection = false;
205     hardware->vesa_detection = false;
206     hardware->vpd_detection = false;
207     hardware->memory_detection = false;
208     hardware->acpi_detection = false;
209     hardware->nb_pci_devices = 0;
210     hardware->is_dmi_valid = false;
211     hardware->is_pxe_valid = false;
212     hardware->is_vpd_valid = false;
213     hardware->is_acpi_valid = false;
214     hardware->pci_domain = NULL;
215     hardware->detected_memory_size = 0;
216     hardware->physical_cpu_count =1; /* we have at least one cpu */
217 
218     /* Cleaning structures */
219     memset(hardware->disk_info, 0, sizeof(hardware->disk_info));
220     memset(hardware->mbr_ids, 0, sizeof(hardware->mbr_ids));
221     memset(&hardware->dmi, 0, sizeof(s_dmi));
222     memset(&hardware->cpu, 0, sizeof(s_cpu));
223     memset(&hardware->pxe, 0, sizeof(struct s_pxe));
224     memset(&hardware->vesa, 0, sizeof(struct s_vesa));
225     memset(&hardware->vpd, 0, sizeof(s_vpd));
226     memset(&hardware->acpi, 0, sizeof(s_acpi));
227     memset(hardware->syslinux_fs, 0, sizeof hardware->syslinux_fs);
228     memset(hardware->pciids_path, 0, sizeof hardware->pciids_path);
229     memset(hardware->modules_pcimap_path, 0,
230 	   sizeof hardware->modules_pcimap_path);
231     memset(hardware->modules_alias_path, 0,
232 	   sizeof hardware->modules_alias_path);
233     memset(hardware->memtest_label, 0, sizeof hardware->memtest_label);
234     memset(hardware->auto_label, 0, sizeof hardware->auto_label);
235     memset(hardware->dump_path, 0, sizeof hardware->dump_path);
236     memset(hardware->dump_filename, 0, sizeof hardware->dump_filename);
237     memset(hardware->vesa_background, 0, sizeof hardware->vesa_background);
238     memset(hardware->tftp_ip, 0, sizeof hardware->tftp_ip);
239     memset(hardware->postexec, 0, sizeof hardware->postexec);
240     strcat(hardware->dump_path, "hdt");
241     strcat(hardware->dump_filename, "%{m}+%{p}+%{v}");
242     strcat(hardware->pciids_path, "pci.ids");
243     strcat(hardware->modules_pcimap_path, "modules.pcimap");
244     strcat(hardware->modules_alias_path, "modules.alias");
245     strcat(hardware->memtest_label, "memtest");
246     strlcpy(hardware->vesa_background, CLI_DEFAULT_BACKGROUND,
247 	    sizeof(hardware->vesa_background));
248 }
249 
250 /*
251  * Detecting if a DMI table exist
252  * if yes, let's parse it
253  */
detect_dmi(struct s_hardware * hardware)254 int detect_dmi(struct s_hardware *hardware)
255 {
256     if (hardware->dmi_detection == true)
257 	return -1;
258     hardware->dmi_detection = true;
259     if (dmi_iterate(&hardware->dmi) == -ENODMITABLE) {
260 	hardware->is_dmi_valid = false;
261 	return -ENODMITABLE;
262     }
263 
264     parse_dmitable(&hardware->dmi);
265     hardware->is_dmi_valid = true;
266     return 0;
267 }
268 
269 /*
270  * Detecting ACPI
271  * if yes, let's parse it
272  */
detect_acpi(struct s_hardware * hardware)273 int detect_acpi(struct s_hardware *hardware)
274 {
275     int retval;
276     if (hardware->acpi_detection == true)
277 	return -1;
278     hardware->acpi_detection = true;
279     if ((retval=parse_acpi(&hardware->acpi)) != ACPI_FOUND) {
280 	hardware->is_acpi_valid = false;
281 	return retval;
282     }
283 
284     hardware->is_acpi_valid = true;
285     return retval;
286 }
287 
288 /**
289  * vpd_detection - populate the VPD structure
290  *
291  * VPD is a structure available on IBM machines.
292  * It is documented at:
293  *    http://www.pc.ibm.com/qtechinfo/MIGR-45120.html
294  * (XXX the page seems to be gone)
295  **/
detect_vpd(struct s_hardware * hardware)296 int detect_vpd(struct s_hardware *hardware)
297 {
298     if (hardware->vpd_detection)
299 	return -1;
300     else
301 	hardware->vpd_detection = true;
302 
303     if (vpd_decode(&hardware->vpd) == -ENOVPDTABLE) {
304 	hardware->is_vpd_valid = false;
305 	return -ENOVPDTABLE;
306     } else {
307 	hardware->is_vpd_valid = true;
308 	return 0;
309     }
310 }
311 
312 /* Detection vesa stuff*/
detect_vesa(struct s_hardware * hardware)313 int detect_vesa(struct s_hardware *hardware)
314 {
315     static com32sys_t rm;
316     struct vesa_general_info *gi;
317     struct vesa_mode_info *mi;
318     uint16_t mode, *mode_ptr;
319     char *oem_ptr;
320     int rv = -1;
321 
322     if (hardware->vesa_detection == true)
323 	return -1;
324 
325     hardware->vesa_detection = true;
326     hardware->is_vesa_valid = false;
327 
328     gi = lmalloc(sizeof(*gi));
329     if (!gi)
330 	return -1;
331 
332     mi = lmalloc(sizeof(*mi));
333     if (!mi)
334 	goto out;
335 
336     gi->signature = VBE2_MAGIC;	/* Get VBE2 extended data */
337     memset(&rm, 0, sizeof rm);
338     rm.eax.w[0] = 0x4F00;	/* Get SVGA general information */
339     rm.edi.w[0] = OFFS(gi);
340     rm.es = SEG(gi);
341     __intcall(0x10, &rm, &rm);
342 
343     if (rm.eax.w[0] != 0x004F) {
344 	goto out;
345     };
346 
347     mode_ptr = GET_PTR(gi->video_mode_ptr);
348     oem_ptr = GET_PTR(gi->oem_vendor_name_ptr);
349     strlcpy(hardware->vesa.vendor, oem_ptr, sizeof(hardware->vesa.vendor));
350     oem_ptr = GET_PTR(gi->oem_product_name_ptr);
351     strlcpy(hardware->vesa.product, oem_ptr, sizeof(hardware->vesa.product));
352     oem_ptr = GET_PTR(gi->oem_product_rev_ptr);
353     strlcpy(hardware->vesa.product_revision, oem_ptr,
354 	    sizeof(hardware->vesa.product_revision));
355 
356     hardware->vesa.major_version = (gi->version >> 8) & 0xff;
357     hardware->vesa.minor_version = gi->version & 0xff;
358     hardware->vesa.total_memory = gi->total_memory;
359     hardware->vesa.software_rev = gi->oem_software_rev;
360 
361     hardware->vesa.vmi_count = 0;
362 
363     while ((mode = *mode_ptr++) != 0xFFFF) {
364 
365         memset(&rm, 0, sizeof rm);
366 	rm.eax.w[0] = 0x4F01;	/* Get SVGA mode information */
367 	rm.ecx.w[0] = mode;
368 	rm.edi.w[0] = OFFS(mi);
369 	rm.es = SEG(mi);
370 	__intcall(0x10, &rm, &rm);
371 
372 	/* Must be a supported mode */
373 	if (rm.eax.w[0] != 0x004f)
374 	    continue;
375 
376 	/* Saving detected values */
377 	memcpy(&hardware->vesa.vmi[hardware->vesa.vmi_count].mi, mi,
378 	       sizeof(struct vesa_mode_info));
379 	hardware->vesa.vmi[hardware->vesa.vmi_count].mode = mode;
380 
381 	hardware->vesa.vmi_count++;
382     }
383     hardware->is_vesa_valid = true;
384 
385     rv = 0;
386 out:
387     lfree(mi);
388     lfree(gi);
389     return rv;
390 }
391 
392 /* Try to detect disks from port 0x80 to 0xff */
detect_disks(struct s_hardware * hardware)393 void detect_disks(struct s_hardware *hardware)
394 {
395     int i = -1;
396     int err;
397 
398     if (hardware->disk_detection)
399 	return;
400 
401     hardware->disk_detection = true;
402     for (int drive = 0x80; drive < 0xff; drive++) {
403 	i++;
404 	hardware->disk_info[i].disk = drive;
405 	err = get_drive_parameters(&hardware->disk_info[i]);
406 
407 	/*
408 	 * Do not print output when drive does not exist or
409 	 * doesn't support int13 (cdrom, ...)
410 	 */
411 	if (err == -1 || !hardware->disk_info[i].cbios)
412 	    continue;
413 
414 	/* Detect MBR */
415 	hardware->mbr_ids[i] = get_mbr_id(&hardware->disk_info[i]);
416 
417 	hardware->disks_count++;
418     }
419 }
420 
detect_pxe(struct s_hardware * hardware)421 int detect_pxe(struct s_hardware *hardware)
422 {
423     void *dhcpdata;
424 
425     size_t dhcplen;
426     t_PXENV_UNDI_GET_NIC_TYPE gnt;
427 
428     if (hardware->pxe_detection == true)
429 	return -1;
430     hardware->pxe_detection = true;
431     hardware->is_pxe_valid = false;
432     memset(&gnt, 0, sizeof(t_PXENV_UNDI_GET_NIC_TYPE));
433     memset(&hardware->pxe, 0, sizeof(struct s_pxe));
434 
435     /* This code can only work if pxelinux is loaded */
436     if (hardware->sv->filesystem != SYSLINUX_FS_PXELINUX) {
437 	return -1;
438     }
439 // printf("PXE: PXElinux detected\n");
440     if (!pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK, &dhcpdata, &dhcplen)) {
441 	pxe_bootp_t *dhcp = &hardware->pxe.dhcpdata;
442 	memcpy(&hardware->pxe.dhcpdata, dhcpdata,
443 	       sizeof(hardware->pxe.dhcpdata));
444 	snprintf(hardware->pxe.mac_addr, sizeof(hardware->pxe.mac_addr),
445 		 "%02x:%02x:%02x:%02x:%02x:%02x", dhcp->CAddr[0],
446 		 dhcp->CAddr[1], dhcp->CAddr[2], dhcp->CAddr[3],
447 		 dhcp->CAddr[4], dhcp->CAddr[5]);
448 
449 	/* Saving our IP address in a easy format */
450 	hardware->pxe.ip_addr[0] = hardware->pxe.dhcpdata.yip & 0xff;
451 	hardware->pxe.ip_addr[1] = hardware->pxe.dhcpdata.yip >> 8 & 0xff;
452 	hardware->pxe.ip_addr[2] = hardware->pxe.dhcpdata.yip >> 16 & 0xff;
453 	hardware->pxe.ip_addr[3] = hardware->pxe.dhcpdata.yip >> 24 & 0xff;
454 
455 	if (!pxe_get_nic_type(&gnt)) {
456 	    switch (gnt.NicType) {
457 	    case PCI_NIC:
458 		hardware->is_pxe_valid = true;
459 		hardware->pxe.vendor_id = gnt.info.pci.Vendor_ID;
460 		hardware->pxe.product_id = gnt.info.pci.Dev_ID;
461 		hardware->pxe.subvendor_id = gnt.info.pci.SubVendor_ID;
462 		hardware->pxe.subproduct_id =
463 		    gnt.info.pci.SubDevice_ID,
464 		    hardware->pxe.rev = gnt.info.pci.Rev;
465 		hardware->pxe.pci_bus = (gnt.info.pci.BusDevFunc >> 8) & 0xff;
466 		hardware->pxe.pci_dev = (gnt.info.pci.BusDevFunc >> 3) & 0x7;
467 		hardware->pxe.pci_func = gnt.info.pci.BusDevFunc & 0x03;
468 		hardware->pxe.base_class = gnt.info.pci.Base_Class;
469 		hardware->pxe.sub_class = gnt.info.pci.Sub_Class;
470 		hardware->pxe.prog_intf = gnt.info.pci.Prog_Intf;
471 		hardware->pxe.nictype = gnt.NicType;
472 		break;
473 	    case CardBus_NIC:
474 		hardware->is_pxe_valid = true;
475 		hardware->pxe.vendor_id = gnt.info.cardbus.Vendor_ID;
476 		hardware->pxe.product_id = gnt.info.cardbus.Dev_ID;
477 		hardware->pxe.subvendor_id = gnt.info.cardbus.SubVendor_ID;
478 		hardware->pxe.subproduct_id =
479 		    gnt.info.cardbus.SubDevice_ID,
480 		    hardware->pxe.rev = gnt.info.cardbus.Rev;
481 		hardware->pxe.pci_bus =
482 		    (gnt.info.cardbus.BusDevFunc >> 8) & 0xff;
483 		hardware->pxe.pci_dev =
484 		    (gnt.info.cardbus.BusDevFunc >> 3) & 0x7;
485 		hardware->pxe.pci_func = gnt.info.cardbus.BusDevFunc & 0x03;
486 		hardware->pxe.base_class = gnt.info.cardbus.Base_Class;
487 		hardware->pxe.sub_class = gnt.info.cardbus.Sub_Class;
488 		hardware->pxe.prog_intf = gnt.info.cardbus.Prog_Intf;
489 		hardware->pxe.nictype = gnt.NicType;
490 		break;
491 	    case PnP_NIC:
492 	    default:
493 		return -1;
494 		break;
495 	    }
496 
497 	    /* The firt pass try to find the exact pci device */
498 	    hardware->pxe.pci_device = NULL;
499 	    hardware->pxe.pci_device_pos = 0;
500 	    struct pci_device *pci_device;
501 	    int pci_number = 0;
502 	    for_each_pci_func(pci_device, hardware->pci_domain) {
503 		pci_number++;
504 		if ((__pci_bus == hardware->pxe.pci_bus) &&
505 		    (__pci_slot == hardware->pxe.pci_dev) &&
506 		    (__pci_func == hardware->pxe.pci_func) &&
507 		    (pci_device->vendor == hardware->pxe.vendor_id)
508 		    && (pci_device->product == hardware->pxe.product_id)) {
509 		    hardware->pxe.pci_device = pci_device;
510 		    hardware->pxe.pci_device_pos = pci_number;
511 		    return 0;
512 		}
513 	    }
514 
515 	    /* If we reach that part, it means the pci device pointed by
516 	     * the pxe rom wasn't found in our list.
517 	     * Let's try to find the device only by its pci ids.
518 	     * The pci device we'll match is maybe not exactly the good one
519 	     * as we can have the same pci id several times.
520 	     * At least, the pci id, the vendor/product will be right.
521 	     * That's clearly a workaround for some weird cases.
522 	     * This should happend very unlikely */
523 	    hardware->pxe.pci_device = NULL;
524 	    hardware->pxe.pci_device_pos = 0;
525 	    pci_number = 0;
526 	    for_each_pci_func(pci_device, hardware->pci_domain) {
527 		pci_number++;
528 		if ((pci_device->vendor == hardware->pxe.vendor_id)
529 		    && (pci_device->product == hardware->pxe.product_id)) {
530 		    hardware->pxe.pci_device = pci_device;
531 		    hardware->pxe.pci_device_pos = pci_number;
532 		    return 0;
533 		}
534 	    }
535 
536 	}
537     }
538     return 0;
539 }
540 
detect_memory(struct s_hardware * hardware)541 void detect_memory(struct s_hardware *hardware) {
542      if (hardware->memory_detection == false) {
543 	     hardware->memory_detection = true;
544      hardware->detected_memory_size = detect_memsize();
545      }
546 }
547 
detect_pci(struct s_hardware * hardware)548 void detect_pci(struct s_hardware *hardware)
549 {
550     if (hardware->pci_detection == true)
551 	return;
552     hardware->pci_detection = true;
553 
554     hardware->nb_pci_devices = 0;
555 
556     /* Scanning to detect pci buses and devices */
557     hardware->pci_domain = pci_scan();
558 
559     if (!hardware->pci_domain)
560 	return;
561 
562     /* Gathering addtional information */
563     gather_additional_pci_config(hardware->pci_domain);
564 
565     struct pci_device *pci_device;
566     for_each_pci_func(pci_device, hardware->pci_domain) {
567 	hardware->nb_pci_devices++;
568     }
569 
570     if (!quiet) {
571 	more_printf("PCI: %d devices detected\n", hardware->nb_pci_devices);
572 	more_printf("PCI: Resolving names\n");
573     }
574     /* Assigning product & vendor name for each device */
575     hardware->pci_ids_return_code =
576 	get_name_from_pci_ids(hardware->pci_domain, hardware->pciids_path);
577 
578     if (!quiet)
579 	more_printf("PCI: Resolving class names\n");
580     /* Assigning class name for each device */
581     hardware->pci_ids_return_code =
582 	get_class_name_from_pci_ids(hardware->pci_domain,
583 				    hardware->pciids_path);
584 
585     if (!quiet)
586 	more_printf("PCI: Resolving module names\n");
587     /* Detecting which kernel module should match each device using modules.pcimap */
588     hardware->modules_pcimap_return_code =
589 	get_module_name_from_pcimap(hardware->pci_domain,
590 				    hardware->modules_pcimap_path);
591 
592     /* Detecting which kernel module should match each device using modules.alias */
593     hardware->modules_alias_return_code =
594 	get_module_name_from_alias(hardware->pci_domain,
595 				   hardware->modules_alias_path);
596 
597 }
598 
cpu_detect(struct s_hardware * hardware)599 void cpu_detect(struct s_hardware *hardware)
600 {
601     if (hardware->cpu_detection == true)
602 	return;
603     detect_cpu(&hardware->cpu);
604     /* Old processors doesn't manage the identify commands
605      * Let's use the dmi value in that case */
606     if (strlen(remove_spaces(hardware->cpu.model)) == 0)
607 	strlcpy(hardware->cpu.model, hardware->dmi.processor.version,
608 		sizeof(hardware->cpu.model));
609 
610     /* Some CPUs like to put many spaces in the model name
611      * That makes some weird display in console/menu
612      * Let's remove that mulitple spaces */
613     strlcpy(hardware->cpu.model,del_multi_spaces(hardware->cpu.model),sizeof(hardware->cpu.model));
614 
615     if ((hardware->is_acpi_valid) && (hardware->acpi.madt.valid)) {
616     	hardware->physical_cpu_count=hardware->acpi.madt.processor_local_apic_count / hardware->cpu.num_cores;
617     }
618     hardware->cpu_detection = true;
619 }
620 
621 /*
622  * Find the last instance of a particular command line argument
623  * (which should include the final =; do not use for boolean arguments)
624  */
find_argument(const char ** argv,const char * argument)625 const char *find_argument(const char **argv, const char *argument)
626 {
627     int la = strlen(argument);
628     const char **arg;
629     const char *ptr = NULL;
630 
631     for (arg = argv; *arg; arg++) {
632 	if (!memcmp(*arg, argument, la))
633 	    ptr = *arg + la;
634     }
635 
636     return ptr;
637 }
638 
clear_screen(void)639 void clear_screen(void)
640 {
641     move_cursor_to_next_line();
642     disable_utf8();
643     set_g1_special_char();
644     set_us_g0_charset();
645     display_cursor(false);
646     clear_entire_screen();
647     gotoxy(0,0);
648     reset_more_printf();
649 }
650 
651 /* remove begining spaces */
skip_spaces(char * p)652 char *skip_spaces(char *p)
653 {
654     while (*p && *p <= ' ') {
655 	p++;
656     }
657 
658     return p;
659 }
660 
661 /* remove trailing & begining spaces */
remove_spaces(char * p)662 char *remove_spaces(char *p)
663 {
664     char *save = p;
665     p += strlen(p) - 1;
666     while (*p && *p <= ' ') {
667 	*p = '\0';
668 	p--;
669     }
670     p = save;
671     while (*p && *p <= ' ') {
672 	p++;
673     }
674 
675     return p;
676 }
677 
678 /* remove trailing LF */
remove_trailing_lf(char * p)679 char *remove_trailing_lf(char *p)
680 {
681     char *save = p;
682     p += strlen(p) - 1;
683     while (*p && *p == 10) {
684 	*p = '\0';
685 	p--;
686     }
687     p = save;
688 
689     return p;
690 }
691 
692 /* delete multiple spaces, one is enough */
del_multi_spaces(char * p)693 char *del_multi_spaces(char *p)
694 {
695     /* Saving the original pointer */
696     char *save = p;
697 
698     /* Let's parse the complete string
699      * As we search for a double spacing
700      * we have to be sure then string is
701      * long enough to be processed */
702     while (*p && *(p + 1)) {
703 
704 	/* If we have two consecutive spaces */
705 	if ((*p == ' ') && (*(p + 1) == ' ')) {
706 
707 	    /* Let's copy to the current position
708 	     * the content from the second space*/
709 	    strlcpy(p, p + 1, strlen(p + 1));
710 
711 	    /* Don't increment the pointer as we
712 	     * changed the content of the current position*/
713 	    continue;
714 	}
715 
716 	/* Nothing as been found, let's see on the next char */
717 	p++;
718     }
719     /* Returning the original pointer */
720     return save;
721 }
722 
723 /* Reset the more_printf counter */
reset_more_printf(void)724 void reset_more_printf(void)
725 {
726     display_line_nb = 0;
727 }
728 
draw_background(const char * what)729 int draw_background(const char *what)
730 {
731     if (!what)
732 	return vesacon_default_background();
733     else
734 	return vesacon_load_background(what);
735 }
736 
init_console(struct s_hardware * hardware)737 void init_console(struct s_hardware *hardware)
738 {
739     if (vesamode) {
740 	openconsole(&dev_rawcon_r, &dev_vesaserial_w);
741 	draw_background(hardware->vesa_background);
742     } else
743 	console_ansi_raw();
744 }
745 
detect_hardware(struct s_hardware * hardware)746 void detect_hardware(struct s_hardware *hardware)
747 {
748     if (!quiet)
749         more_printf("ACPI: Detecting\n");
750     detect_acpi(hardware);
751 
752     if (!quiet)
753         more_printf("MEMORY: Detecting\n");
754     detect_memory(hardware);
755 
756     if (!quiet)
757         more_printf("DMI: Detecting Table\n");
758     if (detect_dmi(hardware) == -ENODMITABLE) {
759         more_printf("DMI: ERROR ! Table not found ! \n");
760         more_printf("DMI: Many hardware components will not be detected ! \n");
761     } else {
762         if (!quiet)
763             more_printf("DMI: Table found ! (version %u.%u)\n",
764                         hardware->dmi.dmitable.major_version,
765                         hardware->dmi.dmitable.minor_version);
766     }
767 
768     if (!quiet)
769         more_printf("CPU: Detecting\n");
770     cpu_detect(hardware);
771 
772     if (!quiet)
773         more_printf("DISKS: Detecting\n");
774     detect_disks(hardware);
775 
776     if (!quiet)
777         more_printf("VPD: Detecting\n");
778     detect_vpd(hardware);
779 
780     detect_pci(hardware);
781     if (!quiet)
782         more_printf("PCI: %d Devices Found\n", hardware->nb_pci_devices);
783 
784    if (!quiet)
785         more_printf("PXE: Detecting\n");
786     detect_pxe(hardware);
787 
788     if (!quiet)
789         more_printf("VESA: Detecting\n");
790     detect_vesa(hardware);
791 }
792 
793