Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
mstniy committed Jan 26, 2018
1 parent 165d1c1 commit 6e4a7f3
Show file tree
Hide file tree
Showing 98 changed files with 8,083 additions and 0 deletions.
44 changes: 44 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
bochs = bochs
qemu = qemu-system-x86_64
qemu-img = qemu-img
make = make
gpp = g++ --std=c++11

bootsector/bootsector.bin : FORCE
$(make) -C bootsector bootsector.bin

bootloader/bootloader.bin : FORCE
$(make) -C bootloader bootloader.bin

image.bin : bootsector/bootsector.bin bootloader/bootloader.bin
copy bootsector\bootsector.bin /b + bootloader\bootloader.bin /b $@ /b

# On linux, 'truncate' can be used instead
extend_file.exe : extend_file.cpp
$(gpp) $< -o $@

harddisk.img : image.bin extend_file.exe
copy $< $@
extend_file.exe $@ 10321920

sim : harddisk.img cerius.bxrc
$(bochs) -f cerius.bxrc -q

simqemu: harddisk.img
$(qemu) -drive file=harddisk.img,format=raw -m 512M

simqemuahci: harddisk.img
$(qemu) -device ahci,id=ahci0 -drive if=none,file=harddisk.img,format=raw,id=drive -device ide-drive,bus=ahci0.0,drive=drive,id=sata0-0-0 -m 512M

harddisk.vmdk: harddisk.img
$(qemu-img) convert -O vmdk $< $@

clear : FORCE
$(make) -C bootsector clear
$(make) -C bootloader clear
del image.bin
del harddisk.img
del harddisk.vmdk
del extend_file.exe

