Skip to content

Commit

Permalink
kernel: load gdt, idt for x64
Browse files Browse the repository at this point in the history
  • Loading branch information
ffwff committed Aug 9, 2019
1 parent f3aa817 commit 2904d88
Show file tree
Hide file tree
Showing 23 changed files with 235 additions and 162 deletions.
31 changes: 18 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ ARCH32=i686-elf
AS32=$(ARCH32)-as
LD32=$(ARCH32)-ld
CR=toolchain/crystal/.build/crystal
CRFLAGS=--cross-compile --target $(ARCH) --prelude ./prelude.cr
CRFLAGS=--cross-compile --target $(ARCH) --prelude ./prelude.cr --error-trace
KERNEL_OBJ=build/main.cr.o build/boot.o
KERNEL_SRC=$(wildcard src/*.cr src/*/*.cr)

Expand All @@ -23,32 +23,37 @@ QEMUFLAGS += \
-m 2G \
-serial stdio \
-no-shutdown -no-reboot \
-vga std
-vga std \
-d int

GDB = /usr/local/bin/gdb

.PHONY: kernel
.PHONY: kernel src/asm/bootstrap.s
all: build/kernel

build/main.cr.o: $(KERNEL_SRC)
@echo "CR src/main.cr"
@FREESTANDING=1 $(CR) build $(CRFLAGS) src/main.cr -o build/main.cr

build/%.o: src/asm/%.s
build/%.o: src/asm/x64/%.s
@echo "AS $<"
@$(AS) $^ -o $@ -Isrc/asm

build/multiboot.o: src/asm/multiboot.s
@echo "AS32 $<"
$(AS32) $^ -o $@ -Isrc/asm
@$(AS) $^ -o $@ -Isrc/asm/x64

build/kernel64: $(KERNEL_OBJ)
@echo "LD64 $^ => $@"
@$(LD) -T link64.ld -o $@ $^

build/kernel: build/multiboot.o
# bootstrapping code
build/kernel: build/bootstrap.o
@echo "LD $^ => $@"
@$(LD32) -T link.ld -z max-page-size=0x1000 -o $@ build/multiboot.o
@$(LD32) -T link.ld -o $@ build/bootstrap.o

build/kernel64.bin: build/kernel64
objcopy --output-target=binary $< $@

build/bootstrap.o: src/asm/bootstrap.s build/kernel64.bin
@echo "AS32 $<"
$(AS32) $< -o $@

#
run: build/kernel
Expand All @@ -67,12 +72,12 @@ rungdb_img: build/kernel drive.img
sleep 0.1s && $(GDB) -quiet \
-ex 'set arch i386:x86-64:intel' \
-ex 'target remote localhost:9000' \
-ex 'hb _bootstrap_start' \
-ex 'hb kmain' \
-ex 'continue' \
-ex 'disconnect' \
-ex 'set arch i386:x86-64:intel' \
-ex 'target remote localhost:9000' \
build/kernel
build/kernel64
-@pkill qemu

rungdb_img_custom: build/kernel drive.img
Expand Down
7 changes: 6 additions & 1 deletion link.ld
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ SECTIONS
*(.text)
}

