From eea5bf4b859eb56c5772c58ca54937a90a10e7ee Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sat, 10 Jun 2017 20:55:56 +0200 Subject: moved bootloader to subdirectory --- src/boot/boot.asm | 227 +++++++++++++++++++++++++++++++++++++ src/boot/boot_gdt.asm | 43 +++++++ src/boot/magic.asm | 9 ++ src/boot/stage1_functions.asm | 121 ++++++++++++++++++++ src/boot/stage2_a20.asm | 157 +++++++++++++++++++++++++ src/boot/stage2_check_magic.asm | 48 ++++++++ src/boot/stage2_pm_functions.asm | 177 +++++++++++++++++++++++++++++ src/boot/stage2_real_functions.asm | 169 +++++++++++++++++++++++++++ src/boot/stage2_switch_mode.asm | 40 +++++++ 9 files changed, 991 insertions(+) create mode 100644 src/boot/boot.asm create mode 100644 src/boot/boot_gdt.asm create mode 100644 src/boot/magic.asm create mode 100644 src/boot/stage1_functions.asm create mode 100644 src/boot/stage2_a20.asm create mode 100644 src/boot/stage2_check_magic.asm create mode 100644 src/boot/stage2_pm_functions.asm create mode 100644 src/boot/stage2_real_functions.asm create mode 100644 src/boot/stage2_switch_mode.asm (limited to 'src/boot') diff --git a/src/boot/boot.asm b/src/boot/boot.asm new file mode 100644 index 0000000..c3cb57e --- /dev/null +++ b/src/boot/boot.asm @@ -0,0 +1,227 @@ +; legacy BIOS PC-boot code, starts in 16-bit real mode + +; BIOS always loads us to this location + [org 0x7c00] + +; 16-bit real-mode + [bits 16] + +; export a map of boot loader symbols for debugging + [map symbols boot.map] + +; initialize segment registers + mov ax, 0 + mov ds, ax + mov es, ax + mov ss, ax + +; dl contains the boot drive, primarily because that's the last function +; called by the BIOS MBR loader, we remember that for loading additional +; blocks from the boot medium + mov [BOOT_DRIVE], dl + +; make sure we know the location of the stack by setting it on our own +; this stack is only used in real mode in stage 1, so it's growing from +; 0xffff down + mov bp, 0xFFFF + mov sp, bp + +; print out some information about CPU mode and BIOS boot drive + mov si, MESSAGE_REAL_MODE + call print_string + + mov si, MESSAGE_BOOT_DRIVE + call print_string + mov ax, dx + call print_hex + call print_newline + +; print we are going to load stage 2 of the boot blocks + mov si, MESSAGE_LOADING_STAGE_2 + call print_string + +; load stage 2 with simple load method to 0x7e00 (directly +; after the boot sector) + mov dl, [BOOT_DRIVE] + call read_stage2_from_disk + call print_newline + +; jump over variables and subroutines of stage 1 and execute stage 2 + jmp stage2 + +%include "boot/stage1_functions.asm" + +DISK_ERROR: + db "DISK ERROR ", 0 + +SHORT_READ: + db "DISK SHORT READ", 0 + +MESSAGE_REAL_MODE: + db "Started in 16-bit Real Mode", 13, 10, 0 + +MESSAGE_BOOT_DRIVE: + db "Booting from drive ", 0 + +MESSAGE_LOADING_STAGE_2: + db "Loading stage 2 boot loader", 0 + +MESSAGE_DETECTING_DISK_GEOMETRY: + db "Detecting disk geometry ", 0 + +MESSAGE_LOADING_KERNEL: + db "Loading kernel", 0 + +BOOT_DRIVE: + db 0 + +; pad rest of sector with zeroes so we get 512 bytes in the end +times 510-($-$$) db 0 + +; magic number of a boot sector +dw 0xaa55 + +stage2: + +; print a message that we are indeed in stage 2 now + mov si, MESSAGE_STAGE_2_LOADED + call print_string + +; detect disk geometry (works for real floppies only?) + mov cl, [BOOT_DRIVE] + and cl, 0x80 + jnz .not_a_floppy + + mov si, MESSAGE_DETECTING_DISK_GEOMETRY + call print_string + mov dl, [BOOT_DRIVE] + call detect_disk_geometry + mov dl, [BOOT_DRIVE] + call probe_and_fix_disk_geometry + call print_newline +.not_a_floppy: + +; print a message we are now loading the kernel + mov si, MESSAGE_LOADING_KERNEL + call print_string + + +; load kernel to 0x8400 (directly after stage 2 +; of the boot loader) + mov dl, [BOOT_DRIVE] + call read_from_disk + call print_newline + +; turn off disk motor + call kill_motor + +; check A20 gate + mov si, MESSAGE_STAGE_2_CHECKING_A20 + call print_string + call check_and_enable_A20 + cmp ax, 1 + je .A20_enabled + mov si, MESSAGE_STAGE_2_A20_DISABLED + call print_string +; jmp .halt_os_realmode + +.A20_enabled: + mov si, MESSAGE_STAGE_2_A20_ENABLED + call print_string + +; remember current position on screen, otherwise we loose this +; information after switching to protected mode + call current_row + mov [CURSOR_Y], dh + +; enter protected mode + call switch_to_protected_mode + +; we should never get here, but just in case + jmp $ + +; stop loading in real mode +.halt_os_realmode: + mov si, MESSAGE_HALTED_REAL + call print_string +.loop: cli + hlt + jmp .loop + +MESSAGE_STAGE_2_LOADED: + db "Stage 2 boot sectors loaded", 13, 10, 0 + +MESSAGE_STAGE_2_CHECKING_A20: + db "Checking A20 address gate... ", 0 + +MESSAGE_STAGE_2_A20_ENABLED: + db " ...enabled", 13, 10, 0 + +MESSAGE_STAGE_2_A20_DISABLED: + db " ...disabled", 13, 10, 0 + +MESSAGE_HALTED_REAL: + db "Operating system halted in real mode", 13, 10, 0 + +%include "boot/stage2_real_functions.asm" +%include "boot/stage2_switch_mode.asm" +%include "boot/stage2_a20.asm" + +[bits 32] + +BEGIN_PROTECTED_MODE: + +; we switched to protected mode + mov si, MESSAGE_PROTECTED_MODE + call pm_print_string + call pm_print_newline + +; check sanity of kernel by searching for MAGIC string at a given +; position + call check_magic + cmp ax, 1 + jnz .halt_os_pm + +; print a message before we call the C level kernel + mov si, MESSAGE_CALL_C_ENTRY + call pm_print_string + call pm_print_newline + +; call our kernel + call kernel_main + +; restore cursor variables from VGA hardware + call read_hardware_vga_cursor + +; "kernel halted" message, when we terminate the C kernel +.halt_os_pm: + mov si, MESSAGE_HALTED + call pm_print_string + call pm_print_newline + +; end of C, disable interupts again, NMIs can still happen +; make sure we loop endlessly here but without burning too +; much CPU + cli +.loop: + hlt + jmp .loop + +MESSAGE_PROTECTED_MODE: + db "Switched to 32-bit Protected Mode", 0 + +MESSAGE_CALL_C_ENTRY: + db "Calling C entry function", 0 + +MESSAGE_HALTED: + db "Operating system halted", 0 + +%include "boot/stage2_pm_functions.asm" +%include "boot/stage2_check_magic.asm" + +; make sure we have full sectors, stage 1 is 512 bytes, so we +; have to will up 3 sectors +times 2048-($-$$) db 0 + +; position is 0x8400 now for the C entry +kernel_main: diff --git a/src/boot/boot_gdt.asm b/src/boot/boot_gdt.asm new file mode 100644 index 0000000..87e1585 --- /dev/null +++ b/src/boot/boot_gdt.asm @@ -0,0 +1,43 @@ +; GDT global descriptor table + +gdt_start: + +; mandatory null entry +gdt_null: + dd 0x0 + dd 0x0 + +; code segment +; base=0x0, limit=0xfffff +; flags: present (not paged), ring 0, executable, direction bit +; conforming, writable, not accessed +; granularity: 4kb pages, 32-bit mode, no 64-bit segment, AVL would +; be for our own extensions +gdt_code: + dw 0xffff ; limit (bits 0-15) + dw 0x0 ; base (bits 0-15) + db 0x0 ; base (bits 16-23) + db 10011010b ; flags + db 11001111b ; flags, limit (bits 16-19) + db 0x0 ; base (bit 24-31) + +; flat model, same as code segment, but flags are +; flags: ring 0, +gdt_data: + dw 0xffff ; limit (bits 0-15) + dw 0x0 ; base (bits 0-15) + db 0x0 ; base (bits 16-23) + db 10010010b ; flags + db 11001111b ; flags, limit (bits 16-19) + db 0x0 ; base (bit 24-31) + +gdt_end: + +gdt_descriptor: + dw gdt_end -gdt_start - 1 ; size + dd gdt_start ; start address of the GDT + +; constants representing the segment bases +CODE_SEGMENT equ gdt_code - gdt_start +DATA_SEGMENT equ gdt_data - gdt_start + diff --git a/src/boot/magic.asm b/src/boot/magic.asm new file mode 100644 index 0000000..f7aaf0d --- /dev/null +++ b/src/boot/magic.asm @@ -0,0 +1,9 @@ +; pad rest of sector with zeroes so we get 512 bytes in the end +times 512-14-($-$$) db 0 + +; the magic string we search for in stage 2 to ensure we don't read +; a truncated kernel image +; we make it unique per compilation to avoid funny problems if +; the size of the image differs between compilation steps and the +; host system doens't initialize or randomize the RAM. +db "ABAOS", %[MAGIC], 0 diff --git a/src/boot/stage1_functions.asm b/src/boot/stage1_functions.asm new file mode 100644 index 0000000..bdb2aac --- /dev/null +++ b/src/boot/stage1_functions.asm @@ -0,0 +1,121 @@ +; IN dx: hex value to print +print_hex: + push bx + push si + mov si, HEX_TEMPLATE + mov bx, dx + shr bx, 12 + mov bx, [HEXABET+bx] + mov [HEX_TEMPLATE+2], bl + mov bx, dx + and bx, 0x0FFF + shr bx, 8 + mov bx, [HEXABET+bx] + mov [HEX_TEMPLATE+3], bl + mov bx, dx + and bx, 0x00FF + shr bx, 4 + mov bx, [HEXABET+bx] + mov [HEX_TEMPLATE+4], bl + mov bx, dx + and bx, 0x000F + mov bx, [HEXABET+bx] + mov [HEX_TEMPLATE+5], bl + call print_string + pop si + pop bx + ret + +HEX_TEMPLATE: + db '0x???? ', 0 + +HEXABET: + db '0123456789ABCDEF' + +print_newline: + push ax + mov al, 10 + call print_char + mov al, 13 + call print_char + pop ax + ret + +; IN si +print_string: + push ax +.loop: + lodsb + cmp al, 0 + je .fini + call print_char + jmp .loop +.fini: + pop ax + ret + +; IN al: character to print +; MOD ah +print_char: + mov ah, 0x0e + int 0x10 + ret + +fat_cursor: + push ax + push cx + mov ah, 0x01 + mov cx, 0x0007 + int 0x10 + pop cx + pop ax + ret + +; OUT: current row +current_row: + push ax + push bx + push cx + mov ah, 0x03 + mov bh, 0 + int 0x10 + pop cx + pop bx + pop ax + ret + +; IN dl: drive to read from +read_stage2_from_disk: + mov ah, 0x02 ; read sectors from drive + + mov al, 3 ; read 3 sectors of stage 2 + mov ch, 0 ; select first cylinder + mov dh, 0 ; first head + mov cl, 2 ; second sector after boot sector + + mov bx, 0 ; where to store the data + mov es, bx + mov bx, 0x7e00 ; 512 bytes after first sector + + int 0x13 + + jc .read_error + + cmp al, 3 ; 3 sectors read? + jne .short_read ; if not, short read + + ret + +.read_error: + mov si, DISK_ERROR + call print_string + mov dh, 0 + mov dl, ah + call print_hex + jmp $ + +.short_read: + mov si, SHORT_READ + call print_string + jmp $ + diff --git a/src/boot/stage2_a20.asm b/src/boot/stage2_a20.asm new file mode 100644 index 0000000..c0951ad --- /dev/null +++ b/src/boot/stage2_a20.asm @@ -0,0 +1,157 @@ +; functions to handle A20 address line status and switching + +; returns 0 if not A20_ENABLED, 1 if A20_ENABLED in AX +check_A20_enabled: + pushf + push ds + push es + push di + push si + + cli + + xor ax, ax + mov es, ax + mov di, 0x0500 ; es:di = 0000:0500 + + mov ax, 0xffff + mov ds, ax + mov si, 0x0510 ; ds:si = ffff:0510 + + mov al, byte [es:di] ; preserve values in memory + push ax ; on stack + mov al, byte [ds:si] + push ax + + mov byte [es:di], 0x00 ; now the test: write 0x00 to 0000:0500 + mov byte [ds:si], 0xFF ; write 0xff to ffff:0510 + + cmp byte [es:di], 0xFF ; memory wrap? A20 notA20_ENABLED + + pop ax ; restore original memory contents + mov byte [ds:si], al + pop ax + mov byte [es:di], al + + je .enabled + jmp .disabled + +.enabled: + mov al, '+' + call print_char + mov ax, 1 ; not wrapped around + jmp .exit + +.disabled: + mov al, '-' + call print_char + mov ax, 0 ; wrapped around (last cmp) + jmp .exit + +.exit: + pop si + pop di + pop es + pop ds + popf + + ret + +check_and_enable_A20: + call check_A20_enabled + cmp ax, 1 + je A20_ENABLED + +A20_ENABLE_KBD_PORT: + mov al, 'K' + call print_char + mov al, 0xdd + out 0x64, al + + call check_A20_enabled + cmp ax, 1 + je A20_ENABLED + +A20_ENABLE_KBD_OUT: + + mov al, 'k' + call print_char + + cli ; disable interrupts, we talk directly to the keyboard ports + + call .wait_input + mov al,0xAD + out 0x64,al ; disable keyboard + call .wait_input + + mov al,0xD0 + out 0x64,al ; tell controller to read output port + call .wait_output + + in al,0x60 + push eax ; get output port data and store it + call .wait_input + + mov al,0xD1 + out 0x64,al ; tell controller to write output port + call .wait_input + + pop eax + or al,2 ; set bit 1 (enable a20) + out 0x60,al ; write out data back to the output port + + call .wait_input + mov al,0xAE ; enable keyboard + out 0x64,al + + call .wait_input + + sti + + jmp .retest + +; wait for input buffer to be clear +.wait_input: + in al,0x64 + test al,2 + jnz .wait_input + ret + +; wait for output buffer to be clear +.wait_output: + in al,0x64 + test al,1 + jz .wait_output + ret + +.retest: + call check_A20_enabled + cmp ax, 1 + je A20_ENABLED + +A20_FAST_SPECIAL_PORT: + + mov al, 'F' + call print_char + + in al, 0x92 + or al, 2 + out 0x92, al + + call check_A20_enabled + cmp ax, 1 + je A20_ENABLED + ret + +A20_ENABLE_VIA_BIOS: + mov al, 'B' + call print_char + mov ax, 0x2401 + int 0x15 + + call check_A20_enabled + cmp ax, 1 + je A20_ENABLED + +A20_ENABLED: + ret diff --git a/src/boot/stage2_check_magic.asm b/src/boot/stage2_check_magic.asm new file mode 100644 index 0000000..1deaf05 --- /dev/null +++ b/src/boot/stage2_check_magic.asm @@ -0,0 +1,48 @@ +; check whether the end of the loaded image contains in fact the magic +; string (avoid truncation of image) +check_magic: + push ebx + push ecx + push edx + push esi + push edi + mov eax, NOF_LOAD_SECTORS ; number of 512-byte sectors + shl eax, 9 ; 512 bytes per sector + mov edx, 0x8400 ; offset of kernel + add edx, eax + sub edx, MAGICLEN ; subtract the length of the magic string + mov esi, edx ; now use edx as first string address to compare to + mov edi, COMPARE_MAGIC ; position of second string + mov ecx, MAGICLEN ; length of the magic string + repe cmpsb + jne .ok + jmp .mismatch +.ok: + mov si, MAGIC_OK_MSG + call pm_print_string + call pm_print_newline + xor eax, eax + jmp .end +.mismatch: + mov si, MAGIC_NOT_OK_MSG + call pm_print_string + call pm_print_newline + xor eax, eax + mov eax, 1 +.end: + pop edi + pop esi + pop edx + pop ecx + pop ebx + ret + +COMPARE_MAGIC: +db "ABAOS", %[MAGIC], 0 +MAGICLEN equ $ - COMPARE_MAGIC + +MAGIC_NOT_OK_MSG: +db "Magic signature found", 0 + +MAGIC_OK_MSG: +db "Magic signature not found!", 0 diff --git a/src/boot/stage2_pm_functions.asm b/src/boot/stage2_pm_functions.asm new file mode 100644 index 0000000..f3c348b --- /dev/null +++ b/src/boot/stage2_pm_functions.asm @@ -0,0 +1,177 @@ +VIDEO_MEMORY equ 0xb8000 + +VIDEO_COLS equ 80 +VIDEO_ROWS equ 25 + +CURSOR_X: + dw 0 + +CURSOR_Y: + dw 0 + +pm_print_newline: + push eax + mov [CURSOR_X], word 0 + mov ax, [CURSOR_Y] + inc ax + mov [CURSOR_Y], ax + pop eax + call update_vga_cursor + ret + +; IN si +pm_print_string: + push eax +.loop: + lodsb + cmp al, 0 + je .fini + call pm_print_char + jmp .loop +.fini: + pop eax + ret + +; IN al: character to print +pm_print_char: + push edx + push ecx + push ebx + push eax + mov ax, [CURSOR_Y] + mov cl, VIDEO_COLS + mul cl + mov bx, [CURSOR_X] + add ax, bx + shl ax, 1 + mov edx, VIDEO_MEMORY + add dx, ax + pop eax + mov ah, 0x07 + mov [edx], ax + pop ebx + pop ecx + pop edx + call inc_cursor + ret + +; IN dx: hex value to print +pm_print_hex: + push bx + push si + mov si, PM_HEX_TEMPLATE + mov bx, dx + shr bx, 12 + mov bx, [PM_HEXABET+bx] + mov [PM_HEX_TEMPLATE+2], bl + mov bx, dx + and bx, 0x0FFF + shr bx, 8 + mov bx, [PM_HEXABET+bx] + mov [PM_HEX_TEMPLATE+3], bl + mov bx, dx + and bx, 0x00FF + shr bx, 4 + mov bx, [PM_HEXABET+bx] + mov [PM_HEX_TEMPLATE+4], bl + mov bx, dx + and bx, 0x000F + mov bx, [PM_HEXABET+bx] + mov [PM_HEX_TEMPLATE+5], bl + call pm_print_string + pop si + pop bx + ret + +inc_cursor: + push eax + mov ax, [CURSOR_X] + inc ax + mov [CURSOR_X], ax + cmp ax, VIDEO_COLS + jl .fini + mov [CURSOR_X], word 1 + mov ax, [CURSOR_Y] + inc ax + mov [CURSOR_Y], ax + cmp ax, VIDEO_ROWS + jl .fini + ; TODO: scoll one line, for now restart on top + mov [CURSOR_Y], word 0 +.fini: + call update_vga_cursor + pop eax + ret + +; update the VGA cursor on screen +update_vga_cursor: + push eax + push ebx + push ecx + push edx + mov al, [CURSOR_Y] + mov cl, VIDEO_COLS + mul cl + mov bx, ax + movzx ax, [CURSOR_X] + add bx, ax + mov cx, bx + ;cursor LOW port to vga INDEX register + mov al, 0fh ;Cursor Location Low Register -- + mov dx, 3d4h ;VGA port 3D4h + out dx, al + mov ax, cx ;restore 'postion' back to AX + mov dx, 3d5h ;VGA port 3D5h + out dx, al ;send to VGA hardware + ;cursor HIGH port to vga INDEX register + mov al, 0eh + mov dx, 3d4h ;VGA port 3D4h + out dx, al + mov ax, cx ;restore 'position' back to AX + shr ax, 8 ;get high byte in 'position' + mov dx, 3d5h ;VGA port 3D5h + out dx, al ;send to VGA hardware + pop edx + pop ecx + pop ebx + pop eax + ret + +; read cursor from hardware +read_hardware_vga_cursor: + push eax + push ebx + push ecx + push edx + xor eax, eax + xor ebx, ebx + mov al, 0eh + mov dx, 3d4h + out dx, al + mov dx, 3d5h + in al, dx + mov bh, al + mov al, 0fh + mov dx, 3d4h + out dx, al + mov dx, 3d5h + in al, dx + mov bl, al + mov ax, bx + mov edx, 0 + mov cx, VIDEO_COLS + div cx + mov [CURSOR_X], dx + mov [CURSOR_Y], ax + pop edx + pop ecx + pop ebx + pop eax + ret + +PM_HEX_TEMPLATE: + db '0x???? ', 0 + +PM_HEXABET: + db '0123456789ABCDEF' + diff --git a/src/boot/stage2_real_functions.asm b/src/boot/stage2_real_functions.asm new file mode 100644 index 0000000..d49bfce --- /dev/null +++ b/src/boot/stage2_real_functions.asm @@ -0,0 +1,169 @@ +; number of sectors to be read for the kernel itself +; (note: the first sector gets loaded by the BIOS, the +; next 3 sectors are read by the simple stage 1 loader, +; so subtract 3 here!) +NOF_LOAD_SECTORS equ 37 + +; data sections used for reading the kernel from disk +SECTORS_PER_CYLINDER: + db 0x3F ; detect parameters enters the correct value here (sectors + 1) + ; if detection fails, force int13 to read ahead +NOF_HEADS: + db 0x01 ; number of heads + 1 +SECTORS_TO_LOAD: + db NOF_LOAD_SECTORS ; load NOF_LOAD_SECTORS sectors in total +CURRENT_SECTOR: + db 5 ; first sector after stage 2 +CURRENT_CYLINDER: + db 0 +CURRENT_HEAD: + db 0 + +; detect disk geometry +; IN dl: drive +detect_disk_geometry: + mov dx, 0 + mov es, dx + mov ah, 0x08 + int 0x13 + jc .error + jmp .ok + +.error: + mov si, DISK_ERROR + call print_string + mov dh, 0 + mov dl, ah + call print_hex + ret + +.ok: + add dh, 1 + mov [NOF_HEADS], BYTE dh + call print_hex + mov dx, cx + call print_hex + and cl, 0x3F + add cl, 1 + mov [SECTORS_PER_CYLINDER], BYTE cl + ret + +probe_and_fix_disk_geometry: + mov cl, 0x1 ; from 1 to 63 + mov BYTE [SECTORS_PER_CYLINDER], cl + +.loop: + mov dl, [BOOT_DRIVE] + mov ah, 0x02 ; read sectors from drive + mov al, 1 ; read 1 sector + mov cl, BYTE [SECTORS_PER_CYLINDER] + mov ch, BYTE 0 + mov dh, BYTE 0 + + int 0x13 + + jnc .next_sector ; on error, remeber cl being the highest sector + +.fix_heads: + cmp [NOF_HEADS], BYTE 0 ; 0 heads, the BIOS is playing tricks to us! + je .illegal_heads + jmp .end + +.illegal_heads: + mov [NOF_HEADS], BYTE 1 + jmp .end + +.next_sector: + mov cl, BYTE [SECTORS_PER_CYLINDER] + inc cl ; next sector + mov BYTE [SECTORS_PER_CYLINDER], cl + cmp cl, 0x40 ; to a max of 63, if so, this is the default + jbe .loop + jmp .fix_heads + +.end: + ret + +; read the whole stage2 and kernel from the disk +; IN dl: drive to read from +read_from_disk: + + mov bx, 0 ; where to store the data + mov es, bx + mov bx, 0x8400 ; 2'048 bytes after first sector + +.read_next_sector: + + call read_one_sector_from_disk + + sub [SECTORS_TO_LOAD], BYTE 1 ; one less to load + cmp [SECTORS_TO_LOAD], BYTE 0 ; finished? + je .finished + + add bx, 0x200 ; advance write buffer position + add [CURRENT_SECTOR], BYTE 1 ; next sector + mov ch, [SECTORS_PER_CYLINDER] + cmp [CURRENT_SECTOR], ch ; after the end of the current track? + je .next_head + jmp .read_next_sector + +.next_head: + mov [CURRENT_SECTOR], BYTE 1 ; start from first sector again + add [CURRENT_HEAD], BYTE 1 ; advance head + mov ch, [NOF_HEADS] + cmp [CURRENT_HEAD], ch ; after the number of heads? + je .next_track + jmp .read_next_sector + +.next_track: + mov [CURRENT_HEAD], BYTE 0 ; start from head 0 again + add [CURRENT_CYLINDER], BYTE 1 ; advance track + jmp .read_next_sector + +.finished: + ret + +; Read one sector after the other, if we get illegal parameter +; errors we assume we have gone over the limit of number of +; sectors per cylinder. This avoids to probe for this number with +; shacky BIOS functions or with probing (as LILO does). It's not +; very efficient though.. +; IN dl: drive to read from +read_one_sector_from_disk: + + mov ah, 0x02 ; read sectors from drive + mov al, 1 ; read 1 sector + mov ch, BYTE [CURRENT_CYLINDER] + mov dh, BYTE [CURRENT_HEAD] + mov cl, BYTE [CURRENT_SECTOR] + + int 0x13 + + jc .read_error + + cmp al, 1 ; 1 sector read? + jne .short_read ; if not, short read + + mov al, '.' + call print_char + + ret + +.read_error: + mov si, DISK_ERROR + call print_string + mov dh, 0 + mov dl, ah + call print_hex + jmp $ + +.short_read: + mov si, SHORT_READ + call print_string + jmp $ + +kill_motor: + mov dx, 0x3F2 + mov al, 0x00 + out dx, al + ret diff --git a/src/boot/stage2_switch_mode.asm b/src/boot/stage2_switch_mode.asm new file mode 100644 index 0000000..9259e08 --- /dev/null +++ b/src/boot/stage2_switch_mode.asm @@ -0,0 +1,40 @@ +[bits 16] + +%include "boot/boot_gdt.asm" + +switch_to_protected_mode: + ; switch off interrupts for now, we don't + ; have a valid IDT installed yet + cli + + ; load GDT (global descriptor table) + lgdt [gdt_descriptor] + + ; do the actual switch + mov eax, cr0 + or eax, 0x1 + mov cr0, eax + + ; unconditional far jump into code segment, + ; wipes the instruction prefetch pipeline + jmp CODE_SEGMENT:init_pm + +[bits 32] + +; initialize registers and stack for protected mode +init_pm: + mov ax, DATA_SEGMENT + mov ds, ax + mov ss, ax + mov es, ax + mov fs, ax + mov gs, ax + + ; a new stack + mov ebp, 0x90000 + mov esp, ebp + + call BEGIN_PROTECTED_MODE + +[bits 16] + -- cgit v1.2.3-54-g00ecf