; boot1.asm - boot1 written for turbo assembler, since gas only ; generates 32 bit code and this must run in real mode. ; To compile as hard disk boot1: ; tasm /m3 /dBOOTDEV=HDISK boot1 ; tlink boot1 ; exe2bin boot1 ; ren boot1.bin boot1 ; To compile as floppy boot1f: ; tasm /m3 /dBOOTDEV=FLOPPY boot1 ,boot1f ; tlink boot1f ; exe2bin boot1f ; ren boot1f.bin boot1f ;*********************************************************************** ; This is the code for the NeXT boot1 bootsector. ;*********************************************************************** P486 ;enable i386 instructions IDEAL SEGMENT CSEG ASSUME CS:CSEG,DS:CSEG SDEBUG = 0 ;BOOTSEG = 100h ; boot will be loaded at 4k ;BOOTOFF = 0000h BOOTSEG = 00h BOOTOFF = 1000h BUFSZ = 2000h ; 8K disk transfer buffer ; FDISK partition table in sector 0 PARTSTART = 1beh ; starting address of partition table NUMPART = 4 ; number of partitions in partition table PARTSZ = 16 ; each partition table entry is 16 bytes BOOT_IND = 0 ; offset of boot indicator in partition table BEG_HEAD = 1 ; offset of beginning head BEG_SEC = 2 ; offset of beginning sector BEG_CYL = 3 ; offset of beginning cylinder NAME_OFFSET = 4 ; offset of partition name PARTSEC = 8 ; offset of partition sector specifier NEXTNAME = 0A7h ; value of boot_ind, means bootable partition LOADSZ = 88 ; maxiumum possible size of unix boot - 44k FLOPPY = 0 HDISK = 80h ;BOOTDEV = ? ; set to 00h for floppy, 80h for hard disk ; (use a command line switch to set) ; NeXT disk label DISKLABEL = 15 ; sector num of 2nd disk label, 1st is trashed by bootsec DL_DISKTAB = 44 ; We support disk label version 3 "3Vld" in our little endian world DL_V3 = 33566c64h ; NeXT disktab DT_SECSIZE = 48 DT_BOOT0_BLKNO = 80 ; This code is a replacement for boot1. It is loaded at 0x0:0x7c00 start: mov ax,BOOTSEG cli ; interrupts off mov ss,ax ; set up stack seg mov sp,0fff0h sti ; reenable interrupts xor ax,ax mov es,ax mov ds,ax mov si,7C00h cld ; so pointers will get updated mov di,0E000h ; relocate boot program to 0xE000 mov cx,100h ; copy 256x2 bytes repnz movsw ; move it off1 = 0E000h + (a1 - start) jmp FAR 0000:off1 ; jump to a1 in relocated place a1: mov ax,0E00h mov ds,ax mov ax,BOOTSEG mov es,ax ; load the boot loader (boot2) into BOOTSEG:BUFSZ call loadboot ; ljmp to the second stage boot loader (boot2). ; After ljmp, cs is BOOTSEG and boot1 (BUFSZ bytes) will be used ; as an internal buffer "intbuf". xor edx,edx ; bootdev = 0 for hard disk IF ( BOOTDEV EQ FLOPPY ) inc edx ; bootdev = 1 for floppy disk ENDIF ;boot2 immediately follows disk buffer; 4K + BUFSZ jmp FAR BOOTSEG:(BOOTOFF + BUFSZ) ; jump to boot2 in loaded location loadboot: mov si, OFFSET intro call message ; display intro message ; load second stage boot from fixed disk ; get boot drive parameters ; Note: I believe that the bootsector read may not be necessary; ; at least some blk0 bootsectors leave a pointer to the active ; partition entry in si (assuming there was another blk0 bootsec) call getinfo IF ( BOOTDEV EQ HDISK ) ; read sector 0 into BOOTSEG:0 by using BIOS call (INT 13H 02H) ; this gets info on the disk's actual partition table ; However, in the case of multiple partitions, this may not ; be the same as the sector with the code here. mov di,5 ; try 5 times to read bootsector retry_disk: xor bx, bx ; buffer is BOOTSEG:0 mov ax,201h mov cx,bx mov dx,bx mov bx,BOOTOFF ; actually, it's 0:BOOTOFF inc cx ; cyl 0, sector 1 mov dl,BOOTDEV ; target 0, head 0 push di int 13h ; read the bootsector pop di jnb read_success1 ; woops, bios failed to read sector xor ax,ax int 13h ; reset disk dec di jne retry_disk jmp read_error ; disk failed read_success1: ; find the NeXT partition mov bx,PARTSTART mov cx,NUMPART again: mov al, [es:(bx+BOOTOFF)+NAME_OFFSET] ; get partition name cmp al, NEXTNAME ; is it NeXT partition? jne cont ; nope, keep looking foundNextPart: ; found it, get label location mov eax, [es:(bx+BOOTOFF)+PARTSEC] ; offset to NeXT partition add eax, DISKLABEL ; add offset to the label jmp getLabl ; fetch that label cont: add bx, PARTSZ loop again ; if more part table entries, ; keep looking ; fall through, didn't find NeXT disk partition entry no_fdisk: ENDIF ; Read NeXT disk label mov eax, DISKLABEL ; Get block number of label getLabl: mov bx,BOOTOFF ; read into load area mov cx,1 call readSectors ; we used to think about testing the disk label version here... mov bx,BOOTOFF ; point to beginning of label ; Use values from label to read entire boot program ; Get block number of boot ; Get dl_secsize and dl_boot0_blkno[0] mov edx, [es:(bx + DL_DISKTAB+DT_SECSIZE)] bswap edx ; edx -> sector size mov eax, [es:(bx + DL_DISKTAB+DT_BOOT0_BLKNO)] bswap eax ; eax -> block # ; Compute dl_secsize * dt_boot0_blkno[0] / 512 shr edx, 9 ; divide dl_secsize by 512 mul edx ; multiply boot block loc ; by dl_secsize/512 ; eax has secno mov bx, (BUFSZ + BOOTOFF) ; read boot2 into BOOTSEG:BUFSZ mov edi, LOADSZ ; read this many sectors nexsec: push eax ; push sector # push bx ; push buffer address mov ecx, edi ; max number of sectors to read call readSectors pop bx pop eax add eax, ecx ; add number of sectors read sub di, cx shl cx, 9 ; multiply by 512 bytes per sector add bx, cx cmp di, 0 jne nexsec ret spt: DW 0 ; sectors;track (one-based) spc: DW 0 ; tracks;cylinder (zero-based) nsec: DW 0 ; number of sectors to read readSectors: ; eax has starting block #, bx has offset from BOOTSEG ; cx has maximum number of sectors to read ; Trashes ax, bx, cx, dx ; BIOS call "INT 0x13 Function 0x2" to read sectors ; ah = 0x2 al = number of sectors ; ch = cylinder cl = sector ; dh = head dl = drive (0x80=hard disk, 0=floppy disk) ; es:bx = segment:offset of buffer IF ( BOOTDEV EQ FLOPPY ) push eax mov al,'.' call putchr pop eax ENDIF push bx ; save offset mov [WORD nsec], cx mov ebx, eax ; bx -> block # xor ecx, ecx mov cx, [WORD spc] ; cx -> sectors/cyl xor edx,edx ; prepare for division div ecx ; eax = cyl, edx=remainder push ax ; save cylinder #, sec/spc mov eax, edx mov cx, [WORD spt] ; ecx -> sectors/track xor edx,edx ; prepare for division div ecx ; eax = head push ax ; save head, (secspc)/spt mov eax, ebx ; reload block # xor edx, edx ; prepare for division div ecx ; edx has sector # sub cx, dx ;cx now has number of sectors to read cmp cx, [WORD nsec] jge last ; use the minimum of bx and cx mov [WORD nsec], cx last: mov cx, dx ; cl -> sector inc cl ; starts @ 1 pop ax ; get head mov dh, al ; dh -> head pop ax ; get cyl mov ch, al ; ch -> cyl mov dl, BOOTDEV ; floppy disk xor al,al shr ax,2 or cl,al ; retain pesky big cyl bits ; mov al, 1 ; get # of sectors ;pop ax ; number of sectors to read mov ax, [WORD nsec] pop bx ; get buffer mov ah, 2 ; bios read function int 13h jb read_error mov cx, [WORD nsec] ; return number of sectors read ret getinfo: ; get some drive parameters mov dl, BOOTDEV ; boot drive is drive C mov ah, 8h push es int 13h pop es mov al, dh ; max head # inc al ; al -> tracks/cyl and cx, 3fh ; cl -> secs/track mul cl ; ax -> secs/cyl mov [WORD spc], ax mov [WORD spt], cx ret message: ; write the error message in ds:esi ; to console push es mov ax,ds mov es,ax mov bx, 1 ; bh=0, bl=1 (blue) cld nextb: lodsb ; load a byte into al cmp al, 0 je done mov ah, 0eh ; bios int 10, function 0xe int 10h ; bios display a byte in tty mode jmp nextb done: pop es ret putchr: push bx mov bx, 1 ; bh=0, bl=1 (blue) mov ah, 0eh ; bios int 10, function 0xe int 10h ; bios display a byte in tty mode pop bx ret IF SDEBUG hexout: ; print ebx as hex number push cx push ax mov cx,8 ;output 8 nibbles htop: rol ebx,4 mov al,bl and al,0fh cmp al,0ah jb o_digit add al,'A'-10 jmp o_print o_digit: add al,'0' o_print: call putchr dec cx jne htop ; mov al,10 ; call putchr ; mov al,13 ; call putchr mov al,' ' call putchr pop ax pop cx ret ENDIF read_error: mov si, OFFSET eread boot_exit: ; boot_exit: write error message and halt call message ; display error message halt: jmp halt intro: db 10,'NEXTSTEP boot1 vXX.XX.XX.XX.XX',10,13,0 eread: db 'Read error',10,13,0 ; the last 2 bytes in the sector contain the signature d1: a2 = 510 - (d1 - start) DB a2 dup (0) DW 0AA55h ENDS END