;=============================================================================== ; LOADER.ASM ; ; BOOTLOADER FOR ROMWBW PSYSTEM ; ; CP/M DISK FORMATS ALLOW FOR RESERVED TRACKS THAT CONTAIN AN IMAGE OF THE ; OPERATING SYSTEM TO BE LOADED WHEN THE DISK IS BOOTED. THE OPERATING SYSTEM ; IMAGE ITSELF IS NORMALLY PREFIXED BY A 1-N SECTORS CONTAINING OS BOOTSTRAP ; CODE AND DISK METADATA. ; ; THE RETROBREW COMPUTING GROUP HAS BEEN USING A CONVENTION OF PREFIXING THE ; OS IMAGE WITH 3 SECTORS (512 BYTES X 3 FOR A TOTAL OF 1536 BYTES): ; ; SECTOR 1: IBM-PC STYLE BOOT BLOCK CONTAINING BOOTSTRAP, ; PARTITION TABLE, AND BOOT SIGNATURE ; SECTOR 2: RESERVED ; SECTOR 3: METADATA ; ; THE HARDWARE BIOS IS EXPECTED TO READ AND LOAD THE FIRST TWO SECTORS FROM THE ; DISK TO MEMORY ADDRESS $8000 AND JUMP TO THAT LOCATION TO BEGIN THE BOOT ; PROCESS. THE BIOS IS EXPECTED TO VERIFY THAT A STANDARD BOOT SIGNATURE ; OF $55, $AA IS PRESENT AT OFFSET $1FE-$1FF. IF THE SIGNATURE IS NOT FOUND, ; THE BIOS SHOULD ASSUME THE DISK HAS NOT BEEN PROPERLY INITIALIZED AND SHOULD ; NOT JUMP TO THE LOAD ADDRESS. ; ;=============================================================================== ; #INCLUDE "../ver.inc" ; #INCLUDE "psys.inc" ; SYS_ENT .EQU $0100 ; SYSTEM (OS) ENTRY POINT ADDRESS SYS_LOC .EQU $0100 ; STARTING ADDRESS TO LOAD SYSTEM IMAGE SYS_END .EQU $0100 + loader_size + bios_size + boot_size ; ENDING ADDRESS OF SYSTEM IMAGE ; SEC_SIZE .EQU 512 ; DISK SECTOR SIZE BLK_SIZE .EQU 128 ; OS BLOCK/RECORD SIZE ; PREFIX_SIZE .EQU (SEC_SIZE * 3) ; 3 SECTORS ; META_SIZE .EQU 32 ; SEE BELOW META_LOC .EQU (PREFIX_SIZE - META_SIZE) ; PT_LOC .EQU $1BE PT_SIZ .EQU $40 ; .ORG 0 ; ;------------------------------------------------------------------------------- ; SECTOR 1 ; ; THIS SECTOR FOLLOWS THE CONVENTIONS OF AN IBM-PC MBR CONTAINING THE OS ; BOOTSTRAP CODE, PARTITION TABLE, AND BOOT SIGNATURE ; ;---------------------------------------------------------------------------- ; .FILL PT_LOC - $,0 ; FILL TO START OF PARTITION TABLE ; ; STANDARD IBM-PC PARTITION TABLE. ALTHOUGH A ; PARTITION TABLE IS NOT RELEVANT FOR A FLOPPY DISK, IT DOES NO HARM. ; THE CONTENTS OF THE PARTITION TABLE CAN BE MANAGED BY FDISK80. ; ; BELOW WE ALLOW FOR 32 SLICES OF ROMWBW CP/M FILESYSTEMS ; FOLLOWED BY A FAT16 PARTITION. THE SLICES FOLLOW THE ORIGINAL ; HD512 ROMWBW FORMAT. IF THE DISK IS USING HD1K, A SEPARATE ; PARTITION TABLE WILL BE IN PLACE AND RENDER THIS PARTITION TABLE ; IRRELEVANT. ; ; THE CYL/SEC FIELDS ENCODE CYLINDER AND SECTOR AS: ; CCCCCCCC:CCSSSSSS ; 76543210:98543210 ; PART0: .DB 0 ; ACTIVE IF $80 .DB 0 ; CHS START ADDRESS (HEAD) .DW 0 ; CHS START ADDRESS (CYL/SEC) .DB 0 ; PART TYPE ID .DB 0 ; CHS LAST ADDRESS (HEAD) .DW 0 ; CHS LAST ADDRESS (CYL/SEC) .DW 0,0 ; LBA FIRST (DWORD) .DW 0,0 ; LBA COUNT (DWORD) PART1: .DB 0 ; ACTIVE IF $80 .DB 0 ; CHS START ADDRESS (HEAD) .DW %1111111111000001 ; CHS START ADDRESS (CYL/SEC) .DB 6 ; PART TYPE ID .DB 15 ; CHS LAST ADDRESS (HEAD) .DW %1111111111010000 ; CHS LAST ADDRESS (CYL/SEC) .DW $4000,$0010 ; LBA FIRST (DWORD) .DW $0000,$000C ; LBA COUNT (DWORD) PART2: .DB 0 ; ACTIVE IF $80 .DB 0 ; CHS START ADDRESS (HEAD) .DW 0 ; CHS START ADDRESS (CYL/SEC) .DB 0 ; PART TYPE ID .DB 0 ; CHS LAST ADDRESS (HEAD) .DW 0 ; CHS LAST ADDRESS (CYL/SEC) .DW 0,0 ; LBA FIRST (DWORD) .DW 0,0 ; LBA COUNT (DWORD) PART3: .DB 0 ; ACTIVE IF $80 .DB 0 ; CHS START ADDRESS (HEAD) .DW 0 ; CHS START ADDRESS (CYL/SEC) .DB 0 ; PART TYPE ID .DB 0 ; CHS LAST ADDRESS (HEAD) .DW 0 ; CHS LAST ADDRESS (CYL/SEC) .DW 0,0 ; LBA FIRST (DWORD) .DW 0,0 ; LBA COUNT (DWORD) ; ; THE END OF THE FIRST SECTOR MUST CONTAIN THE TWO BYTE BOOT SIGNATURE. ; BOOTSIG .DB $55,$AA ; STANDARD BOOT SIGNATURE ; ;------------------------------------------------------------------------------- ; SECTOR 2 ; ; THIS SECTOR HAS NOT BEEN DEFINED AND IS RESERVED. ; ;---------------------------------------------------------------------------- ; .FILL SEC_SIZE,0 ; JUST FILL SECTOR WITH ZEROES ; ;------------------------------------------------------------------------------- ; SECTOR 3 ; ; OS AND DISK METADATA ; ;---------------------------------------------------------------------------- ; .FILL (BLK_SIZE * 3),0 ; FIRST 384 BYTES ARE NOT YET DEFINED ; ; THE FOLLOWING TWO BYTES ARE AN ADDITIONAL SIGNATURE THAT IS VERIFIED BY ; SOME HARDWARE BIOSES. ; PR_SIG .DB $5A,$A5 ; SIGNATURE GOES HERE ; .FILL (META_LOC - $),0 ; ; METADATA ; PR_WP .DB 0 ; (1) WRITE PROTECT BOOLEAN PR_UPDSEQ .DW 0 ; (2) PREFIX UPDATE SEQUENCE NUMBER (DEPRECATED?) PR_VER .DB RMJ,RMN,RUP,RTP ; (4) OS BUILD VERSION PR_LABEL .DB "Unlabeled$$$$$$$","$" ; (17) DISK LABEL (EXACTLY 16 BYTES!!!) .DW 0 ; (2) DEPRECATED PR_LDLOC .DW SYS_LOC ; (2) ADDRESS TO START LOADING SYSTEM PR_LDEND .DW SYS_END ; (2) ADDRESS TO STOP LOADING SYSTEM PR_ENTRY .DW SYS_ENT ; (2) ADDRESS TO ENTER SYSTEM (OS) ; #IF (META_SIZE != ($ - META_LOC)) .ECHO "META_SIZE VALUE IS WRONG!!!\r\n" !!! #ENDIF ; #IF ($ != PREFIX_SIZE) .ECHO "LOADER PREFIX IS WRONG SIZE!!!\r\n" !!! #ENDIF ; ;------------------------------------------------------------------------------- ; SECTOR 4+ ; ; PSYSTEM LOADER ; - LOAD SBIOS TO HIGH MEMORY (JUST BELOW HBIOS PROXY) ; - LOAD PSYSTEM BOOTSTRAP & JUMP TO IT ; ;---------------------------------------------------------------------------- ; #include "../HBIOS/hbios.inc" ; ; bel .equ 7 ; ASCII bell bs .equ 8 ; ASCII backspace lf .equ 10 ; ASCII linefeed cr .equ 13 ; ASCII carriage return ; interp_base .equ $0100 ; first loc used by the interpreter low_memory .equ $0100 ; lowest available ram location interleave .equ 1 ; interleaving factor (n:1) first_track .equ 1 ; first interleaved track skew .equ 0 ; track-to-track skew ; ; ; .org loader_loc ; ld sp,stack ; setup private stack ; call nl2 ; formatting ld hl,str_banner ; display boot banner call pstr ; do it ; ; Copy BIOS to running location ; ld hl,loader_end ; BIOS image is at end of loader ld de,bios_loc ; BIOS execution location ld bc,bios_size ; Size of BIOS ldir ; do it ; ; Copy p-System bootstrap to running location ; ld hl,loader_end + bios_size ; bootstrap appended after BIOS ld de,boot_loc ; bootstrap runs here ld bc,boot_size ; size of bootstrap code ldir ; do it ; ; Print some interesting info ; call nl2 ; spacing ld hl,str_info ; info string call pstr ; print it ld bc,bios_loc ; bios location adr call prthexword ; print it ld hl,str_info2 ; additional info string call pstr ; print it ld bc,boot_loc ; bootstrap location adr call prthexword ; print it ; ; Push key values onto the stack ; ld hl,seclen ; maximum number of bytes per sector push hl ld hl,sectors ; maximum number of sectors in table push hl ld hl,skew ; track-to-track skew push hl ld hl,first_track ; first interleaved track push hl ld hl,interleave ; interleaving factor push hl ld hl,seclen ; bytes per sector push hl ld hl,sectors ; sectors per track push hl ld hl,tracks ; tracks per disk push hl ld hl,bios_loc-2 ; top word of available ram - sbios address-2 push hl ld hl,low_memory ; bottom word of available ram push hl ld hl,bios_loc ; address of BIOS (start of jump table) push hl ld hl,interp_base ; starting address of the interpreter push hl #ifdef TESTBIOS ld hl,disks-1 ; maximum (highest) disk drive number push hl #endif ; jp boot_loc ; jump to bootloader ; ret ; ; ; Print string at HL on console, null terminated ; pstr: ld a,(hl) ; get next character or a ; set flags inc hl ; bump pointer regardless ret z ; done if null call cout ; display character jr pstr ; loop till done ; ; Print volume label string at HL, '$' terminated, 16 chars max ; pvol: ld b,16 ; init max char downcounter pvol1: ld a,(hl) ; get next character cp '$' ; set flags inc hl ; bump pointer regardless ret z ; done if null call cout ; display character djnz pvol1 ; loop till done ret ; hit max of 16 chars ; ; Start a newline on console (cr/lf) ; nl2: call nl ; double newline nl: ld a,cr ; cr call cout ; send it ld a,lf ; lf jp cout ; send it and return ; ; Print a dot on console ; pdot: push af ld a,'.' call cout pop af ret ; ; Print the hex byte value in A ; prthexbyte: push af push de call hexascii ld a,d call cout ld a,e call cout pop de pop af ret ; ; Print the hex word value in BC ; prthexword: push af ld a,b call prthexbyte ld a,c call prthexbyte pop af ret ; ; Convert binary value in A to ASCII hex characters in DE ; hexascii: ld d,a call hexconv ld e,a ld a,d rlca rlca rlca rlca call hexconv ld d,a ret ; ; Convert low nibble of A to ASCII hex ; hexconv: and 0Fh ; low nibble only add a,90h daa adc a,40h daa ret ; ; Output character from A ; cout: ; Save all incoming registers push af push bc push de push hl ; ; Output character to console via HBIOS ld e,a ; output char to E ld c,CIO_CONSOLE ; console unit to C ld b,BF_CIOOUT ; HBIOS func: output char rst 08 ; HBIOS outputs character ; ; Restore all registers pop hl pop de pop bc pop af ret ; ; Input character to A ; cin: ; Save incoming registers (AF is output) push bc push de push hl ; ; Input character from console via hbios ld c,CIO_CONSOLE ; console unit to c ld b,BF_CIOIN ; HBIOS func: input char rst 08 ; HBIOS reads character ld a,e ; move character to A for return ; ; Restore registers (AF is output) pop hl pop de pop bc ret ; ; Return input status in A (0 = no char, != 0 char waiting) ; cst: ; Save incoming registers (AF is output) push bc push de push hl ; ; Get console input status via HBIOS ld c,CIO_CONSOLE ; console unit to C ld b,BF_CIOIST ; HBIOS func: input status rst 08 ; HBIOS returns status in A ; ; Restore registers (AF is output) pop hl pop de pop bc ret ; str_banner .db "RomWBW HBIOS p-System Loader v" .db BIOSVER .db 0 str_info .db "Loading pSystem BIOS @ 0x",0 str_info2 .db ", Bootstrap @ 0x",0 ; .fill 32,0 stack .equ $ ; .fill loader_end - $ ; .end