blob: 53577ecfe3a60b5a21c18d63b2264892447522ae [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
9#include "biosvar.h" // struct bregs
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050010#include "config.h" // CONFIG_*
11#include "cmos.h" // inb_cmos
Kevin O'Connor15aee2e2008-03-01 13:34:04 -050012#include "ata.h" // ata_detect
Kevin O'Connor180a9592008-03-04 22:50:53 -050013#include "disk.h" // cdrom_boot
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050014
Kevin O'Connor44c631d2008-03-02 11:24:36 -050015// We need a copy of this string, but we are not actually a PnP BIOS,
16// so make sure it is *not* aligned, so OSes will not see it if they
17// scan.
Kevin O'Connor19786762008-03-05 21:09:59 -050018char pnp_string[] VISIBLE16 __attribute__((aligned (2))) = " $PnP";
Kevin O'Connor44c631d2008-03-02 11:24:36 -050019
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050020//--------------------------------------------------------------------------
21// print_boot_device
22// displays the boot device
23//--------------------------------------------------------------------------
24
25static const char drivetypes[][10]={
26 "", "Floppy","Hard Disk","CD-Rom", "Network"
27};
28
Kevin O'Connore0113c92008-04-05 15:51:12 -040029void
30printf_bootdev(u16 bootdev)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050031{
Kevin O'Connore0113c92008-04-05 15:51:12 -040032 u16 type = GET_EBDA(ipl.table[bootdev].type);
33
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050034 /* NIC appears as type 0x80 */
35 if (type == IPL_TYPE_BEV)
36 type = 0x4;
37 if (type == 0 || type > 0x4)
38 BX_PANIC("Bad drive type\n");
Kevin O'Connore0113c92008-04-05 15:51:12 -040039 printf("%s", drivetypes[type]);
Kevin O'Connora2e73802008-02-27 10:27:00 -050040
Kevin O'Connore0113c92008-04-05 15:51:12 -040041 /* print product string if BEV */
42 void *far_description = (void*)GET_EBDA(ipl.table[bootdev].description);
43 if (type == 4 && far_description != 0) {
44 char description[33];
45 /* first 32 bytes are significant */
46 memcpy(MAKE_FARPTR(GET_SEG(SS), &description), far_description, 32);
47 /* terminate string */
48 description[32] = 0;
49 printf(" [%.s]", description);
50 }
51}
52
53static void
54print_boot_device(u16 bootdev)
55{
56 printf("Booting from ");
57 printf_bootdev(bootdev);
58 printf("...\n");
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050059}
60
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050061//--------------------------------------------------------------------------
62// print_boot_failure
63// displays the reason why boot failed
64//--------------------------------------------------------------------------
65static void
66print_boot_failure(u16 type, u8 reason)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050067{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050068 if (type == 0 || type > 0x3)
69 BX_PANIC("Bad drive type\n");
70
Kevin O'Connora2e73802008-02-27 10:27:00 -050071 printf("Boot failed");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050072 if (type < 4) {
73 /* Report the reason too */
74 if (reason==0)
75 printf(": not a bootable disk");
76 else
77 printf(": could not read the boot disk");
78 }
Kevin O'Connora2e73802008-02-27 10:27:00 -050079 printf("\n\n");
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050080}
81
82static void
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050083try_boot(u16 seq_nr)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050084{
Kevin O'Connor7a558e42008-03-11 20:38:33 -040085 irq_enable();
86
Kevin O'Connor56a506d2008-03-29 13:15:36 -040087 SET_EBDA(ipl.sequence, seq_nr);
Kevin O'Connor7a558e42008-03-11 20:38:33 -040088
Kevin O'Connore0113c92008-04-05 15:51:12 -040089 u16 bootdev = inb_cmos(CMOS_BIOS_BOOTFLAG2);
Kevin O'Connor840c5342008-03-29 14:04:34 -040090 bootdev |= ((inb_cmos(CMOS_BIOS_BOOTFLAG1) & 0xf0) << 4);
91 bootdev >>= 4 * seq_nr;
92 bootdev &= 0xf;
Kevin O'Connore0113c92008-04-05 15:51:12 -040093
94 /* Read user selected device */
95 u16 bootfirst = GET_EBDA(ipl.bootfirst);
96 if (bootfirst != 0xFFFF) {
97 bootdev = bootfirst;
98 /* Reset boot sequence */
99 SET_EBDA(ipl.bootfirst, 0xFFFF);
100 SET_EBDA(ipl.sequence, 0xFFFF);
101 }
102
Kevin O'Connor840c5342008-03-29 14:04:34 -0400103 if (bootdev == 0)
104 BX_PANIC("No bootable device.\n");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500105
Kevin O'Connor840c5342008-03-29 14:04:34 -0400106 /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
107 bootdev -= 1;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500108
Kevin O'Connor56a506d2008-03-29 13:15:36 -0400109 if (bootdev >= GET_EBDA(ipl.count)) {
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500110 BX_INFO("Invalid boot device (0x%x)\n", bootdev);
111 return;
112 }
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500113
114 /* Do the loading, and set up vector as a far pointer to the boot
115 * address, and bootdrv as the boot drive */
Kevin O'Connore0113c92008-04-05 15:51:12 -0400116 print_boot_device(bootdev);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500117
Kevin O'Connore0113c92008-04-05 15:51:12 -0400118 u16 type = GET_EBDA(ipl.table[bootdev].type);
119
120 u16 bootseg, bootip;
121 u8 bootdrv = 0;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500122 struct bregs cr;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500123 switch(type) {
124 case IPL_TYPE_FLOPPY: /* FDD */
125 case IPL_TYPE_HARDDISK: /* HDD */
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500126
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500127 bootdrv = (type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00;
128 bootseg = 0x07c0;
129
130 // Read sector
131 memset(&cr, 0, sizeof(cr));
132 cr.dl = bootdrv;
133 cr.es = bootseg;
134 cr.ah = 2;
135 cr.al = 1;
136 cr.cl = 1;
137 call16_int(0x13, &cr);
138
139 if (cr.flags & F_CF) {
140 print_boot_failure(type, 1);
141 return;
142 }
143
144 /* Always check the signature on a HDD boot sector; on FDD,
145 * only do the check if the CMOS doesn't tell us to skip it */
146 if ((type != IPL_TYPE_FLOPPY)
147 || !((inb_cmos(CMOS_BIOS_BOOTFLAG1) & 0x01))) {
148 if (GET_FARVAR(bootseg, *(u16*)0x1fe) != 0xaa55) {
149 print_boot_failure(type, 0);
150 return;
151 }
152 }
153
154 /* Canonicalize bootseg:bootip */
155 bootip = (bootseg & 0x0fff) << 4;
156 bootseg &= 0xf000;
157 break;
Kevin O'Connor180a9592008-03-04 22:50:53 -0500158 case IPL_TYPE_CDROM: {
159 /* CD-ROM */
160 if (! CONFIG_CDROM_BOOT)
161 break;
162 u16 status = cdrom_boot();
163 if (status) {
164 printf("CDROM boot failure code : %04x\n", status);
165 print_boot_failure(type, 1);
166 return;
167 }
168
169 bootdrv = GET_EBDA(cdemu.emulated_drive);
170 bootseg = GET_EBDA(cdemu.load_segment);
171 /* Canonicalize bootseg:bootip */
172 bootip = (bootseg & 0x0fff) << 4;
173 bootseg &= 0xf000;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500174 break;
Kevin O'Connor180a9592008-03-04 22:50:53 -0500175 }
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500176 case IPL_TYPE_BEV: {
177 /* Expansion ROM with a Bootstrap Entry Vector (a far
178 * pointer) */
Kevin O'Connor56a506d2008-03-29 13:15:36 -0400179 u32 vector = GET_EBDA(ipl.table[bootdev].vector);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500180 bootseg = vector >> 16;
181 bootip = vector & 0xffff;
182 break;
183 }
184 default:
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500185 return;
186 }
187
Kevin O'Connordcc7a4f2008-03-08 23:25:16 -0500188 /* Debugging info */
189 BX_INFO("Booting from %x:%x\n", bootseg, bootip);
190
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500191 memset(&cr, 0, sizeof(cr));
192 cr.ip = bootip;
193 cr.cs = bootseg;
194 // Set the magic number in ax and the boot drive in dl.
195 cr.dl = bootdrv;
196 cr.ax = 0xaa55;
197 call16(&cr);
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400198}
199
200static void
201do_boot(u16 seq_nr)
202{
203 try_boot(seq_nr);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500204
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500205 // Boot failed: invoke the boot recovery function
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400206 struct bregs br;
207 memset(&br, 0, sizeof(br));
208 call16_int(0x18, &br);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500209}
210
211// Boot Failure recovery: try the next device.
Kevin O'Connor19786762008-03-05 21:09:59 -0500212void VISIBLE16
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500213handle_18()
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500214{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500215 debug_enter(NULL);
Kevin O'Connor56a506d2008-03-29 13:15:36 -0400216 u16 seq = GET_EBDA(ipl.sequence) + 1;
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400217 do_boot(seq);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500218}
219
220// INT 19h Boot Load Service Entry Point
Kevin O'Connor19786762008-03-05 21:09:59 -0500221void VISIBLE16
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500222handle_19()
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500223{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500224 debug_enter(NULL);
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400225 do_boot(0);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500226}