diff options
-rw-r--r-- | doc/memdisk.txt | 1 | ||||
-rw-r--r-- | memdisk/Makefile | 10 | ||||
-rw-r--r-- | memdisk/bda.h | 56 | ||||
-rw-r--r-- | memdisk/dskprobe.c | 114 | ||||
-rw-r--r-- | memdisk/dskprobe.h | 21 | ||||
-rw-r--r-- | memdisk/eltorito.c | 58 | ||||
-rw-r--r-- | memdisk/eltorito.h | 83 | ||||
-rw-r--r-- | memdisk/memdisk.inc | 83 | ||||
-rw-r--r-- | memdisk/memdisk_chs.asm | 3 | ||||
-rw-r--r-- | memdisk/memdisk_chs_512.asm | 5 | ||||
-rw-r--r-- | memdisk/memdisk_edd.asm | 3 | ||||
-rw-r--r-- | memdisk/memdisk_edd_512.asm | 5 | ||||
-rw-r--r-- | memdisk/memdisk_iso_2048.asm | 5 | ||||
-rw-r--r-- | memdisk/memdisk_iso_512.asm | 5 | ||||
-rw-r--r-- | memdisk/setup.c | 275 |
15 files changed, 625 insertions, 102 deletions
diff --git a/doc/memdisk.txt b/doc/memdisk.txt index 58ec748b..8a308f10 100644 --- a/doc/memdisk.txt +++ b/doc/memdisk.txt @@ -75,6 +75,7 @@ b) If the disk image is less than 4,194,304 bytes (4096K, 4 MB) it is s=# Specify number of sectors (max 63) floppy[=#] The image is a floppy image[**] harddisk[=#] The image is a hard disk image[**] + iso The image is an El Torito ISO9660 image (drive 0xE0) # represents a decimal number. diff --git a/memdisk/Makefile b/memdisk/Makefile index d185d87c..09f17c8e 100644 --- a/memdisk/Makefile +++ b/memdisk/Makefile @@ -38,11 +38,15 @@ endif # Important: init.o16 must be first!! OBJS16 = init.o16 init32.o OBJS32 = start32.o setup.o msetup.o e820func.o conio.o memcpy.o memset.o \ - memmove.o unzip.o memdisk_chs.o memdisk_edd.o + memmove.o unzip.o dskprobe.o eltorito.o \ + memdisk_chs_512.o memdisk_edd_512.o \ + memdisk_iso_512.o memdisk_iso_2048.o -CSRC = setup.c msetup.c e820func.c conio.c unzip.c +CSRC = setup.c msetup.c e820func.c conio.c unzip.c dskprobe.c eltorito.c SSRC = start32.S memcpy.S memset.S memmove.S -NASMSRC = memdisk_chs.asm memdisk_edd.asm memdisk16.asm +NASMSRC = memdisk_chs_512.asm memdisk_edd_512.asm \ + memdisk_iso_512.asm memdisk_iso_2048.asm \ + memdisk16.asm all: memdisk # e820test diff --git a/memdisk/bda.h b/memdisk/bda.h new file mode 100644 index 00000000..cfac441f --- /dev/null +++ b/memdisk/bda.h @@ -0,0 +1,56 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2001-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: 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 + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include <stdint.h> + +/* Addresses in the zero page */ +#define BIOS_INT13 (0x13*4) /* INT 13h vector */ +#define BIOS_INT15 (0x15*4) /* INT 15h vector */ +#define BIOS_INT1E (0x1E*4) /* INT 1Eh vector */ +#define BIOS_INT40 (0x40*4) /* INT 13h vector */ +#define BIOS_INT41 (0x41*4) /* INT 41h vector */ +#define BIOS_INT46 (0x46*4) /* INT 46h vector */ +#define BIOS_BASEMEM 0x413 /* Amount of DOS memory */ +#define BIOS_EQUIP 0x410 /* BIOS equipment list */ +#define BIOS_HD_COUNT 0x475 /* Number of hard drives present */ + +/* Access to objects in the zero page */ +static inline void wrz_8(uint32_t addr, uint8_t data) +{ + *((uint8_t *) addr) = data; +} + +static inline void wrz_16(uint32_t addr, uint16_t data) +{ + *((uint16_t *) addr) = data; +} + +static inline void wrz_32(uint32_t addr, uint32_t data) +{ + *((uint32_t *) addr) = data; +} + +static inline uint8_t rdz_8(uint32_t addr) +{ + return *((uint8_t *) addr); +} + +static inline uint16_t rdz_16(uint32_t addr) +{ + return *((uint16_t *) addr); +} + +static inline uint32_t rdz_32(uint32_t addr) +{ + return *((uint32_t *) addr); +} diff --git a/memdisk/dskprobe.c b/memdisk/dskprobe.c new file mode 100644 index 00000000..de858bb9 --- /dev/null +++ b/memdisk/dskprobe.c @@ -0,0 +1,114 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Shao Miller - 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 + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * dskprobe.c + * + * Routines for probing BIOS disk drives + */ + +/* + * Uncomment for debugging + * + * #define DBG_DSKPROBE 1 + */ + +#include <stdint.h> +#include "memdisk.h" +#include "bda.h" +#include "conio.h" + +/* + * We will probe a BIOS drive numer using INT 13h, AH=probe + * and will pass along that call's success or failure + */ +int probe_int13_ah(uint8_t drive, uint8_t probe) +{ + int err; + com32sys_t regs; + + memset(®s, 0, sizeof regs); + + regs.eax.b[1] = probe; /* AH = probe */ + regs.edx.b[0] = drive; /* DL = drive number to probe */ + intcall(0x13, ®s, ®s); + + err = !(regs.eflags.l & 1); +#ifdef DBG_DSKPROBE + printf("probe_int13_ah(0x%02x, 0x%02x) == %d\n", drive, probe, err); +#endif + return err; +} + +/* + * We will probe the BIOS Data Area and count the drives found there. + * This heuristic then assumes that all drives of 'drive's type are + * found in a contiguous range, and returns 1 if the probed drive + * is less than or equal to the BDA count. + * This particular function's code is derived from code in setup.c by + * H. Peter Anvin. Please respect that file's copyright for this function + */ +int probe_bda_drive(uint8_t drive) +{ + int bios_drives; + int err; + + if (drive & 0x80) { + bios_drives = rdz_8(BIOS_HD_COUNT); /* HDD count */ + } else { + uint8_t equip = rdz_8(BIOS_EQUIP); + if (equip & 1) + bios_drives = (equip >> 6) + 1; /* Floppy count */ + else + bios_drives = 0; + } + err = (drive - (drive & 0x80)) >= bios_drives ? 0 : 1; +#ifdef DBG_DSKPROBE + printf("probe_bda_drive(0x%02x) == %d, count: %d\n", + drive, err, bios_drives); +#endif + return err; +} + +/* + * We will probe a drive with a few different methods, returning + * the count of succesful probes + */ +int probe_drive(uint8_t drive) +{ + int c = 0; + /* Only probe the BDA for floppies */ + if (drive & 0x80) { + c += probe_int13_ah(drive, 0x08); + c += probe_int13_ah(drive, 0x15); + c += probe_int13_ah(drive, 0x41); + } + c += probe_bda_drive(drive); + return c; +} + +/* + * We will probe a contiguous range of BIOS drive, starting with drive + * number 'start'. We probe with a few different methods, and return + * the first drive which doesn't respond to any of the probes. + */ +uint8_t probe_drive_range(uint8_t start) +{ + uint8_t drive = start; + while (probe_drive(drive)) { + drive++; + /* Check for passing the floppy/HDD boundary */ + if ((drive & 0x7F) == 0) + break; + } + return drive; +} diff --git a/memdisk/dskprobe.h b/memdisk/dskprobe.h new file mode 100644 index 00000000..99bfa666 --- /dev/null +++ b/memdisk/dskprobe.h @@ -0,0 +1,21 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Shao Miller - 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 + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * dskprobe.h + * + * Routines for probing BIOS disk drives + */ + +#include <stdint.h> + +extern uint8_t probe_drive_range(uint8_t); diff --git a/memdisk/eltorito.c b/memdisk/eltorito.c new file mode 100644 index 00000000..7e0ba89b --- /dev/null +++ b/memdisk/eltorito.c @@ -0,0 +1,58 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Shao Miller - 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 + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * eltorito.c + * + * EDD-4 El Torito structures and debugging routines + */ + +#include <stdint.h> +#include "memdisk.h" +#include "conio.h" +#include "eltorito.h" + +#ifdef DBG_ELTORITO +void eltorito_dump(uint32_t image) +{ + printf("-- El Torito dump --\n", image); + + /* BVD starts at sector 17. */ + struct edd4_bvd *bvd = (struct edd4_bvd *)(image + 17 * 2048); + + printf("bvd.boot_rec_ind: 0x%02x\n", bvd->boot_rec_ind); + printf("bvd.iso9660_id: %c%c%c%c%c\n", bvd->iso9660_id[0], + bvd->iso9660_id[1], bvd->iso9660_id[2], bvd->iso9660_id[3], + bvd->iso9660_id[4]); + printf("bvd.ver: 0x%02x\n", bvd->ver); + printf("bvd.eltorito: %s\n", bvd->eltorito); + printf("bvd.boot_cat: 0x%08x\n", bvd->boot_cat); + + struct edd4_bootcat *boot_cat = + (struct edd4_bootcat *)(image + bvd->boot_cat * 2048); + + printf("boot_cat.validation_entry\n"); + printf(" .header_id: 0x%02x\n", boot_cat->validation_entry.header_id); + printf(" .platform_id: 0x%02x\n", boot_cat->validation_entry.platform_id); + printf(" .id_string: %s\n", boot_cat->validation_entry.id_string); + printf(" .checksum: 0x%04x\n", boot_cat->validation_entry.checksum); + printf(" .key55: 0x%02x\n", boot_cat->validation_entry.key55); + printf(" .keyAA: 0x%02x\n", boot_cat->validation_entry.keyAA); + printf("boot_cat.initial_entry\n"); + printf(" .header_id: 0x%02x\n", boot_cat->initial_entry.header_id); + printf(" .media_type: 0x%02x\n", boot_cat->initial_entry.media_type); + printf(" .load_seg: 0x%04x\n", boot_cat->initial_entry.load_seg); + printf(" .system_type: 0x%02x\n", boot_cat->initial_entry.system_type); + printf(" .sect_count: %d\n", boot_cat->initial_entry.sect_count); + printf(" .load_block: 0x%08x\n", boot_cat->initial_entry.load_block); +} +#endif diff --git a/memdisk/eltorito.h b/memdisk/eltorito.h new file mode 100644 index 00000000..7d46e1d9 --- /dev/null +++ b/memdisk/eltorito.h @@ -0,0 +1,83 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Shao Miller - 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 + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * eltorito.h + * + * EDD-4 El Torito structures and debugging routines + */ + +#include <stdint.h> + +/* + * Uncomment for El Torito debugging + * + * #define DBG_ELTORITO 1 + */ + +#ifdef DBG_ELTORITO +extern void eltorito_dump(uint32_t); +#endif + +/* EDD-4 Bootable Optical Disc Drive Boot Volume Descriptor */ +struct edd4_bvd { + uint8_t boot_rec_ind; /* Boot Record Indicator */ + uint8_t iso9660_id[5]; /* ISO9660 ID */ + uint8_t ver; /* Descriptor Version */ + uint8_t eltorito[32]; /* "EL TORITO" etc. */ + uint8_t res1[32]; /* Reserved */ + uint32_t boot_cat; /* Boot catalog sector */ + uint8_t res2[1973]; /* Reserved */ +} __attribute__ ((packed)); + +struct validation_entry { + uint8_t header_id; /* Header ID */ + uint8_t platform_id; /* Platform ID */ + uint16_t res1; /* Reserved */ + uint8_t id_string[24]; /* Manufacturer */ + uint16_t checksum; /* Sums with whole record to zero */ + uint8_t key55; /* Key byte 0x55 */ + uint8_t keyAA; /* Key byte 0xAA */ +} __attribute__ ((packed)); + +struct initial_entry { + uint8_t header_id; /* Header ID */ + uint8_t media_type; /* Media type */ + uint16_t load_seg; /* Load segment */ + uint8_t system_type; /* (Filesystem ID) */ + uint8_t res1; /* Reserved */ + uint16_t sect_count; /* Emulated sectors to load */ + uint32_t load_block; /* Starting sector of image */ + uint8_t res2[4]; /* Reserved */ +} __attribute__ ((packed)); + +/* EDD-4 Bootable Optical Disc Drive Boot Catalog (fixed-size portions) */ +struct edd4_bootcat { + struct validation_entry validation_entry; + struct initial_entry initial_entry; +} __attribute__ ((packed)); + +/* EDD-4 CD Specification Packet */ +struct edd4_cd_pkt { + uint8_t size; /* Packet size */ + uint8_t type; /* Boot media type (flags) */ + uint8_t driveno; /* INT 13h drive number */ + uint8_t controller; /* Controller index */ + uint32_t start; /* Starting LBA of image */ + uint16_t devno; /* Device number */ + uint16_t userbuf; /* User buffer segment */ + uint16_t load_seg; /* Load segment */ + uint16_t sect_count; /* Emulated sectors to load */ + uint8_t geom1; /* Cylinders bits 0 thru 7 */ + uint8_t geom2; /* Sects/track 0 thru 5, cyls 8, 9 */ + uint8_t geom3; /* Heads */ +} __attribute__ ((packed)); diff --git a/memdisk/memdisk.inc b/memdisk/memdisk.inc index 3c79b624..98ad52b7 100644 --- a/memdisk/memdisk.inc +++ b/memdisk/memdisk.inc @@ -8,6 +8,7 @@ ; ; Copyright 2001-2009 H. Peter Anvin - All Rights Reserved ; Copyright 2009 Intel Corporation; author: H. Peter Anvin +; Portions copyright 2009 Shao Miller [El Torito code] ; ; 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 @@ -79,7 +80,6 @@ org 0h -%define SECTORSIZE_LG2 9 ; log2(sector size) %define SECTORSIZE (1 << SECTORSIZE_LG2) ; Parameter registers definition; this is the definition @@ -136,6 +136,10 @@ Int13Start: mov ss,ax mov sp,[cs:MyStack] +%if ELTORITO + cmp word [cs:SavedAX],4a00h ; El Torito function? + jae our_drive ; We grab it +%endif ; See if DL points to our class of device (FD, HD) push dx push dx @@ -147,6 +151,12 @@ Int13Start: jz our_drive ; If ZF=1, we have an exact match cmp dl,[cs:DriveNo] jb .nomatch ; Drive < Our drive + cmp dl,[cs:DriveShiftLimit] + jae .nomatch ; Drive > The maximum drive + ; number that we will shift for. + ; This leaves any higher-up BIOS + ; drives alone, such as an optical + ; disc drive 0xA0 or 0xE0 dec dl ; Drive > Our drive, adjust drive # .nomatch: TRACER '!' @@ -200,6 +210,14 @@ our_drive: ; Note: AX == P_AX here cmp ah,Int13FuncsCnt-1 ja Invalid_jump +%if ELTORITO + mov al,[CD_PKT.type] ; Check if we are in + cmp al,0 ; El Torito no emulation mode + ja .emulation ; No. We support the function + cmp ah,3fh ; Yes. We must not support functions + jbe Invalid_jump ; 0 through 3Fh. Check and decide +.emulation: +%endif xor al,al ; AL = 0 is standard entry condition mov di,ax shr di,7 ; Convert AH to an offset in DI @@ -388,8 +406,9 @@ EDDPresence: jne Invalid mov P_BX,0AA55h ; EDD signature mov P_AX,03000h ; EDD 3.0 - mov P_CX,0003h ; Bit 0 - Fixed disk access subset + mov P_CX,0007h ; Bit 0 - Fixed disk access subset ; Bit 1 - Locking and ejecting subset + ; Bit 2 - EDD subset pop ax ; Drop return address xor ax,ax ; Success jmp DoneWeird ; Success, but AH != 0, sigh... @@ -570,10 +589,31 @@ edd_setup_regs: EDDEject: mov ax,0B200h ; Volume Not Removable ret - +%if ELTORITO +ElToritoTerminate: + TRACER 'T' + mov ax,[cs:SavedAX] + cmp al,1 ; We only support query, not terminate + jne ElToritoErr ; Fail + mov es,P_DS ; Caller's DS:SI pointed to packet + mov di,P_SI ; We'll use ES:DI + mov si,CD_PKT.size ; First byte is packet size + xor cx,0 ; Empty our count + ;mov cl,[ds:si] ; We'll copy that many bytes + mov cl,13h + rep movsb ; Copy until CX is zero + mov ax,0 ; Success + ret +ElToritoEmulate: +ElToritoBoot: +ElToritoCatalog: +ElToritoErr: + TRACER '!' + mov ax,100h ; Invalid parameter + ret +%endif ; ELTORITO %endif ; EDD - ; ; INT 15h intercept routines ; @@ -955,7 +995,14 @@ Int13Funcs dw Reset ; 00h - RESET dw EDDSeek ; 47h - EDD SEEK dw EDDGetParms ; 48h - EDD GET PARAMETERS dw EDDDetectChange ; 49h - EDD MEDIA CHANGE STATUS -%endif +%if ELTORITO ; EDD El Torito Functions + ; ELTORITO _must_ also have EDD + dw ElToritoEmulate ; 4Ah - Initiate Disk Emulation + dw ElToritoTerminate ; 4Bh - Terminate Disk Emulation + dw ElToritoBoot ; 4Ch - Initiate Disk Emu. and Reboot + dw ElToritoCatalog ; 4Dh - Return Boot Catalog +%endif ; ELTORITO +%endif ; EDD Int13FuncsEnd equ $ Int13FuncsCnt equ (Int13FuncsEnd-Int13Funcs) >> 1 @@ -1013,6 +1060,13 @@ DPT_ptr dw 0 ; If nonzero, pointer to DPT MDI_Len equ $-MemDisk_Info ; ---- MDI structure ends here --- +DriveShiftLimit db 0ffh ; Installer will [soon] probe for + ; a range of contiguous drives. + ; Any BIOS drives above this region + ; shall not be impacted by our + ; shifting behaviour + db 0 ; pad to a DWORD + dw 0 ; pad to a QWORD MemInt1588 dw 0 ; 1MB-65MB memory amount (1K) Cylinders dw 0 ; Cylinder count @@ -1058,7 +1112,24 @@ EDD_DPT: .res3 db 0 ; Reserved .chksum db 0 ; DPI checksum -%endif +%if ELTORITO +; El Torito CD Specification Packet - mostly filled in by installer +CD_PKT: +.size db 13h ; Packet size (19 bytes) +.type db 0 ; Boot media type (flags) +.driveno db 0E0h ; INT 13h drive number +.controller db 0 ; Controller index +.start dd 0 ; Starting LBA of image +.devno dw 0 ; Device number +.user_buf dw 0 ; User buffer segment +.load_seg dw 0 ; Load segment +.sect_count dw 0 ; Emulated sectors to load +.geom1 db 0 ; Cylinders bits 0 thru 7 +.geom2 db 0 ; Sects/track 0 thru 5, cyls 8, 9 +.geom3 db 0 ; Heads +%endif ; ELTORITO + +%endif ; EDD ; End patch area alignb 4, db 0 diff --git a/memdisk/memdisk_chs.asm b/memdisk/memdisk_chs.asm deleted file mode 100644 index 94dad9db..00000000 --- a/memdisk/memdisk_chs.asm +++ /dev/null @@ -1,3 +0,0 @@ - [map all memdisk_chs.map] -%define EDD 0 -%include "memdisk.inc" diff --git a/memdisk/memdisk_chs_512.asm b/memdisk/memdisk_chs_512.asm new file mode 100644 index 00000000..bb436f35 --- /dev/null +++ b/memdisk/memdisk_chs_512.asm @@ -0,0 +1,5 @@ + [map all memdisk_chs_512.map] +%define EDD 0 +%define ELTORITO 0 +%define SECTORSIZE_LG2 9 ; log2(sector size) +%include "memdisk.inc" diff --git a/memdisk/memdisk_edd.asm b/memdisk/memdisk_edd.asm deleted file mode 100644 index 6f909d74..00000000 --- a/memdisk/memdisk_edd.asm +++ /dev/null @@ -1,3 +0,0 @@ - [map all memdisk_edd.map] -%define EDD 1 -%include "memdisk.inc" diff --git a/memdisk/memdisk_edd_512.asm b/memdisk/memdisk_edd_512.asm new file mode 100644 index 00000000..3a6d5ca1 --- /dev/null +++ b/memdisk/memdisk_edd_512.asm @@ -0,0 +1,5 @@ + [map all memdisk_edd_512.map] +%define EDD 1 +%define ELTORITO 0 +%define SECTORSIZE_LG2 9 ; log2(sector size) +%include "memdisk.inc" diff --git a/memdisk/memdisk_iso_2048.asm b/memdisk/memdisk_iso_2048.asm new file mode 100644 index 00000000..0c8ffee3 --- /dev/null +++ b/memdisk/memdisk_iso_2048.asm @@ -0,0 +1,5 @@ + [map all memdisk_iso_2048.map] +%define EDD 1 +%define ELTORITO 1 +%define SECTORSIZE_LG2 11 ; log2(sector size) +%include "memdisk.inc" diff --git a/memdisk/memdisk_iso_512.asm b/memdisk/memdisk_iso_512.asm new file mode 100644 index 00000000..1555b772 --- /dev/null +++ b/memdisk/memdisk_iso_512.asm @@ -0,0 +1,5 @@ + [map all memdisk_iso_512.map] +%define EDD 1 +%define ELTORITO 1 +%define SECTORSIZE_LG2 9 ; log2(sector size) +%include "memdisk.inc" diff --git a/memdisk/setup.c b/memdisk/setup.c index 52781694..40f3f8c5 100644 --- a/memdisk/setup.c +++ b/memdisk/setup.c @@ -2,6 +2,7 @@ * * Copyright 2001-2009 H. Peter Anvin - All Rights Reserved * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * Portions copyright 2009 Shao Miller [El Torito code] * * 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 @@ -12,7 +13,10 @@ * ----------------------------------------------------------------------- */ #include <stdint.h> +#include "bda.h" +#include "dskprobe.h" #include "e820.h" +#include "eltorito.h" #include "conio.h" #include "version.h" #include "memdisk.h" @@ -22,12 +26,18 @@ const char memdisk_version[] = "MEMDISK " VERSION_STR " " DATE; const char copyright[] = "Copyright " FIRSTYEAR "-" YEAR_STR " H. Peter Anvin et al"; -extern const char _binary_memdisk_chs_bin_start[]; -extern const char _binary_memdisk_chs_bin_end[]; -extern const char _binary_memdisk_chs_bin_size[]; -extern const char _binary_memdisk_edd_bin_start[]; -extern const char _binary_memdisk_edd_bin_end[]; -extern const char _binary_memdisk_edd_bin_size[]; +extern const char _binary_memdisk_chs_512_bin_start[]; +extern const char _binary_memdisk_chs_512_bin_end[]; +extern const char _binary_memdisk_chs_512_bin_size[]; +extern const char _binary_memdisk_edd_512_bin_start[]; +extern const char _binary_memdisk_edd_512_bin_end[]; +extern const char _binary_memdisk_edd_512_bin_size[]; +extern const char _binary_memdisk_iso_512_bin_start[]; +extern const char _binary_memdisk_iso_512_bin_end[]; +extern const char _binary_memdisk_iso_512_bin_size[]; +extern const char _binary_memdisk_iso_2048_bin_start[]; +extern const char _binary_memdisk_iso_2048_bin_end[]; +extern const char _binary_memdisk_iso_2048_bin_size[]; struct memdisk_header { uint16_t int13_offs; @@ -106,6 +116,10 @@ struct patch_area { uint16_t dpt_ptr; /* End of the official MemDisk_Info */ + uint8_t driveshiftlimit; /* Do not shift drives above this region */ + uint8_t _pad2; /* Pad to DWORD */ + uint16_t _pad3; /* Pad to QWORD */ + uint16_t memint1588; uint16_t cylinders; @@ -131,51 +145,18 @@ struct patch_area { dpt_t dpt; struct edd_dpt edd_dpt; + struct edd4_cd_pkt cd_pkt; /* Only really in a memdisk_iso_* hook */ } __attribute__((packed)); -/* Access to high memory */ - -/* Access to objects in the zero page */ -static inline void wrz_8(uint32_t addr, uint8_t data) -{ - *((uint8_t *) addr) = data; -} - -static inline void wrz_16(uint32_t addr, uint16_t data) -{ - *((uint16_t *) addr) = data; -} - -static inline void wrz_32(uint32_t addr, uint32_t data) -{ - *((uint32_t *) addr) = data; -} - -static inline uint8_t rdz_8(uint32_t addr) -{ - return *((uint8_t *) addr); -} - -static inline uint16_t rdz_16(uint32_t addr) -{ - return *((uint16_t *) addr); -} - -static inline uint32_t rdz_32(uint32_t addr) -{ - return *((uint32_t *) addr); -} - -/* Addresses in the zero page */ -#define BIOS_INT13 (0x13*4) /* INT 13h vector */ -#define BIOS_INT15 (0x15*4) /* INT 15h vector */ -#define BIOS_INT1E (0x1E*4) /* INT 1Eh vector */ -#define BIOS_INT40 (0x40*4) /* INT 13h vector */ -#define BIOS_INT41 (0x41*4) /* INT 41h vector */ -#define BIOS_INT46 (0x46*4) /* INT 46h vector */ -#define BIOS_BASEMEM 0x413 /* Amount of DOS memory */ -#define BIOS_EQUIP 0x410 /* BIOS equipment list */ -#define BIOS_HD_COUNT 0x475 /* Number of hard drives present */ +/* An EDD disk packet */ +struct edd_dsk_pkt { + uint8_t size; /* Packet size */ + uint8_t res1; /* Reserved */ + uint16_t count; /* Count to transfer */ + uint32_t buf; /* Buffer pointer */ + uint64_t start; /* LBA to start from */ + uint64_t buf64; /* 64-bit buf pointer */ +} __attribute__ ((packed)); /* * Routine to seek for a command-line item and return a pointer @@ -339,7 +320,7 @@ void unzip_if_needed(uint32_t * where_p, uint32_t * size_p) if (!okmem) die("Not enough memory to decompress image (need 0x%08x bytes)\n", - gzdatasize); + gzdatasize); printf("gzip image: decompressed addr 0x%08x, len 0x%08x: ", target, gzdatasize); @@ -354,11 +335,12 @@ void unzip_if_needed(uint32_t * where_p, uint32_t * size_p) * Figure out the "geometry" of the disk in question */ struct geometry { - uint32_t sectors; /* 512-byte sector count */ + uint32_t sectors; /* Sector count */ uint32_t c, h, s; /* C/H/S geometry */ uint32_t offset; /* Byte offset for disk */ uint8_t type; /* Type byte for INT 13h AH=08h */ uint8_t driveno; /* Drive no */ + uint16_t sector_size; /* Sector size in bytes (512 vs. 2048) */ const char *hsrc, *ssrc; /* Origins of H and S geometries */ }; @@ -426,7 +408,8 @@ struct dosemu_header { #define FOUR(a,b,c,d) (((a) << 24)|((b) << 16)|((c) << 8)|(d)) -static const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t size) +static const struct geometry *get_disk_image_geometry(uint32_t where, + uint32_t size) { static struct geometry hd_geometry; struct dosemu_header dosemu; @@ -437,6 +420,8 @@ static const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t s printf("command line: %s\n", shdr->cmdline); + hd_geometry.sector_size = 512; /* Assume floppy/HDD at first */ + offset = 0; if (CMD_HASDATA(p = getcmditem("offset")) && (v = atou(p))) offset = v; @@ -448,6 +433,71 @@ static const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t s hd_geometry.sectors = sectors; hd_geometry.offset = offset; + if ((p = getcmditem("iso")) != CMD_NOTFOUND) { +#ifdef DBG_ELTORITO + eltorito_dump(where); +#endif + struct edd4_bvd *bvd = (struct edd4_bvd *)(where + 17 * 2048); + /* Tiny sanity check */ + if ((bvd->boot_rec_ind != 0) || (bvd->ver != 1)) + printf("El Torito BVD sanity check failed.\n"); + struct edd4_bootcat *boot_cat = + (struct edd4_bootcat *)(where + bvd->boot_cat * 2048); + /* Another tiny sanity check */ + if ((boot_cat->validation_entry.platform_id != 0) || + (boot_cat->validation_entry.key55 != 0x55) || + (boot_cat->validation_entry.keyAA != 0xAA)) + printf("El Torito boot catalog sanity check failed.\n"); + /* If we have an emulation mode, set the offset to the image */ + if (boot_cat->initial_entry.media_type) + hd_geometry.offset += boot_cat->initial_entry.load_block * 2048; + if (boot_cat->initial_entry.media_type < 4) { + /* We're a floppy emulation mode or our params will be + * overwritten by the no emulation mode case + */ + hd_geometry.driveno = 0x00; + hd_geometry.c = 80; + hd_geometry.h = 2; + } + switch (boot_cat->initial_entry.media_type) { + case 0: /* No emulation */ + hd_geometry.driveno = 0xE0; + hd_geometry.type = 10; /* ATAPI removable media device */ + hd_geometry.c = 65535; + hd_geometry.h = 255; + hd_geometry.s = 15; + /* 2048-byte sectors, so adjust the size and count */ + hd_geometry.sector_size = 2048; + sectors = (size - hd_geometry.offset) >> 11; + break; + case 1: /* 1.2 MB floppy */ + hd_geometry.s = 15; + hd_geometry.type = 2; + sectors = 2400; + break; + case 2: /* 1.44 MB floppy */ + hd_geometry.s = 18; + hd_geometry.type = 4; + sectors = 2880; + break; + case 3: /* 2.88 MB floppy */ + hd_geometry.s = 36; + hd_geometry.type = 6; + sectors = 5760; + break; + case 4: + hd_geometry.driveno = 0x80; + hd_geometry.type = 0; + sectors = (size - hd_geometry.offset) >> 9; + break; + } + /* For HDD emulation, we figure out the geometry later. Otherwise: */ + if (hd_geometry.s) { + hd_geometry.hsrc = hd_geometry.ssrc = "El Torito"; + } + hd_geometry.sectors = sectors; + } + /* Do we have a DOSEMU header? */ memcpy(&dosemu, (char *)where + hd_geometry.offset, sizeof dosemu); if (!memcmp("DOSEMU", dosemu.magic, 7)) { @@ -511,7 +561,7 @@ static const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t s if (!(max_h | max_s)) { /* No FAT filesystem found to steal geometry from... */ - if (sectors < 4096 * 2) { + if ((sectors < 4096 * 2) && (hd_geometry.sector_size == 512)) { int ok = 0; unsigned int xsectors = sectors; @@ -572,7 +622,9 @@ static const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t s const struct ptab_entry *ptab = (const struct ptab_entry *) ((char *)where + hd_geometry.offset + (512 - 2 - 4 * 16)); - hd_geometry.driveno = 0x80; /* Assume hard disk */ + /* Assume hard disk */ + if (!hd_geometry.driveno) + hd_geometry.driveno = 0x80; if (*(uint16_t *) ((char *)where + 512 - 2) == 0xaa55) { for (i = 0; i < 4; i++) { @@ -674,46 +726,46 @@ static uint32_t pnp_install_check(void) struct gdt_ptr { uint16_t limit; uint32_t base; -} __attribute__((packed)); +} __attribute__ ((packed)); static void set_seg_base(uint32_t gdt_base, int seg, uint32_t v) { - *(uint16_t *)(gdt_base + seg + 2) = v; - *(uint8_t *)(gdt_base + seg + 4) = v >> 16; - *(uint8_t *)(gdt_base + seg + 7) = v >> 24; + *(uint16_t *) (gdt_base + seg + 2) = v; + *(uint8_t *) (gdt_base + seg + 4) = v >> 16; + *(uint8_t *) (gdt_base + seg + 7) = v >> 24; } static void relocate_rm_code(uint32_t newbase) { uint32_t gdt_base; uint32_t oldbase = rm_args.rm_base; - uint32_t delta = newbase - oldbase; + uint32_t delta = newbase - oldbase; cli(); memmove((void *)newbase, (void *)oldbase, rm_args.rm_size); - rm_args.rm_return += delta; - rm_args.rm_intcall += delta; - rm_args.rm_bounce += delta; - rm_args.rm_base += delta; - rm_args.rm_gdt += delta; - rm_args.rm_pmjmp += delta; - rm_args.rm_rmjmp += delta; + rm_args.rm_return += delta; + rm_args.rm_intcall += delta; + rm_args.rm_bounce += delta; + rm_args.rm_base += delta; + rm_args.rm_gdt += delta; + rm_args.rm_pmjmp += delta; + rm_args.rm_rmjmp += delta; gdt_base = rm_args.rm_gdt; - *(uint32_t *)(gdt_base+2) = gdt_base; /* GDT self-pointer */ + *(uint32_t *) (gdt_base + 2) = gdt_base; /* GDT self-pointer */ /* Segments 0x10 and 0x18 are real-mode-based */ set_seg_base(gdt_base, 0x10, rm_args.rm_base); set_seg_base(gdt_base, 0x18, rm_args.rm_base); - asm volatile("lgdtl %0" : : "m" (*(char *)gdt_base)); + asm volatile ("lgdtl %0"::"m" (*(char *)gdt_base)); - *(uint32_t *)rm_args.rm_pmjmp += delta; - *(uint16_t *)rm_args.rm_rmjmp += delta >> 4; + *(uint32_t *) rm_args.rm_pmjmp += delta; + *(uint16_t *) rm_args.rm_rmjmp += delta >> 4; - rm_args.rm_handle_interrupt += delta; + rm_args.rm_handle_interrupt += delta; sti(); } @@ -768,11 +820,14 @@ void setup(const struct real_mode_args *rm_args_ptr) const struct geometry *geometry; unsigned int total_size; unsigned int cmdline_len, stack_len, e820_len; + const struct edd4_bvd *bvd; + const struct edd4_bootcat *boot_cat = 0; com32sys_t regs; uint32_t ramdisk_image, ramdisk_size; uint32_t boot_base, rm_base; int bios_drives; int do_edd = 1; /* 0 = no, 1 = yes, default is yes */ + int do_eltorito = 0; /* default is no */ int no_bpt; /* No valid BPT presented */ uint32_t boot_seg = 0; /* Meaning 0000:7C00 */ uint32_t boot_len = 512; /* One sector */ @@ -811,13 +866,28 @@ void setup(const struct real_mode_args *rm_args_ptr) else do_edd = (geometry->driveno & 0x80) ? 1 : 0; + if (getcmditem("iso") != CMD_NOTFOUND) { + do_eltorito = 1; + do_edd = 1; /* Mandatory */ + } + /* Choose the appropriate installable memdisk hook */ - if (do_edd) { - bin_size = (int)&_binary_memdisk_edd_bin_size; - memdisk_hook = (char *)&_binary_memdisk_edd_bin_start; + if (do_eltorito) { + if (geometry->sector_size == 2048) { + bin_size = (int)&_binary_memdisk_iso_2048_bin_size; + memdisk_hook = (char *)&_binary_memdisk_iso_2048_bin_start; + } else { + bin_size = (int)&_binary_memdisk_iso_512_bin_size; + memdisk_hook = (char *)&_binary_memdisk_iso_512_bin_start; + } } else { - bin_size = (int)&_binary_memdisk_chs_bin_size; - memdisk_hook = (char *)&_binary_memdisk_chs_bin_start; + if (do_edd) { + bin_size = (int)&_binary_memdisk_edd_512_bin_size; + memdisk_hook = (char *)&_binary_memdisk_edd_512_bin_start; + } else { + bin_size = (int)&_binary_memdisk_chs_512_bin_size; + memdisk_hook = (char *)&_binary_memdisk_chs_512_bin_start; + } } /* Reserve the ramdisk memory */ @@ -837,7 +907,7 @@ void setup(const struct real_mode_args *rm_args_ptr) pptr->driveno = geometry->driveno; pptr->drivetype = geometry->type; - pptr->cylinders = geometry->c; + pptr->cylinders = geometry->c; /* Possible precision loss */ pptr->heads = geometry->h; pptr->sectors = geometry->s; pptr->disksize = geometry->sectors; @@ -933,16 +1003,36 @@ void setup(const struct real_mode_args *rm_args_ptr) pptr->edd_dpt.c = geometry->c; pptr->edd_dpt.h = geometry->h; pptr->edd_dpt.s = geometry->s; - pptr->edd_dpt.flags |= 0x0002; /* Geometry valid */ + /* EDD-4 states that invalid geometry should be returned + * for INT 0x13, AH=0x48 "EDD Get Disk Parameters" call on an + * El Torito ODD. Check for 2048-byte sector size + */ + if (geometry->sector_size != 2048) + pptr->edd_dpt.flags |= 0x0002; /* Geometry valid */ } if (!(geometry->driveno & 0x80)) { /* Floppy drive. Mark it as a removable device with media change notification; media is present. */ pptr->edd_dpt.flags |= 0x0014; } - + pptr->edd_dpt.devpath[0] = pptr->diskbuf; - pptr->edd_dpt.chksum = -checksum_buf(&pptr->edd_dpt.dpikey, 73-30); + pptr->edd_dpt.chksum = -checksum_buf(&pptr->edd_dpt.dpikey, 73 - 30); + } + + if (do_eltorito) { + bvd = (struct edd4_bvd *)(ramdisk_image + 17 * 2048); + boot_cat = + (struct edd4_bootcat *)(ramdisk_image + bvd->boot_cat * 2048); + pptr->cd_pkt.type = boot_cat->initial_entry.media_type; /* Cheat */ + pptr->cd_pkt.driveno = geometry->driveno; + pptr->cd_pkt.start = boot_cat->initial_entry.load_block; + pptr->cd_pkt.load_seg = boot_cat->initial_entry.load_seg; + pptr->cd_pkt.sect_count = boot_cat->initial_entry.sect_count; + boot_len = pptr->cd_pkt.sect_count * 2048; + pptr->cd_pkt.geom1 = (uint8_t)(pptr->cylinders) & 0xFF; + pptr->cd_pkt.geom2 = (uint8_t)(pptr->sectors) | (uint8_t)((pptr->cylinders >> 2) & 0xC0); + pptr->cd_pkt.geom3 = (uint8_t)(pptr->heads); } /* The size is given by hptr->total_size plus the size of the E820 @@ -1059,6 +1149,13 @@ void setup(const struct real_mode_args *rm_args_ptr) if (pptr->drivecnt <= (geometry->driveno & 0x7f)) pptr->drivecnt = (geometry->driveno & 0x7f) + 1; + /* Probe for contiguous range of BIOS drives starting with driveno */ + pptr->driveshiftlimit = probe_drive_range(geometry->driveno) + 1; + if ((pptr->driveshiftlimit & 0x80) != (geometry->driveno & 0x80)) + printf("We lost the last drive in our class of drives.\n"); + printf("Drive probing gives drive shift limit: 0x%02x\n", + pptr->driveshiftlimit); + /* Pointer to the command line */ pptr->cmdline_off = bin_size + (nranges + 1) * sizeof(ranges[0]); pptr->cmdline_seg = driverseg; @@ -1087,7 +1184,7 @@ void setup(const struct real_mode_args *rm_args_ptr) if (nhd > 128) nhd = 128; - wrz_8(BIOS_HD_COUNT, nhd); + if (!do_eltorito) wrz_8(BIOS_HD_COUNT, nhd); } else { /* Update BIOS floppy disk count */ uint8_t equip = rdz_8(BIOS_EQUIP); @@ -1124,11 +1221,11 @@ void setup(const struct real_mode_args *rm_args_ptr) /* Figure out entry point */ if (!boot_seg) { - boot_base = 0x7c00; - shdr->sssp = 0x7c00; - shdr->csip = 0x7c00; + boot_base = 0x7c00; + shdr->sssp = 0x7c00; + shdr->csip = 0x7c00; } else { - boot_base = boot_seg << 4; + boot_base = boot_seg << 4; shdr->sssp = boot_seg << 16; shdr->csip = boot_seg << 16; } @@ -1143,7 +1240,11 @@ void setup(const struct real_mode_args *rm_args_ptr) /* Reboot into the new "disk" */ puts("Loading boot sector... "); - memcpy((void *)boot_base, (char *)pptr->diskbuf + boot_lba*512, boot_len); + if (do_eltorito) { + /* 4 times as many 512-byte sectors in a 2048-byte sector */ + boot_lba = pptr->cd_pkt.start * 4; + } + memcpy((void *)boot_base, (char *)pptr->diskbuf + boot_lba * 512, boot_len); if (getcmditem("pause") != CMD_NOTFOUND) { puts("press any key to boot... "); @@ -1155,5 +1256,5 @@ void setup(const struct real_mode_args *rm_args_ptr) /* On return the assembly code will jump to the boot vector */ shdr->esdi = pnp_install_check(); - shdr->edx = geometry->driveno; + shdr->edx = geometry->driveno; } |