FORCE:
48 changes: 48 additions & 0 deletions bootloader/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# TODO: Can we get 'make' to search these directories recursively for C++ files?
MEMORY_SRC_DIRS = $(wildcard memory/*)
SRC_DIRS = drivers drivers/Ata common interrupt tests $(MEMORY_SRC_DIRS)
C_SOURCES = $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.cpp))
C_OBJS = ${C_SOURCES:.cpp=.o}
ASM_DIRS = asm interrupt
ASM_SOURCES = $(foreach dir,$(ASM_DIRS),$(wildcard $(dir)/*.asm))
ASM_OBJS = ${ASM_SOURCES:.asm=.o}

nasm = nasm
# -fno-rtti : Disables runtime type identification, i.e., dynamic_cast
# -fno-exceptions: Disables exceptions and all the related crazyness.
gpp = g++ -fno-rtti -fno-exceptions -nostdlib -ffreestanding -fno-use-cxa-atexit --std=c++11 -I. -Icommon
ld = ld

bit16/bootloader_16bit_stage.bin : bit16/bootloader_16bit_stage.asm bit16/*.asm
$(nasm) $< -f bin -o $@ -Wall

bootloader_64bit_stage.o : bootloader_64bit_stage.cpp
$(gpp) -c $< -o $@

bootloader_64bit_stage_caller.elf : bootloader_64bit_stage_caller.asm
$(nasm) $< -f elf64 -o $@ -Wall

bootloader_64bit_stage_with_caller.pe : mylinkscript.txt bootloader_64bit_stage.o bootloader_64bit_stage_caller.elf $(C_OBJS) $(ASM_OBJS)
$(ld) -T $< -o $@ $(filter-out $<,$^)

bootloader_64bit_stage_with_caller.bin : bootloader_64bit_stage_with_caller.pe
objcopy -O binary $< $@

bootloader.bin : bit16/bootloader_16bit_stage.bin bootloader_64bit_stage_with_caller.bin
copy bit16\bootloader_16bit_stage.bin /b + bootloader_64bit_stage_with_caller.bin /b $@ /b

$(C_OBJS) : %.o : %.cpp
$(gpp) -c $< -o $@

$(ASM_OBJS) : %.o : %.asm
$(nasm) $< -f elf64 -o $@ -Wall

clear :
$(foreach dir,$(SRC_DIRS), $(shell del "$(dir)\*.o"))
del bit16\*.bin
del asm\*.o
del *.bin
del *.elf
del *.pe
del *.o

12 changes: 12 additions & 0 deletions bootloader/asm/movestack.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[BITS 64]
global MoveStack

MoveStack:
sub rbp, rsp
add rbp, rdi
mov rcx, rsi
mov rsi, rsp
mov rdi, rdi
mov rsp, rdi
rep movsb
ret
9 changes: 9 additions & 0 deletions bootloader/asm/movestack.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef MOVESTACK_H
#define MOVESTACK_H

// Moves the stack to specified location. Changes rbp such that rbp-rsp will not change.
// Copies the first *stackMoveSize* many bytes from the old stack into the new stack.
// Since this function isn't smart enough to change stack-relative pointers that currently exist on the stack (rbp's in particular), it needs to be called directly from bootloader_64bit_stage
extern "C" __attribute((sysv_abi)) void MoveStack(void* newStackTop, uint64_t stackMoveSize);

#endif
68 changes: 68 additions & 0 deletions bootloader/bit16/adjust_page_table.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
[bits 16]

; uint64_t adjust_page_table(uint32_t initReserveLower, uint32_t initReserveHigher);

; Identity maps the first megabyte and the given initial reserve with kernel-exclusive read-write access.
; Note that initReserveLower/Higher are physical addresses which contain 2mb of usable memory.
; Sets eax to the lower half of the linear address of the 2mb-long initial reserve
; Sets ebx to the higher half

adjust_page_table:
push bp
mov bp, sp
; Initialize the first entry of PML4
mov ebx, paging64.pml4
mov dword [ebx], paging64.pdpt
or dword [ebx], 3
mov dword [ebx+4096], paging64.pdpt
; Initialize the first entry of PDPT
mov ebx, paging64.pdpt
mov dword [ebx], paging64.pd
or dword [ebx], 3
mov dword [ebx+4096], paging64.pd
; Initialize the first entry of PD
mov ebx, paging64.pd
mov dword [ebx], paging64.pt
or dword [ebx], 3
mov dword [ebx+4096], paging64.pt
; Initialize the relevant part of PT
; eax : current physical address to map, ebx: current physical address of current PT entry, ecx: number of PT entries initialized so far
mov eax, 0
mov ecx, 0
mov ebx, paging64.pt
.pt_loop_begin:
cmp ecx, 256 ; 1 mb = 256 * 4kb
jae .pt_loop_end
mov edx, eax
or edx, 11b
mov [ebx], edx
;mov [ebx+4096], edx ; We don't need to set the linear fields for PT entries, because they don't have any child.
add eax, 4096 ; 4kb
add ebx, 8
inc ecx
jmp .pt_loop_begin
.pt_loop_end:
mov eax, [bp+4] ; Page in the initial reserve
mov ebx, [bp+8]
or eax, 10000011b ; Present, writable, pagesize
mov [paging64.pd+8], eax
mov [paging64.pd+12], ebx ; No need to initialize the lin field of the entry because it maps a page, because it has pagesize bit set.
mov eax, 2*1024*1024 ; TODO: Randomize the linear address of the initial reserve.
xor ebx, ebx
leave
ret 8

paging64:
times 4096-(($-$$+0x7E00) % 4096) db 0 ; 4kb alignment
.pml4:
times 512 dq 0 ; This is the format expected by 64bit Pager
times 512 dq 0
.pdpt:
times 512 dq 0
times 512 dq 0
.pd:
times 512 dq 0
times 512 dq 0
.pt:
times 512 dq 0
times 512 dq 0
120 changes: 120 additions & 0 deletions bootloader/bit16/bootloader_16bit_stage.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
[bits 16]
[org 0x7E00] ; Bootsector jmp's to 0x7E00 after it loads the bootloader into the memory

mov sp, 0x7C00 ; Addresses 0x7C00 through 0x7E00 is reserved for the SMAP. Stack starts at 0x7C00 and grows downwards.
mov bp,sp

sub sp, 10 ; word [bp-2] : Number of SMAP entries as returned by detect_mem function.
; dword [bp-6] : Initial reserve linear address, as mapped by adjust_page_table (higher bits)
; dword [bp-10] : Initial reserve linear address, as mapped by adjust_page_table (lower bits)

mov bx, TESTING_A20_MSG
call print_string
call test_a20
test ax, ax
jnz a20_enabled
mov bx, ENABLING_A20_MSG
call print_string
call enable_a20
mov bx, TESTING_A20_MSG
call print_string
call test_a20
test ax, ax
jz a20_cannot_enable
a20_enabled:
mov bx, A20_ENABLED_MSG
call print_string
mov bx, DETECTING_CAPABILITIES_MSG
call print_string
call detect_capabilities
test eax, eax
jz missing_capabilities
mov bx, DETECTING_MEMORY_MSG
call print_string

push 32 ; We have 512 bytes reserved for the SMAP. Since each entry is 16 bytes long, that gives us a maximum of 32 entries.
push 0x7C00;
call detect_mem
cmp ax, 0
je smap_failed
mov word [bp-2], ax
push ax
push 0x7C00
call find_place_for_initial_reserve
mov ecx, eax
or ecx, ebx
test ecx, ecx
jz no_initial_reserve_found
push ebx ; We need not remember the physical address of the initial reserve
push eax
call adjust_page_table
mov dword [bp-6], ebx
mov dword [bp-10], eax
jmp switch_64
[bits 64]
long_mode_begin:
mov rdi, paging64.pml4
mov rsi, 0x7C00
movzx rdx, word [rbp-2]
mov rcx, qword [rbp-10]
mov r8, 2*1024*1024
add sp, 10
call STAGE64_BEGIN ; bootloader_64bit_stage(paging64.pml4, smap, smap_length, initialreservestart, initialreservelength)
cli ; If the kernel returns, shut the cpu down.
hlt


[BITS 16]

a20_cannot_enable:
mov bx, A20_CANNOT_ENABLE_MSG
call print_string
jmp hang

missing_capabilities:
mov bx, MISSING_CAPABILITIES_MSG
call print_string
jmp hang

smap_failed:
mov bx, SMAP_FAILED_MSG
call print_string
jmp hang

no_initial_reserve_found:
mov bx, NO_INITIAL_RESERVE_MSG
call print_string
jmp hang

hang:
cli
hlt
jmp hang


; Constants
TESTING_A20_MSG: db 'Testing if A20 line is enabled...', 0
ENABLING_A20_MSG: db 'Enabling A20 line...', 0
A20_ENABLED_MSG: db 'A20 line is enabled.', 0
A20_CANNOT_ENABLE_MSG: db 'Cannot enable A20 line. Hanging...', 0
DETECTING_CAPABILITIES_MSG: db 'Checking CPU capabilities...', 0
DETECTING_MEMORY_MSG: db 'Detecting memory...', 0
SMAP_FAILED_MSG: db 'Smap failed. Hanging...', 0
MISSING_CAPABILITIES_MSG: db 'No support for CPUID, long mode or SSE2. Hanging...', 0
NO_INITIAL_RESERVE_MSG: db 'No suitable range for the initial memory reserve was found. Hanging...', 0

; Constants
STAGE64_BEGIN equ 0x11E00 ; Linking 16-bit and 64-bit code together seems to confuse the linker. To avoid linking the 16-bit stage with the rest of the bootloader, we jump to a specific address in memory once we switch from 16-bit mode to 64-bit mode. We also tell the linker to put a "jmp" instruction to that address, which jumps to the actual entry point of the 64-bit stage.


%include "bit16/print_string.asm" ; NASM is weird and searches for these includes in its cd, instead of the directory of the code.
%include "bit16/test_a20.asm"
%include "bit16/enable_a20.asm"
%include "bit16/print_hex.asm"
%include "bit16/detect_capabilities.asm"
%include "bit16/detect_mem.asm"
%include "bit16/initial_reserve.asm"
%include "bit16/switch_64.asm"
%include "bit16/adjust_page_table.asm"

times (STAGE64_BEGIN-0x7E00)-($-$$) db 0
25 changes: 25 additions & 0 deletions bootloader/bit16/detect_capabilities.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[BITS 16]

detect_capabilities:
call detect_cpuid
test eax, eax
jz .fail

call detect_long_mode
test eax, eax
jz .fail

call detect_sse2
test eax, eax
jz .fail

mov eax, 1
ret

.fail:
xor eax, eax
ret

%include "bit16/detect_cpuid.asm"
%include "bit16/detect_long_mode.asm"
%include "bit16/detect_sse2.asm"
35 changes: 35 additions & 0 deletions bootloader/bit16/detect_cpuid.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[bits 16]

; From : http://wiki.osdev.org/Setting_Up_Long_Mode

detect_cpuid:
; 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.
xor eax, ecx

ret
20 changes: 20 additions & 0 deletions bootloader/bit16/detect_long_mode.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[bits 16]

; From : http://wiki.osdev.org/Setting_Up_Long_Mode

detect_long_mode:
mov eax, 0x80000000 ; Set the A-register to 0x80000000.
cpuid ; CPU identification.
cmp eax, 0x80000001 ; Compare the A-register with 0x80000001.
jb .fail ; 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 ; They aren't, there is no long mode.
mov eax, 1
ret

.fail:
xor eax, eax
ret
Loading

0 comments on commit 6e4a7f3

Please sign in to comment.