Code:
;[WORD WRAP PROTECTION]------------------------------------------------------------------------------------------------------------------------
; Written By: Jeremy. A. Wildsmith
; Copyright jetaos, 2009, Jeremy. A. Wildsmith
; Main executable of the bootloader.
[BITS 16] ; Describe code is 16-bit, in real-mode, the processor runs in 16-bit mode
[ORG 0x7C00] ; Tells the assembler where the code will be in memory
; after being loaded
jmp _start
;
;GDT
gdt:
gdt_null:
dq 0 ;First entry in the gdt is null, and is reserved for the processor.
gdt_code:
;DWORD1
dw 0x0FFFF ; Base is 0x0, limit is 0xFFFF. GDT Size is 0xFFFF bytes long
dw 0x0 ; No use of the last WORD
;DWORD2
db 0x0 ; First bits in base address is 0
db 10011010b ; Ring0, Is data or code|Readable, non-conforming, code segment. Segment is present
db 11001111b ; Limit 0x0F, 32bit size, 4Kb multiplier
db 0x0 ; Last bits in base address is 0
gdt_data:
;DWORD1
dw 0x0FFFF ; Base is 0(overlaps code segment) Limit is 0xFFFF
dw 0x0 ; No use of the last WORD
;DWORD2
db 0x0 ; First bits in base address
db 10010010b ; Non-conforming, writable, data segment, data or code, expands down, and is present
db 11001111b ; 32 bit, 'BIG' , LIMIT 0x0F
db 0x0 ; Last bits in the base address
gdt_end:
;GDT Descriptor
gdt_desc:
dw gdt_end - gdt ; Size of GDT
dd gdt ; Address of GDT
_start:
xor ax, ax ; Zero ax
mov ds, ax ; Setup data segment register to 0
mov es, ax ; Setup extra segment register.
mov [data_iBootDriveSource], dl ; Get boot source drive from dl register, and store it.
mov ebp, data_sBootMessage
call func_PrintSystemMessage ; Print system message
call func_GetSysMemory ; Get amount of RAM in the system.
mov [data_sysBootInfo + SysBootInfo.sysMemKbMain], cx ; Store result.
mov [data_sysBootInfo + SysBootInfo.sysMemKb64blk], dx ; Store result.
mov ax, 0x1000
mov di, ax
mov [data_sysBootInfo + SysBootInfo.pMemEntries], ax ; store the memMap at es:di
call func_GetSysMemoryMap ; Get system memory map.
mov [data_sysBootInfo + SysBootInfo.numEntries], bp ; Bp contains number of entries
mov BX, 0x2000 ; Dump to ds:BX
mov AL, 30 ; Read 30 sectors
mov CL, 2 ; Start reading at sector 2
mov DL, byte [data_iBootDriveSource] ; Read from a drive defined in variable data_iBootDriveSource
call func_DumpSectors ; Dump selected sectors in DS:BX
mov ebp, data_sBooting ; Load message into ebp register
call func_PrintSystemMessage ; Print system message
;Load GDT
cli ; Clear interrupts
lgdt [gdt_desc] ; Load gdt
;Move processor into protected mode.
mov eax, cr0 ; Load CR0 into EAX
or eax, 1 ; Set the first bit in eax
mov cr0, eax ; Load EAX into CR0
JMP 08h:clear_pipe ; Clear pipe, setup stack and pass control to kernel
hlt ; Jump to current location(endless loop)
func_GetSysMemory:
push EBX
push EAX
;Null out all general purpose registers, different BIOS store results in different registers.
xor edx, edx
xor ecx, ecx
xor eax, eax
mov ax, 0xE801 ;Service
int 0x15
jc jmp_BootError ;If carryflag is set, then an error occured getting memory.
cmp ah, 0x86 ; Function not supported.
je jmp_BootError
cmp ah, 0x80
je jmp_BootError
jcxz func_GetSysMemory_useEax ;Does the bios use registers EAX and EBX?
;Otherwise use ECX and EDX
jmp func_GetSysMemory_end
func_GetSysMemory_useEax: ;Means use Eax and Ebx
mov cx, ax
mov dx, bx
func_GetSysMemory_end:
add cx, 1024
pop EAX
pop EBX
ret
;bp = entry count
;es:di = Base of buffer.
func_GetSysMemoryMap:
mov eax, 0x0000E820 ;Some bios requires low-word to be cleared.
xor ebx, ebx ;Start at beginning.
xor bp, bp
mov ecx, 24 ;Size of buffer = 24 bytes
mov edx, 'PAMS' ;SMAP
INT 0x15
jc jmp_BootError
jcxz .skipentry ;If bytes read is zero bytes long, skip it.
.checkentry: ;Otherwise check it
mov ecx, [es:di + MemoryMapEntry.length] ;Load lower-dword of len
test ecx, ecx ;Is it zero
jne .goodentry ;If not jump to good entry
mov ecx, [es:di + MemoryMapEntry.length + 4] ;Load upper-dword of len
jecxz .skipentry ;Jump if ECX is zero
.goodentry:
inc bp
add di, 24
cmp ebx, 0
je .end
.nextentry:
mov edx, 'PAMS'
mov ecx, 24
mov eax, 0x0000E820
INT 0x15
jcxz .skipentry
jmp .checkentry
.skipentry:
cmp ebx, 0
jne .nextentry
.end:
ret;
func_DumpSectors:
; Assumes:
; Data segment is setup
; BX = offset to data segment where sector is loaded.
; AL = Number of sectors to read
; CL = Disk sector
; DL = Drive
func_DumpSectors_ResetDrive:
mov AH, 0x0 ; Call service 0
INT 0x13 ; Reset drive
jc func_DumpSectors_ResetDrive ; If carry Flag is set(reset drive failed) attempt to reset again
mov AH, 0x02 ; Service 2
mov CH, 0 ; Cylinder 0
mov DH, 0 ; Disk head
INT 0x13 ; Make call to service
jc func_DumpSectors_ResetDrive ; If carry Flag is set(read drive failed) attempt to reset again
ret ; Return to caller
jmp_BootError:
mov ebp, data_sError ; Load error message into ebp register.
call func_PrintSystemMessage ; Print message
call func_WaitForKey ; Wait for key press
func_WaitForKey:
xor ah, ah ;Make call to service 0
INT 0x16 ;Execute interrupt 0x10
ret
func_moveCursorDown:
pushad ;Reserve Registers
;Get cursor position
mov AH, 0x03 ;Get cursor position, DH = row, DL = Col
mov BH, 0x00 ;Page #0 = graphics mode
INT 0x10 ;Execute video interrupt
;Set cursor position
inc DH ;Increment current row by one
xor DL, DL ;Reset del register(col number)
mov AH, 0x02 ;Set cursor position
mov BH, 0x00 ;Page #0 = graphics mode
INT 0x10 ;Execute video interrupt
popad ;Restore Registers
retn
func_PrintSystemMessage:
;Assumes ebp is base address of system message
push ebp ; Preserve ebp register.
mov ebp, data_sSystemPrefix ; Load ebp with system label prefix message
call func_PrintString ; Call Print Function
pop ebp ; Restore ebp register. Which is the system message
call func_PrintString ; Call print function
ret ; Return to caller
func_PrintString:
;Assume ebp contains pointer to start of string.
;$ == linedown char.
push ebp ; reserve ebp register.
@func_PrintString_loop1:
mov AL, byte [EBP] ; set al register to the character placed at ebp
cmp AL, 0 ; if AL == 0
jz func_PrintString_end1 ; return
cmp AL, '$' ; if AL != linedown Char
jne func_PrintString_print ; print character
call func_moveCursorDown ; else linedown
jmp func_PrintString_loop1_continue ; and continue loop
func_PrintString_print:
call func_PrintChar ; print char placed in al register
func_PrintString_loop1_continue:
inc EBP ; Increase ebp to move to next character
jmp @func_PrintString_loop1 ; go to start of loop
func_PrintString_end1: ; The end of the functions, all registers are
; restored to their state when callee made the call.
pop ebp ; Restore ebp register
retn ; return to caller
retn
func_PrintChar:
;Assume AL register contains ascii character to print.
;Preserve registers.
push EAX
push EBX
mov AH, 0x0E ; Service is 0x0E
mov BH, 0x00 ; Page #0
mov BL, 0x04 ; Colors
int 0x10 ; Call interrupt
;Restore registers
pop EBX
pop EAX
retn ; return to caller
[BITS 32] ;32 bit instructions for when the processor is put into protected mode.
clear_pipe: ;Assumes far jump was made to this code, at segment 0x8, which will cear the instruction pipe
mov ax, 10h ; Set AX Register to 0x10(16d), which points to the data segment
mov ds, ax ; Setup data segment
mov ss, ax ; Setup stack segment
mov esp, 090000h ; Move stack pointer to 0x90000 offset from data segment
push data_sysBootInfo ; push pointer to bootinfo struct.
call 02000h ; Jmp to kernel
add esp, 4 ; Cleanup stack
hlt ; If for some weird reason the jump isn't made, or a return jump is made, hault the processor to prevent it from executing..
;data, Strings are null terminated.
data_sError db 'Boot Error.$',0
data_sBootMessage db 'BL(b3.v[1.0])$',0
data_sSystemPrefix db '[SYS] ',0
data_sBooting db 'BL loading kern$',0
data_iBootDriveSource db 0
data_sysBootInfo dq 0
struc MemoryMapEntry
.addrBase resq 1
.length resq 1
.type resd 1
.acpi_null resd 1
endstruc
struc SysBootInfo
.pMemEntries resd 1
.numEntries resw 1
.sysMemKbMain resd 1
.sysMemKb64blk resd 1
endstruc
;NULL Memory Region + Bootloader Signature
TIMES 510 - ($ - $$) db 0 ; Fill the rest of the program with 0. $ = cur loc,
; $$ == start
; Bootloader must be 512 bytes long(Size of one sector).
DW 0xAA55 ;Apply signature telling the bios this is a valid boot loader.
;[WORD WRAP PROTECTION]------------------------------------------------------------------------------------------------------------------------