Skip to content
Snippets Groups Projects
Commit a530a787 authored by Recolic Keghart's avatar Recolic Keghart
Browse files

Merge branch 'x64' into 'master'

X64 MBR mode done.

See merge request !2
parents 30818145 d1682d21
No related branches found
No related tags found
1 merge request!2X64 MBR mode done.
......@@ -5,7 +5,7 @@ bootloader-legacy:
$(MAKE) -C bootloader-legacy
bootloader-uefi:
$(MAKE) -C bootloader-legacy
$(MAKE) -C bootloader-uefi
kernel:
$(MAKE) -C kernel
......
dd if=/dev/zero of=out.img bs=512K count=16
VBoxManage convertfromraw out.img out.vdi --format vdi
# notes
## register usage rule
volatile (caller saved): rax, rcx, rdx
non-volatile: others
arguments and return value: rax, rcx, rdx, stack
## bootloader(legacy) memory model
- common
0x7c00 - 0x7e00 : bootloader.img, executes from beginning 0x7c00
0x7e00 - 0x17c00 : kernel.img, called by bootloader, from beginning 0x7e00
- bios age
![](../res/1.png)
- 32bit protected mode age
Just used this mode to launch 64bit long mode. No paging enabled.
- 64bit long mode age
0x1000 - 0x5000 : 64bit long mode paging table**s**
0x00000000 - 0x00200000 : 512 * 4K pages, before the kernel initializing page table in C++.
## bootloader(legacy) disk model
0-511Byte : bootloader.img from boot.asm, MBR flag
512B - 64KiB : kernel.img. executes from 512Byte first instruction.
## works and TODO
Currently, paging for 32bit bootloader not implemented. Not planned.
kernel currently working on both 32bit(without paging) and 64bit mode. But in the future, will work only in 64bit mode.
build:
nasm -f bin boot.asm -o boot.img
build_x86:
build_x86_64:
run: build
qemu-system-x86_64 boot.img
......@@ -70,7 +70,7 @@ _load_kern:
disk_io_error:
mov bx, _motd_disk_error
call println_bios
jmp _stall
jmp $
......@@ -100,26 +100,56 @@ _prot_begin:
mov ebx, _motd_32
call println_vga
; Test if 64bit available
call test_support_long_mode
cmp eax, 0
je _test_passed
mov ebx, _motd_no_long_mode
call println_vga
jmp _call_kern_32
_test_passed:
jmp inline_enter_long_mode
%include "./inline_x64lib.inc"
jmp _call_kern_64
[bits 32]
_call_kern_32:
; Enter the kernel. This should never return.
call KERN_ADDR
; Kernel returns.
mov ebx, _motd_endk
call println_vga
jmp $
_stall:
[bits 64]
_call_kern_64:
; Enter the kernel. This should never return.
call KERN_ADDR
; Kernel returns.
;mov ebx, _motd_endk
;call println_vga
; TODO: add 64bit println_vga and error msg
jmp $
_motd_disk_error:
db 'DISK_IO_ERROR', 0x0
db 'MED', 0x0
_motd_32:
db '[LOAD KERN SUCC] [ENTER X86 MODE SUCC]', 0x0
db 'M32', 0x0
_motd_kern_ok:
db '[LOAD KERN SUCC]', 0x0
db 'MKN', 0x0
_motd_endk:
db '[LOAD KERN SUCC] [ENTER X86 MODE SUCC] [KERN EXITED]', 0x0
db 'MEK', 0x0
_motd_no_long_mode:
db 'MNL', 0x0
_boot_drive_id:
db 0x0
_motd_debug_point:
db 'MDB', 0x0
%include "./mbr_end.inc"
......
; requires: str.32.inc
; runs in 32bit protection mode
;test_cpuid_support:
; ; Check if CPUID is supported by attempting to flip the ID bit (bit 21) in
; ; the FLAGS register. If we can flip it, CPUID is available.
;
; ; Copy FLAGS in to EAX via stack
; pushfd
; pop eax
;
; ; Copy to ECX as well for comparing later on
; mov ecx, eax
;
; ; Flip the ID bit
; xor eax, 1 << 21
;
; ; Copy EAX to FLAGS via the stack
; push eax
; popfd
;
; ; Copy FLAGS back to EAX (with the flipped bit if CPUID is supported)
; pushfd
; pop eax
;
; ; Restore FLAGS from the old version stored in ECX (i.e. flipping the ID bit
; ; back if it was ever flipped).
; push ecx
; popfd
;
; ; Compare EAX and ECX. If they are equal then that means the bit wasn't
; ; flipped, and CPUID isn't supported.
; sub eax, ecx
; ; eax != 0 if CPUID supported, eax==0 if not supported.
; ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
test_support_long_mode:
; test if possible to enter x64 mode.
; return value in eax.
; return 0 = OK. 1 = CPUID_NOT_AVAIL, 2 = CPUID_EXT_NOT_AVAIL, 3 = LONGMODE_NOT_AVAIL
; call test_cpuid_support
; cmp eax, 0
; jne _cpuid_supported
; mov eax, 1
; ret
;_cpuid_supported:
mov eax, 0x80000000 ; Set the A-register to 0x80000000.
cpuid ; CPU identification.
cmp eax, 0x80000001 ; Compare the A-register with 0x80000001.
jb _fail_no_long_mode_2 ; It is less, there is no long mode.
mov eax, 0x80000001 ; Set the A-register to 0x80000001.
cpuid ; CPU identification.
test edx, 1 << 29 ; Test if the LM-bit, which is bit 29, is set in the D-register.
jz _fail_no_long_mode_3 ; They aren't, there is no long mode.
mov eax, 0
ret
_fail_no_long_mode_2:
mov eax, 2
ret
_fail_no_long_mode_3:
mov eax, 3
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
GDT64: ; Global Descriptor Table (64-bit).
.Null: equ $ - GDT64 ; The null descriptor.
dw 0xFFFF ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 0 ; Access.
db 1 ; Granularity.
db 0 ; Base (high).
.Code: equ $ - GDT64 ; The code descriptor.
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 10011010b ; Access (exec/read).
db 10101111b ; Granularity, 64 bits flag, limit19:16.
db 0 ; Base (high).
.Data: equ $ - GDT64 ; The data descriptor.
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 10010010b ; Access (read/write).
db 00000000b ; Granularity.
db 0 ; Base (high).
.Pointer: ; The GDT-pointer.
dw $ - GDT64 - 1 ; Limit.
dq GDT64 ; Base.
inline_enter_long_mode:
;;;;;;;;;;;;; section 1: paging
; disable paging in 32bit protected mode (if any)
mov eax, cr0
and eax, 01111111111111111111111111111111b ; Clear the PG-bit, which is bit 31.
mov cr0, eax
; prepare paging for long mode. Using memory 0x1000 - 0x5000, to put 4-level page tables.
mov edi, 0x1000 ; begin addr
xor eax, eax
mov ecx, 0x1000 ; size
rep stosd ; memset, 0x1000 * 4Bytes to set this memory area to ZERO.
; set PML4T
mov edi, 0x1000
mov cr3, edi
; fill first entry of PML4T, PDPT, PDT.
mov DWORD [edi], 0x2003 ; 0x2003 IS NOT the address. it contains many flags, and another DWORD is zero. Just a trick.
mov edi, 0x2000
mov DWORD [edi], 0x3003
mov edi, 0x3000
mov DWORD [edi], 0x4003
mov edi, 0x4000
; fill all entries of the PT. This is a trick, which not setting all bits in entry.
; This page table has 512 4K page, 0x00000000 - 0x00200000.
mov ebx, 0x00000003 ; BIT M--12 contains PageFrameNumber.
mov ecx, 512 ; counter
_set_one_entry:
mov DWORD [edi], ebx
add ebx, 0x1000 ; each page is 4K
add edi, 8 ; each entry is 64bit.
loop _set_one_entry
; Page table prepared. Enable PAE-paging.
mov eax, cr4
or eax, 1<<5
mov cr4, eax
;;;;;;;;;;;;;;;; Section 2: enter compatibility mode
mov ecx, 0xC0000080 ; Set the C-register to 0xC0000080, which is the EFER MSR.
rdmsr ; Read from the model-specific register.
or eax, 1 << 8 ; Set the LM-bit which is the 9th bit (bit 8).
wrmsr ; Write to the model-specific register.
mov eax, cr0 ; Set the A-register to control register 0.
or eax, 1 << 31 ; Set the PG-bit, which is the 32nd bit (bit 31).
mov cr0, eax ; Set control register 0 to the A-register.
;;;;;;;;;;;;;;;;; Section 3: enter 64bit long mode
lgdt [GDT64.Pointer] ; Load the 64-bit global descriptor table.
jmp GDT64.Code:Realm64 ; Set the code segment and enter 64-bit long mode.
[BITS 64]
Realm64:
cli ; Clear the interrupt flag.
mov ax, GDT64.Data ; Set the A-register to the data descriptor.
mov ds, ax ; Set the data segment to the A-register.
mov es, ax ; Set the extra segment to the A-register.
mov fs, ax ; Set the F-segment to the A-register.
mov gs, ax ; Set the G-segment to the A-register.
mov ss, ax ; Set the stack segment to the A-register.
; done
; 32bit print_vga not working in 64bit mode
# BITS could be 32 or 64.
BITS ?= 64
ifeq ($(BITS), 64)
ARCH = x86_64
else
ARCH = i386
endif
assemble: kernel head
ld -o kernel.img -Ttext 0x7e00 --oformat binary image_head.o kernel.o -m elf_i386
ld -o kernel.img -Ttext 0x7e00 --oformat binary image_head.o kernel.o -m elf_$(ARCH)
# Sector 1 = bootloader, Sector 2 - (512B TO 64K) = kernel
# Extend kernel.img to correct size.
test $$(stat -c %s kernel.img) -le 65024
truncate --size=65024 kernel.img
head:
nasm -f elf image_head.asm -o image_head.o
nasm -f elf$(BITS) -DTARGET_BITS=$(BITS) image_head.asm -o image_head.o
kernel:
g++ -ffreestanding -fno-pie -c kernel.cc -o kernel.o -m32 -std=c++17
g++ -ffreestanding -fno-pie -c kernel.cc -o kernel.o -m$(BITS) -std=c++17
clean:
rm *.o *.img
rm -f *.o *.img
[bits 32]
[bits TARGET_BITS]
[extern main]
call main
ret
......@@ -12,7 +12,6 @@ constexpr uint16_t VGA_MAKE_CHAR(char c, uint8_t color) {
}
constexpr uint8_t default_color = 0x0f;
inline void trigger_scroll(uint16_t *pos) {
for(uint16_t row = 1; row < VGA_HEIGHT; ++row) {
memcpy(VGA_BEGIN_ADDR + (row-1)*VGA_WIDTH, VGA_BEGIN_ADDR + row*VGA_WIDTH, VGA_WIDTH);
......
res/1.png 0 → 100644
res/1.png

48.2 KiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment