blob: 6db213a43e8b78d081cee4f8bac6f786a2428bbc [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
14
15struct ipl_s IPL;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050016
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050017//--------------------------------------------------------------------------
18// print_boot_device
19// displays the boot device
20//--------------------------------------------------------------------------
21
22static const char drivetypes[][10]={
Kevin O'Connorabc75972008-05-18 00:20:53 -040023 "", "Floppy", "Hard Disk", "CD-Rom", "Network"
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050024};
25
Kevin O'Connore0113c92008-04-05 15:51:12 -040026void
27printf_bootdev(u16 bootdev)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050028{
Kevin O'Connorc659fde2008-12-28 23:43:20 -050029 u16 type = IPL.table[bootdev].type;
Kevin O'Connore0113c92008-04-05 15:51:12 -040030
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050031 /* NIC appears as type 0x80 */
32 if (type == IPL_TYPE_BEV)
33 type = 0x4;
34 if (type == 0 || type > 0x4)
35 BX_PANIC("Bad drive type\n");
Kevin O'Connore0113c92008-04-05 15:51:12 -040036 printf("%s", drivetypes[type]);
Kevin O'Connora2e73802008-02-27 10:27:00 -050037
Kevin O'Connore0113c92008-04-05 15:51:12 -040038 /* print product string if BEV */
Kevin O'Connor35ae7262009-01-19 15:44:44 -050039 char *description_fl = IPL.table[bootdev].description;
40 if (type == 4 && description_fl != 0) {
Kevin O'Connore0113c92008-04-05 15:51:12 -040041 char description[33];
42 /* first 32 bytes are significant */
Kevin O'Connor8b267cb2009-01-19 19:25:21 -050043 memcpy(description, description_fl, 32);
Kevin O'Connore0113c92008-04-05 15:51:12 -040044 /* terminate string */
45 description[32] = 0;
46 printf(" [%.s]", description);
47 }
48}
49
50static void
51print_boot_device(u16 bootdev)
52{
53 printf("Booting from ");
54 printf_bootdev(bootdev);
55 printf("...\n");
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050056}
57
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050058//--------------------------------------------------------------------------
59// print_boot_failure
60// displays the reason why boot failed
61//--------------------------------------------------------------------------
62static void
63print_boot_failure(u16 type, u8 reason)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050064{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050065 if (type == 0 || type > 0x3)
66 BX_PANIC("Bad drive type\n");
67
Kevin O'Connora2e73802008-02-27 10:27:00 -050068 printf("Boot failed");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050069 if (type < 4) {
70 /* Report the reason too */
71 if (reason==0)
72 printf(": not a bootable disk");
73 else
74 printf(": could not read the boot disk");
75 }
Kevin O'Connora2e73802008-02-27 10:27:00 -050076 printf("\n\n");
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050077}
78
79static void
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050080try_boot(u16 seq_nr)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050081{
Kevin O'Connor40967022008-07-21 22:23:05 -040082 if (! CONFIG_BOOT)
83 BX_PANIC("Boot support not compiled in.\n");
84
Kevin O'Connorc659fde2008-12-28 23:43:20 -050085 u32 bootdev = IPL.bootorder;
Kevin O'Connor840c5342008-03-29 14:04:34 -040086 bootdev >>= 4 * seq_nr;
87 bootdev &= 0xf;
Kevin O'Connore0113c92008-04-05 15:51:12 -040088
Kevin O'Connor840c5342008-03-29 14:04:34 -040089 if (bootdev == 0)
90 BX_PANIC("No bootable device.\n");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050091
Kevin O'Connorabc75972008-05-18 00:20:53 -040092 /* Translate bootdev to an IPL table offset by subtracting 1 */
Kevin O'Connor840c5342008-03-29 14:04:34 -040093 bootdev -= 1;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050094
Kevin O'Connorc659fde2008-12-28 23:43:20 -050095 if (bootdev >= IPL.count) {
Kevin O'Connorac8df8c2008-05-24 23:46:33 -040096 dprintf(1, "Invalid boot device (0x%x)\n", bootdev);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050097 return;
98 }
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050099
100 /* Do the loading, and set up vector as a far pointer to the boot
101 * address, and bootdrv as the boot drive */
Kevin O'Connore0113c92008-04-05 15:51:12 -0400102 print_boot_device(bootdev);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500103
Kevin O'Connorc659fde2008-12-28 23:43:20 -0500104 u16 type = IPL.table[bootdev].type;
Kevin O'Connore0113c92008-04-05 15:51:12 -0400105
106 u16 bootseg, bootip;
107 u8 bootdrv = 0;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500108 struct bregs cr;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500109 switch(type) {
Kevin O'Connorf13b0082008-08-17 11:26:42 -0400110 case IPL_TYPE_FLOPPY:
111 case IPL_TYPE_HARDDISK:
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500112
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500113 bootdrv = (type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00;
114 bootseg = 0x07c0;
115
116 // Read sector
117 memset(&cr, 0, sizeof(cr));
118 cr.dl = bootdrv;
119 cr.es = bootseg;
120 cr.ah = 2;
121 cr.al = 1;
122 cr.cl = 1;
123 call16_int(0x13, &cr);
124
125 if (cr.flags & F_CF) {
126 print_boot_failure(type, 1);
127 return;
128 }
129
130 /* Always check the signature on a HDD boot sector; on FDD,
Kevin O'Connorabc75972008-05-18 00:20:53 -0400131 * only do the check if configured for it */
Kevin O'Connorc659fde2008-12-28 23:43:20 -0500132 if (type != IPL_TYPE_FLOPPY || IPL.checkfloppysig) {
Kevin O'Connor95827c42009-02-07 00:04:57 -0500133 struct mbr_s *mbr = (void*)0;
134 if (GET_FARVAR(bootseg, mbr->signature) != MBR_SIGNATURE) {
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500135 print_boot_failure(type, 0);
136 return;
137 }
138 }
139
140 /* Canonicalize bootseg:bootip */
141 bootip = (bootseg & 0x0fff) << 4;
142 bootseg &= 0xf000;
143 break;
Kevin O'Connor180a9592008-03-04 22:50:53 -0500144 case IPL_TYPE_CDROM: {
145 /* CD-ROM */
146 if (! CONFIG_CDROM_BOOT)
Kevin O'Connord19501e2008-12-10 20:52:09 -0500147 return;
Kevin O'Connora05223c2008-06-28 12:15:57 -0400148 int status = cdrom_boot();
Kevin O'Connor180a9592008-03-04 22:50:53 -0500149 if (status) {
150 printf("CDROM boot failure code : %04x\n", status);
151 print_boot_failure(type, 1);
152 return;
153 }
154
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500155 u16 ebda_seg = get_ebda_seg();
156 bootdrv = GET_EBDA2(ebda_seg, cdemu.emulated_drive);
157 bootseg = GET_EBDA2(ebda_seg, cdemu.load_segment);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500158 /* Canonicalize bootseg:bootip */
159 bootip = (bootseg & 0x0fff) << 4;
160 bootseg &= 0xf000;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500161 break;
Kevin O'Connor180a9592008-03-04 22:50:53 -0500162 }
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500163 case IPL_TYPE_BEV: {
164 /* Expansion ROM with a Bootstrap Entry Vector (a far
165 * pointer) */
Kevin O'Connorc659fde2008-12-28 23:43:20 -0500166 u32 vector = IPL.table[bootdev].vector;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500167 bootseg = vector >> 16;
168 bootip = vector & 0xffff;
169 break;
170 }
171 default:
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500172 return;
173 }
174
Kevin O'Connordcc7a4f2008-03-08 23:25:16 -0500175 /* Debugging info */
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400176 dprintf(1, "Booting from %x:%x\n", bootseg, bootip);
Kevin O'Connordcc7a4f2008-03-08 23:25:16 -0500177
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500178 memset(&cr, 0, sizeof(cr));
179 cr.ip = bootip;
180 cr.cs = bootseg;
181 // Set the magic number in ax and the boot drive in dl.
182 cr.dl = bootdrv;
183 cr.ax = 0xaa55;
184 call16(&cr);
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400185}
186
187static void
188do_boot(u16 seq_nr)
189{
190 try_boot(seq_nr);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500191
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500192 // Boot failed: invoke the boot recovery function
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400193 struct bregs br;
194 memset(&br, 0, sizeof(br));
195 call16_int(0x18, &br);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500196}
197
198// Boot Failure recovery: try the next device.
Kevin O'Connor44eeaf12008-07-06 10:14:49 -0400199void VISIBLE32
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500200handle_18()
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500201{
Kevin O'Connor61d6b062008-06-21 12:15:10 -0400202 debug_serial_setup();
Kevin O'Connor15c1f222008-06-12 22:59:43 -0400203 debug_enter(NULL, DEBUG_HDL_18);
Kevin O'Connor08815372008-12-29 21:16:31 -0500204 u16 ebda_seg = get_ebda_seg();
205 u16 seq = GET_EBDA2(ebda_seg, boot_sequence) + 1;
206 SET_EBDA2(ebda_seg, boot_sequence, seq);
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400207 do_boot(seq);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500208}
209
210// INT 19h Boot Load Service Entry Point
Kevin O'Connor44eeaf12008-07-06 10:14:49 -0400211void VISIBLE32
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500212handle_19()
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500213{
Kevin O'Connor61d6b062008-06-21 12:15:10 -0400214 debug_serial_setup();
Kevin O'Connor15c1f222008-06-12 22:59:43 -0400215 debug_enter(NULL, DEBUG_HDL_19);
Kevin O'Connor08815372008-12-29 21:16:31 -0500216 SET_EBDA(boot_sequence, 0);
Kevin O'Connor7af49bf2008-03-09 13:46:13 -0400217 do_boot(0);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500218}
Kevin O'Connorcdd3d652008-07-12 14:22:14 -0400219
220// Ughh - some older gcc compilers have a bug which causes VISIBLE32
Kevin O'Connorf13b0082008-08-17 11:26:42 -0400221// functions to not be exported as global variables.
Kevin O'Connorcdd3d652008-07-12 14:22:14 -0400222asm(".global handle_18, handle_19");