From 8b47254fc83f5e3170de88edfee689348791afc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roc=20Vall=C3=A8s=20Dom=C3=A8nech?= Date: Tue, 14 Sep 2021 18:08:07 +0900 Subject: [PATCH] Initial commit. --- .gitignore | 9 ++ LICENSE | 21 +++++ Makefile | 44 +++++++++ README.md | 40 +++++++++ optromloader.S | 235 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 349 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 optromloader.S diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5e1a242 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.bin +*.rom +*.img +*.kate-swp +*.86 +*.386 +optromloader9 +optromloader15 +optromloader18 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d2947eb --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Roc Vallès i Domènech + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e557509 --- /dev/null +++ b/Makefile @@ -0,0 +1,44 @@ +fasm = fasm +#hexdumpcmd = hexdump -C +hexdumpcmd = xxd -a +qemu = qemu-system-i386 +date = \"`date +%Y%m%d%H%M`\" +.PHONY: all +all: hexdump optromloader18 optromloader15 optromloader9 fd1440.img fd720.img fd1200.img fd360.img +optromloader18: optromloader.S + @echo "*** assembling $@..." + $(fasm) -d date=$(date) -d sectorspertrack=18 optromloader.S $@ +optromloader15: optromloader.S + @echo "*** assembling $@..." + $(fasm) -d date=$(date) -d sectorspertrack=15 optromloader.S $@ +optromloader9: optromloader.S + @echo "*** assembling $@..." + $(fasm) -d date=$(date) -d sectorspertrack=9 optromloader.S $@ +fd1440.img: optromloader18 optrom.bin + @echo "*** building $@..." + cat optromloader18 optrom.bin | dd bs=1474560 conv=sync of=$@ +fd720.img: optromloader9 optrom.bin + @echo "*** building $@..." + cat optromloader9 optrom.bin | dd bs=737280 conv=sync of=$@ +fd1200.img: optromloader15 optrom.bin + @echo "*** building $@..." + cat optromloader15 optrom.bin | dd bs=1228800 conv=sync of=$@ +fd360.img: optromloader9 optrom.bin + @echo "*** building $@..." + cat optromloader9 optrom.bin | dd bs=368640 conv=sync of=$@ +.PHONY: clean +clean: + @echo "*** Removing build artifacts..." + rm -f optromloader9 optromloader15 optromloader18 fd1440.img fd720.img fd1200.img fd360.img +.PHONY: hexdump +hexdump: optromloader18 + @echo "*** hexdump optromloader18..." + $(hexdumpcmd) optromloader18 +.PHONY: emulate +emulate: fd1440.img + @echo "*** Emulating with qemu..." + $(qemu) -drive if=floppy,format=raw,index=0,file=fd1440.img +.PHONY: emulaterom +emulaterom: optrom.bin + @echo "*** Emulating with qemu..." + $(qemu) -net none -option-rom optrom.bin diff --git a/README.md b/README.md new file mode 100644 index 0000000..42cd94a --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# optromloader: IBM PC/Clone 8086+ floppy-loading of option roms. + +Booted from a floppy, it will load an Option ROM image into the end of conventional memory. + +![PCem PC1512 screenshot](https://b.rvalles.net/unsorted/pcem_pc1512_optromboot_xtide.png) + +Usage +* Ensure fasm (flat assembler) is installed +* Copy your ROM image as the `optrom.bin` file. +* Run `make`. +* Optionally test with qemu: `make emulate`. +* Floppy images will be created (fd*.img). +* Alternatively, use a binary release. Concatenate: + * optromloader9/15/18 (according to sectors per track in your floppy format) + * 9 for 5.25" 360K and 3.5" 720K + * 15 for 5.25" 1.2M + * 18 for 3.5" 1.44M + * the ROM image. + * pad to floppy size. + +Use cases (non-exhaustive) +* Test boot ROMs before burning them. +* Netboot with etherboot/gpxe/ipxe. +* IDE support (including LBA!) with XTIDE Universal BIOS. + +Highlights +* flat assembler syntax. +* Pure 8086 code. +* Works on newer hardware, such as the 486 I wrote it for. +* Fits in a floppy bootblock. +* Trivial to use. Concatenate loader and the ROM image, write into floppy. +* Makefile will prepare 5.25" 360K/1.2M and 3.5" 720K/1.44M floppy images. + +Caveats +* Hardcoded to use the first floppy drive. +* ROM checksum isn't checked (yet). + * Always ensure a boot ROM is signed before burning. + * Qemu provides a python tool to sign ROMs: + * https://github.com/qemu/qemu/blob/master/scripts/signrom.py + * For XTIDE Universal BIOS roms, use its XTIDECFG tool to configure and sign ROM images. diff --git a/optromloader.S b/optromloader.S new file mode 100644 index 0000000..80f44e0 --- /dev/null +++ b/optromloader.S @@ -0,0 +1,235 @@ +;optromloader, by Roc Valles Domenech. +;MIT license, see LICENSE for details. +;https://www.rvalles.net +format binary as "raw" +use16 +org 7C00h +jmp 0x0000:start +start: + mov sp,$7C00 + mov ax,0 + mov bx,ss + mov ss,ax + mov ds,ax + mov si,banner_str + call printstr + mov ax,1 + mov bx,bootblock_end + call readblock + mov bx,[bootblock_end] + cmp bx,$AA55 + jnz bad_header_magic + mov si,romsize_str + call printstr + mov ax,0 + mov al,[bootblock_end+2] + mov bx,ax + call printhex8 + mov si,romsizebytes_str + call printstr + mov ax,bx + mov cl,9 + shl ax,cl + call printhex16 + mov si,ramsize_str + call printstr + int 12h + call printhex16 + mov dx,bx + test dx,1 + jz .blocks_even + add dx,1 +.blocks_even: + shr dx,1 + sub ax,dx + mov [1043],ax + mov si,ramsizeafter_str + call printstr + int 12h + call printhex16 + mov cl,6 + shl ax,cl ;target segment + mov es,ax + mov dx,0 + mov si,readblocks_str + call printstr + mov cx,bx + mov bx,0 ;target address +.readrom: + ;hlt + add dl,1 + mov ax,dx + call printhex8 + call readblock + add bx,512 + mov si,readblocksbs_str + call printstr + cmp cx,dx + jne .readrom + ;mov si,cksum_str + ;call printstr + mov ax,es + mov [.calloptrom+3], ax + mov ah,0eh + mov al,'#' + int 10h + ;sti ;some bad BIOSs disable on int13 and forget to restore. +.calloptrom: + call 0xA000:3 + mov ah,0eh + mov al,'@' + int 10h + int 19h +;***************************************************************************** +bad_header_magic: + mov si,bad_header_magic_str + call printstr + mov ax,bx + call printhex16 + jmp $ +printstr: ;SI *str + push ax + mov ah,0eh ;print character +.printstr_loop: + lodsb ;SI++ -> al + test al,al + jz .printstr_end + int 10h ;print + jmp .printstr_loop +.printstr_end: + pop ax + ret +;FIXME: these value dumpers could be shorter. +printhex8: ;AL (preserved) value to print + push ax + push bx + push cx + mov ah,0eh + mov bl,al + mov cl,4 + rol bl,cl ;in 8086, 1 or cl. 186+ for higher imm. + call printhexdigit + rol bl,cl + call printhexdigit + pop cx + pop bx + pop ax + ret +printhex16: ;AX (preserved) value to print + push ax + push bx + push cx + mov bx,ax + mov ah,0eh + mov cl,4 + rol bx,cl + call printhexdigit + rol bx,cl + call printhexdigit + rol bx,cl + call printhexdigit + rol bx,cl + call printhexdigit + pop cx + pop bx + pop ax + ret +printhexdigit: ;FIXME: Make shorter. possibly use daa/adc inst. + mov al,bl + and al,$F + add al,$30 + cmp al,$3A + jb .printhexlow + add al,7 +.printhexlow: + int 10h + ret +resetfloppy: + mov ah,0 + mov dl,0 + int 13h + ret +readblock: ;AX blocknumber, ES:BX (preserved) addr. + ;call printhex16 + ;xchg ax,bx + ;call printhex16 + ;xchg ax,bx + push cx + push dx + ;CHS magic: get number of tracks, heads>>1 is cyl + mov dl,sectorspertrack + div dl ;ax/dl -> /al, %ah + mov dh,0 ;head 0..15 + test al,1 + jz .heads_even + add dh,1 +.heads_even: + shr al,1 + ;CX 0-5 sector, 6-7 track MSB, 8-15 track LSB + mov ch,al ;cyl + add ah,1 ;CHS sectors start at 1 + mov cl,ah ;sector + mov ah,02h ;BIOS 13h read CHS block + mov al,1 ;sectors to read 1..128 + mov dl,0 ;drive 0=A 80h=hdd0 + ;xchg ax,cx + ;call printhex16 + ;xchg ax,cx + ;xchg ax,dx + ;call printhex16 + ;xchg ax,dx + push ax +.retry: + ;hlt + ;push ax + ;mov ah,0eh + ;mov al,'%' + ;int 10h + ;pop ax + int 13h + ;push ax + ;mov ah,0eh + ;mov al,'?' + ;int 10h + ;pop ax + cmp ah,0 + jne .error + ;mov dx,es + ;mov ds,dx + ;mov ax,[bx] + ;call printhex16 + mov dx,0 + mov ds,dx + pop ax + pop dx + pop cx + ret +.error: + push ax + mov ah,0eh + mov al,'E' + int 10h + pop ax + mov al,ah + mov ah,0 + call printhex8 + call resetfloppy + mov si,readblocks_str + call printstr + pop ax + push ax + jmp .retry +banner_str: db "optromloader, by Roc Valles Domenech , built ",date,'.',13,10,0 +bad_header_magic_str: db "Ehdrmagic:",0 +romsize_str: db "ROM blks:",0 +romsizebytes_str: db "->",0 +ramsize_str: db 13,10,"RAM:",0 +ramsizeafter_str: db "/",0 +readblocks_str: db 13,10,"Rd:",0 +readblocksbs_str: db 8,8,0 +;readblocksbs_str: db 13,10,"Rd+",0 +;cksum_str: db 13,10,"Ck+",0 +.finalize_bootblock: + times 510-($-$$) db 0 + dw $AA55 +bootblock_end: