blob: b090058fab64e41e3381c11d20407e1624d0c93d [file] [log] [blame]
Kevin O'Connorf076a3e2008-02-25 22:25:15 -05001// 16bit code to load disk image and start system boot.
2//
3// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
4// Copyright (C) 2002 MandrakeSoft S.A.
5//
6// This file may be distributed under the terms of the GNU GPLv3 license.
7
Kevin O'Connorf076a3e2008-02-25 22:25:15 -05008#include "util.h" // irq_enable
Kevin O'Connor9521e262008-07-04 13:04:29 -04009#include "biosvar.h" // GET_EBDA
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050010#include "config.h" // CONFIG_*
Kevin O'Connor15aee2e2008-03-01 13:34:04 -050011#include "ata.h" // ata_detect
Kevin O'Connor180a9592008-03-04 22:50:53 -050012#include "disk.h" // cdrom_boot
Kevin O'Connor9521e262008-07-04 13:04:29 -040013#include "bregs.h" // struct bregs
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050014
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050015//--------------------------------------------------------------------------
16// print_boot_device
17// displays the boot device
18//--------------------------------------------------------------------------
19
20static const char drivetypes[][10]={
Kevin O'Connorabc75972008-05-18 00:20:53 -040021 "", "Floppy", "Hard Disk", "CD-Rom", "Network"
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050022};
23
Kevin O'Connore0113c92008-04-05 15:51:12 -040024void
25printf_bootdev(u16 bootdev)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050026{
Kevin O'Connore0113c92008-04-05 15:51:12 -040027 u16 type = GET_EBDA(ipl.table[bootdev].type);
28
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050029 /* NIC appears as type 0x80 */
30 if (type == IPL_TYPE_BEV)
31 type = 0x4;
32 if (type == 0 || type > 0x4)
33 BX_PANIC("Bad drive type\n");
Kevin O'Connore0113c92008-04-05 15:51:12 -040034 printf("%s", drivetypes[type]);
Kevin O'Connora2e73802008-02-27 10:27:00 -050035
Kevin O'Connore0113c92008-04-05 15:51:12 -040036 /* print product string if BEV */
37 void *far_description = (void*)GET_EBDA(ipl.table[bootdev].description);
38 if (type == 4 && far_description != 0) {
39 char description[33];
40 /* first 32 bytes are significant */
41 memcpy(MAKE_FARPTR(GET_SEG(SS), &description), far_description, 32);
42 /* terminate string */
43 description[32] = 0;
44 printf(" [%.s]", description);
45 }
46}
47
48static void
49print_boot_device(u16 bootdev)
50{
51 printf("Booting from ");
52 printf_bootdev(bootdev);
53 printf("...\n");
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050054}
55
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050056//--------------------------------------------------------------------------
57// print_boot_failure
58// displays the reason why boot failed
59//--------------------------------------------------------------------------
60static void
61print_boot_failure(u16 type, u8 reason)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050062{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050063 if (type == 0 || type > 0x3)
64 BX_PANIC("Bad drive type\n");
65
Kevin O'Connora2e73802008-02-27 10:27:00 -050066 printf("Boot failed");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050067 if (type < 4) {
68 /* Report the reason too */
69 if (reason==0)
70 printf(": not a bootable disk");
71 else
72 printf(": could not read the boot disk");
73 }
Kevin O'Connora2e73802008-02-27 10:27:00 -050074 printf("\n\n");
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050075}
76
77static void
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050078try_boot(u16 seq_nr)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050079{
Kevin O'Connor56a506d2008-03-29 13:15:36 -040080 SET_EBDA(ipl.sequence, seq_nr);
Kevin O'Connor7a558e42008-03-11 20:38:33 -040081
Kevin O'Connorabc75972008-05-18 00:20:53 -040082 u32 bootdev = GET_EBDA(ipl.bootorder);
Kevin O'Connor840c5342008-03-29 14:04:34 -040083 bootdev >>= 4 * seq_nr;
84 bootdev &= 0xf;
Kevin O'Connore0113c92008-04-05 15:51:12 -040085
Kevin O'Connor840c5342008-03-29 14:04:34 -040086 if (bootdev == 0)
87 BX_PANIC("No bootable device.\n");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050088
Kevin O'Connorabc75972008-05-18 00:20:53 -040089 /* Translate bootdev to an IPL table offset by subtracting 1 */
Kevin O'Connor840c5342008-03-29 14:04:34 -040090 bootdev -= 1;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050091
Kevin O'Connor56a506d2008-03-29 13:15:36 -040092 if (bootdev >= GET_EBDA(ipl.count)) {
Kevin O'Connorac8df8c2008-05-24 23:46:33 -040093 dprintf(1, "Invalid boot device (0x%x)\n", bootdev);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050094 return;
95 }
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050096
97 /* Do the loading, and set up vector as a far pointer to the boot
98 * address, and bootdrv as the boot drive */
Kevin O'Connore0113c92008-04-05 15:51:12 -040099 print_boot_device(bootdev);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500100
Kevin O'Connore0113c92008-04-05 15:51:12 -0400101 u16 type = GET_EBDA(ipl.table[bootdev].type);
102
103 u16 bootseg, bootip;
104 u8 bootdrv = 0;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500105 struct bregs cr;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500106 switch(type) {
107 case IPL_TYPE_FLOPPY: /* FDD */
108 case IPL_TYPE_HARDDISK: /* HDD */
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500109
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500110 bootdrv = (type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00;
111 bootseg = 0x07c0;
112
113 // Read sector
114 memset(&cr, 0, sizeof(cr));
115 cr.dl = bootdrv;
116 cr.es = bootseg;
117 cr.ah = 2;
118 cr.al = 1;
119 cr.cl = 1;
120 call16_int(0x13, &cr);
121
122 if (cr.flags & F_CF) {
123 print_boot_failure(type, 1);
124 return;
125 }
126
127 /* Always check the signature on a HDD boot sector; on FDD,
Kevin O'Connorabc75972008-05-18 00:20:53 -0400128 * only do the check if configured for it */
129 if (type != IPL_TYPE_FLOPPY || GET_EBDA(ipl.checkfloppysig)) {
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500130 if (GET_FARVAR(bootseg, *(u16*)0x1fe) != 0xaa55) {
131 print_boot_failure(type, 0);
132 return;
133 }
134 }
135
136 /* Canonicalize bootseg:bootip */
137 bootip = (bootseg & 0x0fff) << 4;
138 bootseg &= 0xf000;
139 break;
Kevin O'Connor180a9592008-03-04 22:50:53 -0500140 case IPL_TYPE_CDROM: {
141 /* CD-ROM */
142 if (! CONFIG_CDROM_BOOT)
143 break;
Kevin O'Connora05223c2008-06-28 12:15:57 -0400144 int status = cdrom_boot();
Kevin O'Connor180a9592008-03-04 22:50:53 -0500145 if (status) {
146 printf("CDROM boot failure code : %04x\n", status);
147 print_boot_failure(type, 1);
148 return;
149 }
150
151 bootdrv = GET_EBDA(cdemu.emulated_drive);
152 bootseg = GET_EBDA(cdemu.load_segment);
153 /* Canonicalize bootseg:bootip */
154 bootip = (bootseg & 0x0fff) << 4;
155 bootseg &= 0xf000;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500156 break;
Kevin O'Connor180a9592008-03-04 22:50:53 -0500157 }
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500158 case IPL_TYPE_BEV: {
159 /* Expansion ROM with a Bootstrap Entry Vector (a far
160 * pointer) */
Kevin O'Connor56a506d2008-03-29 13:15:36 -0400161 u32 vector = GET_EBDA(ipl.table[bootdev].vector);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500162 bootseg = vector >> 16;
163 bootip = vector & 0xffff;
164 break;
165 }
166 default:
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500167 return;
168 }
169
Kevin O'Connordcc7a4f2008-03-08 23:25:16 -0500170 /* Debugging info */
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400171 dprintf(1, "Booting from %x:%x\n", bootseg, bootip);
Kevin O'Connordcc7a4f2008-03-08 23:25:16 -0500172
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500173 memset(&cr, 0, sizeof(cr));
174 cr.ip = bootip;
175 cr.cs = bootseg;
176 // Set the magic number in ax and the boot drive in dl.
177 cr.dl = bootdrv;
178 cr.ax = 0xaa55;
179 call16(&cr);
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400180}
181
182static void
183do_boot(u16 seq_nr)
184{
185 try_boot(seq_nr);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500186
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500187 // Boot failed: invoke the boot recovery function
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400188 struct bregs br;
189 memset(&br, 0, sizeof(br));
190 call16_int(0x18, &br);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500191}
192
193// Boot Failure recovery: try the next device.
Kevin O'Connor44eeaf12008-07-06 10:14:49 -0400194void VISIBLE32
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500195handle_18()
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500196{
Kevin O'Connor61d6b062008-06-21 12:15:10 -0400197 debug_serial_setup();
Kevin O'Connor15c1f222008-06-12 22:59:43 -0400198 debug_enter(NULL, DEBUG_HDL_18);
Kevin O'Connor56a506d2008-03-29 13:15:36 -0400199 u16 seq = GET_EBDA(ipl.sequence) + 1;
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400200 do_boot(seq);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500201}
202
203// INT 19h Boot Load Service Entry Point
Kevin O'Connor44eeaf12008-07-06 10:14:49 -0400204void VISIBLE32
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500205handle_19()
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500206{
Kevin O'Connor61d6b062008-06-21 12:15:10 -0400207 debug_serial_setup();
Kevin O'Connor15c1f222008-06-12 22:59:43 -0400208 debug_enter(NULL, DEBUG_HDL_19);
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400209 do_boot(0);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500210}
Kevin O'Connorcdd3d652008-07-12 14:22:14 -0400211
212// Ughh - some older gcc compilers have a bug which causes VISIBLE32
213// functions to not be exported as a global variables.
214asm(".global handle_18, handle_19");