Compare commits

..

No commits in common. "65db388f005ee787a4d08b0107ba068c24795765" and "0d16e3e35a8175e21fe8085010be92f794f7acf3" have entirely different histories.

2 changed files with 228 additions and 62 deletions

View File

@ -1,48 +1,95 @@
; A20 Wraparound check as gotten from osdev.org
check_a20_wraparound:
pushf
push ds
push es
push di
push si
.prolog:
push dword esi
sub esp, 64
mov esi, esp
xor ax, ax ; ax = 0
mov es, ax
; EAX is used for the return value,
; so it doesn't have to be preserved.
mov [esi + (64 - 8)], ebx
mov [esi + (64 - 12)], edi
not ax ; ax = 0xFFFF
mov ds, ax
.test_a20:
; Save the values which are going to be overwritten
mov edi, 0x0800
mov eax, [edi]
mov edi, 0x00100800
mov ebx, [edi]
mov di, 0x0500
mov si, 0x0510
; Write to two locations which, if A20 wraps around,
; will both be written to by the second statement.
; Write 0 to 0x08000 to avoid the unlikely case that
; those bytes are there coincidentally and A20 is on.
mov edi, 0x0800
mov [edi], dword 0x00000000
mov edi, 0x00100800
mov [edi], dword 0xffaa00dd
mov al, byte [es:di]
push ax
; Check the lower address (which should NOT contain)
; this value for the value. If it does contain it, the
; memory space wraps around to 0 every 2^19 bytes.
cmp [0x0800], dword 0xffaa00dd
je .return_a20_not_enabled ; If the value at 0x0800
; was written to instead
; (or at the same time) of
; writing to 0x100800,
; the A20 wasn't enabled.
; Reset the values at the addresses to which the test
; values were written znd return that A20 is enabled.
mov edi, 0x0800
mov [edi], eax
mov edi, 0x00100800
mov [edi], ebx
mov al, byte [ds:si]
push ax
.return_a20_enabled:
mov byte [es:di], 0x00
mov byte [ds:si], 0xFF
mov eax, 1
cmp byte [es:di], 0xFF
pop ax
mov byte [ds:si], al
pop ax
mov byte [es:di], al
mov ax, 0
je .exit
mov ax, 1
.exit:
pop si
pop di
pop es
pop ds
popf
; Restore the one used register which
; doesn't contain the return value.
mov ebx, [esi + (64 - 8)]
add esp, 64
pop dword esi
ret
.return_a20_not_enabled:
; It's only necessary to write to one of the addresses
; as both of them are equal either way.
mov edi, 0x0800
mov [edi], eax
mov eax, 0
; Restore the one used register which
; doesn't contain the return value.
mov ebx, [esi + (64 - 12)]
mov edi, [esi + (64 - 8)]
add esp, 64
pop dword esi
ret
enable_a20_through_keyboard_controller:
.prolog:
push dword esi
sub esp, 64
mov esi, esp
mov [esi + (64 - 8)], ebx
mov [esi + (64 - 12)], ecx
mov [esi + (64 - 16)], edx
mov [esi + (64 - 20)], edi
.epilog:
mov ebx, [esi + (64 - 8)]
mov ecx, [esi + (64 - 12)]
mov edx, [esi + (64 - 16)]
mov edi, [esi + (64 - 20)]
add esp, 64
pop dword esi
ret

View File

