From 75b89a82fae8b6d553467b92cb5431b2b5b4df7e Mon Sep 17 00:00:00 2001 From: Apple Date: Wed, 10 Jul 2002 00:50:52 +0000 Subject: [PATCH] boot-93.tar.gz --- Makefile | 2 +- gen/Makefile | 2 +- gen/libsa/Makefile | 2 +- gen/libsaio/disk.c | 4 +- gen/libsaio/ufs_byteorder.c | 8 +- gen/libsaio/ufs_byteorder.h | 12 +- gen/rcz/Makefile | 2 +- gen/rcz/rcz.c | 13 +- gen/rcz/rcz_compress_mem.c | 6 +- gen/rcz/rcz_decompress_mem.c | 1 - i386/Makefile | 2 +- i386/boot0/boot0.s | 845 +++++++------ i386/boot1/boot1.s | 69 +- i386/boot2/Makefile | 12 +- i386/boot2/appleClut8.h | 96 ++ i386/boot2/boot.c | 365 ++---- i386/boot2/boot.h | 38 +- i386/boot2/boot2.s | 28 +- i386/boot2/drivers.c | 165 +-- i386/boot2/graphics.c | 604 +++++++-- i386/boot2/happy_screen.h | 80 ++ i386/boot2/options.c | 636 ++++++++++ i386/boot2/prompt.c | 17 +- i386/libsa/Makefile | 8 +- i386/libsa/bswap.c | 33 - i386/libsa/libsa.h | 34 +- i386/libsa/memory.h | 94 +- i386/libsa/string.c | 6 +- i386/libsaio/Makefile | 16 +- i386/libsaio/appleClut8.h | 102 -- i386/libsaio/asm.s | 304 +++-- i386/libsaio/bios.h | 4 + i386/libsaio/bios.s | 377 +++--- i386/libsaio/biosfn.c | 301 +++-- i386/libsaio/bootstruct.c | 48 +- i386/libsaio/cache.c | 206 +-- i386/libsaio/console.c | 4 +- i386/libsaio/disk.c | 761 +++++++----- i386/libsaio/fdisk.h | 78 ++ i386/libsaio/gets.c | 115 -- i386/libsaio/hfs.c | 884 +++++++++++++ i386/libsaio/hfs_CaseTables.h | 275 ++++ i386/libsaio/hfs_compare.c | 316 +++++ i386/libsaio/legacy/PCI.h | 54 - i386/libsaio/legacy/asm.h | 101 -- i386/libsaio/legacy/disk.h | 137 -- i386/libsaio/legacy/fdisk.h | 51 - i386/libsaio/libsaio.h | 6 +- i386/libsaio/load.c | 237 ++-- i386/libsaio/misc.c | 53 +- i386/libsaio/nbp.c | 76 +- i386/libsaio/nbp.h | 59 - i386/libsaio/old/bios_old.s | 610 --------- i386/libsaio/old/shmalloc.c | 29 - i386/libsaio/old/stringTable.h.00 | 52 - i386/libsaio/old/stringTableNew.c | 564 --------- i386/libsaio/pci.c | 10 +- i386/libsaio/pci.h | 44 + i386/libsaio/saio.h | 142 --- i386/libsaio/saio_internal.h | 191 ++- i386/libsaio/saio_types.h | 107 +- i386/libsaio/{cache.h => sl.h} | 58 +- i386/libsaio/stringTable.c | 62 +- i386/libsaio/sys.c | 1584 ++++++------------------ i386/libsaio/table.c | 53 +- i386/libsaio/ufs.c | 450 +++++++ i386/libsaio/ufs_byteorder.c | 6 +- i386/libsaio/ufs_byteorder.h | 15 +- i386/libsaio/vbe.c | 164 +-- i386/libsaio/vbe.h | 45 +- i386/libsaio/vga.c | 289 ----- i386/libsaio/vga.h | 67 - i386/nasm/Makefile | 2 +- i386/nasm/assemble.c | 4 +- i386/rcz/Makefile | 4 +- i386/rcz/rcz_compress_mem.c | 6 +- i386/rcz/rcz_decompress_mem.c | 1 - i386/testmodule/install/install.module | Bin 89492 -> 0 bytes i386/testmodule/test.module | Bin 46472 -> 0 bytes i386/tests/sizeof | Bin 50036 -> 0 bytes i386/util/Makefile | 5 +- i386/util/dumptiff | Bin 35844 -> 0 bytes i386/util/tif_packbits.c | 2 +- 83 files changed, 6289 insertions(+), 6026 deletions(-) create mode 100644 i386/boot2/appleClut8.h create mode 100644 i386/boot2/happy_screen.h create mode 100644 i386/boot2/options.c delete mode 100644 i386/libsa/bswap.c delete mode 100644 i386/libsaio/appleClut8.h create mode 100644 i386/libsaio/fdisk.h delete mode 100644 i386/libsaio/gets.c create mode 100644 i386/libsaio/hfs.c create mode 100644 i386/libsaio/hfs_CaseTables.h create mode 100644 i386/libsaio/hfs_compare.c delete mode 100644 i386/libsaio/legacy/PCI.h delete mode 100644 i386/libsaio/legacy/asm.h delete mode 100644 i386/libsaio/legacy/disk.h delete mode 100644 i386/libsaio/legacy/fdisk.h delete mode 100644 i386/libsaio/nbp.h delete mode 100644 i386/libsaio/old/bios_old.s delete mode 100644 i386/libsaio/old/shmalloc.c delete mode 100644 i386/libsaio/old/stringTable.h.00 delete mode 100644 i386/libsaio/old/stringTableNew.c delete mode 100644 i386/libsaio/saio.h rename i386/libsaio/{cache.h => sl.h} (51%) create mode 100644 i386/libsaio/ufs.c delete mode 100644 i386/libsaio/vga.c delete mode 100644 i386/libsaio/vga.h delete mode 100755 i386/testmodule/install/install.module delete mode 100755 i386/testmodule/test.module delete mode 100755 i386/tests/sizeof delete mode 100755 i386/util/dumptiff diff --git a/Makefile b/Makefile index 0724682..fe88a53 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ export USE_APPLE_PB_SUPPORT = all # Makefile for kernel booter -# CFLAGS = -O $(MORECPP) -arch i386 -g -munaligned-text +# CFLAGS = -O $(MORECPP) -arch i386 -g DEFINES= CONFIG = hd LIBDIR = libsa diff --git a/gen/Makefile b/gen/Makefile index b9ce995..2d2f67d 100644 --- a/gen/Makefile +++ b/gen/Makefile @@ -3,7 +3,7 @@ # Machine-independent code # -#CFLAGS = -O $(MORECPP) -arch i386 -g -munaligned-text +#CFLAGS = -O $(MORECPP) -arch i386 -g DEFINES= CONFIG = hd LIBDIR = libsa diff --git a/gen/libsa/Makefile b/gen/libsa/Makefile index 20c0a10..dd6b61a 100644 --- a/gen/libsa/Makefile +++ b/gen/libsa/Makefile @@ -6,7 +6,7 @@ UTILDIR = ../util INSTALL_MI_DIR = $(DSTROOT)/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders/machdep/machine DEBUG = -O -CFLAGS = $(DEBUG) $(MORECPP) -arch i386 -g -Wmost -Wno-precomp -munaligned-text +CFLAGS = $(DEBUG) $(MORECPP) -arch i386 -g -Wmost -Wno-precomp DEFINES= CONFIG = hd INC = -I. -I$(SYMROOT) -I$(UTILDIR) diff --git a/gen/libsaio/disk.c b/gen/libsaio/disk.c index 77bbba0..9f99c83 100644 --- a/gen/libsaio/disk.c +++ b/gen/libsaio/disk.c @@ -47,8 +47,8 @@ #define DRIVER_PRIVATE #import "sys/types.h" -#import -#import +#import +#import #import "libsaio.h" #import "memory.h" diff --git a/gen/libsaio/ufs_byteorder.c b/gen/libsaio/ufs_byteorder.c index 45640aa..ab90632 100644 --- a/gen/libsaio/ufs_byteorder.c +++ b/gen/libsaio/ufs_byteorder.c @@ -26,10 +26,10 @@ * All rights reserved. */ -#import -#import -#import -#import +#import +#import +#import +#import #import #import "ufs_byteorder.h" #import "libsaio.h" diff --git a/gen/libsaio/ufs_byteorder.h b/gen/libsaio/ufs_byteorder.h index 7ee6dcf..ed353f7 100644 --- a/gen/libsaio/ufs_byteorder.h +++ b/gen/libsaio/ufs_byteorder.h @@ -32,12 +32,12 @@ * 8 Jul 1992 Brian Pinkerton at NeXT * Created. */ -#import -#import -#import -#import -#import -#import +#import +#import +#import +#import +#import +#import void byte_swap_ints(int *array, int count); void byte_swap_shorts(short *array, int count); diff --git a/gen/rcz/Makefile b/gen/rcz/Makefile index 077094e..308c033 100644 --- a/gen/rcz/Makefile +++ b/gen/rcz/Makefile @@ -8,7 +8,7 @@ USRBIN = $(DSTROOT)/usr/bin INSTALLDIR = $(DSTROOT)/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders/standalone DEBUG = -O -CFLAGS = $(DEBUG) $(MORECPP) $(RC_CFLAGS) -g -Wmost -Wno-precomp -traditional-cpp +CFLAGS = $(DEBUG) $(MORECPP) $(RC_CFLAGS) -g -Wmost -Werror DEFINES= CONFIG = hd INC = -I. -I$(SYMROOT) -I$(UTILDIR) -I$(LIBSADIR) diff --git a/gen/rcz/rcz.c b/gen/rcz/rcz.c index e3c15a1..6155f0c 100644 --- a/gen/rcz/rcz.c +++ b/gen/rcz/rcz.c @@ -22,6 +22,7 @@ * @APPLE_LICENSE_HEADER_END@ */ #import +#import #import #import #import @@ -40,12 +41,12 @@ usage(void) exit(1); } -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { char *infile = NULL, *outfile = NULL; int compress = 0; int verbose = 0; - FILE *inf, *outf; + FILE *inf, *outf = NULL; unsigned char *inbuf, *outbuf; unsigned long length, total; kern_return_t ret; @@ -113,7 +114,7 @@ main(int argc, char *argv[]) } fseek(inf,0,2); length = ftell(inf); rewind(inf); - if ((ret = map_fd(fileno(inf), 0, &inbuf, TRUE, length)) != KERN_SUCCESS) { + if ((ret = map_fd(fileno(inf), 0, (vm_address_t *)&inbuf, TRUE, length)) != KERN_SUCCESS) { mach_error("map_fd", ret); exit(1); } @@ -123,7 +124,7 @@ main(int argc, char *argv[]) if (verbose) fprintf(stderr, "%ld %ld\nCompression ratio: %f\n", length, total, total/(1.0*length)); fclose(inf); - vm_deallocate(mach_task_self(), inbuf, length); + vm_deallocate(mach_task_self(), (vm_address_t)inbuf, length); fclose(outf); } else { unsigned char *ptr; @@ -149,7 +150,7 @@ main(int argc, char *argv[]) } } fseek(inf,0,2); length = ftell(inf); rewind(inf); - if ((ret = map_fd(fileno(inf), 0, &inbuf, TRUE, length)) != KERN_SUCCESS) { + if ((ret = map_fd(fileno(inf), 0, (vm_address_t *)&inbuf, TRUE, length)) != KERN_SUCCESS) { mach_error("map_fd", ret); exit(1); } @@ -171,7 +172,7 @@ main(int argc, char *argv[]) if (verbose) fprintf(stderr, "%ld %ld\nCompression ratio: %f\n", length, total, total/(1.0*length)); fclose(inf); - vm_deallocate(mach_task_self(), inbuf, length); + vm_deallocate(mach_task_self(), (vm_address_t)inbuf, length); fclose(outf); } exit(0); diff --git a/gen/rcz/rcz_compress_mem.c b/gen/rcz/rcz_compress_mem.c index af44704..56a58c2 100644 --- a/gen/rcz/rcz_compress_mem.c +++ b/gen/rcz/rcz_compress_mem.c @@ -44,9 +44,9 @@ rcz_compress_memory( ) /* Returns actual number of bytes emitted as compressed stream 'out.' */ { - unsigned int c, ct, j, jmatch, jabove, match; - unsigned int data[32], version; - unsigned int word, token, tokenct, total; + unsigned int c, ct, j, jmatch = 0, jabove, match; + unsigned int data[32]; + unsigned int word, token, tokenct; unsigned char *outorigin = out; /* First, put version number into stream. */ diff --git a/gen/rcz/rcz_decompress_mem.c b/gen/rcz/rcz_decompress_mem.c index b5a3f86..e223f49 100644 --- a/gen/rcz/rcz_decompress_mem.c +++ b/gen/rcz/rcz_decompress_mem.c @@ -46,7 +46,6 @@ rcz_decompress_memory(unsigned char *in, unsigned char *out) unsigned int c, j, k, jmatch, jabove; unsigned int length, even_length, word, token, version; unsigned char *outorigin = out; - int *a, *b; version = *in++; version = (version<<8) | (*in++); diff --git a/i386/Makefile b/i386/Makefile index a05daf6..88b7ee3 100644 --- a/i386/Makefile +++ b/i386/Makefile @@ -2,7 +2,7 @@ # Makefile for i386 boot program # define FLOPPY and SMALL using DEFINES macro as necessary -CFLAGS = -O $(MORECPP) -arch i386 -g -mi386:unaligned-text -static +CFLAGS = -O $(MORECPP) -arch i386 -g -static DEFINES= CONFIG = hd LIBDIR = libsa diff --git a/i386/boot0/boot0.s b/i386/boot0/boot0.s index dcf9c84..f1eb72e 100644 --- a/i386/boot0/boot0.s +++ b/i386/boot0/boot0.s @@ -26,529 +26,631 @@ ; responsibility is to locate the booter partition, load the ; booter into memory, and jump to the booter's entry point. ; The booter partition can be a primary or a logical partition. -; But the booter partition must reside within the 8GB limit -; imposed by CHS addressing + translation. ; ; This boot loader can be placed at any of the following places: -; * Master Boot Record (MBR) -; * Boot sector of an extended partition -; * Boot sector of a primary partition -; * Boot sector of a logical partition +; 1. Master Boot Record (MBR) +; 2. Boot sector of an extended partition +; 3. Boot sector of a primary partition +; 4. Boot sector of a logical partition ; ; In order to coexist with a fdisk partition table (64 bytes), and ; leave room for a two byte signature (0xAA55) in the end, boot0 is ; restricted to 446 bytes (512 - 64 - 2). If boot0 did not have to -; live in the MBR, then we would have 510 bytes to play with. +; live in the MBR, then we would have 510 bytes to work with. ; -; boot0 is always loaded by the BIOS or another first level booter -; to 0:7C00h. +; boot0 is always loaded by the BIOS or another booter to 0:7C00h. ; ; This code is written for the NASM assembler. ; nasm boot0.s -o boot0 -;-------------------------------------------------------------------------- -; Constants. -DEBUG EQU 0 ; enable debugging output +; +; Set to 1 to enable obscure debug messages. +; +DEBUG EQU 0 + +; +; Set to 1 to support loading the booter (boot2) from a +; logical partition. +; +EXT_PART_SUPPORT EQU 1 + +; +; Various constants. +; +kBoot0Segment EQU 0x0000 +kBoot0Stack EQU 0xFFF0 ; boot0 stack pointer +kBoot0LoadAddr EQU 0x7C00 ; boot0 load address +kBoot0RelocAddr EQU 0xE000 ; boot0 relocated address + +kMBRBuffer EQU 0x1000 ; MBR buffer address +kExtBuffer EQU 0x1200 ; EXT boot block buffer address -BOOTSEG EQU 0x0 ; our sole segment -BOOTSP EQU 0xFFF0 ; stack pointer -BOOTLOAD EQU 0x7C00 ; booter load address -BOOTRELOC EQU 0xE000 ; booter is relocated here -BOOTSIG EQU 0xAA55 ; booter signature +kPartTableOffset EQU 0x1be +kMBRPartTable EQU kMBRBuffer + kPartTableOffset +kExtPartTable EQU kExtBuffer + kPartTableOffset -BOOT2_SIZE EQU 88 ; load this many blocks for boot2 -BOOT2_ADDR EQU 0x3000 ; where to load boot2 +kBoot2Sectors EQU 112 ; sectors to load for boot2 +kBoot2Address EQU 0x0000 ; boot2 load address +kBoot2Segment EQU 0x2000 ; boot2 load segment -DRIVE_NUM EQU 0x80 ; "C" drive -SECTOR_BYTES EQU 512 ; sector size in bytes +kSectorBytes EQU 512 ; sector size in bytes +kBootSignature EQU 0xAA55 ; boot sector signature -BUF_MBR EQU 0x1000 ; memory buffer for MBR -BUF_EXT EQU 0x1200 ; memory buffer for extended partition +kPartCount EQU 4 ; number of paritions per table +kPartTypeBoot EQU 0xab ; boot2 partition type +kPartTypeExtDOS EQU 0x05 ; DOS extended partition type +kPartTypeExtWin EQU 0x0f ; Windows extended partition type +kPartTypeExtLinux EQU 0x85 ; Linux extended partition type -TABLE_MAIN EQU BUF_MBR + 0x1be ; location of main partition table -TABLE_EXT EQU BUF_EXT + 0x1be ; location of ext partition table -ENTRY_SIZE EQU 16 ; size of each fdisk partition entry -TYPE_BOOT EQU 0xab ; partition type we are looking for -TYPE_EXT EQU 0x05 ; extended partition type -TYPE_EXT_1 EQU 0x0f ; Windows extended partition -TYPE_EXT_2 EQU 0x85 ; Linux extended partition -EXT_LEVELS_MAX EQU 128 ; max extended partition levels +%ifdef FLOPPY +kDriveNumber EQU 0x00 +%else +kDriveNumber EQU 0x80 +%endif + +; +; In memory variables. +; +ebios_lba dd 0 ; starting LBA of the intial extended partition. +read_func dw 0 ; pointer to the LBA or CHS read function -; Disk parameters gathered through INT13/F8 call. ; -max_sectors db 0 ; number of sectors per track -max_heads db 0 ; number of heads +; Format of fdisk partition entry. +; +; The symbol 'part_size' is automatically defined as an `EQU' +; giving the size of the structure. +; + struc part +.bootid: resb 1 ; bootable or not +.head: resb 1 ; starting head, sector, cylinder +.sect: resb 1 ; +.cyl: resb 1 ; +.type: resb 1 ; partition type +.endhead resb 1 ; ending head, sector, cylinder +.endsect: resb 1 ; +.endcyl: resb 1 ; +.lba: resd 1 ; starting lba +.sectors resd 1 ; size in sectors + endstruc -; Parameters to our load function. ; -chs_cx dw 0 ; cx register for INT13/F2 call -chs_dx dw 0 ; dx register for INT13/F2 call +; Macros. +; +%macro DebugCharMacro 1 + mov al, %1 + call print_char +%endmacro +%if DEBUG +%define DebugChar(x) DebugCharMacro x +%else +%define DebugChar(x) +%endif ;-------------------------------------------------------------------------- ; Start of text segment. SEGMENT .text - ORG 0xE000 ; must match BOOTRELOC + ORG 0xE000 ; must match kBoot0RelocAddr ;-------------------------------------------------------------------------- -; Loaded at 0:7c00h. +; Boot code is loaded at 0:7C00h. ; start - ; Set up the stack to grow down from BOOTSEG:BOOTSP. + ; + ; Set up the stack to grow down from kBoot0Segment:kBoot0Stack. ; Interrupts should be off while the stack is being manipulated. ; - cli ; interrupts off - mov ax, BOOTSEG ; - mov ss, ax ; ss <- BOOTSEG - mov sp, BOOTSP ; sp <- BOOTSP - sti ; reenable interrupts + cli ; interrupts off + xor ax, ax ; zero ax + mov ss, ax ; ss <- 0 + mov sp, kBoot0Stack ; sp <- top of stack + sti ; reenable interrupts + + mov es, ax ; es <- 0 + mov ds, ax ; ds <- 0 - ; Relocate the booter code from DS:SI to ES:DI, - ; or from 0:7C00h to BOOTSEG:BOOTRELOC. ; - mov es, ax ; es <- BOOTSEG - xor ax, ax - mov ds, ax ; ds <- 0 - mov si, BOOTLOAD ; si <- BOOTLOAD (source) - mov di, BOOTRELOC ; di <- BOOTRELOC (destination) + ; Relocate boot0 code. ; - cld ; auto-increment SI and/or DI registers - mov cx, 256 ; copy 256 words (512 bytes) - repnz movsw ; repeat string move (word) operation + mov si, kBoot0LoadAddr ; si <- source + mov di, kBoot0RelocAddr ; di <- destination + ; + cld ; auto-increment SI and/or DI registers + mov cx, kSectorBytes/2 ; copy 256 words + repnz movsw ; repeat string move (word) operation ; Code relocated, jump to start_reloc in relocated location. ; - jmp BOOTSEG:start_reloc + jmp 0:start_reloc ;-------------------------------------------------------------------------- ; Start execution from the relocated location. ; -start_reloc - mov ax, BOOTSEG - mov ds, ax ; ds <- BOOTSEG +start_reloc: + + DebugChar('>') - mov al, '=' ; indicate execution start - call putchar + mov dl, kDriveNumber ; starting BIOS drive number + +.loop: + +%if DEBUG + mov al, dl + call print_hex +%endif - ; Get disk parameters (CHS) using INT13/F8 call. ; - mov dl, DRIVE_NUM ; boot drive is drive C - mov ah, 8 ; Read Disk Driver Parameter function - int 0x13 - and cl, 0x3f ; sectors/track - mov [max_sectors], cl - mov [max_heads], dh - jc error - - mov al, '>' ; indicate INT13/F8 success - call putchar - - ; Since this code may not always reside in the MBR, we will always - ; start by loading the MBR to BUF_MBR. - ; - mov WORD [chs_cx], 0x0001 ; cyl = 0, sect = 1 - mov BYTE [chs_dx + 1], 0 ; head = 0 - xor cx, cx ; skip 0 sectors - mov ax, 1 ; read 1 sector - mov bx, BUF_MBR ; load buffer + ; Clear various flags in memory. + ; + xor eax, eax + mov [ebios_lba], eax ; clear EBIOS LBA offset + mov WORD [read_func], read_chs ; assume CHS support + + ; + ; Since this code may not always reside in the MBR, always start by + ; loading the MBR to kMBRBuffer. + ; + mov al, 1 ; load one sector + xor bx, bx + mov es, bx ; MBR load segment = 0 + mov bx, kMBRBuffer ; MBR load address + mov si, bx ; pointer to fake partition entry + mov WORD [si], 0x0000 ; CHS DX: head = 0 + mov WORD [si + 2], 0x0001 ; CHS CX: cylinder = 0, sector = 1 + call load - jc error + jc .next_drive ; MBR load error - mov di, TABLE_MAIN ; argument for find_booter - cmp WORD [di + 64], BOOTSIG ; correct signature found? - jne error ; Oops! no signature! - mov bl, TYPE_BOOT ; look for this partition type - mov bh, 0 ; initial nesting level is 0 - call find_booter + ; + ; Check if EBIOS is supported for this hard drive. + ; + mov ah, 0x41 ; Function 0x41 + mov bx, 0x55AA ; check signature +; mov dl, kDriveNumber ; Drive number + int 0x13 -error - mov si, load_error - call message -hang_1 - jmp hang_1 + ; + ; If successful, the return values are as follows: + ; + ; carry = 0 + ; ah = major version of EBIOS extensions (0x21 = version 1.1) + ; al = altered + ; bx = 0xAA55 + ; cx = support bits. bit 0 must be set for function 0x42. + ; + jc .ebios_check_done + cmp bx, 0xAA55 ; check BX = 0xAA55 + jnz .ebios_check_done + test cl, 0x01 ; check enhanced drive read support + mov WORD [read_func], read_lba ; use read_lba for reads + DebugChar('E') ; EBIOS supported +.ebios_check_done: + + ; + ; Look for the booter partition in the MBR partition table, + ; which is at offset kMBRPartTable. + ; + mov di, kMBRPartTable ; pointer to partition table + mov ah, 0 ; initial nesting level is 0 + call find_boot ; will not return on success + +.next_drive: + inc dl ; next drive number + test dl, 0x4 ; went through all 4 drives? + jz .loop ; not yet, loop again + + mov si, boot_error_str + call print_string + +hang: + jmp SHORT hang ;-------------------------------------------------------------------------- -; Locate the booter partition and load the booter. +; Find the boot partition and load the booter from the partition. ; ; Arguments: -; di - pointer to fdisk partition table. -; bl - partition type to look for. +; AH = recursion nesting level +; DL = drive number (0x80 + unit number) +; DI = pointer to fdisk partition table. ; -; The following registers are modified: -; ax, bh +; Clobber list: +; AX, BX, EBP ; -find_booter - push cx +find_boot: + push cx ; preserve CX and SI push si - mov si, di ; si <- pointer to partition table - mov cx, 4 ; 4 partition entries per table - -find_booter_pri ; - ; Hunt for a fdisk partition type that matches the value in bl. + ; Check for boot block signature 0xAA55 following the 4 partition + ; entries. ; -%IF DEBUG - mov al, bh ; log partition type seen - call putspace - mov al, [si + 4] - call display_byte -%ENDIF - - cmp BYTE [si + 4], bl ; Is this the booter partition? - je load_booter ; yes, load the booter + cmp WORD [di + part_size * kPartCount], kBootSignature + jne .exit ; boot signature not found - add si, ENTRY_SIZE ; si <- next partition entry - loop find_booter_pri ; loop while cx is not zero + mov si, di ; make SI a pointer to partition table + mov cx, kPartCount ; number of partition entries per table - ; No primary (or perhaps logical) booter partition found in the - ; current partition table. Restart and look for extended partitions. +.loop: ; - mov si, di ; si <- pointer to partition table - mov cx, 4 ; 4 partition entries per table + ; First scan through the partition table looking for the boot + ; partition. Postpone walking the extended partition chain for + ; the second pass. Do not merge the two without changing the + ; buffering scheme used to store extended partition tables. + ; +%if DEBUG + mov al, ah ; indent based on nesting level + call print_spaces + mov al, [si + part.type] ; print partition type + call print_hex +%endif + + cmp BYTE [si + part.type], kPartTypeBoot + jne .continue -find_booter_ext ; - ; Look for extended partition entries in the partition table. + ; Found boot partition, read boot2 image to memory. ; -%IF DEBUG - mov al, bh ; log partition type seen - call putspace - mov al, 'E' - call putchar - mov al, [si + 4] - call display_byte -%ENDIF + mov al, kBoot2Sectors + mov bx, kBoot2Segment + mov es, bx + mov bx, kBoot2Address + call load ; will not return on success + jc .continue ; load error, keep looking? - cmp BYTE [si + 4], TYPE_EXT ; Is this an extended partition? - je find_booter_ext_2 ; yes, load its partition table + ; + ; Jump to boot2. The drive number is already in register DL. + ; + ; The first sector loaded from the disk is reserved for the boot + ; block (boot0), adjust the jump location by adding a sector offset. + ; + jmp kBoot2Segment:kBoot2Address + kSectorBytes - cmp BYTE [si + 4], TYPE_EXT_1 ; Is this an extended partition? - je find_booter_ext_2 ; yes, load its partition table - - cmp BYTE [si + 4], TYPE_EXT_2 ; Is this an extended partition? - je find_booter_ext_2 ; yes, load its partition table +.continue: + add si, part_size ; advance SI to next partition entry + loop .loop ; loop through all partition entries -find_booter_ext_1 +%if EXT_PART_SUPPORT ; - ; si is not pointing to an extended partition entry, - ; try the next entry in the partition table. + ; No primary (or logical) boot partition found in the current + ; partition table. Restart and look for extended partitions. ; - add si, ENTRY_SIZE ; si <- next partition entry - loop find_booter_ext ; loop while cx is not zero + mov si, di ; make SI a pointer to partition table + mov cx, kPartCount ; number of partition entries per table - jmp find_booter_end ; give up +.ext_loop: -find_booter_ext_2 - cmp bh, EXT_LEVELS_MAX - ja find_booter_end ; in too deep! + mov al, [si + part.type] ; AL <- partition type - inc bh ; increment nesting level counter + cmp al, kPartTypeExtDOS ; Extended DOS + je .ext_load - ; Prepare the arguments for the load function call to - ; load the extended partition table into memory. - ; Note that si points to the extended partition entry. - ; - mov ax, [si] ; DH/DL - mov [chs_dx], ax - mov ax, [si + 2] ; CH/CL - mov [chs_cx], ax - pusha - xor cx, cx ; skip 0 sectors - mov ax, 1 ; read 1 sector - mov bx, BUF_EXT ; load to BUF_EXT - call load - popa + cmp al, kPartTypeExtWin ; Extended Windows(95) + je .ext_load - jc find_booter_ext_3 ; bail out if load failed + cmp al, kPartTypeExtLinux ; Extended Linux + je .ext_load - mov di, TABLE_EXT ; di <- pointer to new partition table - cmp WORD [di + 64], BOOTSIG - jne find_booter_ext_3 ; OhOh! no signature! +.ext_continue: + ; + ; Advance si to the next partition entry in the extended + ; partition table. + ; + add si, part_size ; advance SI to next partition entry + loop .ext_loop ; loop through all partition entries + jmp .exit ; boot partition not found - call find_booter ; recursion... +.ext_load: + ; + ; Setup the arguments for the load function call to bring the + ; extended partition table into memory. + ; Remember that SI points to the extended partition entry. + ; + mov al, 1 ; read 1 sector + xor bx, bx + mov es, bx ; es = 0 + mov bx, kExtBuffer ; load extended boot sector + call load + jc .ext_continue ; load error -find_booter_ext_3 - dec bh ; decrement nesting level counter + ; + ; The LBA address of all extended partitions is relative based + ; on the LBA address of the extended partition in the MBR, or + ; the extended partition at the head of the chain. Thus it is + ; necessary to save the LBA address of the first extended partition. + ; + or ah, ah + jnz .ext_find_boot + mov ebp, [si + part.lba] + mov [ebios_lba], ebp + +.ext_find_boot: + ; + ; Call find_boot recursively to scan through the extended partition + ; table. Load DI with a pointer to the extended table in memory. + ; + inc ah ; increment recursion level + mov di, kExtPartTable ; partition table pointer + call find_boot ; recursion... + ;dec ah - ; If we got here, then we know there isn't a booter - ; partition linked from this partition entry. + ; + ; Since there is an "unwritten" rule that limits each partition table + ; to have 0 or 1 extended partitions, there is no point in looking for + ; any additional extended partition entries at this point. There is no + ; boot partition linked beyond the extended partition that was loaded + ; above. + ; - test bh, bh ; if we are at level 0, then - jz find_booter_ext_1 ; look for next extended partition entry +%endif ; EXT_PART_SUPPORT -find_booter_end +.exit: + ; + ; Boot partition not found. Giving up. + ; pop si pop cx ret ;-------------------------------------------------------------------------- -; Yeah! Found the booter partition. The first sector in this partition -; is reserved for the boot sector code (us). So load the booter -; starting from the second sector in the partition, then jump to the -; start of the booter. -; -load_booter - mov ax, [si] ; DH/DL - mov [chs_dx], ax - mov ax, [si + 2] ; CH/CL - mov [chs_cx], ax - - mov cx, 1 ; skip the initial boot sector - mov ax, BOOT2_SIZE ; read BOOT2_SIZE sectors - mov bx, BOOT2_ADDR ; where to place boot2 code - call load ; load it... - - xor edx, edx ; argument for boot2 (hard drive boot) - jmp BOOTSEG:BOOT2_ADDR ; there is no going back now! - -;-------------------------------------------------------------------------- -; Load sectors from disk using INT13/F2 call. The sectors are loaded -; one sector at a time to avoid any BIOS bugs, and eliminate -; complexities with crossing track boundaries, and other gotchas. +; load - Load one or more sectors from a partition. ; ; Arguments: -; cx - number of sectors to skip -; ax - number of sectors to read -; bx - pointer to the memory buffer (must not cross a segment boundary) -; [chs_cx][chs_dx] - CHS starting position +; AL = number of 512-byte sectors to read. +; ES:BX = pointer to where the sectors should be stored. +; DL = drive number (0x80 + unit number) +; SI = pointer to the partition entry. ; ; Returns: -; CF = 0 success -; CF = 1 error -; -; The caller must save any registers it needs. -; -load - jcxz load_sectors - call next_sector ; [chs_cx][chs_dx] <- next sector - loop load - -load_sectors - mov cx, ax ; cx <- number of sectors to read - -load_loop - call read_sector ; load a single sector - jc load_exit ; abort if carry flag is set - add bx, SECTOR_BYTES ; increment buffer pointer - call next_sector ; [chs_cx][chs_dx] <- next sector - loop load_loop - clc ; successful exit -load_exit +; CF = 0 success +; 1 error +; +load: + push cx + mov cx, 5 ; number of times to retry + +.loop: + call [read_func] ; call either read_chs or read_lba + jnc .exit ; load success + loop .loop ; retry on error + +.exit: + pop cx ret ;-------------------------------------------------------------------------- -; Read a single sector from the hard disk. +; read_chs - Read sectors from a partition using CHS addressing. ; ; Arguments: -; [chs_cx][chs_dx] - CHS starting position -; bx - pointer to the sector memory buffer -; (must not cross a segment boundary) +; AL = number of 512-byte sectors to read. +; ES:BX = pointer to where the sectors should be stored. +; DL = drive number (0x80 + unit number) +; SI = pointer to the partition entry. ; ; Returns: -; CF = 0 success -; CF = 1 error -; -; Caller's cx register is preserved. +; CF = 0 success +; 1 error ; -read_sector - push cx - mov cx, 5 ; try 5 times to read the sector - -read_sector_1 - mov bp, cx ; save cx +read_chs: + pusha ; save all registers - mov cx, [chs_cx] - mov dx, [chs_dx] - mov dl, DRIVE_NUM ; drive number - mov ax, 0x0201 ; Func 2, read 1 sector - int 0x13 ; read sector - jnc read_sector_ok ; CF = 0 indicates success - - mov al, '*' ; sector read error indicator - call putchar + ; + ; Read the CHS start values from the partition entry. + ; + mov dh, [ si + part.head ] ; drive head + mov cx, [ si + part.sect ] ; drive sector + cylinder - xor ax, ax ; Reset the drive and retry the read - int 0x13 + ; + ; INT13 Func 2 - Read Disk Sectors + ; + ; Arguments: + ; AH = 2 + ; AL = number of sectors to read + ; CH = lowest 8 bits of the 10-bit cylinder number + ; CL = bits 6 & 7: cylinder number bits 8 and 9 + ; bits 0 - 5: starting sector number (1-63) + ; DH = starting head number (0 to 255) + ; DL = drive number (80h + drive unit) + ; es:bx = pointer where to place sectors read from disk + ; + ; Returns: + ; AH = return status (sucess is 0) + ; AL = burst error length if ah=0x11 (ECC corrected) + ; carry = 0 success + ; 1 error + ; +; mov dl, kDriveNumber + mov ah, 0x02 ; Func 2 + int 0x13 ; INT 13 + jnc .exit - mov cx, bp - loop read_sector_1 ; retry while cx is not zero + DebugChar('e') ; indicate INT13/F2 error - stc ; set carry flag to indicate error - pop cx - ret + ; + ; Issue a disk reset on error. + ; Should this be changed to Func 0xD to skip the diskette controller + ; reset? + ; + xor ax, ax ; Func 0 + int 0x13 ; INT 13 + stc ; set carry to indicate error -read_sector_ok - mov al, '.' ; successful sector read indicator - call putchar - clc ; success, clear carry flag - pop cx +.exit: + popa ret ;-------------------------------------------------------------------------- -; Given the current CHS position stored in [chs_cx][chs_dx], update -; it so that the value in [chs_cx][chs_dx] points to the following -; sector. +; read_lba - Read sectors from a partition using LBA addressing. ; ; Arguments: -; [chs_cx][chs_dx] - CHS position -; -; [max_sectors] and [max_heads] must be valid. +; AL = number of 512-byte sectors to read (valid from 1-127). +; ES:BX = pointer to where the sectors should be stored. +; DL = drive number (0x80 + unit number) +; SI = pointer to the partition entry. ; -; Caller's ax and bx registers are preserved. +; Returns: +; CF = 0 success +; 1 error ; -next_sector - push ax - push bx +read_lba: + pusha ; save all registers + mov bp, sp ; save current SP - ; Extract the CHS values from the packed register values in memory. ; - mov al, [chs_cx] - and al, 0x3f ; al <- sector number (1-63) + ; Create the Disk Address Packet structure for the + ; INT13/F42 (Extended Read Sectors) on the stack. + ; - mov bx, [chs_cx] - rol bl, 2 - ror bx, 8 - and bx, 0x03ff ; bx <- cylinder number + ; push DWORD 0 ; offset 12, upper 32-bit LBA + push ds ; For sake of saving memory, + push ds ; push DS register, which is 0. - mov ah, [chs_dx + 1] ; ah <- head number + mov ecx, [ebios_lba] ; offset 8, lower 32-bit LBA + add ecx, [si + part.lba] + push ecx - inc al ; Increment CHS by one sector. - cmp al, [max_sectors] - jbe next_sector_done + push es ; offset 6, memory segment - inc ah - cmp ah, [max_heads] - jbe next_sector_new_head + push bx ; offset 4, memory offset - inc bx + xor ah, ah ; offset 3, must be 0 + push ax ; offset 2, number of sectors -next_sector_new_cyl - xor ah, ah ; head number starts at 0 + push WORD 16 ; offset 0-1, packet size -next_sector_new_head - mov al, 1 ; sector number starts at 1 + ; + ; INT13 Func 42 - Extended Read Sectors + ; + ; Arguments: + ; AH = 0x42 + ; DL = drive number (80h + drive unit) + ; DS:SI = pointer to Disk Address Packet + ; + ; Returns: + ; AH = return status (sucess is 0) + ; carry = 0 success + ; 1 error + ; + ; Packet offset 2 indicates the number of sectors read + ; successfully. + ; +; mov dl, kDriveNumber + mov si, sp + mov ah, 0x42 + int 0x13 + + jnc .exit -next_sector_done - ; Reassemble the CHS values back into the packed representation - ; in memory. + DebugChar('E') ; indicate INT13/F42 error + + ; + ; Issue a disk reset on error. + ; Should this be changed to Func 0xD to skip the diskette controller + ; reset? ; - mov [chs_cx + 1], bl ; lower 8-bits of the 10-bit cylinder - ror bh, 2 - or bh, al - mov [chs_cx], bh ; cylinder & sector number - mov [chs_dx + 1], ah ; head number + xor ax, ax ; Func 0 + int 0x13 ; INT 13 + stc ; set carry to indicate error - pop bx - pop ax +.exit: + mov sp, bp ; restore SP + popa ret ;-------------------------------------------------------------------------- ; Write a string to the console. ; ; Arguments: -; ds:si pointer to a NULL terminated string. -; -; The following registers are modified: -; ax, bx, si -; -message - mov bx, 1 ; bh=0, bl=1 (blue) - cld ; increment SI after each lodsb call -message_loop - lodsb ; load a byte from DS:SI into al - cmp al, 0 ; Is it a NULL? - je message_done ; yes, all done - mov ah, 0xE ; bios INT10 Func 0xE - int 0x10 ; bios display a byte in tty mode - jmp short message_loop -message_done +; DS:SI pointer to a NULL terminated string. +; +; Clobber list: +; AX, BX, SI +; +print_string + mov bx, 1 ; BH=0, BL=1 (blue) + cld ; increment SI after each lodsb call +.loop + lodsb ; load a byte from DS:SI into AL + cmp al, 0 ; Is it a NULL? + je .exit ; yes, all done + mov ah, 0xE ; INT10 Func 0xE + int 0x10 ; display byte in tty mode + jmp short .loop +.exit ret +%if DEBUG + ;-------------------------------------------------------------------------- ; Write a ASCII character to the console. ; ; Arguments: -; al contains the ASCII character printed. -; -putchar - push bx - mov bx, 1 ; bh=0, bl=1 (blue) - mov ah, 0x0e ; bios int 10, function 0xe - int 0x10 ; bios display a byte in tty mode - pop bx - ret - -%IF DEBUG -;========================================================================== -; DEBUG FUNCTION START +; AL = ASCII character. ; -; If DEBUG is set to 1, this booter will become too large for the MBR, -; but it will still be less than 510 bytes, which is fine for a partition's -; boot sector. -;========================================================================== +print_char + pusha + mov bx, 1 ; BH=0, BL=1 (blue) + mov ah, 0x0e ; bios INT 10, Function 0xE + int 0x10 ; display byte in tty mode + popa + ret ;-------------------------------------------------------------------------- ; Write a variable number of spaces to the console. ; ; Arguments: -; al number to spaces to display +; AL = number to spaces. ; -putspace - push cx +print_spaces: + pusha xor cx, cx - mov cl, al ; use cx as the loop counter - mov al, ' ' ; character to print -putspace_loop - jcxz putspace_done - call putchar - loop putspace_loop -putspace_done - pop cx + mov cl, al ; use CX as the loop counter + mov al, ' ' ; character to print +.loop: + jcxz .exit + call print_char + loop .loop +.exit: + popa ret ;-------------------------------------------------------------------------- -; Write the hex byte value to the console. +; Write the byte value to the console in hex. ; ; Arguments: -; al contains the byte to be displayed. e.g. if al is 0x3f, then 3F -; will be displayed on screen. +; AL = Value to be displayed in hex. ; -display_byte +print_hex: push ax ror al, 4 - call display_nibble ; display upper nibble + call print_nibble ; display upper nibble pop ax - call display_nibble ; display lower nibble - ; - mov ax, 10 ; display carriage return - call putchar - mov ax, 13 - call putchar + call print_nibble ; display lower nibble + + mov al, 10 ; carriage return + call print_char + mov al, 13 + call print_char ret -display_nibble +print_nibble: and al, 0x0f add al, '0' cmp al, '9' - jna display_nibble_1 + jna .print_ascii add al, 'A' - '9' - 1 -display_nibble_1 - call putchar +.print_ascii: + call print_char ret -;========================================================================== -; DEBUG FUNCTION END -;========================================================================== -%ENDIF +%endif ; DEBUG ;-------------------------------------------------------------------------- ; NULL terminated strings. ; -load_error db 10, 13, 'Load Error', 0 +boot_error_str db 10, 13, 'Boot Error', 0 ;-------------------------------------------------------------------------- ; Pad the rest of the 512 byte sized booter with zeroes. The last @@ -558,10 +660,31 @@ load_error db 10, 13, 'Load Error', 0 ; that the 'times' argument is negative. pad_boot - times 446-($-$$) db 0 + times 446-($-$$) db 0 + +%ifdef FLOPPY +;-------------------------------------------------------------------------- +; Put fake partition entries for the bootable floppy image +; +part1bootid db 0x80 ; first partition active +part1head db 0x00 ; head # +part1sect db 0x02 ; sector # (low 6 bits) +part1cyl db 0x00 ; cylinder # (+ high 2 bits of above) +part1systid db 0xab ; Apple boot partition +times 3 db 0x00 ; ignore head/cyl/sect #'s +part1relsect dd 0x00000001 ; start at sector 1 +part1numsect dd 0x00000080 ; 64K for booter +part2bootid db 0x00 ; not active +times 3 db 0x00 ; ignore head/cyl/sect #'s +part2systid db 0xa8 ; Apple UFS partition +times 3 db 0x00 ; ignore head/cyl/sect #'s +part2relsect dd 0x00000082 ; start after booter +; part2numsect dd 0x00000abe ; 1.44MB - 65K +part2numsect dd 0x000015fe ; 2.88MB - 65K +%endif pad_table_and_sig times 510-($-$$) db 0 - dw BOOTSIG + dw kBootSignature END diff --git a/i386/boot1/boot1.s b/i386/boot1/boot1.s index 6e0cbbb..8af950e 100644 --- a/i386/boot1/boot1.s +++ b/i386/boot1/boot1.s @@ -46,6 +46,7 @@ ; This code is written for the NASM assembler. ; nasm boot0.s -o boot0 + ;-------------------------------------------------------------------------- ; Constants. @@ -59,13 +60,14 @@ BOOTLOAD EQU 0x7C00 ; booter load address BOOTRELOC EQU 0xE000 ; booter is relocated here BOOTSIG EQU 0xAA55 ; booter signature -BOOT2_SIZE EQU 88 ; load this many blocks for boot2 -BOOT2_ADDR EQU 0x3000 ; where to load boot2 +BOOT2_SIZE EQU 112 ; load this many blocks for boot2 +BOOT2_ADDR EQU 0x0200 ; where to load boot2 +BOOT2_SEG EQU 0x2000 %IF BOOTDEV = FLOPPY -DRIVE_NUM EQU FLOPPY ; floppy drive +DRIVE_NUM EQU FLOPPY ; floppy drive %ELSE -DRIVE_NUM EQU HDISK ; "C" drive +DRIVE_NUM EQU HDISK ; "C" drive %ENDIF SECTOR_BYTES EQU 512 ; sector size in bytes @@ -106,8 +108,8 @@ start ; or from 0:7C00h to BOOTSEG:BOOTRELOC. ; mov es, ax ; es <- BOOTSEG - xor ax, ax - mov ds, ax ; ds <- 0 + mov ds, ax ; ds <- BOOTSEG + mov si, BOOTLOAD ; si <- BOOTLOAD (source) mov di, BOOTRELOC ; di <- BOOTRELOC (destination) ; @@ -123,9 +125,6 @@ start ; Start execution from the relocated location. ; start_reloc - mov ax, BOOTSEG - mov ds, ax ; ds <- BOOTSEG - mov al, '=' ; indicate execution start call putchar @@ -142,9 +141,6 @@ start_reloc mov al, '>' ; indicate INT13/F8 success call putchar - mov ax, BOOTSEG ; es <- BOOTSEG - mov es, ax - ; Since this code may not always reside in the MBR, we will always ; start by loading the MBR to BUF_MBR. ; @@ -227,7 +223,7 @@ find_booter_ext cmp BYTE [si + 4], TYPE_EXT_1 ; Is this an extended partition? je find_booter_ext_2 ; yes, load its partition table - + cmp BYTE [si + 4], TYPE_EXT_2 ; Is this an extended partition? je find_booter_ext_2 ; yes, load its partition table @@ -298,14 +294,15 @@ load_booter mov cx, 1 ; skip the initial boot sector mov ax, BOOT2_SIZE ; read BOOT2_SIZE sectors + mov bx, BOOT2_SEG + mov es, bx mov bx, BOOT2_ADDR ; where to place boot2 code call load ; load it... - xor edx, edx ; argument for boot2 (hard drive boot) -%IF BOOTDEV = FLOPPY - inc edx ; floppy is dev 1 -%ENDIF - jmp BOOTSEG:BOOT2_ADDR ; there is no going back now! + xor edx, edx + mov dl, DRIVE_NUM ; argument for boot2 + + jmp BOOT2_SEG:BOOT2_ADDR ; there is no going back now! ;-------------------------------------------------------------------------- ; Load sectors from disk using INT13/F2 call. The sectors are loaded @@ -347,8 +344,8 @@ load_exit ; ; Arguments: ; [chs_cx][chs_dx] - CHS starting position -; bx - pointer to the sector memory buffer -; (must not cross a segment boundary) +; es:bx - pointer to the sector memory buffer +; (must not cross a segment boundary) ; ; Returns: ; CF = 0 success @@ -570,27 +567,27 @@ load_error db 10, 13, 'Load Error', 0 ; that the 'times' argument is negative. pad_boot - times 446-($-$$) db 0 + times 446-($-$$) db 0 %IF BOOTDEV = FLOPPY ;-------------------------------------------------------------------------- ; Put fake partition entries for the bootable floppy image ; -part1bootid db 0x80 ; first partition active -part1head db 0x00 ; head # -part1sect db 0x02 ; sector # (low 6 bits) -part1cyl db 0x00 ; cylinder # (+ high 2 bits of above) -part1systid db 0xab ; Apple boot partition -times 3 db 0x00 ; ignore head/cyl/sect #'s -part1relsect dd 0x00000001 ; start at sector 1 -part1numsect dd 0x00000058 ; 44K for booter -part2bootid db 0x00 ; not active -times 3 db 0x00 ; ignore head/cyl/sect #'s -part2systid db 0xa8 ; Apple UFS partition -times 3 db 0x00 ; ignore head/cyl/sect #'s -part2relsect dd 0x0000005a ; start after booter -; part2numsect dd 0x00000ae6 ; 1.44MB - 45K -part2numsect dd 0x00001626 ; 2.88MB - 45K +part1bootid db 0x80 ; first partition active +part1head db 0x00 ; head # +part1sect db 0x02 ; sector # (low 6 bits) +part1cyl db 0x00 ; cylinder # (+ high 2 bits of above) +part1systid db 0xab ; Apple boot partition +times 3 db 0x00 ; ignore head/cyl/sect #'s +part1relsect dd 0x00000001 ; start at sector 1 +part1numsect dd 0x00000080 ; 64K for booter +part2bootid db 0x00 ; not active +times 3 db 0x00 ; ignore head/cyl/sect #'s +part2systid db 0xa8 ; Apple UFS partition +times 3 db 0x00 ; ignore head/cyl/sect #'s +part2relsect dd 0x00000082 ; start after booter +; part2numsect dd 0x00000abe ; 1.44MB - 65K +part2numsect dd 0x000015fe ; 2.88MB - 65K %ENDIF pad_table_and_sig diff --git a/i386/boot2/Makefile b/i386/boot2/Makefile index 3374438..8bfefb0 100644 --- a/i386/boot2/Makefile +++ b/i386/boot2/Makefile @@ -6,8 +6,8 @@ DIR = boot2 include ../MakePaths.dir OPTIM = -Os -CFLAGS = $(RC_CFLAGS) $(OPTIM) $(MORECPP) -arch i386 -g -Wmost -Wno-precomp \ - -munaligned-text -DSAIO_INTERNAL_USER -static -traditional-cpp +CFLAGS = $(RC_CFLAGS) $(OPTIM) $(MORECPP) -arch i386 -g -Wmost -Werror \ + -fno-builtin -DSAIO_INTERNAL_USER -static DEFINES= CONFIG = hd SYMDIR = $(SYMROOT) @@ -32,19 +32,19 @@ VPATH = $(OBJROOT):$(SYMROOT) # The ordering is important; # boot2.o must be first. -OBJS = boot2.o boot.o graphics.o drivers.o prompt.o +OBJS = boot2.o boot.o graphics.o drivers.o prompt.o options.o # button.o browser.o scrollbar.o == NOTYET UTILDIR = ../util SFILES = boot2.s -CFILES = boot.c graphics.c drivers.c prompt.c +CFILES = boot.c graphics.c drivers.c prompt.c options.c HFILES = boot.h OTHERFILES = Makefile ALLSRC = $(FOREIGNSRC) $(FOREIGNBIN) $(SFILES) $(CFILES) \ $(HFILES) $(OTHERFILES) DIRS_NEEDED = $(OBJROOT) $(SYMROOT) -BOOT2ADDR = 3000 -MAXBOOTSIZE = 45056 +BOOT2ADDR = 20200 +MAXBOOTSIZE = 65024 all: $(DIRS_NEEDED) boot diff --git a/i386/boot2/appleClut8.h b/i386/boot2/appleClut8.h new file mode 100644 index 0000000..7e7ddff --- /dev/null +++ b/i386/boot2/appleClut8.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.1 (the "License"). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef __BOOT2_APPLECLUT8_H +#define __BOOT2_APPLECLUT8_H + +static const unsigned char appleClut8[ 256 * 3 ] = +{ + 0xff,0xff,0xff, 0xfe,0xfe,0xfe, 0xfd,0xfd,0xfd, 0xb8,0x27,0x2b, + 0xfc,0xfc,0xfc, 0xff,0xff,0x00, 0xfa,0xfa,0xfa, 0xf9,0xf9,0xf9, + 0xf8,0xf8,0xf8, 0xf7,0xf7,0xf7, 0xf6,0xf6,0xf6, 0xf5,0xf5,0xf5, + 0xf4,0xf4,0xf4, 0xf2,0xf2,0xf2, 0xf1,0xf1,0xf1, 0x00,0x00,0x00, + 0xef,0xef,0xef, 0xee,0xee,0xee, 0xed,0xed,0xed, 0xeb,0xeb,0xeb, + 0xe8,0xe8,0xe8, 0xe7,0xe7,0xe7, 0xc9,0x38,0x3e, 0xe5,0xe5,0xe5, + 0xff,0x00,0xff, 0xfb,0xfb,0xfb, 0xde,0x6c,0x72, 0xe0,0xe0,0xe0, + 0xe8,0x86,0x90, 0xde,0xde,0xde, 0xdd,0xdd,0xdd, 0xd3,0x7e,0x8d, + 0xd9,0xd9,0xd9, 0xf3,0x96,0xa6, 0xb1,0x1c,0x39, 0xff,0x00,0x00, + 0xbe,0x5e,0x72, 0xd3,0xd3,0xd3, 0xc6,0x2e,0x67, 0xd1,0xd1,0xd1, + 0xa3,0x06,0x45, 0xce,0xce,0xce, 0xcc,0xcc,0xff, 0xcc,0xcc,0xcc, + 0xc6,0x8f,0xa7, 0xe1,0xd3,0xd9, 0xce,0x9e,0xb4, 0xca,0xca,0xca, + 0xbf,0x3f,0x7d, 0xc9,0xc9,0xc9, 0xf4,0x89,0xbe, 0xc6,0xc6,0xc6, + 0xd6,0x51,0x97, 0xc9,0x2c,0x84, 0x96,0x1a,0x6a, 0xc2,0xc2,0xc2, + 0xf3,0x6f,0xc6, 0xe5,0x4c,0xbb, 0xb7,0x5a,0x9c, 0xbf,0xbf,0xbf, + 0xbe,0xbe,0xbe, 0xbd,0xbd,0xbd, 0xb8,0x21,0xa2, 0xd3,0x44,0xc0, + 0xc2,0x66,0xb7, 0xf4,0x66,0xe6, 0xfc,0x73,0xfd, 0xb9,0xb9,0xb9, + 0xea,0xdf,0xea, 0xd4,0x71,0xd5, 0xf9,0x8b,0xff, 0xf5,0xad,0xff, + 0xbc,0x92,0xc2, 0xc7,0x4f,0xd9, 0xa0,0x44,0xaf, 0xc8,0x8c,0xd5, + 0xd7,0x74,0xf7, 0xb4,0xb4,0xb4, 0xda,0x95,0xf9, 0xed,0xcb,0xff, + 0xb2,0xb2,0xb2, 0xa1,0x61,0xd7, 0xb2,0x85,0xe2, 0x59,0x26,0x9c, + 0x7c,0x51,0xcc, 0xb0,0xb0,0xb0, 0xb4,0x8e,0xfc, 0xd5,0xc0,0xff, + 0x5d,0x32,0xcc, 0x7b,0x5c,0xe5, 0xc0,0xb0,0xfd, 0x60,0x53,0xad, + 0x12,0x0c,0x7e, 0x2e,0x29,0x99, 0x79,0x78,0xe9, 0x5b,0x5c,0xd0, + 0x69,0x6a,0xcc, 0x93,0x94,0xf8, 0x92,0x92,0xc3, 0x41,0x44,0xba, + 0xa8,0xab,0xff, 0xa3,0xa3,0xa3, 0xdb,0xdd,0xea, 0x31,0x49,0xaa, + 0x70,0x8f,0xf9, 0x48,0x66,0xc1, 0x5c,0x7e,0xe9, 0xe2,0xe5,0xeb, + 0xb0,0xcd,0xff, 0x6c,0x89,0xb7, 0x34,0x65,0xaf, 0x8c,0xb9,0xff, + 0x37,0x79,0xd4, 0x5a,0x99,0xea, 0x0e,0x4c,0x95, 0x79,0xb9,0xff, + 0x8a,0xa3,0xbc, 0x20,0x61,0x9d, 0x8f,0xae,0xca, 0x0a,0x60,0xa8, + 0x3f,0x94,0xd9, 0x63,0xb5,0xf9, 0xe2,0xe8,0xed, 0x28,0x6a,0x99, + 0x55,0xb2,0xe7, 0x32,0x89,0xa9, 0xcf,0xda,0xde, 0x29,0xa1,0xc7, + 0x86,0xa9,0xb4, 0x00,0x5f,0x79, 0x0c,0x77,0x8e, 0x12,0x8f,0xab, + 0x41,0xba,0xd5, 0x24,0x82,0x83, 0x2c,0xc4,0xc3, 0x1a,0xab,0xa6, + 0x4b,0xa8,0xa2, 0x0a,0x93,0x85, 0x0d,0xa5,0x96, 0x26,0xbc,0xac, + 0x04,0x81,0x72, 0x19,0xb3,0x86, 0x29,0xc1,0x94, 0x21,0x9c,0x71, + 0x02,0x8c,0x50, 0x35,0xd0,0x89, 0x46,0xa5,0x76, 0x02,0x7d,0x39, + 0x29,0xc9,0x71, 0x57,0xd6,0x8f, 0xa2,0xb5,0xaa, 0x01,0x88,0x2a, + 0x74,0xbe,0x8a, 0x19,0xb6,0x47, 0x2d,0xc6,0x51, 0x38,0xde,0x5d, + 0x4c,0xf4,0x6f, 0x91,0x9c,0x93, 0x00,0x8e,0x19, 0x10,0xaf,0x28, + 0xe3,0xe3,0xe3, 0x08,0xa1,0x1a, 0x59,0xc2,0x61, 0xf0,0xf0,0xf0, + 0x8f,0x9c,0x90, 0x23,0xce,0x2a, 0x12,0xba,0x17, 0x01,0x8a,0x02, + 0x03,0x9a,0x02, 0x40,0xe4,0x40, 0x08,0xb2,0x05, 0x13,0xcc,0x0f, + 0x36,0xd7,0x32, 0x28,0xe9,0x1f, 0x53,0xfb,0x4c, 0x6f,0xaf,0x6a, + 0x71,0xe0,0x67, 0x32,0xc0,0x12, 0x29,0xa5,0x08, 0x5c,0xdd,0x35, + 0x00,0xff,0xff, 0x63,0xc8,0x45, 0x86,0xfd,0x5b, 0x71,0xf6,0x39, + 0x55,0xcc,0x15, 0x00,0xff,0x00, 0x90,0xca,0x6e, 0x43,0xa7,0x01, + 0x8d,0xe4,0x37, 0xb3,0xf0,0x64, 0x85,0x8e,0x7a, 0xb0,0xfa,0x4d, + 0xd6,0xd6,0xd6, 0x88,0xd0,0x1a, 0x6a,0xa7,0x03, 0x98,0xbf,0x41, + 0xcd,0xf8,0x51, 0x94,0xa4,0x55, 0x91,0xb0,0x0a, 0xda,0xf1,0x3c, + 0xba,0xca,0x53, 0xb9,0xc3,0x28, 0xb1,0xba,0x12, 0xd2,0xd9,0x26, + 0xe8,0xec,0x2d, 0x98,0x96,0x02, 0xad,0xad,0x5c, 0xe2,0xd8,0x38, + 0xd9,0xc4,0x38, 0xa8,0x9a,0x50, 0x00,0x00,0xff, 0xbe,0xae,0x5e, + 0x9a,0x98,0x8e, 0xac,0x8d,0x0d, 0xc5,0xa0,0x2b, 0xdb,0xb5,0x48, + 0xdd,0x00,0x00, 0x9c,0x6d,0x03, 0xd4,0xa8,0x47, 0xb7,0x71,0x17, + 0xdc,0xa1,0x5a, 0xb9,0x9c,0x7c, 0xb4,0xab,0xa2, 0x9e,0x4b,0x01, + 0xc8,0x78,0x35, 0xd2,0x8d,0x51, 0xad,0x52,0x0f, 0x00,0xbb,0x00, + 0xb2,0x66,0x38, 0xb1,0xa6,0x9f, 0xb1,0x87,0x6f, 0xa4,0x34,0x03, + 0xee,0x9e,0x85, 0xc9,0x73,0x5a, 0xe6,0x94,0x7c, 0xa9,0x22,0x06, + 0xdb,0x87,0x74, 0xb0,0x2e,0x15, 0xb7,0x5a,0x50, 0xb2,0x42,0x3b, + 0xcd,0x73,0x6e, 0xd9,0x58,0x58, 0xac,0xac,0xac, 0xa0,0xa0,0xa0, + 0x9a,0x9a,0x9a, 0x92,0x92,0x92, 0x8e,0x8e,0x8e, 0xbb,0xbb,0xbb, + 0x81,0x81,0x81, 0x88,0x88,0x88, 0x77,0x77,0x77, 0x55,0x55,0x55, + 0x44,0x44,0x44, 0x22,0x22,0x22, 0x7b,0x7b,0x7b, 0x00,0x00,0x00 +}; + +#endif /* !__BOOT2_APPLECLUT8_H */ diff --git a/i386/boot2/boot.c b/i386/boot2/boot.c index 72f1be5..368acab 100644 --- a/i386/boot2/boot.c +++ b/i386/boot2/boot.c @@ -48,47 +48,28 @@ * Completely reworked by Sam Streeper (sam_s@NeXT.com) * Reworked again by Curtis Galloway (galloway@NeXT.com) */ -#include "libsa.h" -#include "memory.h" -#include "saio.h" -#include "libsaio.h" -#include "kernBootStruct.h" + #include "boot.h" -#include "nbp.h" /* * The user asked for boot graphics. */ -static BOOL gWantBootGraphics = NO; - -/* - * The device that the booter was loaded from. - */ -int gBootDev; +BOOL gBootGraphics = NO; +int gBIOSDev; +long gBootMode = kBootModeNormal; -extern char * gFilename; -extern BOOL sysConfigValid; -extern char bootPrompt[]; -extern BOOL errors; -extern BOOL gVerboseMode; -extern BOOL gSilentBoot; - -/* - * Prototypes. - */ -static void getBootString(); +static BOOL gUnloadPXEOnExit = 0; /* * How long to wait (in seconds) to load the * kernel after displaying the "boot:" prompt. */ -#define kBootTimeout 10 +#define kBootErrorTimeout 5 //========================================================================== // Zero the BSS. -static void -zeroBSS() +static void zeroBSS() { extern char _DATA__bss__begin, _DATA__bss__end; extern char _DATA__common__begin, _DATA__common__end; @@ -103,8 +84,7 @@ zeroBSS() //========================================================================== // execKernel - Load the kernel image (mach-o) and jump to its entry point. -static int -execKernel(int fd) +static int execKernel(int fd) { register KERNBOOTSTRUCT * kbp = kernBootStruct; static struct mach_header head; @@ -117,8 +97,7 @@ execKernel(int fd) kbp->kaddr = kbp->ksize = 0; - ret = loadprog( kbp->kernDev, - fd, + ret = loadprog( kbp->kernDev, fd, &head, &kernelEntry, (char **) &kbp->kaddr, @@ -129,18 +108,18 @@ execKernel(int fd) if ( ret != 0 ) return ret; - // Load boot drivers from the specifed root. + // Load boot drivers from the specifed root path. LoadDrivers("/"); clearActivityIndicator(); - if (errors) { + if (gErrors) { printf("Errors encountered while starting up the computer.\n"); - printf("Pausing %d seconds...\n", kBootTimeout); - sleep(kBootTimeout); + printf("Pausing %d seconds...\n", kBootErrorTimeout); + sleep(kBootErrorTimeout); } - message("Starting Darwin/x86", 0); + printf("Starting Darwin/x86"); turnOffFloppy(); @@ -153,24 +132,22 @@ execKernel(int fd) // Cleanup the PXE base code. - if ( gBootDev == kBootDevNetwork ) + if ( gUnloadPXEOnExit ) { if ( (ret = nbpUnloadBaseCode()) != nbpStatusSuccess ) { - printf("nbpUnloadBaseCode error %d\n", (int) ret); sleep(2); + printf("nbpUnloadBaseCode error %d\n", (int) ret); + sleep(2); } } - // Switch to graphics mode just before starting the kernel. + // Switch to desired video mode just before starting the kernel. - if ( gWantBootGraphics ) - { - setMode(GRAPHICS_MODE); - } + setVideoMode( gBootGraphics ? GRAPHICS_MODE : TEXT_MODE ); // Jump to kernel's entry point. There's no going back now. - startprog(kernelEntry); + startprog( kernelEntry ); // Not reached @@ -178,37 +155,39 @@ execKernel(int fd) } //========================================================================== -// Scan and record the system's PCI bus information. +// Scan and record the system's hardware information. static void scanHardware() { -extern int ReadPCIBusInfo(PCI_bus_info_t *); -extern void PCI_Bus_Init(PCI_bus_info_t *); + extern int ReadPCIBusInfo(PCI_bus_info_t *); + extern void PCI_Bus_Init(PCI_bus_info_t *); ReadPCIBusInfo( &kernBootStruct->pciInfo ); - PCI_Bus_Init( &kernBootStruct->pciInfo ); + + // + // Initialize PCI matching support in the booter. + // Not used, commented out to minimize code size. + // + // PCI_Bus_Init( &kernBootStruct->pciInfo ); } //========================================================================== -// The 'main' function for the booter. This function is called by the -// assembly routine init(), which is in turn called by boot1 or by -// NBP. +// The 'main' function for the booter. Called by boot0 when booting +// from a block device, or by the network booter. // // arguments: -// bootdev - Value passed from boot1/NBP to specify the device -// that the booter was loaded from. See boot.h for the list -// of allowable values. +// biosdev - Value passed from boot1/NBP to specify the device +// that the booter was loaded from. // -// If bootdev is kBootDevNetwork, then this function will return if +// If biosdev is kBIOSDevNetwork, then this function will return if // booting was unsuccessful. This allows the PXE firmware to try the -// next bootable device on its list. If bootdev is not kBootDevNetwork, -// this function will not return control back to the caller. +// next boot device on its list. -void -boot(int bootdev) +void boot(int biosdev) { register KERNBOOTSTRUCT * kbp = kernBootStruct; int fd; + int status; zeroBSS(); @@ -216,25 +195,40 @@ boot(int bootdev) enableA20(); - // Remember the device that the booter was loaded from. + // Set reminder to unload the PXE base code. Neglect to unload + // the base code will result in a hang or kernel panic. + + if ( BIOS_DEV_TYPE(biosdev) == kBIOSDevTypeNetwork ) + gUnloadPXEOnExit = 1; + +#if 0 + gUnloadPXEOnExit = 1; + biosdev = 0x80; +#endif - gBootDev = bootdev; + // Record the device that the booter was loaded from. + + gBIOSDev = biosdev & kBIOSDevMask; // Initialize boot info structure. - initKernBootStruct(); + initKernBootStruct( gBIOSDev ); // Setup VGA text mode. + // Not sure if it is safe to call setVideoMode() before the + // config table has been loaded. Call video_mode() instead. - setMode(TEXT_MODE); + video_mode( 2 ); // 80x25 mono text mode. // Scan hardware configuration. scanHardware(); - // Display boot prompt. + // Display banner and show hardware info. - printf( bootPrompt, kbp->convmem, kbp->extmem, kBootTimeout ); + setCursorPosition( 0, 0, 0 ); + printf( bootBanner, kbp->convmem, kbp->extmem ); + printVBEInfo(); // Parse args, load and start kernel. @@ -243,64 +237,18 @@ boot(int bootdev) // Initialize globals. sysConfigValid = 0; - errors = 0; - - // Make sure we are in VGA text mode. - - setMode(TEXT_MODE); - - // Set up kbp->kernDev to reflect the boot device. - - if ( bootdev == kBootDevHardDisk ) - { - if (kbp->numIDEs > 0) - { - kbp->kernDev = DEV_HD; - } - else - { - kbp->kernDev = DEV_SD; - } - } - else if ( bootdev == kBootDevFloppyDisk ) - { - kbp->kernDev = DEV_FLOPPY; - } - else - { - kbp->kernDev = DEV_EN; - } - flushdev(); + gErrors = 0; - // Display boot prompt and get user supplied boot string. - - getBootString(); - - if ( bootdev != kBootDevNetwork ) - { - // To force loading config file off same device as kernel, - // open kernel file to force device change if necessary. - - fd = open(kbp->bootFile, 0); - if (fd >= 0) close(fd); - } - - if ( sysConfigValid == 0 ) - { - if (kbp->kernDev == DEV_EN) - break; // return control back to PXE - else - continue; // keep looping - } + getBootOptions(); + status = processBootOptions(); + if ( status == 1 ) break; + if ( status == -1 ) continue; // Found and loaded a config file. Proceed with boot. - gWantBootGraphics = getBoolForKey( kBootGraphicsKey ); - gSilentBoot = getBoolForKey( kQuietBootKey ); - - message("Loading Darwin/x86", 0); + printf("Loading Darwin/x86\n"); - if ( (fd = openfile(kbp->bootFile, 0)) >= 0 ) + if ( (fd = openfile( kbp->bootFile, 0 )) >= 0 ) { execKernel(fd); // will not return on success } @@ -308,184 +256,21 @@ boot(int bootdev) { error("Can't find %s\n", kbp->bootFile); - if ( bootdev == kBootDevFloppyDisk ) + if ( BIOS_DEV_TYPE(gBIOSDev) == kBIOSDevTypeFloppy ) { // floppy in drive, but failed to load kernel. - bootdev = kBootDevHardDisk; - message("Couldn't start up the computer using this " - "floppy disk.", 0); + gBIOSDev = kBIOSDevTypeHardDrive; + initKernBootStruct( gBIOSDev ); + printf("Attempt to load from hard drive."); } - else if ( bootdev == kBootDevNetwork ) + else if ( BIOS_DEV_TYPE(gBIOSDev) == kBIOSDevTypeNetwork ) { - break; // Return control back to PXE. + // Return control back to PXE. Don't unload PXE base code. + gUnloadPXEOnExit = 0; + break; } } } /* while(1) */ -} - -//========================================================================== -// Skip spaces/tabs characters. - -static inline void -skipblanks(char ** cp) -{ - while ( **(cp) == ' ' || **(cp) == '\t' ) - ++(*cp); -} - -//========================================================================== -// Load the help file and display the file contents on the screen. - -static void showHelp() -{ -#define BOOT_DIR_DISK "/usr/standalone/i386/" -#define BOOT_DIR_NET "" -#define makeFilePath(x) \ - (gBootDev == kBootDevNetwork) ? BOOT_DIR_NET x : BOOT_DIR_DISK x - - int fd; - char * help = makeFilePath("BootHelp.txt"); - - if ( (fd = open(help, 0)) >= 0 ) - { - char * buffer = malloc( file_size(fd) ); - read(fd, buffer, file_size(fd) - 1); - close(fd); - printf("%s", buffer); - free(buffer); - } -} - -//========================================================================== -// Returns 1 if the string pointed by 'cp' contains an user-specified -// kernel image file name. Used by getBootString() function. - -static int -containsKernelName(const char * cp) -{ - register char c; - - skipblanks(&cp); - - // Convert char to lower case. - - c = *cp | 0x20; - - // Must start with a letter or a '/'. - - if ( (c < 'a' || c > 'z') && ( c != '/' ) ) - return 0; - - // Keep consuming characters until we hit a separator. - - while ( *cp && (*cp != '=') && (*cp != ' ') && (*cp != '\t') ) - cp++; - - // Only SPACE or TAB separator is accepted. - // Reject everything else. - - if (*cp == '=') - return 0; - - return 1; -} - -//========================================================================== -// Display the "boot:" prompt and copies the user supplied string to -// kernBootStruct->bootString. The kernel image file name is written -// to kernBootStruct->bootFile. - -static void -getBootString() -{ - char line[BOOT_STRING_LEN]; - char * cp; - char * val; - int count; - static int timeout = kBootTimeout; - - do { - line[0] = '\0'; - cp = &line[0]; - - // If there were errors, don't timeout on boot prompt since - // the same error is likely to occur again. - - if ( errors ) timeout = 0; - errors = 0; - - // Print the boot prompt and wait a few seconds for user input. - - printf("\n"); - count = Gets(line, sizeof(line), timeout, "boot: ", ""); - flushdev(); - - // If something was typed, don't use automatic boot again. - // The boot: prompt will not timeout and go away until - // the user hits the return key. - - if ( count ) timeout = 0; - - skipblanks(&cp); - - // If user typed '?', then display the usage message. - - if ( *cp == '?' ) - { - showHelp(); - continue; - } - - // Load config table file specified by the user, or fallback - // to the default one. - - val = 0; - getValueForBootKey(cp, "config", &val, &count); - loadSystemConfig(val, count); - if ( !sysConfigValid ) - continue; - } - while ( 0 ); - - // Did the user specify a kernel file name at the boot prompt? - - if ( containsKernelName(cp) == 0 ) - { - // User did not type a kernel image file name on the boot prompt. - // This is fine, read the default kernel file name from the - // config table. - - if ( getValueForKey(kKernelNameKey, &val, &count) ) - { - strncpy(kernBootStruct->bootFile, val, count); - } - } - else - { - // Get the kernel name from the user-supplied boot string, - // and copy the name to the buffer provided. - - char * namep = kernBootStruct->bootFile; - - while ( *cp && !(*cp == ' ' || *cp == '\t') ) - *namep++ = *cp++; - - *namep = '\0'; - } - - // Verbose flag specified. - - gVerboseMode = getValueForBootKey(cp, "-v", &val, &count); - - // Save the boot string in kernBootStruct->bootString. - - if ( getValueForKey(kKernelFlagsKey, &val, &count) && count ) - { - strncpy( kernBootStruct->bootString, val, count ); - } - if ( strlen(cp) ) - { - strcat(kernBootStruct->bootString, " "); - strcat(kernBootStruct->bootString, cp); - } + + if (gUnloadPXEOnExit) nbpUnloadBaseCode(); } diff --git a/i386/boot2/boot.h b/i386/boot2/boot.h index c338591..851c537 100644 --- a/i386/boot2/boot.h +++ b/i386/boot2/boot.h @@ -29,36 +29,42 @@ #ifndef __BOOT2_BOOT_H #define __BOOT2_BOOT_H +#include "libsaio.h" + /* * Keys used in system Default.table / Instance0.table */ #define kGraphicsModeKey "Graphics Mode" +#define kTextModeKey "Text Mode" #define kBootGraphicsKey "Boot Graphics" #define kQuietBootKey "Quiet Boot" #define kKernelFlagsKey "Kernel Flags" #define kKernelNameKey "Kernel" -/* - * Possible values for the bootdev argument passed to boot(). - */ -enum { - kBootDevHardDisk = 0, - kBootDevFloppyDisk, - kBootDevNetwork -}; - /* * A global set by boot() to record the device that the booter * was loaded from. */ -extern int gBootDev; +extern int gBIOSDev; +extern BOOL gBootGraphics; +extern long gBootMode; +extern BOOL sysConfigValid; +extern char bootBanner[]; +extern char bootPrompt[]; + +// Boot Modes +enum { + kBootModeNormal = 0, + kBootModeSafe, + kBootModeSecure +}; /* * graphics.c */ -extern void message(char * str, int centered); -extern void setMode(int mode); -extern int currentMode(); +extern void printVBEInfo(); +extern void setVideoMode(int mode); +extern int getVideoMode(); extern void spinActivityIndicator(); extern void clearActivityIndicator(); @@ -67,4 +73,10 @@ extern void clearActivityIndicator(); */ extern long LoadDrivers(char * dirSpec); +/* + * options.c + */ +extern void getBootOptions(); +extern int processBootOptions(); + #endif /* !__BOOT2_BOOT_H */ diff --git a/i386/boot2/boot2.s b/i386/boot2/boot2.s index ec16572..ab6389b 100644 --- a/i386/boot2/boot2.s +++ b/i386/boot2/boot2.s @@ -42,9 +42,13 @@ #define data32 .byte 0x66 #define retf .byte 0xcb - .file "boot2.s" + .data + +EXPORT(_chainbootdev) .byte 0x80 +EXPORT(_chainbootflag) .byte 0x00 + .text # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -81,6 +85,9 @@ LABEL(boot2) pushl %edx # bootdev call _boot + testb $0xff, _chainbootflag + jnz start_chain_boot # Jump to a foreign booter + call __prot_to_real # Back to real mode. data32 @@ -96,3 +103,22 @@ LABEL(boot2) retf # Hardcode a far return +start_chain_boot: + xorl %edx, %edx + movb _chainbootdev, %dl # Setup DL with the BIOS device number + + call __prot_to_real # Back to real mode. + + data32 + call __switch_stack # Restore original stack + + pop %es # Restore original ES and DS + pop %ds + popl %edi # Restore all general purpose registers + popl %esi # except EAX. + popl %ebp + popl %ebx + popl %ecx + + data32 + ljmp $0, $0x7c00 # Jump to boot code already in memory diff --git a/i386/boot2/drivers.c b/i386/boot2/drivers.c index e95053a..e335f4e 100644 --- a/i386/boot2/drivers.c +++ b/i386/boot2/drivers.c @@ -29,10 +29,7 @@ * DRI: Josh de Cesare */ -#include "libsaio.h" -#include "memory.h" -#include "kernBootStruct.h" -#include "nbp.h" +#include "sl.h" #include "boot.h" enum { @@ -107,10 +104,15 @@ struct DriversPackage { }; typedef struct DriversPackage DriversPackage; +enum { + kCFBundleType2, + kCFBundleType3 +}; + static long FileLoadDrivers(char *dirSpec, long plugin); static long NetLoadDrivers(char *dirSpec); static long LoadDriverMKext(char *fileSpec); -static long LoadDriverPList(char *dirSpec, char *name); +static long LoadDriverPList(char *dirSpec, char *name, long bundleType); static long LoadMatchedModules(void); static long MatchPersonalities(void); static long MatchLibraries(void); @@ -138,41 +140,15 @@ static TagPtr gPersonalityHead, gPersonalityTail; static char * gExtensionsSpec; static char * gDriverSpec; static char * gFileSpec; +static char * gTempSpec; +static char * gFileName; //========================================================================== // BootX shim functions. -#include - -#define kLoadAddr TFTP_ADDR -#define kLoadSize TFTP_LEN - #define kPageSize 4096 #define RoundPage(x) ((((unsigned)(x)) + kPageSize - 1) & ~(kPageSize - 1)) -static long -LoadFile( char * fileSpec ) -{ - unsigned long count = TFTP_LEN; - unsigned long addr = TFTP_ADDR; - - if ( gBootDev == kBootDevNetwork ) - { - if ( nbpTFTPReadFile(fileSpec, &count, addr) != nbpStatusSuccess ) - return -1; - } - else - { - int fd = open( fileSpec, 0 ); - if ( fd < 0 ) - return -1; - - count = read( fd, (char *) addr, count ); - close(fd); - } - return count; -} - static long gImageFirstBootXAddr; static long gImageLastKernelAddr; @@ -183,7 +159,7 @@ AllocateBootXMemory( long size ) if ( addr < gImageLastKernelAddr ) return 0; - bzero(addr, size); + bzero((void *)addr, size); gImageFirstBootXAddr = addr; @@ -224,76 +200,14 @@ AllocateMemoryRange(char * rangeName, long start, long length, long type) return 0; } -// Map BootX file types to UFS file types defined in ufs/ufs/dir.h. - -enum { - kUnknownFileType = DT_UNKNOWN, - kFlatFileType = DT_REG, - kDirectoryFileType = DT_DIR, - kLinkFileType = DT_LNK -}; - -static long -GetFileInfo( char * dirSpec, char * name, long * flags, long * time ) -{ - struct dirstuff * dir; - struct direct * entry = 0; - - dir = opendir(dirSpec); - if ( dir ) - { - while (( entry = readdir(dir) )) - { - if ( strcmp( entry->d_name, name ) == 0 ) - { - *flags = entry->d_type; - *time = 0; - break; - } - } - closedir(dir); - } - return ( entry ) ? 0 : -1; -} - // Map BootX types to boot counterparts. -#define gBootFileType gBootDev +#define gBootFileType BIOS_DEV_TYPE(gBIOSDev) enum { - kNetworkDeviceType = kBootDevNetwork, - kBlockDeviceType = kBootDevHardDisk + kNetworkDeviceType = kBIOSDevTypeNetwork, + kBlockDeviceType = kBIOSDevTypeHardDrive }; -static struct dirstuff * -OpenDir( char * dirSpec ) -{ - return opendir(dirSpec); -} - -static void -CloseDir( struct dirstuff * dirStuff ) -{ - closedir(dirStuff); -} - -static long -GetDirEntry( struct dirstuff * dir, long * dirIndex, char ** name, - long * flags, long * time) -{ - if ( dir ) - { - struct direct * entry = readdir(dir); - - if ( entry ) - { - *name = entry->d_name; - *flags = entry->d_type; - *time = 0; - return 0; - } - } - return (-1); -} static long InitDriverSupport() @@ -301,9 +215,11 @@ InitDriverSupport() gExtensionsSpec = (char *) malloc( 4096 ); gDriverSpec = (char *) malloc( 4096 ); gFileSpec = (char *) malloc( 4096 ); + gTempSpec = (char *) malloc( 4096 ); + gFileName = (char *) malloc( 4096 ); - if ( !gExtensionsSpec || !gDriverSpec || !gFileSpec ) - stop( "InitDriverSupport error" ); + if ( !gExtensionsSpec || !gDriverSpec || !gFileSpec || !gTempSpec || !gFileName ) + stop("InitDriverSupport error"); gImageLastKernelAddr = RoundPage( kernBootStruct->kaddr + kernBootStruct->ksize ); @@ -368,7 +284,7 @@ long LoadDrivers( char * dirSpec ) #endif MatchPersonalities(); - + MatchLibraries(); LoadMatchedModules(); @@ -382,19 +298,19 @@ long LoadDrivers( char * dirSpec ) static long FileLoadDrivers( char * dirSpec, long plugin ) { - long ret, length, index, flags, time; - char * name; - struct dirstuff * dir; + long ret, length, index, flags, time, bundleType; + const char * name; if ( !plugin ) { long time2; ret = GetFileInfo(dirSpec, "Extensions.mkext", &flags, &time); - if ((ret == 0) && (flags == kFlatFileType)) + if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat)) { ret = GetFileInfo(dirSpec, "Extensions", &flags, &time2); - if ((ret != 0) || (flags == kDirectoryFileType) || (time > time2)) + if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeDirectory) || + (((gBootMode & kBootModeSafe) == 0) && (time > time2))) { sprintf(gDriverSpec, "%sExtensions.mkext", dirSpec); verbose("LoadDrivers: Loading from [%s]\n", gDriverSpec); @@ -407,26 +323,32 @@ FileLoadDrivers( char * dirSpec, long plugin ) verbose("LoadDrivers: Loading from [%s]\n", dirSpec); - // INTEL addition - dir = OpenDir( dirSpec ); - index = 0; while (1) { - // INTEL modification - ret = GetDirEntry(dir, &index, &name, &flags, &time); + ret = GetDirEntry(dirSpec, &index, &name, &flags, &time); if (ret == -1) break; // Make sure this is a directory. - if (flags != kDirectoryFileType) continue; + if ((flags & kFileTypeMask) != kFileTypeDirectory) continue; // Make sure this is a kext. length = strlen(name); if (strcmp(name + length - 5, ".kext")) continue; + // Save the file name. + strcpy(gFileName, name); + + // Determine the bundle type. + sprintf(gTempSpec, "%s/%s", dirSpec, gFileName); + ret = GetFileInfo(gTempSpec, "Contents", &flags, &time); + if (ret == 0) bundleType = kCFBundleType2; + else bundleType = kCFBundleType3; + if (!plugin) - sprintf(gDriverSpec, "%s/%s/Contents/PlugIns", dirSpec, name); + sprintf(gDriverSpec, "%s/%s/%sPlugIns", dirSpec, gFileName, + (bundleType == kCFBundleType2) ? "Contents/" : ""); - ret = LoadDriverPList(dirSpec, name); + ret = LoadDriverPList(dirSpec, gFileName, bundleType); if (ret != 0) { // printf("LoadDrivers: failed\n"); @@ -436,9 +358,6 @@ FileLoadDrivers( char * dirSpec, long plugin ) ret = FileLoadDrivers(gDriverSpec, 1); } - // INTEL addition - if ( dir ) CloseDir( dir ); - return 0; } @@ -488,7 +407,7 @@ LoadDriverMKext( char * fileSpec ) char segName[32]; DriversPackage * package = (DriversPackage *)kLoadAddr; -#define GetPackageElement(e) bswap32(package-> ## e) +#define GetPackageElement(e) NXSwapBigLongToHost(package->e) // Load the MKext. if (LoadFile(fileSpec) == -1) return -1; @@ -522,7 +441,7 @@ LoadDriverMKext( char * fileSpec ) // LoadDriverPList static long -LoadDriverPList( char * dirSpec, char * name ) +LoadDriverPList( char * dirSpec, char * name, long bundleType ) { long length, driverPathLength; ModulePtr module; @@ -534,7 +453,8 @@ LoadDriverPList( char * dirSpec, char * name ) do { // Save the driver path. - sprintf(gFileSpec, "%s/%s/Contents/MacOS/", dirSpec, name); + sprintf(gFileSpec, "%s/%s/%s", dirSpec, name, + (bundleType == kCFBundleType2) ? "Contents/MacOS/" : ""); driverPathLength = strlen(gFileSpec); tmpDriverPath = malloc(driverPathLength + 1); @@ -544,7 +464,8 @@ LoadDriverPList( char * dirSpec, char * name ) // Construct the file spec to the plist, then load it. - sprintf(gFileSpec, "%s/%s/Contents/Info.plist", dirSpec, name); + sprintf(gFileSpec, "%s/%s/%sInfo.plist", dirSpec, name, + (bundleType == kCFBundleType2) ? "Contents/" : ""); length = LoadFile(gFileSpec); if (length == -1) break; diff --git a/i386/boot2/graphics.c b/i386/boot2/graphics.c index db91fe5..da3fb64 100644 --- a/i386/boot2/graphics.c +++ b/i386/boot2/graphics.c @@ -26,159 +26,549 @@ * All rights reserved. */ -#include "libsaio.h" #include "boot.h" #include "vbe.h" -#include "kernBootStruct.h" - -#define CHAR_W 8 -#define CHAR_W_SHIFT 3 -#define CHAR_H 16 -#define CHAR_H_SHIFT 4 -#define BYTE_SHIFT 3 -#define NCOLS (screen_width / CHAR_W) -#define NROWS (screen_height / CHAR_H) -#define SCREEN_W (screen_width) -#define SCREEN_H (screen_height) +#include "appleClut8.h" +#include "happy_screen.h" /* - * Forward declarations. + * for spinning disk */ -static int convert_vbe_mode(char * mode_name, int * mode); -BOOL gSilentBoot; +static int currentIndicator = 0; + +static unsigned long lookUpCLUTIndex( unsigned char index, + unsigned char depth ); + +static void drawColorRectangle( unsigned short x, + unsigned short y, + unsigned short width, + unsigned short height, + unsigned char colorIndex ); + +static void drawDataRectangle( unsigned short x, + unsigned short y, + unsigned short width, + unsigned short height, + unsigned char * data ); + +#define VIDEO(x) (kernBootStruct->video.v_ ## x) + //========================================================================== -// Display a (optionally centered) text message. +// printVBEInfo -void -message(char * str, int centered) +void printVBEInfo() +{ + VBEInfoBlock vbeInfo; + int err; + + // Fetch VBE Controller Info. + + bzero( &vbeInfo, sizeof(vbeInfo) ); + err = getVBEInfo( &vbeInfo ); + if ( err != errSuccess ) + return; + + // Check presence of VESA signature. + + if ( strncmp( vbeInfo.VESASignature, "VESA", 4 ) ) + return; + + // Announce controller properties. + + printf("VESA v%d.%d %dMB (%s)\n", + vbeInfo.VESAVersion >> 8, + vbeInfo.VESAVersion & 0xf, + vbeInfo.TotalMemory / 16, + VBEDecodeFP(const char *, vbeInfo.OEMStringPtr) ); +} + +//========================================================================== +// getVESAModeWithProperties +// +// Return the VESA mode that matches the properties specified. +// If a mode is not found, then return the "best" available mode. + +static unsigned short +getVESAModeWithProperties( unsigned short width, + unsigned short height, + unsigned char bitsPerPixel, + unsigned short attributesSet, + unsigned short attributesClear, + VBEModeInfoBlock * outModeInfo ) { - register int x; + VBEInfoBlock vbeInfo; + unsigned short * modePtr; + VBEModeInfoBlock modeInfo; + unsigned char modeBitsPerPixel; + unsigned short matchedMode = modeEndOfList; + int err; + + // Clear output mode info. - x = (NCOLS - strlen(str)) >> 1; + bzero( outModeInfo, sizeof(*outModeInfo) ); - if ( currentMode() == TEXT_MODE ) + // Get VBE controller info containing the list of supported modes. + + bzero( &vbeInfo, sizeof(vbeInfo) ); + err = getVBEInfo( &vbeInfo ); + if ( err != errSuccess ) + { + return modeEndOfList; + } + + // Loop through the mode list, and find the matching mode. + + for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr ); + *modePtr != modeEndOfList; modePtr++ ) { - if (centered) + // Get mode information. + + bzero( &modeInfo, sizeof(modeInfo) ); + err = getVBEModeInfo( *modePtr, &modeInfo ); + if ( err != errSuccess ) { - while(x--) printf(" "); + continue; } - printf("%s\n", str); - } + +#if 0 // debug + printf("Mode %x: %dx%dx%d mm:%d attr:%x\n", + *modePtr, modeInfo.XResolution, modeInfo.YResolution, + modeInfo.BitsPerPixel, modeInfo.MemoryModel, + modeInfo.ModeAttributes); +#endif + + // Filter out unwanted modes based on mode attributes. + + if ( ( ( modeInfo.ModeAttributes & attributesSet ) != attributesSet ) + || ( ( modeInfo.ModeAttributes & attributesClear ) != 0 ) ) + { + continue; + } + + // Pixel depth in bits. + + modeBitsPerPixel = modeInfo.BitsPerPixel; + + if ( ( modeBitsPerPixel == 4 ) && ( modeInfo.MemoryModel == 0 ) ) + { + // Text mode, 16 colors. + } + else if ( ( modeBitsPerPixel == 8 ) && ( modeInfo.MemoryModel == 4 ) ) + { + // Packed pixel, 256 colors. + } + else if ( ( ( modeBitsPerPixel == 16 ) || ( modeBitsPerPixel == 15 ) ) + && ( modeInfo.MemoryModel == 6 ) + && ( modeInfo.RedMaskSize == 5 ) + && ( modeInfo.GreenMaskSize == 5 ) + && ( modeInfo.BlueMaskSize == 5 ) ) + { + // Direct color, 16 bpp (1:5:5:5). + modeInfo.BitsPerPixel = modeBitsPerPixel = 16; + } + else if ( ( modeBitsPerPixel == 32 ) + && ( modeInfo.MemoryModel == 6 ) + && ( modeInfo.RedMaskSize == 8 ) + && ( modeInfo.GreenMaskSize == 8 ) + && ( modeInfo.BlueMaskSize == 8 ) ) + { + // Direct color, 32 bpp (8:8:8:8). + } + else + { + continue; // Not a supported mode. + } + + // Modes larger than the specified dimensions are skipped. + + if ( ( modeInfo.XResolution > width ) || + ( modeInfo.YResolution > height ) ) + { + continue; + } + + // Perfect match, we're done looking. + + if ( ( modeInfo.XResolution == width ) && + ( modeInfo.YResolution == height ) && + ( modeBitsPerPixel == bitsPerPixel ) ) + { + matchedMode = *modePtr; + bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) ); + break; + } + + // Save the next "best" mode in case a perfect match + // is not found. + + if ( ( modeInfo.XResolution >= outModeInfo->XResolution ) && + ( modeInfo.YResolution >= outModeInfo->YResolution ) && + ( modeBitsPerPixel >= outModeInfo->BitsPerPixel ) ) + { + matchedMode = *modePtr; + bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) ); + } + } + + return matchedMode; } -/* - * for spinning disk - */ -static int currentIndicator = 0; +//========================================================================== +// setupPalette + +static void setupPalette( VBEPalette * p, const unsigned char * g ) +{ + int i; + unsigned char * source = (unsigned char *) g; + + for (i = 0; i < 256; i++) + { + (*p)[i] = 0; + (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 16; // Red + (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 8; // Green + (*p)[i] |= ((unsigned long)((*source++) >> 2)); // Blue + } +} //========================================================================== -// Set the screen mode: TEXT_MODE or GRAPHICS_MODE +// setVESAGraphicsMode -void -setMode(int mode) +static int +setVESAGraphicsMode( unsigned short width, + unsigned short height, + unsigned char bitsPerPixel ) { - unsigned int vmode; - char * vmode_name; - int err = errSuccess; + VBEModeInfoBlock minfo; + unsigned short mode; + int err = errFuncNotSupported; + + do { + mode = getVESAModeWithProperties( width, height, bitsPerPixel, + maColorModeBit | + maModeIsSupportedBit | + maGraphicsModeBit | + maLinearFrameBufferAvailBit, + 0, + &minfo ); + if ( mode == modeEndOfList ) + { + break; + } + + // Set the mode. + + err = setVBEMode( mode | kLinearFrameBufferBit ); + if ( err != errSuccess ) + { + break; + } + + // Set 8-bit color palette. + + if ( minfo.BitsPerPixel == 8 ) + { + VBEPalette palette; + setupPalette( &palette, appleClut8 ); + if ((err = setVBEPalette(palette)) != errSuccess) + { + break; + } + } + + // Is this required for buggy Video BIOS implementations? + // On which adapter? + + if ( minfo.BytesPerScanline == 0 ) + minfo.BytesPerScanline = ( minfo.XResolution * + minfo.BitsPerPixel ) >> 3; - if ( currentMode() == mode ) return; + // Update KernBootStruct using info provided by the selected + // VESA mode. - if ( mode == GRAPHICS_MODE && - (vmode_name = newStringForKey(kGraphicsModeKey)) != 0) + kernBootStruct->graphicsMode = GRAPHICS_MODE; + kernBootStruct->video.v_width = minfo.XResolution; + kernBootStruct->video.v_height = minfo.YResolution; + kernBootStruct->video.v_depth = minfo.BitsPerPixel; + kernBootStruct->video.v_rowBytes = minfo.BytesPerScanline; + kernBootStruct->video.v_baseAddr = VBEMakeUInt32(minfo.PhysBasePtr); + } + while ( 0 ); + + if ( err == errSuccess ) { - // Set to the graphics mode specified in the config table file, - // enable linear frame buffer mode, and update kernBootStruct. + char * happyScreen; + short * happyScreen16; + long * happyScreen32; + long cnt, x, y; + + // Fill the background to white (same as BootX). - if ( convert_vbe_mode(vmode_name, &vmode) == 0 ) - vmode = mode1024x768x256; /* default mode */ + drawColorRectangle( 0, 0, minfo.XResolution, minfo.YResolution, + 0x00 /* color index */ ); - err = set_linear_video_mode(vmode); + // Prepare the data for the happy mac. - if ( err == errSuccess ) + switch ( VIDEO(depth) ) { - kernBootStruct->graphicsMode = GRAPHICS_MODE; - kernBootStruct->video.v_display = gSilentBoot; - kernBootStruct->video.v_baseAddr = (unsigned long) frame_buffer; - kernBootStruct->video.v_width = SCREEN_W; - kernBootStruct->video.v_height = SCREEN_H; - kernBootStruct->video.v_depth = bits_per_pixel; - kernBootStruct->video.v_rowBytes = (screen_rowbytes == 0) ? - (SCREEN_W * bits_per_pixel) >> BYTE_SHIFT : screen_rowbytes; + case 16 : + happyScreen16 = malloc(kHappyScreenWidth * kHappyScreenHeight * 2); + for (cnt = 0; cnt < (kHappyScreenWidth * kHappyScreenHeight); cnt++) + happyScreen16[cnt] = lookUpCLUTIndex(gHappyScreenPict[cnt], 16); + happyScreen = (char *) happyScreen16; + break; + + case 32 : + happyScreen32 = malloc(kHappyScreenWidth * kHappyScreenHeight * 4); + for (cnt = 0; cnt < (kHappyScreenWidth * kHappyScreenHeight); cnt++) + happyScreen32[cnt] = lookUpCLUTIndex(gHappyScreenPict[cnt], 32); + happyScreen = (char *) happyScreen32; + break; + + default : + happyScreen = (char *) gHappyScreenPict; + break; } - free(vmode_name); + x = ( VIDEO(width) - kHappyScreenWidth ) / 2; + y = ( VIDEO(height) - kHappyScreenHeight ) / 2 + kHappyScreenOffset; + + // Draw the happy mac in the center of the display. + + drawDataRectangle( x, y, kHappyScreenWidth, kHappyScreenHeight, + happyScreen ); + } + + return err; +} + +//========================================================================== +// LookUpCLUTIndex + +static unsigned long lookUpCLUTIndex( unsigned char index, + unsigned char depth ) +{ + long result, red, green, blue; + + red = appleClut8[index * 3 + 0]; + green = appleClut8[index * 3 + 1]; + blue = appleClut8[index * 3 + 2]; + + switch (depth) { + case 16 : + result = ((red & 0xF8) << 7) | + ((green & 0xF8) << 2) | + ((blue & 0xF8) >> 3); + result |= (result << 16); + break; + + case 32 : + result = (red << 16) | (green << 8) | blue; + break; + + default : + result = index | (index << 8); + result |= (result << 16); + break; } - - if ( (mode == TEXT_MODE) || (err != errSuccess) ) + + return result; +} + +//========================================================================== +// drawColorRectangle + +static void * stosl(void * dst, long val, long len) +{ + asm( "rep; stosl" + : "=c" (len), "=D" (dst) + : "0" (len), "1" (dst), "a" (val) + : "memory" ); + + return dst; +} + +static void drawColorRectangle( unsigned short x, + unsigned short y, + unsigned short width, + unsigned short height, + unsigned char colorIndex ) +{ + long pixelBytes; + long color = lookUpCLUTIndex( colorIndex, VIDEO(depth) ); + char * vram; + + pixelBytes = VIDEO(depth) / 8; + vram = (char *) VIDEO(baseAddr) + + VIDEO(rowBytes) * y + pixelBytes * x; + + while ( height-- ) { - video_mode(2); // 80x25 text mode - - kernBootStruct->graphicsMode = TEXT_MODE; - kernBootStruct->video.v_display = 0; - kernBootStruct->video.v_baseAddr = (unsigned long) 0xb8000; - kernBootStruct->video.v_width = 80; - kernBootStruct->video.v_height = 25; - kernBootStruct->video.v_depth = 8; - kernBootStruct->video.v_rowBytes = 0x8000; + int rem = ( pixelBytes * width ) % 4; + if ( rem ) bcopy( &color, vram, rem ); + stosl( vram + rem, color, pixelBytes * width / 4 ); + vram += VIDEO(rowBytes); } +} - currentIndicator = 0; +//========================================================================== +// drawDataRectangle + +static void drawDataRectangle( unsigned short x, + unsigned short y, + unsigned short width, + unsigned short height, + unsigned char * data ) +{ + long pixelBytes = VIDEO(depth) / 8; + char * vram = (char *) VIDEO(baseAddr) + + VIDEO(rowBytes) * y + pixelBytes * x; + + while ( height-- ) + { + bcopy( data, vram, width * pixelBytes ); + vram += VIDEO(rowBytes); + data += width * pixelBytes; + } } //========================================================================== -// Return the current screen mode, TEXT_MODE or GRAPHICS_MODE. +// setVESATextMode -int currentMode(void) +static int +setVESATextMode( unsigned short cols, + unsigned short rows, + unsigned char bitsPerPixel ) { - return kernBootStruct->graphicsMode; + VBEModeInfoBlock minfo; + unsigned short mode = modeEndOfList; + + if ( (cols != 80) || (rows != 25) ) // not 80x25 mode + { + mode = getVESAModeWithProperties( cols, rows, bitsPerPixel, + maColorModeBit | + maModeIsSupportedBit, + maGraphicsModeBit, + &minfo ); + } + + if ( ( mode == modeEndOfList ) || ( setVBEMode(mode) != errSuccess ) ) + { + video_mode( 2 ); // VGA BIOS, 80x25 text mode. + minfo.XResolution = 80; + minfo.YResolution = 25; + } + + // Update KernBootStruct using info provided by the selected + // VESA mode. + + kernBootStruct->graphicsMode = TEXT_MODE; + kernBootStruct->video.v_baseAddr = 0xb8000; + kernBootStruct->video.v_width = minfo.XResolution; + kernBootStruct->video.v_height = minfo.YResolution; + kernBootStruct->video.v_depth = 8; + kernBootStruct->video.v_rowBytes = 0x8000; + + return errSuccess; // always return success } //========================================================================== -// Convert from a string describing a graphics mode, to a VGA mode number. - -typedef struct { - char mode_name[15]; - int mode_val; -} mode_table_t; - -mode_table_t mode_table[] = { - { "640x400x256", mode640x400x256 }, - { "640x480x256", mode640x480x256 }, - { "800x600x16", mode800x600x16 }, - { "800x600x256", mode800x600x256 }, - { "1024x768x16", mode1024x768x16 }, - { "1024x768x256", mode1024x768x256 }, - { "1280x1024x16", mode1280x1024x16 }, - { "1280x1024x256", mode1280x1024x256 }, - { "640x480x555", mode640x480x555 }, - { "640x480x888", mode640x480x888 }, - { "800x600x555", mode800x600x555 }, - { "800x600x888", mode800x600x888 }, - { "1024x768x555", mode1024x768x555 }, - { "1024x768x888", mode1024x768x888 }, - { "1280x1024x555", mode1280x1024x555 }, - { "1280x1024x888", mode1280x1024x888 }, - { "", 0 } -}; - -int convert_vbe_mode(char * mode_name, int * mode) +// getNumberArrayFromProperty + +static int +getNumberArrayFromProperty( const char * propKey, + unsigned long numbers[], + unsigned long maxArrayCount ) { - mode_table_t * mtp = mode_table; + char * propStr; + int count = 0; - if (mode_name == 0 || *mode_name == 0) - return 0; +#define _isdigit(c) ((c) >= '0' && (c) <= '9') - while ( *mtp->mode_name ) + propStr = newStringForKey( (char *) propKey ); + if ( propStr ) { - if (strcmp(mtp->mode_name, mode_name) == 0) + char * delimiter = propStr; + + while ( count < maxArrayCount && *propStr != '\0' ) { - *mode = mtp->mode_val; - return 1; + unsigned long val = strtoul( propStr, &delimiter, 10 ); + if ( propStr != delimiter ) + { + numbers[count++] = val; + propStr = delimiter; + } + while ( ( *propStr != '\0' ) && !_isdigit(*propStr) ) + propStr++; } - mtp++; + + free( propStr ); } - return 0; + + return count; +} + +//========================================================================== +// setVideoMode +// +// Set the video mode to TEXT_MODE or GRAPHICS_MODE. + +void +setVideoMode( int mode ) +{ + unsigned long params[3]; + int count; + int err = errSuccess; + + if ( mode == GRAPHICS_MODE ) + { + count = getNumberArrayFromProperty( kGraphicsModeKey, params, 3 ); + if ( count < 3 ) + { + params[0] = 1024; // Default graphics mode is 1024x768x16. + params[1] = 768; + params[2] = 16; + } + + // Map from pixel format to bits per pixel. + + if ( params[2] == 256 ) params[2] = 8; + if ( params[2] == 555 ) params[2] = 16; + if ( params[2] == 888 ) params[2] = 32; + + err = setVESAGraphicsMode( params[0], params[1], params[2] ); + if ( err == errSuccess ) + { + // If this boolean is set to true, then the console driver + // in the kernel will show the animated color wheel on the + // upper left corner. + + kernBootStruct->video.v_display = !gVerboseMode; + } + } + + if ( (mode == TEXT_MODE) || (err != errSuccess) ) + { + count = getNumberArrayFromProperty( kTextModeKey, params, 2 ); + if ( count < 2 ) + { + params[0] = 80; // Default text mode is 80x25. + params[1] = 25; + } + + setVESATextMode( params[0], params[1], 4 ); + kernBootStruct->video.v_display = 0; + } + + currentIndicator = 0; +} + +//========================================================================== +// Return the current video mode, TEXT_MODE or GRAPHICS_MODE. + +int getVideoMode(void) +{ + return kernBootStruct->graphicsMode; } //========================================================================== @@ -202,7 +592,7 @@ spinActivityIndicator( void ) else lastTickTime = currentTickTime; - if ( currentMode() == TEXT_MODE ) + if ( getVideoMode() == TEXT_MODE ) { string[0] = indicator[currentIndicator]; printf(string); @@ -214,7 +604,7 @@ spinActivityIndicator( void ) void clearActivityIndicator( void ) { - if ( currentMode() == TEXT_MODE ) + if ( getVideoMode() == TEXT_MODE ) { printf(" \b"); } diff --git a/i386/boot2/happy_screen.h b/i386/boot2/happy_screen.h new file mode 100644 index 0000000..81f875d --- /dev/null +++ b/i386/boot2/happy_screen.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * happy_screen.h - Picture displayed a the beginning of the boot process + * + * Copyright (c) 2002 Apple Computer, Inc. + * + * DRI: Josh de Cesare + */ + +#define kHappyScreenWidth (52) +#define kHappyScreenHeight (44) +#define kHappyScreenOffset (-44) + +static const unsigned char gHappyScreenPict[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x12,0x27,0xf7,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0xf7,0x27,0x12,0x00,0x00, + 0x00,0x12,0x37,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x37,0x12,0x00, + 0x00,0x27,0x50,0x43,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x43,0x50,0x27,0x00, + 0x00,0xf7,0x50,0x20,0xa3,0x33,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x33,0xa3,0x20,0x50,0xf7,0x00, + 0x00,0x50,0x50,0x00,0x33,0x33,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x33,0x33,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x37,0x3c,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x37,0x3c,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa3,0x55,0x55,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa3,0x55,0x55,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x4d,0x50,0x0d,0x00,0x00,0x00,0x12,0x33,0x09,0x00,0x00,0x00,0x00,0x0b,0x4d,0x50,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x15,0x01,0x00,0x00,0x07,0x4d,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x15,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1e,0x50,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,0x4d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x4d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,0x50,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x29,0x50,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1d,0x50,0x37,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xc0,0x27,0x17,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x31,0x50,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x1b,0x50,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1e,0x50,0x33,0xa3,0x00,0x00,0x00,0x00,0xa3,0x33,0x50,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x2f,0x50,0x33,0x1b,0x0a,0x0a,0x1b,0x33,0x50,0x2f,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x2f,0x50,0x50,0x50,0x50,0x50,0x50,0x2f,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x31,0x43,0x43,0x31,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x4d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x4d,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x00,0x33,0x33,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x33,0x33,0x00,0x50,0x50,0x00, + 0x00,0x50,0x50,0x20,0xa3,0x33,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x33,0xa3,0x20,0x50,0x50,0x00, + 0x00,0x27,0x50,0x43,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x43,0x50,0x27,0x00, + 0x00,0x12,0x37,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x37,0x12,0x00, + 0x00,0x00,0x12,0x27,0xf7,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0xf7,0x27,0x12,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; diff --git a/i386/boot2/options.c b/i386/boot2/options.c new file mode 100644 index 0000000..b48f091 --- /dev/null +++ b/i386/boot2/options.c @@ -0,0 +1,636 @@ +/* + * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.1 (the "License"). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include "boot.h" +#include "fdisk.h" + +enum { + kReturnKey = 0x0d, + kEscapeKey = 0x1b, + kBackspaceKey = 0x08, + kASCIIKeyMask = 0x7f +}; + +enum { + kMenuTopRow = 5, + kMenuMaxItems = 6, + kScreenLastRow = 24 +}; + +static BVRef gBootVolume = 0; + +static void showHelp(); + +//========================================================================== + +enum { + kCursorTypeHidden = 0x0100, + kCursorTypeUnderline = 0x0607 +}; + +typedef struct { + int x; + int y; + int type; +} CursorState; + +static void changeCursor( int col, int row, int type, CursorState * cs ) +{ + if (cs) getCursorPositionAndType( &cs->x, &cs->y, &cs->type ); + setCursorType( type ); + setCursorPosition( col, row, 0 ); +} + +static void moveCursor( int col, int row ) +{ + setCursorPosition( col, row, 0 ); +} + +static void restoreCursor( const CursorState * cs ) +{ + setCursorPosition( cs->x, cs->y, 0 ); + setCursorType( cs->type ); +} + +//========================================================================== + +static void flushKeyboardBuffer() +{ + while ( readKeyboardStatus() ) getc(); +} + +//========================================================================== + +static int countdown( const char * msg, int row, int timeout ) +{ + int time; + int ch = 0; + int col = strlen(msg) + 1; + + flushKeyboardBuffer(); + + moveCursor( 0, row ); + printf(msg); + + for ( time = time18(), timeout++; timeout; ) + { + if (ch = readKeyboardStatus()) + break; + + if ( time18() >= time ) + { + time += 18; + timeout--; + moveCursor( col, row ); + printf("(%d) ", timeout); + } + } + + flushKeyboardBuffer(); + + return ch; +} + +//========================================================================== + +static char gBootArgs[BOOT_STRING_LEN]; +static char * gBootArgsPtr = gBootArgs; +static char * gBootArgsEnd = gBootArgs + BOOT_STRING_LEN - 1; + +static void clearBootArgs() +{ + gBootArgsPtr = gBootArgs; + memset( gBootArgs, '\0', BOOT_STRING_LEN ); +} + +//========================================================================== + +static void showBootPrompt( int row, BOOL visible ) +{ + extern char bootPrompt[]; + + changeCursor( 0, row, kCursorTypeUnderline, 0 ); + clearScreenRows( row, kScreenLastRow ); + clearBootArgs(); + + if ( visible ) + { + printf( bootPrompt ); + } + else + { + printf("Press Return to start up the foreign OS. "); + } +} + +//========================================================================== + +static void updateBootArgs( int key ) +{ + key &= kASCIIKeyMask; + + switch ( key ) + { + case kBackspaceKey: + if ( gBootArgsPtr > gBootArgs ) + { + int x, y, t; + getCursorPositionAndType( &x, &y, &t ); + if ( x == 0 && y ) + { + x = 80; y--; + } + if (x) x--; + setCursorPosition( x, y, 0 ); + putca(' ', 0x07, 1); + *gBootArgsPtr-- = '\0'; + } + break; + + default: + if ( key >= ' ' && gBootArgsPtr < gBootArgsEnd) + { + putchar(key); // echo to screen + *gBootArgsPtr++ = key; + } + break; + } +} + +//========================================================================== + +typedef struct { + char name[80]; + void * param; +} MenuItem; + +static const MenuItem * gMenuItems = NULL; +static int gMenuItemCount; +static int gMenuRow; +static int gMenuHeight; +static int gMenuTop; +static int gMenuBottom; +static int gMenuSelection; + +static void printMenuItem( const MenuItem * item, int highlight ) +{ + printf(" "); + + if ( highlight ) + putca(' ', 0x70, strlen(item->name) + 4); + else + putca(' ', 0x07, 40); + + printf(" %40s\n", item->name); +} + +//========================================================================== + +static void showMenu( const MenuItem * items, int count, + int selection, int row, int height ) +{ + int i; + CursorState cursorState; + + if ( items == NULL || count == 0 ) return; + + // head and tail points to the start and the end of the list. + // top and bottom points to the first and last visible items + // in the menu window. + + gMenuItems = items; + gMenuRow = row; + gMenuHeight = height; + gMenuItemCount = count; + gMenuTop = 0; + gMenuBottom = min( count, height ) - 1; + gMenuSelection = selection; + + // If the selected item is not visible, shift the list down. + + if ( gMenuSelection > gMenuBottom ) + { + gMenuTop += ( gMenuSelection - gMenuBottom ); + gMenuBottom = gMenuSelection; + } + + // Draw the visible items. + + changeCursor( 0, row, kCursorTypeHidden, &cursorState ); + + for ( i = gMenuTop; i <= gMenuBottom; i++ ) + { + printMenuItem( &items[i], (i == gMenuSelection) ); + } + + restoreCursor( &cursorState ); +} + +//========================================================================== + +static int updateMenu( int key, void ** paramPtr ) +{ + int moved = 0; + + union { + struct { + unsigned int + selectionUp : 1, + selectionDown : 1, + scrollUp : 1, + scrollDown : 1; + } f; + unsigned int w; + } draw = {{0}}; + + if ( NULL == gMenuItems ) return 0; + + // Look at the scan code. + + switch ( key ) + { + case 0x4800: // Up Arrow + if ( gMenuSelection != gMenuTop ) + draw.f.selectionUp = 1; + else if ( gMenuTop > 0 ) + draw.f.scrollDown = 1; + break; + + case 0x5000: // Down Arrow + if ( gMenuSelection != gMenuBottom ) + draw.f.selectionDown = 1; + else if ( gMenuBottom < (gMenuItemCount - 1) ) + draw.f.scrollUp = 1; + break; + } + + if ( draw.w ) + { + if ( draw.f.scrollUp ) + { + scollPage(0, gMenuRow, 40, gMenuRow + gMenuHeight - 1, 0x07, 1, 1); + gMenuTop++; gMenuBottom++; + draw.f.selectionDown = 1; + } + + if ( draw.f.scrollDown ) + { + scollPage(0, gMenuRow, 40, gMenuRow + gMenuHeight - 1, 0x07, 1, -1); + gMenuTop--; gMenuBottom--; + draw.f.selectionUp = 1; + } + + if ( draw.f.selectionUp || draw.f.selectionDown ) + { + CursorState cursorState; + + // Set cursor at current position, and clear inverse video. + + changeCursor( 0, gMenuRow + gMenuSelection - gMenuTop, + kCursorTypeHidden, &cursorState ); + + printMenuItem( &gMenuItems[gMenuSelection], 0 ); + + if ( draw.f.selectionUp ) gMenuSelection--; + else gMenuSelection++; + + moveCursor( 0, gMenuRow + gMenuSelection - gMenuTop ); + + printMenuItem( &gMenuItems[gMenuSelection], 1 ); + + restoreCursor( &cursorState ); + } + + *paramPtr = gMenuItems[gMenuSelection].param; + moved = 1; + } + + return moved; +} + +//========================================================================== + +static void skipblanks( const char ** cpp ) +{ + while ( **(cpp) == ' ' || **(cpp) == '\t' ) ++(*cpp); +} + +//========================================================================== + +static const char * extractKernelName( char ** cpp ) +{ + char * kn = *cpp; + char * cp = *cpp; + char c; + + // Convert char to lower case. + + c = *cp | 0x20; + + // Must start with a letter or a '/'. + + if ( (c < 'a' || c > 'z') && ( c != '/' ) ) + return 0; + + // Keep consuming characters until we hit a separator. + + while ( *cp && (*cp != '=') && (*cp != ' ') && (*cp != '\t') ) + cp++; + + // Only SPACE or TAB separator is accepted. + // Reject everything else. + + if (*cp == '=') + return 0; + + // Overwrite the separator, and move the pointer past + // the kernel name. + + if (*cp != '\0') *cp++ = '\0'; + *cpp = cp; + + return kn; +} + +//========================================================================== + +void getBootOptions() +{ + int i; + int key; + int selectIndex = 0; + int bvCount; + int nextRow; + BVRef bvr; + BVRef bvChain; + BVRef menuBVR; + BOOL showPrompt, newShowPrompt; + MenuItem * menuItems = NULL; + static BOOL firstRun = YES; + + clearBootArgs(); + clearScreenRows( kMenuTopRow, kScreenLastRow ); + changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 ); + printf("Scanning device %x...", gBIOSDev); + + // Get a list of bootable volumes on the device. + + bvChain = scanBootVolumes( gBIOSDev, &bvCount ); + gBootVolume = menuBVR = selectBootVolume( bvChain ); + +#if 0 + // When booting from CD (via HD emulation), default to hard + // drive boot when possible. + + if ( gBootVolume->part_type == FDISK_BOOTER && + gBootVolume->biosdev == 0x80 ) + { + // Scan the original device 0x80 that has been displaced + // by the CD-ROM. + + BVRef hd_bvr = selectBootVolume(scanBootVolumes(0x81, 0)); + if ( hd_bvr->flags & kBVFlagNativeBoot ) + { + int key = countdown("Press C to start up from CD-ROM.", + kMenuTopRow, 5); + + if ( (key & 0x5f) != 'c' ) + { + gBootVolume = hd_bvr; + gBIOSDev = hd_bvr->biosdev; + initKernBootStruct( gBIOSDev ); + goto done; + } + } + } +#endif + + // Allow user to override default setting. + + if ( firstRun && + countdown("Press any key to enter startup options.", + kMenuTopRow, 3) == 0 ) + { + goto done; + } + + if ( bvCount ) + { + // Allocate memory for an array of menu items. + + menuItems = (MenuItem *) malloc( sizeof(MenuItem) * bvCount ); + if ( menuItems == NULL ) goto done; + + // Associate a menu item for each BVRef. + + for ( bvr = bvChain, i = bvCount - 1, selectIndex = 0; + bvr; bvr = bvr->next, i-- ) + { + getBootVolumeDescription( bvr, menuItems[i].name, 80 ); + menuItems[i].param = (void *) bvr; + if ( bvr == menuBVR ) selectIndex = i; + } + } + + // Clear screen and hide the blinking cursor. + + clearScreenRows( kMenuTopRow, kMenuTopRow + 2 ); + changeCursor( 0, kMenuTopRow, kCursorTypeHidden, 0 ); + nextRow = kMenuTopRow; + showPrompt = YES; + + // Show the menu. + + if ( bvCount ) + { + printf("Use \30\31 keys to select the startup volume."); + showMenu( menuItems, bvCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems ); + nextRow += min( bvCount, kMenuMaxItems ) + 3; + } + + // Show the boot prompt. + + showPrompt = (bvCount == 0) || (menuBVR->flags & kBVFlagNativeBoot); + showBootPrompt( nextRow, showPrompt ); + + do { + key = getc(); + + updateMenu( key, (void **) &menuBVR ); + + newShowPrompt = (bvCount == 0) || + (menuBVR->flags & kBVFlagNativeBoot); + + if ( newShowPrompt != showPrompt ) + { + showPrompt = newShowPrompt; + showBootPrompt( nextRow, showPrompt ); + } + if ( showPrompt ) updateBootArgs( key ); + + switch ( key & kASCIIKeyMask ) + { + case kReturnKey: + if ( *gBootArgs == '?' ) + { + showHelp(); key = 0; + showBootPrompt( nextRow, showPrompt ); + break; + } + gBootVolume = menuBVR; + break; + + case kEscapeKey: + clearBootArgs(); + break; + + default: + key = 0; + } + } + while ( 0 == key ); + +done: + firstRun = NO; + + clearScreenRows( kMenuTopRow, kScreenLastRow ); + changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 ); + + if ( menuItems ) free(menuItems); +} + +//========================================================================== + +extern unsigned char chainbootdev; +extern unsigned char chainbootflag; + +int processBootOptions() +{ + KERNBOOTSTRUCT * kbp = kernBootStruct; + const char * cp = gBootArgs; + const char * val = 0; + const char * kernel; + int cnt; + + skipblanks( &cp ); + + // Update the unit and partition number. + + if ( gBootVolume ) + { + if ( gBootVolume->flags & kBVFlagForeignBoot ) + { + readBootSector( gBootVolume->biosdev, gBootVolume->part_boff, + (void *) 0x7c00 ); + + // + // Setup edx, and signal intention to chain load the + // foreign booter. + // + + chainbootdev = gBootVolume->biosdev; + chainbootflag = 1; + + return 1; + } + + kbp->kernDev &= ~((B_UNITMASK << B_UNITSHIFT ) | + (B_PARTITIONMASK << B_PARTITIONSHIFT)); + + kbp->kernDev |= MAKEKERNDEV( 0, + /* unit */ BIOS_DEV_UNIT(gBootVolume->biosdev), + /* partition */ gBootVolume->part_no ); + } + + // Load config table specified by the user, or use the default. + + getValueForBootKey( cp, "config", &val, &cnt ); + loadSystemConfig(val, cnt); + if ( !sysConfigValid ) return -1; + + // Use the kernel name specified by the user, or fetch the name + // in the config table. + + if (( kernel = extractKernelName((char **)&cp) )) + { + strcpy( kbp->bootFile, kernel ); + } + else + { + if ( getValueForKey( kKernelNameKey, &val, &cnt ) ) + strncpy( kbp->bootFile, val, cnt ); + } + + // Store the merged kernel flags and boot args. + + getValueForKey( kKernelFlagsKey, &val, &cnt ); + if ( (strlen(cp) + 1 + cnt) < BOOT_STRING_LEN ) + { + if (cnt) strncpy(kbp->bootString, val, cnt); + sprintf(&kbp->bootString[cnt], "%s%s", cnt ? " " : "", cp); + } + + gVerboseMode = getValueForKey( "-v", &val, &cnt ) || + getValueForKey( "-s", &val, &cnt ); + + gBootGraphics = getBoolForKey( kBootGraphicsKey ); + + gBootMode = ( getValueForKey( "-f", &val, &cnt ) ) ? + kBootModeSafe : kBootModeNormal; + + return 0; +} + +//========================================================================== +// Load the help file and display the file contents on the screen. + +static void showHelp() +{ +#define BOOT_HELP_PATH "/usr/standalone/i386/BootHelp.txt" + + int fd; + + if ( (fd = open(BOOT_HELP_PATH, 0)) >= 0 ) + { + char * buffer; + + // Activate and clear page 1 + // Perhaps this should be loaded only once? + + setActiveDisplayPage(1); + clearScreenRows(0, 24); + setCursorPosition( 0, 0, 1 ); + + buffer = malloc( file_size(fd) ); + read(fd, buffer, file_size(fd) - 1); + close(fd); + printf("%s", buffer); + free(buffer); + + // Wait for a keystroke and return to page 0. + + getc(); + setActiveDisplayPage(0); + } +} diff --git a/i386/boot2/prompt.c b/i386/boot2/prompt.c index 4c3eb03..cf2ea4d 100644 --- a/i386/boot2/prompt.c +++ b/i386/boot2/prompt.c @@ -28,12 +28,11 @@ #include "vers.h" -char bootPrompt[] = "\n\nDarwin/x86 boot v" I386BOOT_VERSION "\n" - "%dK conventional / %dK extended memory\n\n" - "Darwin/x86 will start up in %d seconds, or you can:\n" - " Type -v and press Return to start up Darwin/x86 with " - "diagnostic messages\n" - " Type ? and press Return to learn about advanced startup " - "options\n" - " Type any other character to stop Darwin/x86 from " - "starting up automatically\n"; +char bootBanner[] = "\nDarwin/x86 boot v" I386BOOT_VERSION "\n" + "%dK conventional / %dK extended memory\n"; + +char bootPrompt[] = + "Press Return to start up Darwin/x86 with no options, or you can:\n" + " Type -v and press Return to start up with diagnostic messages\n" + " Type ? and press Return to learn about advanced startup options\n\n" + "boot: "; diff --git a/i386/libsa/Makefile b/i386/libsa/Makefile index fbf2c0f..0f65de1 100644 --- a/i386/libsa/Makefile +++ b/i386/libsa/Makefile @@ -7,8 +7,8 @@ INSTALL_SA_DIR = $(DSTROOT)/System/Library/Frameworks/System.framework/Versions/ INSTALL_MD_DIR = $(DSTROOT)/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders/machdep/i386 OPTIM = -Os -CFLAGS = $(RC_CFLAGS) $(OPTIM) $(MORECPP) -arch i386 -g -Wmost -Wno-precomp \ - -munaligned-text -static -traditional-cpp +CFLAGS = $(RC_CFLAGS) $(OPTIM) $(MORECPP) -arch i386 -g -Wmost -Werror \ + -fno-builtin -static INC = -I. -I$(SYMROOT) -I$(UTILDIR) ifneq "" "$(wildcard /bin/mkdirs)" @@ -25,12 +25,12 @@ VPATH = $(OBJROOT):$(SYMROOT) SA_OBJS = prf.o printf.o zalloc.o \ string.o strtol.o error.o \ - setjmp.o qsort.o bswap.o + setjmp.o qsort.o SFILES = setjmp.s CFILES = prf.c printf.c zalloc.c \ string.c strtol.c error.c \ - qsort.c bswap.c + qsort.c HFILES = memory.h EXPORTED_HFILES = libsa.h kernBootStruct.h memory.h INSTALLED_SA_HFILES = libsa.h diff --git a/i386/libsa/bswap.c b/i386/libsa/bswap.c deleted file mode 100644 index 48baf4b..0000000 --- a/i386/libsa/bswap.c +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#include "libsa.h" - -unsigned long bswap32( unsigned long data ) -{ - __asm__ volatile("bswap %0" - : "=r" (data) - : "0" (data)); - return data; -} diff --git a/i386/libsa/libsa.h b/i386/libsa/libsa.h index a88097d..f162c84 100644 --- a/i386/libsa/libsa.h +++ b/i386/libsa/libsa.h @@ -35,11 +35,11 @@ * string.c */ #ifndef bcopy -extern void bcopy(const void * src, void * dst, int len); +extern void bcopy(const void * src, void * dst, size_t len); #endif #ifndef bzero -extern void bzero(void * dst, int len); +extern void bzero(void * dst, size_t len); #endif extern void * memset(void * dst, int c, size_t n); @@ -49,7 +49,8 @@ extern int strncmp(const char * s1, const char * s2, size_t n); extern char * strcpy(char * s1, const char * s2); extern char * strncpy(char * s1, const char * s2, size_t n); extern int atoi(const char * str); -extern int ptol(char * str); +extern int ptol(const char * str); +extern int strlen(const char * str); extern char * strcat(char * s1, const char * s2); extern char * strncat(char * s1, const char * s2, size_t n); @@ -66,30 +67,20 @@ extern char * strerror(int errnum); /* * strtol.c */ -extern long strtol(const char * nptr, - char ** endptr, - int base); - -extern unsigned long strtoul(const char * nptr, - char ** endptr, - int base); +extern long strtol(const char * nptr, char ** endptr, int base); +extern unsigned long strtoul(const char * nptr, char ** endptr, int base); /* * prf.c */ -extern void prf(const char * fmt, - va_list ap, - void (*putfn_p)(), - void * putfn_arg); +extern void prf(const char * fmt, va_list ap, void (*putfn_p)(), + void * putfn_arg); /* * printf.c */ extern int sprintf(char *s, const char * format, ...); -extern int slvprintf(char * buffer, - int len, - const char * fmt, - va_list arg); +extern int slvprintf(char * buffer, int len, const char * fmt, va_list arg); /* * zalloc.c @@ -103,11 +94,6 @@ extern void * realloc(void * ptr, size_t size); * getsegbyname.c */ extern struct segment_command * - getsegbynamefromheader(struct mach_header * mhp, char * segname); - -/* - * bswap.c - */ -extern unsigned long bswap32( unsigned long data ); + getsegbynamefromheader(struct mach_header * mhp, char * segname); #endif /* !__BOOT_LIBSA_H */ diff --git a/i386/libsa/memory.h b/i386/libsa/memory.h index ee65894..7eed3ea 100644 --- a/i386/libsa/memory.h +++ b/i386/libsa/memory.h @@ -27,48 +27,74 @@ /* Memory addresses used by booter and friends */ +#define BASE_SEG 0x2000 +#define STACK_SEG 0x3000 +#define STACK_OFS 0xFFF0 // stack pointer + +#define BOOT2_SEG BASE_SEG +#define BOOT2_OFS 0x0200 // 512 byte disk sector offset + +#define BIOS_ADDR 0x0C00 // BIOS disk I/O buffer +#define BIOS_LEN 0x2400 // 9K + /* These are all "virtual" addresses... * which are physical addresses plus MEMBASE. */ - -#define MEMBASE 0x0 -#define BASE_SEG 0x0 - -#define BIOS_ADDR 0x000C00 // BIOS buffer -#define BIOS_LEN 0x002400 // 9k -#define BOOTER_LOAD_ADDR 0x003000 // loaded here for compat. -#define BOOTER_ADDR 0x003000 // start of booter code -#define BOOTER_LEN 0x00B000 -#define STACK_ADDR 0x00FFF0 -#define BOOTSTRUCT_ADDR 0x011000 // it's slightly smaller -#define BOOTSTRUCT_LEN 0x00F000 -#define RLD_ADDR 0x030000 // not used -#define RLD_LEN 0x070000 -#define VIDEO_ADDR 0x0A0000 // unusable space -#define VIDEO_LEN 0x060000 -#define KERNEL_ADDR 0x100000 // 14Mb kernel + drivers -#define KERNEL_LEN 0xe00000 -#define ZALLOC_ADDR 0xf00000 // 1Mb for zalloc -#define ZALLOC_LEN 0x100000 -#define TFTP_ADDR 0x1000000 // 8Mb download buffer -#define TFTP_LEN 0x800000 - -/* These are physical values */ - -#define CONVENTIONAL_LEN 0x0A0000 // 640k -#define EXTENDED_ADDR 0x100000 // 1024k -#define KERNEL_BOOT_ADDR KERNEL_ADDR // load at 1Mb - -#define ptov(paddr) ((paddr) - MEMBASE) -#define vtop(vaddr) ((vaddr) + MEMBASE) +#define ADDR32(seg, ofs) (((seg) << 4 ) + (ofs)) + +#define MEMBASE 0x0 + +#define BOOTSTRUCT_ADDR 0x011000 // it's slightly smaller +#define BOOTSTRUCT_LEN 0x00F000 + +#define BASE_ADDR ADDR32(BASE_SEG, 0) +#define BOOT2_ADDR ADDR32(BOOT2_SEG, BOOT2_OFS) + +#define VIDEO_ADDR 0x0A0000 // unusable space +#define VIDEO_LEN 0x060000 + +#define KERNEL_ADDR 0x100000 // 15M kernel + drivers +#define KERNEL_LEN 0xF00000 + +#define ZALLOC_ADDR 0x1000000 // 4M zalloc area +#define ZALLOC_LEN 0x400000 + +#define LOAD_ADDR 0x01400000 // File download buffer +#define LOAD_LEN 0x800000 // Max file size + +#define TFTP_ADDR LOAD_ADDR // tftp download buffer +#define TFTP_LEN LOAD_LEN + +#define kLoadAddr LOAD_ADDR +#define kLoadSize LOAD_LEN + +#define CONVENTIONAL_LEN 0x0A0000 // 640k +#define EXTENDED_ADDR 0x100000 // 1024k + +#define ptov(paddr) ((paddr) - MEMBASE) +#define vtop(vaddr) ((vaddr) + MEMBASE) + +/* + * Extract segment/offset from a linear address. + */ +#define OFFSET16(addr) ((addr) - BASE_ADDR) +#define OFFSET(addr) ((addr) & 0xFFFF) +#define SEGMENT(addr) (((addr) & 0xF0000) >> 4) + +/* + * We need a minimum of 32MB of system memory. + */ +#define MIN_SYS_MEM_KB (32 * 1024) /* - * Limits to the size of various things... + * The number of descriptor entries in the GDT. */ +#define NGDTENT 7 /* - * We need a minimum of 24Mb of system memory. + * The total size of the GDT in bytes. + * Each descriptor entry require 8 bytes. */ -#define MIN_SYS_MEM_KB (24 * 1024) +#define GDTLIMIT ( NGDTENT * 8 ) #endif /* !__BOOT_MEMORY_H */ diff --git a/i386/libsa/string.c b/i386/libsa/string.c index b423aca..2d76e4e 100644 --- a/i386/libsa/string.c +++ b/i386/libsa/string.c @@ -45,12 +45,12 @@ void * memcpy(void * dst, const void * src, size_t len) return dst; } -void bcopy(const void * src, void * dst, int len) +void bcopy(const void * src, void * dst, size_t len) { memcpy(dst, src, len); } -void bzero(void * dst, int len) +void bzero(void * dst, size_t len) { memset(dst, 0, len); } @@ -108,7 +108,7 @@ strncpy(char * s1, const char * s2, size_t n) } int -ptol(char *str) +ptol(const char *str) { register int c = *str; diff --git a/i386/libsaio/Makefile b/i386/libsaio/Makefile index 550acbf..079c6a0 100644 --- a/i386/libsaio/Makefile +++ b/i386/libsaio/Makefile @@ -8,9 +8,9 @@ INSTALLDIR = $(DSTROOT)/System/Library/Frameworks/System.framework/Versions/B/Pr SYMROOT= OPTIM = -Os -CFLAGS = $(RC_CFLAGS) $(OPTIM) $(MORECPP) -arch i386 -g -Wmost -Wno-precomp \ - -D__ARCHITECTURE__=\"i386\" -DSAIO_INTERNAL_USER -munaligned-text -static \ - -traditional-cpp -DRCZ_COMPRESSED_FILE_SUPPORT +CFLAGS = $(RC_CFLAGS) $(OPTIM) $(MORECPP) -arch i386 -g -Wmost -Werror \ + -D__ARCHITECTURE__=\"i386\" -DSAIO_INTERNAL_USER -fno-builtin -static \ + -DRCZ_COMPRESSED_FILE_SUPPORT DEFINES= CONFIG = hd INC = -I../rcz -I. -I$(SYMROOT) -I$(UTILDIR) -I$(LIBSADIR) -I/System/Library/Frameworks/System.framework/PrivateHeaders @@ -26,11 +26,11 @@ LIBS= VPATH = $(OBJROOT):$(SYMROOT) -SAIO_OBJS = table.o asm.o biosfn.o misc.o gets.o \ - vga.o disk.o sys.o cache.o \ - ufs_byteorder.o bootstruct.o \ - stringTable.o load.o \ - bios.o pci.o vbe.o nbp.o +SAIO_OBJS = table.o asm.o bios.o biosfn.o \ + disk.o sys.o cache.o bootstruct.o \ + ufs.o ufs_byteorder.o \ + stringTable.o load.o misc.o \ + vbe.o nbp.o hfs.o hfs_compare.o SAIO_EXTERN_OBJS = console.o diff --git a/i386/libsaio/appleClut8.h b/i386/libsaio/appleClut8.h deleted file mode 100644 index e608d18..0000000 --- a/i386/libsaio/appleClut8.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#ifndef __LIBSAIO_APPLECLUT8_H -#define __LIBSAIO_APPLECLUT8_H - -static const unsigned char appleClut8[ 256 * 3 ] = { - - 0x00,0x00,0x00, 0xFF,0xFF,0xCC, 0xFF,0xFF,0x99, 0xFF,0xFF,0x66, - 0xFF,0xFF,0x33, 0xFF,0xFF,0x00, 0xFF,0xCC,0xFF, 0xFF,0xCC,0xCC, - 0xFF,0xCC,0x99, 0xFF,0xCC,0x66, 0xFF,0xCC,0x33, 0xFF,0xCC,0x00, - 0xFF,0x99,0xFF, 0xFF,0x99,0xCC, 0xFF,0x99,0x99, 0xFF,0x99,0x66, - 0xFF,0x99,0x33, 0xFF,0x99,0x00, 0xFF,0x66,0xFF, 0xFF,0x66,0xCC, - 0xFF,0x66,0x99, 0xFF,0x66,0x66, 0xFF,0x66,0x33, 0xFF,0x66,0x00, - 0xFF,0x33,0xFF, 0xFF,0x33,0xCC, 0xFF,0x33,0x99, 0xFF,0x33,0x66, - 0xFF,0x33,0x33, 0xFF,0x33,0x00, 0xFF,0x00,0xFF, 0xFF,0x00,0xCC, - 0xFF,0x00,0x99, 0xFF,0x00,0x66, 0xFF,0x00,0x33, 0xFF,0x00,0x00, - 0xCC,0xFF,0xFF, 0xCC,0xFF,0xCC, 0xCC,0xFF,0x99, 0xCC,0xFF,0x66, - 0xCC,0xFF,0x33, 0xCC,0xFF,0x00, 0xCC,0xCC,0xFF, 0xCC,0xCC,0xCC, - 0xCC,0xCC,0x99, 0xCC,0xCC,0x66, 0xCC,0xCC,0x33, 0xCC,0xCC,0x00, - 0xCC,0x99,0xFF, 0xCC,0x99,0xCC, 0xCC,0x99,0x99, 0xCC,0x99,0x66, - 0xCC,0x99,0x33, 0xCC,0x99,0x00, 0xCC,0x66,0xFF, 0xCC,0x66,0xCC, - 0xCC,0x66,0x99, 0xCC,0x66,0x66, 0xCC,0x66,0x33, 0xCC,0x66,0x00, - 0xCC,0x33,0xFF, 0xCC,0x33,0xCC, 0xCC,0x33,0x99, 0xCC,0x33,0x66, - - - 0xCC,0x33,0x33, 0xCC,0x33,0x00, 0xCC,0x00,0xFF, 0xCC,0x00,0xCC, - 0xCC,0x00,0x99, 0xCC,0x00,0x66, 0xCC,0x00,0x33, 0xCC,0x00,0x00, - 0x99,0xFF,0xFF, 0x99,0xFF,0xCC, 0x99,0xFF,0x99, 0x99,0xFF,0x66, - 0x99,0xFF,0x33, 0x99,0xFF,0x00, 0x99,0xCC,0xFF, 0x99,0xCC,0xCC, - 0x99,0xCC,0x99, 0x99,0xCC,0x66, 0x99,0xCC,0x33, 0x99,0xCC,0x00, - 0x99,0x99,0xFF, 0x99,0x99,0xCC, 0x99,0x99,0x99, 0x99,0x99,0x66, - 0x99,0x99,0x33, 0x99,0x99,0x00, 0x99,0x66,0xFF, 0x99,0x66,0xCC, - 0x99,0x66,0x99, 0x99,0x66,0x66, 0x99,0x66,0x33, 0x99,0x66,0x00, - 0x99,0x33,0xFF, 0x99,0x33,0xCC, 0x99,0x33,0x99, 0x99,0x33,0x66, - 0x99,0x33,0x33, 0x99,0x33,0x00, 0x99,0x00,0xFF, 0x99,0x00,0xCC, - 0x99,0x00,0x99, 0x99,0x00,0x66, 0x99,0x00,0x33, 0x99,0x00,0x00, - 0x66,0xFF,0xFF, 0x66,0xFF,0xCC, 0x66,0xFF,0x99, 0x66,0xFF,0x66, - 0x66,0xFF,0x33, 0x66,0xFF,0x00, 0x66,0xCC,0xFF, 0x66,0xCC,0xCC, - 0x66,0xCC,0x99, 0x66,0xCC,0x66, 0x66,0xCC,0x33, 0x66,0xCC,0x00, - 0x66,0x99,0xFF, 0x66,0x99,0xCC, 0x66,0x99,0x99, 0x66,0x99,0x66, - 0x66,0x99,0x33, 0x66,0x99,0x00, 0x66,0x66,0xFF, 0x66,0x66,0xCC, - 0x66,0x66,0x99, 0x66,0x66,0x66, 0x66,0x66,0x33, 0x66,0x66,0x00, - - - 0x66,0x33,0xFF, 0x66,0x33,0xCC, 0x66,0x33,0x99, 0x66,0x33,0x66, - 0x66,0x33,0x33, 0x66,0x33,0x00, 0x66,0x00,0xFF, 0x66,0x00,0xCC, - 0x66,0x00,0x99, 0x66,0x00,0x66, 0x66,0x00,0x33, 0x66,0x00,0x00, - 0x33,0xFF,0xFF, 0x33,0xFF,0xCC, 0x33,0xFF,0x99, 0x33,0xFF,0x66, - 0x33,0xFF,0x33, 0x33,0xFF,0x00, 0x33,0xCC,0xFF, 0x33,0xCC,0xCC, - 0x33,0xCC,0x99, 0x33,0xCC,0x66, 0x33,0xCC,0x33, 0x33,0xCC,0x00, - 0x33,0x99,0xFF, 0x33,0x99,0xCC, 0x33,0x99,0x99, 0x33,0x99,0x66, - 0x33,0x99,0x33, 0x33,0x99,0x00, 0x33,0x66,0xFF, 0x33,0x66,0xCC, - 0x33,0x66,0x99, 0x33,0x66,0x66, 0x33,0x66,0x33, 0x33,0x66,0x00, - 0x33,0x33,0xFF, 0x33,0x33,0xCC, 0x33,0x33,0x99, 0x33,0x33,0x66, - 0x33,0x33,0x33, 0x33,0x33,0x00, 0x33,0x00,0xFF, 0x33,0x00,0xCC, - 0x33,0x00,0x99, 0x33,0x00,0x66, 0x33,0x00,0x33, 0x33,0x00,0x00, - 0x00,0xFF,0xFF, 0x00,0xFF,0xCC, 0x00,0xFF,0x99, 0x00,0xFF,0x66, - 0x00,0xFF,0x33, 0x00,0xFF,0x00, 0x00,0xCC,0xFF, 0x00,0xCC,0xCC, - 0x00,0xCC,0x99, 0x00,0xCC,0x66, 0x00,0xCC,0x33, 0x00,0xCC,0x00, - 0x00,0x99,0xFF, 0x00,0x99,0xCC, 0x00,0x99,0x99, 0x00,0x99,0x66, - - - 0x00,0x99,0x33, 0x00,0x99,0x00, 0x00,0x66,0xFF, 0x00,0x66,0xCC, - 0x00,0x66,0x99, 0x00,0x66,0x66, 0x00,0x66,0x33, 0x00,0x66,0x00, - 0x00,0x33,0xFF, 0x00,0x33,0xCC, 0x00,0x33,0x99, 0x00,0x33,0x66, - 0x00,0x33,0x33, 0x00,0x33,0x00, 0x00,0x00,0xFF, 0x00,0x00,0xCC, - 0x00,0x00,0x99, 0x00,0x00,0x66, 0x00,0x00,0x33, 0xEE,0x00,0x00, - 0xDD,0x00,0x00, 0xBB,0x00,0x00, 0xAA,0x00,0x00, 0x88,0x00,0x00, - 0x77,0x00,0x00, 0x55,0x00,0x00, 0x44,0x00,0x00, 0x22,0x00,0x00, - 0x11,0x00,0x00, 0x00,0xEE,0x00, 0x00,0xDD,0x00, 0x00,0xBB,0x00, - 0x00,0xAA,0x00, 0x00,0x88,0x00, 0x00,0x77,0x00, 0x00,0x55,0x00, - 0x00,0x44,0x00, 0x00,0x22,0x00, 0x00,0x11,0x00, 0x00,0x00,0xEE, - 0x00,0x00,0xDD, 0x00,0x00,0xBB, 0x00,0x00,0xAA, 0x00,0x00,0x88, - 0x00,0x00,0x77, 0x00,0x00,0x55, 0x00,0x00,0x44, 0x00,0x00,0x22, - 0x00,0x00,0x11, 0xEE,0xEE,0xEE, 0xDD,0xDD,0xDD, 0xBB,0xBB,0xBB, - 0xAA,0xAA,0xAA, 0x88,0x88,0x88, 0x77,0x77,0x77, 0x55,0x55,0x55, - 0x44,0x44,0x44, 0x22,0x22,0x22, 0x11,0x11,0x11, 0xFF,0xFF,0xFF -}; - -#endif /* !__LIBSAIO_APPLECLUT8_H */ diff --git a/i386/libsaio/asm.s b/i386/libsaio/asm.s index ede3dfa..2b27ffd 100644 --- a/i386/libsaio/asm.s +++ b/i386/libsaio/asm.s @@ -31,6 +31,17 @@ /* * HISTORY * $Log: asm.s,v $ + * Revision 1.3 2002/07/09 14:06:21 jliu + * Merging changes from PR-2954224 branch in boot/i386. + * + * Revision 1.2.30.1 2002/07/05 16:24:51 jliu + * Merged UFS/HFS/HFS+ filesystem support from BootX. + * Moved boot2 load address due to increased size. boot0/boot1 also changed. + * Updated boot graphics and CLUT. + * Added support to chain load foreign booters. + * Fixed param passing bug in network loader. + * Misc cleanup in libsaio. + * * Revision 1.2 2000/05/23 23:01:11 lindak * Merged PR-2309530 into Kodiak (liu i386 booter: does not support label-less * ufs partitions) @@ -59,11 +70,11 @@ * Import of boot-25 (~mwatson) * * Revision 2.1.1.2 90//03//22 17:59:50 rvb - * Added _sp() => where is the stack at. [kupfer] + * Added _sp() => where is the stack at. [kupfer] * * Revision 2.1.1.1 90//02//09 17:25:04 rvb - * Add Intel copyright - * [90//02//09 rvb] + * Add Intel copyright + * [90//02//09 rvb] * */ @@ -86,76 +97,115 @@ .file "asm.s" -BOOTSEG = BASE_SEG +CR0_PE_ON = 0x1 +CR0_PE_OFF = 0x7ffffffe -CR0_PE_ON = 0x1 -CR0_PE_OFF = 0xfffffffe +STACK32_BASE = ADDR32(STACK_SEG, 0) +STACK16_SEG = STACK_SEG +CODE32_BASE = ADDR32(BASE_SEG, 0) +CODE16_SEG = BASE_SEG + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// Pointer to 6-bytes in memory that contains the base address and the limit +// (size of GDT table in bytes) of the GDT. The LGDT is the only instruction +// that directly loads a linear address (not a segment relative address) and +// a limit in protected mode. .globl _Gdtr .data - .align 2,0x90 + .align 2, 0x90 _Gdtr: - .word 0x2F -// .long _Gdt+4096 + .word GDTLIMIT .long vtop(_Gdt) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Data area for __switch_stack. // -save_sp: .long STACK_ADDR -save_ss: .long 0 - +save_sp: .long STACK_OFS +save_ss: .long STACK_SEG .text // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // real_to_prot() -// transfer from real mode to protected mode. -// preserves all registers except eax +// +// Transfer from real mode to protected mode. +// Preserves all registers except EAX. // LABEL(__real_to_prot) - // guarantee that interrupt is disabled when in prot mode + + // Interrupts are disabled in protected mode. + cli - addr32 // load the gdtr + // Load the Global Descriptor Table Register (GDTR). + + addr32 data32 - lgdt _Gdtr + lgdt OFFSET16(_Gdtr) - // set the PE bit of CR0 to go to protected mode + // Enter protected mode by setting the PE bit in CR0. mov %cr0, %eax data32 or $CR0_PE_ON, %eax - mov %eax, %cr0 + mov %eax, %cr0 - // make intrasegment jump to flush the processor pipeline and - // reload CS register + // Make intrasegment jump to flush the processor pipeline and + // reload CS register. data32 ljmp $0x08, $xprot xprot: // we are in USE32 mode now - // set up the protected mode segment registers : DS, SS, ES + // set up the protected mode segment registers : DS, SS, ES, FS, GS mov $0x10, %eax movw %ax, %ds movw %ax, %ss movw %ax, %es + movw %ax, %fs + movw %ax, %gs + + // Convert STACK_SEG:SP to 32-bit linear stack pointer. - xorl %eax, %eax // clear garbage from upper word of esp - movw %sp, %ax + movzwl %sp, %eax + addl $STACK32_BASE, %eax movl %eax, %esp + // Convert STACK_SEG:BP to 32-bit linear base pointer. + + movzwl %bp, %eax + addl $STACK32_BASE, %eax + movl %eax, %ebp + + // Modify the caller's return address on the stack from + // segment offset to linear address. + + popl %eax + addl $CODE32_BASE, %eax + pushl %eax + ret // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // prot_to_real() -// transfer from protected mode to real mode -// preserves all registers except eax +// +// Transfer from protected mode to real mode. +// Preserves all registers except EAX. // LABEL(__prot_to_real) + // Set up segment registers appropriate for real mode. + + movw $0x30, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + ljmp $0x18, $x16 // change to USE16 mode x16: @@ -168,74 +218,65 @@ x16: // and reload CS register data32 - ljmp $BOOTSEG, $xreal + ljmp $CODE16_SEG, $xreal - CODE32_BASE xreal: // we are in real mode now - // set up the real mode segment registers : DS, SS, ES + // set up the real mode segment registers : DS, DS, ES, FS, GS movw %cs, %ax movw %ax, %ds - movw %ax, %ss movw %ax, %es + movw %ax, %fs + movw %ax, %gs + + // load stack segment register SS. data32 - ret + movl $STACK16_SEG, %eax + movw %ax, %ss -#if defined(DEFINE_INLINE_FUNCTIONS) + // clear top 16-bits of ESP and EBP. -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// outb(port, byte) -// -LABEL(_outb) - push %ebp - mov %esp, %ebp - push %edx + data32 + movzwl %sp, %esp + data32 + movzwl %bp, %ebp - movw 8(%ebp), %dx - movb 12(%ebp), %al - outb %al, %dx + // Modify caller's return address on the stack + // from linear address to segment offset. - pop %edx - pop %ebp - ret + data32 + popl %eax + data32 + movzwl %ax, %eax + data32 + pushl %eax -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// inb(port) -// -LABEL(_inb) - push %ebp - mov %esp, %ebp - push %edx + // Reenable maskable interrupts. - movw 8(%ebp), %dx - subw %ax, %ax - inb %dx, %al + sti - pop %edx - pop %ebp + data32 ret -#endif /* DEFINE_INLINE_FUNCTIONS */ - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // halt() // LABEL(_halt) -// call _getchar hlt jmp _halt // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // startprog(phyaddr) -// Start the program on protected mode where phyaddr is the entry point +// Start the program on protected mode where phyaddr is the entry point. // LABEL(_startprog) push %ebp mov %esp, %ebp - mov 0x8(%ebp), %ecx // entry offset - mov $0x28, %ebx // segment + mov 0x8(%ebp), %ecx // entry offset + mov $0x28, %ebx // segment push %ebx push %ecx @@ -255,89 +296,92 @@ LABEL(__sp) ret // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Returns the current stack pointer. +// Returns the current frame pointer. // LABEL(__bp) mov %ebp, %eax ret -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Switch stack. -# Switches between registers SS:SP and memory save_ss:save_sp. -# Call this function from real mode only!!! -# -# AX, DI, and SI are modified. -# +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// switch_stack() +// +// Switches stack pointer between SS:SP and memory save_ss:save_sp. +// Call this function from real mode only!!! +// +// AX, DI, and SI are clobbered. +// LABEL(__switch_stack) - popl %eax # save return address - popl %edi # discard upper 16-bit - - data32 - addr32 - movl save_ss, %esi # copy new SS to ESI - - data32 - addr32 - movl save_sp, %edi # copy new SP to EDI - - addr32 - mov %ss, save_ss # save current SS - - data32 - addr32 - movl %esp, save_sp # Save current SP - - cli - mov %si, %ss # Perform stack switch - mov %di, %sp - sti - - pushl %eax # push IP of caller onto the new stack - - xorl %eax, %eax - xorl %esi, %esi - xorl %edi, %edi - - ret - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Issue a request to the network loader. -# + popl %eax # save return address + popl %edi # discard upper 16-bit + + data32 + addr32 + movl OFFSET16(save_ss), %esi # new SS to SI + + data32 + addr32 + movl OFFSET16(save_sp), %edi # new SP to DI + + addr32 + mov %ss, OFFSET16(save_ss) # save current SS to memory + + data32 + addr32 + movl %esp, OFFSET16(save_sp) # save current SP to memory + + cli + mov %si, %ss # switch stack + mov %di, %sp + sti + + pushl %eax # push IP of caller onto the new stack + + xorl %eax, %eax + xorl %esi, %esi + xorl %edi, %edi + + ret + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// loader() +// +// Issue a request to the network loader. +// LABEL(_loader) - enter $0, $0 - pushal + enter $0, $0 + pushal + + # + # Pass a far pointer to the command structure + # to the INT call through DX:CX. + # + # The command code is in BX. + # + + movw 8(%ebp), %bx # 8[EBP] = command code + movw 12(%ebp), %cx # 12[EBP] = command structure offset + movw 14(%ebp), %dx # 14[EBP] = command structure segment - # - # Pass a far pointer to the command structure - # to the INT call through DI:CX. - # - # The command code is in BX. - # + call __prot_to_real # Revert to real mode - movw 8(%ebp), %bx # 8[EBP] = command code - movw 12(%ebp), %cx # 12[EBP] = command structure offset - movw 14(%ebp), %di # 14[EBP] = command structure segment + ###### Real Mode Begin ###### - call __prot_to_real # Revert to real mode + data32 + call __switch_stack # Switch to NBP stack - ###### Real Mode Begin ###### + int $0x2b # Call NBP - data32 - call __switch_stack # Switch to NBP stack + data32 + call __switch_stack # Restore stack - int $0x2b # Call NBP + data32 + call __real_to_prot # Back to protected mode - data32 - call __switch_stack # Restore stack + ###### Real Mode End ###### - data32 - call __real_to_prot # Back to protected mode - - ###### Real Mode End ###### - - popal - leave - ret + popal + leave + ret #if 0 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/i386/libsaio/bios.h b/i386/libsaio/bios.h index 3878b87..d99bafd 100644 --- a/i386/libsaio/bios.h +++ b/i386/libsaio/bios.h @@ -70,4 +70,8 @@ typedef struct { machineFlags_t flags; } biosBuf_t; +#define EBIOS_FIXED_DISK_ACCESS 0x01 +#define EBIOS_ENHANCED_DRIVE_INFO 0x04 +extern unsigned char uses_ebios[]; + #endif /* !__LIBSAIO_BIOS_H */ diff --git a/i386/libsaio/bios.s b/i386/libsaio/bios.s index 4be6b70..9654a12 100644 --- a/i386/libsaio/bios.s +++ b/i386/libsaio/bios.s @@ -28,32 +28,33 @@ * Harness for calling real-mode BIOS functions. */ -#include "legacy/asm.h" - -#define data32 .byte 0x66 -#define addr32 .byte 0x67 - -#define O_INT 0 -#define O_EAX 4 -#define O_EBX 8 -#define O_ECX 12 -#define O_EDX 16 -#define O_EDI 20 -#define O_ESI 24 -#define O_EBP 28 -#define O_CS 32 -#define O_DS 34 -#define O_ES 36 -#define O_FLG 38 +#include +#include "memory.h" + +#define data32 .byte 0x66 +#define addr32 .byte 0x67 + +#define O_INT 0 +#define O_EAX 4 +#define O_EBX 8 +#define O_ECX 12 +#define O_EDX 16 +#define O_EDI 20 +#define O_ESI 24 +#define O_EBP 28 +#define O_CS 32 +#define O_DS 34 +#define O_ES 36 +#define O_FLG 38 .data - .lcomm save_eax, 4,2 - .lcomm save_edx, 4,2 - .lcomm save_es, 2,1 - .lcomm save_flag, 2,1 - .lcomm new_eax, 4,2 - .lcomm new_edx, 4,2 - .lcomm new_es, 2,1 + .lcomm save_eax, 4,2 + .lcomm save_edx, 4,2 + .lcomm save_es, 2,1 + .lcomm save_flag, 2,1 + .lcomm new_eax, 4,2 + .lcomm new_edx, 4,2 + .lcomm new_es, 2,1 .text @@ -61,191 +62,191 @@ * Call real-mode BIOS INT functions. * */ -ENTRY(bios) - enter $0,$0 - pushal - - movl 8(%ebp), %edx // address of save area - movb O_INT(%edx), %al // save int number - movb %al, do_int+1 - - movl O_EBX(%edx), %ebx - movl O_ECX(%edx), %ecx - movl O_EDI(%edx), %edi - movl O_ESI(%edx), %esi - movl O_EBP(%edx), %ebp - movl %edx, save_edx - movl O_EAX(%edx), %eax - movl %eax, new_eax - movl O_EDX(%edx), %eax - movl %eax, new_edx - movw O_ES(%edx), %ax - movl %ax, new_es - - call EXT(_prot_to_real) - - data32 - addr32 - mov new_eax, %eax - data32 - addr32 - mov new_edx, %edx - data32 - addr32 - mov new_es, %es +LABEL(_bios) + enter $0, $0 + pushal + + movl 8(%ebp), %edx // address of save area + movb O_INT(%edx), %al // save int number + movb %al, do_int+1 + + movl O_EBX(%edx), %ebx + movl O_ECX(%edx), %ecx + movl O_EDI(%edx), %edi + movl O_ESI(%edx), %esi + movl O_EBP(%edx), %ebp + movl %edx, save_edx + movl O_EAX(%edx), %eax + movl %eax, new_eax + movl O_EDX(%edx), %eax + movl %eax, new_edx + movw O_ES(%edx), %ax + movl %ax, new_es + + call __prot_to_real + + data32 + addr32 + mov OFFSET16(new_eax), %eax + data32 + addr32 + mov OFFSET16(new_edx), %edx + data32 + addr32 + mov OFFSET16(new_es), %es do_int: - int $0x00 - pushf - data32 - addr32 - movl %eax, save_eax - popl %eax // actually pop %ax - addr32 - movl %eax, save_flag // actually movw - mov %es, %ax - addr32 - movl %eax, save_es // actually movw - data32 - call EXT(_real_to_prot) - - movl %edx, new_edx // save new edx before clobbering - movl save_edx, %edx - movl new_edx, %eax // now move it into buffer - movl %eax, O_EDX(%edx) - movl save_eax, %eax - movl %eax, O_EAX(%edx) - movw save_es, %ax - movw %ax, O_ES(%edx) - movw save_flag, %ax - movw %ax, O_FLG(%edx) - movl %ebx, O_EBX(%edx) - movl %ecx, O_ECX(%edx) - movl %edi, O_EDI(%edx) - movl %esi, O_ESI(%edx) - movl %ebp, O_EBP(%edx) - - popal - leave - - ret - + int $0x00 + pushf + data32 + addr32 + movl %eax, OFFSET16(save_eax) + popl %eax // actually pop %ax + addr32 + movl %eax, OFFSET16(save_flag) // actually movw + mov %es, %ax + addr32 + movl %eax, OFFSET16(save_es) // actually movw + data32 + call __real_to_prot + + movl %edx, new_edx // save new edx before clobbering + movl save_edx, %edx + movl new_edx, %eax // now move it into buffer + movl %eax, O_EDX(%edx) + movl save_eax, %eax + movl %eax, O_EAX(%edx) + movw save_es, %ax + movw %ax, O_ES(%edx) + movw save_flag, %ax + movw %ax, O_FLG(%edx) + movl %ebx, O_EBX(%edx) + movl %ecx, O_ECX(%edx) + movl %edi, O_EDI(%edx) + movl %esi, O_ESI(%edx) + movl %ebp, O_EBP(%edx) + + popal + leave + + ret + /*============================================================================ * Determines the total system memory size using various BIOS Int 15 calls. * */ -ENTRY(get_memsize) - enter $0, $0 # create frame pointer (32 bit operand/stack) - pushal # save all registers - - movl 8(%ebp), %ebx # push input structure pointer to stack - pushl %ebx - - call EXT(_prot_to_real) # switch to real mode - - ################################################################## - # In real mode. - # Do not forget the opcode overrides, since the assembler - # does not know we have made a transition to 16-bit operation. - ################################################################## - - data32 - movl $0xE801, %eax # Get memory size - clc - int $0x15 - data32 - jnc getmsz_e801 - - data32 - movl $0xDA88, %eax # Get memory size - clc - int $0x15 - data32 - jnc getmsz_da88 - - movb $0x8A, %ah # Get memory size - clc - int $0x15 - data32 - jnc getmsz_8a - - movb $0x88, %ah # Get memory size - clc - int $0x15 - data32 - jnc getmsz_88 - - xorl %edx, %edx # Error, cannot get memory size - xorl %eax, %eax +LABEL(_get_memsize) + enter $0, $0 # create frame pointer (32 bit operand/stack) + pushal # save all registers + + movl 8(%ebp), %ebx # push input structure pointer to stack + pushl %ebx + + call __prot_to_real # switch to real mode + + ################################################################## + # In real mode. + # Do not forget the opcode overrides, since the assembler + # does not know we have made a transition to 16-bit operation. + ################################################################## + + data32 + movl $0xE801, %eax # Get memory size + clc + int $0x15 + data32 + jnc getmsz_e801 + + data32 + movl $0xDA88, %eax # Get memory size + clc + int $0x15 + data32 + jnc getmsz_da88 + + movb $0x8A, %ah # Get memory size + clc + int $0x15 + data32 + jnc getmsz_8a + + movb $0x88, %ah # Get memory size + clc + int $0x15 + data32 + jnc getmsz_88 + + xorl %edx, %edx # Error, cannot get memory size + xorl %eax, %eax getmsz_done: - data32 - addr32 - pushl %eax # Push EAX to 32-bit stack + data32 + addr32 + pushl %eax # Push EAX to 32-bit stack - data32 - call EXT(_real_to_prot) # Back to protected mode. EAX is modified. + data32 + call __real_to_prot # Back to protected mode. EAX is modified. - ################################################################## - # Back to protected mode. - ################################################################## + ################################################################## + # Back to protected mode. + ################################################################## - popl %eax # Pop EAX from stack - popl %ebx # Pop pointer to register structure + popl %eax # Pop EAX from stack + popl %ebx # Pop pointer to register structure - # Copy the result to the input structure pointed to by a pointer - # which is on top of the stack. Write register EAX and EDX to the - # structure. + # Copy the result to the input structure pointed to by a pointer + # which is on top of the stack. Write register EAX and EDX to the + # structure. - movl %eax, O_EAX(%ebx) - movl %edx, O_EDX(%ebx) + movl %eax, O_EAX(%ebx) + movl %edx, O_EDX(%ebx) - popal # restore all registers - leave # undo enter operator - ret + popal # restore all registers + leave # undo enter operator + ret getmsz_88: - orl %eax, %eax - data32 - jz getmsz_64m - xorl %edx, %edx + orl %eax, %eax + data32 + jz getmsz_64m + xorl %edx, %edx getmsz_8a: - data32 - movl $1024, %ebx # Add in 1M - addl %ebx, %eax - adcl $0, %edx - data32 - jmp getmsz_done + data32 + movl $1024, %ebx # Add in 1M + addl %ebx, %eax + adcl $0, %edx + data32 + jmp getmsz_done getmsz_64m: - data32 - movl $1, %edx - xorl %eax, %eax - data32 - jmp getmsz_done + data32 + movl $1, %edx + xorl %eax, %eax + data32 + jmp getmsz_done getmsz_da88: - xor %dh, %dh - movb %cl, %dl - movl %ebx, %eax - data32 - jmp getmsz_8a + xor %dh, %dh + movb %cl, %dl + movl %ebx, %eax + data32 + jmp getmsz_8a getmsz_e801: - xorl %edx, %edx - orl %ebx, %ebx - data32 - jz getmsz_88 - - data32 - movl $64, %eax - mul %ebx - - data32 - movl $16384, %ebx - addl %ebx, %eax - adcl $0, %edx - - data32 - jmp getmsz_done + xorl %edx, %edx + orl %ebx, %ebx + data32 + jz getmsz_88 + + data32 + movl $64, %eax + mul %ebx + + data32 + movl $16384, %ebx + addl %ebx, %eax + adcl $0, %edx + + data32 + jmp getmsz_done diff --git a/i386/libsaio/biosfn.c b/i386/libsaio/biosfn.c index ff0d3a3..8af9bbe 100644 --- a/i386/libsaio/biosfn.c +++ b/i386/libsaio/biosfn.c @@ -27,8 +27,6 @@ */ #include "libsaio.h" -#include "memory.h" -#include "kernBootStruct.h" static biosBuf_t bb; unsigned char uses_ebios[8] = {0, 0, 0, 0, 0, 0, 0, 0}; @@ -47,9 +45,9 @@ int readKeyboardStatus(void) bb.eax.r.h = 0x01; bios(&bb); if (bb.flags.zf) { - return 0; + return 0; } else { - return bb.eax.rr; + return bb.eax.rr; } } @@ -64,11 +62,11 @@ int readKeyboardShiftFlags(void) unsigned int time18(void) { union { - struct { - unsigned int low:16; - unsigned int high:16; - } s; - unsigned int i; + struct { + unsigned int low:16; + unsigned int high:16; + } s; + unsigned int i; } time; bb.intno = 0x1a; @@ -119,26 +117,26 @@ int biosread(int dev, int cyl, int head, int sec, int num) int i; bb.intno = 0x13; - sec += 1; /* sector numbers start at 1 */ + sec += 1; /* sector numbers start at 1 */ for (i=0;;) { - bb.ecx.r.h = cyl; - bb.ecx.r.l = ((cyl & 0x300) >> 2) | (sec & 0x3F); - bb.edx.r.h = head; - bb.edx.r.l = dev; - bb.eax.r.l = num; - bb.ebx.rr = ptov(BIOS_ADDR); - bb.es = ((unsigned long)&i & 0xffff0000) >> 4; - - bb.eax.r.h = 0x02; - bios(&bb); + bb.ecx.r.h = cyl; + bb.ecx.r.l = ((cyl & 0x300) >> 2) | (sec & 0x3F); + bb.edx.r.h = head; + bb.edx.r.l = dev; + bb.eax.r.l = num; + bb.ebx.rr = OFFSET(ptov(BIOS_ADDR)); + bb.es = SEGMENT(ptov(BIOS_ADDR)); + + bb.eax.r.h = 0x02; + bios(&bb); - if ((bb.eax.r.h == 0x00) || (i++ >= 5)) - break; + if ((bb.eax.r.h == 0x00) || (i++ >= 5)) + break; - /* reset disk subsystem and try again */ - bb.eax.r.h = 0x00; - bios(&bb); + /* reset disk subsystem and try again */ + bb.eax.r.h = 0x00; + bios(&bb); } return bb.eax.r.h; } @@ -146,24 +144,28 @@ int biosread(int dev, int cyl, int head, int sec, int num) int ebiosread(int dev, long sec, int count) { int i; - struct { - unsigned char size; - unsigned char reserved; - unsigned char numblocks; - unsigned char reserved2; - unsigned int buffer; - unsigned long long startblock; + static struct { + unsigned char size; + unsigned char reserved; + unsigned char numblocks; + unsigned char reserved2; + unsigned short bufferOffset; + unsigned short bufferSegment; + unsigned long long startblock; } addrpacket = {0}; addrpacket.size = sizeof(addrpacket); for (i=0;;) { - bb.intno = 0x13; + bb.intno = 0x13; bb.eax.r.h = 0x42; bb.edx.r.l = dev; - bb.esi.rr = ((unsigned)&addrpacket & 0xffff); - addrpacket.numblocks = count; - addrpacket.buffer = ptov(BIOS_ADDR); - addrpacket.startblock = sec; + bb.esi.rr = OFFSET((unsigned)&addrpacket); + bb.ds = SEGMENT((unsigned)&addrpacket); + addrpacket.reserved = addrpacket.reserved2 = 0; + addrpacket.numblocks = count; + addrpacket.bufferOffset = OFFSET(ptov(BIOS_ADDR)); + addrpacket.bufferSegment = SEGMENT(ptov(BIOS_ADDR)); + addrpacket.startblock = sec; bios(&bb); if ((bb.eax.r.h == 0x00) || (i++ >= 5)) break; @@ -178,16 +180,27 @@ int ebiosread(int dev, long sec, int count) void putc(int ch) { bb.intno = 0x10; - bb.ebx.r.h = 0x00; /* background black */ - bb.ebx.r.l = 0x0F; /* foreground white */ + bb.ebx.r.h = 0x00; /* background black */ + bb.ebx.r.l = 0x0F; /* foreground white */ bb.eax.r.h = 0x0e; bb.eax.r.l = ch; bios(&bb); } +void putca(int ch, int attr, int repeat) +{ + bb.intno = 0x10; + bb.ebx.r.h = 0x00; /* page number */ + bb.ebx.r.l = attr; /* attribute */ + bb.eax.r.h = 0x9; + bb.eax.r.l = ch; + bb.ecx.rx = repeat; /* repeat count */ + bios(&bb); +} + unsigned int get_diskinfo(int drive) { - struct { + static struct { unsigned short size; unsigned short flags; unsigned long cylinders; @@ -200,23 +213,23 @@ unsigned int get_diskinfo(int drive) unsigned char useEbios = 0; union { - compact_diskinfo_t di; - unsigned int ui; + compact_diskinfo_t di; + unsigned int ui; } ret; static int maxhd = 0; ret.ui = 0; if (maxhd == 0) { - bb.intno = 0x13; - bb.eax.r.h = 0x08; - bb.edx.r.l = 0x80; - bios(&bb); - if (bb.flags.cf == 0) - maxhd = 0x7f + bb.edx.r.l; + bb.intno = 0x13; + bb.eax.r.h = 0x08; + bb.edx.r.l = 0x80; + bios(&bb); + if (bb.flags.cf == 0) + maxhd = 0x7f + bb.edx.r.l; }; if (drive > maxhd) - return 0; + return 0; /* Check drive for EBIOS support. */ bb.intno = 0x13; @@ -225,16 +238,21 @@ unsigned int get_diskinfo(int drive) bb.ebx.rr = 0x55aa; bios(&bb); if(bb.ebx.rr == 0xaa55 && bb.flags.cf == 0) { + /* Get flags for supported operations. */ + useEbios = bb.ecx.r.l; + } + if (useEbios & EBIOS_ENHANCED_DRIVE_INFO) { /* Get EBIOS drive info. */ ebios.size = 26; bb.intno = 0x13; bb.eax.r.h = 0x48; bb.edx.r.l = drive; - bb.esi.rr = ((unsigned)&ebios & 0xffff); + bb.esi.rr = OFFSET((unsigned)&ebios); + bb.ds = SEGMENT((unsigned)&ebios); bios(&bb); - if(bb.flags.cf == 0 && ebios.cylinders != 0) { - useEbios = 1; + if(bb.flags.cf != 0) { + useEbios = 0; } } @@ -249,7 +267,7 @@ unsigned int get_diskinfo(int drive) hds = bb.edx.r.h; sec = bb.ecx.r.l & 0x3F; - if(useEbios) { + if(useEbios & EBIOS_ENHANCED_DRIVE_INFO) { cyl = (ebios.total_sectors / ((hds + 1) * sec)) - 1; } else { @@ -263,18 +281,75 @@ unsigned int get_diskinfo(int drive) return ret.ui; } -void setCursorPosition(int x, int y) +void setCursorPosition(int x, int y, int page) { bb.intno = 0x10; bb.eax.r.h = 0x02; - bb.ebx.r.h = 0x00; /* page 0 for graphics */ + bb.ebx.r.h = page; /* page 0 for graphics */ bb.edx.r.l = x; bb.edx.r.h = y; bios(&bb); } +void setCursorType(int type) +{ + bb.intno = 0x10; + bb.eax.r.h = 0x01; + bb.ecx.rr = type; + bios(&bb); +} + +void getCursorPositionAndType(int * x, int * y, int * type) +{ + bb.intno = 0x10; + bb.eax.r.h = 0x03; + bios(&bb); + *x = bb.edx.r.l; + *y = bb.edx.r.h; + *type = bb.ecx.rr; +} + +void scollPage(int x1, int y1, int x2, int y2, int attr, int rows, int dir) +{ + bb.intno = 0x10; + bb.eax.r.h = (dir > 0) ? 0x06 : 0x07; + bb.eax.r.l = rows; + bb.ebx.r.h = attr; + bb.ecx.r.h = y1; + bb.ecx.r.l = x1; + bb.edx.r.h = y2; + bb.edx.r.l = x2; + bios(&bb); +} + +void clearScreenRows( int y1, int y2 ) +{ + scollPage( 0, y1, 80 - 1, y2, 0x07, y2 - y1 + 1, 1 ); +} + +void setActiveDisplayPage( int page ) +{ + bb.intno = 0x10; + bb.eax.r.h = 5; + bb.eax.r.l = page; + bios(&bb); +} + #if DEBUG +int terminateDiskEmulation() +{ + static char cd_spec[0x12]; + + bb.intno = 0x13; + bb.eax.r.h = 0x4b; + bb.eax.r.l = 0; // subfunc: terminate emulation + bb.esi.rr = OFFSET((unsigned)&cd_spec); + bb.ds = SEGMENT((unsigned)&cd_spec); + bios(&bb); + return bb.eax.r.h; +} + int readDriveParameters(int drive, struct driveParameters *dp) { bb.intno = 0x13; @@ -282,20 +357,20 @@ int readDriveParameters(int drive, struct driveParameters *dp) bb.eax.r.h = 0x08; bios(&bb); if (bb.eax.r.h == 0) { - dp->heads = bb.edx.r.h; - dp->sectors = bb.ecx.r.l & 0x3F; - dp->cylinders = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2); - dp->totalDrives = bb.edx.r.l; + dp->heads = bb.edx.r.h; + dp->sectors = bb.ecx.r.l & 0x3F; + dp->cylinders = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2); + dp->totalDrives = bb.edx.r.l; } else { - bzero(dp, sizeof(*dp)); + bzero(dp, sizeof(*dp)); } return bb.eax.r.h; } #endif -#define APM_INTNO 0x15 -#define APM_INTCODE 0x53 +#define APM_INTNO 0x15 +#define APM_INTCODE 0x53 int APMPresent(void) @@ -308,13 +383,13 @@ APMPresent(void) bb.ebx.rr = 0x0000; bios(&bb); if ((bb.flags.cf == 0) && - (bb.ebx.r.h == 'P') && - (bb.ebx.r.l == 'M')) { - /* Success */ - kbp->apmConfig.major_vers = bb.eax.r.h; - kbp->apmConfig.minor_vers = bb.eax.r.l; - kbp->apmConfig.flags.data = bb.ecx.rr; - return 1; + (bb.ebx.r.h == 'P') && + (bb.ebx.r.l == 'M')) { + /* Success */ + kbp->apmConfig.major_vers = bb.eax.r.h; + kbp->apmConfig.minor_vers = bb.eax.r.l; + kbp->apmConfig.flags.data = bb.ecx.rr; + return 1; } return 0; } @@ -330,39 +405,39 @@ APMConnect32(void) bb.ebx.rr = 0x0000; bios(&bb); if (bb.flags.cf == 0) { - /* Success */ - kbp->apmConfig.cs32_base = (bb.eax.rr) << 4; - kbp->apmConfig.entry_offset = bb.ebx.rx; - kbp->apmConfig.cs16_base = (bb.ecx.rr) << 4; - kbp->apmConfig.ds_base = (bb.edx.rr) << 4; - if (kbp->apmConfig.major_vers >= 1 && - kbp->apmConfig.minor_vers >= 1) { - kbp->apmConfig.cs_length = bb.esi.rr; - kbp->apmConfig.ds_length = bb.edi.rr; - } else { - kbp->apmConfig.cs_length = - kbp->apmConfig.ds_length = 64 * 1024; - } - kbp->apmConfig.connected = 1; - return 1; + /* Success */ + kbp->apmConfig.cs32_base = (bb.eax.rr) << 4; + kbp->apmConfig.entry_offset = bb.ebx.rx; + kbp->apmConfig.cs16_base = (bb.ecx.rr) << 4; + kbp->apmConfig.ds_base = (bb.edx.rr) << 4; + if (kbp->apmConfig.major_vers >= 1 && + kbp->apmConfig.minor_vers >= 1) { + kbp->apmConfig.cs_length = bb.esi.rr; + kbp->apmConfig.ds_length = bb.edi.rr; + } else { + kbp->apmConfig.cs_length = + kbp->apmConfig.ds_length = 64 * 1024; + } + kbp->apmConfig.connected = 1; + return 1; } return 0; } -#ifdef EISA_SUPPORT // turn off for now since there isn't enough room +#ifdef EISA_SUPPORT BOOL eisa_present( void ) { - static BOOL checked; - static BOOL isEISA; + static BOOL checked; + static BOOL isEISA; if (!checked) { - if (strncmp((char *)0xfffd9, "EISA", 4) == 0) - isEISA = TRUE; - - checked = TRUE; + if (strncmp((char *)0xfffd9, "EISA", 4) == 0) + isEISA = TRUE; + + checked = TRUE; } return (isEISA); @@ -372,20 +447,20 @@ int ReadEISASlotInfo(EISA_slot_info_t *ep, int slot) { union { - struct { - unsigned char char2h :2; - unsigned char char1 :5; - unsigned char char3 :5; - unsigned char char2l :3; - unsigned char d2 :4; - unsigned char d1 :4; - unsigned char d4 :4; - unsigned char d3 :4; - } s; - unsigned char data[4]; + struct { + unsigned char char2h :2; + unsigned char char1 :5; + unsigned char char3 :5; + unsigned char char2l :3; + unsigned char d2 :4; + unsigned char d1 :4; + unsigned char d4 :4; + unsigned char d3 :4; + } s; + unsigned char data[4]; } u; static char hex[0x10] = "0123456789ABCDEF"; - + bb.intno = 0x15; bb.eax.r.h = 0xd8; @@ -393,7 +468,7 @@ ReadEISASlotInfo(EISA_slot_info_t *ep, int slot) bb.ecx.r.l = slot; bios(&bb); if (bb.flags.cf) - return bb.eax.r.h; + return bb.eax.r.h; ep->u_ID.d = bb.eax.r.l; ep->configMajor = bb.ebx.r.h; ep->configMinor = bb.ebx.r.l; @@ -430,12 +505,12 @@ ReadEISAFuncInfo(EISA_func_info_t *ep, int slot, int function) bb.esi.rr = (unsigned int)ep->data; bios(&bb); if (bb.eax.r.h == 0) { - ep->slot = slot; - ep->function = function; + ep->slot = slot; + ep->function = function; } return bb.eax.r.h; } -#endif +#endif /* EISA_SUPPORT */ #define PCI_SIGNATURE 0x20494350 /* "PCI " */ @@ -447,12 +522,12 @@ ReadPCIBusInfo(PCI_bus_info_t *pp) bb.eax.r.l = 0x01; bios(&bb); if ((bb.eax.r.h == 0) && (bb.edx.rx == PCI_SIGNATURE)) { - pp->BIOSPresent = 1; - pp->u_bus.d = bb.eax.r.l; - pp->majorVersion = bb.ebx.r.h; - pp->minorVersion = bb.ebx.r.l; - pp->maxBusNum = bb.ecx.r.l; - return 0; + pp->BIOSPresent = 1; + pp->u_bus.d = bb.eax.r.l; + pp->majorVersion = bb.ebx.r.h; + pp->minorVersion = bb.ebx.r.l; + pp->maxBusNum = bb.ecx.r.l; + return 0; } return -1; } diff --git a/i386/libsaio/bootstruct.c b/i386/libsaio/bootstruct.c index c4e545b..667f7c0 100644 --- a/i386/libsaio/bootstruct.c +++ b/i386/libsaio/bootstruct.c @@ -26,9 +26,7 @@ * All rights reserved. */ -#include "io_inline.h" #include "libsaio.h" -#include "kernBootStruct.h" // CMOS access ports in I/O space. // @@ -40,8 +38,7 @@ * Returns the number of active ATA drives since these will increment the * bios device numbers of SCSI drives. */ -static int -countIDEDisks() +static int countIDEDisks() { int count = 0; unsigned short hdtype; @@ -84,20 +81,29 @@ countIDEDisks() KERNBOOTSTRUCT * kernBootStruct = (KERNBOOTSTRUCT *) KERNSTRUCT_ADDR; -void -initKernBootStruct() +void initKernBootStruct( int biosdev ) { + static int init_done = 0; unsigned char i; - bzero( (char *) kernBootStruct, sizeof(*kernBootStruct) ); + if ( !init_done ) + { + bzero( (char *) kernBootStruct, sizeof(*kernBootStruct) ); - // Get size of conventional memory. - - kernBootStruct->convmem = memsize(0); - - // Get size of extended memory. - - kernBootStruct->extmem = memsize(1); + // Get size of conventional memory. + + kernBootStruct->convmem = memsize(0); + + // Get size of extended memory. + + kernBootStruct->extmem = memsize(1); + + kernBootStruct->magicCookie = KERNBOOTMAGIC; + kernBootStruct->configEnd = kernBootStruct->config; + kernBootStruct->graphicsMode = TEXT_MODE; + + init_done = 1; + } // Get number of ATA devices. @@ -110,7 +116,15 @@ initKernBootStruct() kernBootStruct->diskInfo[i] = get_diskinfo(0x80 + i); } - kernBootStruct->magicCookie = KERNBOOTMAGIC; - kernBootStruct->configEnd = kernBootStruct->config; - kernBootStruct->graphicsMode = GRAPHICS_MODE; + // Update kernDev from biosdev. + + switch ( BIOS_DEV_TYPE( biosdev ) ) + { + case kBIOSDevTypeNetwork: + kernBootStruct->kernDev = B_TYPE(DEV_EN); break; + case kBIOSDevTypeHardDrive: + kernBootStruct->kernDev = B_TYPE(DEV_HD); break; + case kBIOSDevTypeFloppy: + kernBootStruct->kernDev = B_TYPE(DEV_FD); break; + } } diff --git a/i386/libsaio/cache.c b/i386/libsaio/cache.c index 6ead4d6..4528dc5 100644 --- a/i386/libsaio/cache.c +++ b/i386/libsaio/cache.c @@ -1,94 +1,160 @@ /* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * - * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. * - * The Original Code and all software distributed under the License are + * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ -/* cache */ +/* + * cache.c - A simple cache for file systems meta-data. + * + * Copyright (c) 2000 Apple Computer, Inc. + * + * DRI: Josh de Cesare + */ -#include "cache.h" -#include "libsa.h" +#include +// #include -cache_t *cacheInit( - int nitems, - int item_size -) -{ - cache_t *cp; - item_size += sizeof(item_t); - cp = (cache_t *)malloc(sizeof(cache_t) + nitems * item_size); - cp->nitems = nitems; - cp->item_size = item_size; - return cp; -} +struct CacheEntry { + CICell ih; + long time; + long long offset; +}; +typedef struct CacheEntry CacheEntry; -/* - * Either find an item in the cache, or find where it should go. - * Returns 1 if found, 0 if not found. - * This function assumes that if you find an empty slot, you will use it; - * therefore, empty slots returned are marked valid. - */ -int cacheFind( - cache_t *cp, - int key1, - int key2, - char **ip -) +#define kCacheSize (0x100000) +#define kCacheMinBlockSize (0x200) +#define kCacheMaxBlockSize (0x4000) +#define kCacheMaxEntries (kCacheSize / kCacheMinBlockSize) + +static CICell gCacheIH; +static long gCacheBlockSize; +static long gCacheNumEntries; +static long gCacheTime; + +#ifdef __i386__ +static CacheEntry *gCacheEntries; +static char *gCacheBuffer; +#else +static CacheEntry gCacheEntries[kCacheMaxEntries]; +static char gCacheBuffer[kCacheSize]; +#endif + +unsigned long gCacheHits; +unsigned long gCacheMisses; +unsigned long gCacheEvicts; + +void CacheInit( CICell ih, long blockSize ) { - item_t *iip, *min_p; - int i,j; +#ifdef __i386__ + if ((ih == gCacheIH) && (blockSize == gCacheBlockSize)) + return; +#endif + + if ((blockSize < kCacheMinBlockSize) || + (blockSize >= kCacheMaxBlockSize)) + return; + + gCacheBlockSize = blockSize; + gCacheNumEntries = kCacheSize / gCacheBlockSize; + gCacheTime = 0; - for(i=j=0, iip = min_p = (item_t *)cp->storage; i < cp->nitems; i++) { - if (iip->referenced && (iip->key1 == key1) && (iip->key2 == key2)) { - *ip = iip->storage; - if (iip->referenced < 65535) - iip->referenced++; - return 1; - } - if (iip->referenced < min_p->referenced) { - min_p = iip; - j = i; - } - iip = (item_t *)((char *)iip + cp->item_size); + gCacheHits = 0; + gCacheMisses = 0; + gCacheEvicts = 0; + + gCacheIH = ih; + +#ifdef __i386__ + if (!gCacheBuffer) gCacheBuffer = (char *) malloc(kCacheSize); + if (!gCacheEntries) gCacheEntries = (CacheEntry *) malloc(kCacheMaxEntries * sizeof(CacheEntry)); + if ( !gCacheBuffer || !gCacheEntries ) + { + gCacheIH = 0; // invalidate cache + return; } - *ip = min_p->storage; - min_p->referenced = 1; - min_p->key1 = key1; - min_p->key2 = key2; - return 0; +#endif + + bzero(gCacheEntries, kCacheMaxEntries * sizeof(CacheEntry)); } -/* - * Flush the cache. - */ -void cacheFlush( - cache_t *cp -) +long CacheRead( CICell ih, char * buffer, long long offset, + long length, long cache ) { - int i; - item_t *ip; - - if (cp == 0) - return; - for(i=0, ip = (item_t *)cp->storage; i < cp->nitems; i++) { - ip->referenced = 0; - ip = (item_t *)((char *)ip + cp->item_size); + long cnt, oldestEntry = 0, oldestTime, loadCache = 0; + CacheEntry *entry; + + // See if the data can be cached. + if (cache && (gCacheIH == ih) && (length == gCacheBlockSize)) { + // Look for the data in the cache. + for (cnt = 0; cnt < gCacheNumEntries; cnt++) { + entry = &gCacheEntries[cnt]; + if ((entry->ih == ih) && (entry->offset == offset)) { + entry->time = ++gCacheTime; + break; + } + } + + // If the data was found copy it to the caller. + if (cnt != gCacheNumEntries) { + bcopy(gCacheBuffer + cnt * gCacheBlockSize, buffer, gCacheBlockSize); + gCacheHits++; + return gCacheBlockSize; + } + + // Could not find the data in the cache. + loadCache = 1; } + + // Read the data from the disk. + Seek(ih, offset); + Read(ih, (long)buffer, length); + if (cache) gCacheMisses++; + + // Put the data from the disk in the cache if needed. + if (loadCache) { + // Find a free entry. + oldestTime = gCacheTime; + for (cnt = 0; cnt < gCacheNumEntries; cnt++) { + entry = &gCacheEntries[cnt]; + + // Found a free entry. + if (entry->ih == 0) break; + + if (entry->time < oldestTime) { + oldestTime = entry->time; + oldestEntry = cnt; + } + } + + // If no free entry was found, use the oldest. + if (cnt == gCacheNumEntries) { + cnt = oldestEntry; + gCacheEvicts++; + } + + // Copy the data from disk to the new entry. + entry = &gCacheEntries[cnt]; + entry->ih = ih; + entry->time = ++gCacheTime; + entry->offset = offset; + bcopy(buffer, gCacheBuffer + cnt * gCacheBlockSize, gCacheBlockSize); + } + + return length; } diff --git a/i386/libsaio/console.c b/i386/libsaio/console.c index 53de5a0..9f3555c 100644 --- a/i386/libsaio/console.c +++ b/i386/libsaio/console.c @@ -47,7 +47,7 @@ #include "libsaio.h" BOOL gVerboseMode; -BOOL errors; +BOOL gErrors; /* * write one character to console @@ -117,7 +117,7 @@ int verbose(const char * fmt, ...) int error(const char * fmt, ...) { va_list ap; - errors = YES; + gErrors = YES; va_start(ap, fmt); prf(fmt, ap, putchar, 0); va_end(ap); diff --git a/i386/libsaio/disk.c b/i386/libsaio/disk.c index b08678d..7c70cf8 100644 --- a/i386/libsaio/disk.c +++ b/i386/libsaio/disk.c @@ -44,249 +44,172 @@ * All rights reserved. */ -#define DRIVER_PRIVATE - -#include "sys/types.h" -#include "legacy/disk.h" -#include "legacy/fdisk.h" #include "libsaio.h" -#include "memory.h" - -/* - * Type and constant definitions. - */ -typedef struct disk_blk0 boot_sector; -#define BOOT_SIGNATURE DISK_SIGNATURE -#define PART_TYPE_EXT 0x05 -#define PART_TYPE_APPLE 0xa8 -#define UFS_FRONT_PORCH 0 - -#if DEBUG -#define DPRINT(x) { printf x; } -#define DSPRINT(x) { printf x; sleep(1); } -#else -#define DPRINT(x) -#define DSPRINT(x) -#endif - -/* - * Function prototypes. - */ -extern void spinActivityIndicator(); -static void diskActivityHook(); -static int Biosread(int biosdev, int secno); -static struct fdisk_part * find_partition(u_int8_t type, - u_int8_t biosdev, - BOOL mba); +#include "fdisk.h" /* * diskinfo unpacking. */ -#define SPT(di) ((di) & 0xff) -#define HEADS(di) ((((di)>>8) & 0xff) + 1) -#define SPC(di) (SPT(di) * HEADS(di)) -#define BPS 512 /* sector size of the device */ -#define N_CACHE_SECS (BIOS_LEN / BPS) +#define SPT(di) ((di) & 0xff) +#define HEADS(di) ((((di)>>8) & 0xff) + 1) +#define SPC(di) (SPT(di) * HEADS(di)) -/* - * Stores the geometry of the disk in order to - * perform LBA to CHS translation for non EBIOS calls. - */ -static struct diskinfo { - int spt; /* sectors per track */ - int spc; /* sectors per cylinder */ -} diskinfo; - -/* - * Globals variables. - */ -int label_secsize = BPS; -char * b[NBUFS]; -daddr_t blknos[NBUFS]; -struct iob iob[NFILES]; +#define BPS 512 /* sector size of the device */ +#define N_CACHE_SECS (BIOS_LEN / BPS) +#define UFS_FRONT_PORCH 0 /* - * intbuf points to the start of the sector cache. BIOS calls will - * store the sectors read into this memory area. If cache_valid - * is TRUE, then intbuf contents are valid. Otherwise, ignore the - * cache and read from disk. + * trackbuf points to the start of the track cache. Biosread() + * will store the sectors read from disk to this memory area. * - * biosbuf points to a sector within the sector cache. + * biosbuf points to a sector within the track cache, and is + * updated by Biosread(). */ -static char * const intbuf = (char *)ptov(BIOS_ADDR); -static BOOL cache_valid = FALSE; -static char * biosbuf; +static const char * const trackbuf = (char *) ptov(BIOS_ADDR); +static const char * biosbuf; -/*========================================================================== - * +/* + * Map a disk drive to bootable volumes contained within. */ -void -devopen(char * name, struct iob * io) -{ - static int last_biosdev = -1; - static daddr_t last_offset = 0; +struct DiskBVMap { + int biosdev; // BIOS device number (unique) + BVRef bvr; // chain of boot volumes on the disk + int bvrcnt; // number of boot volumes + struct DiskBVMap * next; // linkage to next mapping +}; - struct fdisk_part * part; - long di; +static struct DiskBVMap * gDiskBVMap = NULL; +static struct disk_blk0 * gBootSector = NULL; - io->i_error = 0; - io->dirbuf_blkno = -1; +extern long HFSInitPartition(CICell ih); +extern long HFSLoadFile(CICell ih, char * filePath); +extern long HFSGetDirEntry(CICell ih, char * dirPath, long * dirIndex, + char ** name, long * flags, long * time); - // Use cached values if possible. - // - if (io->biosdev == last_biosdev) { - io->i_boff = last_offset; - return; - } +extern long UFSInitPartition(CICell ih); +extern long UFSLoadFile(CICell ih, char * filePath); +extern long UFSGetDirEntry(CICell ih, char * dirPath, long * dirIndex, + char ** name, long * flags, long * time); - // initialize disk parameters -- spt and spc - // must do this before doing reads from the device. +extern void spinActivityIndicator(); - di = get_diskinfo(io->biosdev); - if (di == 0) { - io->i_error = ENXIO; - return; - } +static void getVolumeDescription(BVRef bvr, char * str, long strMaxLen); - diskinfo.spt = SPT(di); - diskinfo.spc = diskinfo.spt * HEADS(di); - - // FIXME - io->partition is ignored. Doesn't make sense anymore. - // we also don't overwrite the 'name' argument. - // Whats special about "$LBL" ? - - part = find_partition(PART_TYPE_APPLE, io->biosdev, FALSE); - if (part == NULL) { - io->i_error = EIO; - DSPRINT(("Unable to find partition: IO error\n")); - } else { - last_offset = io->i_boff = part->relsect + UFS_FRONT_PORCH/BPS; - last_biosdev = io->biosdev; - DSPRINT(("partition offset: %x\n", io->i_boff)); - } -} +//========================================================================== -/*========================================================================== - * - */ -void devflush() +static int getDiskGeometry( int biosdev, int * spt, int * spc ) { - cache_valid = FALSE; // invalidate the sector cache (intbuf) -} - -/*========================================================================== - * - */ -int devread(struct iob * io) -{ - long sector; - int offset; -// int dev; - - io->i_flgs |= F_RDDATA; + static int cached_biosdev = -1; + static int cached_spt = 0; + static int cached_spc = 0; + + if ( biosdev != cached_biosdev ) + { + long di = get_diskinfo(biosdev); + if (di == 0) return (-1); // BIOS call error - io->i_error = 0; // assume the best + cached_spt = SPT(di); + cached_spc = cached_spt * HEADS(di); -// dev = io->i_ino.i_dev; + DEBUG_DISK(("%s: %d sectors, %d heads\n", + __FUNCTION__, cached_spt, (int)HEADS(di))); + } - sector = io->i_bn * (label_secsize/BPS); + *spt = cached_spt; + *spc = cached_spc; - for (offset = 0; offset < io->i_cc; offset += BPS) { + return 0; +} - io->i_error = Biosread(io->biosdev, sector); - if (io->i_error) - return (-1); +//========================================================================== +// Maps (E)BIOS return codes to message strings. - /* copy 1 sector from the internal buffer biosbuf into buf */ - bcopy(biosbuf, &io->i_ma[offset], BPS); +struct NamedValue { + unsigned char value; + const char * name; +}; - sector++; - } +static const char * getNameForValue( const struct NamedValue * nameTable, + unsigned char value ) +{ + const struct NamedValue * np; - io->i_flgs &= ~F_TYPEMASK; + for ( np = nameTable; np->value; np++) + if (np->value == value) + return np->name; - return (io->i_cc); + return NULL; } -/*========================================================================== - * Maps (E)BIOS return codes to message strings. - */ -struct bios_error_info { - int errno; - const char * string; -}; - #define ECC_CORRECTED_ERR 0x11 -static struct bios_error_info bios_errors[] = { - {0x10, "Media error"}, - {0x11, "Corrected ECC error"}, - {0x20, "Controller or device error"}, - {0x40, "Seek failed"}, - {0x80, "Device timeout"}, - {0xAA, "Drive not ready"}, - {0x00, 0} +static const struct NamedValue bios_errors[] = { + { 0x10, "Media error" }, + { 0x11, "Corrected ECC error" }, + { 0x20, "Controller or device error" }, + { 0x40, "Seek failed" }, + { 0x80, "Device timeout" }, + { 0xAA, "Drive not ready" }, + { 0x00, 0 } }; -static const char * -bios_error(int errno) +static const char * bios_error(int errnum) { - struct bios_error_info * bp; - - for (bp = bios_errors; bp->errno; bp++) { - if (bp->errno == errno) - return bp->string; - } - return "Error 0x%02x"; // No string, print error code only + static char errorstr[] = "Error 0x00"; + const char * errname; + + errname = getNameForValue( bios_errors, errnum ); + if ( errname ) return errname; + + sprintf(errorstr, "Error 0x%02x", errnum); + return errorstr; // No string, print error code only } -/*========================================================================== - * Use BIOS INT13 calls to read the sector specified. This function will - * also perform read-ahead to cache a few subsequent sector to the sector - * cache. - * - * The fields in diskinfo structure must be filled in before calling this - * function. - * - * Return: - * Return code from INT13/F2 or INT13/F42 call. If operation was - * successful, 0 is returned. - * - */ -static int -Biosread(int biosdev, int secno) +//========================================================================== +// Use BIOS INT13 calls to read the sector specified. This function will +// also perform read-ahead to cache a few subsequent sector to the sector +// cache. +// +// Return: +// 0 on success, or an error code from INT13/F2 or INT13/F42 BIOS call. + +static int Biosread( int biosdev, unsigned int secno ) { - static int xbiosdev, xcyl, xhead, xsec, xnsecs; - - extern unsigned char uses_ebios[]; + static int xbiosdev, xcyl, xhead; + static unsigned int xsec, xnsecs; + static BOOL cache_valid = FALSE; - int rc; + int rc = -1; int cyl, head, sec; int spt, spc; int tries = 0; - DSPRINT(("Biosread %d \n", secno)); + // DEBUG_DISK(("Biosread dev %x sec %d \n", biosdev, secno)); // To read the disk sectors, use EBIOS if we can. Otherwise, // revert to the standard BIOS calls. - // - if ((biosdev >= BIOS_DEV_HD) && uses_ebios[biosdev - BIOS_DEV_HD]) { + + if ((biosdev >= kBIOSDevTypeHardDrive) && + (uses_ebios[biosdev - kBIOSDevTypeHardDrive] & EBIOS_FIXED_DISK_ACCESS)) + { if (cache_valid && (biosdev == xbiosdev) && (secno >= xsec) && (secno < (xsec + xnsecs))) { - biosbuf = intbuf + (BPS * (secno - xsec)); + biosbuf = trackbuf + (BPS * (secno - xsec)); return 0; } xnsecs = N_CACHE_SECS; xsec = secno; + cache_valid = FALSE; while ((rc = ebiosread(biosdev, secno, xnsecs)) && (++tries < 5)) { if (rc == ECC_CORRECTED_ERR) { /* Ignore corrected ECC errors */ + rc = 0; break; } error(" EBIOS read error: %s\n", bios_error(rc), rc); @@ -294,10 +217,8 @@ Biosread(int biosdev, int secno) sleep(1); } } - else { - spt = diskinfo.spt; // From previous INT13/F8 call. - spc = diskinfo.spc; - + else if ( getDiskGeometry(biosdev, &spt, &spc) == 0 ) + { cyl = secno / spc; head = (secno % spc) / spt; sec = secno % spt; @@ -309,24 +230,26 @@ Biosread(int biosdev, int secno) (sec >= xsec) && (sec < (xsec + xnsecs))) { - // this sector is in intbuf cache - biosbuf = intbuf + (BPS * (sec - xsec)); + // this sector is in trackbuf cache + biosbuf = trackbuf + (BPS * (sec - xsec)); return 0; } // Cache up to a track worth of sectors, but do not cross a // track boundary. - // + xcyl = cyl; xhead = head; xsec = sec; xnsecs = ((sec + N_CACHE_SECS) > spt) ? (spt - sec) : N_CACHE_SECS; + cache_valid = FALSE; while ((rc = biosread(biosdev, cyl, head, sec, xnsecs)) && (++tries < 5)) { if (rc == ECC_CORRECTED_ERR) { /* Ignore corrected ECC errors */ + rc = 0; break; } error(" BIOS read error: %s\n", bios_error(rc), rc); @@ -337,162 +260,388 @@ Biosread(int biosdev, int secno) } // If the BIOS reported success, mark the sector cache as valid. - // + if (rc == 0) { cache_valid = TRUE; } - biosbuf = intbuf; + biosbuf = trackbuf; xbiosdev = biosdev; - diskActivityHook(); + spinActivityIndicator(); return rc; } -/*========================================================================== - * Replace this function if you want to change - * the way disk activity is indicated to the user. - */ -void -diskActivityHook(void) +//========================================================================== + +static int readBytes( int biosdev, unsigned int blkno, + unsigned int byteCount, void * buffer ) { - spinActivityIndicator(); + + char * cbuf = (char *) buffer; + int error; + int copy_len; + + DEBUG_DISK(("%s: dev %x block %x [%d] -> 0x%x...", __FUNCTION__, + biosdev, blkno, byteCount, (unsigned)cbuf)); + + for ( ; byteCount; cbuf += BPS, blkno++ ) + { + error = Biosread( biosdev, blkno ); + if ( error ) + { + DEBUG_DISK(("error\n")); + return (-1); + } + + copy_len = (byteCount > BPS) ? BPS : byteCount; + bcopy( biosbuf, cbuf, copy_len ); + byteCount -= copy_len; + } + + DEBUG_DISK(("done\n")); + + return 0; } -/*========================================================================== - * Returns YES if the partition type specified is an extended fdisk - * partition. - */ -static BOOL -isExtendedPartition(u_int8_t type) +//========================================================================== + +static int isExtendedFDiskPartition( const struct fdisk_part * part ) { - int i; - - u_int8_t extended_partitions[] = { - 0x05, /* Extended */ - 0x0f, /* Win95 extended */ - 0x85, /* Linux extended */ - }; - - for (i = 0; - i < sizeof(extended_partitions)/sizeof(extended_partitions[0]); - i++) - { - if (extended_partitions[i] == type) - return YES; - } - return NO; + static unsigned char extParts[] = + { + 0x05, /* Extended */ + 0x0f, /* Win95 extended */ + 0x85, /* Linux extended */ + }; + + int i; + + for (i = 0; i < sizeof(extParts)/sizeof(extParts[0]); i++) + { + if (extParts[i] == part->systid) return 1; + } + return 0; } -/*========================================================================== - * Traverse the fdisk partition tables on disk until a partition is found - * that matches the specified type. - * - * Arguments: - * type - Partition type to search for (e.g. 0xa7 for NeXTSTEP). - * biosdev - BIOS device unit. 0x80 and up for hard-drive. - * mba - If true, the partition found must be marked active. - * - * Return: - * A pointer to the matching partition entry in biosbuf memory. - * Note that the starting LBA field in the partition entry is - * modified to contain the absolute sector address, rather than - * the relative address. - * A NULL is returned if a match is not found. - * - * There are certain fdisk rules that allows us to simplify the search. - * - * - There can be 0-1 extended partition entry in any partition table. - * - In the MBR, there can be 0-4 primary partitions entries. - * - In the extended partition, there can be 0-1 logical partition entry. - * - */ -struct fdisk_part * -find_partition(u_int8_t type, u_int8_t biosdev, BOOL mba) +//========================================================================== + +static int getNextFDiskPartition( int biosdev, int * partno, + const struct fdisk_part ** outPart ) { -#define MAX_ITERATIONS 128 + static int sBiosdev = -1; + static int sNextPartNo; + static unsigned int sExtBase; + static unsigned int sExtDepth; + static struct fdisk_part * sExtPart; + struct fdisk_part * part; + + if ( sBiosdev != biosdev || *partno < 0 ) + { + // Fetch MBR. + if ( readBootSector( biosdev, DISK_BLK0, 0 ) ) return 0; + + sBiosdev = biosdev; + sNextPartNo = 0; + sExtBase = 0; + sExtDepth = 0; + sExtPart = NULL; + } - static u_int32_t iter = 0; - static u_int32_t offset_root; - static u_int32_t offset; + while (1) + { + part = NULL; - int n; - int rc; - boot_sector * bootsect; - struct fdisk_part * match = 0; - struct fdisk_part * parts; + if ( sNextPartNo < FDISK_NPART ) + { + part = (struct fdisk_part *) gBootSector->parts[sNextPartNo]; + } + else if ( sExtPart ) + { + unsigned int blkno = sExtPart->relsect + sExtBase; - if (iter == 0) { - if (rc = Biosread(biosdev, 0)) // Read MBR at sector zero. - return 0; - offset = 0; + // Save the block offset of the first extended partition. + + if ( sExtDepth == 0 ) sExtBase = sExtPart->relsect; + + // Load extended partition table. + + if ( readBootSector( biosdev, blkno, 0 ) == 0 ) + { + sNextPartNo = 0; + sExtDepth++; + sExtPart = NULL; + continue; + } + } + + if ( part == NULL ) break; // Reached end of partition chain. + + // Advance to next partition number. + + sNextPartNo++; + + // Assume at most one extended partition per table. + + if ( isExtendedFDiskPartition(part) ) + { + sExtPart = part; + continue; + } + + // Skip empty slots. + + if ( part->systid == 0x00 ) + { + continue; + } + + // Change relative offset to an absolute offset. + + part->relsect += sExtBase; + + *outPart = part; + *partno = sExtDepth ? (sExtDepth + 4) : sNextPartNo; + + break; } - bootsect = (boot_sector *) biosbuf; - if (bootsect->signature != BOOT_SIGNATURE) - return 0; + return (part != NULL); +} + +//========================================================================== - // Find a primary or a logical partition that matches the partition - // type specified. - // - for (n = 0, parts = (struct fdisk_part *) bootsect->parts; - n < 4; - n++, parts++) +static BVRef newFDiskBVRef( int biosdev, int partno, unsigned int blkoff, + const struct fdisk_part * part, + FSInit initFunc, FSLoadFile loadFunc, + FSGetDirEntry getdirFunc, int probe ) +{ + BVRef bvr = (BVRef) malloc( sizeof(*bvr) ); + if ( bvr ) { - DSPRINT(("fdisk: [%d] %02x\n", iter, parts->systid)); + bzero(bvr, sizeof(*bvr)); - if (mba && ((parts->bootid & 0x80) == 0)) - continue; + bvr->biosdev = biosdev; + bvr->part_no = partno; + bvr->part_boff = blkoff; + bvr->part_type = part->systid; + bvr->fs_loadfile = loadFunc; + bvr->fs_getdirentry = getdirFunc; + bvr->description = getVolumeDescription; + + if ( part->bootid & FDISK_ACTIVE ) + bvr->flags |= kBVFlagPrimary; + + // Probe the filesystem. + + if ( initFunc ) + { + bvr->flags |= kBVFlagNativeBoot; - if (parts->systid == type) { - // - // Found it!!! - // Make the relsect field (LBA starting sector) absolute by - // adding in the offset. - // - parts->relsect += offset; + if ( probe && initFunc( bvr ) != 0 ) + { + // filesystem probe failed. - DSPRINT(("Found: %x (%d)\n", parts->relsect, parts->numsect)); + DEBUG_DISK(("%s: failed probe on dev %x part %d\n", + __FUNCTION__, biosdev, partno)); - return parts; + free(bvr); + bvr = NULL; + } + } + else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 ) + { + bvr->flags |= kBVFlagForeignBoot; + } + else + { + free(bvr); + bvr = NULL; } } + return bvr; +} - // Find if there is an extended partition entry that points to - // an extended partition table. Note that we only allow up to - // one extended partition per partition table. - // - for (n = 0, parts = (struct fdisk_part *) bootsect->parts; - n < 4; - n++, parts++) - { - DSPRINT(("fdisk: [E%d] %02x\n", iter, parts->systid)); +//========================================================================== + +BVRef diskScanBootVolumes( int biosdev, int * countPtr ) +{ + const struct fdisk_part * part; + struct DiskBVMap * map; + int partno = -1; + BVRef bvr; + BVRef booterUFS = NULL; + int spc, spt; - if (isExtendedPartition(parts->systid)) + do { + // Find an existing mapping for this device. + + for ( map = gDiskBVMap; map; map = map->next ) { - if (iter > MAX_ITERATIONS) // limit recursion depth - return 0; + if ( biosdev == map->biosdev ) break; + } + if ( map ) break; - if (iter == 0) - offset = offset_root = parts->relsect; - else - offset = parts->relsect + offset_root; + // Create a new mapping. - iter++; + map = (struct DiskBVMap *) malloc( sizeof(*map) ); + if ( map ) + { + map->biosdev = biosdev; + map->bvr = NULL; + map->bvrcnt = 0; + map->next = gDiskBVMap; + gDiskBVMap = map; - // Load extended partition table. - // - if (((rc = Biosread(biosdev, offset)) == 0) && - (bootsect->signature == BOOT_SIGNATURE)) + // Create a record for each partition found on the disk. + + while ( getNextFDiskPartition( biosdev, &partno, &part ) ) { - match = find_partition(type, biosdev, mba); + DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__, + partno, part->systid)); + + bvr = 0; + + switch ( part->systid ) + { + case FDISK_UFS: + bvr = newFDiskBVRef( + biosdev, partno, + part->relsect + UFS_FRONT_PORCH/BPS, + part, + UFSInitPartition, + UFSLoadFile, + UFSGetDirEntry, + 0 ); + break; + + case FDISK_HFS: + bvr = newFDiskBVRef( + biosdev, partno, + part->relsect, + part, + HFSInitPartition, + HFSLoadFile, + HFSGetDirEntry, + 0 ); + break; + + case FDISK_BOOTER: + if (getDiskGeometry(biosdev, &spt, &spc) != 0) + break; + + booterUFS = newFDiskBVRef( + biosdev, partno, + ((part->relsect + spc - 1) / spc) * spc, + part, + UFSInitPartition, + UFSLoadFile, + UFSGetDirEntry, + 0 ); + break; + + default: + bvr = newFDiskBVRef( + biosdev, partno, + part->relsect, + part, + 0, 0, 0, 0 ); + break; + } + + if ( bvr ) + { + bvr->next = map->bvr; + map->bvr = bvr; + map->bvrcnt++; + } } - - iter--; - break; + // Booting from a CD with an UFS filesystem embedded + // in a booter partition. + + if ( booterUFS ) + { + if ( map->bvrcnt == 0 ) + { + map->bvr = booterUFS; + map->bvrcnt++; + } + else free( booterUFS ); + } + } + } while (0); + + if (countPtr) *countPtr = map ? map->bvrcnt : 0; + + return map ? map->bvr : NULL; +} + +//========================================================================== + +static const struct NamedValue fdiskTypes[] = +{ + { 0x07, "Windows NTFS" }, + { 0x0c, "Windows FAT32" }, + { 0x83, "Linux" }, + { FDISK_UFS, "Apple UFS" }, + { FDISK_HFS, "Apple HFS" }, + { FDISK_BOOTER, "Apple Boot/UFS" }, + { 0x00, 0 } /* must be last */ +}; + +static void getVolumeDescription( BVRef bvr, char * str, long strMaxLen ) +{ + unsigned char type = (unsigned char) bvr->part_type; + const char * name = getNameForValue( fdiskTypes, type ); + + if ( name ) + sprintf( str, "hd(%d,%d) %s", + BIOS_DEV_UNIT(bvr->biosdev), bvr->part_no, name ); + else + sprintf( str, "hd(%d,%d) TYPE %02x", + BIOS_DEV_UNIT(bvr->biosdev), bvr->part_no, type ); +} + +//========================================================================== + +int readBootSector( int biosdev, unsigned int secno, void * buffer ) +{ + struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer; + int error; + + if ( bootSector == NULL ) + { + if ( gBootSector == NULL ) + { + gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector)); + if ( gBootSector == NULL ) return -1; } + bootSector = gBootSector; } - - return match; + + error = readBytes( biosdev, secno, BPS, bootSector ); + if ( error || bootSector->signature != DISK_SIGNATURE ) + return -1; + + return 0; +} + +//========================================================================== +// Handle seek request from filesystem modules. + +void diskSeek( BVRef bvr, long long position ) +{ + bvr->fs_boff = position / BPS; +} + +//========================================================================== +// Handle read request from filesystem modules. + +int diskRead( BVRef bvr, long addr, long length ) +{ + return readBytes( bvr->biosdev, + bvr->fs_boff + bvr->part_boff, + length, + (void *) addr ); } diff --git a/i386/libsaio/fdisk.h b/i386/libsaio/fdisk.h new file mode 100644 index 0000000..6805024 --- /dev/null +++ b/i386/libsaio/fdisk.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.1 (the "License"). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Copyright (c) 1992 NeXT Computer, Inc. + * + * IBM PC disk partitioning data structures. + * + * HISTORY + * + * 8 July 1992 David E. Bohman at NeXT + * Created. + */ + +#ifndef __LIBSAIO_FDISK_H +#define __LIBSAIO_FDISK_H + +#define DISK_BLK0 0 /* blkno of boot block */ +#define DISK_BLK0SZ 512 /* size of boot block */ +#define DISK_BOOTSZ 446 /* size of boot code in boot block */ +#define DISK_SIGNATURE 0xAA55 /* signature of the boot record */ +#define FDISK_NPART 4 /* number of entries in fdisk table */ +#define FDISK_ACTIVE 0x80 /* indicator of active partition */ +#define FDISK_NEXTNAME 0xA7 /* indicator of NeXT partition */ +#define FDISK_DOS12 0x01 /* 12-bit fat < 10MB dos partition */ +#define FDISK_DOS16S 0x04 /* 16-bit fat < 32MB dos partition */ +#define FDISK_DOSEXT 0x05 /* extended dos partition */ +#define FDISK_DOS16B 0x06 /* 16-bit fat >= 32MB dos partition */ +#define FDISK_UFS 0xa8 /* Apple UFS partition */ +#define FDISK_HFS 0xaf /* Apple HFS partition */ +#define FDISK_BOOTER 0xab /* Apple booter partition */ + +/* + * Format of fdisk partion entry (if present). + */ +struct fdisk_part { + unsigned char bootid; /* bootable or not */ + unsigned char beghead; /* begining head, sector, cylinder */ + unsigned char begsect; /* begcyl is a 10-bit number */ + unsigned char begcyl; /* High 2 bits are in begsect */ + unsigned char systid; /* OS type */ + unsigned char endhead; /* ending head, sector, cylinder */ + unsigned char endsect; /* endcyl is a 10-bit number */ + unsigned char endcyl; /* High 2 bits are in endsect */ + unsigned long relsect; /* partion physical offset on disk */ + unsigned long numsect; /* number of sectors in partition */ +}; + +/* + * Format of boot block. + */ +struct disk_blk0 { + unsigned char bootcode[DISK_BOOTSZ]; + unsigned char parts[FDISK_NPART][sizeof (struct fdisk_part)]; + unsigned short signature; +}; + +#endif /* !__LIBSAIO_FDISK_H */ diff --git a/i386/libsaio/gets.c b/i386/libsaio/gets.c deleted file mode 100644 index a47c70f..0000000 --- a/i386/libsaio/gets.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright 1993, NeXT Computer Inc. - * All rights reserved. - */ - -#include "libsaio.h" - -int gets( char * buf, int len ) -{ - char *lp = buf, *end = buf + len - 1; - int c; - - flushdev(); // XXX - - for (;;) { - c = getchar() & 0x7f; - if (c < ' ' && c != '\n' && c != '\b') c = 0; - if (c == 0x7f) c = '\b'; - - switch(c) - { - case '\0': - continue; - case '\n': - *lp++ = '\0'; - putchar('\n'); - return 1; - case '\b': - if (lp > buf) { - lp--; - putchar('\b'); - putchar(' '); - putchar('\b'); - } - continue; - default: - if (lp < end) - *lp++ = c; - else - { - putchar('\b'); - putchar(' '); - putchar('\b'); - putchar('\007'); - } - } - } -} - -/* - * Return a string in buf if typing has begun within timeout units. - */ -int -Gets( char * buf, - int len, - int timeout, - char * prompt, - char * message ) -{ - int ch = 0; - int next_second; - - flushdev(); // XXX - - printf("%s", prompt); - - if (message) - printf("%s", message); - - if (timeout) - { - for ( next_second = time18() + 18; timeout; ) - { - if (ch = readKeyboardStatus()) - { - break; - } - if ( time18() >= next_second ) - { - next_second += 18; - timeout--; - } - } - - if (ch == 0) - { - printf("\n"); - return 0; - } - } - return ( gets(buf, len) ); -} diff --git a/i386/libsaio/hfs.c b/i386/libsaio/hfs.c new file mode 100644 index 0000000..939d208 --- /dev/null +++ b/i386/libsaio/hfs.c @@ -0,0 +1,884 @@ +/* + * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * hfs.c - File System Module for HFS and HFS+. + * + * Copyright (c) 1999-2002 Apple Computer, Inc. + * + * DRI: Josh de Cesare + */ + +#include +#include + +#define kBlockSize (0x200) + +#define kMDBBaseOffset (2 * kBlockSize) + +#define kBTreeCatalog (0) +#define kBTreeExtents (1) + +#ifdef __i386__ + +static CICell gCurrentIH; +static long long gAllocationOffset; +static long gIsHFSPlus; +static long gBlockSize; +static long gCacheBlockSize; +static char *gBTreeHeaderBuffer; +static BTHeaderRec *gBTHeaders[2]; +static char *gHFSMdbVib; +static HFSMasterDirectoryBlock *gHFSMDB; +static char *gHFSPlusHeader; +static HFSPlusVolumeHeader *gHFSPlus; +static char *gLinkTemp; +static char *gTempStr; + +#else /* !__i386__ */ + +static CICell gCurrentIH; +static long long gAllocationOffset; +static long gIsHFSPlus; +static long gBlockSize; +static long gCacheBlockSize; +static char gBTreeHeaderBuffer[512]; +static BTHeaderRec *gBTHeaders[2]; +static char gHFSMdbVib[kBlockSize]; +static HFSMasterDirectoryBlock *gHFSMDB =(HFSMasterDirectoryBlock*)gHFSMdbVib; +static char gHFSPlusHeader[kBlockSize]; +static HFSPlusVolumeHeader *gHFSPlus =(HFSPlusVolumeHeader*)gHFSPlusHeader; +static char gLinkTemp[64]; + +#endif /* !__i386__ */ + +static long ReadFile(void *file, long *length); +static long GetCatalogEntryInfo(void *entry, long *flags, long *time); +static long ResolvePathToCatalogEntry(char *filePath, long *flags, + void *entry, long dirID, long *dirIndex); + +static long GetCatalogEntry(long *dirIndex, char **name, + long *flags, long *time); +static long ReadCatalogEntry(char *fileName, long dirID, void *entry, + long *dirIndex); +static long ReadExtentsEntry(long fileID, long startBlock, void *entry); + +static long ReadBTreeEntry(long btree, void *key, char *entry, long *dirIndex); +static void GetBTreeRecord(long index, char *nodeBuffer, long nodeSize, + char **key, char **data); + +static long ReadExtent(char *extent, long extentSize, long extentFile, + long offset, long size, void *buffer, long cache); + +static long GetExtentStart(void *extents, long index); +static long GetExtentSize(void *extents, long index); + +static long CompareHFSCatalogKeys(void *key, void *testKey); +static long CompareHFSPlusCatalogKeys(void *key, void *testKey); +static long CompareHFSExtentsKeys(void *key, void *testKey); +static long CompareHFSPlusExtentsKeys(void *key, void *testKey); + +extern long FastRelString(char *str1, char *str2); +extern long FastUnicodeCompare(u_int16_t *uniStr1, u_int32_t len1, + u_int16_t *uniStr2, u_int32_t len2); +extern void utf_encodestr(const u_int16_t *ucsp, int ucslen, + u_int8_t *utf8p, u_int32_t bufsize); +extern void utf_decodestr(const u_int8_t *utf8p, u_int16_t *ucsp, + u_int16_t *ucslen, u_int32_t bufsize); + + +long HFSInitPartition(CICell ih) +{ + long extentSize, extentFile, nodeSize; + void *extent; + + if (ih == gCurrentIH) { +#ifdef __i386__ + CacheInit(ih, gCacheBlockSize); +#endif + return 0; + } + + verbose("HFSInitPartition: %x\n", ih); + +#ifdef __i386__ + if (!gTempStr) gTempStr = (char *)malloc(4096); + if (!gLinkTemp) gLinkTemp = (char *)malloc(64); + if (!gBTreeHeaderBuffer) gBTreeHeaderBuffer = (char *)malloc(512); + if (!gHFSMdbVib) { + gHFSMdbVib = (char *)malloc(kBlockSize); + gHFSMDB = (HFSMasterDirectoryBlock *)gHFSMdbVib; + } + if (!gHFSPlusHeader) { + gHFSPlusHeader = (char *)malloc(kBlockSize); + gHFSPlus = (HFSPlusVolumeHeader *)gHFSPlusHeader; + } + if (!gTempStr || !gLinkTemp || !gBTreeHeaderBuffer || + !gHFSMdbVib || !gHFSPlusHeader) return -1; +#endif /* __i386__ */ + + gAllocationOffset = 0; + gIsHFSPlus = 0; + gBTHeaders[0] = 0; + gBTHeaders[1] = 0; + + // Look for the HFS MDB + Seek(ih, kMDBBaseOffset); + Read(ih, (long)gHFSMdbVib, kBlockSize); + + if ( SWAP_BE16(gHFSMDB->drSigWord) == kHFSSigWord ) { + gAllocationOffset = SWAP_BE16(gHFSMDB->drAlBlSt) * kBlockSize; + + // See if it is HFSPlus + if (SWAP_BE16(gHFSMDB->drEmbedSigWord) != kHFSPlusSigWord) { + // Normal HFS; + gCacheBlockSize = gBlockSize = SWAP_BE32(gHFSMDB->drAlBlkSiz); + CacheInit(ih, gCacheBlockSize); + gCurrentIH = ih; + + // Get the Catalog BTree node size. + extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec; + extentSize = SWAP_BE32(gHFSMDB->drCTFlSize); + extentFile = kHFSCatalogFileID; + ReadExtent(extent, extentSize, extentFile, 0, 256, + gBTreeHeaderBuffer + kBTreeCatalog * 256, 0); + + nodeSize = SWAP_BE16(((BTHeaderRec *)(gBTreeHeaderBuffer + kBTreeCatalog * 256 + + sizeof(BTNodeDescriptor)))->nodeSize); + + // If the BTree node size is larger than the block size, reset the cache. + if (nodeSize > gBlockSize) { + gCacheBlockSize = nodeSize; + CacheInit(ih, gCacheBlockSize); + } + + return 0; + } + + // Calculate the offset to the embeded HFSPlus volume. + gAllocationOffset += (long long)SWAP_BE16(gHFSMDB->drEmbedExtent.startBlock) * + SWAP_BE32(gHFSMDB->drAlBlkSiz); + } + + // Look for the HFSPlus Header + Seek(ih, gAllocationOffset + kMDBBaseOffset); + Read(ih, (long)gHFSPlusHeader, kBlockSize); + + // Not a HFS[+] volume. + if (SWAP_BE16(gHFSPlus->signature) != kHFSPlusSigWord) return -1; + + gIsHFSPlus = 1; + gCacheBlockSize = gBlockSize = SWAP_BE32(gHFSPlus->blockSize); + CacheInit(ih, gCacheBlockSize); + gCurrentIH = ih; + + // Get the Catalog BTree node size. + extent = &gHFSPlus->catalogFile.extents; + extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize); + extentFile = kHFSCatalogFileID; + + ReadExtent(extent, extentSize, extentFile, 0, 256, + gBTreeHeaderBuffer + kBTreeCatalog * 256, 0); + + nodeSize = SWAP_BE16(((BTHeaderRec *)(gBTreeHeaderBuffer + kBTreeCatalog * 256 + + sizeof(BTNodeDescriptor)))->nodeSize); + + // If the BTree node size is larger than the block size, reset the cache. + if (nodeSize > gBlockSize) { + gCacheBlockSize = nodeSize; + CacheInit(ih, gCacheBlockSize); + } + + return 0; +} + +long HFSLoadFile(CICell ih, char * filePath) +{ + char entry[512]; + long dirID, result, length, flags; + + if (HFSInitPartition(ih) == -1) return -1; + + verbose("Loading HFS%s file: [%s] from %x.\n", + (gIsHFSPlus ? "+" : ""), filePath, ih); + + dirID = kHFSRootFolderID; + // Skip a lead '\'. Start in the system folder if there are two. + if (filePath[0] == '/') { + if (filePath[1] == '/') { + if (gIsHFSPlus) dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]); + else dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]); + if (dirID == 0) return -1; + filePath++; + } + filePath++; + } + + result = ResolvePathToCatalogEntry(filePath, &flags, entry, dirID, 0); + if ((result == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) return -1; + +#if 0 // Not yet for Intel. System.config/Default.table will fail this check. + // Check file owner and permissions. + if (flags & (kOwnerNotRoot | kPermGroupWrite | kPermOtherWrite)) return -1; +#endif + + result = ReadFile(entry, &length); + if (result == -1) return -1; + + return length; +} + +long HFSGetDirEntry(CICell ih, char * dirPath, long * dirIndex, char ** name, + long * flags, long * time) +{ + char entry[512]; + long dirID, dirFlags; + + if (HFSInitPartition(ih) == -1) return -1; + + if (*dirIndex == -1) return -1; + + dirID = kHFSRootFolderID; + // Skip a lead '\'. Start in the system folder if there are two. + if (dirPath[0] == '/') { + if (dirPath[1] == '/') { + if (gIsHFSPlus) dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]); + else dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]); + if (dirID == 0) return -1; + dirPath++; + } + dirPath++; + } + + if (*dirIndex == 0) { + ResolvePathToCatalogEntry(dirPath, &dirFlags, entry, dirID, dirIndex); + if (*dirIndex == 0) *dirIndex = -1; + if ((dirFlags & kFileTypeMask) != kFileTypeUnknown) return -1; + } + + GetCatalogEntry(dirIndex, name, flags, time); + if (*dirIndex == 0) *dirIndex = -1; + if ((*flags & kFileTypeMask) == kFileTypeUnknown) return -1; + + return 0; +} + +// Private Functions + +static long ReadFile(void * file, long * length) +{ + void *extents; + long fileID; + HFSCatalogFile *hfsFile = file; + HFSPlusCatalogFile *hfsPlusFile = file; + + if (gIsHFSPlus) { + fileID = SWAP_BE32(hfsPlusFile->fileID); + *length = SWAP_BE64(hfsPlusFile->dataFork.logicalSize); + extents = &hfsPlusFile->dataFork.extents; + } else { + fileID = SWAP_BE32(hfsFile->fileID); + *length = SWAP_BE32(hfsFile->dataLogicalSize); + extents = &hfsFile->dataExtents; + } + + if (*length > kLoadSize) { + printf("File is too large.\n"); + return -1; + } + +#ifdef __i386__ + *length = ReadExtent((char *)extents, *length, fileID, + 0, *length, (char *)gFSLoadAddress, 0); +#else + *length = ReadExtent((char *)extents, *length, fileID, + 0, *length, (char *)kLoadAddr, 0); +#endif + + return 0; +} + +static long GetCatalogEntryInfo(void * entry, long * flags, long * time) +{ + long tmpTime = 0; + + // Get information about the file. + + switch ( SWAP_BE16(*(short *)entry) ) + { + case kHFSFolderRecord : + *flags = kFileTypeDirectory; + tmpTime = SWAP_BE32(((HFSCatalogFolder *)entry)->modifyDate); + break; + + case kHFSPlusFolderRecord : + *flags = kFileTypeDirectory | + (SWAP_BE16(((HFSPlusCatalogFolder *)entry)->bsdInfo.fileMode) & kPermMask); + if (SWAP_BE32(((HFSPlusCatalogFolder *)entry)->bsdInfo.ownerID) != 0) + *flags |= kOwnerNotRoot; + tmpTime = SWAP_BE32(((HFSPlusCatalogFolder *)entry)->contentModDate); + break; + + case kHFSFileRecord : + *flags = kFileTypeFlat; + tmpTime = SWAP_BE32(((HFSCatalogFile *)entry)->modifyDate); + break; + + case kHFSPlusFileRecord : + *flags = kFileTypeFlat | + (SWAP_BE16(((HFSPlusCatalogFile *)entry)->bsdInfo.fileMode) & kPermMask); + if (SWAP_BE32(((HFSPlusCatalogFile *)entry)->bsdInfo.ownerID) != 0) + *flags |= kOwnerNotRoot; + tmpTime = SWAP_BE32(((HFSPlusCatalogFile *)entry)->contentModDate); + break; + + case kHFSFileThreadRecord : + case kHFSPlusFileThreadRecord : + case kHFSFolderThreadRecord : + case kHFSPlusFolderThreadRecord : + *flags = kFileTypeUnknown; + tmpTime = 0; + break; + } + + if (time != 0) { + // Convert base time from 1904 to 1970. + *time = tmpTime - 2082844800; + } + + return 0; +} + +static long ResolvePathToCatalogEntry(char * filePath, long * flags, + void * entry, long dirID, long * dirIndex) +{ + char *restPath; + long result, cnt, subFolderID, tmpDirIndex; + HFSPlusCatalogFile *hfsPlusFile; + + // Copy the file name to gTempStr + cnt = 0; + while ((filePath[cnt] != '/') && (filePath[cnt] != '\0')) cnt++; + strncpy(gTempStr, filePath, cnt); + + // Move restPath to the right place. + if (filePath[cnt] != '\0') cnt++; + restPath = filePath + cnt; + + // gTempStr is a name in the current Dir. + // restPath is the rest of the path if any. + + result = ReadCatalogEntry(gTempStr, dirID, entry, dirIndex); + if (result == -1) return -1; + + GetCatalogEntryInfo(entry, flags, 0); + + if ((*flags & kFileTypeMask) == kFileTypeDirectory) { + if (gIsHFSPlus) + subFolderID = SWAP_BE32(((HFSPlusCatalogFolder *)entry)->folderID); + else + subFolderID = SWAP_BE32(((HFSCatalogFolder *)entry)->folderID); + + result = ResolvePathToCatalogEntry(restPath, flags, entry, + subFolderID, dirIndex); + } + + if (gIsHFSPlus && ((*flags & kFileTypeMask) == kFileTypeFlat)) { + hfsPlusFile = (HFSPlusCatalogFile *)entry; + if ((SWAP_BE32(hfsPlusFile->userInfo.fdType) == kHardLinkFileType) && + (SWAP_BE32(hfsPlusFile->userInfo.fdCreator) == kHFSPlusCreator)) { + sprintf(gLinkTemp, "%s/%s%ld", HFSPLUSMETADATAFOLDER, + HFS_INODE_PREFIX, SWAP_BE32(hfsPlusFile->bsdInfo.special.iNodeNum)); + result = ResolvePathToCatalogEntry(gLinkTemp, flags, entry, + kHFSRootFolderID, &tmpDirIndex); + } + } + + return result; +} + +static long GetCatalogEntry(long * dirIndex, char ** name, + long * flags, long * time) +{ + long extentSize, nodeSize, curNode, index; + void *extent; + char *nodeBuf, *testKey, *entry; + BTNodeDescriptor *node; + + if (gIsHFSPlus) { + extent = &gHFSPlus->catalogFile.extents; + extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize); + } else { + extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec; + extentSize = SWAP_BE32(gHFSMDB->drCTFlSize); + } + + nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize); + nodeBuf = (char *)malloc(nodeSize); + node = (BTNodeDescriptor *)nodeBuf; + + index = *dirIndex % nodeSize; + curNode = *dirIndex / nodeSize; + + // Read the BTree node and get the record for index. + ReadExtent(extent, extentSize, kHFSCatalogFileID, + curNode * nodeSize, nodeSize, nodeBuf, 1); + GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &entry); + + GetCatalogEntryInfo(entry, flags, time); + + // Get the file name. + if (gIsHFSPlus) { + utf_encodestr(((HFSPlusCatalogKey *)testKey)->nodeName.unicode, + SWAP_BE16(((HFSPlusCatalogKey *)testKey)->nodeName.length), + gTempStr, 256); + } else { + strncpy(gTempStr, + &((HFSCatalogKey *)testKey)->nodeName[1], + ((HFSCatalogKey *)testKey)->nodeName[0]); + } + *name = gTempStr; + + // Update dirIndex. + index++; + if (index == SWAP_BE16(node->numRecords)) { + index = 0; + curNode = SWAP_BE32(node->fLink); + } + *dirIndex = curNode * nodeSize + index; + + free(nodeBuf); + + return 0; +} + +static long ReadCatalogEntry(char * fileName, long dirID, + void * entry, long * dirIndex) +{ + long length; + char key[sizeof(HFSPlusCatalogKey)]; + HFSCatalogKey *hfsKey = (HFSCatalogKey *)key; + HFSPlusCatalogKey *hfsPlusKey = (HFSPlusCatalogKey *)key; + + // Make the catalog key. + if ( gIsHFSPlus ) + { + hfsPlusKey->parentID = SWAP_BE32(dirID); + length = strlen(fileName); + if (length > 255) length = 255; + utf_decodestr(fileName, hfsPlusKey->nodeName.unicode, + &(hfsPlusKey->nodeName.length), 512); + } else { + hfsKey->parentID = SWAP_BE32(dirID); + length = strlen(fileName); + if (length > 31) length = 31; + hfsKey->nodeName[0] = length; + strncpy(hfsKey->nodeName + 1, fileName, length); + } + + return ReadBTreeEntry(kBTreeCatalog, &key, entry, dirIndex); +} + +static long ReadExtentsEntry(long fileID, long startBlock, void * entry) +{ + char key[sizeof(HFSPlusExtentKey)]; + HFSExtentKey *hfsKey = (HFSExtentKey *)key; + HFSPlusExtentKey *hfsPlusKey = (HFSPlusExtentKey *)key; + + // Make the extents key. + if (gIsHFSPlus) { + hfsPlusKey->forkType = 0; + hfsPlusKey->fileID = SWAP_BE32(fileID); + hfsPlusKey->startBlock = SWAP_BE32(startBlock); + } else { + hfsKey->forkType = 0; + hfsKey->fileID = SWAP_BE32(fileID); + hfsKey->startBlock = SWAP_BE16(startBlock); + } + + return ReadBTreeEntry(kBTreeExtents, &key, entry, 0); +} + +static long ReadBTreeEntry(long btree, void * key, char * entry, long * dirIndex) +{ + long extentSize; + void *extent; + short extentFile; + char *nodeBuf; + BTNodeDescriptor *node; + long nodeSize, result = 0, entrySize = 0; + long curNode, index = 0, lowerBound, upperBound; + char *testKey, *recordData; + + // Figure out which tree is being looked at. + if (btree == kBTreeCatalog) { + if (gIsHFSPlus) { + extent = &gHFSPlus->catalogFile.extents; + extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize); + } else { + extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec; + extentSize = SWAP_BE32(gHFSMDB->drCTFlSize); + } + extentFile = kHFSCatalogFileID; + } else { + if (gIsHFSPlus) { + extent = &gHFSPlus->extentsFile.extents; + extentSize = SWAP_BE64(gHFSPlus->extentsFile.logicalSize); + } else { + extent = (HFSExtentDescriptor *)&gHFSMDB->drXTExtRec; + extentSize = SWAP_BE32(gHFSMDB->drXTFlSize); + } + extentFile = kHFSExtentsFileID; + } + + // Read the BTree Header if needed. + if (gBTHeaders[btree] == 0) { + ReadExtent(extent, extentSize, extentFile, 0, 256, + gBTreeHeaderBuffer + btree * 256, 0); + gBTHeaders[btree] = (BTHeaderRec *)(gBTreeHeaderBuffer + btree * 256 + + sizeof(BTNodeDescriptor)); + } + + curNode = SWAP_BE32(gBTHeaders[btree]->rootNode); + nodeSize = SWAP_BE16(gBTHeaders[btree]->nodeSize); + nodeBuf = (char *)malloc(nodeSize); + node = (BTNodeDescriptor *)nodeBuf; + + while (1) { + // Read the current node. + ReadExtent(extent, extentSize, extentFile, + curNode * nodeSize, nodeSize, nodeBuf, 1); + + // Find the matching key. + lowerBound = 0; + upperBound = SWAP_BE16(node->numRecords) - 1; + while (lowerBound <= upperBound) { + index = (lowerBound + upperBound) / 2; + + GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData); + + if (gIsHFSPlus) { + if (btree == kBTreeCatalog) { + result = CompareHFSPlusCatalogKeys(key, testKey); + } else { + result = CompareHFSPlusExtentsKeys(key, testKey); + } + } else { + if (btree == kBTreeCatalog) { + result = CompareHFSCatalogKeys(key, testKey); + } else { + result = CompareHFSExtentsKeys(key, testKey); + } + } + + if (result < 0) upperBound = index - 1; // search < trial + else if (result > 0) lowerBound = index + 1; // search > trial + else break; // search = trial + } + + if (result < 0) { + index = upperBound; + GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData); + } + + // Found the closest key... Recurse on it if this is an index node. + if (node->kind == kBTIndexNode) { + curNode = SWAP_BE32( *((long *)recordData) ); + } else break; + } + + // Return error if the file was not found. + if (result != 0) { free(nodeBuf); return -1; } + + if (btree == kBTreeCatalog) { + switch (SWAP_BE16(*(short *)recordData)) { + case kHFSFolderRecord : entrySize = 70; break; + case kHFSFileRecord : entrySize = 102; break; + case kHFSFolderThreadRecord : entrySize = 46; break; + case kHFSFileThreadRecord : entrySize = 46; break; + case kHFSPlusFolderRecord : entrySize = 88; break; + case kHFSPlusFileRecord : entrySize = 248; break; + case kHFSPlusFolderThreadRecord : entrySize = 264; break; + case kHFSPlusFileThreadRecord : entrySize = 264; break; + } + } else { + if (gIsHFSPlus) entrySize = sizeof(HFSPlusExtentRecord); + else entrySize = sizeof(HFSExtentRecord); + } + + bcopy(recordData, entry, entrySize); + + // Update dirIndex. + if (dirIndex != 0) { + index++; + if (index == SWAP_BE16(node->numRecords)) { + index = 0; + curNode = SWAP_BE32(node->fLink); + } + *dirIndex = curNode * nodeSize + index; + } + + free(nodeBuf); + + return 0; +} + +static void GetBTreeRecord(long index, char * nodeBuffer, long nodeSize, + char ** key, char ** data) +{ + long keySize; + long recordOffset; + + recordOffset = SWAP_BE16(*((short *)(nodeBuffer + (nodeSize - 2 * index - 2)))); + *key = nodeBuffer + recordOffset; + if (gIsHFSPlus) { + keySize = SWAP_BE16(*(short *)*key); + *data = *key + 2 + keySize; + } else { + keySize = **key; + *data = *key + 2 + keySize - (keySize & 1); + } +} + +static long ReadExtent(char * extent, long extentSize, + long extentFile, long offset, long size, + void * buffer, long cache) +{ + long lastOffset, blockNumber, countedBlocks = 0; + long nextExtent = 0, sizeRead = 0, readSize; + long nextExtentBlock, currentExtentBlock = 0; + long long readOffset; + long extentDensity, sizeofExtent, currentExtentSize; + char *currentExtent, *extentBuffer = 0, *bufferPos = buffer; + + if (offset >= extentSize) return 0; + + if (gIsHFSPlus) { + extentDensity = kHFSPlusExtentDensity; + sizeofExtent = sizeof(HFSPlusExtentDescriptor); + } else { + extentDensity = kHFSExtentDensity; + sizeofExtent = sizeof(HFSExtentDescriptor); + } + + lastOffset = offset + size; + while (offset < lastOffset) { + blockNumber = offset / gBlockSize; + + // Find the extent for the offset. + for (; ; nextExtent++) { + if (nextExtent < extentDensity) { + if ((countedBlocks+GetExtentSize(extent, nextExtent)-1)= blockNumber) { + currentExtent = extentBuffer + sizeofExtent * (nextExtent % extentDensity); + break; + } + + countedBlocks += currentExtentSize; + } + + readOffset = ((blockNumber - countedBlocks) * gBlockSize) + + (offset % gBlockSize); + + readSize = GetExtentSize(currentExtent, 0) * gBlockSize - readOffset; + if (readSize > (size - sizeRead)) readSize = size - sizeRead; + + readOffset += (long long)GetExtentStart(currentExtent, 0) * gBlockSize; + + CacheRead(gCurrentIH, bufferPos, gAllocationOffset + readOffset, + readSize, cache); + + sizeRead += readSize; + offset += readSize; + bufferPos += readSize; + } + + if (extentBuffer) free(extentBuffer); + + return sizeRead; +} + +static long GetExtentStart(void * extents, long index) +{ + long start; + HFSExtentDescriptor *hfsExtents = extents; + HFSPlusExtentDescriptor *hfsPlusExtents = extents; + + if (gIsHFSPlus) start = SWAP_BE32(hfsPlusExtents[index].startBlock); + else start = SWAP_BE16(hfsExtents[index].startBlock); + + return start; +} + +static long GetExtentSize(void * extents, long index) +{ + long size; + HFSExtentDescriptor *hfsExtents = extents; + HFSPlusExtentDescriptor *hfsPlusExtents = extents; + + if (gIsHFSPlus) size = SWAP_BE32(hfsPlusExtents[index].blockCount); + else size = SWAP_BE16(hfsExtents[index].blockCount); + + return size; +} + +static long CompareHFSCatalogKeys(void * key, void * testKey) +{ + HFSCatalogKey *searchKey, *trialKey; + long result, searchParentID, trialParentID; + + searchKey = key; + trialKey = testKey; + + searchParentID = SWAP_BE32(searchKey->parentID); + trialParentID = SWAP_BE32(trialKey->parentID); + + // parent dirID is unsigned + if (searchParentID > trialParentID) result = 1; + else if (searchParentID < trialParentID) result = -1; + else { + // parent dirID's are equal, compare names + result = FastRelString(searchKey->nodeName, trialKey->nodeName); + } + + return result; +} + +static long CompareHFSPlusCatalogKeys(void * key, void * testKey) +{ + HFSPlusCatalogKey *searchKey, *trialKey; + long result, searchParentID, trialParentID; + + searchKey = key; + trialKey = testKey; + + searchParentID = SWAP_BE32(searchKey->parentID); + trialParentID = SWAP_BE32(trialKey->parentID); + + // parent dirID is unsigned + if (searchParentID > trialParentID) result = 1; + else if (searchParentID < trialParentID) result = -1; + else { + // parent dirID's are equal, compare names + if ((searchKey->nodeName.length == 0) || (trialKey->nodeName.length == 0)) + result = searchKey->nodeName.length - trialKey->nodeName.length; + else + result = FastUnicodeCompare(&searchKey->nodeName.unicode[0], + SWAP_BE16(searchKey->nodeName.length), + &trialKey->nodeName.unicode[0], + SWAP_BE16(trialKey->nodeName.length)); + } + + return result; +} + +static long CompareHFSExtentsKeys(void * key, void * testKey) +{ + HFSExtentKey *searchKey, *trialKey; + long result; + + searchKey = key; + trialKey = testKey; + + // assume searchKey < trialKey + result = -1; + + if (searchKey->fileID == trialKey->fileID) { + // FileNum's are equal; compare fork types + if (searchKey->forkType == trialKey->forkType) { + // Fork types are equal; compare allocation block number + if (searchKey->startBlock == trialKey->startBlock) { + // Everything is equal + result = 0; + } else { + // Allocation block numbers differ; determine sign + if (SWAP_BE16(searchKey->startBlock) > SWAP_BE16(trialKey->startBlock)) + result = 1; + } + } else { + // Fork types differ; determine sign + if (searchKey->forkType > trialKey->forkType) result = 1; + } + } else { + // FileNums differ; determine sign + if (SWAP_BE32(searchKey->fileID) > SWAP_BE32(trialKey->fileID)) + result = 1; + } + + return result; +} + +static long CompareHFSPlusExtentsKeys(void * key, void * testKey) +{ + HFSPlusExtentKey *searchKey, *trialKey; + long result; + + searchKey = key; + trialKey = testKey; + + // assume searchKey < trialKey + result = -1; + + if (searchKey->fileID == trialKey->fileID) { + // FileNum's are equal; compare fork types + if (searchKey->forkType == trialKey->forkType) { + // Fork types are equal; compare allocation block number + if (searchKey->startBlock == trialKey->startBlock) { + // Everything is equal + result = 0; + } else { + // Allocation block numbers differ; determine sign + if (SWAP_BE32(searchKey->startBlock) > SWAP_BE32(trialKey->startBlock)) + result = 1; + } + } else { + // Fork types differ; determine sign + if (searchKey->forkType > trialKey->forkType) result = 1; + } + } else { + // FileNums differ; determine sign + if (SWAP_BE32(searchKey->fileID) > SWAP_BE32(trialKey->fileID)) + result = 1; + } + + return result; +} diff --git a/i386/libsaio/hfs_CaseTables.h b/i386/libsaio/hfs_CaseTables.h new file mode 100644 index 0000000..d4691b6 --- /dev/null +++ b/i386/libsaio/hfs_CaseTables.h @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + File: CaseTables.h +*/ + + +/* The lower case table consists of a 256-entry high-byte table followed by some number of + 256-entry subtables. The high-byte table contains either an offset to the subtable for + characters with that high byte or zero, which means that there are no case mappings or + ignored characters in that block. Ignored characters are mapped to zero. + */ + +u_int16_t gLowerCaseTable[] = { + + // High-byte indices ( == 0 iff no case mapping and no ignorables ) + + /* 0 */ 0x0100, 0x0200, 0x0000, 0x0300, 0x0400, 0x0500, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 1 */ 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 2 */ 0x0700, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 3 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 4 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 5 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 6 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 7 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 9 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* A */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* B */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* C */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* D */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* E */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* F */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0900, 0x0A00, + + // Table 1 (for high byte 0x00) + + /* 0 */ 0xFFFF, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + /* 1 */ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + /* 2 */ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + /* 3 */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + /* 4 */ 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + /* 5 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + /* 6 */ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + /* 7 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + /* 8 */ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + /* 9 */ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + /* A */ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + /* B */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + /* C */ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00E6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + /* D */ 0x00F0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00F8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00FE, 0x00DF, + /* E */ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + /* F */ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, + + // Table 2 (for high byte 0x01) + + /* 0 */ 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, 0x010F, + /* 1 */ 0x0111, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0117, 0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, 0x011F, + /* 2 */ 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0127, 0x0127, 0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F, + /* 3 */ 0x0130, 0x0131, 0x0133, 0x0133, 0x0134, 0x0135, 0x0136, 0x0137, 0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, 0x0140, + /* 4 */ 0x0140, 0x0142, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147, 0x0148, 0x0149, 0x014B, 0x014B, 0x014C, 0x014D, 0x014E, 0x014F, + /* 5 */ 0x0150, 0x0151, 0x0153, 0x0153, 0x0154, 0x0155, 0x0156, 0x0157, 0x0158, 0x0159, 0x015A, 0x015B, 0x015C, 0x015D, 0x015E, 0x015F, + /* 6 */ 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165, 0x0167, 0x0167, 0x0168, 0x0169, 0x016A, 0x016B, 0x016C, 0x016D, 0x016E, 0x016F, + /* 7 */ 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, 0x0177, 0x0178, 0x0179, 0x017A, 0x017B, 0x017C, 0x017D, 0x017E, 0x017F, + /* 8 */ 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188, 0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259, + /* 9 */ 0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268, 0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275, + /* A */ 0x01A0, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x01A6, 0x01A8, 0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01AF, + /* B */ 0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292, 0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF, + /* C */ 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9, 0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC, 0x01CD, 0x01CE, 0x01CF, + /* D */ 0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, 0x01D5, 0x01D6, 0x01D7, 0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, 0x01DD, 0x01DE, 0x01DF, + /* E */ 0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E5, 0x01E5, 0x01E6, 0x01E7, 0x01E8, 0x01E9, 0x01EA, 0x01EB, 0x01EC, 0x01ED, 0x01EE, 0x01EF, + /* F */ 0x01F0, 0x01F3, 0x01F3, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7, 0x01F8, 0x01F9, 0x01FA, 0x01FB, 0x01FC, 0x01FD, 0x01FE, 0x01FF, + + // Table 3 (for high byte 0x03) + + /* 0 */ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, 0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F, + /* 1 */ 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, 0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F, + /* 2 */ 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, 0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F, + /* 3 */ 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, 0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F, + /* 4 */ 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347, 0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F, + /* 5 */ 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, 0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F, + /* 6 */ 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, 0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F, + /* 7 */ 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, 0x0378, 0x0379, 0x037A, 0x037B, 0x037C, 0x037D, 0x037E, 0x037F, + /* 8 */ 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387, 0x0388, 0x0389, 0x038A, 0x038B, 0x038C, 0x038D, 0x038E, 0x038F, + /* 9 */ 0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + /* A */ 0x03C0, 0x03C1, 0x03A2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + /* B */ 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + /* C */ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x03CF, + /* D */ 0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7, 0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF, + /* E */ 0x03E0, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7, 0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF, + /* F */ 0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03F4, 0x03F5, 0x03F6, 0x03F7, 0x03F8, 0x03F9, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF, + + // Table 4 (for high byte 0x04) + + /* 0 */ 0x0400, 0x0401, 0x0452, 0x0403, 0x0454, 0x0455, 0x0456, 0x0407, 0x0458, 0x0459, 0x045A, 0x045B, 0x040C, 0x040D, 0x040E, 0x045F, + /* 1 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0419, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + /* 2 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + /* 3 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + /* 4 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + /* 5 */ 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045D, 0x045E, 0x045F, + /* 6 */ 0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467, 0x0469, 0x0469, 0x046B, 0x046B, 0x046D, 0x046D, 0x046F, 0x046F, + /* 7 */ 0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0476, 0x0477, 0x0479, 0x0479, 0x047B, 0x047B, 0x047D, 0x047D, 0x047F, 0x047F, + /* 8 */ 0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F, + /* 9 */ 0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497, 0x0499, 0x0499, 0x049B, 0x049B, 0x049D, 0x049D, 0x049F, 0x049F, + /* A */ 0x04A1, 0x04A1, 0x04A3, 0x04A3, 0x04A5, 0x04A5, 0x04A7, 0x04A7, 0x04A9, 0x04A9, 0x04AB, 0x04AB, 0x04AD, 0x04AD, 0x04AF, 0x04AF, + /* B */ 0x04B1, 0x04B1, 0x04B3, 0x04B3, 0x04B5, 0x04B5, 0x04B7, 0x04B7, 0x04B9, 0x04B9, 0x04BB, 0x04BB, 0x04BD, 0x04BD, 0x04BF, 0x04BF, + /* C */ 0x04C0, 0x04C1, 0x04C2, 0x04C4, 0x04C4, 0x04C5, 0x04C6, 0x04C8, 0x04C8, 0x04C9, 0x04CA, 0x04CC, 0x04CC, 0x04CD, 0x04CE, 0x04CF, + /* D */ 0x04D0, 0x04D1, 0x04D2, 0x04D3, 0x04D4, 0x04D5, 0x04D6, 0x04D7, 0x04D8, 0x04D9, 0x04DA, 0x04DB, 0x04DC, 0x04DD, 0x04DE, 0x04DF, + /* E */ 0x04E0, 0x04E1, 0x04E2, 0x04E3, 0x04E4, 0x04E5, 0x04E6, 0x04E7, 0x04E8, 0x04E9, 0x04EA, 0x04EB, 0x04EC, 0x04ED, 0x04EE, 0x04EF, + /* F */ 0x04F0, 0x04F1, 0x04F2, 0x04F3, 0x04F4, 0x04F5, 0x04F6, 0x04F7, 0x04F8, 0x04F9, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF, + + // Table 5 (for high byte 0x05) + + /* 0 */ 0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509, 0x050A, 0x050B, 0x050C, 0x050D, 0x050E, 0x050F, + /* 1 */ 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517, 0x0518, 0x0519, 0x051A, 0x051B, 0x051C, 0x051D, 0x051E, 0x051F, + /* 2 */ 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, 0x0528, 0x0529, 0x052A, 0x052B, 0x052C, 0x052D, 0x052E, 0x052F, + /* 3 */ 0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, 0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F, + /* 4 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, 0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F, + /* 5 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557, 0x0558, 0x0559, 0x055A, 0x055B, 0x055C, 0x055D, 0x055E, 0x055F, + /* 6 */ 0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, 0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F, + /* 7 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, 0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F, + /* 8 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587, 0x0588, 0x0589, 0x058A, 0x058B, 0x058C, 0x058D, 0x058E, 0x058F, + /* 9 */ 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597, 0x0598, 0x0599, 0x059A, 0x059B, 0x059C, 0x059D, 0x059E, 0x059F, + /* A */ 0x05A0, 0x05A1, 0x05A2, 0x05A3, 0x05A4, 0x05A5, 0x05A6, 0x05A7, 0x05A8, 0x05A9, 0x05AA, 0x05AB, 0x05AC, 0x05AD, 0x05AE, 0x05AF, + /* B */ 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, 0x05B8, 0x05B9, 0x05BA, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF, + /* C */ 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05C4, 0x05C5, 0x05C6, 0x05C7, 0x05C8, 0x05C9, 0x05CA, 0x05CB, 0x05CC, 0x05CD, 0x05CE, 0x05CF, + /* D */ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + /* E */ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC, 0x05ED, 0x05EE, 0x05EF, + /* F */ 0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0x05F5, 0x05F6, 0x05F7, 0x05F8, 0x05F9, 0x05FA, 0x05FB, 0x05FC, 0x05FD, 0x05FE, 0x05FF, + + // Table 6 (for high byte 0x10) + + /* 0 */ 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1008, 0x1009, 0x100A, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F, + /* 1 */ 0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, 0x1017, 0x1018, 0x1019, 0x101A, 0x101B, 0x101C, 0x101D, 0x101E, 0x101F, + /* 2 */ 0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027, 0x1028, 0x1029, 0x102A, 0x102B, 0x102C, 0x102D, 0x102E, 0x102F, + /* 3 */ 0x1030, 0x1031, 0x1032, 0x1033, 0x1034, 0x1035, 0x1036, 0x1037, 0x1038, 0x1039, 0x103A, 0x103B, 0x103C, 0x103D, 0x103E, 0x103F, + /* 4 */ 0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047, 0x1048, 0x1049, 0x104A, 0x104B, 0x104C, 0x104D, 0x104E, 0x104F, + /* 5 */ 0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057, 0x1058, 0x1059, 0x105A, 0x105B, 0x105C, 0x105D, 0x105E, 0x105F, + /* 6 */ 0x1060, 0x1061, 0x1062, 0x1063, 0x1064, 0x1065, 0x1066, 0x1067, 0x1068, 0x1069, 0x106A, 0x106B, 0x106C, 0x106D, 0x106E, 0x106F, + /* 7 */ 0x1070, 0x1071, 0x1072, 0x1073, 0x1074, 0x1075, 0x1076, 0x1077, 0x1078, 0x1079, 0x107A, 0x107B, 0x107C, 0x107D, 0x107E, 0x107F, + /* 8 */ 0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087, 0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x108F, + /* 9 */ 0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097, 0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x109F, + /* A */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF, + /* B */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF, + /* C */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10C6, 0x10C7, 0x10C8, 0x10C9, 0x10CA, 0x10CB, 0x10CC, 0x10CD, 0x10CE, 0x10CF, + /* D */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF, + /* E */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF, + /* F */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10F6, 0x10F7, 0x10F8, 0x10F9, 0x10FA, 0x10FB, 0x10FC, 0x10FD, 0x10FE, 0x10FF, + + // Table 7 (for high byte 0x20) + + /* 0 */ 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x200B, 0x0000, 0x0000, 0x0000, 0x0000, + /* 1 */ 0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017, 0x2018, 0x2019, 0x201A, 0x201B, 0x201C, 0x201D, 0x201E, 0x201F, + /* 2 */ 0x2020, 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027, 0x2028, 0x2029, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x202F, + /* 3 */ 0x2030, 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037, 0x2038, 0x2039, 0x203A, 0x203B, 0x203C, 0x203D, 0x203E, 0x203F, + /* 4 */ 0x2040, 0x2041, 0x2042, 0x2043, 0x2044, 0x2045, 0x2046, 0x2047, 0x2048, 0x2049, 0x204A, 0x204B, 0x204C, 0x204D, 0x204E, 0x204F, + /* 5 */ 0x2050, 0x2051, 0x2052, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057, 0x2058, 0x2059, 0x205A, 0x205B, 0x205C, 0x205D, 0x205E, 0x205F, + /* 6 */ 0x2060, 0x2061, 0x2062, 0x2063, 0x2064, 0x2065, 0x2066, 0x2067, 0x2068, 0x2069, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 7 */ 0x2070, 0x2071, 0x2072, 0x2073, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, 0x207A, 0x207B, 0x207C, 0x207D, 0x207E, 0x207F, + /* 8 */ 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087, 0x2088, 0x2089, 0x208A, 0x208B, 0x208C, 0x208D, 0x208E, 0x208F, + /* 9 */ 0x2090, 0x2091, 0x2092, 0x2093, 0x2094, 0x2095, 0x2096, 0x2097, 0x2098, 0x2099, 0x209A, 0x209B, 0x209C, 0x209D, 0x209E, 0x209F, + /* A */ 0x20A0, 0x20A1, 0x20A2, 0x20A3, 0x20A4, 0x20A5, 0x20A6, 0x20A7, 0x20A8, 0x20A9, 0x20AA, 0x20AB, 0x20AC, 0x20AD, 0x20AE, 0x20AF, + /* B */ 0x20B0, 0x20B1, 0x20B2, 0x20B3, 0x20B4, 0x20B5, 0x20B6, 0x20B7, 0x20B8, 0x20B9, 0x20BA, 0x20BB, 0x20BC, 0x20BD, 0x20BE, 0x20BF, + /* C */ 0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7, 0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x20CF, + /* D */ 0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7, 0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x20DF, + /* E */ 0x20E0, 0x20E1, 0x20E2, 0x20E3, 0x20E4, 0x20E5, 0x20E6, 0x20E7, 0x20E8, 0x20E9, 0x20EA, 0x20EB, 0x20EC, 0x20ED, 0x20EE, 0x20EF, + /* F */ 0x20F0, 0x20F1, 0x20F2, 0x20F3, 0x20F4, 0x20F5, 0x20F6, 0x20F7, 0x20F8, 0x20F9, 0x20FA, 0x20FB, 0x20FC, 0x20FD, 0x20FE, 0x20FF, + + // Table 8 (for high byte 0x21) + + /* 0 */ 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107, 0x2108, 0x2109, 0x210A, 0x210B, 0x210C, 0x210D, 0x210E, 0x210F, + /* 1 */ 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117, 0x2118, 0x2119, 0x211A, 0x211B, 0x211C, 0x211D, 0x211E, 0x211F, + /* 2 */ 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x2126, 0x2127, 0x2128, 0x2129, 0x212A, 0x212B, 0x212C, 0x212D, 0x212E, 0x212F, + /* 3 */ 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137, 0x2138, 0x2139, 0x213A, 0x213B, 0x213C, 0x213D, 0x213E, 0x213F, + /* 4 */ 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147, 0x2148, 0x2149, 0x214A, 0x214B, 0x214C, 0x214D, 0x214E, 0x214F, + /* 5 */ 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F, + /* 6 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F, + /* 7 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F, + /* 8 */ 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187, 0x2188, 0x2189, 0x218A, 0x218B, 0x218C, 0x218D, 0x218E, 0x218F, + /* 9 */ 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197, 0x2198, 0x2199, 0x219A, 0x219B, 0x219C, 0x219D, 0x219E, 0x219F, + /* A */ 0x21A0, 0x21A1, 0x21A2, 0x21A3, 0x21A4, 0x21A5, 0x21A6, 0x21A7, 0x21A8, 0x21A9, 0x21AA, 0x21AB, 0x21AC, 0x21AD, 0x21AE, 0x21AF, + /* B */ 0x21B0, 0x21B1, 0x21B2, 0x21B3, 0x21B4, 0x21B5, 0x21B6, 0x21B7, 0x21B8, 0x21B9, 0x21BA, 0x21BB, 0x21BC, 0x21BD, 0x21BE, 0x21BF, + /* C */ 0x21C0, 0x21C1, 0x21C2, 0x21C3, 0x21C4, 0x21C5, 0x21C6, 0x21C7, 0x21C8, 0x21C9, 0x21CA, 0x21CB, 0x21CC, 0x21CD, 0x21CE, 0x21CF, + /* D */ 0x21D0, 0x21D1, 0x21D2, 0x21D3, 0x21D4, 0x21D5, 0x21D6, 0x21D7, 0x21D8, 0x21D9, 0x21DA, 0x21DB, 0x21DC, 0x21DD, 0x21DE, 0x21DF, + /* E */ 0x21E0, 0x21E1, 0x21E2, 0x21E3, 0x21E4, 0x21E5, 0x21E6, 0x21E7, 0x21E8, 0x21E9, 0x21EA, 0x21EB, 0x21EC, 0x21ED, 0x21EE, 0x21EF, + /* F */ 0x21F0, 0x21F1, 0x21F2, 0x21F3, 0x21F4, 0x21F5, 0x21F6, 0x21F7, 0x21F8, 0x21F9, 0x21FA, 0x21FB, 0x21FC, 0x21FD, 0x21FE, 0x21FF, + + // Table 9 (for high byte 0xFE) + + /* 0 */ 0xFE00, 0xFE01, 0xFE02, 0xFE03, 0xFE04, 0xFE05, 0xFE06, 0xFE07, 0xFE08, 0xFE09, 0xFE0A, 0xFE0B, 0xFE0C, 0xFE0D, 0xFE0E, 0xFE0F, + /* 1 */ 0xFE10, 0xFE11, 0xFE12, 0xFE13, 0xFE14, 0xFE15, 0xFE16, 0xFE17, 0xFE18, 0xFE19, 0xFE1A, 0xFE1B, 0xFE1C, 0xFE1D, 0xFE1E, 0xFE1F, + /* 2 */ 0xFE20, 0xFE21, 0xFE22, 0xFE23, 0xFE24, 0xFE25, 0xFE26, 0xFE27, 0xFE28, 0xFE29, 0xFE2A, 0xFE2B, 0xFE2C, 0xFE2D, 0xFE2E, 0xFE2F, + /* 3 */ 0xFE30, 0xFE31, 0xFE32, 0xFE33, 0xFE34, 0xFE35, 0xFE36, 0xFE37, 0xFE38, 0xFE39, 0xFE3A, 0xFE3B, 0xFE3C, 0xFE3D, 0xFE3E, 0xFE3F, + /* 4 */ 0xFE40, 0xFE41, 0xFE42, 0xFE43, 0xFE44, 0xFE45, 0xFE46, 0xFE47, 0xFE48, 0xFE49, 0xFE4A, 0xFE4B, 0xFE4C, 0xFE4D, 0xFE4E, 0xFE4F, + /* 5 */ 0xFE50, 0xFE51, 0xFE52, 0xFE53, 0xFE54, 0xFE55, 0xFE56, 0xFE57, 0xFE58, 0xFE59, 0xFE5A, 0xFE5B, 0xFE5C, 0xFE5D, 0xFE5E, 0xFE5F, + /* 6 */ 0xFE60, 0xFE61, 0xFE62, 0xFE63, 0xFE64, 0xFE65, 0xFE66, 0xFE67, 0xFE68, 0xFE69, 0xFE6A, 0xFE6B, 0xFE6C, 0xFE6D, 0xFE6E, 0xFE6F, + /* 7 */ 0xFE70, 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE75, 0xFE76, 0xFE77, 0xFE78, 0xFE79, 0xFE7A, 0xFE7B, 0xFE7C, 0xFE7D, 0xFE7E, 0xFE7F, + /* 8 */ 0xFE80, 0xFE81, 0xFE82, 0xFE83, 0xFE84, 0xFE85, 0xFE86, 0xFE87, 0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, 0xFE8D, 0xFE8E, 0xFE8F, + /* 9 */ 0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, 0xFE96, 0xFE97, 0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, 0xFE9E, 0xFE9F, + /* A */ 0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, 0xFEAE, 0xFEAF, + /* B */ 0xFEB0, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, 0xFEBE, 0xFEBF, + /* C */ 0xFEC0, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, 0xFECD, 0xFECE, 0xFECF, + /* D */ 0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, 0xFED5, 0xFED6, 0xFED7, 0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, 0xFEDE, 0xFEDF, + /* E */ 0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, 0xFEEE, 0xFEEF, + /* F */ 0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, 0xFEF6, 0xFEF7, 0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0xFEFD, 0xFEFE, 0x0000, + + // Table 10 (for high byte 0xFF) + + /* 0 */ 0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07, 0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F, + /* 1 */ 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17, 0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0xFF1F, + /* 2 */ 0xFF20, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, + /* 3 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F, + /* 4 */ 0xFF40, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, + /* 5 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0xFF5B, 0xFF5C, 0xFF5D, 0xFF5E, 0xFF5F, + /* 6 */ 0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67, 0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F, + /* 7 */ 0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77, 0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F, + /* 8 */ 0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87, 0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F, + /* 9 */ 0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97, 0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F, + /* A */ 0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, 0xFFA6, 0xFFA7, 0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, 0xFFAE, 0xFFAF, + /* B */ 0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, 0xFFB6, 0xFFB7, 0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, 0xFFBE, 0xFFBF, + /* C */ 0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC6, 0xFFC7, 0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF, + /* D */ 0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, 0xFFD6, 0xFFD7, 0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, 0xFFDE, 0xFFDF, + /* E */ 0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0xFFE4, 0xFFE5, 0xFFE6, 0xFFE7, 0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED, 0xFFEE, 0xFFEF, + /* F */ 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7, 0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF, +}; + + +/* RelString case folding table */ + +unsigned short gCompareTable[] = { + + /* 0 */ 0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00, 0x0F00, + /* 1 */ 0x1000, 0x1100, 0x1200, 0x1300, 0x1400, 0x1500, 0x1600, 0x1700, 0x1800, 0x1900, 0x1A00, 0x1B00, 0x1C00, 0x1D00, 0x1E00, 0x1F00, + /* 2 */ 0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, 0x2600, 0x2700, 0x2800, 0x2900, 0x2A00, 0x2B00, 0x2C00, 0x2D00, 0x2E00, 0x2F00, + /* 3 */ 0x3000, 0x3100, 0x3200, 0x3300, 0x3400, 0x3500, 0x3600, 0x3700, 0x3800, 0x3900, 0x3A00, 0x3B00, 0x3C00, 0x3D00, 0x3E00, 0x3F00, + /* 4 */ 0x4000, 0x4100, 0x4200, 0x4300, 0x4400, 0x4500, 0x4600, 0x4700, 0x4800, 0x4900, 0x4A00, 0x4B00, 0x4C00, 0x4D00, 0x4E00, 0x4F00, + /* 5 */ 0x5000, 0x5100, 0x5200, 0x5300, 0x5400, 0x5500, 0x5600, 0x5700, 0x5800, 0x5900, 0x5A00, 0x5B00, 0x5C00, 0x5D00, 0x5E00, 0x5F00, + + // 0x60 maps to 'a' + // range 0x61 to 0x7a ('a' to 'z') map to upper case + + /* 6 */ 0x4180, 0x4100, 0x4200, 0x4300, 0x4400, 0x4500, 0x4600, 0x4700, 0x4800, 0x4900, 0x4A00, 0x4B00, 0x4C00, 0x4D00, 0x4E00, 0x4F00, + /* 7 */ 0x5000, 0x5100, 0x5200, 0x5300, 0x5400, 0x5500, 0x5600, 0x5700, 0x5800, 0x5900, 0x5A00, 0x7B00, 0x7C00, 0x7D00, 0x7E00, 0x7F00, + + // range 0x80 to 0xd8 gets mapped... + + /* 8 */ 0x4108, 0x410C, 0x4310, 0x4502, 0x4E0A, 0x4F08, 0x5508, 0x4182, 0x4104, 0x4186, 0x4108, 0x410A, 0x410C, 0x4310, 0x4502, 0x4584, + /* 9 */ 0x4586, 0x4588, 0x4982, 0x4984, 0x4986, 0x4988, 0x4E0A, 0x4F82, 0x4F84, 0x4F86, 0x4F08, 0x4F0A, 0x5582, 0x5584, 0x5586, 0x5508, + /* A */ 0xA000, 0xA100, 0xA200, 0xA300, 0xA400, 0xA500, 0xA600, 0x5382, 0xA800, 0xA900, 0xAA00, 0xAB00, 0xAC00, 0xAD00, 0x4114, 0x4F0E, + /* B */ 0xB000, 0xB100, 0xB200, 0xB300, 0xB400, 0xB500, 0xB600, 0xB700, 0xB800, 0xB900, 0xBA00, 0x4192, 0x4F92, 0xBD00, 0x4114, 0x4F0E, + /* C */ 0xC000, 0xC100, 0xC200, 0xC300, 0xC400, 0xC500, 0xC600, 0x2206, 0x2208, 0xC900, 0x2000, 0x4104, 0x410A, 0x4F0A, 0x4F14, 0x4F14, + /* D */ 0xD000, 0xD100, 0x2202, 0x2204, 0x2702, 0x2704, 0xD600, 0xD700, 0x5988, 0xD900, 0xDA00, 0xDB00, 0xDC00, 0xDD00, 0xDE00, 0xDF00, + + /* E */ 0xE000, 0xE100, 0xE200, 0xE300, 0xE400, 0xE500, 0xE600, 0xE700, 0xE800, 0xE900, 0xEA00, 0xEB00, 0xEC00, 0xED00, 0xEE00, 0xEF00, + /* F */ 0xF000, 0xF100, 0xF200, 0xF300, 0xF400, 0xF500, 0xF600, 0xF700, 0xF800, 0xF900, 0xFA00, 0xFB00, 0xFC00, 0xFD00, 0xFE00, 0xFF00, + +}; diff --git a/i386/libsaio/hfs_compare.c b/i386/libsaio/hfs_compare.c new file mode 100644 index 0000000..8917c1c --- /dev/null +++ b/i386/libsaio/hfs_compare.c @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * HFSCompare.c - Functions for working with and comparing HFS nams. + * + * Copyright (c) 1999-2000 Apple Computer, Inc. + * + * DRI: Josh de Cesare + */ + +#include +#include "hfs_CaseTables.h" + +//_______________________________________________________________________ +// +// Routine: FastRelString +// +// Output: returns -1 if str1 < str2 +// returns 1 if str1 > str2 +// return 0 if equal +// +//_______________________________________________________________________ + +int32_t FastRelString(char * str1, char * str2) +{ + int32_t bestGuess; + u_int8_t length, length2; + + length = *(str1++); + length2 = *(str2++); + + if (length == length2) + bestGuess = 0; + else if (length < length2) + bestGuess = -1; + else + { + bestGuess = 1; + length = length2; + } + + while (length--) + { + u_int32_t aChar, bChar; + + aChar = *(str1++); + bChar = *(str2++); + + if (aChar != bChar) /* If they don't match exacly, do case conversion */ + { + u_int16_t aSortWord, bSortWord; + + aSortWord = gCompareTable[aChar]; + bSortWord = gCompareTable[bChar]; + + if (aSortWord > bSortWord) + return 1; + + if (aSortWord < bSortWord) + return -1; + } + + /* + * If characters match exactly, then go on to next character + * immediately without doing any extra work. + */ + } + + /* if you got to here, then return bestGuess */ + return bestGuess; +} + + +// +// FastUnicodeCompare - Compare two Unicode strings; produce a relative ordering +// +// IF RESULT +// -------------------------- +// str1 < str2 => -1 +// str1 = str2 => 0 +// str1 > str2 => +1 +// +// The lower case table starts with 256 entries (one for each of the upper bytes +// of the original Unicode char). If that entry is zero, then all characters with +// that upper byte are already case folded. If the entry is non-zero, then it is +// the _index_ (not byte offset) of the start of the sub-table for the characters +// with that upper byte. All ignorable characters are folded to the value zero. +// +// In pseudocode: +// +// Let c = source Unicode character +// Let table[] = lower case table +// +// lower = table[highbyte(c)] +// if (lower == 0) +// lower = c +// else +// lower = table[lower+lowbyte(c)] +// +// if (lower == 0) +// ignore this character +// +// To handle ignorable characters, we now need a loop to find the next valid character. +// Also, we can't pre-compute the number of characters to compare; the string length might +// be larger than the number of non-ignorable characters. Further, we must be able to handle +// ignorable characters at any point in the string, including as the first or last characters. +// We use a zero value as a sentinel to detect both end-of-string and ignorable characters. +// Since the File Manager doesn't prevent the NUL character (value zero) as part of a filename, +// the case mapping table is assumed to map u+0000 to some non-zero value (like 0xFFFF, which is +// an invalid Unicode character). +// +// Pseudocode: +// +// while (1) { +// c1 = GetNextValidChar(str1) // returns zero if at end of string +// c2 = GetNextValidChar(str2) +// +// if (c1 != c2) break // found a difference +// +// if (c1 == 0) // reached end of string on both strings at once? +// return 0; // yes, so strings are equal +// } +// +// // When we get here, c1 != c2. So, we just need to determine which one is less. +// if (c1 < c2) +// return -1; +// else +// return 1; +// + +int32_t FastUnicodeCompare( u_int16_t * str1, register u_int32_t length1, + u_int16_t * str2, register u_int32_t length2 ) +{ + register u_int16_t c1,c2; + register u_int16_t temp; + + while (1) { + /* Set default values for c1, c2 in case there are no more valid chars */ + c1 = 0; + c2 = 0; + + /* Find next non-ignorable char from str1, or zero if no more */ + while (length1 && c1 == 0) { + c1 = SWAP_BE16(*(str1++)); + --length1; + if ((temp = gLowerCaseTable[c1>>8]) != 0) // is there a subtable for this upper byte? + c1 = gLowerCaseTable[temp + (c1 & 0x00FF)]; // yes, so fold the char + } + + /* Find next non-ignorable char from str2, or zero if no more */ + while (length2 && c2 == 0) { + c2 = SWAP_BE16(*(str2++)); + --length2; + if ((temp = gLowerCaseTable[c2>>8]) != 0) // is there a subtable for this upper byte? + c2 = gLowerCaseTable[temp + (c2 & 0x00FF)]; // yes, so fold the char + } + + if (c1 != c2) /* found a difference, so stop looping */ + break; + + if (c1 == 0) /* did we reach the end of both strings at the same time? */ + return 0; /* yes, so strings are equal */ + } + + if (c1 < c2) + return -1; + else + return 1; +} + + +/* + * UTF-8 (UCS Transformation Format) + * + * The following subset of UTF-8 is used to encode UCS-2 filenames. It + * requires a maximum of three 3 bytes per UCS-2 character. Only the + * shortest encoding required to represent the significant UCS-2 bits + * is legal. + * + * UTF-8 Multibyte Codes + * + * Bytes Bits UCS-2 Min UCS-2 Max UTF-8 Byte Sequence (binary) + * ------------------------------------------------------------------- + * 1 7 0x0000 0x007F 0xxxxxxx + * 2 11 0x0080 0x07FF 110xxxxx 10xxxxxx + * 3 16 0x0800 0xFFFF 1110xxxx 10xxxxxx 10xxxxxx + * ------------------------------------------------------------------- + */ + + +/* + * utf_encodestr - Encodes the UCS-2 (Unicode) string at ucsp into a + * null terminated UTF-8 string at utf8p. + * + * ucslen is the number of UCS-2 input characters (not bytes) + * bufsize is the size of the output buffer in bytes + */ +void +utf_encodestr( const u_int16_t * ucsp, int ucslen, + u_int8_t * utf8p, u_int32_t bufsize ) +{ + u_int8_t *bufend; + u_int16_t ucs_ch; + + bufend = utf8p + bufsize; + + while (ucslen-- > 0) { + ucs_ch = SWAP_BE16(*ucsp++); + + if (ucs_ch < 0x0080) { + if (utf8p >= bufend) + break; + if (ucs_ch == '\0') + continue; /* skip over embedded NULLs */ + *utf8p++ = ucs_ch; + + } else if (ucs_ch < 0x800) { + if ((utf8p + 1) >= bufend) + break; + *utf8p++ = (ucs_ch >> 6) | 0xc0; + *utf8p++ = (ucs_ch & 0x3f) | 0x80; + + } else { + if ((utf8p + 2) >= bufend) + break; + *utf8p++ = (ucs_ch >> 12) | 0xe0; + *utf8p++ = ((ucs_ch >> 6) & 0x3f) | 0x80; + *utf8p++ = ((ucs_ch) & 0x3f) | 0x80; + } + } + + *utf8p = '\0'; +} + + +/* + * utf_decodestr - Decodes the null terminated UTF-8 string at + * utf8p into a UCS-2 (Unicode) string at ucsp. + * + * ucslen is the number of UCS-2 output characters (not bytes) + * bufsize is the size of the output buffer in bytes + */ +void utf_decodestr(const u_int8_t * utf8p, u_int16_t * ucsp, u_int16_t * ucslen, u_int32_t bufsize) +{ + u_int16_t *bufstart; + u_int16_t *bufend; + u_int16_t ucs_ch; + u_int8_t byte; + + bufstart = ucsp; + bufend = (u_int16_t *)((u_int8_t *)ucsp + bufsize); + + while ((byte = *utf8p++) != '\0') { + if (ucsp >= bufend) + break; + + /* check for ascii */ + if (byte < 0x80) { + ucs_ch = byte; + + *ucsp++ = SWAP_BE16(ucs_ch); + continue; + } + + switch (byte & 0xf0) { + /* 2 byte sequence*/ + case 0xc0: + case 0xd0: + /* extract bits 6 - 10 from first byte */ + ucs_ch = (byte & 0x1F) << 6; + break; + /* 3 byte sequence*/ + case 0xe0: + /* extract bits 12 - 15 from first byte */ + ucs_ch = (byte & 0x0F) << 6; + + /* extract bits 6 - 11 from second byte */ + if (((byte = *utf8p++) & 0xc0) != 0x80) + goto stop; + + ucs_ch += (byte & 0x3F); + ucs_ch <<= 6; + break; + default: + goto stop; + } + + /* extract bits 0 - 5 from final byte */ + if (((byte = *utf8p++) & 0xc0) != 0x80) + goto stop; + ucs_ch += (byte & 0x3F); + + *ucsp++ = SWAP_BE16(ucs_ch); + } +stop: + *ucslen = SWAP_BE16(ucsp - bufstart); +} diff --git a/i386/libsaio/legacy/PCI.h b/i386/libsaio/legacy/PCI.h deleted file mode 100644 index 70f711d..0000000 --- a/i386/libsaio/legacy/PCI.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright (c) 1994-1996 NeXT Software, Inc. All rights reserved. - * - * PCI Configuration space structure and associated defines. - * - * HISTORY - * - * 13 May 1994 Dean Reece at NeXT - * Created. - * - */ - -/* The IOPCIConfigSpace structure can be used to decode the 256 byte - * configuration space presented by each PCI device. This structure - * is based on the PCI LOCAL BUS SPECIFICATION, rev 2.1, section 6.1 - */ - -typedef struct _IOPCIConfigSpace { - unsigned short VendorID; - unsigned short DeviceID; - unsigned short Command; - unsigned short Status; - unsigned long RevisionID:8; - unsigned long ClassCode:24; - unsigned char CacheLineSize; - unsigned char LatencyTimer; - unsigned char HeaderType; - unsigned char BuiltInSelfTest; - unsigned long BaseAddress[6]; - unsigned long CardbusCISpointer; - unsigned short SubVendorID; - unsigned short SubDeviceID; - unsigned long ROMBaseAddress; - unsigned long reserved3; - unsigned long reserved4; - unsigned char InterruptLine; - unsigned char InterruptPin; - unsigned char MinGrant; - unsigned char MaxLatency; - unsigned long VendorUnique[48]; -} IOPCIConfigSpace; - - -/* PCI_DEFAULT_DATA is the value resulting from a read to a non-existent - * PCI device's configuration space. - */ - -#define PCI_DEFAULT_DATA 0xffffffff - - -/* PCI_INVALID_VENDOR_ID is a Vendor ID reserved by the PCI/SIG and is - * guaranteed not to be assigned to any vendor. - */ - -#define PCI_INVALID_VENDOR_ID 0xffff diff --git a/i386/libsaio/legacy/asm.h b/i386/libsaio/legacy/asm.h deleted file mode 100644 index b7e9016..0000000 --- a/i386/libsaio/legacy/asm.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Mach Operating System - * Copyright (c) 1989 Carnegie-Mellon University - * All rights reserved. The CMU software License Agreement specifies - * the terms and conditions for use and redistribution. - */ -/* - * HISTORY - * $Log: asm.h,v $ - * Revision 1.2 2000/03/07 06:10:59 wsanchez - * Make main branch like boot-3, which builds. - * - * Revision 1.1.2.1 2000/02/29 00:04:34 jliu - * Added legacy header files. - * - * Revision 1.1.1.1 1997/09/30 02:45:05 wsanchez - * Import of kernel from umeshv/kernel - * - * Revision 2.1.1.6 90/03/29 20:45:08 rvb - * Typo on ENTRY if gprof - * [90/03/29 rvb] - * - * Revision 2.1.1.5 90/02/28 15:47:31 rvb - * fix SVC for "ifdef wheeze" [kupfer] - * - * Revision 2.1.1.4 90/02/27 08:47:30 rvb - * Fix the GPROF definitions. - * ENTRY(x) gets profiled iffdef GPROF. - * Entry(x) (and DATA(x)) is NEVER profiled. - * MCOUNT can be used by asm that intends to build a frame, - * after the frame is built. - * [90/02/26 rvb] - * - * Revision 2.1.1.3 90/02/09 17:23:23 rvb - * Add #define addr16 .byte 0x67 - * [90/02/09 rvb] - * - * Revision 2.1.1.2 89/11/10 09:51:33 rvb - * Added LBi, SVC and ENTRY - * - * Revision 2.1.1.1 89/10/22 11:29:38 rvb - * New a.out and coff compatible .s files. - * [89/10/16 rvb] - * - */ - - -#define S_ARG0 4(%esp) -#define S_ARG1 8(%esp) -#define S_ARG2 12(%esp) -#define S_ARG3 16(%esp) - -#define FRAME pushl %ebp; movl %esp, %ebp -#define EMARF leave - -#define B_ARG0 8(%ebp) -#define B_ARG1 12(%ebp) -#define B_ARG2 16(%ebp) -#define B_ARG3 20(%ebp) - -#define EXT(x) _##x -#define LBb(x,n) n##b -#define LBf(x,n) n##f - -#define ALIGN 2 -#define LCL(x) x - -#define LB(x,n) n - -#define SVC .byte 0x9a; .long 0; .word 0x7 -#define String .ascii -#define Value .word - -#define Times(a,b) (a*b) -#define Divide(a,b) (a/b) - -#define INB inb %dx, %al -#define OUTB outb %al, %dx -#define INL inl %dx, %eax -#define OUTL outl %eax, %dx - -#define data16 .byte 0x66 -#define addr16 .byte 0x67 - - - -#ifdef GPROF -#define MCOUNT .data; LB(x, 9): .long 0; .text; lea LBb(x, 9),%edx; call mcount -#define ENTRY(x) .globl EXT(x); .align ALIGN; EXT(x): ; \ - pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; -#define ASENTRY(x) .globl x; .align ALIGN; x: ; \ - pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; -#else /* GPROF */ -#define MCOUNT -#define ENTRY(x) .globl EXT(x); .align ALIGN; EXT(x): -#define ASENTRY(x) .globl x; .align ALIGN; x: -#endif /* GPROF */ - -#define Entry(x) .globl EXT(x); .align ALIGN; EXT(x): -#define DATA(x) .globl EXT(x); .align ALIGN; EXT(x): - diff --git a/i386/libsaio/legacy/disk.h b/i386/libsaio/legacy/disk.h deleted file mode 100644 index 02ee90e..0000000 --- a/i386/libsaio/legacy/disk.h +++ /dev/null @@ -1,137 +0,0 @@ -/* @(#)disk.h 1.0 08/29/87 (c) 1987 NeXT */ - -/* - * HISTORY - * 28-Mar-92 Doug Mitchell - * Moved disk_label struct to . - * - * 22-May-91 Gregg Kellogg (gk) at NeXT - * Split out public interface. - * - * 20-Jul-90 Doug Mitchell - * Added DKIOCSFORMAT, DKIOCGFORMAT - * - * 16-Apr-90 Doug Mitchell at NeXT - * Added DKIOCPANELPRT. - * - * 25-Mar-90 John Seamons (jks) at NeXT - * Removed obsolete DKIOCNOTIFY and DKIOCINSERT. - * - * 23-Mar-90 Doug Mitchell - * Added DKIOCEJECT. - * - * 14-Feb-90 Doug Mitchell at NeXT - * Added DKIOCMNOTIFY. - * - * 16-Mar-88 John Seamons (jks) at NeXT - * Cleaned up to support standard disk label definitions. - * - * 24-Feb-88 Mike DeMoney (mike) at NeXT - * Added defines for dl_bootfile and dl_boot0_blkno. - * Reduced NBAD to allow for these entries in disktab. - * - * 29-Aug-87 John Seamons (jks) at NeXT - * Created. - * - */ - -#ifndef _BSD_DEV_DISK_ -#define _BSD_DEV_DISK_ - -#include -#include -#include -#include -#include -#include - -#define DR_CMDSIZE 32 -#define DR_ERRSIZE 32 - -struct disk_req { - int dr_bcount; /* byte count for data transfers */ - caddr_t dr_addr; /* memory addr for data transfers */ - struct timeval dr_exec_time; /* execution time of operation */ - - /* - * interpretation of cmdblk and errblk is driver specific. - */ - char dr_cmdblk[DR_CMDSIZE]; - char dr_errblk[DR_ERRSIZE]; -}; - -struct sdc_wire { - vm_offset_t start, end; - boolean_t new_pageable; -}; - - -#define BAD_BLK_OFF 4 /* offset of bad blk tbl from label */ -#define NBAD_BLK (12 * 1024 / sizeof (int)) - -struct bad_block { /* bad block table, sized to be 12KB */ - int bad_blk[NBAD_BLK]; -}; - -/* - * sector bitmap states (2 bits per sector) - */ -#define SB_UNTESTED 0 /* must be zero */ -#define SB_BAD 1 -#define SB_WRITTEN 2 -#define SB_ERASED 3 - -struct drive_info { /* info about drive hardware */ - char di_name[MAXDNMLEN]; /* drive type name */ - int di_label_blkno[NLABELS];/* label loc'ns in DEVICE SECTORS */ - int di_devblklen; /* device sector size */ - int di_maxbcount; /* max bytes per transfer request */ -}; - -#define DS_STATSIZE 32 - -struct disk_stats { - int s_ecccnt; /* avg ECC corrections per sector */ - int s_maxecc; /* max ECC corrections observed */ - - /* - * interpretation of s_stats is driver specific - */ - char s_stats[DS_STATSIZE]; -}; - -struct drive_location { - char location[ 128 ]; -}; - -#define DKIOCGLABEL _IOR('d', 0,struct disk_label) // read label -#define DKIOCSLABEL _IOW('d', 1,struct disk_label) // write label -#define DKIOCGBITMAP _IO('d', 2) // read bitmap -#define DKIOCSBITMAP _IO('d', 3) // write bitmap -#define DKIOCREQ _IOWR('d', 4, struct disk_req) // cmd request -#define DKIOCINFO _IOR('d', 5, struct drive_info) // get drive info -#define DKIOCZSTATS _IO('d',7) // zero statistics -#define DKIOCGSTATS _IO('d', 8) // get statistics -#define DKIOCRESET _IO('d', 9) // reset disk -#define DKIOCGFLAGS _IOR('d', 11, int) // get driver flags -#define DKIOCSFLAGS _IOW('d', 12, int) // set driver flags -#define DKIOCSDCWIRE _IOW('d', 14, struct sdc_wire) // sdc wire memory -#define DKIOCSDCLOCK _IO('d', 15) // sdc lock -#define DKIOCSDCUNLOCK _IO('d', 16) // sdc unlock -#define DKIOCGFREEVOL _IOR('d', 17, int) // get free volume # -#define DKIOCGBBT _IO('d', 18) // read bad blk tbl -#define DKIOCSBBT _IO('d', 19) // write bad blk tbl -#define DKIOCMNOTIFY _IOW('d', 20, int) // message on insert -#define DKIOCEJECT _IO('d', 21) // eject disk -#define DKIOCPANELPRT _IOW('d', 22, int) // register Panel - // Request port -#define DKIOCSFORMAT _IOW('d', 23, int) // set 'Formatted' flag -#define DKIOCGFORMAT _IOR('d', 23, int) // get 'Formatted' flag -#define DKIOCBLKSIZE _IOR('d', 24, int) // device sector size -#define DKIOCNUMBLKS _IOR('d', 25, int) // number of sectors -#define DKIOCCHECKINSERT _IO('d',26) // manually poll removable - // media drive -#define DKIOCCANCELAUTOMOUNT _IOW('d',27, dev_t) // cancel automount request -#define DKIOCGLOCATION _IOR('d',28, struct drive_location) // arch dependent location descrip -#endif /* _BSD_DEV_DISK_ */ - diff --git a/i386/libsaio/legacy/fdisk.h b/i386/libsaio/legacy/fdisk.h deleted file mode 100644 index 176ab85..0000000 --- a/i386/libsaio/legacy/fdisk.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1992 NeXT Computer, Inc. - * - * IBM PC disk partitioning data structures. - * - * HISTORY - * - * 8 July 1992 David E. Bohman at NeXT - * Created. - */ - -#ifdef DRIVER_PRIVATE - -#define DISK_BLK0 0 /* blkno of boot block */ -#define DISK_BLK0SZ 512 /* size of boot block */ -#define DISK_BOOTSZ 446 /* size of boot code in boot block */ -#define DISK_SIGNATURE 0xAA55 /* signature of the boot record */ -#define FDISK_NPART 4 /* number of entries in fdisk table */ -#define FDISK_ACTIVE 0x80 /* indicator of active partition */ -#define FDISK_NEXTNAME 0xA7 /* indicator of NeXT partition */ -#define FDISK_DOS12 0x01 /* 12-bit fat < 10MB dos partition */ -#define FDISK_DOS16S 0x04 /* 16-bit fat < 32MB dos partition */ -#define FDISK_DOSEXT 0x05 /* extended dos partition */ -#define FDISK_DOS16B 0x06 /* 16-bit fat >= 32MB dos partition */ - -/* - * Format of fdisk partion entry (if present). - */ -struct fdisk_part { - unsigned char bootid; /* bootable or not */ - unsigned char beghead; /* begining head, sector, cylinder */ - unsigned char begsect; /* begcyl is a 10-bit number */ - unsigned char begcyl; /* High 2 bits are in begsect */ - unsigned char systid; /* OS type */ - unsigned char endhead; /* ending head, sector, cylinder */ - unsigned char endsect; /* endcyl is a 10-bit number */ - unsigned char endcyl; /* High 2 bits are in endsect */ - unsigned long relsect; /* partion physical offset on disk */ - unsigned long numsect; /* number of sectors in partition */ -}; - -/* - * Format of boot block. - */ -struct disk_blk0 { - unsigned char bootcode[DISK_BOOTSZ]; - unsigned char parts[FDISK_NPART][sizeof (struct fdisk_part)]; - unsigned short signature; -}; - -#endif /* DRIVER_PRIVATE */ diff --git a/i386/libsaio/libsaio.h b/i386/libsaio/libsaio.h index d56e70b..40c852c 100644 --- a/i386/libsaio/libsaio.h +++ b/i386/libsaio/libsaio.h @@ -27,8 +27,10 @@ #define __LIBSAIO_LIBSAIO_H #include "libsa.h" -#include "saio.h" +#include "memory.h" +#include "kernBootStruct.h" +#include "io_inline.h" #include "saio_types.h" #include "saio_internal.h" -#endif /* !__LIBSAIO_LIBSAIO_H */ \ No newline at end of file +#endif /* !__LIBSAIO_LIBSAIO_H */ diff --git a/i386/libsaio/load.c b/i386/libsaio/load.c index ef39734..77e6ad0 100644 --- a/i386/libsaio/load.c +++ b/i386/libsaio/load.c @@ -27,46 +27,47 @@ */ #include "libsaio.h" -#include "memory.h" -#include "kernBootStruct.h" #include "rcz_common.h" -#include +#include "rcz_decompress_file.h" #include -static int devMajor[3] = { 6, 3, 1 }; // sd, hd, fd major dev #'s +static int devMajor[3] = { 6, 3, 1 }; // sd, hd, fd major dev #'s + +static int xread(int fd, char * addr, int size); +static int loadmacho(struct mach_header * head, int dev, int io, + entry_t * rentry, char ** raddr, int * rsize, + int file_offset); //========================================================================== // Open a file for reading. If the file doesn't exist, // try opening the compressed version. #ifdef RCZ_COMPRESSED_FILE_SUPPORT -int -openfile(char *filename, int ignored) +int openfile(const char * filename, int ignored) { unsigned char *buf; int fd, size, ret; unsigned char *addr; - + if ((fd = open(filename, 0)) < 0) { - buf = malloc(256); - sprintf(buf, "%s%s", filename, RCZ_EXTENSION); - if ((fd = open(buf, 0)) >= 0) { - size = rcz_file_size(fd); - addr = (unsigned char *)((KERNEL_ADDR + KERNEL_LEN) - size); - ret = rcz_decompress_file(fd, addr); - close(fd); - if (ret < 0) - fd = -1; - else - fd = openmem(addr, size); - } - free(buf); + buf = malloc(256); + sprintf(buf, "%s%s", filename, RCZ_EXTENSION); + if ((fd = open(buf, 0)) >= 0) { + size = rcz_file_size(fd); + addr = (unsigned char *)((KERNEL_ADDR + KERNEL_LEN) - size); + ret = rcz_decompress_file(fd, addr); + close(fd); + if (ret < 0) + fd = -1; + else + fd = openmem(addr, size); + } + free(buf); } return fd; } #else -int -openfile(char *filename, int ignored) +int openfile(char * filename, int ignored) { return open(filename, 0); } @@ -75,13 +76,10 @@ openfile(char *filename, int ignored) //========================================================================== // loadprog -int -loadprog( int dev, - int fd, - struct mach_header * headOut, - entry_t * entry, /* entry point */ - char ** addr, /* load address */ - int * size ) /* size of loaded program */ +int loadprog( int dev, int fd, struct mach_header * headOut, + entry_t * entry, /* entry point */ + char ** addr, /* load address */ + int * size ) /* size of loaded program */ { struct mach_header head; int file_offset = 0; @@ -101,18 +99,18 @@ read_again: else if ( file_offset == 0 && ((head.magic == FAT_CIGAM) || (head.magic == FAT_MAGIC)) ) { - int swap = (head.magic == FAT_CIGAM) ? 1 : 0; - struct fat_header * fhp = (struct fat_header *) &head; - struct fat_arch * fap; - int i, narch = swap ? NXSwapLong(fhp->nfat_arch) : fhp->nfat_arch; - int cpu, size; - char * buf; - - size = sizeof(struct fat_arch) * narch; - buf = malloc(size); + int swap = (head.magic == FAT_CIGAM) ? 1 : 0; + struct fat_header * fhp = (struct fat_header *) &head; + struct fat_arch * fap; + int i, narch = swap ? NXSwapLong(fhp->nfat_arch) : fhp->nfat_arch; + int cpu, size; + char * buf; + + size = sizeof(struct fat_arch) * narch; + buf = malloc(size); b_lseek(fd, 0, 0); read(fd, buf, size); - + for ( i = 0, fap = (struct fat_arch *)(buf+sizeof(struct fat_header)); i < narch; i++, fap++ ) @@ -140,110 +138,103 @@ read_again: // // Read from file descriptor. addr is a physical address. -int xread( int fd, - char * addr, - int size ) +static int xread( int fd, char * addr, int size ) { - char * orgaddr = addr; - long offset; - unsigned count; - long max; + char * orgaddr = addr; + long offset; + unsigned count; + long max; #define BUFSIZ 8192 - char * buf; - int bufsize = BUFSIZ; + char * buf; + int bufsize = BUFSIZ; #if 0 printf("xread: addr=%x, size=%x\n", addr, size); sleep(1); #endif - buf = malloc(BUFSIZ); - - // align your read to increase speed - offset = tell(fd) & 4095; - if ( offset != 0 ) - max = 4096 - offset; - else - max = bufsize; - - while ( size > 0 ) - { - if ( size > max ) count = max; - else count = size; + buf = malloc(BUFSIZ); + + // align your read to increase speed + offset = tell(fd) & 4095; + if ( offset != 0 ) + max = 4096 - offset; + else + max = bufsize; + + while ( size > 0 ) + { + if ( size > max ) count = max; + else count = size; #if 0 - printf("xread: loop size=%x, count=%x\n", size, count); - sleep(1); + printf("xread: loop size=%x, count=%x\n", size, count); + sleep(1); #endif - if ( read(fd, buf, count) != count) break; + if ( read(fd, buf, count) != count) break; - bcopy(buf, ptov(addr), count); - size -= count; - addr += count; + bcopy(buf, ptov(addr), count); + size -= count; + addr += count; - max = bufsize; + max = bufsize; #if 0 - tick += count; - if ( tick > (50*1024) ) - { - putchar('+'); - tick = 0; - } + tick += count; + if ( tick > (50*1024) ) + { + putchar('+'); + tick = 0; + } #endif - } + } - free(buf); - return addr-orgaddr; + free(buf); + return addr-orgaddr; } //========================================================================== // loadmacho -int -loadmacho( struct mach_header * head, - int dev, - int io, - entry_t * rentry, - char ** raddr, - int * rsize, - int file_offset ) +static int loadmacho( struct mach_header * head, int dev, int io, + entry_t * rentry, char ** raddr, int * rsize, + int file_offset ) { - int ncmds; - void * cmds; + int ncmds; + void * cmds; void * cp; - unsigned int entry = 0; - int vmsize = 0; - unsigned int vmaddr = ~0; + unsigned int entry = 0; + int vmsize = 0; + unsigned int vmaddr = ~0; unsigned int vmend = 0; - struct xxx_thread_command { - unsigned long cmd; - unsigned long cmdsize; - unsigned long flavor; - unsigned long count; - i386_thread_state_t state; - } * th; + struct xxx_thread_command { + unsigned long cmd; + unsigned long cmdsize; + unsigned long flavor; + unsigned long count; + i386_thread_state_t state; + } * th; - // XXX should check cputype - cmds = malloc(head->sizeofcmds); - b_lseek(io, sizeof(struct mach_header) + file_offset, 0); + // XXX should check cputype + cmds = malloc(head->sizeofcmds); + b_lseek(io, sizeof(struct mach_header) + file_offset, 0); - if ( read(io, (char *) cmds, head->sizeofcmds) != head->sizeofcmds ) + if ( read(io, (char *) cmds, head->sizeofcmds) != head->sizeofcmds ) { - error("loadmacho: error reading commands\n"); - goto shread; - } + error("loadmacho: error reading commands\n"); + goto shread; + } - for ( ncmds = head->ncmds, cp = cmds; ncmds > 0; ncmds-- ) - { - unsigned int addr; + for ( ncmds = head->ncmds, cp = cmds; ncmds > 0; ncmds-- ) + { + unsigned int addr; -#define lcp ((struct load_command *) cp) -#define scp ((struct segment_command *) cp) +#define lcp ((struct load_command *) cp) +#define scp ((struct segment_command *) cp) - switch ( lcp->cmd ) - { + switch ( lcp->cmd ) + { case LC_SEGMENT: addr = (scp->vmaddr & 0x3fffffff) + (int)*raddr; if ( scp->filesize ) @@ -260,7 +251,7 @@ loadmacho( struct mach_header * head, // FIXME: check to see if we overflow // the available space (should be passed in // as the size argument). - + #if 0 printf("LC: fileoff %x, filesize %x, off %x, addr %x\n", scp->fileoff, scp->filesize, file_offset, addr); @@ -282,21 +273,21 @@ loadmacho( struct mach_header * head, th = (struct xxx_thread_command *) cp; entry = th->state.eip; break; - } - cp += lcp->cmdsize; - } + } + cp += lcp->cmdsize; + } - kernBootStruct->rootdev = (dev & 0xffffff00) | devMajor[Dev(dev)]; + kernBootStruct->rootdev = (dev & 0xffffff00) | devMajor[B_TYPE(dev)]; - free(cmds); + free(cmds); - *rentry = (entry_t)( (int) entry & 0x3fffffff ); - *rsize = vmend - vmaddr; - *raddr = (char *)vmaddr; + *rentry = (entry_t)( (int) entry & 0x3fffffff ); + *rsize = vmend - vmaddr; + *raddr = (char *)vmaddr; - return 0; + return 0; shread: - free(cmds); - return -1; + free(cmds); + return -1; } diff --git a/i386/libsaio/misc.c b/i386/libsaio/misc.c index ed9703f..1336ee6 100644 --- a/i386/libsaio/misc.c +++ b/i386/libsaio/misc.c @@ -44,7 +44,6 @@ * All rights reserved. */ -#include "io_inline.h" #include "libsaio.h" /* @@ -74,48 +73,54 @@ void enableA20() { - /* make sure that the input buffer is empty */ - while (inb(PORT_B) & KB_INFULL); + /* make sure that the input buffer is empty */ + while (inb(PORT_B) & KB_INFULL); - /* make sure that the output buffer is empty */ - if (inb(PORT_B) & KB_OUTFULL) - (void)inb(PORT_A); + /* make sure that the output buffer is empty */ + if (inb(PORT_B) & KB_OUTFULL) + (void)inb(PORT_A); - /* make sure that the input buffer is empty */ - while (inb(PORT_B) & KB_INFULL); + /* make sure that the input buffer is empty */ + while (inb(PORT_B) & KB_INFULL); - /* write output port */ - outb(PORT_B, CMD_WOUT); + /* write output port */ + outb(PORT_B, CMD_WOUT); - /* wait until command is accepted */ - while (inb(PORT_B) & KB_INFULL); + /* wait until command is accepted */ + while (inb(PORT_B) & KB_INFULL); - outb(PORT_A, KB_A20); + outb(PORT_A, KB_A20); - while (inb(PORT_B) & KB_INFULL); /* wait until done */ + while (inb(PORT_B) & KB_INFULL); /* wait until done */ } void sleep(int n) { - int endtime = (time18() + 18*n); - while (time18() < endtime); + int endtime = (time18() + 18*n); + while (time18() < endtime); } void turnOffFloppy(void) { - /* - * Disable floppy: - * Hold controller in reset, - * disable DMA and IRQ, - * turn off floppy motors. - */ - outb(0x3F2, 0x00); + /* + * Disable floppy: + * Hold controller in reset, + * disable DMA and IRQ, + * turn off floppy motors. + */ + outb(0x3F2, 0x00); } -char * newString(char * oldString) +char * newString(const char * oldString) { if ( oldString ) return strcpy(malloc(strlen(oldString)+1), oldString); else return NULL; } + +void stop(const char * msg) +{ + error("\n%s\n", msg); + halt(); +} diff --git a/i386/libsaio/nbp.c b/i386/libsaio/nbp.c index 3cfe1a2..bb35897 100644 --- a/i386/libsaio/nbp.c +++ b/i386/libsaio/nbp.c @@ -23,7 +23,11 @@ */ #include "libsaio.h" -#include "nbp.h" + +/* + * Convert zero-based linear address to far pointer. + */ +#define GET_FP(x) ( (((x) & 0xffff0000) << (16 - 4)) | ((x) & 0xffff) ) /*========================================================================== * Issue a command to the network loader. @@ -32,8 +36,7 @@ * ensure that it resides within the addressable range for the * network loader, which runs in real mode. */ -UInt32 -nbp(nbpCommandCode_t code, nbpCommand_u * cmd) +static UInt32 nbp(nbpCommandCode_t code, nbpCommand_u * cmd) { loader(code, GET_FP((UInt32) cmd)); @@ -46,33 +49,70 @@ nbp(nbpCommandCode_t code, nbpCommand_u * cmd) } /*========================================================================== - * Execute a TFTP Read File command. - * + * Unload Base Code Stack command. + */ +UInt32 nbpUnloadBaseCode() +{ + return nbp(nbpCommandUnloadBaseCode, (nbpCommand_u *) 0); +} + +/*========================================================================== + * TFTP Read File command. */ -UInt32 nbpTFTPReadFile(UInt8 * filename, // name of the file - UInt32 * bufferSize, // [IN] size limit, [OUT} real size - UInt32 bufferAddr) // physical address +static long NBPLoadFile(CICell ih, char * filePath) { nbpCommandTFTPReadFile_s cmd; UInt32 ret; - strcpy(cmd.filename, filename); + strcpy(cmd.filename, filePath); cmd.status = nbpStatusFailed; - cmd.bufferSize = *bufferSize; - cmd.buffer = bufferAddr; + cmd.bufferSize = TFTP_LEN; + cmd.buffer = TFTP_ADDR; - ret = nbp(nbpCommandTFTPReadFile, (nbpCommand_u *) &cmd); + verbose("Loading file: %s\n", filePath); - *bufferSize = cmd.bufferSize; // bytes transferred + ret = nbp(nbpCommandTFTPReadFile, (nbpCommand_u *) &cmd); - return ret; + return (ret == nbpStatusSuccess) ? cmd.bufferSize : -1; } /*========================================================================== - * Execute an Unload Base Code Stack command. - * + * GetDirEntry is not supported. */ -UInt32 nbpUnloadBaseCode() +static long NBPGetDirEntry(CICell ih, char * dirPath, long * dirIndex, + char ** name, long * flags, long * time) { - return nbp(nbpCommandUnloadBaseCode, (nbpCommand_u *) 0); + return -1; +} + +//========================================================================== + +static void NBPGetDescription(CICell ih, char * str, long strMaxLen) +{ + sprintf( str, "Ethernet PXE Client" ); +} + +//========================================================================== + +BVRef nbpScanBootVolumes( int biosdev, int * countPtr ) +{ + static BVRef gNetBVR = NULL; + + if ( countPtr ) *countPtr = 1; + + if ( !gNetBVR ) + { + gNetBVR = malloc( sizeof(*gNetBVR) ); + if ( gNetBVR ) + { + bzero(gNetBVR, sizeof(*gNetBVR)); + gNetBVR->biosdev = biosdev; + gNetBVR->flags = kBVFlagPrimary | kBVFlagNativeBoot; + gNetBVR->description = NBPGetDescription; + gNetBVR->fs_loadfile = NBPLoadFile; + gNetBVR->fs_getdirentry = NBPGetDirEntry; + } + } + + return gNetBVR; } diff --git a/i386/libsaio/nbp.h b/i386/libsaio/nbp.h deleted file mode 100644 index 63ad268..0000000 --- a/i386/libsaio/nbp.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#ifndef __LIBSAIO_NBP_H -#define __LIBSAIO_NBP_H - -#include "nbp_cmd.h" - -/*========================================================================== - * Call the network loader's exported entry point. - * Function is in asm.s. - */ -extern void loader(UInt32 code, UInt32 cmdptr); - -/*========================================================================== - * Convert zero-based linear address to far pointer. - */ -#define GET_FP(x) ( (((x) & 0xffff0000) << (16 - 4)) | \ - ((x) & 0xffff) ) - -/*========================================================================== - * Issue a command to the network loader. - */ -extern UInt32 nbp(nbpCommandCode_t code, nbpCommand_u * cmd); - -/*========================================================================== - * Execute a TFTP Read File command. - */ -extern UInt32 nbpTFTPReadFile(UInt8 * filename, - UInt32 * bufferSize, - UInt32 bufferAddr); - -/*========================================================================== - * Execute an Unload Base Code Stack command. - */ -extern UInt32 nbpUnloadBaseCode(); - -#endif /* !__LIBSAIO_NBP_H */ diff --git a/i386/libsaio/old/bios_old.s b/i386/libsaio/old/bios_old.s deleted file mode 100644 index 52af82e..0000000 --- a/i386/libsaio/old/bios_old.s +++ /dev/null @@ -1,610 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Mach Operating System - * Copyright (c) 1990 Carnegie-Mellon University - * Copyright (c) 1989 Carnegie-Mellon University - * All rights reserved. The CMU software License Agreement specifies - * the terms and conditions for use and redistribution. - */ - -// INTEL CORPORATION PROPRIETARY INFORMATION -// -// This software is supplied under the terms of a license agreement or -// nondisclosure agreement with Intel Corporation and may not be copied -// nor disclosed except in accordance with the terms of that agreement. -// -// Copyright 1988 Intel Corporation -// Copyright 1988, 1989 by Intel Corporation -// - - .file "bios.s" - -#include -#include "memory.h" - - .text - -#if 0 -// biosread(dev, cyl, head, sec, num) -// Read num sectors from disk into the internal buffer "intbuf" which -// is the first 4K bytes of the boot loader. -// BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory -// Call with %ah = 0x2 -// %al = number of sectors -// %ch = cylinder -// %cl = sector -// %dh = head -// %dl = drive (0x80 for hard disk, 0x0 for floppy disk) -// %es:%bx = segment:offset of buffer -// Return: -// %al = 0x0 on success; err code on failure - -ENTRY(_biosread) - push %ebp - mov %esp, %ebp - - push %ebx - push %ecx - push %edx - push %esi - push %edi - push %ds - push %es -// push %fs -// push %gs - - movb 0x10(%ebp), %dh // head - - movw 0x0c(%ebp), %cx - xchgb %ch, %cl // cylinder; %cl=the high 2 bits of cyl - rorb $2, %cl - movb 0x14(%ebp), %al - orb %al, %cl - incb %cl // sector; sec starts from 1, not 0 - - movb 0x8(%ebp), %dl // device - movb 0x18(%ebp),%bl // number of sectors - movb $2,%bh // bios read function - - call EXT(_prot_to_real) // enter real mode, set %es to BOOTSEG - - data16 - mov $5,%edi // retry up to 5 times - -retry_disc: - mov %ebx,%eax // get function and amount -// xor %ebx, %ebx // offset = 0 - data16 - mov $(ptov(BIOS_ADDR)), %ebx - - push %eax // save amount - push %ecx - push %edx - push %edi - int $0x13 - pop %edi - pop %edx - pop %ecx - pop %ebx // pop amount into bx (safe place) - -// test $0, %ah - data16 - jnb read_succes - - // woops, bios failed to read sector - push %eax // save error - xor %eax,%eax - int $0x13 // reset disk - pop %eax // restore error code - dec %edi - data16 - jne retry_disc - -read_succes: - mov %eax, %ebx // save return value - - data16 - call EXT(_real_to_prot) // back to protected mode - - xor %ax, %ax - movb %bh, %al // return value in %ax - -// pop %gs -// pop %fs - pop %es - pop %ds - pop %edi - pop %esi - pop %edx - pop %ecx - pop %ebx - - pop %ebp - - ret - -// putc(ch) -// BIOS call "INT 10H Function 0Eh" to write character to console -// Call with %ah = 0x0e -// %al = character -// %bh = page -// %bl = foreground color ( graphics modes) - - -ENTRY(_putc) - push %ebp - mov %esp, %ebp - - push %ebx - push %ecx - push %edx - push %esi - push %edi - push %ds - push %es - - movb 0x8(%ebp), %cl - - call EXT(_prot_to_real) - -// data16 -// mov $0x13, %ebx // colors in 2 bit palette, grey and white -// mov $0x1, %ebx // %bh=0, %bl=1 (blue) -// -// movb $1,%bh // background gray - movb $0,%bh // background gray - movb $3,%bl // foreground white in 2 bit palette - - movb $0xe, %ah - movb %cl, %al - - int $0x10 // display a byte - - data16 - call EXT(_real_to_prot) - - pop %es - pop %ds - pop %edi - pop %esi - pop %edx - pop %ecx - pop %ebx - - pop %ebp - ret - -ENTRY(cputc) - push %ebp - mov %esp, %ebp - - push %ebx - push %ecx - push %edx - push %esi - push %edi - push %ds - push %es - - movb 0x8(%ebp), %cl - movb 0x12(%ebp), %bl - - call EXT(_prot_to_real) - - movb $0,%bh // page 0 - - movb %cl, %al - movb $0x9, %ah - movb $1, %cx - - int $0x10 // display a byte - - data16 - call EXT(_real_to_prot) - - pop %es - pop %ds - pop %edi - pop %esi - pop %edx - pop %ecx - pop %ebx - - pop %ebp - ret - -// bgetc() -// BIOS call "INT 16H Function 00H" to read character from keyboard -// Call with %ah = 0x0 -// Return: %ah = keyboard scan code -// %al = ASCII character - -ENTRY(bgetc) - push %ebp - mov %esp, %ebp - - push %ebx - push %ecx - push %edx - push %esi - push %edi - push %ds - push %es - - call EXT(_prot_to_real) - - movb $0, %ah - - int $0x16 - - mov %eax, %ebx // _real_to_prot uses %eax - - data16 - call EXT(_real_to_prot) - - xor %eax, %eax - mov %bx, %ax - - pop %es - pop %ds - pop %edi - pop %esi - pop %edx - pop %ecx - pop %ebx - - pop %ebp - ret - -// readKeyboardStatus() -// if there is a character pending, return it; otherwise return 0 -// BIOS call "INT 16H Function 01H" to check whether a character is pending -// Call with %ah = 0x1 -// Return: -// If key waiting to be input: -// %ah = keyboard scan code -// %al = ASCII character -// Zero flag = clear -// else -// Zero flag = set - -ENTRY(_readKeyboardStatus) - push %ebp - mov %esp, %ebp - - push %ebx - push %ecx - push %edx - push %esi - push %edi - push %ds - push %es - - call EXT(_prot_to_real) // enter real mode - - xor %ebx, %ebx - movb $0x1, %ah - int $0x16 - - data16 - jz nochar - - movw %ax, %bx - -nochar: - data16 - call EXT(_real_to_prot) - - xor %eax, %eax - movw %bx, %ax - - pop %es - pop %ds - pop %edi - pop %esi - pop %edx - pop %ecx - pop %ebx - - pop %ebp - ret - - -// time in 18ths of a second -ENTRY(_time18) - push %ebp - mov %esp, %ebp - - push %ebx - push %ecx - push %edx - push %esi - push %edi - push %ds - push %es - - call EXT(_prot_to_real) // enter real mode - - xor %bx, %bx - xor %eax, %eax - int $0x1a - - mov %edx,%ebx - shl $16,%cx // shifts ecx - or %cx,%bx // %ebx has 32 bit time - - data16 - call EXT(_real_to_prot) - - mov %ebx,%eax - - pop %es - pop %ds - pop %edi - pop %esi - pop %edx - pop %ecx - pop %ebx - - pop %ebp - ret - -// -// get_diskinfo(): return a word that represents the -// max number of sectors and heads and drives for this device -// - -ENTRY(_get_diskinfo) - push %ebp - mov %esp, %ebp - - push %ebx - push %ecx - push %edx - push %esi - push %edi - push %ds - push %es - - movb 0x8(%ebp), %dl // diskinfo(drive #) - call EXT(_prot_to_real) // enter real mode - - movb $0x8, %ah // ask for disk info - int $0x13 - - data16 - call EXT(_real_to_prot) // back to protected mode - -// form a longword representing all this gunk - mov %ecx, %eax - shrb $6, %al - andb $0x03, %al - xchgb %ah, %al // ax has max cyl - shl $16, %eax - - movb %dh, %ah // # heads - andb $0x3f, %cl // mask of cylinder gunk - movb %cl, %al // # sectors - - pop %es - pop %ds - pop %edi - pop %esi - pop %edx - pop %ecx - pop %ebx - - pop %ebp - ret -#endif -#if 0 -// -// getEisaInfo(): return an int that represents the -// vendor id for the specified slot (0 < slot < 64) -// returns 0 for any error -// returns bytes in the order [0 1 2 3] in %eax; - -ENTRY(getEisaInfo) - push %ebp - mov %esp, %ebp - - push %ebx - push %ecx - push %edx - push %esi - push %edi - push %ds - push %es - - movb 0x8(%ebp), %cl // slot # - call EXT(_prot_to_real) // enter real mode - - movb $0,%al - movb $0xd8, %ah // eisa slot info - int $0x15 - - data16 - call EXT(_real_to_prot) // back to protected mode - - movb %ah,%bl - xor %eax,%eax - - test $0,%bl - jne eisaerr - -// form a longword representing all this gunk - mov %esi, %eax - shl $16, %eax - mov %di,%ax - bswap %eax - -eisaerr: - pop %es - pop %ds - pop %edi - pop %esi - pop %edx - pop %ecx - pop %ebx - - pop %ebp - ret -#endif - -#if 0 -// -// memsize(i) : return the memory size in KB. i == 0 for conventional memory, -// i == 1 for extended memory -// BIOS call "INT 12H" to get conventional memory size -// BIOS call "INT 15H, AH=88H" to get extended memory size -// Both have the return value in AX. -// - -ENTRY(_memsize) - push %ebp - mov %esp, %ebp - - push %ebx - push %ecx - push %edx - push %esi - push %edi - push %ds - push %es - - mov 8(%ebp), %ebx - call EXT(_prot_to_real) // enter real mode - cmpb $0x1, %bl - data16 - je xext - int $0x12 - data16 - jmp xdone -xext: - movb $0x88, %ah - int $0x15 -xdone: - mov %eax, %ebx - data16 - call EXT(_real_to_prot) - xor %eax, %eax - mov %ebx, %eax - - pop %es - pop %ds - pop %edi - pop %esi - pop %edx - pop %ecx - pop %ebx - - pop %ebp - ret - - -// video_mode(mode) -// BIOS call "INT 10H Function 0h" to set vga graphics mode - - -ENTRY(_video_mode) - push %ebp - mov %esp, %ebp - - push %ebx - push %ecx - push %edx - push %esi - push %edi - push %ds - push %es - - movb 0x8(%ebp), %cl - - call EXT(_prot_to_real) - - movb $0, %ah - movb %cl, %al - - int $0x10 // display a byte - - data16 - call EXT(_real_to_prot) - - pop %es - pop %ds - pop %edi - pop %esi - pop %edx - pop %ecx - pop %ebx - - pop %ebp - ret - - - -// setCursorPosition(x,y) -// BIOS call "INT 10H Function 2" to set cursor position - - -ENTRY(_setCursorPosition) - push %ebp - mov %esp, %ebp - - push %ebx - push %ecx - push %edx - push %esi - push %edi - push %ds - push %es - - movb 0x8(%ebp), %cl - movb 0xc(%ebp), %ch - - call EXT(_prot_to_real) - - movb $2, %ah // setcursor function - movb $0, %bh // page num 0 for graphics - movb %cl, %dl // column, x - movb %ch, %dh // row, y - - int $0x10 // set cursor - - data16 - call EXT(_real_to_prot) - - pop %es - pop %ds - pop %edi - pop %esi - pop %edx - pop %ecx - pop %ebx - - pop %ebp - ret -#endif - diff --git a/i386/libsaio/old/shmalloc.c b/i386/libsaio/old/shmalloc.c deleted file mode 100644 index 09b136b..0000000 --- a/i386/libsaio/old/shmalloc.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#import "libsa.h" -#import "libsaio.h" - -void *sh_malloc(size_t size) {return malloc(size);} -void sh_free(void *start) { free(start); } -void *sh_realloc(void *ptr, size_t size) {return realloc(ptr,size);} diff --git a/i386/libsaio/old/stringTable.h.00 b/i386/libsaio/old/stringTable.h.00 deleted file mode 100644 index bdb7441..0000000 --- a/i386/libsaio/old/stringTable.h.00 +++ /dev/null @@ -1,52 +0,0 @@ -/* - * string table functions. - */ - -#import "saio_types.h" - -extern char * -newStringFromList( - char **list, - int *size -); -extern int stringLength(char *table, int compress); -extern BOOL getValueForStringTableKey(char *table, char *key, char **val, int *size); -extern char *newStringForStringTableKey( - char *table, - char *key -); -extern BOOL getValueForBootKey(char *line, char *match, char **matchval, int *len); -extern BOOL getValueForKey( - char *key, - char **val, - int *size -); -extern char * -loadLocalizableStrings( - char *name -); -extern char * -bundleLongName( - char *bundleName -); -extern loadConfigFile( char *configFile, char **table, int allocTable); -extern int -loadConfigDir( - char *bundleName, // bundle directory name (e.g. "System.config") - int useDefault, // use Default.table instead of instance tables - char **table, // returns pointer to config table - int allocTable // zalloc the table and return in *table -); -extern loadSystemConfig( - char *which, - int size -); -extern int -loadOtherConfigs( - int useDefault -); - - - - - diff --git a/i386/libsaio/old/stringTableNew.c b/i386/libsaio/old/stringTableNew.c deleted file mode 100644 index cd2664a..0000000 --- a/i386/libsaio/old/stringTableNew.c +++ /dev/null @@ -1,564 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright 1993 NeXT, Inc. - * All rights reserved. - */ - -#import "libsaio.h" -#import "kernBootStruct.h" -#import "stringConstants.h" -#import - -extern KERNBOOTSTRUCT *kernBootStruct; -extern char *Language; -extern char *LoadableFamilies; - - -static char_ret -getachar( - char **string_p -) -{ - register char *str = *string_p; - register int c; - char_ret r; - - c = *str++; - if (c == '\\') { - r.quoted = YES; - c = *str++; - switch(c) { - case 'n': - c = '\n'; - break; - case 'r': - c = '\r'; - break; - case 't': - c = '\t'; - break; - default: - break; - } - } else { - r.quoted = NO; - } - *string_p = str; - r.c = c; - return r; -} - -/* - * A token is: - * * - * "*" - * - */ -char * -get_token( - char **string_p -) -{ - char *begin; - char *newstr; - char_ret r; - int len; - - do { - r = getachar(string_p); - } while (r.c && isspace(r.c)); - - if (!r.quoted && r.c == '\"') { - begin = *string_p; - do { - r = getachar(string_p); - } while (r.c && !r.quoted && r.c != '\"'); - } else { - begin = *string_p - 1; - do { - r = getachar(string_p); - } while (r.c && !r.quoted && r.c != ';' && !isspace(r.c)); - } - len = *string_p - begin - 1; - newstr = (char *)malloc(len + 1); - strncpy(newstr, begin, len); - newstr[len] = '\0'; - return newstr; -} - - -char * -stringFromList( - char **list, - int *size -) -{ - char *begin = *list, *end; - char *newstr; - int newsize = *size; - - while (*begin && newsize && isspace(*begin)) { - begin++; - newsize--; - } - end = begin; - while (*end && newsize && !isspace(*end)) { - end++; - newsize--; - } - if (begin == end) - return 0; - newstr = malloc(end - begin + 1); - strncpy(newstr, begin, end - begin); - *list = end; - *size = newsize; - return newstr; -} - -char * -valueForStringTableKey( - char *table, - char *key -) -{ - char *token; - enum { - KEY, - EQUALS, - VALUE, - SEMICOLON, - BEGINCOMMENT, - ENDCOMMENT - } state; - BOOL foundKey; - int len; - - state = KEY; - foundKey = NO; - while (*table) { - token = get_token(&table); - switch(state) { - case KEY: - if (strcmp(token, key) == 0) - foundKey = YES; - if (strncmp(token, "/*", 2) == 0) - state = ENDCOMMENT; - else - state = EQUALS; - break; - case EQUALS: - if (strcmp(token, "=") == 0) { - state = VALUE; - } - break; - case VALUE: - if (foundKey) { - return token; - } - state = SEMICOLON; - break; - case SEMICOLON: - if (strcmp(token, ";") == 0) { - state = KEY; - } - break; - case ENDCOMMENT: - len = strlen(token); - if (len >= 2 && strncmp(token + len - 2, "*/", 2) == 0) - state = KEY; - break; - } - free(token); - } - return 0; -} - -char * -valueForBootKey( - char *line, - char *match -) -{ - char *token; - enum { - KEY, - EQUALS, - VALUE, - WHITESPACE - } state; - BOOL foundKey; - int len; - - state = KEY; - while (*line) { - token = get_token(&line); - } -} - -BOOL -boolForKey( - char *key -) -{ - char *str = valueForKey(key); - BOOL ret; - - if (str && (str[0] == 'Y' || str[1] == 'y')) - ret = YES; - else - ret = NO; - free(str); - return ret; -} - -BOOL -getIntForKey( - char *key, - int *value -) -{ - char *str = valueForKey(key), *ptr = str; - int sum; - BOOL ret; - - if (str) { - for (sum = 0; size > 0; size--) { - sum = (sum * 10) + (*ptr++ - '0'); - } - *value = sum; - ret = YES; - } else { - ret = NO; - } - free(str); - return ret; -} - -char * -valueForKey( - char *key -) -{ - char *str = valueForBootKey(kernBootStruct->bootString, key);; - - if (str) - return str; - else - return valueForStringTableKey(kernBootStruct->config, key); -} - -#define LOCALIZABLE_PATH \ - "%s/%s.config/%s.lproj/%s.strings" -char * -loadLocalizableStrings( - char *name, - char *tableName -) -{ - char buf[256], *config; - register int i, count, fd = -1; - char * paths[] = { - ARCH_DEVICES, - USR_DEVICES, - "/", - NULL - }, **path; - - for (i=0; i<2; i++) { - for (path = paths; *path; path++) { - sprintf(buf, LOCALIZABLE_PATH, *path, name, - (i == 0) ? Language : "English", tableName); - if ((fd = open(buf, 0)) >= 0) { - i = 2; - break; - } - } - } - if (fd < 0) - return 0; - count = file_size(fd); - config = malloc(count); - count = read(fd, config, count); - close(fd); - if (count <= 0) { - free(config); - return 0; - } - return config; -} - -char * -bundleLongName( - char *bundleName, - char *tableName -) -{ - char *table, *name, *val; - int size; - - table = loadLocalizableStrings(bundleName, - tableName ? tableName : "Localizable"); - if ( table != 0 && - getValueForStringTableKey(table,"Long Name", &val, &size) == YES) { - name = malloc(size+1); - strncpy(name, val, size); - free(table); - } else { - name = newString(bundleName); - } - return name; -} - -int sysConfigValid; - -void -addConfig( - char *config -) -{ - char *configPtr = kernBootStruct->configEnd; - int len = strlen(config); - - if ((configPtr - kernBootStruct->config) > CONFIG_SIZE) { - error("No room in memory for config files\n"); - return; - } - strcpy(configPtr, config); - configPtr += (len + 1); - *configPtr = 0; - kernBootStruct->configEnd = configPtr; -} - -/* - * Returns 0 if file loaded OK, - * -1 if file was not loaded - * Does not print error messages. - * Returns pointer to table in memory in *table. - */ -int -loadConfigFile( char *configFile, char **table, BOOL allocTable) -{ - char *configPtr = kernBootStruct->configEnd; - int fd, count; - - /* Read config file into memory */ - if ((fd = open(configFile, 0)) >= 0) - { - if (allocTable) { - configPtr = malloc(file_size(fd)+2); - } else { - if ((configPtr - kernBootStruct->config) > CONFIG_SIZE) { - error("No room in memory for config files\n"); - close(fd); - return -1; - } - verbose("Reading configuration file '%s'.\n",configFile); - } - if (table) *table = configPtr; - count = read(fd, configPtr, IO_CONFIG_DATA_SIZE); - close(fd); - - configPtr += count; - *configPtr++ = 0; - *configPtr = 0; - if (!allocTable) - kernBootStruct->configEnd = configPtr; - - return 0; - } else { - return -1; - } -} - -/* Returns 0 if requested config files were loaded, - * 1 if default files were loaded, - * -1 if no files were loaded. - * Prints error message if files cannot be loaded. - */ - -int -loadConfigDir( - char *bundleName, // bundle directory name (e.g. "System") - BOOL useDefault, // use Default.table instead of instance tables - char **table, // returns pointer to config table - BOOL allocTable // malloc the table and return in *table -) -{ - char *buf; - int i, ret; - BOOL archConfig = dirExists(ARCH_DEVICES); - - buf = malloc(256); - ret = 0; - - // load up to 99 instance tables - for (i=0; i < 99; i++) { - sprintf(buf, "%s/%s.config/Instance%d.table", - archConfig ? ARCH_DEVICES : USR_DEVICES, - bundleName, i); - if (useDefault || (loadConfigFile(buf, table, allocTable) != 0)) { - if (i == 0) { - // couldn't load first instance table; - // try the default table - sprintf(buf, "%s/%s.config/%s", - archConfig ? ARCH_DEVICES : USR_DEVICES, - bundleName, - IO_DEFAULT_TABLE_FILENAME); - if (loadConfigFile(buf, table, allocTable) == 0) { - ret = 1; - } else { - if (!allocTable) - error("Config file \"%s\" not found\n", buf); - ret = -1; - } - } - // we must be done. - break; - } - } - free(buf); - return ret; -} - - -#define USR_SYSTEM_CONFIG \ - USR_DEVICES "/System.config" -#define USR_SYSTEM_DEFAULT_FILE \ - USR_SYSTEM_CONFIG "/Default.table" -#define ARCH_SYSTEM_CONFIG \ - ARCH_DEVICES "/System.config" -#define ARCH_SYSTEM_DEFAULT_FILE \ - ARCH_SYSTEM_CONFIG "/Default.table" -#define SYSTEM_CONFIG "System" -#define LP '(' -#define RP ')' - -/* Returns 0 if requested config files were loaded, - * 1 if default files were loaded, - * -1 if no files were loaded. - * Prints error message if files cannot be loaded. - */ -int -loadSystemConfig( - char *which, - int size -) -{ - char *buf, *bp, *cp; - int ret, len, doDefault=0; - BOOL archConfig = dirExists(ARCH_DEVICES); - - buf = bp = malloc(256); - if (which && size) - { - for(cp = which, len = size; len && *cp && *cp != LP; cp++, len--) ; - if (*cp == LP) { - while (len-- && *cp && *cp++ != RP) ; - /* cp now points past device */ - strncpy(buf,which,cp - which); - bp += cp - which; - } else { - cp = which; - len = size; - } - if (*cp != '/') { - strcpy(bp, archConfig ? - ARCH_SYSTEM_CONFIG : USR_SYSTEM_CONFIG); - strcat(bp, "/"); - strncat(bp, cp, len); - if (strncmp(cp + len - strlen(IO_TABLE_EXTENSION), - IO_TABLE_EXTENSION, strlen(IO_TABLE_EXTENSION)) != 0) - strcat(bp, IO_TABLE_EXTENSION); - } else { - strncpy(bp, cp, len); - bp[size] = '\0'; - } - if ((strcmp(bp, USR_SYSTEM_DEFAULT_FILE) == 0) || - (strcmp(bp, ARCH_SYSTEM_DEFAULT_FILE) == 0)) - doDefault = 1; - ret = loadConfigFile(bp = buf, 0, 0); - } else { - ret = loadConfigDir((bp = SYSTEM_CONFIG), 0, 0, 0); - } - if (ret < 0) { - error("System config file '%s' not found\n", bp); - } else - sysConfigValid = 1; - free(buf); - return (ret < 0 ? ret : doDefault); -} - - -int -loadOtherConfigs( - int useDefault -) -{ - char *val, *table; - int count; - char *string; - int fd, ret; - - if (getValueForKey( "Boot Drivers", &val, &count)) - { - while (string = stringFromList(&val, &count)) { - ret = loadConfigDir(string, useDefault, &table, 0); - if (ret >= 0) { - if ((fd = openDriverReloc(string)) >= 0) { - verbose("Loading binary for %s device driver.\n",string); - if (loadDriver(string, fd) < 0) - error("Error loading %s device driver.\n",string); - close(fd); - } - driverWasLoaded(string, table, NULL); - free(string); - } else { - driverIsMissing(string); - } - } - } else { - error("Warning: No active drivers specified in system config.\n"); - } - - kernBootStruct->first_addr0 = - (int)kernBootStruct->configEnd + 1024; - return 0; -} - -static BOOL -dirExists(char *path) -{ - int fd; - - if ((fd = open(path, 0)) < 0) { - return NO; - } else { - close(fd); - return YES; - } -} - - - diff --git a/i386/libsaio/pci.c b/i386/libsaio/pci.c index 7fd0542..1650bb6 100644 --- a/i386/libsaio/pci.c +++ b/i386/libsaio/pci.c @@ -32,13 +32,7 @@ * Created */ -#include -// #include "legacy/KernDevice.h" -#include "legacy/PCI.h" - -#include "kernBootStruct.h" #include "libsaio.h" -#include "io_inline.h" #include "pci.h" static BOOL testMethod1(void); @@ -76,7 +70,6 @@ PCI_Bus_Init( PCI_bus_info_t *info /* pass in the PCI boot info struct */ ) { - unsigned int maxBusNum = 0, maxDevNum = 0, useMethod = 0; _pci_bus_method_t method = NULL; _pci_slot_info_t *slot_array; @@ -104,14 +97,13 @@ PCI_Bus_Init( } } - if (useMethod == 1) method = getMethod1; else if (useMethod == 2) method = getMethod2; else return NULL; - + nslots = scanBus(maxBusNum, maxDevNum, method, NULL); slot_array = (_pci_slot_info_t *) malloc(sizeof(_pci_slot_info_t) * nslots +1); diff --git a/i386/libsaio/pci.h b/i386/libsaio/pci.h index 5a334bf..d1fde1a 100644 --- a/i386/libsaio/pci.h +++ b/i386/libsaio/pci.h @@ -38,4 +38,48 @@ typedef struct _pci_slot_info { extern _pci_slot_info_t *PCISlotInfo; +/* The IOPCIConfigSpace structure can be used to decode the 256 byte + * configuration space presented by each PCI device. This structure + * is based on the PCI LOCAL BUS SPECIFICATION, rev 2.1, section 6.1 + */ + +typedef struct _IOPCIConfigSpace { + unsigned short VendorID; + unsigned short DeviceID; + unsigned short Command; + unsigned short Status; + unsigned long RevisionID:8; + unsigned long ClassCode:24; + unsigned char CacheLineSize; + unsigned char LatencyTimer; + unsigned char HeaderType; + unsigned char BuiltInSelfTest; + unsigned long BaseAddress[6]; + unsigned long CardbusCISpointer; + unsigned short SubVendorID; + unsigned short SubDeviceID; + unsigned long ROMBaseAddress; + unsigned long reserved3; + unsigned long reserved4; + unsigned char InterruptLine; + unsigned char InterruptPin; + unsigned char MinGrant; + unsigned char MaxLatency; + unsigned long VendorUnique[48]; +} IOPCIConfigSpace; + + +/* PCI_DEFAULT_DATA is the value resulting from a read to a non-existent + * PCI device's configuration space. + */ + +#define PCI_DEFAULT_DATA 0xffffffff + + +/* PCI_INVALID_VENDOR_ID is a Vendor ID reserved by the PCI/SIG and is + * guaranteed not to be assigned to any vendor. + */ + +#define PCI_INVALID_VENDOR_ID 0xffff + #endif /* !__LIBSAIO_PCI_H */ diff --git a/i386/libsaio/saio.h b/i386/libsaio/saio.h deleted file mode 100644 index 4b70b70..0000000 --- a/i386/libsaio/saio.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Mach Operating System - * Copyright (c) 1990 Carnegie-Mellon University - * Copyright (c) 1989 Carnegie-Mellon University - * Copyright (c) 1988 Carnegie-Mellon University - * All rights reserved. The CMU software License Agreement specifies - * the terms and conditions for use and redistribution. - * - */ -/* - * Copyright (c) 1982, 1986 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - * - * @(#)saio.h 7.1 (Berkeley) 6/5/86 - */ - -#ifndef __LIBSAIO_SAIO_H -#define __LIBSAIO_SAIO_H - -#include -#include -#include -#include -#include - -/* - * Io block: includes an inode, cells for the use of seek, etc, - * and a buffer. - */ -struct iob { - int i_flgs; /* see F_ below */ - struct inode i_ino; /* inode, if file */ - daddr_t i_boff; /* block offset on device */ - unsigned int i_offset; /* seek offset in file */ - daddr_t i_bn; /* 1st block # of next read */ - char * i_ma; /* memory address of i/o buffer */ - int i_cc; /* character count of transfer */ - int i_error; /* error # return */ - char * i_buf; /* i/o buffer */ - struct fs * i_ffs; /* file system super block info */ - int biosdev; /* bios device for file, i_ino inadequate */ - daddr_t dirbuf_blkno; /* blk of currently buffered dir */ - int partition; /* which partition */ -}; - -struct dirstuff { - int loc; - struct iob * io; -}; - -#define F_READ 0x1 /* file opened for reading */ -#define F_WRITE 0x2 /* file opened for writing */ -#define F_ALLOC 0x4 /* buffer allocated */ -#define F_FILE 0x8 /* file instead of device */ -#define F_NBSF 0x10 /* no bad sector forwarding */ -#define F_SSI 0x40 /* set skip sector inhibit */ -#define F_MEM 0x80 /* memory instead of file or device */ - -/* IO types */ -#define F_RDDATA 0x0100 /* read data */ -#define F_WRDATA 0x0200 /* write data */ -#define F_HDR 0x0400 /* include header on next i/o */ - -#define F_TYPEMASK 0xff00 - -extern char * devsw[]; - -/* - * Request codes. Must be the same a F_XXX above - */ -#define READ 1 -#define WRITE 2 - -#define NBUFS 4 -extern char * b[NBUFS]; -extern daddr_t blknos[NBUFS]; - -#define NFILES 6 -extern struct iob iob[NFILES]; - -/* Error codes */ -#define EBADF 1 /* bad file descriptor */ -#define EOFFSET 2 /* relative seek not supported */ -#define EDEV 3 /* improper device specification on open */ -#define ENXIO 4 /* unknown device specified */ -#define ESRCH 6 /* directory search for file failed */ -#define EIO 7 /* generic error */ -#define ECMD 10 /* undefined driver command */ -#define EBSE 11 /* bad sector error */ -#define EWCK 12 /* write check error */ -#define EECC 13 /* uncorrectable ecc error */ -#define EHER 14 /* hard error */ - -#define BIOS_DEV_FLOPPY 0x0 -#define BIOS_DEV_HD 0x80 -#define BIOS_DEV_WIN BIOS_DEV_HD -#define BIOS_DEV_EN 0xff /* not really a BIOS device number */ - -#define DEV_SD 0 -#define DEV_HD 1 -#define DEV_FLOPPY 2 -#define DEV_EN 3 - -#define BIOSDEV(dev) ((dev) == DEV_FLOPPY ? BIOS_DEV_FLOPPY : BIOS_DEV_WIN) - -#define NSECS 16 /* number of buffered 512 byte sectors */ - -#define Dev(x) (((x)>>B_TYPESHIFT)&B_TYPEMASK) - -#ifndef max -#define max(a,b) ((a) > (b) ? (a) : (b)) -#endif - -#ifndef min -#define min(a,b) ((a) < (b) ? (a) : (b)) -#endif - -#endif /* !__LIBSAIO_SAIO_H */ diff --git a/i386/libsaio/saio_internal.h b/i386/libsaio/saio_internal.h index 16968b4..6ecde2d 100644 --- a/i386/libsaio/saio_internal.h +++ b/i386/libsaio/saio_internal.h @@ -28,138 +28,123 @@ #include "saio_types.h" /* asm.s */ -extern void real_to_prot(void); -extern void prot_to_real(void); -extern void halt(void); -extern void startprog(unsigned int address); +extern void real_to_prot(void); +extern void prot_to_real(void); +extern void halt(void); +extern void startprog(unsigned int address); +extern void loader(UInt32 code, UInt32 cmdptr); /* bios.s */ -extern void bios(biosBuf_t *bb); -extern void get_memsize(biosBuf_t *bb); +extern void bios(biosBuf_t *bb); +extern void get_memsize(biosBuf_t *bb); /* biosfn.c */ #ifdef EISA_SUPPORT -extern BOOL eisa_present(void); +extern BOOL eisa_present(void); #endif -extern int bgetc(void); -extern int biosread(int dev, int cyl, int head, int sec, int num); -extern int ebiosread(int dev, long sec, int count); -extern void putc(int ch); -extern int getc(void); -extern int readKeyboardStatus(void); -extern unsigned int time18(void); -extern unsigned int get_diskinfo(int dev); -extern int APMPresent(void); -extern int APMConnect32(void); -extern int memsize(int i); -extern void video_mode(int mode); -extern void setCursorPosition(int x, int y); +extern int bgetc(void); +extern int biosread(int dev, int cyl, int head, int sec, int num); +extern int ebiosread(int dev, long sec, int count); +extern void putc(int ch); +extern void putca(int ch, int attr, int repeat); +extern int getc(void); +extern int readKeyboardStatus(void); +extern unsigned int time18(void); +extern unsigned int get_diskinfo(int dev); +extern int APMPresent(void); +extern int APMConnect32(void); +extern int memsize(int i); +extern void video_mode(int mode); +extern void setCursorPosition(int x, int y, int page); +extern void setCursorType(int type); +extern void getCursorPositionAndType(int *x, int *y, int *type); +extern void scollPage(int x1, int y1, int x2, int y2, int attr, int rows, int dir); +extern void clearScreenRows(int y1, int y2); +extern void setActiveDisplayPage( int page ); /* bootstruct.c */ -extern void initKernBootStruct(void); +extern void initKernBootStruct(int biosdev); + +/* cache.c */ +extern void CacheInit(CICell ih, long blockSize); +extern long CacheRead(CICell ih, char *buffer, long long offset, + long length, long cache); /* console.c */ -extern BOOL gVerboseMode; -extern void putchar(int ch); -extern int getchar(void); -extern int printf(const char *format, ...); -extern int error(const char *format, ...); -extern int verbose(const char *format, ...); +extern BOOL gVerboseMode; +extern BOOL gErrors; +extern void putchar(int ch); +extern int getchar(void); +extern int printf(const char *format, ...); +extern int error(const char *format, ...); +extern int verbose(const char *format, ...); /* disk.c */ -extern void devopen(char *name, struct iob *io); -extern int devread(struct iob *io); -extern void devflush(void); - -/* gets.c */ -extern int gets(char *buf, int len); -extern int Gets( - char *buf, - int len, - int timeout, - char *prompt, - char *message -); +extern BVRef diskScanBootVolumes(int biosdev, int *count); +extern void diskSeek(BVRef bvr, long long position); +extern int diskRead(BVRef bvr, long addr, long length); +extern int readBootSector(int biosdev, unsigned int secno, void *buffer); /* load.c */ -extern int openfile(char *filename, int ignored); - -extern int loadmacho( - struct mach_header *head, - int dev, - int io, - entry_t *entry, - char **addr, - int *size, - int file_offset -); -extern int loadprog( - int dev, - int fd, - struct mach_header *headOut, - entry_t *entry, - char **addr, - int *size -); +extern int openfile(const char *filename, int ignored); +extern int loadprog(int dev, int fd, struct mach_header *headOut, + entry_t *entry, char **addr, int *size); /* misc.c */ -extern void sleep(int n); -extern void enableA20(void); -extern void turnOffFloppy(void); -extern char *newString(char *oldString); +extern void sleep(int n); +extern void enableA20(void); +extern void turnOffFloppy(void); +extern char * newString(const char *oldString); +extern void stop(const char *message); + +/* nbp.c */ +extern UInt32 nbpUnloadBaseCode(); +extern BVRef nbpScanBootVolumes(int biosdev, int *count); /* stringTable.c */ extern char * newStringFromList(char **list, int *size); -extern int stringLength(char *table, int compress); -extern BOOL getValueForStringTableKey(char *table, char *key, char **val, int *size); +extern int stringLength(const char *table, int compress); +extern BOOL getValueForStringTableKey(const char *table, const char *key, const char **val, int *size); extern BOOL removeKeyFromTable(const char *key, char *table); extern char * newStringForStringTableKey(char *table, char *key); extern char * newStringForKey(char *key); -extern BOOL getValueForBootKey(char *line, char *match, char **matchval, int *len); -extern BOOL getValueForKey(char *key, char **val, int *size); -extern BOOL getBoolForKey(char *key); -extern BOOL getIntForKey(char *key, int *val); +extern BOOL getValueForBootKey(const char *line, const char *match, const char **matchval, int *len); +extern BOOL getValueForKey(const char *key, const char **val, int *size); +extern BOOL getBoolForKey(const char *key); +extern BOOL getIntForKey(const char *key, int *val); #if 0 extern char * loadLocalizableStrings(char *name, char *tableName); extern char * bundleLongName(char *bundleName, char *tableName); extern int loadOtherConfigs(int useDefault); #endif -extern int loadConfigFile( char *configFile, char **table, BOOL allocTable); -extern int loadConfigDir(char *bundleName, BOOL useDefault, char **table, +extern int loadConfigFile(const char *configFile, const char **table, BOOL allocTable); +extern int loadConfigDir(const char *bundleName, BOOL useDefault, const char **table, BOOL allocTable); -extern int loadSystemConfig(char *which, int size); -extern void addConfig(char *config); +extern int loadSystemConfig(const char *which, int size); +extern void addConfig(const char *config); /* sys.c */ -extern void stop(char *message); -extern int openmem(char * buf, int len); -extern int open(char *str, int how); -extern int close(int fdesc); -extern int file_size(int fdesc); -extern int read(int fdesc, char *buf, int count); -extern int b_lseek(int fdesc, unsigned int addr, int ptr); -extern int tell(int fdesc); -extern void flushdev(void); -extern char *usrDevices(void); -extern struct dirstuff * opendir(char *path); -extern int closedir(struct dirstuff *dirp); -extern struct direct * readdir(struct dirstuff *dirp); -extern int currentdev(void); -extern int switchdev(int dev); - -/* ufs_byteorder.c */ -extern void byte_swap_superblock(struct fs *sb); -extern void byte_swap_inode_in(struct dinode *dc, struct dinode *ic); -extern void byte_swap_dir_block_in(char *addr, int count); - -/* - * vbe.c - */ -extern int set_linear_video_mode(unsigned short mode); - -/* - * vga.c - */ -extern void set_video_mode(unsigned int mode); +extern long LoadFile(const char *fileSpec); +extern long GetDirEntry(const char *dirSpec, long *dirIndex, const char **name, + long *flags, long *time); +extern long GetFileInfo(const char *dirSpec, const char *name, + long *flags, long *time); +extern int openmem(char *buf, int len); +extern int open(const char *str, int how); +extern int close(int fdesc); +extern int file_size(int fdesc); +extern int read(int fdesc, char *buf, int count); +extern int b_lseek(int fdesc, int addr, int ptr); +extern int tell(int fdesc); +extern const char * usrDevices(void); +extern struct dirstuff * opendir(const char *path); +extern int closedir(struct dirstuff *dirp); +extern int readdir(struct dirstuff *dirp, const char **name, long *flags, long *time); +extern void flushdev(void); +extern int currentdev(void); +extern int switchdev(int dev); +extern BVRef scanBootVolumes(int biosdev, int *count); +extern BVRef selectBootVolume(BVRef chain); +extern void getBootVolumeDescription(BVRef bvr, char *str, long strMaxLen); #endif /* !__LIBSAIO_SAIO_INTERNAL_H */ diff --git a/i386/libsaio/saio_types.h b/i386/libsaio/saio_types.h index b98d4ea..e78fc1a 100644 --- a/i386/libsaio/saio_types.h +++ b/i386/libsaio/saio_types.h @@ -26,21 +26,22 @@ #ifndef __LIBSAIO_SAIO_TYPES_H #define __LIBSAIO_SAIO_TYPES_H -typedef char BOOL; -#define NO 0 -#define YES 1 - -#include -#undef i386_THREAD_STATE -#undef i386_THREAD_STATE_COUNT -#include #include +#include +#include "bios.h" +#include "nbp_cmd.h" -typedef unsigned long entry_t; +#if 0 +#define DEBUG_DISK(x) printf x +#else +#define DEBUG_DISK(x) +#endif -#include -#include "bios.h" -#include "saio.h" +typedef char BOOL; +#define NO 0 +#define YES 1 + +typedef unsigned long entry_t; typedef struct { unsigned int sectors:8; @@ -55,4 +56,86 @@ struct driveParameters { int totalDrives; }; +struct BootVolume; +typedef struct BootVolume * BVRef; +typedef struct BootVolume * CICell; + +typedef long (*FSInit)(CICell ih); +typedef long (*FSLoadFile)(CICell ih, char * filePath); +typedef long (*FSGetDirEntry)(CICell ih, char * dirPath, long * dirIndex, + char ** name, long * flags, long * time); +typedef void (*BVGetDescription)(CICell ih, char * str, long strMaxLen); + +struct iob { + unsigned int i_flgs; /* see F_* below */ + unsigned int i_offset; /* seek byte offset in file */ + int i_filesize; /* size of file */ + char * i_buf; /* file load address */ +}; + +#define F_READ 0x1 /* file opened for reading */ +#define F_WRITE 0x2 /* file opened for writing */ +#define F_ALLOC 0x4 /* buffer allocated */ +#define F_FILE 0x8 /* file instead of device */ +#define F_NBSF 0x10 /* no bad sector forwarding */ +#define F_SSI 0x40 /* set skip sector inhibit */ +#define F_MEM 0x80 /* memory instead of file or device */ + +struct dirstuff { + char * dir_path; /* directory path */ + long dir_index; /* directory entry index */ + BVRef dir_bvr; /* volume reference */ +}; + +struct BootVolume { + BVRef next; /* list linkage pointer */ + int biosdev; /* BIOS device number */ + unsigned int flags; /* attribute flags */ + BVGetDescription description; /* BVGetDescription function */ + int part_no; /* partition number (1 based) */ + unsigned int part_boff; /* partition block offset */ + unsigned int part_type; /* partition type */ + unsigned int fs_boff; /* 1st block # of next read */ + FSLoadFile fs_loadfile; /* FSLoadFile function */ + FSGetDirEntry fs_getdirentry; /* FSGetDirEntry function */ +}; + +enum { + kBVFlagPrimary = 0x01, + kBVFlagNativeBoot = 0x02, + kBVFlagForeignBoot = 0x04 +}; + +enum { + kBIOSDevTypeFloppy = 0x00, + kBIOSDevTypeHardDrive = 0x80, + kBIOSDevTypeNetwork = 0xE0, + kBIOSDevUnitMask = 0x0F, + kBIOSDevTypeMask = 0xF0, + kBIOSDevMask = 0xFF +}; + +#define BIOS_DEV_TYPE(d) ((d) & kBIOSDevTypeMask) +#define BIOS_DEV_UNIT(d) ((d) & kBIOSDevUnitMask) + +/* + * KernBootStruct device types. + */ +enum { + DEV_SD = 0, + DEV_HD = 1, + DEV_FD = 2, + DEV_EN = 3 +}; + +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#define MAKEKERNDEV(t, u, p) MAKEBOOTDEV(t, 0, 0, u, p) + #endif /* !__LIBSAIO_SAIO_TYPES_H */ diff --git a/i386/libsaio/cache.h b/i386/libsaio/sl.h similarity index 51% rename from i386/libsaio/cache.h rename to i386/libsaio/sl.h index 01b51d9..baa9e67 100644 --- a/i386/libsaio/cache.h +++ b/i386/libsaio/sl.h @@ -22,35 +22,41 @@ * @APPLE_LICENSE_HEADER_END@ */ -#ifndef __LIBSAIO_CACHE_H -#define __LIBSAIO_CACHE_H +#ifndef __LIBSAIO_SL_H +#define __LIBSAIO_SL_H -typedef struct cache_item { - unsigned int referenced; - int key1, key2; - char storage[0]; -} item_t; +#include +#include +#include +#include "libsaio.h" -typedef struct cache { - int nitems; - int item_size; - char storage[0]; -} cache_t; +#define SWAP_BE16(x) NXSwapBigShortToHost(x) +#define SWAP_BE32(x) NXSwapBigLongToHost(x) +#define SWAP_BE64(x) NXSwapBigLongLongToHost(x) -extern cache_t *cacheInit( - int nitems, - int item_size -); +// File Permissions and Types +enum { + kPermOtherExecute = 1 << 0, + kPermOtherWrite = 1 << 1, + kPermOtherRead = 1 << 2, + kPermGroupExecute = 1 << 3, + kPermGroupWrite = 1 << 4, + kPermGroupRead = 1 << 5, + kPermOwnerExecute = 1 << 6, + kPermOwnerWrite = 1 << 7, + kPermOwnerRead = 1 << 8, + kPermMask = 0x1FF, + kOwnerNotRoot = 1 << 9, + kFileTypeUnknown = 0x0 << 16, + kFileTypeFlat = 0x1 << 16, + kFileTypeDirectory = 0x2 << 16, + kFileTypeLink = 0x3 << 16, + kFileTypeMask = 0x3 << 16 +}; -extern int cacheFind( - cache_t *cp, - int key1, - int key2, - char **ip -); +#define Seek(c, p) diskSeek(c, p); +#define Read(c, a, l) diskRead(c, a, l); -extern void cacheFlush( - cache_t *cp -); +extern void * gFSLoadAddress; -#endif /* !__LIBSAIO_CACHE_H */ +#endif /* !__LIBSAIO_SL_H */ diff --git a/i386/libsaio/stringTable.c b/i386/libsaio/stringTable.c index 8fafe9b..1d91731 100644 --- a/i386/libsaio/stringTable.c +++ b/i386/libsaio/stringTable.c @@ -27,7 +27,6 @@ */ #include "libsaio.h" -#include "kernBootStruct.h" #include "stringConstants.h" #include "legacy/configTablePrivate.h" @@ -35,7 +34,7 @@ extern KERNBOOTSTRUCT *kernBootStruct; extern char *Language; extern char *LoadableFamilies; -static void eatThru(char val, char **table_p); +static void eatThru(char val, const char **table_p); static inline int isspace(char c) { @@ -46,7 +45,7 @@ static inline int isspace(char c) * Compare a string to a key with quoted characters */ static inline int -keyncmp(char *str, char *key, int n) +keyncmp(const char *str, const char *key, int n) { int c; while (n--) { @@ -76,9 +75,9 @@ keyncmp(char *str, char *key, int n) return 0; } -static void eatThru(char val, char **table_p) +static void eatThru(char val, const char **table_p) { - register char *table = *table_p; + register const char *table = *table_p; register BOOL found = NO; while (*table && !found) @@ -170,7 +169,7 @@ newStringFromList( /* * compress == compress escaped characters to one character */ -int stringLength(char *table, int compress) +int stringLength(const char *table, int compress) { int ret = 0; @@ -193,10 +192,10 @@ int stringLength(char *table, int compress) // looks in table for strings of format << "key" = "value"; >> // or << "key"; >> -BOOL getValueForStringTableKey(char *table, char *key, char **val, int *size) +BOOL getValueForStringTableKey(const char *table, const char *key, const char **val, int *size) { int keyLength; - char *tableKey; + const char *tableKey; do { @@ -249,11 +248,12 @@ char *newStringForStringTableKey( char *key ) { - char *val, *newstr, *p; + const char *val; + char *newstr, *p; int size; if (getValueForStringTableKey(table, key, &val, &size)) { - newstr = malloc(size+1); + newstr = (char *)malloc(size+1); for (p = newstr; size; size--, p++, val++) { if ((*p = *val) == '\\') { switch (*++val) { @@ -283,11 +283,12 @@ char *newStringForStringTableKey( char * newStringForKey(char *key) { - char *val, *newstr; + const char *val; + char *newstr; int size; if (getValueForKey(key, &val, &size) && size) { - newstr = malloc(size + 1); + newstr = (char *)malloc(size + 1); strncpy(newstr, val, size); return newstr; } else { @@ -301,7 +302,7 @@ newStringForKey(char *key) * non-whitespace characters, or enclosed in quotes. */ -static char *getToken(char *line, char **begin, int *len) +static const char *getToken(const char *line, const char **begin, int *len) { if (*line == '\"') { *begin = ++line; @@ -317,9 +318,9 @@ static char *getToken(char *line, char **begin, int *len) return line; } -BOOL getValueForBootKey(char *line, char *match, char **matchval, int *len) +BOOL getValueForBootKey(const char *line, const char *match, const char **matchval, int *len) { - char *key, *value; + const char *key, *value; int key_len, value_len; while (*line) { @@ -346,10 +347,10 @@ BOOL getValueForBootKey(char *line, char *match, char **matchval, int *len) } BOOL getBoolForKey( - char *key + const char *key ) { - char *val; + const char *val; int size; if (getValueForKey(key, &val, &size) && (size >= 1) && @@ -359,11 +360,11 @@ BOOL getBoolForKey( } BOOL getIntForKey( - char *key, + const char *key, int *value ) { - char *val; + const char *val; int size, sum; if (getValueForKey(key, &val, &size)) { @@ -377,8 +378,8 @@ BOOL getIntForKey( } BOOL getValueForKey( - char *key, - char **val, + const char *key, + const char **val, int *size ) { @@ -401,7 +402,7 @@ loadLocalizableStrings( { char buf[256], *config; register int count, fd = -1; - char *device_dir = usrDevices(); + const char *device_dir = usrDevices(); sprintf(buf, LOCALIZABLE_PATH, device_dir, name, Language, tableName); @@ -462,7 +463,7 @@ int sysConfigValid; void addConfig( - char *config + const char *config ) { char *configPtr = kernBootStruct->configEnd; @@ -488,7 +489,7 @@ addConfig( * Allocates an extra number of bytes for table expansion. */ int -loadConfigFile( char *configFile, char **table, BOOL allocTable) +loadConfigFile(const char *configFile, const char **table, BOOL allocTable) { char *configPtr = kernBootStruct->configEnd; int fd, count; @@ -530,15 +531,15 @@ loadConfigFile( char *configFile, char **table, BOOL allocTable) int loadConfigDir( - char *bundleName, // bundle directory name (e.g. "System") + const char *bundleName, // bundle directory name (e.g. "System") BOOL useDefault, // use Default.table instead of instance tables - char **table, // returns pointer to config table + const char **table, // returns pointer to config table BOOL allocTable // malloc the table and return in *table ) { char *buf; int i, max, ret; - char *device_dir = usrDevices(); + const char *device_dir = usrDevices(); buf = malloc(256); ret = 0; @@ -598,13 +599,14 @@ static int sysconfig_dev; */ int loadSystemConfig( - char *which, + const char *which, int size ) { - char *buf, *bp, *cp; + char *buf, *bp; + const char *cp; int ret, len, doDefault=0; - char *device_dir = usrDevices(); + const char *device_dir = usrDevices(); #if 0 printf("In Load system config which=%d ; size=%d\n", which, size); diff --git a/i386/libsaio/sys.c b/i386/libsaio/sys.c index e8b75b4..b4e88ed 100644 --- a/i386/libsaio/sys.c +++ b/i386/libsaio/sys.c @@ -54,1309 +54,529 @@ * @(#)sys.c 7.1 (Berkeley) 6/5/86 */ -#include -#include -#include -#include -#include "ufs_byteorder.h" #include "libsaio.h" -#include "cache.h" -#include "kernBootStruct.h" -#include "stringConstants.h" -#include -#include "nbp.h" -#include "memory.h" - -char * gFilename; - -extern int ram_debug_sarld; // in load.c - -#define DCACHE 1 -#define ICACHE 1 -#define SYS_MESSAGES 1 -#define CHECK_CAREFULLY 0 -#define COMPRESSION 1 - -// #define DEBUG 1 - -#ifdef DEBUG -#define DPRINT(x) { printf x; } -#define DSPRINT(x) { printf x; sleep(2); } -#define RDPRINT(x) { if (ram_debug_sarld) printf x; } -#define RDSPRINT(x) { if (ram_debug_sarld) printf x; sleep(2); } -#else -#define DPRINT(x) -#define DSPRINT(x) -#define RDPRINT(x) -#define RDSPRINT(x) -#endif - -char * devsw[] = { - "sd", - "hd", - "fd", - "en", - NULL + +struct devsw { + const char * name; + unsigned char biosdev; }; -//############################################################################# -//# -//# Disk filesystem functions. -//# -//############################################################################# +static struct devsw devsw[] = +{ + { "sd", 0x80 }, /* DEV_SD */ + { "hd", 0x80 }, /* DEV_HD */ + { "fd", 0x00 }, /* DEV_FD */ + { "en", 0xE0 }, /* DEV_EN */ + { 0, 0 } +}; -static ino_t dlook(char *s, struct iob *io); -static char * xx(char *str, struct iob *file); -static int ffs(register long mask); +/* + * Max number of file descriptors. + */ +#define NFILES 6 -extern int label_secsize; +static struct iob iob[NFILES]; -#define BIG_ENDIAN_INTEL_FS __LITTLE_ENDIAN__ +void * gFSLoadAddress = 0; -#if ICACHE -#define ICACHE_SIZE 256 -#define ICACHE_READAHEAD 8 // read behind and read ahead -static cache_t * icache; -#endif ICACHE +static BVRef getBootVolumeRef( const char * path, const char ** outPath ); +static BVRef newBootVolumeRef( int biosdev, int partno ); -#if DCACHE -#define DCACHE_SIZE 16 // 1k (DIRBLKSIZ) blocks -static cache_t * dcache; -#endif +//========================================================================== +// LoadFile - LOW-LEVEL FILESYSTEM FUNCTION. +// Load the specified file to the load buffer at LOAD_ADDR. -#define DEV_BSIZE label_secsize +long LoadFile(const char * fileSpec) +{ + const char * filePath; + long fileSize; + BVRef bvr; -#if CHECK_CAREFULLY -static int open_init; -#endif + // Resolve the boot volume from the file spec. -static struct fs * fs_block; -static int fs_block_valid; + if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL) + return -1; -#define SUPERBLOCK_ERROR "Bad superblock: error %d\n" + // Read file into load buffer. The data in the load buffer will be + // overwritten by the next LoadFile() call. -/*========================================================================== - * - * - */ -static struct iob * iob_from_fdesc(int fdesc) -{ - register struct iob * file; - - if (fdesc < 0 || fdesc >= NFILES || - ((file = &iob[fdesc])->i_flgs & F_ALLOC) == 0) - return NULL; - else - return file; -} + gFSLoadAddress = (void *) LOAD_ADDR; + fileSize = bvr->fs_loadfile(bvr, (char *)filePath); -/*************************************************************************** - * - * Disk functions. - * - ***************************************************************************/ + // Return the size of the file, or -1 if load failed. -/*========================================================================== - * - * - */ -static int -openi(int n, struct iob * io) -{ - struct dinode * dp; - int cc, i, j, n_round; - -#if ICACHE - struct dinode *ip; - - if (icache == 0) { - icache = cacheInit(ICACHE_SIZE, sizeof(struct dinode)); - } -#endif /* ICACHE */ - - io->i_offset = 0; - io->i_bn = fsbtodb(io->i_ffs, ino_to_fsba(io->i_ffs, n)) + io->i_boff; - io->i_cc = io->i_ffs->fs_bsize; - io->i_ma = io->i_buf; - -#if ICACHE - if (cacheFind(icache, n, 0, (char **)&ip) == 1) { - io->i_ino.i_din = *ip; - cc = 0; - } else { -#endif ICACHE - cc = devread(io); - dp = (struct dinode *)io->i_buf; - n_round = (n / INOPB(io->i_ffs)) * INOPB(io->i_ffs); -#if ICACHE - /* Read multiple inodes into cache */ - for (i = max(ino_to_fsbo(io->i_ffs, n) - ICACHE_READAHEAD, 0), - j = min(i+2*ICACHE_READAHEAD, INOPB(io->i_ffs)); i < j; i++) { - cacheFind(icache, n_round + i, 0, (char **)&ip); - -#if BIG_ENDIAN_INTEL_FS -#warning Building with Big Endian changes - byte_swap_dinode_in(&dp[i]); -#endif /* BIG_ENDIAN_INTEL_FS */ - - *ip = dp[i]; - if (i == ino_to_fsbo(io->i_ffs, n)) { - io->i_ino.i_din = *ip; - } - } - } -#else ICACHE - -#if BIG_ENDIAN_INTEL_FS - byte_swap_dinode_in(&dp[ino_to_fsbo(io->i_ffs, n)]); -#endif /* BIG_ENDIAN_INTEL_FS */ - - io->i_ino.i_din = dp[ino_to_fsbo(io->i_ffs, n)]; -#endif ICACHE - - io->i_ino.i_number = n; - return (cc); + return fileSize; } -/*========================================================================== - * - * - */ -static int -readlink(struct iob * io, char * buf, int len) +//========================================================================== +// GetDirEntry - LOW-LEVEL FILESYSTEM FUNCTION. +// Fetch the next directory entry for the given directory. + +long GetDirEntry(const char * dirSpec, long * dirIndex, const char ** name, + long * flags, long * time) { - register struct inode * ip; - - ip = &io->i_ino; -#if 1 - /* read contents */ - io->i_offset = 0; - io->i_cc = 0; - io->i_flgs |= F_FILE; - if (read(io - iob, buf, len) < 0) + const char * dirPath; + BVRef bvr; + + // Resolve the boot volume from the dir spec. + + if ((bvr = getBootVolumeRef(dirSpec, &dirPath)) == NULL) return -1; -#else - if (ip->i_icflags & IC_FASTLINK) { - if (ip->i_size > len) - return -1; - bcopy(ip->i_symlink, buf, ip->i_size); - } else { - /* read contents */ - io->i_offset = 0; - io->i_cc = 0; - io->i_flgs |= F_FILE; - if (read(io - iob, buf, len) < 0) - return -1; - } -#endif - return 0; + + // Return 0 on success, or -1 if there are no additional entries. + + return bvr->fs_getdirentry( bvr, + /* dirPath */ (char *)dirPath, + /* dirIndex */ dirIndex, + /* dirEntry */ (char **)name, flags, time ); } -/*========================================================================== - * - * - */ -static int -find(char * path, struct iob * file) +//========================================================================== +// GetFileInfo - LOW-LEVEL FILESYSTEM FUNCTION. +// Get attributes for the specified file. + +long GetFileInfo(const char * dirSpec, const char * name, + long * flags, long * time) { - char * q; - char c; - int n, parent; - char * lbuf = malloc(MAXPATHLEN + 1); - int ret; - -#if CHECK_CAREFULLY - if (path==NULL || *path=='\0') { - error("null path\n"); - ret = 0; goto out; - } -#endif CHECK_CAREFULLY - - DSPRINT(("in find: path=%s\n", path)); - -root: - n = ROOTINO; - if (openi(n, file) < 0) - { - DPRINT(("openi failed\n")); - -#if SYS_MESSAGES - error("bad root inode\n"); -#endif - - ret = 0; goto out; - } - DPRINT(("openi ok\n")); - - while (*path) - { - while (*path == '/') - path++; - q = path; - while(*q != '/' && *q != '\0') - q++; - c = *q; - *q = '\0'; - if (q == path) path = "." ; /* "/" means "/." */ - - parent = n; - if ((n = dlook(path, file)) != 0) - { - if (c == '\0') - break; - if (openi(n, file) < 0) - { - *q = c; - ret = 0; goto out; - } - *q = c; - path = q; - - /* Check for symlinks */ - if (file->i_ino.i_mode & IFLNK) { - char *buf = malloc(MAXPATHLEN + 1); - if (readlink(file, buf, MAXPATHLEN + 1) < 0) - return -1; - strcat(buf, q); - strcpy(lbuf, buf); - free(buf); - path = lbuf; - if (*path == '/') - goto root; - if (openi(parent, file) < 0) { - ret = 0; goto out; - } - } - continue; - } - else - { - *q = c; - ret = 0; goto out; - } - } - ret = n; -out: - free(lbuf); - return (ret); + long index = 0; + const char * entryName; + + while (GetDirEntry(dirSpec, &index, &entryName, flags, time) == 0) + { + if (strcmp(entryName, name) == 0) + return 0; // success + } + return -1; // file not found } -/*========================================================================== - * - * - */ -static daddr_t -sbmap(struct iob * io, daddr_t bn) +//========================================================================== +// iob_from_fdesc() +// +// Return a pointer to an allocated 'iob' based on the file descriptor +// provided. Returns NULL if the file descriptor given is invalid. + +static struct iob * iob_from_fdesc(int fdesc) { - register struct inode * ip; - int i, j, sh; - daddr_t nb, * bap; - - ip = &io->i_ino; - - if (bn < 0) { -#if SYS_MESSAGES - error("bn negative\n"); -#endif - return ((daddr_t)0); - } - - /* - * blocks 0..NDADDR are direct blocks - */ - if (bn < NDADDR) - { - nb = ip->i_db[bn]; - return (nb); - } - - /* - * addresses NIADDR have single and double indirect blocks. - * the first step is to determine how many levels of indirection. - */ - RDPRINT(("In NINADDR\n")); - - sh = 1; - bn -= NDADDR; - for (j = NIADDR; j > 0; j--) { - sh *= NINDIR(io->i_ffs); - if (bn < sh) - break; - bn -= sh; - } - - if (j == 0) { -#if SYS_MESSAGES - error("bn ovf %d\n", bn); -#endif - return ((daddr_t)0); - } - - /* - * fetch the first indirect block address from the inode - */ - nb = ip->i_ib[NIADDR - j]; - if (nb == 0) { -#if SYS_MESSAGES - error("bn void %d\n",bn); -#endif - return ((daddr_t)0); - } - - /* - * fetch through the indirect blocks - */ - for (; j <= NIADDR; j++) { - if (blknos[j] != nb) { - io->i_bn = fsbtodb(io->i_ffs, nb) + io->i_boff; - if (b[j] == (char *)0) - b[j] = malloc(MAXBSIZE); - io->i_ma = b[j]; - io->i_cc = io->i_ffs->fs_bsize; - - RDPRINT(("Indir block read\n")); - - if (devread(io) != io->i_ffs->fs_bsize) { -#if SYS_MESSAGES - error("bn %d: read error\n", io->i_bn); -#endif - return ((daddr_t)0); - } - blknos[j] = nb; - } - bap = (daddr_t *)b[j]; - sh /= NINDIR(io->i_ffs); - i = (bn / sh) % NINDIR(io->i_ffs); -#if BIG_ENDIAN_INTEL_FS - nb = NXSwapBigLongToHost(bap[i]); -#else /* BIG_ENDIAN_INTEL_FS */ - nb = bap[i]; -#endif /* BIG_ENDIAN_INTEL_FS */ - if (nb == 0) { -#if SYS_MESSAGES - error("bn void %d\n",bn); -#endif - return ((daddr_t)0); - } - } - - return (nb); + register struct iob * io; + + if (fdesc < 0 || fdesc >= NFILES || + ((io = &iob[fdesc])->i_flgs & F_ALLOC) == 0) + return NULL; + else + return io; } -/*========================================================================== - * - * - */ -static struct dirstuff * -disk_opendir(char * path) +//========================================================================== +// openmem() + +int openmem(char * buf, int len) { - register struct dirstuff * dirp; - register int fd; - - dirp = (struct dirstuff *)malloc(sizeof(struct dirstuff)); - if (dirp == (struct dirstuff *)-1) - return 0; + int fdesc; + struct iob * io; - DPRINT(("Calling open in opendir\n")); - fd = open(path,0); - if (fd == -1) { - DPRINT(("open failed \n")); - free((void *)dirp); - return 0; - } + // Locate a free descriptor slot. - DPRINT(("open ok fd is %d \n", fd)); - dirp->io = &iob[fd]; - dirp->loc = 0; - iob[fd].dirbuf_blkno = -1; + for (fdesc = 0; fdesc < NFILES; fdesc++) + if (iob[fdesc].i_flgs == 0) + goto gotfile; - return dirp; -} + stop("Out of file descriptors"); -/*========================================================================== - * - * - */ -static int -disk_closedir(struct dirstuff * dirp) -{ - close(dirp->io - iob); - free((void *)dirp); - return 0; -} +gotfile: + io = &iob[fdesc]; + bzero(io, sizeof(*io)); -/*========================================================================== - * get next entry in a directory. - */ -static struct direct * -disk_readdir(struct dirstuff * dirp) -{ - struct direct * dp; - register struct iob * io; - daddr_t lbn, d; - int off; -#if DCACHE - char * bp; - int dirblkno; - - if (dcache == 0) - dcache = cacheInit(DCACHE_SIZE, DIRBLKSIZ); -#endif DCACHE - - io = dirp->io; - for(;;) - { - if (dirp->loc >= io->i_ino.i_size) - return (NULL); - off = blkoff(io->i_ffs, dirp->loc); - lbn = lblkno(io->i_ffs, dirp->loc); - -#if DCACHE - dirblkno = dirp->loc / DIRBLKSIZ; - if (cacheFind(dcache, io->i_ino.i_number, dirblkno, &bp)) { - dp = (struct direct *)(bp + (dirp->loc % DIRBLKSIZ)); - } else -#else DCACHE - if (io->dirbuf_blkno != lbn) -#endif DCACHE - { - if((d = sbmap(io, lbn)) == 0) - return NULL; - io->i_bn = fsbtodb(io->i_ffs, d) + io->i_boff; - io->i_ma = io->i_buf; - io->i_cc = blksize(io->i_ffs, &io->i_ino, lbn); - - if (devread(io) < 0) - { -#if SYS_MESSAGES - error("bn %d: directory read error\n", io->i_bn); -#endif - return (NULL); - } -#if BIG_ENDIAN_INTEL_FS - byte_swap_dir_block_in(io->i_buf, io->i_cc); -#endif /* BIG_ENDIAN_INTEL_FS */ - -#if DCACHE - bcopy(io->i_buf + dirblkno * DIRBLKSIZ, bp, DIRBLKSIZ); - dp = (struct direct *)(io->i_buf + off); -#endif - } -#if !DCACHE - dp = (struct direct *)(io->i_buf + off); -#endif - dirp->loc += dp->d_reclen; - - if (dp->d_ino != 0) return (dp); - } -} + // Mark the descriptor as taken. Set the F_MEM flag to indicate + // that the file buffer is provided by the caller. -/*========================================================================== - * - * - */ -static ino_t -dlook( - char * s, - struct iob * io -) -{ - struct direct * dp; - register struct inode * ip; - struct dirstuff dirp; - int len; - - if (s == NULL || *s == '\0') - return (0); - ip = &io->i_ino; - if ((ip->i_mode & IFMT) != IFDIR) { -#if SYS_MESSAGES - error(". before %s not a dir\n", s); -#endif - return (0); - } - if (ip->i_size == 0) { -#if SYS_MESSAGES - error("%s: 0 length dir\n", s); -#endif - return (0); - } - len = strlen(s); - dirp.loc = 0; - dirp.io = io; - io->dirbuf_blkno = -1; - - for (dp = disk_readdir(&dirp); dp != NULL; dp = disk_readdir(&dirp)) { - DPRINT(("checking name %s\n", dp->d_name)); - if(dp->d_ino == 0) - continue; - if (dp->d_namlen == len && !strcmp(s, dp->d_name)) - return (dp->d_ino); - } - return (0); -} + io->i_flgs = F_ALLOC | F_MEM; + io->i_buf = buf; + io->i_filesize = len; -/*========================================================================== - * - * - */ -static int -getch(int fdesc) -{ - register struct iob * io; - struct fs * fs; - char * p; - int c, lbn, off, size, diff; - - if ((io = iob_from_fdesc(fdesc)) == 0) { - return (-1); - } - - RDPRINT(("In getch\n")); - - p = io->i_ma; - if (io->i_cc <= 0) { - if ((io->i_flgs & F_FILE) != 0) { - diff = io->i_ino.i_size - io->i_offset; - if (diff <= 0) - return (-1); - fs = io->i_ffs; - lbn = lblkno(fs, io->i_offset); -#if 1 - io->i_bn = fsbtodb(fs, sbmap(io, lbn)) + io->i_boff; -#else - io->i_bn = fsbtodb(fs, sbmap(io, lbn)) + io->i_boff; -#endif - off = blkoff(fs, io->i_offset); - size = blksize(fs, &io->i_ino, lbn); - } else { - diff = 0; -#ifndef SMALL - io->i_bn = io->i_offset / DEV_BSIZE; - off = 0; - size = DEV_BSIZE; -#endif SMALL - } - - RDPRINT(("gc: bn=%x; off=%x\n",io->i_bn, io->i_offset)); - - io->i_ma = io->i_buf; - io->i_cc = size; - if (devread(io) < 0) { - return (-1); - } - if ((io->i_flgs & F_FILE) != 0) { - if (io->i_offset - off + size >= io->i_ino.i_size) - io->i_cc = diff + off; - io->i_cc -= off; - } - p = &io->i_buf[off]; - } - io->i_cc--; - io->i_offset++; - c = (unsigned)*p++; - io->i_ma = p; - return (c); + return fdesc; } -/*========================================================================== - * - */ -static int -disk_read(int fdesc, char * buf, int count) -{ - int i, size; - register struct iob * file; - struct fs * fs; - int lbn, off; - - RDSPRINT(("IN READ\n")); - - if ((file = iob_from_fdesc(fdesc)) == 0) { - return (-1); - } -#if CHECK_CAREFULLY - if ((file->i_flgs&F_READ) == 0) { - return (-1); - } -#endif - if ((file->i_flgs & F_MEM) != 0) { - - RDSPRINT(("In read FMEM\n")); - - if (file->i_offset < file->i_boff) { - if (count > (file->i_boff - file->i_offset)) - count = file->i_boff - file->i_offset; - bcopy(file->i_buf + file->i_offset, buf, count); - file->i_offset += count; - } else { - count = 0; - } - return count; - } - -#ifndef SMALL - if ((file->i_flgs & F_FILE) == 0) { - file->i_cc = count; - file->i_ma = buf; - file->i_bn = file->i_boff + (file->i_offset / DEV_BSIZE); - - RDPRINT(("In read nsmall fbn=%x; offset=%x;", file->i_bn, - file->i_offset)); - RDSPRINT(("boff=%x\n", file->i_boff)); - - i = devread(file); - file->i_offset += count; - return (i); - } -#endif /* SMALL */ - - if (file->i_offset+count > file->i_ino.i_size) - count = file->i_ino.i_size - file->i_offset; - - RDSPRINT(("In read nsmall count=%x;", count)); - - if ((i = count) <= 0) - return (0); - - /* - * While reading full blocks, do I/O into user buffer. - * Anything else uses getc(). - */ - fs = file->i_ffs; - while (i) { - RDSPRINT(("In lread while\n")); - off = blkoff(fs, file->i_offset); - lbn = lblkno(fs, file->i_offset); - size = blksize(fs, &file->i_ino, lbn); - if (off == 0 && size <= i) { - file->i_bn = fsbtodb(fs, sbmap(file, lbn)) + - file->i_boff; - file->i_cc = size; - file->i_ma = buf; - - RDPRINT(("In read->devread\n")); - RDPRINT(("In read fbn=%x; offset=%x;", file->i_bn, - file->i_offset)); - RDSPRINT((" boff=%x\n", file->i_boff)); - - if (devread(file) < 0) { - return (-1); - } - file->i_offset += size; - file->i_cc = 0; - buf += size; - i -= size; - } - else { - RDSPRINT(("IN while nonread\n")); - size -= off; - if (size > i) - size = i; - i -= size; - do { - *buf++ = getch(fdesc); - } while (--size); - } - } - - return (count); -} +//========================================================================== +// open() - Open the file specified by 'path' for reading. -/*========================================================================== - * Disk (block device) functions. - */ -static BOOL -disk_open(char * name, struct iob * file, int how) +int open(const char * path, int flags) { - int i; - - file->i_cc = SBSIZE; -// file->i_bn = (SBLOCK / DEV_BSIZE) + file->i_boff; - file->i_bn = (SBOFF/label_secsize) + file->i_boff; - file->i_offset = 0; - - if (file->i_ffs == 0) { - if (fs_block == 0) { - DPRINT(("No super block; reading one \n")); - fs_block = (struct fs *) malloc(SBSIZE); - } - if (fs_block_valid == 0) { - file->i_ma = (char *)fs_block; - if (devread(file) < 0) { -#ifndef SMALL - error(SUPERBLOCK_ERROR, 1); -#endif - return NO; - } -#if BIG_ENDIAN_INTEL_FS - byte_swap_superblock(fs_block); -#endif /* BIG_ENDIAN_INTEL_FS */ - DPRINT(("Read SB \n")); - fs_block_valid = 1; - } - file->i_ffs = fs_block; - file->i_buf = malloc(MAXBSIZE); - } -#if BIG_ENDIAN_INTEL_FS - DPRINT(("IN BE_FS code \n")); - - if (file->i_ffs->fs_magic != FS_MAGIC) { - DPRINT(("Bad magic in FS %d ; got %d\n", FS_MAGIC, - file->i_ffs->fs_magic)); - error(SUPERBLOCK_ERROR, 2); - return NO; - } - /* - * The following is a gross hack to boot disks that have an actual - * blocksize of 512 bytes but were written with a theoretical 1024 - * byte blocksize (fsbtodb == 0). - * - * We can make this assumption because we can only boot disks with - * a 512 byte sector size. - */ - DPRINT(("SB magic ok \n")); - if (file->i_ffs->fs_fsize == 0) { - error(SUPERBLOCK_ERROR,3); - return NO; - } - file->i_ffs->fs_fsbtodb = ffs(file->i_ffs->fs_fsize / DEV_BSIZE) - 1; -#endif /* BIG_ENDIAN_INTEL_FS */ - - if ((i = find(name, file)) == 0) { - DPRINT(("find() failed\n")); - return NO; - } - -#if CHECK_CAREFULLY - if (how != 0) { - error("Can't write files\n"); - return NO; - } -#endif CHECK_CAREFULLY - - DPRINT(("calling openi \n")); - if (openi(i, file) < 0) { - DPRINT(("openi failed \n")); - return NO; - } - - DPRINT(("openi ok \n")); - - file->i_offset = 0; - file->i_cc = 0; - file->i_flgs |= F_FILE | (how+1); - - return YES; -} + int fdesc, i; + struct iob * io; + const char * filePath; + BVRef bvr; -/*========================================================================== - * - * - */ -static int -ffs(register long mask) -{ - register int cnt; + // Locate a free descriptor slot. - if (mask == 0) return(0); + for (fdesc = 0; fdesc < NFILES; fdesc++) + if (iob[fdesc].i_flgs == 0) + goto gotfile; - for (cnt = 1; !(mask & 1); cnt++) - mask >>= 1; - return(cnt); -} + stop("Out of file descriptors"); -/*========================================================================== - * - * - */ -static void -disk_flushdev() -{ - register int i; - - devflush(); +gotfile: + io = &iob[fdesc]; + bzero(io, sizeof(*io)); + + // Mark the descriptor as taken. + + io->i_flgs = F_ALLOC; + + // Resolve the boot volume from the file spec. + + if ((bvr = getBootVolumeRef(path, &filePath)) == NULL) + goto error; + + // Find the next available memory block in the download buffer. + + io->i_buf = (char *) LOAD_ADDR; for (i = 0; i < NFILES; i++) - if (iob[i].i_flgs & (F_READ | F_WRITE)) - error("flushdev: fd %d is open\n",i); - - fs_block_valid = 0; -#if ICACHE - cacheFlush(icache); -#endif -#if DCACHE - cacheFlush(dcache); -#endif + { + if ((iob[i].i_flgs != F_ALLOC) || (i == fdesc)) continue; + io->i_buf = max(iob[i].i_filesize + iob[i].i_buf, io->i_buf); + } + + // Load entire file into memory. Unnecessary open() calls must + // be avoided. + + gFSLoadAddress = io->i_buf; + io->i_filesize = bvr->fs_loadfile(bvr, (char *)filePath); + if (io->i_filesize < 0) goto error; + + return fdesc; + +error: + close(fdesc); + return -1; } -/*************************************************************************** - * - * Network functions. - * - ***************************************************************************/ +//========================================================================== +// close() - Close a file descriptor. -static int -en_read(int fdesc, char * buf, int count) +int close(int fdesc) { - struct iob * file; + struct iob * io; - if ((file = iob_from_fdesc(fdesc)) == 0) - return (-1); - - DSPRINT(("read[%d]: %x %x %d\n", - fdesc, TFTP_ADDR + file->i_offset, (unsigned) buf, count)); + if ((io = iob_from_fdesc(fdesc)) == NULL) + return (-1); - bcopy((char *)(TFTP_ADDR + file->i_offset), buf, count); - file->i_offset += count; + io->i_flgs = 0; - return count; + return 0; } - -static BOOL -en_open(char * name, struct iob * file, int how) + +//========================================================================== +// lseek() - Reposition the byte offset of the file descriptor from the +// beginning of the file. Returns the relocated offset. + +int b_lseek(int fdesc, int offset, int ptr) { - unsigned long txferSize = TFTP_LEN; - - if (nbpTFTPReadFile(name, &txferSize, TFTP_ADDR) != nbpStatusSuccess) - return NO; + struct iob * io; - file->i_buf = NULL; - file->i_offset = 0; - file->i_ino.i_size = txferSize; // update the real size + if ((io = iob_from_fdesc(fdesc)) == NULL) + return (-1); - return YES; -} + io->i_offset = offset; -static void -en_devopen(char * name, struct iob * io) -{ - io->i_error = 0; + return offset; } -/*************************************************************************** - * - * Dispatch functions. - * - ***************************************************************************/ +//========================================================================== +// tell() - Returns the byte offset of the file descriptor. -/*========================================================================== - * - */ -static int -gen_read(int fdesc, char * buf, int count) +int tell(int fdesc) { - struct iob * file; - - if ((file = iob_from_fdesc(fdesc)) == 0) - return (-1); - - return (file->i_ino.i_dev == DEV_EN) ? - en_read(fdesc, buf, count) : - disk_read(fdesc, buf, count); -} + struct iob * io; -/*========================================================================== - * - */ -static int -gen_open(char * name, struct iob * file, int how) -{ - return (file->i_ino.i_dev == DEV_EN) ? - en_open(name, file, how) : disk_open(name, file, how); + if ((io = iob_from_fdesc(fdesc)) == NULL) + return 0; + + return io->i_offset; } -/*========================================================================== - * - */ -static void -gen_devopen(char * name, struct iob * io) +//========================================================================== +// read() - Read up to 'count' bytes of data from the file descriptor +// into the buffer pointed to by buf. + +int read(int fdesc, char * buf, int count) { - return (io->i_ino.i_dev == DEV_EN) ? - en_devopen(name, io) : devopen(name, io); + struct iob * io; + + if ((io = iob_from_fdesc(fdesc)) == NULL) + return (-1); + + if (io->i_offset + count > io->i_filesize) + count = io->i_filesize - io->i_offset; + + if (count <= 0) + return 0; // end of file + + bcopy(io->i_buf + io->i_offset, buf, count); + + io->i_offset += count; + + return count; } -/*========================================================================== - * - */ -static void -gen_flushdev() +//========================================================================== +// file_size() - Returns the size of the file described by the file +// descriptor. + +int file_size(int fdesc) { - return disk_flushdev(); + struct iob * io; + + if ((io = iob_from_fdesc(fdesc)) == 0) + return 0; + + return io->i_filesize; } -/*========================================================================== - * - */ -static char * -gen_usrDevices() +//========================================================================== + +struct dirstuff * opendir(const char * path) { -#define NET_ARCH_DEVICES "" + struct dirstuff * dirp = 0; + const char * dirPath; + BVRef bvr; + + if ((bvr = getBootVolumeRef(path, &dirPath)) == NULL) + goto error; + + dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff)); + if (dirp == NULL) + goto error; + + dirp->dir_path = newString(dirPath); + if (dirp->dir_path == NULL) + goto error; + + dirp->dir_bvr = bvr; + + return dirp; - return (((currentdev() >> B_TYPESHIFT) & B_TYPEMASK) == DEV_EN) ? - NET_ARCH_DEVICES : ARCH_DEVICES; +error: + closedir(dirp); + return NULL; } -/*************************************************************************** - * - * External functions. - * - ***************************************************************************/ +//========================================================================== -/*========================================================================== - * - */ -struct dirstuff * -opendir(char * path) +int closedir(struct dirstuff * dirp) { - return disk_opendir(path); + if (dirp) { + if (dirp->dir_path) free(dirp->dir_path); + free(dirp); + } + return 0; } -/*========================================================================== - * - */ -int -closedir(struct dirstuff * dirp) +//========================================================================== + +int readdir(struct dirstuff * dirp, const char ** name, long * flags, + long * time) { - return disk_closedir(dirp); + return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr, + /* dirPath */ dirp->dir_path, + /* dirIndex */ &dirp->dir_index, + /* dirEntry */ (char **)name, flags, time ); } -/*========================================================================== - * get next entry in a directory. - */ -struct direct * -readdir(struct dirstuff * dirp) +//========================================================================== + +int currentdev() { - return disk_readdir(dirp); + return kernBootStruct->kernDev; } -/*========================================================================== - * - */ -int -b_lseek(int fdesc, unsigned int addr, int ptr) +//========================================================================== + +int switchdev(int dev) { - register struct iob * io; + kernBootStruct->kernDev = dev; + return dev; +} - RDPRINT(("In lseek addr= %x\n", addr)); +//========================================================================== -#if CHECK_CAREFULLY - if (ptr != 0) { - error("Seek not from beginning of file\n"); - return (-1); - } -#endif /* CHECK_CAREFULLY */ +const char * usrDevices() +{ + return (B_TYPE(currentdev()) == DEV_EN) ? "" : "/private/Drivers/i386"; +} - if ((io = iob_from_fdesc(fdesc)) == 0) { - return (-1); - } - io->i_offset = addr; - io->i_bn = addr / DEV_BSIZE; - io->i_cc = 0; +//========================================================================== - RDPRINT(("In end of lseek offset %x; bn %x\n", io->i_offset,io->i_bn)); +BVRef scanBootVolumes( int biosdev, int * count ) +{ + BVRef bvr = 0; - return (0); + switch ( BIOS_DEV_TYPE( biosdev ) ) + { + case kBIOSDevTypeFloppy: + case kBIOSDevTypeHardDrive: + bvr = diskScanBootVolumes( biosdev, count ); + break; + case kBIOSDevTypeNetwork: + bvr = nbpScanBootVolumes( biosdev, count ); + break; + } + return bvr; } -/*========================================================================== - * - */ -int -tell(int fdesc) -{ - return iob[fdesc].i_offset; -} +//========================================================================== -/*========================================================================== - * - */ -int -read(int fdesc, char * buf, int count) +void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen ) { - return gen_read(fdesc, buf, count); + bvr->description( bvr, str, strMaxLen ); } -/*========================================================================== - * - */ -int -openmem(char * buf, int len) -{ - register struct iob * file; - int fdesc; +//========================================================================== - for (fdesc = 0; fdesc < NFILES; fdesc++) - if (iob[fdesc].i_flgs == 0) - goto gotfile; - stop("Out of file descriptor slots"); +BVRef selectBootVolume( BVRef chain ) +{ + BVRef bvr, bvr1 = 0, bvr2 = 0; -gotfile: - (file = &iob[fdesc])->i_flgs |= F_ALLOC; - file->i_buf = buf; - file->i_boff = len; - file->i_offset = 0; - file->i_flgs |= F_MEM; - return fdesc; -} + for ( bvr = chain; bvr; bvr = bvr->next ) + { + if ( bvr->flags & kBVFlagNativeBoot ) bvr1 = bvr; + if ( bvr->flags & kBVFlagPrimary ) bvr2 = bvr; + } -/*========================================================================== - * Generic open call. - */ -int -open(char * str, int how) -{ - register char * cp; - register struct iob * file; - int fdesc; - - DSPRINT(("In open %s\n", str)); - -#if CHECK_CAREFULLY /* iob[] is in BSS, so it is guaranteed to be zero. */ - if (open_init == 0) { - int i; - for (i = 0; i < NFILES; i++) - iob[i].i_flgs = 0; - open_init = 1; - } -#endif - - for (fdesc = 0; fdesc < NFILES; fdesc++) - if (iob[fdesc].i_flgs == 0) - goto gotfile; - stop("Out of file descriptor slots"); + bvr = bvr1 ? bvr1 : + bvr2 ? bvr2 : chain; -gotfile: - (file = &iob[fdesc])->i_flgs |= F_ALLOC; - - if ((cp = xx(str, file)) == (char *) -1) - { - close(fdesc); - return -1; - } - - if (*cp == '\0') { - file->i_flgs |= how+1; - file->i_cc = 0; - file->i_offset = 0; - return (fdesc); - } - - if (gen_open(cp, file, how) == NO) { - close(fdesc); - return -1; - } - return (fdesc); + return bvr; } -/*========================================================================== - * - */ +//========================================================================== + #define LP '(' #define RP ')' +extern int gBIOSDev; -static char * xx(char *str, struct iob *file) +static BVRef getBootVolumeRef( const char * path, const char ** outPath ) { - register char *cp = str, *xp; - char ** dp; - int old_dev = kernBootStruct->kernDev; - int dev = (kernBootStruct->kernDev >> B_TYPESHIFT) & B_TYPEMASK; - int unit = (kernBootStruct->kernDev >> B_UNITSHIFT) & B_UNITMASK; - int part = (kernBootStruct->kernDev >> B_PARTITIONSHIFT) & B_PARTITIONMASK; - int i; - int no_dev; - int biosOffset; - - biosOffset = unit; // set the device - - for (; *cp && *cp != LP; cp++) ; - if (no_dev = !*cp) { // no left paren found - cp = str; - xp = devsw[dev]; - } else if (cp == str) { // paren but no device - cp++; - xp = devsw[dev]; - } else { - xp = str; - cp++; - } - - for (dp = devsw; *dp; dp++) - { - if ((xp[0] == *dp[0]) && (xp[1] == *(dp[0] + 1))) - goto gotdev; - } - - error("Unknown device '%c%c'\n",xp[0],xp[1]); - return ((char *)-1); - -gotdev: - if (no_dev) - goto none; - i = 0; - while (*cp >= '0' && *cp <= '9') - { - i = i * 10 + *cp++ - '0'; - unit = i; // get the specified unit number - } - - biosOffset = unit; // set the device - - if (*cp == RP || no_dev) - /* do nothing since ptol(")") returns 0 */ ; - else if (*cp == ',') - part = ptol(++cp); // get the specified partition number - else if (cp[-1] == LP) - part = ptol(cp); - else { -badoff: - error("Missing offset specification\n"); - return ((char *)-1); - } - - for ( ;!no_dev ;) { // skip after the right paren - if (*cp == RP) - break; - if (*cp++) - continue; - goto badoff; - } - -none: - file->i_ino.i_dev = dev = dp - devsw; - file->partition = part; - file->biosdev = (BIOSDEV(dev)) + biosOffset; - - if (dev == DEV_SD) { - file->biosdev += kernBootStruct->numIDEs; - } - else if (dev == DEV_EN) { - file->biosdev = BIOS_DEV_EN; + const char * cp; + BVRef bvr; + int type = B_TYPE( kernBootStruct->kernDev ); + int unit = B_UNIT( kernBootStruct->kernDev ); + int part = B_PARTITION( kernBootStruct->kernDev ); + int biosdev = gBIOSDev; + static BVRef lastBVR = 0; + static int lastKernDev; + + // Search for left parenthesis in the path specification. + + for (cp = path; *cp; cp++) { + if (*cp == LP || *cp == '/') break; } - else if (dev == DEV_HD && kernBootStruct->numIDEs == 0) { - error("No IDE drives detected\n"); - return ((char *)-1); - } - kernBootStruct->kernDev = (dev << B_TYPESHIFT) | - (unit << B_UNITSHIFT) | - (part << B_PARTITIONSHIFT); + if (*cp != LP) // no left paren found + { + cp = path; + if ( lastBVR && lastKernDev == kernBootStruct->kernDev ) + { + bvr = lastBVR; + goto quick_exit; + } + } + else if ((cp - path) == 2) // found "xx(" + { + const struct devsw * dp; + const char * xp = path; + int i; + + cp++; + + // Check the 2 character device name pointed by 'xp'. + + for (dp = devsw; dp->name; dp++) + { + if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1])) + break; // found matching entry + } + if (dp->name == NULL) + { + error("Unknown device '%c%c'\n", xp[0], xp[1]); + return NULL; + } + type = dp - devsw; // kerndev type + + // Extract the optional unit number from the specification. + // hd(unit) or hd(unit, part). + + i = 0; + while (*cp >= '0' && *cp <= '9') + { + i = i * 10 + *cp++ - '0'; + unit = i; + } + + // Extract the optional partition number from the specification. + + if (*cp == ',') + part = atoi(++cp); + + // Skip past the right paren. + + for ( ; *cp && *cp != RP; cp++) /* LOOP */; + if (*cp == RP) cp++; + + biosdev = dp->biosdev; + } + else + { + // Bad device specifier, skip past the right paren. - if (kernBootStruct->kernDev != old_dev) - flushdev(); + for ( cp++; *cp && *cp != RP; cp++) /* LOOP */; + if (*cp == RP) cp++; + } - gen_devopen(str, file); + biosdev += (unit & kBIOSDevUnitMask); - if (file->i_error) - return (char *)-1; - if (!no_dev && *cp) cp++; + if ((bvr = newBootVolumeRef(biosdev, part)) == NULL) + { + // error("newBootVolumeRef() error\n"); + return NULL; + } - gFilename = cp; + // Record the most recent device parameters in the + // KernBootStruct. - return cp; -} + kernBootStruct->kernDev = MAKEKERNDEV(type, unit, bvr->part_no); -/*========================================================================== - * - */ -int -close(int fdesc) -{ - register struct iob * file; - register int i; - - if ((file = iob_from_fdesc(fdesc)) == 0) - return (-1); - - if ((file->i_flgs & F_MEM) == 0) { -// free((char *)file->i_ffs); - file->i_ffs = NULL; - if (file->i_buf) { - free(file->i_buf); - file->i_buf = NULL; - } - for (i=0;ii_flgs = 0; - return (0); -} + lastBVR = bvr; + lastKernDev = kernBootStruct->kernDev; -/*========================================================================== - * - */ -int -file_size(int fdesc) -{ - register struct iob * io; - - if ((io = iob_from_fdesc(fdesc)) == 0) - return (-1); +quick_exit: + // Returns the file path following the device spec. + // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'. - return io->i_ino.i_size; -} + *outPath = cp; -/*========================================================================== - * ensure that all device caches are flushed, - * because we are about to change the device media - */ -void -flushdev() -{ - gen_flushdev(); + return bvr; } -/*========================================================================== - * - */ -void -stop(char * s) -{ -#if CHECK_CAREFULLY - register int i; - - for (i = 0; i < NFILES; i++) - if (iob[i].i_flgs != 0) - close(i); -#endif CHECK_CAREFULLY - - /* textMode(); */ // can't call this function from here - error("\n%s\n", s); - sleep(4); // about to halt - halt(); -} +//========================================================================== -/*========================================================================== - * - */ -int currentdev() +static BVRef newBootVolumeRef( int biosdev, int partno ) { - return kernBootStruct->kernDev; -} + BVRef bvr, bvr1, bvrChain; -/*========================================================================== - * - */ -int -switchdev(int dev) -{ - flushdev(); - kernBootStruct->kernDev = dev; - return dev; -} + // Fetch the volume list from the device. -/*========================================================================== - * - */ -char * -usrDevices() -{ - return gen_usrDevices(); + bvrChain = scanBootVolumes( biosdev, NULL ); + + // Look for a perfect match based on device and partition number. + + for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next ) + { + if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue; + + bvr1 = bvr; + if ( bvr->part_no == partno ) break; + } + + return bvr ? bvr : bvr1; } diff --git a/i386/libsaio/table.c b/i386/libsaio/table.c index aa5c40e..35d2117 100644 --- a/i386/libsaio/table.c +++ b/i386/libsaio/table.c @@ -46,9 +46,6 @@ #include "memory.h" -#define NGDTENT 6 -#define GDTLIMIT 48 /* NGDTENT * 8 */ - /* Segment Descriptor * * 31 24 19 16 7 0 @@ -64,23 +61,39 @@ */ struct seg_desc { - unsigned short limit_15_0; - unsigned short base_15_0; - unsigned char base_23_16; - unsigned char bit_15_8; - unsigned char bit_23_16; - unsigned char base_31_24; - }; + unsigned short limit_15_0; + unsigned short base_15_0; + unsigned char base_23_16; + unsigned char bit_15_8; + unsigned char bit_23_16; + unsigned char base_31_24; +}; +struct seg_desc Gdt[ NGDTENT ] = { + /* 0x0 : null */ + {0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00}, -struct seg_desc Gdt[NGDTENT] = { - {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* 0x0 : null */ - // byte granularity, 1Mb limit, MEMBASE offset - {0xFFFF, MEMBASE, 0x0, 0x9E, 0x4F, 0x0}, /* 0x8 : boot code */ - // dword granularity, 2Gb limit, MEMBASE offset - {0xFFFF, MEMBASE, 0x0, 0x92, 0xCF, 0x0}, /* 0x10 : boot data */ - {0xFFFF, MEMBASE, 0x0, 0x9E, 0xF, 0x0}, /* 0x18 : boot code, 16 bits */ - {0xFFFF, 0x0, 0x0, 0x92, 0xCF, 0x0}, /* 0x20 : init data */ - {0xFFFF, 0x0, 0x0, 0x9E, 0xCF, 0x0} /* 0x28 : init code */ -}; + /* 0x8 : boot protected mode 32-bit code segment + byte granularity, 1MB limit, MEMBASE offset */ + {0xFFFF, MEMBASE, 0x00, 0x9E, 0x4F, 0x00}, + + /* 0x10 : boot protected mode data segment + page granularity, 4GB limit, MEMBASE offset */ + {0xFFFF, MEMBASE, 0x00, 0x92, 0xCF, 0x00}, + + /* 0x18 : boot protected mode 16-bit code segment + byte granularity, 1MB limit, MEMBASE offset */ + {0xFFFF, MEMBASE, 0x00, 0x9E, 0x0F, 0x00}, + /* 0x20 : kernel init 32-bit data segment + page granularity, 4GB limit, zero offset */ + {0xFFFF, 0x0000, 0x00, 0x92, 0xCF, 0x00}, + + /* 0x28 : kernel init 32-bit code segment + page granularity, 4GB limit, zero offset */ + {0xFFFF, 0x0000, 0x00, 0x9E, 0xCF, 0x00}, + + /* 0x30 : boot real mode data/stack segment + byte granularity, 64K limit, MEMBASE offset, expand-up */ + {0xFFFF, MEMBASE, 0x00, 0x92, 0x00, 0x00}, +}; diff --git a/i386/libsaio/ufs.c b/i386/libsaio/ufs.c new file mode 100644 index 0000000..059a133 --- /dev/null +++ b/i386/libsaio/ufs.c @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * ufs.c - File System Module for UFS. + * + * Copyright (c) 1998-2002 Apple Computer, Inc. + * + * DRI: Josh de Cesare + */ + +#include + +#include "ufs_byteorder.h" + +typedef struct dinode Inode, *InodePtr; + +// Private function prototypes + +static char *ReadBlock(long fragNum, long fragOffset, long length, + char *buffer, long cache); +static long ReadInode(long inodeNum, InodePtr inode, long *flags, long *time); +static long ResolvePathToInode(char *filePath, long *flags, + InodePtr fileInode, InodePtr dirInode); +static long ReadDirEntry(InodePtr dirInode, long *fileInodeNum, + long *dirIndex, char **name); +static long FindFileInDir(char *fileName, long *flags, + InodePtr fileInode, InodePtr dirInode); +static char *ReadFileBlock(InodePtr fileInode, long fragNum, long blockOffset, + long length, char *buffer, long cache); +static long ReadFile(InodePtr fileInode, long *length); + +#define kDevBlockSize (0x200) // Size of each disk block. +#define kDiskLableBlock (15) // Block the DL is in. + +#ifdef __i386__ + +static CICell gCurrentIH; +static long long gPartitionBase; +static char *gDLBuf; +static char *gFSBuf; +static struct fs *gFS; +static long gBlockSize; +static long gFragSize; +static long gFragsPerBlock; +static char *gTempBlock; +static char *gTempName; +static char *gTempName2; +static InodePtr gRootInodePtr; +static InodePtr gFileInodePtr; + +#else /* !__i386__ */ + +static CICell gCurrentIH; +static long long gPartitionBase; +static char gDLBuf[8192]; +static char gFSBuf[SBSIZE]; +static struct fs *gFS; +static long gBlockSize; +static long gFragSize; +static long gFragsPerBlock; +static char *gTempBlock; +static char gTempName[MAXNAMLEN + 1]; +static char gTempName2[MAXNAMLEN + 1]; +static Inode _gRootInode; +static Inode _gFileInode; +static InodePtr gRootInodePtr = &_gRootInode; +static InodePtr gFileInodePtr = &_gFileInode; + +#endif /* !__i386__ */ + +// Public functions + +long UFSInitPartition( CICell ih ) +{ + if (ih == gCurrentIH) { +#ifdef __i386__ + CacheInit(ih, gBlockSize); +#endif + return 0; + } + + verbose("UFSInitPartition: %x\n", ih); + + gCurrentIH = 0; + +#ifdef __i386__ + if (!gDLBuf) gDLBuf = (char *) malloc(8192); + if (!gFSBuf) gFSBuf = (char *) malloc(SBSIZE); + if (!gTempName) gTempName = (char *) malloc(MAXNAMLEN + 1); + if (!gTempName2) gTempName2 = (char *) malloc(MAXNAMLEN + 1); + if (!gRootInodePtr) gRootInodePtr = (InodePtr) malloc(sizeof(Inode)); + if (!gFileInodePtr) gFileInodePtr = (InodePtr) malloc(sizeof(Inode)); + if (!gDLBuf || !gFSBuf || !gTempName || !gTempName2 || + !gRootInodePtr || !gFileInodePtr) return -1; +#endif + + // Assume there is no Disk Label + gPartitionBase = 0; + + // Look for the Super Block + Seek(ih, gPartitionBase + SBOFF); + Read(ih, (long)gFSBuf, SBSIZE); + + gFS = (struct fs *)gFSBuf; + byte_swap_superblock(gFS); + + if (gFS->fs_magic != FS_MAGIC) { +#ifdef __i386__ + return -1; // not yet for Intel +#else /* !__i386__ */ + disk_label_t *dl; + partition_t *part; + + // Did not find it... Look for the Disk Label. + // Look for the Disk Label + Seek(ih, 1ULL * kDevBlockSize * kDiskLableBlock); + Read(ih, (long)gDLBuf, 8192); + + dl = (disk_label_t *)gDLBuf; + byte_swap_disklabel_in(dl); + + if (dl->dl_version != DL_VERSION) { + return -1; + } + + part = &dl->dl_part[0]; + gPartitionBase = (1ULL * (dl->dl_front + part->p_base) * dl->dl_secsize) - + (1ULL * (dl->dl_label_blkno - kDiskLableBlock) * kDevBlockSize); + + // Re-read the Super Block. + Seek(ih, gPartitionBase + SBOFF); + Read(ih, (long)gFSBuf, SBSIZE); + + gFS = (struct fs *)gFSBuf; + if (gFS->fs_magic != FS_MAGIC) { + return -1; + } +#endif /* !__i386__ */ + } + + // Calculate the block size and set up the block cache. + gBlockSize = gFS->fs_bsize; + gFragSize = gFS->fs_fsize; + gFragsPerBlock = gBlockSize / gFragSize; + if (gTempBlock != 0) free(gTempBlock); + gTempBlock = malloc(gBlockSize); + CacheInit(ih, gBlockSize); + + gCurrentIH = ih; + + // Read the Root Inode + ReadInode(ROOTINO, gRootInodePtr, 0, 0); + + return 0; +} + +long UFSLoadFile( CICell ih, char * filePath ) +{ + long ret, length, flags; + + if (UFSInitPartition(ih) == -1) return -1; + + verbose("Loading UFS file: [%s] from %x.\n", filePath, (unsigned)ih); + + // Skip one or two leading '/'. + if (*filePath == '/') filePath++; + if (*filePath == '/') filePath++; + + ret = ResolvePathToInode(filePath, &flags, gFileInodePtr, gRootInodePtr); + if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) return -1; + +#if 0 + // System.config/Default.table will fail this check. + // Turn this back on when usage of System.config is deprecated. + if (flags & (kOwnerNotRoot | kPermGroupWrite | kPermOtherWrite)) return -1; +#endif + + ret = ReadFile(gFileInodePtr, &length); + if (ret == -1) return -1; + + return length; +} + +long UFSGetDirEntry( CICell ih, char * dirPath, long * dirIndex, + char ** name, long * flags, long * time ) +{ + long ret, fileInodeNum, dirFlags; + Inode tmpInode; + + if (UFSInitPartition(ih) == -1) return -1; + + // Skip a leading '/' if present + if (*dirPath == '/') dirPath++; + if (*dirPath == '/') dirPath++; + + ret = ResolvePathToInode(dirPath, &dirFlags, gFileInodePtr, gRootInodePtr); + if ((ret == -1) || ((dirFlags & kFileTypeMask) != kFileTypeDirectory)) + return -1; + + ret = ReadDirEntry(gFileInodePtr, &fileInodeNum, dirIndex, name); + if (ret != 0) return ret; + + ReadInode(fileInodeNum, &tmpInode, flags, time); + + return 0; +} + +// Private functions + +static char * ReadBlock( long fragNum, long blockOffset, long length, + char * buffer, long cache ) +{ + long long offset; + long blockNum; + + blockNum = fragNum / gFragsPerBlock; + fragNum -= blockNum * gFragsPerBlock; + + blockOffset += fragNum * gFragSize; + + offset = gPartitionBase + 1ULL * blockNum * gBlockSize; + + if (cache && ((blockOffset + length) <= gBlockSize)) { + CacheRead(gCurrentIH, gTempBlock, offset, gBlockSize, 1); + if (buffer != 0) bcopy(gTempBlock + blockOffset, buffer, length); + else buffer = gTempBlock + blockOffset; + } else { + offset += blockOffset; + CacheRead(gCurrentIH, buffer, offset, length, 0); + } + + return buffer; +} + +static long ReadInode( long inodeNum, InodePtr inode, long * flags, long * time ) +{ + long fragNum = ino_to_fsba(gFS, inodeNum); + long blockOffset = ino_to_fsbo(gFS, inodeNum) * sizeof(Inode); + + ReadBlock(fragNum, blockOffset, sizeof(Inode), (char *)inode, 1); + byte_swap_dinode_in(inode); + + if (time != 0) *time = inode->di_mtime; + + if (flags != 0) { + switch (inode->di_mode & IFMT) { + case IFREG: *flags = kFileTypeFlat; break; + case IFDIR: *flags = kFileTypeDirectory; break; + case IFLNK: *flags = kFileTypeLink; break; + default : *flags = kFileTypeUnknown; break; + } + + *flags |= inode->di_mode & kPermMask; + + if (inode->di_uid != 0) *flags |= kOwnerNotRoot; + } + + return 0; +} + +static long ResolvePathToInode( char * filePath, long * flags, + InodePtr fileInode, InodePtr dirInode ) +{ + char * restPath; + long ret, cnt; + + // if filePath is empty the we want this directory. + if (*filePath == '\0') { + bcopy((char *)dirInode, (char *)fileInode, sizeof(Inode)); + return 0; + } + + // Copy the file name to gTempName + cnt = 0; + while ((filePath[cnt] != '/') && (filePath[cnt] != '\0')) cnt++; + strncpy(gTempName, filePath, cnt); + + // Move restPath to the right place. + if (filePath[cnt] != '\0') cnt++; + restPath = filePath + cnt; + + // gTempName is a name in the current Dir. + // restPath is the rest of the path if any. + + ret = FindFileInDir(gTempName, flags, fileInode, dirInode); + if (ret == -1) return -1; + + if ((*restPath != '\0') && ((*flags & kFileTypeMask) == kFileTypeDirectory)) + ret = ResolvePathToInode(restPath, flags, fileInode, fileInode); + + return ret; +} + +static long ReadDirEntry( InodePtr dirInode, long * fileInodeNum, + long * dirIndex, char ** name ) +{ + struct direct *dir; + char *buffer; + long index; + long dirBlockNum, dirBlockOffset; + + while (1) { + index = *dirIndex; + + dirBlockOffset = index % DIRBLKSIZ; + dirBlockNum = index / DIRBLKSIZ; + + buffer = ReadFileBlock(dirInode, dirBlockNum, 0, DIRBLKSIZ, 0, 1); + if (buffer == 0) return -1; + + dir = (struct direct *)(buffer + dirBlockOffset); + byte_swap_dir_block_in((char *)dir, 1); + + *dirIndex += dir->d_reclen; + + if (dir->d_ino != 0) break; + + if (dirBlockOffset != 0) return -1; + } + + *fileInodeNum = dir->d_ino; + *name = strncpy(gTempName2, dir->d_name, dir->d_namlen); + + return 0; +} + +static long FindFileInDir( char * fileName, long * flags, + InodePtr fileInode, InodePtr dirInode ) +{ + long ret, inodeNum, index = 0; + char *name; + + while (1) { + ret = ReadDirEntry(dirInode, &inodeNum, &index, &name); + if (ret == -1) return -1; + + if (strcmp(fileName, name) == 0) break; + } + + ReadInode(inodeNum, fileInode, flags, 0); + + return 0; +} + +static char * ReadFileBlock( InodePtr fileInode, long fragNum, long blockOffset, + long length, char * buffer, long cache ) +{ + long fragCount, blockNum; + long diskFragNum, indFragNum, indBlockOff, refsPerBlock; + char *indBlock; + + fragCount = (fileInode->di_size + gFragSize - 1) / gFragSize; + if (fragNum >= fragCount) return 0; + + refsPerBlock = gBlockSize / sizeof(ufs_daddr_t); + + blockNum = fragNum / gFragsPerBlock; + fragNum -= blockNum * gFragsPerBlock; + + // Get Direct Block Number. + if (blockNum < NDADDR) { + diskFragNum = fileInode->di_db[blockNum]; + } else { + blockNum -= NDADDR; + + // Get Single Indirect Fragment Number. + if (blockNum < refsPerBlock) { + indFragNum = fileInode->di_ib[0]; + } else { + blockNum -= refsPerBlock; + + // Get Double Indirect Fragment Number. + if (blockNum < (refsPerBlock * refsPerBlock)) { + indFragNum = fileInode->di_ib[1]; + } else { + blockNum -= refsPerBlock * refsPerBlock; + + // Get Triple Indirect Fragment Number. + indFragNum = fileInode->di_ib[2]; + + indBlock = ReadBlock(indFragNum, 0, gBlockSize, 0, 1); + indBlockOff = blockNum / (refsPerBlock * refsPerBlock); + blockNum %= (refsPerBlock * refsPerBlock); + indFragNum = SWAP_BE32(((ufs_daddr_t *)indBlock)[indBlockOff]); + } + + indBlock = ReadBlock(indFragNum, 0, gBlockSize, 0, 1); + indBlockOff = blockNum / refsPerBlock; + blockNum %= refsPerBlock; + indFragNum = SWAP_BE32(((ufs_daddr_t *)indBlock)[indBlockOff]); + } + + indBlock = ReadBlock(indFragNum, 0, gBlockSize, 0, 1); + diskFragNum = SWAP_BE32(((ufs_daddr_t *)indBlock)[blockNum]); + } + + buffer = ReadBlock(diskFragNum+fragNum, blockOffset, length, buffer, cache); + + return buffer; +} + +static long ReadFile( InodePtr fileInode, long * length ) +{ + long bytesLeft, curSize, curFrag = 0; + char *buffer, *curAddr = (char *)kLoadAddr; + +#ifdef __i386__ + curAddr = gFSLoadAddress; +#endif + + bytesLeft = *length = fileInode->di_size; + + if (*length > kLoadSize) { + printf("File is too large.\n"); + return -1; + } + + while (bytesLeft) { + if (bytesLeft > gBlockSize) curSize = gBlockSize; + else curSize = bytesLeft; + + buffer = ReadFileBlock(fileInode, curFrag, 0, curSize, curAddr, 0); + if (buffer == 0) break; + + curFrag += gFragsPerBlock; + curAddr += curSize; + bytesLeft -= curSize; + } + + return bytesLeft; +} diff --git a/i386/libsaio/ufs_byteorder.c b/i386/libsaio/ufs_byteorder.c index a49b56f..f55ac08 100644 --- a/i386/libsaio/ufs_byteorder.c +++ b/i386/libsaio/ufs_byteorder.c @@ -26,9 +26,9 @@ * All rights reserved. */ -#include -#include -#include +#include +#include +#include #include #include #include "ufs_byteorder.h" diff --git a/i386/libsaio/ufs_byteorder.h b/i386/libsaio/ufs_byteorder.h index ad4f2f9..ef0c37e 100644 --- a/i386/libsaio/ufs_byteorder.h +++ b/i386/libsaio/ufs_byteorder.h @@ -36,13 +36,13 @@ #ifndef __LIBSAIO_UFS_BYTEORDER_H #define __LIBSAIO_UFS_BYTEORDER_H -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include void byte_swap_ints(int *array, int count); void byte_swap_shorts(short *array, int count); @@ -54,5 +54,6 @@ void byte_swap_disktab_in(struct disktab *dt); void byte_swap_partition(struct partition *part); void byte_swap_dinode_in(struct dinode *di); void byte_swap_dir_block_in(char *addr, int count); +void byte_swap_inode_in(struct dinode *dc, struct dinode *ic); #endif /* !__LIBSAIO_UFS_BYTEORDER_H */ diff --git a/i386/libsaio/vbe.c b/i386/libsaio/vbe.c index 36c11f8..a195171 100644 --- a/i386/libsaio/vbe.c +++ b/i386/libsaio/vbe.c @@ -25,22 +25,9 @@ * Copyright 1993 NeXT, Inc. * All rights reserved. */ -#include "io_inline.h" + #include "libsaio.h" -#include "vga.h" #include "vbe.h" -#include "kernBootStruct.h" -#include "appleClut8.h" - -/* - * Graphics mode settings. - */ -BOOL in_linear_mode; -unsigned char * frame_buffer; -unsigned short screen_width; -unsigned short screen_height; -unsigned char bits_per_pixel; -unsigned short screen_rowbytes; /* * Various inline routines for video I/O @@ -72,160 +59,27 @@ rmwi (int port, int index, int clear, int set) outb (port + 1, (inb (port + 1) & ~clear) | set); } -/* - * Local Prototypes - */ -void setupPalette(VBEPalette * p, const unsigned char * g); - /* * Globals */ static biosBuf_t bb; -#if 0 -static char *models[] = { "Text", - "CGA", - "Hercules", - "Planar", - "Packed Pixel", - "Non-Chain 4", - "Direct Color", - "YUV" }; -#endif - -int -set_linear_video_mode(unsigned short mode) -{ - VBEInfoBlock vinfo; - VBEModeInfoBlock minfo; - int err; - VBEPalette palette; - - do { - /* - * See if VESA is around. - */ - err = getVBEInfo(&vinfo); - if (err != errSuccess) - { - printf("VESA not available.\n"); - break; - } - -#if 0 - /* - * See if this mode is supported. - */ - err = getVBEModeInfo(mode, &minfo); - if ( !((err == errSuccess) && - (minfo.ModeAttributes & maModeIsSupportedBit) && - (minfo.ModeAttributes & maGraphicsModeBit) /* && - (minfo.ModeAttributes & maLinearFrameBufferAvailBit)*/) ) - { - printf("Mode %d is not supported.\n", mode); - err = errFuncNotSupported; - break; - } -#endif - - /* - * Set the mode. - */ - err = setVBEMode(mode | kLinearFrameBufferBit ); - if ( err != errSuccess ) - { - if (vinfo.VESAVersion < MIN_VESA_VERSION) - { - printf("Video Card is VESA %d.%d. It must be at least VESA %d.%d\n", - vinfo.VESAVersion >> 8, - vinfo.VESAVersion & 0xff, - MIN_VESA_VERSION >> 8, - MIN_VESA_VERSION & 0xff); - } - else - { - printf("Error #%d in set video mode.\n", err); - } - break; - } - - /* - * Get mode info. - */ - err = getVBEModeInfo(mode, &minfo); - if ( err != errSuccess ) - { - printf("Error #%d in get mode info.\n", err); - break; - } - - /* - * Set the palette. - */ - if (( vinfo.VESAVersion >= MIN_VESA_VERSION ) && - ( minfo.BitsPerPixel == 8 )) - { - setupPalette(&palette, appleClut8); - if ((err = setVBEPalette(palette)) != errSuccess) - { - printf("Error #%d in setting palette.\n", err); - break; - } - } - - err = errSuccess; - in_linear_mode = YES; - screen_width = minfo.XResolution; - screen_height = minfo.YResolution; - bits_per_pixel = minfo.BitsPerPixel; - screen_rowbytes = minfo.BytesPerScanline; - - /* The S3 video card reports 15 bits... the video console driver - * Can't deal.. set it to 16. - */ - if (bits_per_pixel > 8 && bits_per_pixel < 16) - bits_per_pixel = 16; - - frame_buffer = (unsigned char *) ADDRESS(minfo.PhysBasePtr_low, - minfo.PhysBasePtr_1, - minfo.PhysBasePtr_2, - minfo.PhysBasePtr_high); - } - while ( 0 ); - - return err; -} - -void setupPalette(VBEPalette * p, const unsigned char * g) +int getVBEInfo( void * infoBlock ) { - int i; - unsigned char * source = (unsigned char *) g; - - for (i = 0; i < 256; i++) - { - (*p)[i] = 0; - (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 16; // Red - (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 8; // Green - (*p)[i] |= ((unsigned long)((*source++) >> 2)); // Blue - } -} - -int getVBEInfo(void *vinfo_p) -{ - bb.intno = 0x10; + bb.intno = 0x10; bb.eax.rr = funcGetControllerInfo; - bb.es = SEG(vinfo_p); - bb.edi.rr = OFF(vinfo_p); - bios(&bb); + bb.es = SEG( infoBlock ); + bb.edi.rr = OFF( infoBlock ); + bios( &bb ); return(bb.eax.r.h); } -int getVBEModeInfo(int mode, void *minfo_p) +int getVBEModeInfo( int mode, void * minfo_p ) { - bb.intno = 0x10; + bb.intno = 0x10; bb.eax.rr = funcGetModeInfo; bb.ecx.rr = mode; - bb.es = SEG(minfo_p); + bb.es = SEG(minfo_p); bb.edi.rr = OFF(minfo_p); bios(&bb); return(bb.eax.r.h); diff --git a/i386/libsaio/vbe.h b/i386/libsaio/vbe.h index 62e5c04..5481f8c 100644 --- a/i386/libsaio/vbe.h +++ b/i386/libsaio/vbe.h @@ -35,30 +35,26 @@ #ifndef __LIBSAIO_VBE_H #define __LIBSAIO_VBE_H -/* - * Graphics mode settings. - */ -extern BOOL in_linear_mode; -extern unsigned char * frame_buffer; -extern unsigned short screen_width; -extern unsigned short screen_height; -extern unsigned char bits_per_pixel; -extern unsigned short screen_rowbytes; - #define MIN_VESA_VERSION 0x200 #define SEG(address) \ ((unsigned short)(((unsigned long)address & 0xffff0000) >> 4)) -#define OFF(address) ((unsigned short)((unsigned long)address & 0x0000ffff)) -#define RTOV(low, one, two, high) \ - (((unsigned long)high << 12) | ((unsigned long)one << 8) | \ - (unsigned long)low) -#define ADDRESS(low, one, two, high) \ - (((unsigned long)high << 24) | ((unsigned long)two << 16) | \ - ((unsigned long)one << 8) | (unsigned long)low) + +#define OFF(address) \ + ((unsigned short)((unsigned long)address & 0x0000ffff)) + +#define VBEMakeUInt32(x) \ + (((unsigned long)x##_high << 24) | \ + ((unsigned long)x##_2 << 16) | \ + ((unsigned long)x##_1 << 8) | \ + (unsigned long)x##_low) + +#define VBEDecodeFP(t, fp) \ + ((t)(((fp ## _low) | ((fp ## _1 ) << 8)) + \ + (((fp ## _2) << 4) | ((fp ## _high ) << 12)))) /* - * Functions + * Functions */ enum { funcGetControllerInfo = 0x4F00, @@ -120,9 +116,9 @@ typedef struct { * Capabilites */ enum { - capDACWidthIsSwitchableBit = (1 << 0), /* 1 = yes; 0 = no */ - capControllerIsNotVGACompatableBit = (1 << 1), /* 1 = no; 0 = yes */ - capOldRAMDAC = (1 << 2) /* 1 = yes; 0 = no */ + capDACWidthIsSwitchableBit = (1 << 0), /* 1 = yes; 0 = no */ + capControllerIsNotVGACompatableBit = (1 << 1), /* 1 = no; 0 = yes */ + capOldRAMDAC = (1 << 2) /* 1 = yes; 0 = no */ }; /* @@ -182,7 +178,7 @@ enum { }; /* - * Modes + * Modes */ enum { mode640x400x256 = 0x100, @@ -213,11 +209,12 @@ enum { mode1280x1024x555 = 0x119, mode1280x1024x565 = 0x11A, mode1280x1024x888 = 0x11B, - modeSpecial = 0x81FF + modeSpecial = 0x81FF, + modeEndOfList = 0xFFFF }; /* - * Get/Set VBE Mode parameters + * Get/Set VBE Mode parameters */ enum { kLinearFrameBufferBit = (1 << 14), diff --git a/i386/libsaio/vga.c b/i386/libsaio/vga.c deleted file mode 100644 index c1dd659..0000000 --- a/i386/libsaio/vga.c +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright 1993 NeXT, Inc. - * All rights reserved. - */ -#include "io_inline.h" -#include "libsaio.h" -#include "vga.h" - -#define VGA_SEQ_CNT 5 -#define VGA_CRT_CNT 25 -#define VGA_ATR_CNT 21 -#define VGA_GFX_CNT 9 - -typedef struct VGAState { - /* Miscellaneous output register. */ - unsigned char miscOutput; - /* Sequencer registers. */ - unsigned char sequencerData[VGA_SEQ_CNT]; - /* CRT Controller registers. */ - unsigned char crtcData[VGA_CRT_CNT]; - /* Graphics controller registers. */ - unsigned char graphicsData[VGA_GFX_CNT]; - /* Attribute controller registers. */ - unsigned char attrData[VGA_ATR_CNT]; -} VGAState; - -#if 0 -/* VGA Mode 0x03. */ - -static const VGAState VGAMode3 = { - /* Miscellaneous output register. */ - 0x67, - /* Sequencer registers. */ - { 0x01, 0x00, 0x03, 0x00, 0x02 }, - /* CRT controller registers. */ - { - 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00, 0x4f, - 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, - 0x1f, 0x96, 0xb9, 0xa3, 0xff, - }, - /* Graphics controller registers. */ - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff }, - /* Attribute controller registers. */ - { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, - 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x0c, 0x00, 0x0f, 0x08, - 0x00, - }, -}; -#endif - -/* VGA Mode 0x12. */ - -static const VGAState VGAMode12 = { - /* Miscellaneous output register. */ - 0xe3, - /* Sequencer registers. */ - {0x03, 0x21, 0x0f, 0x00, 0x06}, - /* CRT controller registers. */ - { - 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0xea, 0x8c, - 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3, 0xff, - }, - /* Graphics controller registers. */ - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, - /* Attribute controller registers. */ - { - 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, - 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, - 0x01, 0x00, - 0x03, 0x00, - 0x00, - }, -}; - -#define palette_entry(r,g,b) (((r) << 4)|((g) << 2)|(b)) - -static const unsigned char colorData[4] = { - 0x00, 0x15, 0x2a, 0x3f, -}; - -#ifdef NOTYET -static const unsigned char mode_03_palette[] = { - palette_entry(0, 0, 0), - palette_entry(0, 0, 2), - palette_entry(0, 2, 0), - palette_entry(0, 2, 2), - palette_entry(2, 0, 0), - palette_entry(2, 0, 2), - palette_entry(2, 2, 0), - palette_entry(2, 2, 2), - palette_entry(0, 0, 1), - palette_entry(0, 0, 3), - palette_entry(0, 2, 1), - palette_entry(0, 2, 3), - palette_entry(2, 0, 1), - palette_entry(2, 0, 3), - palette_entry(2, 2, 1), - palette_entry(2, 2, 3), - palette_entry(0, 1, 0), - palette_entry(0, 1, 2), - palette_entry(0, 3, 0), - palette_entry(0, 3, 2), - palette_entry(2, 1, 0), - palette_entry(2, 1, 2), - palette_entry(2, 3, 0), - palette_entry(2, 3, 2), - palette_entry(0, 1, 1), - palette_entry(0, 1, 3), - palette_entry(0, 3, 1), - palette_entry(0, 3, 3), - palette_entry(2, 1, 1), - palette_entry(2, 1, 3), - palette_entry(2, 3, 1), - palette_entry(2, 3, 3), - palette_entry(1, 0, 0), - palette_entry(1, 0, 2), - palette_entry(1, 2, 0), - palette_entry(1, 2, 2), - palette_entry(3, 0, 0), - palette_entry(3, 0, 2), - palette_entry(3, 2, 0), - palette_entry(3, 2, 2), - palette_entry(1, 0, 1), - palette_entry(1, 0, 3), - palette_entry(1, 2, 1), - palette_entry(1, 2, 3), - palette_entry(3, 0, 1), - palette_entry(3, 0, 3), - palette_entry(3, 2, 1), - palette_entry(3, 2, 3), - palette_entry(1, 1, 0), - palette_entry(1, 1, 2), - palette_entry(1, 3, 0), - palette_entry(1, 3, 2), - palette_entry(3, 1, 0), - palette_entry(3, 1, 2), - palette_entry(3, 3, 0), - palette_entry(3, 3, 2), - palette_entry(1, 1, 1), - palette_entry(1, 1, 3), - palette_entry(1, 3, 1), - palette_entry(1, 3, 3), - palette_entry(3, 1, 1), - palette_entry(3, 1, 3), - palette_entry(3, 3, 1), - palette_entry(3, 3, 3), -}; -#endif NOTYET - -static void -spin(volatile int count) -{ - while (count--) - count = count; -} - -void -set_video_mode(unsigned int mode) -{ - register unsigned int j, k; - const VGAState * state; - extern unsigned short screen_width; - extern unsigned short screen_height; - - screen_width = 640; - screen_height = 480; - - switch (mode) { - case 0x02: - case 0x03: - video_mode(mode); - return; - /* - state = &VGAMode3; - break; - */ - case 0x12: - state = &VGAMode12; - break; - default: - return; - } - - /* Turn the video off while we are doing this.... */ - outb(VGA_SEQ_INDEX, 1); - outb(VGA_SEQ_DATA, state->sequencerData[1]); - - /* Set the attribute flip-flop to "index" */ - inb(VGA_INPUT_STATUS_1); - - /* Give palette to CPU, turns off video */ - outb(VGA_WRITE_ATTR_INDEX, 0x00); - - /* Set the general registers */ - outb(VGA_WRITE_MISC_PORT, state->miscOutput); - outb(VGA_WRITE_FEATURE_PORT, 0x00); - - /* Load the sequencer registers */ - for (k = 0; k < VGA_SEQ_CNT; k++) { - outb(VGA_SEQ_INDEX, k); - outb(VGA_SEQ_DATA, state->sequencerData[k]); - } - outb(VGA_SEQ_INDEX, 0x00); - outb(VGA_SEQ_DATA, 0x03); /* Low order two bits are reset bits */ - - /* Load the CRTC registers. - * CRTC registers 0-7 are locked by a bit in register 0x11. We need - * to unlock these registers before we can start setting them. - */ - outb(VGA_CRTC_INDEX, 0x11); - outb(VGA_CRTC_DATA, 0x00); /* Unlocks registers 0-7 */ - for (k = 0; k < VGA_CRT_CNT; k++) { - outb(VGA_CRTC_INDEX, k); - outb(VGA_CRTC_DATA, state->crtcData[k]); - } - - /* Load the attribute registers */ - inb(VGA_INPUT_STATUS_1); /* Set the attribute flip-flop to "index" */ - for (k = 0; k < VGA_ATR_CNT; k++) { - outb(VGA_WRITE_ATTR_INDEX, k); - outb(VGA_WRITE_ATTR_DATA, state->attrData[k]); - } - - /* Load graphics registers */ - for (k = 0; k < VGA_GFX_CNT; k++) { - outb(VGA_GFX_INDEX, k); - outb(VGA_GFX_DATA, state->graphicsData[k]); - } - - /* Set up the palette. */ - - outb(VGA_PALETTE_WRITE, 0); - for (k = 0; k < 256; k++) { -#ifdef NOTYET - if (mode == 0x12) { -#endif NOTYET - j = colorData[k % 4]; - outb(VGA_PALETTE_DATA, j); spin(1000); - outb(VGA_PALETTE_DATA, j); spin(1000); - outb(VGA_PALETTE_DATA, j); spin(1000); -#ifdef NOTYET - } else { - j = mode_03_palette[(k - 64) % 64]; - outb(VGA_PALETTE_DATA, colorData[(j >> 4) & 3]); - outb(VGA_PALETTE_DATA, colorData[(j >> 2) & 3]); - outb(VGA_PALETTE_DATA, colorData[j & 3]); - } -#endif NOTYET - } - - /* Re-enable video */ - /* First, clear memory to zeros */ - bzero((void *) VGA_BUF_ADDR, VGA_BUF_LENGTH); - - /* Set the attribute flip-flop to "index" */ - inb(VGA_INPUT_STATUS_1); - - /* Give the palette back to the VGA */ - outb(VGA_WRITE_ATTR_INDEX, 0x20); - - // Really re-enable video. - outb(VGA_SEQ_INDEX, 1); - outb(VGA_SEQ_DATA, (state->sequencerData[1] & ~0x20)); -} diff --git a/i386/libsaio/vga.h b/i386/libsaio/vga.h deleted file mode 100644 index ee7ad5b..0000000 --- a/i386/libsaio/vga.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * VGA Graphics Controller Port - */ - -#ifndef __LIBSAIO_VGA_H -#define __LIBSAIO_VGA_H - -#define VGA_BUF_ADDR 0xA0000 -#define VGA_BUF_LENGTH 0x10000 - -#define VGA_GFX_INDEX 0x3CE -#define VGA_GFX_DATA 0x3CF -#define VGA_GFX_RD_MAP_SEL 0x4 -#define VGA_GFX_BIT_MASK 0x8 -#define VGA_NUM_GFX_REGS 6 // number of graphics controller - // registers to preserve -#define VGA_SEQ_INDEX 0x3C4 -#define VGA_SEQ_DATA 0x3C5 -#define VGA_SEQ_MAP_MASK 0x2 -#define VGA_NUM_SEQ_REGS 5 // number of sequencer - // registers to preserve -#define VGA_AC_ADDR 0x3C0 -#define VGA_NUM_AC_REGS 0x14 - -#define VGA_CRTC_INDEX 0x3D4 -#define VGA_CRTC_DATA 0x3D5 - -#define VGA_READ_ATTR_INDEX 0x3C1 -#define VGA_READ_ATTR_DATA 0x3C1 -#define VGA_WRITE_ATTR_INDEX 0x3C0 -#define VGA_WRITE_ATTR_DATA 0x3C0 - -#define VGA_PALETTE_WRITE 0x3C8 -#define VGA_PALETTE_READ 0x3C7 -#define VGA_PALETTE_DATA 0x3C9 - -#define VGA_INPUT_STATUS_1 0x3DA -#define VGA_READ_MISC_PORT 0x3CC -#define VGA_WRITE_MISC_PORT 0x3C2 - -#define VGA_READ_FEATURE_PORT 0x3CA -#define VGA_WRITE_FEATURE_PORT 0x3DA - -#endif /* !__LIBSAIO_VGA_H */ diff --git a/i386/nasm/Makefile b/i386/nasm/Makefile index 4622a50..eee23ff 100644 --- a/i386/nasm/Makefile +++ b/i386/nasm/Makefile @@ -10,7 +10,7 @@ MANINSTALLDIR = $(SYMROOT) INSTALLDIR = $(SYMROOT) OPTIM = -O2 -CFLAGS = $(OPTIM) -g -Wall -traditional-cpp +CFLAGS = $(OPTIM) -g -Wmost -Werror DEFINES= INC = -I. ifneq "" "$(wildcard /bin/mkdirs)" diff --git a/i386/nasm/assemble.c b/i386/nasm/assemble.c index 2f17c72..7d00176 100644 --- a/i386/nasm/assemble.c +++ b/i386/nasm/assemble.c @@ -1127,9 +1127,9 @@ static ea *process_ea (operand *input, ea *output, int addrbits, int rfield, return NULL; if (s!=1 && i!=-1) return NULL;/* no can do, in 16-bit EA */ - if (b==-1 && i!=-1) b ^= i ^= b ^= i; /* swap them round */ + if (b==-1 && i!=-1) b ^= i, i ^= b, b ^= i; /* swap them round */ if ((b==R_SI || b==R_DI) && i!=-1) - b ^= i ^= b ^= i; /* have BX/BP as base, SI/DI index */ + b ^= i, i ^= b, b ^= i; /* have BX/BP as base, SI/DI index */ if (b==i) return NULL;/* shouldn't ever happen, in theory */ if (i!=-1 && b!=-1 && (i==R_BP || i==R_BX || b==R_SI || b==R_DI)) diff --git a/i386/rcz/Makefile b/i386/rcz/Makefile index cf15acd..58b517b 100644 --- a/i386/rcz/Makefile +++ b/i386/rcz/Makefile @@ -7,8 +7,8 @@ LIBSADIR = ../libsa INSTALLDIR = $(DSTROOT)/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders/standalone OPTIM = -Os -CFLAGS = $(RC_CFLAGS) $(OPTIM) $(MORECPP) -arch i386 -g -Wmost -Wno-precomp \ - -munaligned-text -static -traditional-cpp +CFLAGS = $(RC_CFLAGS) $(OPTIM) $(MORECPP) -arch i386 -g -Wmost -Werror \ + -fno-builtin -static DEFINES= CONFIG = hd INC = -I. -I$(SYMROOT) -I$(UTILDIR) -I$(LIBSADIR) diff --git a/i386/rcz/rcz_compress_mem.c b/i386/rcz/rcz_compress_mem.c index af44704..56a58c2 100644 --- a/i386/rcz/rcz_compress_mem.c +++ b/i386/rcz/rcz_compress_mem.c @@ -44,9 +44,9 @@ rcz_compress_memory( ) /* Returns actual number of bytes emitted as compressed stream 'out.' */ { - unsigned int c, ct, j, jmatch, jabove, match; - unsigned int data[32], version; - unsigned int word, token, tokenct, total; + unsigned int c, ct, j, jmatch = 0, jabove, match; + unsigned int data[32]; + unsigned int word, token, tokenct; unsigned char *outorigin = out; /* First, put version number into stream. */ diff --git a/i386/rcz/rcz_decompress_mem.c b/i386/rcz/rcz_decompress_mem.c index b5a3f86..e223f49 100644 --- a/i386/rcz/rcz_decompress_mem.c +++ b/i386/rcz/rcz_decompress_mem.c @@ -46,7 +46,6 @@ rcz_decompress_memory(unsigned char *in, unsigned char *out) unsigned int c, j, k, jmatch, jabove; unsigned int length, even_length, word, token, version; unsigned char *outorigin = out; - int *a, *b; version = *in++; version = (version<<8) | (*in++); diff --git a/i386/testmodule/install/install.module b/i386/testmodule/install/install.module deleted file mode 100755 index 5258bb3c36c22db84e88bafa0035d606666bc181..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 89492 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ོJ>!oU|BZ3qo9(m) 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 Zz-7LVeI2ncIj;OGh~s9Ce$U-egYb>ADh z`l>9teb1TH*VTVl{q@)DufP7PJo=j#ez(8lIQ!ynAN&zshleQ$>8}@mnar9cCoMmB z`P$R)pnhEngu@Oz(sw80pG;=m^1*e+`z~PmqhFWIs}qpEpD<*GaI~ZpDxQA{hppfX>>QIvGd*XtDQ%@ zS{k{!?-eV5(!pnhP}>A*jk%)pX$OH?ev#rW$A{;1AW9Rh+rpY^kZ zg4jx9R&- z0;vR238WH8C6G!Wl|U+iR0634QVFCINF|U;AeBHWfm8yi1X2m45=bSGN+6X$DuMrh z5;$}6*|X0&c3;3DWKW^W(xOwdsF|mDe{>@dZtY|$M4+rA~wM`^&iYnKf}|* zop*GC7QZvj-aP-TUCV(seeIw%yKaAWPsbMifxk`9cRaj&H*K_T`M@Q+X`{3Lw$00T zZ(h?u|4yAeaMSYLQ=fZAelYp`1rOkxk=@TYj{Ju{*wy{~o(`mak+bV`B);iu9Yl9c zuhY41zbPFbMz{vyRR{+VUXE}v!b=dIi0~iY;dJ&QycywKgqu%rI%gyN9G+()+=}oo z5q=2aVF))NJQ(4n2&W_B)e!Y+gd{WZ1= z5uQKO>D&!bQT3dPXR4l;@O(Yq{{rE42%ksz5rn%CeiGp`2H_dbN%x}44(2p>jx55ju!Vz*j2X4Lg6 zORH7?4Bu2-zQFy?-8i?sK;Sb4?iKiK=U&7w6nN0NA9#_# z=Q>{p?i2WY=SRRN3Vea{6mY-5>z!wS-zD&c&VK^GTi~qobKu1S4>_*@FA+HB>;YaX zaNd~;H=1Pvzt?#q@PNR+b2#vFfiHI63A{q!_c`-`PZD^evj+HN;29`0)$i%Riy;R( z8-D>~T=n1#Gp0KPYQXn_p5*Xejz_e!(TKkU_({-^OfF?idA%RFi-_^tYT&zpsf`JK z*5X_|9jagKIBOY`pUioT$yX*%7|cuqt}-S^q>Y4;4wdC{#+2q3U@8Z>G;L!{?o3}& z@$iNDD$`#9`bRjP{AV7ec<@K=NZye>0wedfd%;I?~+t ztUx|94Sbe?FEjAx7?aP`4#wn1^(bTVt@<(JuL1v-G5KB{aJI~g{IlN9n0&U5V@!Tr zix`t{*U5~@-|GU#tH%b|>RkfWOOlH}KPp$@lC<#^jfFz@X%f zeAQ+!CO@`?jLFySG{)rrR$xp%ahEVAKe-zilaJfy8IvE}LyXB+?g_@^U-v(Z$>;8% zb0iPshj$EP^35AyO#XU9j28pHpYZ_jjf}|$@AHhwpYAJ+*8o4xcpdPIj0b@aJXhv> zKJawL7Xr^=OumFG7?VHYIgH7tu*{hJ3NL3&zJ=E_CjY|ijBf_Mk1_cfKEjxM4WDF8 z{)WF|Og@MEohNxCzr#ZrlkeeCjLH9SK4bDhT*jFE5Km`JzKB`IGK8m{-lb_;$F(zNd-!LYB#eL70 zWxO9_(Hj_(-{M;sldt08jLBc|XvRNBIoMLoXXh`){TI?S{8GCm)9 zJ;Znm;vZ)`3%otccog;iOUB=v1;5*@%=b%(e+%PNLEpu=fcO&_51=0V8Gjz%u3}sR z&3TL;LHsD=vk||M@j0lYk1*a29plrC?*RTX<0bg^>x_>;y?>u^Kk(Cx*CNedFkS^b zWk~Y>An=!M-d5rgie3mkviaxuNG38Y^ z@GS=ZCgYEx4L`~Fdf=BCZv~#3mw9ai{tL#R1@30N9e5Sv2I~48#+2_>jOT#2k25|C za{Daf>q)O;Tp>9#egf${!FU$vcQJk(@l#yM&)KM>ANfAxw?hs; zW!ym9_%-7%E`kqwL6&O=@L`Pa2R@eZHORM@@#VlP7}tT;Uf?e<{yy*{jPC+|n(=pmcQgK1-~)#xpBvGa-^%z-;CC?o0B|?sbAXpIz8&~< z#+!j%#y0@JkMWhjf5Z4wz*`yL27Ei?4Z!y^E(3p$u?PGd;}PI}MkJpf2R@kb_aM)s z82=b}9^)SZFK0~cw!t`y_BP450Q?EY8O&L?81#=az6$dBA>#*tf5!L{;FlRMMcde~ zD0!O!d>G?7z(+Ga33xu^V}VyP?gbuXoJX1k#?Jva7>}X7UBUP>;Q4CCR{-D0_=lj` z&iEme{T{~u2K;r#CnC-7F#a~;pJIH-iO|&MudGKvmF?R-^}<5wCy7q-v>O4 zG0FBk1Amb5Jx4j6*D#)m`uYUptr#C}S2Vy6Fun_TCu2%;|53>U;dzX=faYYz9|K;` z_$J^6!M@g64L{JAijEo`(MWAY;nw7mTk2|G#GZW60Ji1^gUq;B|~E zmKL-6>jNbq`KgjrQ@c9GA*8~5Q@kfAPVSEel{$AZ>YOBe%hGw2^P@E*onI-tYj=0IvE z-+_L32;((qV@EKiyiPIjxPd>-_zB48Ul`wvx_E%`PZ0kD#xDT>lJU#How)ap^4$%5 zC}Wt3I*(<%AMgNU;-SX)Ht=}~6i2T*|Ty^vEncCyZgQF zzTGyj2X7_dXAf{BU40nkS=e*j7jY_>ZTygV~ zbS{z3?mNDlzYo8i7rd>HR6SpQGhZY>r)RwJ}t35haAw zOHm?k9WNvz;>W7RJP7CYch7U&%2?5>Ru-MqJ-`3B?gjnF^*E~smw3ZD#7Hzo@0`(s zmo2-C)^+#x*SmX0vqaH7bN0+RJ$>{rwy1kye^!VbwYC7!^yYkr-r=6mMLo0i+n$;8 z=g#cy8%56IO}Fu8K@Z;a$rcm-x9(>>f6&|2l zO9_;-xe;+yYR0QJ{9?sjbW+b86mo8Vq1(yi{1MO1=9>uUicuB}kd%i4V*u5mi*hS* z|0-avR%+Bm0*+u2QFJqFM%=nt$5Rsr^ihj^os8>wm8ydeiWNMJi{wL>y+-eCr2;Z} z4Og-H1^!IL%hYBSiX}IbcMHT+v0BMQF9wyl&Z;`NCp7E1c_Q$#-ULcfsCwmW%a14n z{1lT}Tx%^5*nmo!poExJ_WVleKfX5KDHqlHFlk+EPZU&%OuVgVRAjG(g(3Kw+D2Qi}sI5dL zlDDJ;Lspcs3|6EGx<@dKCKfxy$KzI}?)n#%X}(esq%wtK0yRL9lt<8@++4$VGb2zQ zTrc>Xr@`o`$j^Fk;pbpL;fOIcz^DYEQTU`o@N>a)X)IE21$Bl8sBmQ79cm0Wk;=Xm zO<=fM%|}uZ8V@NtoN6xXLydCBb8b!O175a>;ZDDfO0h|Zs|S~%u)ce4wPJjxVwa5+ zOZn)lRjxPOL{CJ^B0^d{NU-O) z!_bq=FC^)*5jRJJK8s}a;99p_9do1Paw>#8E5jvMs(Efc_-rg(htMr$>I02(Z3U{= zsO``@V$^)c*+4}brJ1P))h);bIw8%+8Tl5kpqOaJLoahA`rzH_!PQXmn}h;gKcG=* zgV~GSyf@MG<{}hDsluvNRx6}`YMnS7?U^j#I(;G~4I3$QW@eHt@>fwL3{@gCj-(?* z5Q@}NGwVRf*^E>5qUw%QX{zGZZ7bRkqwQ5b>sH;=u0nMJwv2wEm{d)(Rfke>T&d{U zK@->gRCnO!r4AR?93(hOjVAo4h8!&&(wn%om(@U~MmRn6sWDN0rB@WjsH+ELW-@-Z zGxeavlLIRtn3F>qV0^9#6p~QVG%+UTk`}01N!Z{Oed_%Ml5(^=;#sP_#d_BF(OU}z zELcYnN}ZLoSkhhf_#mpxqPX;x)ub*nwj;G&@FZD12(egYF9c~t87L}AtBzM3x|u0c z09v@oRmq4ASy;|E#?RJAMPH!h50cHx7saXof)YX)*C{F1PoONVEj7*oI36-ZuH5q1_ zrb(Hko==q~V(JF4rRHiF-$iF9iAo)?NlW4Qh~^lIZKW3wLCFrT3)th?*#QIl5D4O3EfZ`7R20#Nid{D)S$?i zYJeE!d3;c29k$>JQc}r>Fu;_mWJ;^oir77q+KSM<<)$CF9}~TcSNb8DHN(c0Np$NUU5R&UkLlE!rw<^g-RNkU5Dsg9?P5RppJiSMj}+^S0?pUY8ZtCVHc)$M0!`|)2UZN-IX z@V=L=*)1FG6%|rGL`Sk`!%n*r99ye3rr{@c!U)#SiO0XBtF@#VWYn5VX${bNRA&M} z$0%cQ0oB}_c4 zHBGQdrA759bULjfm5akU-ONLFrzvHyry>d7!g3d)daQ^b(&8!SC!6j*KO#EBr948^rhDx0U4qf^$^r(;MC zLE^;0U(<;J#KZ6?5Dt zP?DTq9HT0WAKem}$}Dwu8d>U%8WqZZCKPII(oqe~P}pwc%NdwEljfn)fEH)vkk7-_GDYdZADVfwPCb>lB zjes+&4kF0yY%)rTw@O!t(uz__qMdFB(L;YQx1CwTEERa~I8e+3u{2efm=%?o7Mh^P zR#6(6;gTFQ2T3SRFuIM%$f2xorO|ayy_32ZX}?T?ReB!hEAS$0`!$!RssW-{A%zal zTIq}L7WT4FxZ+Dtp9xH!QqERs>)NrRex39i(e$isnWD9{)f>dz%eHtiVB_EuT3cw6 zz%b6S!Vx26YS4|Bv_u+-#ZdWzeU+PCmH677x00Tb&E8)!><5=WEQm?m^u zm~#?jH-PCv+sh()K$E>)q|?I6)53%wd`s$b28v;Pvk1PiQ>BCiEJ@q3Mp(}_35S6| zSBoDp)B)VKTECdfP;$|Blna_s|1GV*&1yDJUTP`UWK5S4d-XmPb}g-V(F#fJccL|h zwSHoVRkpCbS)^eobMcMoPf~4Bv*sVe9gd`KKUF1Zqv5`lcyP-oqeXCpkG<^UYdP>F zkL^mqk+)bs@E%^&*GEkuAuUrq@CZPQakj+ob(G-6 zx-rVAl-UlT9*vc~#fZY}l953kFjUDX-MPtUCgj_rsA(ib1xX!R?~16mc^67M*;Z7< zMK~$ZG)O5{l+#~8&azQoE59K1OeK!SscmPKsPX_#a59ZV9U9?VrKLvyQlllU<*^mL ztcq=?$Ojijl7El5&U@CLs-Gx8O=$Bw;IMI}3ZB$UgYfD4W`n$FXSm>F99xO@tr$Y8ciUFqmTRe#kgE0&4B_Z(>+lWO@wv?s1-9}ens7XGA zQ>o?pFOWiUSe!4Guh7JWbs4gu;}8~QWJ;@2B5#p_EwNzCir8M#viy{2Qt_E>oz{Z! z^`ESv^D;0gTY>+y<a-D8+Ab{W&sYfK-VJ#*AsS}rYB^;Y)~C9m zZpPjz_gdT}mwW(?UR0*99{IDnpG-G{z(%JGQGun5V}ij*kyu{~rtiK{4Md&xSI_#k z98Q|g#qkr{*V1dh!gn~ZbRt(dD3P|jv?6$E+=&!Kt`a*w>TV^Se&oV~Xsx8zeqkI` zLP@Xv()Z8Fh8ewcWSMAVLZykcEAwiPrt40^O;cU6VqSlu;_R;d;xQ$3CyC%pp6UdD zOcA-$L=HkcKIvggjc0nGQ!}7UgxW{+Qm^288Fh)3I{B`ytKw^_;uQvcfILgLbIQ-}Ckz(+!c^DHBp-fe~b-hd0mk`$JWLhSwmI{+b`T@?-ET9>o>8{g;og2SEHz2hqh>S z!!Fuwa4aFV-K%`83Z?k7Bi0w3#4^E(n~;I+c?fmLfsKS>*puhPLT(UwM$! zq#!@W^e{0FOzELb$c&_){4lXTcoaP|{CYkkY`6+Wx3Bb6WXx4MuElo{+MoXc;E+3w z>7q#rYRkii%4siNa}B)djEzR`HeGsd?eb8`I9@-7Zkgm@EjjD zzFVKGQ~E&N#>HCc`&M(Y@--CR^S{S=E}BGI9N~&@If1K8tTKYJO>!t^E8TkN#O13U z;8DUO`?}r19MqsxIa{8<;f209BqLT23D0W076%nzXeaMNp=q(oO>;BDz|lZCW5m}} z@C`X9VE90CA&*2QW?BJ6oFtV;CXWVtbHP+8M81x?Q&I-eIPGE?a(#?1mEj{Gwolpp z?6vVbll%Un3BB&!yG);)R?b2}^LRCI~#&C6sZ!cJe$jOqNJ4DT~ Pn?d}iSh#4f0q1`KLB<}R diff --git a/i386/util/Makefile b/i386/util/Makefile index 5914861..8bd1b72 100644 --- a/i386/util/Makefile +++ b/i386/util/Makefile @@ -14,8 +14,9 @@ LOCALBIN = $(DSTROOT)/usr/local/bin LANGDIR = $(INSTALLDIR)/English.lproj OPTIM = -Os -CFLAGS = $(RC_CFLAGS) $(OPTIM) -Wmost -Wno-precomp -g -I../rcz -traditional-cpp -nostdinc -nostdlib -I/usr/include -I/System/Library/Frameworks/System.framework/Headers -LDFLAGS = /usr/lib/crt1.o /System/Library/Frameworks/System.framework/System -lcc +CFLAGS = $(RC_CFLAGS) $(OPTIM) -Wmost -Werror -g -I../rcz -nostdinc -nostdlib -I/usr/include \ + -I/System/Library/Frameworks/System.framework/Headers +LDFLAGS = -L/usr/lib -lcrt1.o -lSystem -lcc_dynamic CFILES = machOconv.c mkfont.c tif_packbits.c MFILES = dumptiff.m HFILES = cursor.h diff --git a/i386/util/dumptiff b/i386/util/dumptiff deleted file mode 100755 index eec785379ff3db6700a951ce43de7fb31e2f1d1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35844 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