.data BLOCK(4K) : ALIGN(4K)
. = ALIGN(4K);
_DATA_START = .;
.data : ALIGN(4K)
{
*(.data)
. = 0x120000 - _DATA_START;
kernel64 = .;
*(.kernel64*)
}
}
13 changes: 7 additions & 6 deletions link64.ld
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ OUTPUT_FORMAT(elf64-x86-64)
ENTRY(_start)
SECTIONS
{
. = 0x101000;
. = 0x120000;

_TEXT_START = .;
.text BLOCK(4K) : ALIGN(4K)
{
*(.bootstrap)
*(.text)
}
. = ALIGN(4K);
Expand All @@ -18,11 +19,11 @@ SECTIONS
{
*(.data)

text_start = .; LONG(_TEXT_START)
text_end = .; LONG(_TEXT_END)
data_start = .; LONG(_DATA_START)
data_end = .; LONG(_DATA_END)
kernel_end = .; LONG(_KERNEL_END)
text_start = .; QUAD(_TEXT_START)
text_end = .; QUAD(_TEXT_END)
data_start = .; QUAD(_DATA_START)
data_end = .; QUAD(_DATA_END)
kernel_end = .; QUAD(_KERNEL_END)
}
.bss BLOCK(4K) : ALIGN(4K)
{
Expand Down
40 changes: 20 additions & 20 deletions src/alloc/alloc.cr
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ private MAGIC_POOL_HEADER = 0xC0FEC0FE

private lib Kernel
struct PoolHeader
block_buffer_size : UInt32
block_buffer_size : USize
next_pool : PoolHeader*
first_free_block : PoolBlockHeader*
magic_number : UInt32
magic_number : USize
end

struct PoolBlockHeader
Expand Down Expand Up @@ -55,16 +55,16 @@ private struct Pool
# methods
def init_blocks
# NOTE: first_free_block must be set before doing this
i = first_free_block.address.to_u32
end_addr = @header.address.to_u32 + 0x1000 - block_size * 2
i = first_free_block.address
end_addr = @header.address + 0x1000 - block_size * 2
# fill next_free_block field of all except last one
while i < end_addr
ptr = Pointer(Kernel::PoolBlockHeader).new i.to_u64
ptr.value.next_free_block = Pointer(Kernel::PoolBlockHeader).new(i.to_u64 + block_size)
ptr = Pointer(Kernel::PoolBlockHeader).new i
ptr.value.next_free_block = Pointer(Kernel::PoolBlockHeader).new(i + block_size)
i += block_size
end
# fill last one with zero
ptr = Pointer(Kernel::PoolBlockHeader).new i.to_u64
ptr = Pointer(Kernel::PoolBlockHeader).new i
ptr.value.next_free_block = Pointer(Kernel::PoolBlockHeader).null
end

Expand All @@ -79,15 +79,15 @@ private struct Pool

# obtain a free block and pop it from the pool
# returns a pointer to the buffer
def get_free_block : UInt32
def get_free_block : USize
block = first_free_block
@header.value.first_free_block = block.value.next_free_block
block.address.to_u32 + BLOCK_HEADER_SIZE
block.address + BLOCK_HEADER_SIZE
end

# release a free block
def release_block(addr : UInt32)
block = Pointer(Kernel::PoolBlockHeader).new(addr.to_u64 - BLOCK_HEADER_SIZE)
def release_block(addr : USize)
block = Pointer(Kernel::PoolBlockHeader).new(addr - BLOCK_HEADER_SIZE)
block.value.next_free_block = @header.value.first_free_block
@header.value.first_free_block = block
end
Expand All @@ -98,8 +98,8 @@ module KernelArena

# linked list free pools for sizes of 2^4, 2^5 ... 2^10
@@free_pools = uninitialized Kernel::PoolHeader*[6]
@@start_addr = 0u32
@@placement_addr = 0u32
@@start_addr = 0u64
@@placement_addr = 0u64

def start_addr
@@start_addr
Expand All @@ -114,7 +114,7 @@ module KernelArena

# free pool chaining
@[AlwaysInline]
private def idx_for_pool_size(sz : UInt32)
private def idx_for_pool_size(sz : USize)
case sz
when 32; 0
when 64; 1
Expand All @@ -126,28 +126,28 @@ module KernelArena
end

# pool
private def new_pool(buffer_size : UInt32) : Pool
private def new_pool(buffer_size : USize) : Pool
addr = @@placement_addr
unless addr < USERSPACE_START
panic "out of kernel virtual addresses"
end
Paging.alloc_page_pg(@@placement_addr, true, false)
@@placement_addr += 0x1000

pool_hdr = Pointer(Kernel::PoolHeader).new(addr.to_u64)
pool_hdr = Pointer(Kernel::PoolHeader).new(addr)
pool_hdr.value.block_buffer_size = buffer_size
pool_hdr.value.next_pool = Pointer(Kernel::PoolHeader).null
pool_hdr.value.first_free_block = Pointer(Kernel::PoolBlockHeader).new(addr.to_u64 + Pool::HEADER_SIZE)
pool_hdr.value.first_free_block = Pointer(Kernel::PoolBlockHeader).new(addr + Pool::HEADER_SIZE)
pool_hdr.value.magic_number = MAGIC_POOL_HEADER
pool = Pool.new pool_hdr
pool.init_blocks
pool
end

# manual functions
def malloc(sz : UInt32) : UInt32
def malloc(sz : USize) : USize
panic "only supports sizes of <= 1024" if sz > 1024
pool_size = max(32, sz.nearest_power_of_2).to_u32
pool_size = max(32u64, sz.nearest_power_of_2.to_usize)
idx = idx_for_pool_size pool_size
if @@free_pools[idx].null?
# create a new pool if there isn't any freed
Expand Down Expand Up @@ -185,7 +185,7 @@ module KernelArena
end

# TODO reuse empty free pools to different size
def free(ptr : UInt32)
def free(ptr : USize)
pool_hdr = Pointer(Kernel::PoolHeader).new(ptr.to_u64 & 0xFFFF_F000)
pool = Pool.new pool_hdr
pool.release_block ptr
Expand Down
62 changes: 32 additions & 30 deletions src/alloc/gc.cr
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ lib LibCrystal
end

fun __crystal_malloc64(size : UInt64) : Void*
Gc.unsafe_malloc size.to_u32
Gc.unsafe_malloc size
end

fun __crystal_malloc_atomic64(size : UInt64) : Void*
Gc.unsafe_malloc size.to_u32, true
Gc.unsafe_malloc size, true
end

# white nodes
Expand Down Expand Up @@ -115,15 +115,17 @@ module Gc
fix_white
end

POINTER_SZ = sizeof(Void*)

def cycle
# marking phase
if !@@root_scanned
# we don't have any gray/black nodes at the beginning of a cycle
# conservatively scan the stack for pointers
# Serial.puts @@data_start, ' ', @@data_end, '\n'
scan_region @@data_start.not_nil!, @@data_end.not_nil!
stack_start = 0
asm("mov %esp, $0;" : "=r"(stack_start) :: "volatile")
stack_start = 0u64
asm("mov %rsp, $0" : "=r"(stack_start) :: "volatile")
# NOTE: this causes a segfault! examine it
scan_region stack_start, @@stack_end.not_nil!
@@root_scanned = true
Expand All @@ -148,16 +150,16 @@ module Gc

node.value.magic = GC_NODE_MAGIC_BLACK

buffer_addr = node.address.to_u64 + sizeof(Kernel::GcNode) + sizeof(Void*)
header_ptr = Pointer(UInt32).new(node.address.to_u64 + sizeof(Kernel::GcNode))
buffer_addr = node.address + sizeof(Kernel::GcNode) + sizeof(Void*)
header_ptr = Pointer(USize).new(node.address + sizeof(Kernel::GcNode))
# get its type id
type_id = header_ptr[0]
debug "type: ", type_id, "\n"
# handle gc array
if type_id == GC_ARRAY_HEADER_TYPE
len = header_ptr[1]
i = 0
start = Pointer(UInt32).new(node.address.to_u64 + sizeof(Kernel::GcNode) + GC_ARRAY_HEADER_SIZE)
start = Pointer(USize).new(node.address + sizeof(Kernel::GcNode) + GC_ARRAY_HEADER_SIZE)
while i < len
addr = start[i]
if addr >= KernelArena.start_addr && addr <= KernelArena.placement_addr
Expand Down Expand Up @@ -196,8 +198,8 @@ module Gc
while offsets != 0
if offsets & 1
# lookup the buffer address in its offset
addr = Pointer(UInt32).new(buffer_addr + pos.to_u64 * 4).value
debug "pointer@", pos, " ", Pointer(Void).new(buffer_addr + pos.to_u64 * 4), " = ", Pointer(Void).new(addr.to_u64), "\n"
addr = Pointer(USize).new(buffer_addr + pos * POINTER_SZ).value
# debug "pointer@", pos, " ", Pointer(Void).new(buffer_addr + pos * POINTER_SZ), " = ", Pointer(Void).new(addr), "\n"
unless addr >= KernelArena.start_addr && addr <= KernelArena.placement_addr
# must be a nil union, skip
pos += 1
Expand All @@ -206,7 +208,7 @@ module Gc
end

# mark the header as gray
header = Pointer(Kernel::GcNode).new(addr.to_u64 - sizeof(Kernel::GcNode))
header = Pointer(Kernel::GcNode).new(addr - sizeof(Kernel::GcNode))
debug_mark node, header
case header.value.magic
when GC_NODE_MAGIC
Expand Down Expand Up @@ -261,9 +263,9 @@ module Gc
node = @@first_white_node
while !node.null?
panic "invariance broken" unless node.value.magic == GC_NODE_MAGIC || node.value.magic == GC_NODE_MAGIC_ATOMIC
debug "free ", node, " ", (node.as(UInt8*)+8) ," ", (node.as(UInt8*)+8).as(UInt32*)[0], "\n"
#debug "free ", node, " ", (node.as(UInt8*)+8) ," ", (node.as(UInt8*)+8).as(UInt32*)[0], "\n"
next_node = node.value.next_node
KernelArena.free node.address.to_u32
KernelArena.free node.address
node = next_node
end
@@first_white_node = @@first_black_node
Expand All @@ -286,20 +288,20 @@ module Gc
end
end

def unsafe_malloc(size : UInt32, atomic = false)
def unsafe_malloc(size : USize, atomic = false)
if @@enabled
cycle
end
size += sizeof(Kernel::GcNode)
header = Pointer(Kernel::GcNode).new(KernelArena.malloc(size).to_u64)
header = Pointer(Kernel::GcNode).new(KernelArena.malloc(size))
# move the barrier forwards by immediately graying out the header
header.value.magic = atomic ? GC_NODE_MAGIC_GRAY_ATOMIC : GC_NODE_MAGIC_GRAY
# append node to linked list
if @@enabled
push(@@first_gray_node, header)
end
# return
ptr = Pointer(Void).new(header.address.to_u64 + sizeof(Kernel::GcNode))
ptr = Pointer(Void).new(header.address + sizeof(Kernel::GcNode))
debug self, '\n' if @@enabled
ptr
end
Expand All @@ -308,8 +310,8 @@ module Gc
private def out_nodes(io, first_node)
node = first_node
while !node.null?
body = node.as(UInt32*) + 2
type_id = (node + 1).as(UInt32*)[0]
body = node.as(USize*) + 2
type_id = (node + 1).as(USize*)[0]
io.puts body, " (", type_id, ")"
io.puts ", " if !node.value.next_node.null?
node = node.value.next_node
Expand Down Expand Up @@ -337,18 +339,18 @@ module Gc

private def debug_mark(parent : Kernel::GcNode*, child : Kernel::GcNode*, node? = true)
return
cbody = child.as(UInt32*) + 2
ctype_id = (child + 1).as(UInt32*)[0]
if node?
pbody = parent.as(UInt32*) + 2
ptype_id = (parent + 1).as(UInt32*)[0]
#if ctype_id == GC_ARRAY_HEADER_TYPE
Serial.puts "mark ", parent, " (", ptype_id, "): ", child, '\n'
#end
else
#if ctype_id == GC_ARRAY_HEADER_TYPE
Serial.puts "mark ", parent, ": ", child, '\n'
#end
end
#cbody = child.as(UInt32*) + 2
#ctype_id = (child + 1).as(UInt32*)[0]
#if node?
# pbody = parent.as(UInt32*) + 2
# ptype_id = (parent + 1).as(UInt32*)[0]
# #if ctype_id == GC_ARRAY_HEADER_TYPE
# Serial.puts "mark ", parent, " (", ptype_id, "): ", child, '\n'
# #end
#else
# #if ctype_id == GC_ARRAY_HEADER_TYPE
# Serial.puts "mark ", parent, ": ", child, '\n'
# #end
#end
end
end
Loading

0 comments on commit 2904d88

Please sign in to comment.