@ -2,8 +2,6 @@
GDT_MEMORY_AREA equ 0x7e00
GDT_ENTRY_COUNT equ 3
; Arguments (note: all arguments are 4-byte padded):
; [Furthest from EBP]
;
@ -111,6 +109,114 @@ make_regular_data_segment_in_gdt:
; Arguments (note: all arguments are 4-byte padded):
; [Furthest from EBP]
;
; 4. uint32 privilege_level
; - Only 0 to 3; 0 being kernel and 3 being userland.
; Everything above 3 is an error.
;
; 3 uint32 num_pages
; - Only 20 bits are usable. Everything above will
; be cut off to be written to the segment descriptor.
;
; 2. ptr32 base_address
;
; 1. uint32 segment_index
; Note:
; - Zero is NOT usable and will throw an error.
; the highest theoretical value for this is 8191,
; but generally, one should stick to GDT_ENTRY_COUNT.
;
; [Nearest to EBP]
; COMMENTED OUT DUE TO BEING BUGGY!
; make_stack_segment_in_gdt:
; .prolog:
; push esi
; add esp, 64
; mov esi, esp
; mov [esi + (64 - 4)], eax
; mov [esi + (64 - 8)], ebx
; mov [esi + (64 - 12)], ecx
; mov [esi + (64 - 16)], edx
; mov [esi + (64 - 20)], edi
; .get_arguments:
; mov eax, [ebp - 4] ; segment_index
; mov ebx, [ebp - 8] ; base_address
; mov ecx, [ebp - 12] ; num_pages
; mov edx, [ebp - 16] ; privilege_level
; mov [esi + 16], eax ; segment_index
; mov [esi + 20], ebx ; base_address
; mov [esi + 24], ecx ; num_pages
; mov [esi + 28], edx ; privilege_level
; .validate_arguments:
; cmp eax, 8191
; ja .segment_index_too_tall
; cmp eax, 0
; je .segment_index_is_zero
; cmp edx, 3
; ja .privilege_level_too_large
; .calculate_work_address:
; shl eax, 3 ; Entry offset from table start
; add eax, GDT_MEMORY_AREA ; Entry address
; mov [esi + 12], eax
; .write_segment_limit:
; mov [eax], cx
; shr ecx, 16
; and ecx, 0x0f
; mov [eax + 6], cl
; .write_base_address:
; mov [eax + 2], bx
; shr bx, 16
; mov [eax + 4], bl
; mov [eax + 7], bh
; .set_default_flags:
; or [eax + 6], word (0b1100 << 4)
; .set_stack_specific_access_byte:
; mov al, 0b1001
; ; OR the privilege level into the access byte
; mov dl, [ebp - 16]
; shl dl, 1
; and dl, 0b0110
; or al, dl
; shl al, 4 ; Move the 4 bits of general flags to their place
; ; Stack specific part
; or al, 0b0110 ; DATA | STACK | READ_WRITE | NOT_ACCESSED
; mov ebx, [esi + 12]
; mov [ebx + 5], al ; Write to the final destination
; .epilog:
; mov edi, [esi + (64 - 20)]
; mov edx, [esi + (64 - 16)]
; mov ecx, [esi + (64 - 12)]
; mov ebx, [esi + (64 - 8)]
; mov eax, [esi + (64 - 4)]
; sub esp, 64
; pop esi
; ret
; .segment_index_too_tall:
; .segment_index_is_zero:
; .privilege_level_too_large:
; ; todo(logs): Write debug message.
; cli
; hlt
; Arguments (note: all arguments are 4-byte padded):
; [Furthest from EBP]
;
@ -217,7 +323,6 @@ make_code_segment_in_gdt:
hlt
; [Furthest to EBP]
; 1) Return Address
; [Nearest to EBP]
@ -241,17 +346,28 @@ load_flat_gdt:
mov ebp, esp
push dword 2 ; Segment Index
push dword 0 ; Start Offset
push dword 0x000fffff ; Page Count
push dword 0xfffff ; Page Count
push dword 0 ; Required privilege level
call make_regular_data_segment_in_gdt
mov esp, ebp
pop ebp
; COMMENTED OUT DUE TO BEING BUGGY
; push ebp
; mov ebp, esp
; push dword 3 ; Segment Index
; push dword LOWER_STACK_POINTER ; Start Offset
; push dword 0xfffff ; Page Count
; push dword 0 ; Required privilege level
; call make_stack_segment_in_gdt
; mov esp, ebp
; pop ebp
push ebp
mov ebp, esp
push dword 1 ; Segment Index
push dword 0x0000 ; Start Offset
push dword 0x000fffff ; Page Count
push dword 0xfffff ; Page Count
push dword 0 ; Required privilege level
call make_code_segment_in_gdt
mov esp, ebp
@ -259,39 +375,42 @@ load_flat_gdt:
mov bx, 0
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
mov ss, bx
lgdt [.gdtr]
mov ebx, cr0
or ebx, 1
mov cr0, ebx
jmp dword (1 << 3):.epilog
bits 32
.epilog:
mov bx, (2 << 3)
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
; mov bx, (3 << 3)
mov ss, bx
mov ebx, cr0
or ebx, 1
mov cr0, ebx
xor bx, bx
mov ds, bx
jmp dword 0x08:.epilog
bits 32
.epilog:
mov edi, [esi + (64 - 20)]
mov edx, [esi + (64 - 16)]
mov ecx, [esi + (64 - 12)]
mov ebx, [esi + (64 - 8)]
mov eax, [esi + (64 - 4)]
jmp dword stage2_true_entry
add esp, 64
pop esi
jmp stage2_true_entry
; jmp after_gdt_loaded
align 16
.gdtr:
.gdtr.length:
dw 23
dw 15
.gdtr.pointer:
dd GDT_MEMORY_AREA