blob: 3ee957bf94e4f9fc64f4de1457cfa560521b8d52 [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_*
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'Connorf076a3e2008-02-25 22:25:15 -050013
Kevin O'Connor44c631d2008-03-02 11:24:36 -050014// We need a copy of this string, but we are not actually a PnP BIOS,
15// so make sure it is *not* aligned, so OSes will not see it if they
16// scan.
Kevin O'Connor19786762008-03-05 21:09:59 -050017char pnp_string[] VISIBLE16 __attribute__((aligned (2))) = " $PnP";
Kevin O'Connor44c631d2008-03-02 11:24:36 -050018
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050019//--------------------------------------------------------------------------
20// print_boot_device
21// displays the boot device
22//--------------------------------------------------------------------------
23
24static const char drivetypes[][10]={
Kevin O'Connorabc75972008-05-18 00:20:53 -040025 "", "Floppy", "Hard Disk", "CD-Rom", "Network"
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050026};
27
Kevin O'Connore0113c92008-04-05 15:51:12 -040028void
29printf_bootdev(u16 bootdev)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050030{
Kevin O'Connore0113c92008-04-05 15:51:12 -040031 u16 type = GET_EBDA(ipl.table[bootdev].type);
32
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050033 /* NIC appears as type 0x80 */
34 if (type == IPL_TYPE_BEV)
35 type = 0x4;
36 if (type == 0 || type > 0x4)
37 BX_PANIC("Bad drive type\n");
Kevin O'Connore0113c92008-04-05 15:51:12 -040038 printf("%s", drivetypes[type]);
Kevin O'Connora2e73802008-02-27 10:27:00 -050039
Kevin O'Connore0113c92008-04-05 15:51:12 -040040 /* print product string if BEV */
41 void *far_description = (void*)GET_EBDA(ipl.table[bootdev].description);
42 if (type == 4 && far_description != 0) {
43 char description[33];
44 /* first 32 bytes are significant */
45 memcpy(MAKE_FARPTR(GET_SEG(SS), &description), far_description, 32);
46 /* terminate string */
47 description[32] = 0;
48 printf(" [%.s]", description);
49 }
50}
51
52static void
53print_boot_device(u16 bootdev)
54{
55 printf("Booting from ");
56 printf_bootdev(bootdev);
57 printf("...\n");
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050058}
59
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050060//--------------------------------------------------------------------------
61// print_boot_failure
62// displays the reason why boot failed
63//--------------------------------------------------------------------------
64static void
65print_boot_failure(u16 type, u8 reason)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050066{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050067 if (type == 0 || type > 0x3)
68 BX_PANIC("Bad drive type\n");
69
Kevin O'Connora2e73802008-02-27 10:27:00 -050070 printf("Boot failed");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050071 if (type < 4) {
72 /* Report the reason too */
73 if (reason==0)
74 printf(": not a bootable disk");
75 else
76 printf(": could not read the boot disk");
77 }
Kevin O'Connora2e73802008-02-27 10:27:00 -050078 printf("\n\n");
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050079}
80
81static void
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050082try_boot(u16 seq_nr)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050083{
Kevin O'Connor7a558e42008-03-11 20:38:33 -040084 irq_enable();
85
Kevin O'Connor56a506d2008-03-29 13:15:36 -040086 SET_EBDA(ipl.sequence, seq_nr);
Kevin O'Connor7a558e42008-03-11 20:38:33 -040087
Kevin O'Connorabc75972008-05-18 00:20:53 -040088 u32 bootdev = GET_EBDA(ipl.bootorder);
Kevin O'Connor840c5342008-03-29 14:04:34 -040089 bootdev >>= 4 * seq_nr;
90 bootdev &= 0xf;
Kevin O'Connore0113c92008-04-05 15:51:12 -040091
Kevin O'Connor840c5342008-03-29 14:04:34 -040092 if (bootdev == 0)
93 BX_PANIC("No bootable device.\n");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050094
Kevin O'Connorabc75972008-05-18 00:20:53 -040095 /* Translate bootdev to an IPL table offset by subtracting 1 */
Kevin O'Connor840c5342008-03-29 14:04:34 -040096 bootdev -= 1;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050097
Kevin O'Connor56a506d2008-03-29 13:15:36 -040098 if (bootdev >= GET_EBDA(ipl.count)) {
Kevin O'Connorac8df8c2008-05-24 23:46:33 -040099 dprintf(1, "Invalid boot device (0x%x)\n", bootdev);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500100 return;
101 }
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500102
103 /* Do the loading, and set up vector as a far pointer to the boot
104 * address, and bootdrv as the boot drive */
Kevin O'Connore0113c92008-04-05 15:51:12 -0400105 print_boot_device(bootdev);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500106
Kevin O'Connore0113c92008-04-05 15:51:12 -0400107 u16 type = GET_EBDA(ipl.table[bootdev].type);
108
109 u16 bootseg, bootip;
110 u8 bootdrv = 0;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500111 struct bregs cr;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500112 switch(type) {
113 case IPL_TYPE_FLOPPY: /* FDD */
114 case IPL_TYPE_HARDDISK: /* HDD */
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500115
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500116 bootdrv = (type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00;
117 bootseg = 0x07c0;
118
119 // Read sector
120 memset(&cr, 0, sizeof(cr));
121 cr.dl = bootdrv;
122 cr.es = bootseg;
123 cr.ah = 2;
124 cr.al = 1;
125 cr.cl = 1;
126 call16_int(0x13, &cr);
127
128 if (cr.flags & F_CF) {
129 print_boot_failure(type, 1);
130 return;
131 }
132
133 /* Always check the signature on a HDD boot sector; on FDD,
Kevin O'Connorabc75972008-05-18 00:20:53 -0400134 * only do the check if configured for it */
135 if (type != IPL_TYPE_FLOPPY || GET_EBDA(ipl.checkfloppysig)) {
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500136 if (GET_FARVAR(bootseg, *(u16*)0x1fe) != 0xaa55) {
137 print_boot_failure(type, 0);
138 return;
139 }
140 }
141
142 /* Canonicalize bootseg:bootip */
143 bootip = (bootseg & 0x0fff) << 4;
144 bootseg &= 0xf000;
145 break;
Kevin O'Connor180a9592008-03-04 22:50:53 -0500146 case IPL_TYPE_CDROM: {
147 /* CD-ROM */
148 if (! CONFIG_CDROM_BOOT)
149 break;
150 u16 status = cdrom_boot();
151 if (status) {
152 printf("CDROM boot failure code : %04x\n", status);
153 print_boot_failure(type, 1);
154 return;
155 }
156
157 bootdrv = GET_EBDA(cdemu.emulated_drive);
158 bootseg = GET_EBDA(cdemu.load_segment);
159 /* Canonicalize bootseg:bootip */
160 bootip = (bootseg & 0x0fff) << 4;
161 bootseg &= 0xf000;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500162 break;
Kevin O'Connor180a9592008-03-04 22:50:53 -0500163 }
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500164 case IPL_TYPE_BEV: {
165 /* Expansion ROM with a Bootstrap Entry Vector (a far
166 * pointer) */
Kevin O'Connor56a506d2008-03-29 13:15:36 -0400167 u32 vector = GET_EBDA(ipl.table[bootdev].vector);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500168 bootseg = vector >> 16;
169 bootip = vector & 0xffff;
170 break;
171 }
172 default:
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500173 return;
174 }
175
Kevin O'Connordcc7a4f2008-03-08 23:25:16 -0500176 /* Debugging info */
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400177 dprintf(1, "Booting from %x:%x\n", bootseg, bootip);
Kevin O'Connordcc7a4f2008-03-08 23:25:16 -0500178
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500179 memset(&cr, 0, sizeof(cr));
180 cr.ip = bootip;
181 cr.cs = bootseg;
182 // Set the magic number in ax and the boot drive in dl.
183 cr.dl = bootdrv;
184 cr.ax = 0xaa55;
185 call16(&cr);
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400186}
187
188static void
189do_boot(u16 seq_nr)
190{
191 try_boot(seq_nr);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500192
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500193 // Boot failed: invoke the boot recovery function
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400194 struct bregs br;
195 memset(&br, 0, sizeof(br));
196 call16_int(0x18, &br);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500197}
198
199// Boot Failure recovery: try the next device.
Kevin O'Connor19786762008-03-05 21:09:59 -0500200void VISIBLE16
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500201handle_18()
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500202{
Kevin O'Connor61d6b062008-06-21 12:15:10 -0400203 debug_serial_setup();
Kevin O'Connor15c1f222008-06-12 22:59:43 -0400204 debug_enter(NULL, DEBUG_HDL_18);
Kevin O'Connor56a506d2008-03-29 13:15:36 -0400205 u16 seq = GET_EBDA(ipl.sequence) + 1;
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400206 do_boot(seq);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500207}
208
209// INT 19h Boot Load Service Entry Point
Kevin O'Connor19786762008-03-05 21:09:59 -0500210void VISIBLE16
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500211handle_19()
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500212{
Kevin O'Connor61d6b062008-06-21 12:15:10 -0400213 debug_serial_setup();
Kevin O'Connor15c1f222008-06-12 22:59:43 -0400214 debug_enter(NULL, DEBUG_HDL_19);
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400215 do_boot(0);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500216}