blob: 1ab9423bfa93c24b217562b56c400deaa653ff3d [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'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.
17char pnp_string[] VISIBLE __attribute__((aligned (2))) = " $PnP";
18
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]={
25 "", "Floppy","Hard Disk","CD-Rom", "Network"
26};
27
28static void
29print_boot_device(u16 type)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050030{
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");
36 printf("Booting from %s...\n", drivetypes[type]);
Kevin O'Connora2e73802008-02-27 10:27:00 -050037
38 // XXX - latest cvs has BEV description
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050039}
40
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050041//--------------------------------------------------------------------------
42// print_boot_failure
43// displays the reason why boot failed
44//--------------------------------------------------------------------------
45static void
46print_boot_failure(u16 type, u8 reason)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050047{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050048 if (type == 0 || type > 0x3)
49 BX_PANIC("Bad drive type\n");
50
Kevin O'Connora2e73802008-02-27 10:27:00 -050051 printf("Boot failed");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050052 if (type < 4) {
53 /* Report the reason too */
54 if (reason==0)
55 printf(": not a bootable disk");
56 else
57 printf(": could not read the boot disk");
58 }
Kevin O'Connora2e73802008-02-27 10:27:00 -050059 printf("\n\n");
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050060}
61
62static void
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050063try_boot(u16 seq_nr)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050064{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050065 SET_IPL(sequence, seq_nr);
66 u16 bootseg;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050067 u8 bootdrv = 0;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050068 u16 bootdev, bootip;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050069
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050070 if (CONFIG_ELTORITO_BOOT) {
71 bootdev = inb_cmos(CMOS_BIOS_BOOTFLAG2);
72 bootdev |= ((inb_cmos(CMOS_BIOS_BOOTFLAG1) & 0xf0) << 4);
73 bootdev >>= 4 * seq_nr;
74 bootdev &= 0xf;
75 if (bootdev == 0)
76 BX_PANIC("No bootable device.\n");
77
78 /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
79 bootdev -= 1;
80 } else {
81 if (seq_nr ==2)
82 BX_PANIC("No more boot devices.");
83 if (!!(inb_cmos(CMOS_BIOS_CONFIG) & 0x20) ^ (seq_nr == 1))
84 /* Boot from floppy if the bit is set or it's the second boot */
85 bootdev = 0x00;
86 else
87 bootdev = 0x01;
88 }
89
90 if (bootdev >= GET_IPL(count)) {
91 BX_INFO("Invalid boot device (0x%x)\n", bootdev);
92 return;
93 }
94 u16 type = GET_IPL(table[bootdev].type);
95
96 /* Do the loading, and set up vector as a far pointer to the boot
97 * address, and bootdrv as the boot drive */
98 print_boot_device(type);
99
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500100 struct bregs cr;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500101 switch(type) {
102 case IPL_TYPE_FLOPPY: /* FDD */
103 case IPL_TYPE_HARDDISK: /* HDD */
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500104
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500105 bootdrv = (type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00;
106 bootseg = 0x07c0;
107
108 // Read sector
109 memset(&cr, 0, sizeof(cr));
110 cr.dl = bootdrv;
111 cr.es = bootseg;
112 cr.ah = 2;
113 cr.al = 1;
114 cr.cl = 1;
115 call16_int(0x13, &cr);
116
117 if (cr.flags & F_CF) {
118 print_boot_failure(type, 1);
119 return;
120 }
121
122 /* Always check the signature on a HDD boot sector; on FDD,
123 * only do the check if the CMOS doesn't tell us to skip it */
124 if ((type != IPL_TYPE_FLOPPY)
125 || !((inb_cmos(CMOS_BIOS_BOOTFLAG1) & 0x01))) {
126 if (GET_FARVAR(bootseg, *(u16*)0x1fe) != 0xaa55) {
127 print_boot_failure(type, 0);
128 return;
129 }
130 }
131
132 /* Canonicalize bootseg:bootip */
133 bootip = (bootseg & 0x0fff) << 4;
134 bootseg &= 0xf000;
135 break;
136 case IPL_TYPE_CDROM: /* CD-ROM */
137 // XXX
138 return;
139 break;
140 case IPL_TYPE_BEV: {
141 /* Expansion ROM with a Bootstrap Entry Vector (a far
142 * pointer) */
143 u32 vector = GET_IPL(table[bootdev].vector);
144 bootseg = vector >> 16;
145 bootip = vector & 0xffff;
146 break;
147 }
148 default:
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500149 return;
150 }
151
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500152 memset(&cr, 0, sizeof(cr));
153 cr.ip = bootip;
154 cr.cs = bootseg;
155 // Set the magic number in ax and the boot drive in dl.
156 cr.dl = bootdrv;
157 cr.ax = 0xaa55;
158 call16(&cr);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500159
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500160 // Boot failed: invoke the boot recovery function
161 memset(&cr, 0, sizeof(cr));
162 call16_int(0x18, &cr);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500163}
164
165// Boot Failure recovery: try the next device.
166void VISIBLE
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500167handle_18()
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500168{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500169 debug_enter(NULL);
170 u16 seq = GET_IPL(sequence) + 1;
171 try_boot(seq);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500172}
173
174// INT 19h Boot Load Service Entry Point
175void VISIBLE
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500176handle_19()
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500177{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500178 debug_enter(NULL);
179 try_boot(0);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500180}
181
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500182// Called from 32bit code - start boot process
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500183void VISIBLE
184begin_boot()
185{
Kevin O'Connorc65a3802008-03-02 13:58:23 -0500186 if (CONFIG_ATA)
187 ata_detect();
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500188 irq_enable();
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500189 struct bregs br;
190 memset(&br, 0, sizeof(br));
191 call16_int(0x19, &br);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500192}