forked from PoliEcho-holding-org/kern
519 lines
9.5 KiB
ArmAsm
519 lines
9.5 KiB
ArmAsm
[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
|
||
|