VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS-new/boot.c@ 40754

Last change on this file since 40754 was 40754, checked in by vboxsync, 12 years ago

BIOS: Do a basic sanity check on floppy boot sectors, too.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.1 KB
Line 
1/*
2 * Copyright (C) 2006-2011 Oracle Corporation
3 *
4 * This file is part of VirtualBox Open Source Edition (OSE), as
5 * available from http://www.virtualbox.org. This file is free software;
6 * you can redistribute it and/or modify it under the terms of the GNU
7 * General Public License (GPL) as published by the Free Software
8 * Foundation, in version 2 as it comes in the "COPYING" file of the
9 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
10 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
11 * --------------------------------------------------------------------
12 *
13 * This code is based on:
14 *
15 * ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
16 *
17 * Copyright (C) 2002 MandrakeSoft S.A.
18 *
19 * MandrakeSoft S.A.
20 * 43, rue d'Aboukir
21 * 75002 Paris - France
22 * http://www.linux-mandrake.com/
23 * http://www.mandrakesoft.com/
24 *
25 * This library is free software; you can redistribute it and/or
26 * modify it under the terms of the GNU Lesser General Public
27 * License as published by the Free Software Foundation; either
28 * version 2 of the License, or (at your option) any later version.
29 *
30 * This library is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
33 * Lesser General Public License for more details.
34 *
35 * You should have received a copy of the GNU Lesser General Public
36 * License along with this library; if not, write to the Free Software
37 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
38 *
39 */
40
41
42#include <stdint.h>
43#include <string.h>
44#include "inlines.h"
45#include "biosint.h"
46#include "ebda.h"
47
48
49/* PnP header used with LAN boot ROMs. */
50typedef struct {
51 uint32_t sig;
52 uint8_t revision;
53 uint8_t length;
54 uint16_t next_s;
55 uint8_t pad1;
56 uint8_t checksum;
57 uint32_t dev_id;
58 uint16_t mfg_string;
59 uint16_t prod_string;
60 uint8_t base_class;
61 uint8_t subclass;
62 uint8_t interface;
63 uint8_t dev_ind;
64 uint16_t boot_code;
65 uint16_t dv;
66 uint16_t bev;
67 uint16_t pad2;
68 uint16_t sriv;
69} pnp_exp_t;
70
71
72int read_boot_sec(uint8_t bootdrv, uint16_t segment);
73#pragma aux read_boot_sec = \
74 "mov ax,0201h" \
75 "mov dh,0" \
76 "mov cx,1" \
77 "xor bx,bx" \
78 "int 13h" \
79 "mov ax,0" \
80 "sbb ax,0" \
81 parm [dl] [es] modify [ax bx cx dx];
82
83//--------------------------------------------------------------------------
84// print_boot_device
85// displays the boot device
86//--------------------------------------------------------------------------
87
88static const char drivetypes[][10]={"Floppy","Hard Disk","CD-ROM","LAN"};
89
90//@todo: pass inputs as bit flags rather than bytes?
91void print_boot_device(uint8_t cdboot, uint8_t lanboot, uint8_t drive)
92{
93 int i;
94
95 // cdboot contains 0 if lan/floppy/harddisk, 1 otherwise
96 // lanboot contains 0 if floppy/harddisk, 1 otherwise
97 // drive contains real/emulated boot drive
98
99 if(cdboot)i=2; // CD-Rom
100 else if(lanboot)i=3; // LAN
101 else if((drive&0x0080)==0x00)i=0; // Floppy
102 else if((drive&0x0080)==0x80)i=1; // Hard drive
103 else return;
104
105 BX_INFO("Booting from %s...\n",drivetypes[i]);
106}
107
108//--------------------------------------------------------------------------
109// print_boot_failure
110// displays the reason why boot failed
111//--------------------------------------------------------------------------
112//@todo: pass inputs as bit flags rather than bytes?
113void print_boot_failure(uint8_t cdboot, uint8_t lanboot, uint8_t drive,
114 uint8_t reason, uint8_t lastdrive)
115{
116 uint16_t drivenum = drive&0x7f;
117
118 // cdboot: 1 if boot from cd, 0 otherwise
119 // lanboot: 1 if boot from lan, 0 otherwise
120 // drive : drive number
121 // reason: 0 signature check failed, 1 read error
122 // lastdrive: 1 boot drive is the last one in boot sequence
123
124 if (cdboot)
125 BX_INFO("Boot from %s failed\n",drivetypes[2]);
126 else if (lanboot)
127 BX_INFO("Boot from %s failed\n",drivetypes[3]);
128 else if (drive & 0x80)
129 BX_INFO("Boot from %s %d failed\n", drivetypes[1],drivenum);
130 else
131 BX_INFO("Boot from %s %d failed\n", drivetypes[0],drivenum);
132
133 if (lastdrive==1) {
134 if (reason==0)
135 BX_PANIC("No bootable medium found! System halted.\n");
136 else
137 BX_PANIC("Could not read from the boot medium! System halted.\n");
138 }
139}
140
141//--------------------------------------------------------------------------
142// print_cdromboot_failure
143// displays the reason why boot failed
144//--------------------------------------------------------------------------
145void print_cdromboot_failure(uint16_t code)
146{
147 BX_INFO("CDROM boot failure code : %04x\n",code);
148 return;
149}
150
151// returns bootsegment in ax, drive in bl
152uint32_t BIOSCALL int19_function(uint8_t bseqnr)
153{
154 //@todo: common code for getting the EBDA segment
155 uint16_t ebda_seg=read_word(0x0040,0x000E);
156 uint16_t bootseq;
157 uint8_t bootdrv;
158 uint8_t bootcd;
159 uint8_t bootlan;
160 uint8_t bootchk;
161 uint16_t bootseg;
162 uint16_t status;
163 uint8_t lastdrive=0;
164
165 // if BX_ELTORITO_BOOT is not defined, old behavior
166 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
167 // in preparation for the initial INT 13h (0=floppy A:, 0x80=C:)
168 // 0: system boot sequence, first drive C: then A:
169 // 1: system boot sequence, first drive A: then C:
170 // else BX_ELTORITO_BOOT is defined
171 // CMOS regs 0x3D and 0x38 contain the boot sequence:
172 // CMOS reg 0x3D & 0x0f : 1st boot device
173 // CMOS reg 0x3D & 0xf0 : 2nd boot device
174 // CMOS reg 0x38 & 0xf0 : 3rd boot device
175 // CMOS reg 0x3C & 0x0f : 4th boot device
176 // boot device codes:
177 // 0x00 : not defined
178 // 0x01 : first floppy
179 // 0x02 : first harddrive
180 // 0x03 : first cdrom
181 // 0x04 : local area network
182 // else : boot failure
183
184 // Get the boot sequence
185#if BX_ELTORITO_BOOT
186 bootseq=inb_cmos(0x3d);
187 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
188 bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
189 if (read_byte(ebda_seg, (uint16_t)&EbdaData->uForceBootDevice))
190 bootseq = read_byte(ebda_seg, (uint16_t)&EbdaData->uForceBootDevice);
191 /* Boot delay hack. */
192 if (bseqnr == 1)
193 delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
194
195 if (bseqnr==2) bootseq >>= 4;
196 if (bseqnr==3) bootseq >>= 8;
197 if (bseqnr==4) bootseq >>= 12;
198 if (bootseq<0x10) lastdrive = 1;
199 bootdrv=0x00; bootcd=0;
200 bootlan=0;
201 BX_INFO("Boot : bseqnr=%d, bootseq=%x\r\n",bseqnr, bootseq);
202
203 switch(bootseq & 0x0f) {
204 case 0x01:
205 bootdrv=0x00;
206 bootcd=0;
207 break;
208 case 0x02:
209 {
210 // Get the Boot drive.
211 uint8_t boot_drive = read_byte(ebda_seg, (uint16_t)&EbdaData->uForceBootDrive);
212
213 bootdrv = boot_drive + 0x80;
214 bootcd=0;
215 break;
216 }
217 case 0x03:
218 bootdrv=0x00;
219 bootcd=1;
220 break;
221 case 0x04: bootlan=1; break;
222 default: return 0x00000000;
223 }
224#else
225 bootseq=inb_cmos(0x2d);
226
227 if (bseqnr==2) {
228 bootseq ^= 0x20;
229 lastdrive = 1;
230 }
231 bootdrv=0x00; bootcd=0;
232 if((bootseq&0x20)==0) bootdrv=0x80;
233#endif // BX_ELTORITO_BOOT
234
235#if BX_ELTORITO_BOOT
236 // We have to boot from cd
237 if (bootcd != 0) {
238 status = cdrom_boot();
239
240 // If failure
241 if ( (status & 0x00ff) !=0 ) {
242 print_cdromboot_failure(status);
243 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
244 return 0x00000000;
245 }
246
247 bootseg = read_word(ebda_seg,(uint16_t)&EbdaData->cdemu.load_segment);
248 bootdrv = (uint8_t)(status>>8);
249 }
250
251#endif // BX_ELTORITO_BOOT
252
253 // Check for boot from LAN first
254 if (bootlan == 1) {
255 uint8_t __far *fplan;
256
257 fplan = MK_FP(VBOX_LANBOOT_SEG, 0);
258 if (*(uint16_t __far *)fplan == 0xaa55) {
259 pnp_exp_t __far *pnps;
260 uint32_t manuf;
261 void (__far *netboot_entry)(void);
262
263 // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
264 pnps = (void __far *)(fplan + *(uint16_t __far *)(fplan + 0x1a));
265 if (pnps->sig == 0x506e5024/* '$PnP' */) {
266 // Found PnP signature
267 manuf = *(uint32_t __far *)(fplan + pnps->mfg_string);
268 if (manuf == 0x65687445/* 'Ethe' */) {
269 // Found Etherboot ROM
270 print_boot_device(bootcd, bootlan, bootdrv);
271 netboot_entry = (void __far *)(fplan + 6);
272 netboot_entry();
273 } else if (manuf == 0x65746E49/* 'Inte' */) {
274 // Found Intel PXE ROM
275 print_boot_device(bootcd, bootlan, bootdrv);
276 int_enable(); /* Disabled as we were invoked via INT instruction. */
277 netboot_entry = (void __far *)(fplan + pnps->bev);
278 netboot_entry();
279 }
280 }
281 }
282
283 // boot from LAN will not return if successful.
284 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
285 return 0x00000000;
286 }
287
288 // We have to boot from harddisk or floppy
289 if (bootcd == 0 && bootlan == 0) {
290 bootseg=0x07c0;
291
292 status = read_boot_sec(bootdrv,bootseg);
293 if (status != 0) {
294 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
295 return 0x00000000;
296 }
297 }
298
299 // There is *no* requirement whatsoever for a valid floppy boot sector
300 // to have a 55AAh signature. UNIX boot floppies typically have no such
301 // signature. In general, it is impossible to tell a valid bootsector
302 // from an invalid one.
303 // NB: It is somewhat common for failed OS installs to have the
304 // 0x55AA signature and a valid partition table but zeros in the
305 // rest of the boot sector. We do a quick check by comparing the first
306 // two words of boot sector; if identical, the boot sector is
307 // extremely unlikely to be valid.
308 if (bootdrv != 0) bootchk = 0;
309 else bootchk = 1; /* disable 0x55AA signature check on drive A: */
310
311#if BX_ELTORITO_BOOT
312 // if boot from cd, no signature check
313 if (bootcd != 0)
314 bootchk = 1;
315#endif // BX_ELTORITO_BOOT
316
317 if (read_word(bootseg,0) == read_word(bootseg,2)
318 || (bootchk == 0 && read_word(bootseg,0x1fe) != 0xaa55))
319 {
320 print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
321 return 0x00000000;
322 }
323
324#if BX_ELTORITO_BOOT
325 // Print out the boot string
326 print_boot_device(bootcd, bootlan, bootdrv);
327#else // BX_ELTORITO_BOOT
328 print_boot_device(0, bootlan, bootdrv);
329#endif // BX_ELTORITO_BOOT
330
331 // return the boot segment
332 return (((uint32_t)bootdrv) << 16) + bootseg;
333}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use