#ident "$Id$"
/* ----------------------------------------------------------------------- *
*
- * Copyright 2003-2004 H. Peter Anvin - All Rights Reserved
+ * Copyright 2003-2005 H. Peter Anvin - All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*
* ... e.g. "chain hd0 1" will boot the first partition on the first hard disk.
*
- * Only partitions 1-4 supported at this time; 0 = boot MBR (default.)
+ * Partitions 1-4 are primary, 5+ logical, 0 = boot MBR (default.)
*/
#include <com32.h>
static inline void error(const char *msg)
{
- puts(msg);
+ fputs(msg, stderr);
}
/*
if ( !outreg ) outreg = &tmpregs;
- while ( retry ) {
+ while ( retry-- ) {
__intcall(0x13, inreg, outreg);
- if ( (outreg->eflags.l & 1) == 0 )
+ if ( !(outreg->eflags.l & EFLAGS_CF) )
return 0; /* CF=0, OK */
}
*/
struct diskinfo {
int disk;
+ int ebios; /* EBIOS supported on this disk */
+ int cbios; /* CHS geometry is valid */
int head;
int sect;
- int ebios;
} disk_info;
int get_disk_params(int disk)
{
- com32sys_t getparm, parm, getebios, ebios;
-
- memset(&getparm, 0, sizeof getparm);
- memset(&getebios, 0, sizeof getebios);
- memset(&disk_info, 0, sizeof disk_info);
+ static com32sys_t getparm, parm, getebios, ebios;
disk_info.disk = disk;
- if ( disk & 0x80 ) {
- /* Get disk parameters -- hard drives only */
-
- getparm.eax.b[1] = 0x08;
- getparm.edx.b[0] = disk;
- if ( int13_retry(&getparm, &parm) )
- return -1;
-
- disk_info.head = parm.edx.b[1]+1;
- disk_info.sect = parm.ecx.b[0] & 0x3f;
-
- /* Get EBIOS support */
-
- getebios.eax.w[0] = 0x4100;
- getebios.edx.b[0] = disk;
- getebios.ebx.w[0] = 0x55aa;
- getebios.eflags.b[0] = 0x3; /* CF set */
- if ( !int13_retry(&getebios, &ebios) ) {
- if ( ebios.ebx.w[0] == 0xaa55 &&
- (ebios.ecx.b[0] & 1) )
- disk_info.ebios = 1;
- }
+ /* Get EBIOS support */
+ getebios.eax.w[0] = 0x4100;
+ getebios.ebx.w[0] = 0x55aa;
+ getebios.edx.b[0] = disk;
+ getebios.eflags.b[0] = 0x3; /* CF set */
+
+ __intcall(0x13, &getebios, &ebios);
+
+ if ( !(ebios.eflags.l & EFLAGS_CF) &&
+ ebios.ebx.w[0] == 0xaa55 &&
+ (ebios.ecx.b[0] & 1) ) {
+ disk_info.ebios = 1;
+ }
+
+ /* Get disk parameters -- really only useful for
+ hard disks, but if we have a partitioned floppy
+ it's actually our best chance... */
+ getparm.eax.b[1] = 0x08;
+ getparm.edx.b[0] = disk;
+
+ __intcall(0x13, &getparm, &parm);
+
+ if ( parm.eflags.l & EFLAGS_CF )
+ return disk_info.ebios ? 0 : -1;
+
+ disk_info.head = parm.edx.b[1]+1;
+ disk_info.sect = parm.ecx.b[0] & 0x3f;
+ if ( disk_info.sect == 0 ) {
+ disk_info.sect = 1;
+ } else {
+ disk_info.cbios = 1; /* Valid geometry */
}
return 0;
} else {
unsigned int c, h, s, t;
- s = (lba % disk_info.sect) + 1;
- t = lba / disk_info.sect; /* Track = head*cyl */
- h = t % disk_info.head;
- c = t / disk_info.head;
+ if ( !disk_info.cbios ) {
+ /* We failed to get the geometry */
+
+ if ( lba )
+ return -1; /* Can only read MBR */
+
+ s = 1; h = 0; c = 0;
+ } else {
+ s = (lba % disk_info.sect) + 1;
+ t = lba / disk_info.sect; /* Track = head*cyl */
+ h = t % disk_info.head;
+ c = t / disk_info.head;
+ }
if ( s > 63 || h > 256 || c > 1023 )
return -1;
}
-int main(void)
+int main(int argc, char *argv[])
{
char *mbr, *boot_sector = NULL;
struct part_entry *partinfo;
- char *cmdline = __com32.cs_cmdline;
+ char *drivename, *partition;
int hd, drive, whichpart;
static com32sys_t inreg; /* In bss, so zeroed automatically */
openconsole(&dev_null_r, &dev_stdcon_w);
- /* Parse command line */
- while ( isspace(*cmdline) )
- cmdline++;
+ if ( argc < 2 ) {
+ error("Usage: chain.c32 (hd|fd)# [partition]\n");
+ goto bail;
+ }
+
+ drivename = argv[1];
+ partition = argv[2]; /* Possibly null */
hd = 0;
- if ( (cmdline[0] == 'h' || cmdline[0] == 'f') &&
- cmdline[1] == 'd' ) {
- hd = cmdline[0] == 'h';
- cmdline += 2;
+ if ( (drivename[0] == 'h' || drivename[0] == 'f') &&
+ drivename[1] == 'd' ) {
+ hd = drivename[0] == 'h';
+ drivename += 2;
}
- drive = (hd ? 0x80 : 0) | strtoul(cmdline, &cmdline, 0);
+ drive = (hd ? 0x80 : 0) | strtoul(drivename, NULL, 0);
whichpart = 0; /* Default */
- if ( isspace(*cmdline) ) {
- while ( isspace(*cmdline) )
- cmdline++;
-
- whichpart = strtoul(cmdline, NULL, 0);
- }
+ if ( partition )
+ whichpart = strtoul(partition, NULL, 0);
- if ( !(drive & 0x80) && whichpart != 0 ) {
- error("Partitions not supported on floppy drives\n");
- goto bail;
+ if ( !(drive & 0x80) && whichpart ) {
+ error("Warning: Partitions of floppy devices may not work\n");
}
/* Divvy up the bounce buffer. To keep things sector-
dapa = (struct ebios_dapa *)__com32.cs_bounce;
mbr = (char *)__com32.cs_bounce + SECTOR;
- /* Get the MBR */
- if ( get_disk_params(drive) ) {
+ /* Get the disk geometry (not needed for MBR) */
+ if ( get_disk_params(drive) && whichpart ) {
error("Cannot get disk parameters\n");
goto bail;
}
+ /* Get MBR */
if ( read_sector(mbr, 0) ) {
- error("Cannot read MBR\n");
+ error("Cannot read Master Boot Record\n");
goto bail;
}
inreg.esi.w[0] = 0x7be;
memcpy((char *)0x7be, partinfo, sizeof(*partinfo));
}
+
+ fputs("Booting...\n", stdout);
+
inreg.eax.w[0] = 0x000d; /* Clean up and chain boot */
inreg.edx.w[0] = 0; /* Should be 3 for "keeppxe" */
inreg.edi.l = (uint32_t)boot_sector;
; network booting API. It is based on the SYSLINUX boot loader for
; MS-DOS floppies.
;
-; Copyright (C) 1994-2004 H. Peter Anvin
+; Copyright (C) 1994-2005 H. Peter Anvin
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
PathPrefix resb 256 ; Path prefix derived from boot file
DotQuadBuf resb 16 ; Buffer for dotted-quad IP address
IPOption resb 80 ; ip= option buffer
+InitStack resd 1 ; Pointer to reset stack
; Warning here: RBFG build 22 randomly overwrites memory location
; [0x5680,0x576c), possibly more. It seems that it gets confused and
section .bss
alignb 4
-InitStack resd 1 ; Pointer to reset stack
RebootTime resd 1 ; Reboot timeout, if set by option
StrucPtr resd 1 ; Pointer to PXENV+ or !PXE structure
APIVer resw 1 ; PXE API version found
section .text
;
; PXELINUX needs more BSS than the other derivatives;
- ; therefore we relocate it from 7C00h on startup
+ ; therefore we relocate it from 7C00h on startup.
;
-StackBuf equ $-44 ; Base of stack if we use our own
+StackBuf equ $ ; Base of stack if we use our own
;
; Primary entry point.
mov eax,[es:bx+0Ah] ; PXE RM API
mov [PXENVEntry],eax
- mov si,undi_data_msg ; ***
+ mov si,undi_data_msg
call writestr
mov ax,[es:bx+20h]
call writehex4
mov eax,[es:bx+10h]
mov [PXEEntry],eax
- mov si,undi_data_msg ; ***
+ mov si,undi_data_msg
call writestr
mov eax,[es:bx+2Ah]
call writehex8
jmp .call_loop
.call_done:
-%if USE_PXE_PROVIDED_STACK
+;
+; This isn't necessary anymore; we can use the memory area previously
+; used by the PXE stack indefinitely, and the chainload code sets up
+; a new stack independently. Leave the source code in here for now,
+; but expect to rip it out soonish.
+;
+%if 0 ; USE_PXE_PROVIDED_STACK
; We need to switch to our local stack here...
pusha
pushf