; ; JR-IDE Project ; - (c) 2017 Alan Hightower ; - Portions of code (c) IBM and (c) Microsoft ; ; This program is free software: you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation, either version 3 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . ; ; Portions of the MBR and boot sector code were derrived from ; disassembly and reverse annotation of the PC-DOS 5.02 master ; boot record strap and FAT boot sector. include "jride.inc" _MBRSEG segment public use16 'CODE' public _entry assume cs:_MBRSEG, ds:nothing, es:nothing org 0600h _entry: ; Copy ourselves from transient load sector (7c00) to ; our execution address (0600) and setup stack between ; the two. cli xor ax, ax mov ss, ax mov sp, 7c00h mov si, sp mov ds, ax mov es, ax sti cld mov di, 0600h mov cx, 0100h rep movsw jmp far ptr 00000h, _start _start: IFDEF FIXUP_DOSMEM_MBR mov word ptr ds:[400h + BDA_MEMORY_SIZE], 736 mov word ptr ds:[400h + BDA_ADAPTER_MEMORY], 736 ENDIF mov si, _part_A mov bl, 4 _check_part: cmp byte ptr ds:[si], 080h jz _loc_002 cmp byte ptr ds:[si], 0 jnz _loc_003 add si, 10h dec bl jnz _check_part int 18h _loc_002: mov dx, word ptr ds:[si] mov cx, word ptr ds:[si + 2] mov bp, si _loc_006: add si, 10h ; next partition entry dec bl ; one less entry count jz _try_boot cmp byte ptr ds:[si], 0 jz _loc_006 _loc_003: mov si, _str_invalid _print_error: lodsb cmp al, 0 jz _fatal_halt push si mov bx, 7 mov ah, 0eh int 10h pop si jmp _print_error _fatal_halt: jmp _fatal_halt _try_boot: mov di, 5 ; retry count _try_boot_retry: mov bx, 7c00h mov ax, 0201h push di int 13h pop di jnb _verify_load xor ax, ax int 13h dec di jnz _try_boot_retry mov si, _str_error_load jmp _print_error _verify_load: mov si, _str_missing mov di, 7dfeh cmp word ptr ds:[di], 0aa55h jnz _print_error mov si, bp jmp far ptr 00000h, 07c00h _str_invalid: db 'Invalid partition table', 0 _str_error_load: db 'Error loading operating system', 0 _str_missing: db 'Missing operating system', 0 org 007beh _part_A: _MBRSEG ends BOOT_SECTOR equ (07c00h) BS_OEM_ID equ (BOOT_SECTOR + 03h) BS_BYTES_PER_SEC equ (BOOT_SECTOR + 0bh) BS_SEC_PER_CLUSTER equ (BOOT_SECTOR + 0dh) BS_RESERVED_SECS equ (BOOT_SECTOR + 0eh) BS_FAT_COUNT equ (BOOT_SECTOR + 10h) BS_ROOT_ENTRIES equ (BOOT_SECTOR + 11h) BS_TOTAL_SECTORS equ (BOOT_SECTOR + 13h) BS_MEDIA_DESCR equ (BOOT_SECTOR + 15h) BS_SEC_PER_FAT equ (BOOT_SECTOR + 16h) BS_SEC_PER_TRACK equ (BOOT_SECTOR + 18h) BS_TOTAL_HEADS equ (BOOT_SECTOR + 1ah) BS_HIDDEN_SECTORS equ (BOOT_SECTOR + 1ch) BS_BIG_SEC_TOTAL equ (BOOT_SECTOR + 20h) BS_DRIVE_NUMBER equ (BOOT_SECTOR + 24h) BS_BOOT_SIGNATURE equ (BOOT_SECTOR + 26h) BS_VOLUME_ID equ (BOOT_SECTOR + 27h) BS_VOLUME_LABEL equ (BOOT_SECTOR + 2bh) BS_FAT_TYPE equ (BOOT_SECTOR + 36h) ; additional loaded FDPT from here forward (+11 bytes) ; 00h = Step rate / unload time ; 01h = non-dma mode / load time ; 02h = motor off delay ; 03h = bytes per sector enumeration ; 04h = sectors per track ; 05h = sector gap length ; 06h = data length ; 07h = sector gap length when formatting ; 08h = format filler byte ; 09h = head settle time in ms ; 0ah = motor start time in 1/8 sec ; 0bh = maximum track number ; +global arguments CURRENT_HEAD equ (BOOT_SECTOR + 25h) ; 8-bits (byte ptr) CURRENT_CYL equ (BOOT_SECTOR + 4dh) ; 10-bits (word ptr) CURRENT_SECTOR equ (BOOT_SECTOR + 4fh) ; 6-bits (byte ptr) ROOT_FILE_SECTOR equ (BOOT_SECTOR + 49h) ; dword ptr ROOT_DIR_SECTOR equ (BOOT_SECTOR + 50h) ; dword ptr _BOOTSEG segment public use16 'CODE' assume cs:_TEXT, ds:nothing, es:nothing org 07c00h _entry_bs: jmp _start_bs nop ; Boot sector header table here - filled in on creation org 07c3eh _start_bs: cli ; Setup working stack below us xor ax, ax mov ss, ax mov sp, 7c00h ; zero es as well push ss pop es ; Load Disk Parameter Table (DPT - Int 1Eh) ; far pointer into ds:si mov bx, 1eh * 4 lds si, ss:[bx] ; Why preserve these? push ds push si push ss push bx ; Copy 11 bytes from DPT overwriting ; instructions above? mov di, _start_bs mov cx, 11 cld rep movsb push es pop ds mov byte ptr ds:[di - 2], 0fh ; head settle time mov cx, ds:[BS_SEC_PER_TRACK] mov ds:[di - 7], cl ; sector per track ; Update the 1eh vector pointer to new table mov ds:[bx + 2], ax mov word ptr ds:[bx], _start_bs sti ; Reset disk sub-system int 13h jc _boot_fail xor ax, ax cmp ds:[BS_TOTAL_SECTORS], ax jz _find_io_sys mov cx, ds:[BS_TOTAL_SECTORS] mov ds:[BS_BIG_SEC_TOTAL], cx _find_io_sys: mov al, ds:[BS_FAT_COUNT] mul word ptr ds:[BS_SEC_PER_FAT] add ax, ds:[BS_HIDDEN_SECTORS] adc dx, ds:[BS_HIDDEN_SECTORS + 2] add ax, ds:[BS_RESERVED_SECS] adc dx, 0 mov ds:[ROOT_DIR_SECTOR ], ax mov ds:[ROOT_DIR_SECTOR + 2], dx mov ds:[ROOT_FILE_SECTOR ], ax mov ds:[ROOT_FILE_SECTOR + 2], dx mov ax, 32 mul word ptr ds:[BS_ROOT_ENTRIES] ; round up to nearest sector mov bx, ds:[BS_BYTES_PER_SEC] add ax, bx dec ax div bx add word ptr ds:[ROOT_FILE_SECTOR ], ax adc word ptr ds:[ROOT_FILE_SECTOR + 2], 0 mov bx, 0500h mov dx, ds:[ROOT_DIR_SECTOR + 2] mov ax, ds:[ROOT_DIR_SECTOR] call _lba_to_chs jc _boot_fail mov al, 1 call _disk_read jc _boot_fail mov di, bx ; 7cd7 - 8b fb mov cx, 11 mov si, _str_files repe cmpsb ; 7cdf - f3 a6 jnz _boot_fail lea di, ds:[bx + 020h] ; 7ce3 - 8d 7f 20 mov cx, 000bh ; 7ce6 - b9 0b 00 repe cmpsb ; 7ce9 - f3 a6 jz _loc_005b ; 7ceb - 74 18 -> 7d05 _boot_fail: mov si, _str_nodisk call _print_string xor ax, ax int 16h ; Wait for keypress pop si pop ds pop word ptr ds:[si] pop word ptr ds:[si + 2] int 19h ; Retry boot process _loc_007b: pop ax pop ax pop ax jmp _boot_fail _loc_005b: mov ax, ds:[bx + 01ah] dec ax dec ax mov bl, ds:[BS_SEC_PER_CLUSTER] xor bh, bh mul bx add ax, ds:[ROOT_FILE_SECTOR] adc dx, ds:[ROOT_FILE_SECTOR + 2] ; Copy the first three sectors to ; 0070:0000 which is actually below ; us and the stack mov bx, 0700h mov cx, 3 _copy_dos: push ax push dx push cx call _lba_to_chs jc _loc_007b mov al, 1 call _disk_read pop cx pop dx pop ax jc _boot_fail add ax, 1 adc dx, 0 add bx, word ptr ds:[BS_BYTES_PER_SEC] loop _copy_dos ; Jump to the first three sectors of the ; IO image and let it finish copying ; itself mov ch, ds:[BS_MEDIA_DESCR] mov dl, ds:[BS_DRIVE_NUMBER] mov bx, ds:[ROOT_FILE_SECTOR] mov ax, ds:[ROOT_FILE_SECTOR + 2] jmp far ptr 00070h, 00000h ; ******************************************************** ; Function - Print a null terminated string ; ; Inputs: DS:SI = Far pointer to start of string ; ; Outputs: None ; ; Clobbers: SI, AX, BX, flags _print_string proc near public _print_string_loop: lodsb or al, al ; jz _print_string_done jz _temporary mov ah, 0eh ; BIOS Video: Teletype mov bx, 7 ; active page int 10h jmp _print_string_loop _print_string_done: ; ret _print_string endp _lba_to_chs proc near public cmp dx, ds:[BS_SEC_PER_TRACK] jae _loc_009b div word ptr ds:[BS_SEC_PER_TRACK] inc dl mov ds:[CURRENT_SECTOR], dl xor dx, dx div word ptr ds:[BS_TOTAL_HEADS] mov ds:[CURRENT_HEAD], dl mov ds:[CURRENT_CYL], ax clc ret _loc_009b: stc _temporary: ret _lba_to_chs endp ; ******************************************************** ; Function - Transfer disk sectors ; ; Inputs: AL = Number of sectors to transfer ; + Boot sector parameter block filled out ; ; Outputs: None ; ; Clobbers: Just about everything _disk_read proc near public mov ah, 2 mov dx, ds:[CURRENT_CYL] mov cl, 6 shl dh, cl or dh, ds:[CURRENT_SECTOR] mov cx, dx xchg cl, ch mov dl, ds:[BS_DRIVE_NUMBER] mov dh, ds:[CURRENT_HEAD] int 13h ret _disk_read endp _str_nodisk: db CR, LF, db 'Non-System disk or disk error', CR, LF db 'Replace and press any key when ready', CR, LF, 0 _str_files: db 'IBMBIO COM' db 'IBMDOS COM' _BOOTSEG ends end