Files
kern/boot/stage2.s
T
2024-12-09 12:51:40 +01:00

519 lines
9.5 KiB
ArmAsm
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
[bits 16]
[org 0x7e00]
%define STAGE3_LOC 0x50000
%define MODE_INFO_BLOCK_LOC 0x6000
start:
mov [driveNum], dl
; Physical memory map setup
xor ax, ax
mov es, ax
memMapEntries equ 0x7000
getMemoryMap:
mov di, memMapEntries + 4 ; 4 bytes after memMapEntries
xor ebx, ebx
xor bp, bp
mov edx, "PAMS" ; SMAP in little endian
mov eax, 0xe820
mov dword [es:di+20], 1 ; Force valid ACPI 3.X entry
mov ecx, 24
int 0x15
jc .error
cmp eax, "PAMS"
jne .error
test ebx, ebx
jnz .start
.error:
stc
jmp inputGfx
.nextEntry:
mov edx, "PAMS" ; In case BIOS messes with edx
mov ecx, 24
mov eax, 0xe820
int 0x15
.start:
jcxz .skipEntry
mov ecx, [es:di+8] ; Low 32 bits of length
or ecx, [es:di+12] ; High 32 bits of length
jz .skipEntry
; Valid entry
inc bp
add di, 24 ; Next entry
.skipEntry:
test ebx, ebx
jz .done
jmp .nextEntry
.done:
mov [memMapEntries], bp
clc
;; Get graphics values from user (resolution etc.)
inputGfx:
xor ecx, ecx
cmp word [width], 0 ; Values already set
jne vbeSetup
mov si, gfxChooseMsg
call print
call getNumber ; Stores input value in bx
mov [width], bx
mov si, gfxHeightMsg
call print
call getNumber
mov [height], bx
mov si, gfxBppMsg
call print
call getNumber
mov [bpp], bx
vbeSetup:
; Setup VBE info
xor ax, ax
mov es, ax
mov ax, 0x4f00
mov di, vbeInfoBlock
int 0x10
cmp ax, 0x4f
jne error
mov ax, word [vbeInfoBlock.videoModePtr]
mov [offset], ax
mov ax, word [vbeInfoBlock.videoModePtr+2]
mov [_segment], ax
mov fs, ax
mov si, [offset]
;; Get next VBE mode
.findMode:
mov dx, [fs:si]
inc si
inc si
mov [offset], si
mov [mode], dx
cmp dx, 0xffff ; Indicates end of modes
je .endOfModes
mov ax, 0x4f01 ; Get VBE mode info
mov cx, [mode]
mov di, modeInfoBlock
int 0x10
cmp ax, 0x4f
jne error
; Print values (Debug)
; mov ax, [modeInfoBlock.xRes]
; ror ax, 8
; call printHex
; ror ax, 8
; call printHex
; mov ax, 0x0e20
; int 0x10
; mov ax, [modeInfoBlock.yRes]
; ror ax, 8
; call printHex
; ror ax, 8
; call printHex
; mov ax, 0x0e20
; int 0x10
; xor ax, ax
; mov al, [modeInfoBlock.bpp]
; call printHex
; mov ax, 0x0e20
; int 0x10
; mov al, 0x0a
; int 0x10
; mov al, 0x0d
; int 0x10
; Check if it is the right mode
mov ax, [width]
cmp ax, [modeInfoBlock.xRes]
jne .nextMode
mov ax, [height]
cmp ax, [modeInfoBlock.yRes]
jne .nextMode
mov al, [bpp]
cmp al, [modeInfoBlock.bpp]
jne .nextMode
; Set VBE mode
mov ax, 0x4f02
mov bx, [mode]
or bx, 0x4000 ; Set 14th bit to 1
xor di, di
int 0x10
cmp ax, 0x4f
jne error
jmp checkA20
.nextMode:
mov ax, [_segment]
mov fs, ax
mov si, [offset]
jmp .findMode
.endOfModes:
mov ax, 0x03
int 0x10 ; Clear screen
mov si, gfxModeNotFoundErr
call print
mov word [width], 0 ; Unset values
jmp inputGfx
error:
mov si, vbeErr
call print
cli
hlt
;; Enables the A20 line
enableA20:
in al, 0x92
or al, 2
out 0x92, al
;; Check if the A20 line is enabled
checkA20:
push ds
push es
push di
push si
cli
xor ax, ax ; ax = 0
mov es, ax ; es = 0
not ax ; ax = 0xffff
mov ds, ax ; ds = 0xffff
mov di, 0x0500
mov si, 0x0510
mov al, byte [es:di]
push ax
mov al, byte [ds:si]
push ax
mov byte [es:di], 0x00
mov byte [ds:si], 0xff
cmp byte [es:di], 0xff
pop ax
mov byte [ds:si], al
pop ax
mov byte [es:di], al
mov ax, 0
jne enableA20
pop si
pop di
pop es
pop ds
;; Load the global descriptor table (GDT)
loadGDT:
cli
lgdt [GDT_Descriptor]
; Enable protected mode
mov eax, cr0
or eax, 1
mov cr0, eax
; Far jump to 32 bit mode!!
jmp CODE_SEG:protected_start
;;
;; Prints a hex byte
;; al - value to print
;;
printHex:
push ax
push bx
mov bh, 2
mov bl, al
and al, 0xf0
ror al, 4
mov ah, 0x0e ; For printing
.printNibble:
cmp al, 10
jl .print
add al, 39
.print:
add al, 48 ; ASCII Char
int 0x10
dec bh
jz .done
mov al, bl
and al, 0x0f
jmp .printNibble
.done:
pop bx
pop ax
ret
;;
;; Prints a null terminated string
;; si - pointer to string
;;
print:
push ax
mov ah, 0x0e
.loop:
lodsb ; mov al, [si] inc si
cmp al, 0
je .done
int 0x10
jmp .loop
.done:
pop ax
ret
;;
;; Reads a base 10 number as input from user
;; Returns:
;; bx - number read
;;
getNumber: ; TODO: if user enters a number that overflows (n > 0xffff) shit breaks
push cx
push ax
push dx
xor bx, bx
mov cx, 10
.nextDigit:
xor ah, ah
int 0x16
mov ah, 0x0e
cmp al, 0x08 ; Backspace
je .backspace
cmp al, 0x0d ; Enter
je .enter
cmp al, '0' ; Make sure user entered a number
jl .nextDigit
cmp al, '9'
jg .nextDigit
int 0x10 ; Print the digit
sub al, '0' ; Convert to integer
mov ah, 0
imul bx, bx, 10 ; bx *= 10
add bx, ax ; bx += ax
jmp .nextDigit
.backspace:
cmp bx, 0 ; Check if we can backspace
je .nextDigit
int 0x10 ; go back one space
mov ax, bx
xor dx, dx
div cx ; dx:ax / cx -> ax = result, dx = remainder
mov bx, ax
mov ah, 0x0e
mov al, ' '
int 0x10
mov al, 0x08
int 0x10
jmp .nextDigit
.enter:
pop dx
pop ax
pop cx
ret
;; 32 Bit entry code
[bits 32]
protected_start:
; Set up data and stack segments
mov ax, DATA_SEG
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
; Set up the stack pointer in protected mode
mov ebp, 0x90000
mov esp, ebp
; Store VBE Mode Info Block in memory
mov esi, modeInfoBlock
mov edi, MODE_INFO_BLOCK_LOC ; Destination
mov ecx, 64 ; 64 * 4 = 256B (size of modeInfoBlock)
rep movsd
; Perform The far jump
jmp CODE_SEG:STAGE3_LOC
;; Data
driveNum: db 0
vbeErr: db "VBE Error!", 0
acpiFuncErr: db "ACPI Function not supported!", 0
gfxChooseMsg: db "Please enter desired values" ; No NULL terminator, we want to print gfxWidthMsg right after anyway
gfxWidthMsg: db 0x0a, 0x0d, "Width: ", 0
gfxHeightMsg: db 0x0a, 0x0d, "Height: ", 0
gfxBppMsg: db 0x0a, 0x0d, "Bits Per Pixel: ", 0
gfxModeNotFoundErr: db "Mode not found! ", 0
;; GDT
GDT:
.start:
.nullDescriptor: ; No clue why this exists
dd 0
dd 0
.codeDescriptor: ; Memory for code
dw 0xffff ; First 16 bits of limit
dw 0 ; 16 bits +
db 0 ; + 8 bits = 24 bits
db 0b10011010 ; p, dpl, s, type flags
db 0b11001111 ; Other flags, last 4 bits of limit
db 0 ; Base
.dataDescriptor: ; Memory for data
dw 0xffff ; First 16 bits of limit
dw 0 ; 16 bits +
db 0 ; + 8 bits = 24 bits
db 0b10010010 ; p, dpl, s, type flags
db 0b11001111 ; Other flags, last 4 bits of limit
db 0 ; Base
.end:
GDT_Descriptor:
dw GDT.end - GDT.start - 1 ; Size
dd GDT.start ; GDT Pointer
CODE_SEG equ GDT.codeDescriptor - GDT.start
DATA_SEG equ GDT.dataDescriptor - GDT.start
;; VBE Stuff
; Default width
%ifndef DEF_W
%define DEF_W 0
%endif
; Default height
%ifndef DEF_H
%define DEF_H 0
%endif
; Default bpp
%ifndef DEF_BPP
%define DEF_BPP 0
%endif
; Use defaults
%ifdef DEF_RES
width: dw DEF_W
%else
width: dw 0
%endif
height: dw DEF_H
bpp: db DEF_BPP
offset: dw 0
_segment: dw 0 ; segment is a keyword
mode: dw 0
times (512*2)-($-$$) db 0 ; End Sector 2
;; Sector 2
vbeInfoBlock:
.vbeSigniture: db "VBE2"
.vbeVersion: dw 0x0300 ; BCD Version
.oemStringPtr: dd 0
.capibilities: dd 0
.videoModePtr: dd 0
.totalMemory: dw 0
.oemSoftwareRev: dw 0
.oemVendorNamePtr: dd 0
.oemProductNamePtr: dd 0
.oemProductRevisionPtr: dd 0
.reserved: times 222 db 0
.oemData: times 256 db 0
;; Sector 3
modeInfoBlock:
;; Required by all VBE revisions
.modeAttr: dw 0
.windowAAtrr: db 0
.windowBAttr: db 0
.windowGranularity: dw 0
.windowSize: dw 0
.windowASegment: dw 0
.windowBSegment: dw 0
.windowFunctionPtr: dd 0
.bytesPerScanline: dw 0
;; Required by VBE 1.2+
.xRes: dw 0
.yRes: dw 0
.xCharSize: db 0
.yCharSize: db 0
.planeCount: db 0
.bpp: db 0
.bankCount: db 0
.memoryModel: db 0
.bankSize: db 0
.imagePageCount: db 0
.reserved1: db 1
;; Direct color fields
.redMaskSize: db 0
.redFieldPos: db 0
.greenMaskSize: db 0
.greenFieldPos: db 0
.blueMaskSize: db 0
.blueFieldPos: db 0
.reservedMaskSize: db 0
.reservedFieldPos: db 0
.directColorModeInfo: db 0
;; Required by VBE 2.0+
.physicalBasePtr: dd 0
.reserved2: dd 0
.reserved3: dw 0
;; Required by VBE 3.0+
.linearBytesPerScanline: dw 0
.bankImagePageCount: db 0
.linearImagePageCount: db 0
.linearRedMaskSize: db 0
.linearRedFieldPos: db 0
.linearGreenMaskSize: db 0
.linearGreenFieldPos: db 0
.linearBlueMaskSize: db 0
.linearBlueFieldPos: db 0
.linearReservedMaskSize: db 0
.linearReservedFieldPos: db 0
.maxPixelClock: dd 0
.reserved4: times 190 db 0
times (512*4)-($-$$) db 0