commit before starting Brendan's multitasking tutorial
This commit is contained in:
parent
5880d5296e
commit
ed5b97a87b
17 changed files with 211 additions and 65 deletions
|
|
@ -11,6 +11,7 @@ pub fn build(b: *Builder) void {
|
|||
kernel.addAssemblyFile("src/arch/x86/gdt.s");
|
||||
kernel.addAssemblyFile("src/arch/x86/isr.s");
|
||||
kernel.addAssemblyFile("src/arch/x86/paging.s");
|
||||
// kernel.addAssemblyFile("src/arch/x86/switch_tasks.s");
|
||||
|
||||
kernel.setBuildMode(b.standardReleaseOptions());
|
||||
kernel.setTarget(builtin.Arch.i386, builtin.Os.freestanding, builtin.Abi.none);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
#!/bin/bash
|
||||
exit_missing() {
|
||||
printf "$_ must be installed\n" ; exit 1;
|
||||
}
|
||||
|
||||
exit_missing() { printf "$_ must be installed\n" ; exit 1; }
|
||||
which xorriso || exit_missing
|
||||
which grub-mkrescue || exit_missing
|
||||
|
||||
mkdir -p build/iso/boot
|
||||
cp build/bzImage build/iso/boot
|
||||
grub-mkrescue -o build/kernel.iso build/iso
|
||||
1
src/arch/x86/constants.zig
Normal file
1
src/arch/x86/constants.zig
Normal file
|
|
@ -0,0 +1 @@
|
|||
pub const PAGE_SIZE: usize = 4096;
|
||||
|
|
@ -58,7 +58,7 @@ pub fn initialize() void {
|
|||
isr.install_irqs();
|
||||
isr.install_syscalls();
|
||||
interrupt.registerIRQ(0, interrupt.pit_handler);
|
||||
interrupt.registerIRQ(1, ps2.keyboard_handler);
|
||||
interrupt.registerIRQ(1, kernel.ps2.keyboard_handler);
|
||||
|
||||
// load IDT
|
||||
lidt(@ptrToInt(&idtr));
|
||||
|
|
|
|||
|
|
@ -1,18 +1,16 @@
|
|||
// std
|
||||
pub const assert = @import("std").debug.assert;
|
||||
pub const std = @import("std");
|
||||
pub const assert = std.debug.assert;
|
||||
|
||||
// from core kernel
|
||||
pub usingnamespace @import("../../vga.zig");
|
||||
pub const multiboot = @import("../../multiboot.zig");
|
||||
pub const time = @import("../../time.zig");
|
||||
pub const ps2 = @import("../../ps2.zig");
|
||||
pub const kernel = @import("../../index.zig");
|
||||
|
||||
// x86 namespace
|
||||
pub usingnamespace @import("lib/io.zig");
|
||||
pub usingnamespace @import("lib/instructions.zig");
|
||||
pub usingnamespace @import("main.zig");
|
||||
pub const layout = @import("layout.zig");
|
||||
pub const memory = @import("memory.zig");
|
||||
pub usingnamespace @import("constants.zig");
|
||||
pub const pmem = @import("pmem.zig");
|
||||
pub const paging = @import("paging.zig");
|
||||
pub const idt = @import("idt.zig");
|
||||
pub const isr = @import("isr.zig");
|
||||
|
|
|
|||
|
|
@ -35,11 +35,11 @@ var handlers = [_]fn () void{unhandled} ** 48;
|
|||
|
||||
fn unhandled() noreturn {
|
||||
const n = isr.context.interrupt_n;
|
||||
print("unhandled interrupt number {d}", n);
|
||||
kernel.print("unhandled interrupt number {d}", n);
|
||||
if (n < IRQ_0) {
|
||||
println(" (exception)");
|
||||
kernel.println(" (exception)");
|
||||
} else {
|
||||
println(" (IRQ number {d})", n - IRQ_0);
|
||||
kernel.println(" (IRQ number {d})", n - IRQ_0);
|
||||
}
|
||||
hang();
|
||||
}
|
||||
|
|
@ -196,5 +196,5 @@ pub fn pit_handler() void {
|
|||
// pit freq = 1.193182 MHz
|
||||
// chan0 divisor = 2685
|
||||
// PIT_RATE in us
|
||||
time.increment(2251);
|
||||
kernel.time.increment(2251);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
// usingnamespace @import("kernel");
|
||||
usingnamespace @import("index.zig");
|
||||
// const multiboot = @import("../../multiboot.zig");
|
||||
|
||||
/// x86 specific intialization
|
||||
pub fn x86_main(info: *const multiboot.MultibootInfo) void {
|
||||
pub fn x86_main(info: *const kernel.multiboot.MultibootInfo) void {
|
||||
gdt.initialize();
|
||||
idt.initialize();
|
||||
memory.initialize(info);
|
||||
pmem.initialize(info);
|
||||
paging.initialize();
|
||||
|
||||
// enable interrupts
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
usingnamespace @import("index.zig");
|
||||
// usingnamespace @import("x86");
|
||||
|
||||
extern fn setupPaging(phys_pd: usize) void;
|
||||
|
||||
const PageEntry = usize;
|
||||
pub const PAGE_SIZE = 4096;
|
||||
pub const PT = @intToPtr([*]PageEntry, 0xFFC00000);
|
||||
pub const PD = @intToPtr([*]PageEntry, 0xFFFFF000);
|
||||
const PRESENT = 0x1;
|
||||
|
|
@ -18,18 +16,18 @@ const HUGE = 0x80;
|
|||
pub var pageDirectory: [1024]PageEntry align(4096) linksection(".bss") = [_]PageEntry{0} ** 1024;
|
||||
|
||||
fn pageFault() void {
|
||||
println("pagefault");
|
||||
kernel.println("pagefault");
|
||||
while (true) asm volatile ("hlt");
|
||||
}
|
||||
|
||||
inline fn pageBase(addr: usize) usize {
|
||||
inline fn pageBase(virt: usize) usize {
|
||||
return addr & (~PAGE_SIZE +% 1);
|
||||
}
|
||||
inline fn pde(addr: usize) *PageEntry {
|
||||
return &PD[addr >> 22];
|
||||
inline fn pde(virt: usize) *PageEntry {
|
||||
return &PD[virt >> 22]; //relies on recursive mapping
|
||||
}
|
||||
inline fn pte(addr: usize) *PageEntry {
|
||||
return &PT[addr >> 12];
|
||||
inline fn pte(virt: usize) *PageEntry {
|
||||
return &PT[virt >> 12]; //relies on recursive mapping
|
||||
}
|
||||
|
||||
// virtual to physical
|
||||
|
|
@ -40,17 +38,18 @@ pub fn translate(virt: usize) ?usize {
|
|||
|
||||
pub fn unmap(virt: usize) void {
|
||||
if (translate(virt)) |phys| {
|
||||
memory.free(translate(virt));
|
||||
mem.free(phys);
|
||||
} else {
|
||||
println("can't unmap 0x{x}, map is empty.", addr);
|
||||
kernel.println("can't unmap 0x{x} because it is not mapped.", virt);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mmap(virt: usize, phys: ?usize) !void {
|
||||
var pde: *PageEntry = pde(virt);
|
||||
if (pde.* == 0) pde.* = try memory.allocate() | WRITE | PRESENT;
|
||||
var pte: *PageEntry = pte(virt);
|
||||
pte.* = if (phys) |p| p else allocate() | PRESENT;
|
||||
//TODO: support hugepages
|
||||
// allocate a page directory if there is none
|
||||
if (pde(virt).* == 0) pde(virt).* = (try pmem.allocate()) | WRITE | PRESENT;
|
||||
// allocate a frame if phys isn't specified
|
||||
pte(virt).* = (if (phys) |p| p else try pmem.allocate()) | PRESENT;
|
||||
}
|
||||
|
||||
pub fn initialize() void {
|
||||
|
|
@ -61,7 +60,8 @@ pub fn initialize() void {
|
|||
// recursive mapping
|
||||
p2[1023] = @ptrToInt(&p2[0]) | PRESENT | WRITE;
|
||||
|
||||
assert(memory.stack_end < layout.IDENTITY);
|
||||
// TODO: verify is this a hack?
|
||||
assert(pmem.stack_end < kernel.layout.IDENTITY);
|
||||
|
||||
interrupt.register(14, pageFault);
|
||||
setupPaging(@ptrToInt(&pageDirectory[0]));
|
||||
|
|
@ -72,12 +72,12 @@ pub fn introspect() void {
|
|||
i = 0;
|
||||
while (i < 1024) : (i += 1) {
|
||||
if (PD[i] == 0) continue;
|
||||
println("p2[{}] -> 0x{x}", i, PD[i]);
|
||||
kernel.println("p2[{}] -> 0x{x}", i, PD[i]);
|
||||
if (PD[i] & HUGE != 0) continue;
|
||||
var j: usize = 0;
|
||||
while (j < 1024) : (j += 1) {
|
||||
var entry: PageEntry = PT[i * 1024 + j];
|
||||
if (entry != 0) println("p2[{}]p1[{}] -> 0x{x}", i, j, entry);
|
||||
if (entry != 0) kernel.println("p2[{}]p1[{}] -> 0x{x}", i, j, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ var stack_index: usize = 0; // Index into the stack.
|
|||
pub var stack_size: usize = undefined;
|
||||
pub var stack_end: usize = undefined;
|
||||
|
||||
pub const PAGE_SIZE: usize = 4096;
|
||||
pub inline fn pageAlign(address: u32) u32 {
|
||||
// 4095 -> 4096
|
||||
// 4096 -> 4096
|
||||
|
|
@ -15,7 +14,6 @@ pub inline fn pageAlign(address: u32) u32 {
|
|||
return (address + PAGE_SIZE - 1) & (~PAGE_SIZE +% 1);
|
||||
}
|
||||
|
||||
////
|
||||
// Return the amount of variable elements (in bytes).
|
||||
//
|
||||
pub inline fn available() usize {
|
||||
|
|
@ -26,19 +24,17 @@ pub inline fn available_MiB() usize {
|
|||
return available() / (1024 * 1024);
|
||||
}
|
||||
|
||||
////
|
||||
// Request a free physical page and return its address.
|
||||
//
|
||||
pub fn allocate() !usize {
|
||||
if (available() == 0) {
|
||||
println("out of memory");
|
||||
kernel.println("out of memory");
|
||||
return error.OutOfMemory;
|
||||
}
|
||||
stack_index -= 1;
|
||||
return stack[stack_index];
|
||||
}
|
||||
|
||||
////
|
||||
// Free a previously allocated physical page.
|
||||
//
|
||||
// Arguments:
|
||||
|
|
@ -49,16 +45,15 @@ pub fn free(address: usize) void {
|
|||
stack_index += 1;
|
||||
}
|
||||
|
||||
////
|
||||
// Scan the memory map to index all available memory.
|
||||
//
|
||||
// Arguments:
|
||||
// info: Information structure from bootloader.
|
||||
//
|
||||
pub fn initialize(info: *const multiboot.MultibootInfo) void {
|
||||
pub fn initialize(info: *const kernel.multiboot.MultibootInfo) void {
|
||||
// Ensure the bootloader has given us the memory map.
|
||||
assert((info.flags & multiboot.MULTIBOOT_INFO_MEMORY) != 0);
|
||||
assert((info.flags & multiboot.MULTIBOOT_INFO_MEM_MAP) != 0);
|
||||
assert((info.flags & kernel.multiboot.MULTIBOOT_INFO_MEMORY) != 0);
|
||||
assert((info.flags & kernel.multiboot.MULTIBOOT_INFO_MEM_MAP) != 0);
|
||||
|
||||
// TODO: WHAT WHY WHAAAAT, must check back here later
|
||||
// Place stack at 0x200000 so that in the future I trigger a
|
||||
|
|
@ -74,7 +69,7 @@ pub fn initialize(info: *const multiboot.MultibootInfo) void {
|
|||
|
||||
var map: usize = info.mmap_addr;
|
||||
while (map < info.mmap_addr + info.mmap_length) {
|
||||
var entry = @intToPtr(*multiboot.MultibootMMapEntry, map);
|
||||
var entry = @intToPtr(*kernel.multiboot.MultibootMMapEntry, map);
|
||||
|
||||
// Calculate the start and end of this memory area.
|
||||
var start = @truncate(usize, entry.addr);
|
||||
|
|
@ -83,16 +78,16 @@ pub fn initialize(info: *const multiboot.MultibootInfo) void {
|
|||
start = if (start >= stack_end) start else stack_end;
|
||||
|
||||
// Flag all the pages in this memory area as free.
|
||||
if (entry.type == multiboot.MULTIBOOT_MEMORY_AVAILABLE) while (start < end) : (start += PAGE_SIZE)
|
||||
if (entry.type == kernel.multiboot.MULTIBOOT_MEMORY_AVAILABLE) while (start < end) : (start += PAGE_SIZE)
|
||||
free(start);
|
||||
|
||||
// Go to the next entry in the memory map.
|
||||
map += entry.size + @sizeOf(@typeOf(entry.size));
|
||||
}
|
||||
|
||||
println("available memory: {d} MiB ", available() / 1024 / 1024);
|
||||
kernel.println("available memory: {d} MiB ", available() / 1024 / 1024);
|
||||
}
|
||||
|
||||
pub fn introspect() void {
|
||||
println("physframes left: {d} ({d} MiB)", stack_index, available_MiB());
|
||||
kernel.println("physframes left: {d} ({d} MiB)", stack_index, available_MiB());
|
||||
}
|
||||
47
src/arch/x86/switch_tasks.s
Normal file
47
src/arch/x86/switch_tasks.s
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
;https://wiki.osdev.org/Multitasking_Systems
|
||||
|
||||
;C declaration:
|
||||
; void switch_tasks(thread_control_block *next_thread);
|
||||
;
|
||||
;WARNING: Caller is expected to disable IRQs before calling, and enable IRQs again after function returns
|
||||
|
||||
switch_tasks:
|
||||
|
||||
;Save previous task's state
|
||||
|
||||
;Notes:
|
||||
; For cdecl; EAX, ECX, and EDX are already saved by the caller and don't need to be saved again
|
||||
; EIP is already saved on the stack by the caller's "CALL" instruction
|
||||
; The task isn't able to change CR3 so it doesn't need to be saved
|
||||
; Segment registers are constants (while running kernel code) so they don't need to be saved
|
||||
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
push ebp
|
||||
|
||||
mov edi,[current_task_TCB] ;edi = address of the previous task's "thread control block"
|
||||
mov [edi+TCB.ESP],esp ;Save ESP for previous task's kernel stack in the thread's TCB
|
||||
|
||||
;Load next task's state
|
||||
|
||||
mov esi,[esp+(4+1)*4] ;esi = address of the next task's "thread control block" (parameter passed on stack)
|
||||
mov [current_task_TCB],esi ;Current task's TCB is the next task TCB
|
||||
|
||||
mov esp,[esi+TCB.ESP] ;Load ESP for next task's kernel stack from the thread's TCB
|
||||
mov eax,[esi+TCB.CR3] ;eax = address of page directory for next task
|
||||
mov ebx,[esi+TCB.ESP0] ;ebx = address for the top of the next task's kernel stack
|
||||
mov [TSS.ESP0],ebx ;Adjust the ESP0 field in the TSS (used by CPU for for CPL=3 -> CPL=0 privilege level changes)
|
||||
mov ecx,cr3 ;ecx = previous task's virtual address space
|
||||
|
||||
cmp eax,ecx ;Does the virtual address space need to being changed?
|
||||
je .doneVAS ; no, virtual address space is the same, so don't reload it and cause TLB flushes
|
||||
mov cr3,eax ; yes, load the next task's virtual address space
|
||||
.doneVAS:
|
||||
|
||||
pop ebp
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
|
||||
ret ;Load next task's EIP from its kernel stack)
|
||||
|
|
@ -6,7 +6,7 @@ var command_len: usize = 0;
|
|||
fn execute(com: []u8) void {
|
||||
const eql = std.mem.eql;
|
||||
if (eql(u8, com, "x86paging")) return x86.paging.introspect();
|
||||
if (eql(u8, com, "x86memory")) return x86.memory.introspect();
|
||||
if (eql(u8, com, "x86memory")) return x86.pmem.introspect();
|
||||
if (eql(u8, com, "lspci")) return pci.lspci();
|
||||
if (eql(u8, com, "uptime")) return time.uptime();
|
||||
if (eql(u8, com, "topbar")) return topbar();
|
||||
|
|
|
|||
|
|
@ -1,14 +1,20 @@
|
|||
// std
|
||||
/// std
|
||||
pub const std = @import("std");
|
||||
pub const assert = std.debug.assert;
|
||||
|
||||
// main namespace
|
||||
pub usingnamespace @import("vga.zig");
|
||||
|
||||
///arch
|
||||
pub const x86 = @import("arch/x86/index.zig");
|
||||
|
||||
///core
|
||||
pub const layout = @import("layout.zig");
|
||||
pub const multiboot = @import("multiboot.zig");
|
||||
pub const mem = @import("memory.zig");
|
||||
pub const vmem = @import("vmem.zig");
|
||||
pub const task = @import("task.zig");
|
||||
pub const time = @import("time.zig");
|
||||
|
||||
///extra
|
||||
pub const console = @import("console.zig");
|
||||
pub const pci = @import("pci/pci.zig");
|
||||
pub const ps2 = @import("ps2.zig");
|
||||
pub const time = @import("time.zig");
|
||||
pub const ps2 = @import("ps2.zig"); // i don't know whether this is x86 specific or not
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//https://wiki.osdev.org/Memory_Map_(x86)
|
||||
// virtual memory layout of the kernel
|
||||
|
||||
const kiB = 1024;
|
||||
const kiB = 1024; // bytes
|
||||
const MiB = 1024 * kiB; // 0x100000
|
||||
const GiB = 1024 * MiB;
|
||||
|
||||
|
|
@ -10,6 +11,7 @@ pub const KERNEL = 1 * MiB;
|
|||
pub const IDENTITY = 4 * MiB; // 0->4MiB
|
||||
|
||||
pub const HEAP = 8 * MiB;
|
||||
pub const HEAP_END = 0x1000000;
|
||||
pub const USER_STACKS = 0x1000000;
|
||||
pub const USER_STACKS_END = 0x10000000;
|
||||
// zig fmt: on
|
||||
15
src/main.zig
15
src/main.zig
|
|
@ -1,5 +1,4 @@
|
|||
usingnamespace @import("kernel");
|
||||
// const x86 = @import("x86");
|
||||
|
||||
// Place the header at the very beginning of the binary.
|
||||
export const multiboot_header align(4) linksection(".multiboot") = multiboot: {
|
||||
|
|
@ -16,6 +15,8 @@ export const multiboot_header align(4) linksection(".multiboot") = multiboot: {
|
|||
};
|
||||
};
|
||||
|
||||
extern fn switch_tasks(stack: u32) void;
|
||||
|
||||
// arch independant initialization
|
||||
export fn kmain(magic: u32, info: *const multiboot.MultibootInfo) noreturn {
|
||||
assert(magic == multiboot.MULTIBOOT_BOOTLOADER_MAGIC);
|
||||
|
|
@ -24,9 +25,17 @@ export fn kmain(magic: u32, info: *const multiboot.MultibootInfo) noreturn {
|
|||
x86.x86_main(info);
|
||||
println("--- core initialization ---");
|
||||
pci.scan();
|
||||
console.initialize();
|
||||
vmem.initialize();
|
||||
|
||||
// const t = task.Task.new(@ptrToInt(topbar));
|
||||
// var a = vmem.allocate(u32) catch unreachable;
|
||||
// println("a={}", &a);
|
||||
// const b = vmem.allocate(VGAEntry) catch unreachable;
|
||||
// println("b={x}", &b);
|
||||
|
||||
const t = task.Task.new(@ptrToInt(topbar)) catch unreachable;
|
||||
println("task={x}", &t);
|
||||
|
||||
console.initialize();
|
||||
|
||||
while (true) asm volatile ("hlt");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
pub usingnamespace @import("index.zig");
|
||||
|
||||
pub fn allocate(comptime T: type) !*type {}
|
||||
|
||||
pub fn free(address: usize) void {}
|
||||
|
||||
pub fn initialize() void {}
|
||||
56
src/task.zig
Normal file
56
src/task.zig
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
pub usingnamespace @import("index.zig");
|
||||
// var tasks = Array(?*Task).init(&mem.allocator);
|
||||
|
||||
const STACK_SIZE = x86.PAGE_SIZE; // Size of thread stacks.
|
||||
|
||||
pub const Task = struct {
|
||||
// context: isr.Context,
|
||||
|
||||
////
|
||||
// Create a new thread inside the current process.
|
||||
// NOTE: Do not call this function directly. Use Process.createThread instead.
|
||||
//
|
||||
// Arguments:
|
||||
// entry_point: The entry point of the new thread.
|
||||
//
|
||||
// Returns:
|
||||
// Pointer to the new thread structure.
|
||||
//
|
||||
tid: u16,
|
||||
|
||||
pub fn stack(tid: u16) usize {
|
||||
const stack = layout.USER_STACKS + (2 * (tid - 1) * STACK_SIZE);
|
||||
assert(stack < layout.USER_STACKS_END);
|
||||
return stack;
|
||||
}
|
||||
|
||||
pub fn new(entry_point: usize) !*Task {
|
||||
// assert(scheduler.current_process == process);
|
||||
|
||||
// map the stack
|
||||
|
||||
// Allocate and initialize the thread structure.
|
||||
var this = try vmem.allocate(Task);
|
||||
this.tid = 4;
|
||||
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
// fn initContext(entry_point: usize, stack: usize) isr.Context {
|
||||
// // Insert a trap return address to destroy the thread on return.
|
||||
// var stack_top = @intToPtr(*usize, stack + STACK_SIZE - @sizeOf(usize));
|
||||
// stack_top.* = layout.THREAD_DESTROY;
|
||||
|
||||
// return isr.Context{
|
||||
// .cs = gdt.USER_CODE | gdt.USER_RPL,
|
||||
// .ss = gdt.USER_DATA | gdt.USER_RPL,
|
||||
// .eip = entry_point,
|
||||
// .esp = @ptrToInt(stack_top),
|
||||
// .eflags = 0x202,
|
||||
|
||||
// .registers = isr.Registers.init(),
|
||||
// .interrupt_n = 0,
|
||||
// .error_code = 0,
|
||||
// };
|
||||
// }
|
||||
40
src/vmem.zig
Normal file
40
src/vmem.zig
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
pub usingnamespace @import("index.zig");
|
||||
|
||||
// TODO: make a better memory allocator
|
||||
// stupid simple virtual memory allocator
|
||||
// - does 1:1 virtual/physical mapping
|
||||
// - no defragmentation
|
||||
// - no allocation bigger than a page
|
||||
|
||||
const stack_size: usize = (layout.HEAP_END - layout.HEAP) / x86.PAGE_SIZE;
|
||||
var stack: [stack_size]usize = undefined; // Stack of free virtual addresses
|
||||
var stack_index: usize = 0; // Index into the stack.
|
||||
|
||||
pub fn available() usize {
|
||||
return stack_index * x86.PAGE_SIZE;
|
||||
}
|
||||
|
||||
pub fn allocate(comptime T: type) !*T {
|
||||
assert(@sizeOf(T) < x86.PAGE_SIZE); // this allocator only support 1:1 mapping
|
||||
if (available() == 0) return error.OutOfMemory;
|
||||
stack_index -= 1;
|
||||
var vaddr: usize = stack[stack_index];
|
||||
try x86.paging.mmap(vaddr, null);
|
||||
return @intToPtr(*T, vaddr);
|
||||
}
|
||||
|
||||
pub fn free(address: usize) void {
|
||||
x86.paging.unmap(address);
|
||||
stack[stack_index] = address;
|
||||
stack_index += 1;
|
||||
}
|
||||
|
||||
pub fn initialize() void {
|
||||
var addr: usize = layout.HEAP;
|
||||
while (addr < layout.HEAP_END) : (addr += x86.PAGE_SIZE) {
|
||||
// println("addr {x}", addr);
|
||||
stack[stack_index] = addr;
|
||||
stack_index += 1;
|
||||
// return;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue