;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;Copyrights(C) 2005, 2006 by Sohail Qayum Malik;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;boot.asm(The secondry boot code). ;; ;;Written by, Soni Malik(soni.malik@gmail.com). ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;State of machine when controll was transferred to us. ;; ;;DL = drive-id of the device we booted from. ;; ;;DH = head-number of the device we booted from. ;; ;;ES:SI = in case of HD boot the segmented address of the partition table's ;; ;; active partition table entry. ;; ;;DS = 0x1000 ;; ;;SS = 0x0000 ;; ;;SP = 0x7c00 ;; ;; ;; ;;This programm will be loaded in the low memory area 1000:0000, by the ;; ;;bootblok.img.This programm will hen copy itself to the HMA and then ;; ;;do the rest of the execution there. ;; ;;The main purpose of this programm is to perfrom test, gather data ;; ;;and finally load the kernel at address 1000:0000, but before that it ;; ;;also switch to the protected mode and finally jumps to the kernel. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; LOWSEGMENT equ 1000h LOWOFFSET equ 0000h SPOFFSET equ 0ffffh HIGHSEGMENT equ 0ffffh HIGHOFFSET equ 00010h SECTORSINRESERVEDAREA equ 0eh FATCOPIES equ 10h SECTORSPERFAT equ 16h SECTORSPERTRACK equ 18h SECTORSPERCLUSTER equ 0dh BYTESPERSECTOR equ 0bh DOSMEDIADESCRIPTOR equ 15h ENTRIESPERROOTDIRECTORY equ 11h HEAD equ 02h TRACK equ 04h SECTOR equ 06h BXINDEX equ 08h ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;The segment address of the area where the bootsector and the FAT and the ;; ;root directory will the read in before being copied at the ;; ;cs:[_free_space + HIGHOFFSET]. This should be in the low memory, THIS ;; ;SEGMENT IS NOT YET FINALIZED. ;; ; ;; FILESYSTEMSEGMENT equ 1000h ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; STATUS equ 12h SECTORSREAD equ 10h DRIVE equ 06h CR equ 0dh LF equ 0ah EOL equ 00h ;Lets save the registers that were set before us. push es push si push dx ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;We are moving our self, from 1000:0000 to ffff:0010. ;From low to high memory. mov si, LOWOFFSET ;0x0000 mov di, HIGHOFFSET ;0x0010 mov ax, HIGHSEGMENT ;0xffff mov es, ax mov cx, [_size] cld rep ;DF is cleared. movsb ;move from ds:si to es:di ;till cx != 0. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;remove them from the old stack. ;later on we'll push them on new stack. pop dx pop si pop es ;update the ds, ss, sp, important we've created a new stack. mov ax, HIGHSEGMENT ;0xffff mov ds, ax ;because we are moving the stack. cli mov ss, ax ;do it. mov sp, SPOFFSET ;0xffff sti ;done. ;push them on the new stack and update the bp. push es push si push dx ;I want them to there when I do this "mov sp, sp". mov bp, sp ;**************************************************************************** ;We'll now jump to our new location and continue execution in the HMA. ;ss=ds=sp=cs=0x0ffff, es=NOTHING ,sp=bp=0xffff - 06h(fff9). ;DF=clear. ;Finally the jump, "jump far HIGHSEGMENT:_start + HIGHOFFSET or some ;thing like that. db 0eah, 3eh, 00h, 0ffh, 0ffh ;**************************************************************************** ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; _start: ;We are finally in the HMA, inform others. mov si, MHIGH + HIGHOFFSET call near _print ;Print the address of the _FAT12fs_driver. ;I dont know whay I doing this, I dont intend to keep the machine ;in real mode for long, and in future I'll not use the FAT12. mov si, MFAT12 + HIGHOFFSET call near _print push cs call near _print_hex pop ax push _FAT12fs_driver + HIGHOFFSET call near _print_hex pop ax ;sp=bp=fff9h ;Pushing the arguments before calling _FAT12fs_driver. push 0000h ;returned status push 0000h ;number of sectors read push ds ;segment which has the filename push kernel + HIGHOFFSET ;offset into the above segment push 1000h ;segment where the file is copied push 0000h ;offset into the above segment push 0000h ;the drive ;The far call to the function push cs call near _FAT12fs_driver add sp, 0ah ;SP = SP - 10, shrinking the top to the point where the number of sectors read are. ;sp=fff5h, bp=fff9h ;The _FAT12fs_driver returns. ;See if status code is zero(success), if not hang forever(jump to _badKarma). cmp byte [bp - 02h], 00h je _file_read mov si, MFAT12ERROR + HIGHOFFSET call near _print_nl call near _print push word [bp - 02h] call near _print_hex jmp _badKarma _file_read: mov si, MKREAD + HIGHOFFSET call near _print push word [bp - 04h] call near _print_hex add sp, 06h ;sp=bp=fff9h ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;We should not reach this area, if we do then print the message and ;hang forver. _badKarma: call _print_nl mov si, MHLT + HIGHOFFSET call near _print _hold: hlt jmp _hold ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;C calling conventions, called function does not clean the stack above ;its own stack frame. ;The call should be far. ;call far _FAT12fs_driver ;By the way, why not this instruction "call far _FAT12fs_driver". ;Well we want our output to a simple plane binary file no ;crazy ELF relocation tables or EXE style relocation items. ;Place to hold the returned values by the function _FAT12fs_driver. ;push 0000h ;Status of the operation ; ;00h = successful operation ; ;otherwise the value will be the value ; ;returned by the ROM read or write opearions in ; ;ah. ;push 0000h ;Number of sectors read. ;Arguments to the function _FAT12fs_driver. ; ;Argument pair DS:offset, which is the address of the name of the file. ;push ds ;The segment address. ;push 0000h ;The offset address. ; ;Argument pair ES:BX, the area or buffer where the file will be read in. ;push 0000h ;push _free_space + HIGHOFFSET ; ;The drive where the FAT12 file system is availabe. ;These values should be 00h or 01h for /dev/fd0 and /dev/fd1 ;push 0000h ; ;Finally the call to the function. ;push cs ;call near _FAT12fs_driver _FAT12fs_driver: push bp mov bp, sp sub sp, 08h ;Saving all the clobbered registers. push ax push bx push cx push dx push ds push si push es ;Lets reset the FDC. At error, return with error. ;Why bother the processor, when drive is not ready. mov ah, 00h mov dl, [bp + DRIVE] ;[bp + 06h] int 13h mov [bp + STATUS], ah ;[bp + 12h] ;The short jump has only 8 bits of displacement into IP ;so the target which is _error_jump_1 is more than 256 bytes ;away from the current value of IP this is why I using the ;_proxy_jump_1. jc _proxy_jump_1 jmp _continue_jump_1 _proxy_jump_1: jmp _error_jump_1 _continue_jump_1: ;Lets initialize. mov word [bp - HEAD], 0000h mov word [bp - TRACK], 0000h mov word [bp - SECTOR], 0001h mov word [bp - BXINDEX], 0000h ;BXINDEX = BX ;Lets go and read the boot sector. ;The register pair ES:BX should have the address of buffer ;where the sector will be read into. mov ax, FILESYSTEMSEGMENT mov es, ax mov bx, [bp - BXINDEX] ;Now read the bootsector, the CHS is read from the stack. mov ah, 02h ;service number. mov al, 01h ;number of sectors to read. mov ch, [bp - TRACK] ;track number. mov cl, [bp - SECTOR] ;starting sector number. mov dh, [bp - HEAD] ;head number. mov dl, [bp + DRIVE] ;[bp + 06h] int 13h mov [bp + STATUS], ah ;ah has the status of operation. [bp + 12h] jc _proxy_jump_2 jmp _continue_jump_2 _proxy_jump_2: jmp _error_jump_1 _continue_jump_2: ;Update the BX by the number of bytes in a sector. ;Since we've just read the boot sector. es mov ax, [BYTESPERSECTOR] add [bp - BXINDEX], ax mov bx, [bp - BXINDEX] ;We now need the starting sector number of the FAT. ;The variable [bp - SECTOR] already has the starting sector number ;of the reserved area, which is the sector number of the bootsector. ;So reserved area is bootsector + "few other sectors(the sectors per FAT)". es mov ax, [SECTORSINRESERVEDAREA] add [bp - SECTOR], ax ;Now to get the actual value of CHS, before reading the FAT. _make_CHS_1: es mov ax, [SECTORSPERTRACK] ;Get sectors per track, cmp [bp - SECTOR], ax ;compare them with the current sector number, jbe _success_jump_1 ;if current sector number is equal or below the sectors per tarck then head and track nunbers should stay the same, sub [bp - SECTOR], ax ;since current sector number is greater than sectors per track, so lets move to next tack of the cylinder, mov ax, 0001h ;head now should be changed, so deduct 1 - head if the answer is zero then sub ax, [bp - HEAD] ;then track should be changed too or it should be incremented other wise not. mov [bp - HEAD], ax jnz _success_jump_1 add word [bp - TRACK], 0001h ;Since track has been changed jump back to the begining to see if we need, jmp _make_CHS_1 ;such adjustments. ;********************************************************************** _success_jump_1: ;Now lets get down and read the FAT. es mov cx, [SECTORSPERFAT] _success_jump_2: push cx mov ah, 02h ;service number. mov al, 01h ;number of sectors to read. mov ch, [bp - TRACK] ;track number. mov cl, [bp - SECTOR] ;starting sector number. mov dh, [bp - HEAD] ;head number. mov dl, [bp + DRIVE] int 13h mov [bp + STATUS], ah ;ah has the status of operation. jc _proxy_jump_3 jmp _continue_jump_3 _proxy_jump_3: jmp _error_jump_1 _continue_jump_3: add word [bp - SECTOR], 0001h _make_CHS_2 es mov ax, [SECTORSPERTRACK] ;Get sectors per track, cmp [bp - SECTOR], ax ;compare them with the current sector number, jbe _success_jump_3 ;if current sector number is equal or below the sectors per tarck then head and track nunbers should stay the same, sub [bp - SECTOR], ax ;since current sector number is greater than sectors per track, so lets move to next tack of the cylinder, mov ax, 0001h ;head now should be changed, so deduct 1 - head if the answer is zero then sub ax, [bp - HEAD] ;then track should be changed too or it should be incremented other wise not. mov [bp - HEAD], ax jnz _success_jump_3 add word [bp - TRACK], 0001h ;Since track has been changed jump back to the begining to see if we need, jmp _make_CHS_2 ;such adjustments. _success_jump_3: es mov ax, [BYTESPERSECTOR] add [bp - BXINDEX], ax mov bx, [bp - BXINDEX] pop cx loop _success_jump_2 ;**************************************************************************** ;Now lets go and read the root directory. ;Get the number of entries in the root directory. es mov ax, [ENTRIESPERROOTDIRECTORY] ;Each entry is 32 bytes long. mov bx, 0020h ;Get the size of directory on bytes. ;AX = AX * bx mul bx ;Now convert them in the number of sectors. ;Get the bytes per sector value. es mov bx, [BYTESPERSECTOR] ;AX:DX/bx, the Conefficent in AX and remainder in DX. xor dx, dx div bx ;Perpare the counter register, now CX is the nunber of sectors. mov cx, ax ;Since BX has been clobbered.... mov bx, [bp - BXINDEX] _success_jump_4: push cx mov ah, 02h ;service number. mov al, 01h ;number of sectors to read. mov ch, [bp - TRACK] ;track number. mov cl, [bp - SECTOR] ;starting sector number. mov dh, [bp - HEAD] ;head number. mov dl, [bp + DRIVE] int 13h mov [bp + STATUS], ah ;ah has the status of operation. jc _error_jump_1 ;if error then CF=1. add word [bp - SECTOR], 0001h _make_CHS_3 es mov ax, [SECTORSPERTRACK] ;Get sectors per track, cmp [bp - SECTOR], ax ;compare them with the current sector number, jbe _success_jump_5 ;if current sector number is equal or below the sectors per tarck then head and track nunbers should stay the same, sub [bp - SECTOR], ax ;since current sector number is greater than sectors per track, so lets move to next tack of the cylinder, mov ax, 0001h ;head now should be changed, so deduct 1 - head if the answer is zero then sub ax, [bp - HEAD] ;then track should be changed too or it should be incremented other wise not. mov [bp - HEAD], ax jnz _success_jump_5 add word [bp - TRACK], 0001h ;Since track has been changed jump back to the begining to see if we need, jmp _make_CHS_3 ;such adjustments. _success_jump_5: es mov ax, [BYTESPERSECTOR] add [bp - BXINDEX], ax mov bx, [bp - BXINDEX] pop cx loop _success_jump_4 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; xor dx, dx mov ax, [bp - BXINDEX] es mov bx, [BYTESPERSECTOR] div bx mov [bp + SECTORSREAD], ax ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mov ax, FILESYSTEMSEGMENT mov ds, ax xor si, si mov ax, cs mov es, ax mov di, _free_space + HIGHOFFSET mov cx, [bp - BXINDEX] rep movsb ;cs ;push word [_free_space + HIGHOFFSET + 0200h] ;call near _print_nl ;call near _print_nl ;call near _print_hex ;pop ax ;cs ;push word [_free_space + HIGHOFFSET + 1400h] ;call near _print_nl ;call near _print_hex ;pop ax _error_jump_1: ;Restoring all the clobbered registers. pop es pop si pop ds pop dx pop cx pop bx pop ax mov sp, bp pop bp retf _print_hex: push bp mov bp, sp push ax push cx push dx mov cx, 04h mov dx, [bp + 04h] _print_digit: rol dx, 04h mov ax, 0e0fh and al, dl add al, 90h daa adc al, 40h daa int 10h loop _print_digit pop dx pop cx pop ax mov sp, bp pop bp retn _print_nl: push bp mov bp, sp push ax push bx mov al, CR mov ah, 0eh mov bx, 0007h int 10h mov al, LF int 10h pop bx pop ax mov sp, bp pop bp retn _print: push bp mov bp, sp push ax push bx call _print_nl _print_1: lodsb ;Copy byte from DS:SI to al. or al, al jz _stop mov ah, 0eh mov bx, 0007h int 10h ;Jump to _print_1 jmp _print_1 _stop: pop bx pop ax mov sp, bp pop bp retn ;DATA MHIGH db "Secondry boot moved to HMA.",EOL MHLT db "System halted(secondry boot).",EOL MFAT12 db "_FAT12fs_driver loaded at ",EOL MFAT12ERROR db "_FAT12fs_driver read error ",EOL kernel db "MYKERNELIMG",EOL MKREAD db "Kernel read at 10000000, size in sectors ",EOL ;More Data. ;Total number of bytes to be read from low to high memory area. ;This value should be orgined at 1 to max. _size dw 0fff0h ;Hopefully this space will be large enough to accomodate two copies of FAT ;and a directory array and a bootsector.... _free_space: ;Space will be occupied like the index below. ;Bootsector 512 bytes. ;Back to Back two copies of FAT. Each FAT is 9 sectors wide so ;512 * 9 * 2 + 512(bootsector). ;Copy of the directory. It is 14 sectors wide, so.... ;14 * 512 +{512 * 9 * 2(FATs) + 512(bootsector)}. ; ;So total area required is 16896 bytes, so programm wisely. :-( ; ;soni.malik@gmail.com ; ;