blob: 9dec69e757f329fa2076ade6bc52ef2a7b4bda3b [file] [log] [blame]
Kevin O'Connorf13b0082008-08-17 11:26:42 -04001// Code to load disk image and start system boot.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -05002//
3// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
4// Copyright (C) 2002 MandrakeSoft S.A.
5//
Kevin O'Connorb1b7c2a2009-01-15 20:52:58 -05006// This file may be distributed under the terms of the GNU LGPLv3 license.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -05007
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'Connor180a9592008-03-04 22:50:53 -050011#include "disk.h" // cdrom_boot
Kevin O'Connor9521e262008-07-04 13:04:29 -040012#include "bregs.h" // struct bregs
Kevin O'Connorc659fde2008-12-28 23:43:20 -050013#include "boot.h" // struct ipl_s
Kevin O'Connor9f4e1d92009-02-08 15:44:08 -050014#include "cmos.h" // inb_cmos
Kevin O'Connorc659fde2008-12-28 23:43:20 -050015
16struct ipl_s IPL;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050017
Kevin O'Connor9f4e1d92009-02-08 15:44:08 -050018
19/****************************************************************
20 * IPL handlers
21 ****************************************************************/
22
23void
24boot_setup()
25{
26 if (! CONFIG_BOOT)
27 return;
28 dprintf(3, "init boot device ordering\n");
29
30 memset(&IPL, 0, sizeof(IPL));
31
32 // Floppy drive
Kevin O'Connor71f036d2009-02-08 16:57:22 -050033 struct ipl_entry_s *ie = &IPL.table[0];
34 ie->type = IPL_TYPE_FLOPPY;
35 ie->description = "Floppy";
36 ie++;
Kevin O'Connor9f4e1d92009-02-08 15:44:08 -050037
38 // First HDD
Kevin O'Connor71f036d2009-02-08 16:57:22 -050039 ie->type = IPL_TYPE_HARDDISK;
40 ie->description = "Hard Disk";
41 ie++;
Kevin O'Connor9f4e1d92009-02-08 15:44:08 -050042
43 // CDROM
44 if (CONFIG_CDROM_BOOT) {
Kevin O'Connor71f036d2009-02-08 16:57:22 -050045 ie->type = IPL_TYPE_CDROM;
46 ie->description = "CD-Rom";
47 ie++;
Kevin O'Connor9f4e1d92009-02-08 15:44:08 -050048 }
49
Kevin O'Connor71f036d2009-02-08 16:57:22 -050050 IPL.count = ie - IPL.table;
Kevin O'Connor9f4e1d92009-02-08 15:44:08 -050051 SET_EBDA(boot_sequence, 0xffff);
52 if (CONFIG_COREBOOT) {
53 // XXX - hardcode defaults for coreboot.
54 IPL.bootorder = 0x00000231;
55 IPL.checkfloppysig = 1;
56 } else {
57 // On emulators, get boot order from nvram.
58 IPL.bootorder = (inb_cmos(CMOS_BIOS_BOOTFLAG2)
59 | ((inb_cmos(CMOS_BIOS_BOOTFLAG1) & 0xf0) << 4));
60 if (!(inb_cmos(CMOS_BIOS_BOOTFLAG1) & 1))
61 IPL.checkfloppysig = 1;
62 }
63}
64
65// Add a BEV vector for a given pnp compatible option rom.
66void
67add_bev(u16 seg, u16 bev, u16 desc)
68{
69 // Found a device that thinks it can boot the system. Record
70 // its BEV and product name string.
71
72 if (! CONFIG_BOOT)
73 return;
74
75 if (IPL.count >= ARRAY_SIZE(IPL.table))
76 return;
77
Kevin O'Connor71f036d2009-02-08 16:57:22 -050078 struct ipl_entry_s *ie = &IPL.table[IPL.count];
79 ie->type = IPL_TYPE_BEV;
80 ie->vector = (seg << 16) | bev;
Kevin O'Connor9f4e1d92009-02-08 15:44:08 -050081 if (desc)
Kevin O'Connor71f036d2009-02-08 16:57:22 -050082 ie->description = MAKE_FLATPTR(seg, desc);
Kevin O'Connor9f4e1d92009-02-08 15:44:08 -050083
84 IPL.count++;
85}
86
87
88/****************************************************************
Kevin O'Connor9f4e1d92009-02-08 15:44:08 -050089 * Boot menu
90 ****************************************************************/
91
92void
93interactive_bootmenu()
94{
95 if (! CONFIG_BOOTMENU)
96 return;
97
98 while (get_keystroke(0) >= 0)
99 ;
100
101 printf("Press F12 for boot menu.\n\n");
102
103 int scan_code = get_keystroke(2500);
104 if (scan_code != 0x86)
105 /* not F12 */
106 return;
107
108 while (get_keystroke(0) >= 0)
109 ;
110
111 printf("Select boot device:\n\n");
112
113 int count = IPL.count;
114 int i;
115 for (i = 0; i < count; i++) {
Kevin O'Connor71f036d2009-02-08 16:57:22 -0500116 struct ipl_entry_s *ie = &IPL.table[i];
117 char desc[33];
118 printf("%d. %s\n", i+1
119 , strtcpy(desc, ie->description, ARRAY_SIZE(desc)));
Kevin O'Connor9f4e1d92009-02-08 15:44:08 -0500120 }
121
122 for (;;) {
123 scan_code = get_keystroke(1000);
124 if (scan_code == 0x01)
125 // ESC
126 break;
127 if (scan_code >= 0 && scan_code <= count + 1) {
128 // Add user choice to the boot order.
129 u16 choice = scan_code - 1;
130 u32 bootorder = IPL.bootorder;
131 IPL.bootorder = (bootorder << 4) | choice;
132 break;
133 }
134 }
135 printf("\n");
136}
137
138
139/****************************************************************
140 * Boot code (int 18/19)
141 ****************************************************************/
142
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500143static void
Kevin O'Connor71f036d2009-02-08 16:57:22 -0500144call_boot_entry(u16 bootseg, u16 bootip, u8 bootdrv)
145{
146 dprintf(1, "Booting from %x:%x\n", bootseg, bootip);
147
148 struct bregs br;
149 memset(&br, 0, sizeof(br));
150 br.ip = bootip;
151 br.cs = bootseg;
152 // Set the magic number in ax and the boot drive in dl.
153 br.dl = bootdrv;
154 br.ax = 0xaa55;
155 call16(&br);
156}
157
158// Boot from a disk (either floppy or harddrive)
159static void
160boot_disk(u8 bootdrv, int checksig)
161{
162 u16 bootseg = 0x07c0;
163
164 // Read sector
165 struct bregs br;
166 memset(&br, 0, sizeof(br));
167 br.dl = bootdrv;
168 br.es = bootseg;
169 br.ah = 2;
170 br.al = 1;
171 br.cl = 1;
172 call16_int(0x13, &br);
173
174 if (br.flags & F_CF) {
175 printf("Boot failed: could not read the boot disk\n\n");
176 return;
177 }
178
179 if (checksig) {
180 struct mbr_s *mbr = (void*)0;
181 if (GET_FARVAR(bootseg, mbr->signature) != MBR_SIGNATURE) {
182 printf("Boot failed: not a bootable disk\n\n");
183 return;
184 }
185 }
186
187 /* Canonicalize bootseg:bootip */
188 u16 bootip = (bootseg & 0x0fff) << 4;
189 bootseg &= 0xf000;
190
191 call_boot_entry(bootseg, bootip, bootdrv);
192}
193
194// Boot from a CD-ROM
195static void
196boot_cdrom()
197{
198 if (! CONFIG_CDROM_BOOT)
199 return;
200 int status = cdrom_boot();
201 if (status) {
202 printf("Boot failed: Could not read from CDROM (code %04x)\n", status);
203 return;
204 }
205
206 u16 ebda_seg = get_ebda_seg();
207 u8 bootdrv = GET_EBDA2(ebda_seg, cdemu.emulated_drive);
208 u16 bootseg = GET_EBDA2(ebda_seg, cdemu.load_segment);
209 /* Canonicalize bootseg:bootip */
210 u16 bootip = (bootseg & 0x0fff) << 4;
211 bootseg &= 0xf000;
212
213 call_boot_entry(bootseg, bootip, bootdrv);
214}
215
216static void
217do_boot(u16 seq_nr)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500218{
Kevin O'Connor40967022008-07-21 22:23:05 -0400219 if (! CONFIG_BOOT)
220 BX_PANIC("Boot support not compiled in.\n");
221
Kevin O'Connorc659fde2008-12-28 23:43:20 -0500222 u32 bootdev = IPL.bootorder;
Kevin O'Connor840c5342008-03-29 14:04:34 -0400223 bootdev >>= 4 * seq_nr;
224 bootdev &= 0xf;
Kevin O'Connore0113c92008-04-05 15:51:12 -0400225
Kevin O'Connor840c5342008-03-29 14:04:34 -0400226 if (bootdev == 0)
227 BX_PANIC("No bootable device.\n");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500228
Kevin O'Connorabc75972008-05-18 00:20:53 -0400229 /* Translate bootdev to an IPL table offset by subtracting 1 */
Kevin O'Connor840c5342008-03-29 14:04:34 -0400230 bootdev -= 1;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500231
Kevin O'Connorc659fde2008-12-28 23:43:20 -0500232 if (bootdev >= IPL.count) {
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400233 dprintf(1, "Invalid boot device (0x%x)\n", bootdev);
Kevin O'Connor71f036d2009-02-08 16:57:22 -0500234 goto fail;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500235 }
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500236
237 /* Do the loading, and set up vector as a far pointer to the boot
238 * address, and bootdrv as the boot drive */
Kevin O'Connor71f036d2009-02-08 16:57:22 -0500239 struct ipl_entry_s *ie = &IPL.table[bootdev];
240 char desc[33];
241 printf("Booting from %s...\n"
242 , strtcpy(desc, ie->description, ARRAY_SIZE(desc)));
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500243
Kevin O'Connor71f036d2009-02-08 16:57:22 -0500244 switch(ie->type) {
Kevin O'Connorf13b0082008-08-17 11:26:42 -0400245 case IPL_TYPE_FLOPPY:
Kevin O'Connor71f036d2009-02-08 16:57:22 -0500246 boot_disk(0x00, IPL.checkfloppysig);
247 break;
Kevin O'Connorf13b0082008-08-17 11:26:42 -0400248 case IPL_TYPE_HARDDISK:
Kevin O'Connor71f036d2009-02-08 16:57:22 -0500249 boot_disk(0x80, 1);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500250 break;
Kevin O'Connor71f036d2009-02-08 16:57:22 -0500251 case IPL_TYPE_CDROM:
252 boot_cdrom();
253 break;
254 case IPL_TYPE_BEV:
255 call_boot_entry(ie->vector >> 16, ie->vector & 0xffff, 0);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500256 break;
Kevin O'Connor180a9592008-03-04 22:50:53 -0500257 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500258
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500259 // Boot failed: invoke the boot recovery function
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400260 struct bregs br;
Kevin O'Connor71f036d2009-02-08 16:57:22 -0500261fail:
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400262 memset(&br, 0, sizeof(br));
263 call16_int(0x18, &br);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500264}
265
266// Boot Failure recovery: try the next device.
Kevin O'Connor44eeaf12008-07-06 10:14:49 -0400267void VISIBLE32
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500268handle_18()
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500269{
Kevin O'Connor61d6b062008-06-21 12:15:10 -0400270 debug_serial_setup();
Kevin O'Connor15c1f222008-06-12 22:59:43 -0400271 debug_enter(NULL, DEBUG_HDL_18);
Kevin O'Connor08815372008-12-29 21:16:31 -0500272 u16 ebda_seg = get_ebda_seg();
273 u16 seq = GET_EBDA2(ebda_seg, boot_sequence) + 1;
274 SET_EBDA2(ebda_seg, boot_sequence, seq);
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400275 do_boot(seq);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500276}
277
278// INT 19h Boot Load Service Entry Point
Kevin O'Connor44eeaf12008-07-06 10:14:49 -0400279void VISIBLE32
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500280handle_19()
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500281{
Kevin O'Connor61d6b062008-06-21 12:15:10 -0400282 debug_serial_setup();
Kevin O'Connor15c1f222008-06-12 22:59:43 -0400283 debug_enter(NULL, DEBUG_HDL_19);
Kevin O'Connor08815372008-12-29 21:16:31 -0500284 SET_EBDA(boot_sequence, 0);
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400285 do_boot(0);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500286}
Kevin O'Connorcdd3d652008-07-12 14:22:14 -0400287
288// Ughh - some older gcc compilers have a bug which causes VISIBLE32
Kevin O'Connorf13b0082008-08-17 11:26:42 -0400289// functions to not be exported as global variables.
Kevin O'Connorcdd3d652008-07-12 14:22:14 -0400290asm(".global handle_18, handle_19");