1 // Code to load disk image and start system boot.
3 // Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002 MandrakeSoft S.A.
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
8 #include "util.h" // irq_enable
9 #include "biosvar.h" // GET_EBDA
10 #include "config.h" // CONFIG_*
11 #include "disk.h" // cdrom_boot
12 #include "bregs.h" // struct bregs
13 #include "boot.h" // struct ipl_s
14 #include "cmos.h" // inb_cmos
19 /****************************************************************
21 ****************************************************************/
28 dprintf(3, "init boot device ordering\n");
30 memset(&IPL, 0, sizeof(IPL));
33 struct ipl_entry_s *ip = &IPL.table[0];
34 ip->type = IPL_TYPE_FLOPPY;
38 ip->type = IPL_TYPE_HARDDISK;
42 if (CONFIG_CDROM_BOOT) {
43 ip->type = IPL_TYPE_CDROM;
47 IPL.count = ip - IPL.table;
48 SET_EBDA(boot_sequence, 0xffff);
49 if (CONFIG_COREBOOT) {
50 // XXX - hardcode defaults for coreboot.
51 IPL.bootorder = 0x00000231;
52 IPL.checkfloppysig = 1;
54 // On emulators, get boot order from nvram.
55 IPL.bootorder = (inb_cmos(CMOS_BIOS_BOOTFLAG2)
56 | ((inb_cmos(CMOS_BIOS_BOOTFLAG1) & 0xf0) << 4));
57 if (!(inb_cmos(CMOS_BIOS_BOOTFLAG1) & 1))
58 IPL.checkfloppysig = 1;
62 // Add a BEV vector for a given pnp compatible option rom.
64 add_bev(u16 seg, u16 bev, u16 desc)
66 // Found a device that thinks it can boot the system. Record
67 // its BEV and product name string.
72 if (IPL.count >= ARRAY_SIZE(IPL.table))
75 struct ipl_entry_s *ip = &IPL.table[IPL.count];
76 ip->type = IPL_TYPE_BEV;
77 ip->vector = (seg << 16) | bev;
79 ip->description = MAKE_FLATPTR(seg, desc);
85 /****************************************************************
87 ****************************************************************/
89 static const char drivetypes[][10]={
90 "", "Floppy", "Hard Disk", "CD-Rom", "Network"
93 // display a device name
95 printf_bootdev(u16 bootdev)
97 u16 type = IPL.table[bootdev].type;
99 /* NIC appears as type 0x80 */
100 if (type == IPL_TYPE_BEV)
102 if (type == 0 || type > 0x4) {
106 printf("%s", drivetypes[type]);
108 /* print product string if BEV */
109 char *description_fl = IPL.table[bootdev].description;
110 if (type == 4 && description_fl != 0) {
111 char description[33];
112 /* first 32 bytes are significant */
113 memcpy(description, description_fl, 32);
114 /* terminate string */
116 printf(" [%.s]", description);
120 // display the boot device
122 print_boot_device(u16 bootdev)
124 printf("Booting from ");
125 printf_bootdev(bootdev);
129 // display the reason why a boot failed
131 print_boot_failure(u16 type, u8 reason)
133 printf("Boot failed");
135 /* Report the reason too */
137 printf(": not a bootable disk");
139 printf(": could not read the boot disk");
145 /****************************************************************
147 ****************************************************************/
150 interactive_bootmenu()
152 if (! CONFIG_BOOTMENU)
155 while (get_keystroke(0) >= 0)
158 printf("Press F12 for boot menu.\n\n");
160 int scan_code = get_keystroke(2500);
161 if (scan_code != 0x86)
165 while (get_keystroke(0) >= 0)
168 printf("Select boot device:\n\n");
170 int count = IPL.count;
172 for (i = 0; i < count; i++) {
179 scan_code = get_keystroke(1000);
180 if (scan_code == 0x01)
183 if (scan_code >= 0 && scan_code <= count + 1) {
184 // Add user choice to the boot order.
185 u16 choice = scan_code - 1;
186 u32 bootorder = IPL.bootorder;
187 IPL.bootorder = (bootorder << 4) | choice;
195 /****************************************************************
196 * Boot code (int 18/19)
197 ****************************************************************/
203 BX_PANIC("Boot support not compiled in.\n");
205 u32 bootdev = IPL.bootorder;
206 bootdev >>= 4 * seq_nr;
210 BX_PANIC("No bootable device.\n");
212 /* Translate bootdev to an IPL table offset by subtracting 1 */
215 if (bootdev >= IPL.count) {
216 dprintf(1, "Invalid boot device (0x%x)\n", bootdev);
220 /* Do the loading, and set up vector as a far pointer to the boot
221 * address, and bootdrv as the boot drive */
222 print_boot_device(bootdev);
224 u16 type = IPL.table[bootdev].type;
230 case IPL_TYPE_FLOPPY:
231 case IPL_TYPE_HARDDISK:
233 bootdrv = (type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00;
237 memset(&cr, 0, sizeof(cr));
243 call16_int(0x13, &cr);
245 if (cr.flags & F_CF) {
246 print_boot_failure(type, 1);
250 /* Always check the signature on a HDD boot sector; on FDD,
251 * only do the check if configured for it */
252 if (type != IPL_TYPE_FLOPPY || IPL.checkfloppysig) {
253 struct mbr_s *mbr = (void*)0;
254 if (GET_FARVAR(bootseg, mbr->signature) != MBR_SIGNATURE) {
255 print_boot_failure(type, 0);
260 /* Canonicalize bootseg:bootip */
261 bootip = (bootseg & 0x0fff) << 4;
264 case IPL_TYPE_CDROM: {
266 if (! CONFIG_CDROM_BOOT)
268 int status = cdrom_boot();
270 printf("CDROM boot failure code : %04x\n", status);
271 print_boot_failure(type, 1);
275 u16 ebda_seg = get_ebda_seg();
276 bootdrv = GET_EBDA2(ebda_seg, cdemu.emulated_drive);
277 bootseg = GET_EBDA2(ebda_seg, cdemu.load_segment);
278 /* Canonicalize bootseg:bootip */
279 bootip = (bootseg & 0x0fff) << 4;
284 /* Expansion ROM with a Bootstrap Entry Vector (a far
286 u32 vector = IPL.table[bootdev].vector;
287 bootseg = vector >> 16;
288 bootip = vector & 0xffff;
296 dprintf(1, "Booting from %x:%x\n", bootseg, bootip);
298 memset(&cr, 0, sizeof(cr));
301 // Set the magic number in ax and the boot drive in dl.
312 // Boot failed: invoke the boot recovery function
314 memset(&br, 0, sizeof(br));
315 call16_int(0x18, &br);
318 // Boot Failure recovery: try the next device.
322 debug_serial_setup();
323 debug_enter(NULL, DEBUG_HDL_18);
324 u16 ebda_seg = get_ebda_seg();
325 u16 seq = GET_EBDA2(ebda_seg, boot_sequence) + 1;
326 SET_EBDA2(ebda_seg, boot_sequence, seq);
330 // INT 19h Boot Load Service Entry Point
334 debug_serial_setup();
335 debug_enter(NULL, DEBUG_HDL_19);
336 SET_EBDA(boot_sequence, 0);
340 // Ughh - some older gcc compilers have a bug which causes VISIBLE32
341 // functions to not be exported as global variables.
342 asm(".global handle_18, handle_19");