aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorMarvin Borner2021-03-20 19:55:51 +0100
committerGitHub2021-03-20 19:55:51 +0100
commit5132bac014d63331acf61bb60b9254023f76b869 (patch)
tree8e2946b7a6630da13ee403c787f77270aeb6185d /kernel
parent435231378798819304eef427bad8e77dffea85df (diff)
parentb96c27bba0b242fc860fc9a2fcb63f121312fa7e (diff)
Merged ELF loading
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile4
-rw-r--r--kernel/drivers/fb.c12
-rw-r--r--kernel/drivers/interrupts.c1
-rw-r--r--kernel/features/fs.c47
-rw-r--r--kernel/features/load.c77
-rw-r--r--kernel/features/mm.c37
-rw-r--r--kernel/features/proc.c19
-rw-r--r--kernel/features/syscall.c13
-rw-r--r--kernel/inc/fb.h2
-rw-r--r--kernel/inc/load.h100
-rw-r--r--kernel/inc/mm.h9
-rw-r--r--kernel/link.ld2
-rw-r--r--kernel/main.c6
13 files changed, 267 insertions, 62 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index e9ade73..64035e5 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -36,5 +36,5 @@ all: compile
compile: $(COBJS)
@mkdir -p ../build/
- @$(LD) -N -z undefs -ekernel_main -Ttext 0x00050000 -o ../build/kernel.elf -L../build/ $+ -lk
- @$(LD) -N -Tlink.ld -o ../build/kernel.bin -L../build/ $+ -lk
+ @$(LD) -N -z undefs -ekernel_main -Ttext 0x00009000 -o ../build/kernel.elf -L../build/ $+ -lk
+ @$(LD) -N -z max-page-size=0x1000 -Tlink.ld -o ../build/kernel.bin -L../build/ $+ -lk
diff --git a/kernel/drivers/fb.c b/kernel/drivers/fb.c
index af8a830..2db05f2 100644
--- a/kernel/drivers/fb.c
+++ b/kernel/drivers/fb.c
@@ -33,11 +33,8 @@ static s32 fb_ioctl(u32 request, void *arg1, void *arg2, void *arg3, struct devi
case IO_FB_GET: {
if (!info)
return -1;
- struct vbe_basic *vbe = (struct vbe_basic *)info->vbe;
memcpy(arg1, info->vbe, sizeof(struct vbe_basic));
- u32 size = vbe->height * vbe->pitch;
- memory_map_identity(proc_current()->page_dir,
- memory_range_around((u32)vbe->fb, size), MEMORY_USER);
+ fb_map_buffer(proc_current()->page_dir, info);
return 0;
}
default:
@@ -50,6 +47,13 @@ static s32 fb_ready(void)
return 1;
}
+void fb_map_buffer(struct page_dir *dir, struct vid_info *boot)
+{
+ struct vbe_basic *vbe = (struct vbe_basic *)boot->vbe;
+ u32 size = vbe->height * vbe->pitch;
+ memory_map_identity(dir, memory_range_around((u32)vbe->fb, size), MEMORY_USER);
+}
+
void fb_install(struct vid_info *boot)
{
info = boot;
diff --git a/kernel/drivers/interrupts.c b/kernel/drivers/interrupts.c
index 2e1444f..255f976 100644
--- a/kernel/drivers/interrupts.c
+++ b/kernel/drivers/interrupts.c
@@ -179,6 +179,7 @@ void isr_panic(struct regs *r)
printf("\t-> Exception occurred in %s at addr 0x%x\n", proc->name,
r->eip - proc->entry);
proc_exit(proc, 1);
+ proc_yield(r);
} else {
__asm__ volatile("cli\nhlt");
}
diff --git a/kernel/features/fs.c b/kernel/features/fs.c
index 56d253a..920add1 100644
--- a/kernel/features/fs.c
+++ b/kernel/features/fs.c
@@ -136,9 +136,6 @@ s32 vfs_read(const char *path, void *buf, u32 offset, u32 count)
if (!buf || !memory_valid(buf))
return -EFAULT;
- if (offset > count)
- return -EINVAL;
-
struct mount_info *m = vfs_find_mount_info(path);
if (!m || !m->dev || !m->dev->vfs)
return -ENOENT;
@@ -168,9 +165,6 @@ s32 vfs_write(const char *path, void *buf, u32 offset, u32 count)
if (!buf || !memory_valid(buf))
return -EFAULT;
- if (offset > count)
- return -EINVAL;
-
struct mount_info *m = vfs_find_mount_info(path);
if (!m || !m->dev || !m->dev->vfs)
return -ENOENT;
@@ -485,25 +479,31 @@ static u32 read_indirect(u32 indirect, u32 block_num, struct device *dev)
static s32 read_inode(struct ext2_inode *in, void *buf, u32 offset, u32 count, struct device *dev)
{
- // TODO: Support read offset
- UNUSED(offset);
-
if (!in || !buf)
return -EINVAL;
- u32 num_blocks = in->blocks / (BLOCK_SIZE / SECTOR_SIZE);
+ if (in->size == 0)
+ return 0;
+
+ u32 num_blocks = in->blocks / (BLOCK_SIZE / SECTOR_SIZE) + 1;
if (!num_blocks)
return -EINVAL;
- // TODO: memcpy block chunks until count is copied
- while (BLOCK_SIZE * num_blocks > count)
- num_blocks--;
+ u32 first_block = offset / BLOCK_SIZE;
+ u32 last_block = (offset + count) / BLOCK_SIZE;
+ if (last_block >= num_blocks)
+ last_block = num_blocks - 1;
+ u32 first_block_offset = offset % BLOCK_SIZE;
+
+ u32 remaining = MIN(count, in->size - offset);
+ u32 copied = 0;
u32 indirect = 0;
u32 blocknum = 0;
+
// TODO: Support triply indirect pointers
- for (u32 i = 0; i < num_blocks; i++) {
+ for (u32 i = first_block; i <= last_block; i++) {
if (i < 12) {
blocknum = in->block[i];
} else if (i < BLOCK_COUNT + 12) {
@@ -518,9 +518,16 @@ static s32 read_inode(struct ext2_inode *in, void *buf, u32 offset, u32 count, s
}
char *data = buffer_read(blocknum, dev);
- memcpy((u32 *)((u32)buf + i * BLOCK_SIZE), data, BLOCK_SIZE);
+ u32 block_offset = (i == first_block) ? first_block_offset : 0;
+ u32 byte_count = MIN(BLOCK_SIZE - block_offset, remaining);
+
+ memcpy((u8 *)buf + copied, data + block_offset, byte_count);
+
+ copied += byte_count;
+ remaining -= byte_count;
+
free(data);
- /* printf("Loaded %d of %d\n", i + 1, num_blocks); */
+ /* printf("Loaded %d of %d\n", i + 1, last_block); */
}
if (indirect_cache) {
@@ -534,7 +541,7 @@ static s32 read_inode(struct ext2_inode *in, void *buf, u32 offset, u32 count, s
indirect_cache = NULL;
}
- return count;
+ return copied;
}
static u32 find_inode(const char *name, u32 dir_inode, struct device *dev)
@@ -627,11 +634,11 @@ s32 ext2_stat(const char *path, struct stat *buf, struct device *dev)
if (find_inode_by_path(path, &in, dev) != &in)
return -ENOENT;
- u32 num_blocks = in.blocks / (BLOCK_SIZE / SECTOR_SIZE);
- u32 sz = BLOCK_SIZE * num_blocks;
+ //u32 num_blocks = in.blocks / (BLOCK_SIZE / SECTOR_SIZE);
+ //u32 sz = BLOCK_SIZE * num_blocks;
buf->dev_id = dev->id;
- buf->size = sz; // Actually in->size but ext2..
+ buf->size = in.size;
return 0;
}
diff --git a/kernel/features/load.c b/kernel/features/load.c
index 65d76d4..3430a75 100644
--- a/kernel/features/load.c
+++ b/kernel/features/load.c
@@ -13,6 +13,10 @@
s32 bin_load(const char *path, struct proc *proc)
{
+ UNUSED(path);
+ UNUSED(proc);
+ panic("Deprecated!\n");
+#if 0
if (!path || !memory_valid(path) || !proc)
return -EFAULT;
@@ -48,4 +52,77 @@ s32 bin_load(const char *path, struct proc *proc)
memory_switch_dir(prev);
return 0;
+#endif
+}
+
+s32 elf_load(const char *path, struct proc *proc)
+{
+ if (!path || !memory_valid(path) || !proc)
+ return -EFAULT;
+
+ struct stat s = { 0 };
+ s32 stat = vfs_stat(path, &s);
+ if (stat != 0)
+ return stat;
+
+ struct elf_header header = { 0 };
+ s32 read = vfs_read(path, &header, 0, sizeof(header));
+ if (read < 0)
+ return read;
+ if (read != sizeof(header))
+ return -ENOEXEC;
+
+ strcpy(proc->name, path);
+
+ // Valid?
+ u8 *magic = header.ident;
+ u8 valid_magic = magic[ELF_IDENT_MAG0] == ELF_MAG0 && magic[ELF_IDENT_MAG1] == ELF_MAG1 &&
+ magic[ELF_IDENT_MAG2] == ELF_MAG2 && magic[ELF_IDENT_MAG3] == ELF_MAG3 &&
+ magic[ELF_IDENT_CLASS] == ELF_IDENT_CLASS_32 &&
+ magic[ELF_IDENT_DATA] == ELF_IDENT_DATA_LSB;
+ if (!valid_magic || (header.type != ELF_ETYPE_REL && header.type != ELF_ETYPE_EXEC) ||
+ header.version != 1 || header.machine != ELF_MACHINE_386)
+ return -ENOEXEC;
+
+ for (u32 i = 0; i < header.phnum; i++) {
+ struct elf_program program = { 0 };
+ if (vfs_read(path, &program, header.phoff + header.phentsize * i,
+ sizeof(program)) != sizeof(program))
+ return -ENOEXEC;
+
+ if (program.vaddr == 0)
+ continue;
+
+ if (program.vaddr <= 0x100000)
+ return -ENOEXEC;
+
+ struct page_dir *prev;
+ memory_backup_dir(&prev);
+ memory_switch_dir(proc->page_dir);
+
+ struct memory_range vrange = memory_range_around(program.vaddr, program.memsz);
+ struct memory_range prange = physical_alloc(vrange.size);
+ virtual_map(proc->page_dir, prange, vrange.base, MEMORY_CLEAR | MEMORY_USER);
+
+ if ((u32)vfs_read(proc->name, (void *)program.vaddr, program.offset,
+ program.filesz) != program.filesz) {
+ memory_switch_dir(prev);
+ return -ENOEXEC;
+ }
+
+ memory_switch_dir(prev);
+ }
+
+ struct page_dir *prev;
+ memory_backup_dir(&prev);
+ memory_switch_dir(proc->page_dir);
+
+ u32 stack = (u32)memory_alloc(proc->page_dir, PROC_STACK_SIZE, MEMORY_USER | MEMORY_CLEAR);
+ proc->regs.ebp = stack + PROC_STACK_SIZE;
+ proc->regs.useresp = stack + PROC_STACK_SIZE;
+ proc->regs.eip = header.entry;
+ proc->entry = header.entry;
+
+ memory_switch_dir(prev);
+ return 0;
}
diff --git a/kernel/features/mm.c b/kernel/features/mm.c
index d007039..b804076 100644
--- a/kernel/features/mm.c
+++ b/kernel/features/mm.c
@@ -4,6 +4,7 @@
#include <assert.h>
#include <cpu.h>
#include <def.h>
+#include <fb.h>
#include <mem.h>
#include <mm.h>
#include <print.h>
@@ -15,25 +16,27 @@ static struct page_table kernel_tables[PAGE_KERNEL_COUNT] ALIGNED(PAGE_SIZE) = {
* Lowlevel paging
*/
-/*static void paging_disable(void)
+static void paging_switch_dir(u32 dir)
+{
+ cr3_set(dir);
+}
+
+extern void paging_invalidate_tlb(void);
+
+/*void paging_disable(void)
{
cr0_set(cr0_get() | 0x7fffffff);
}*/
-static void paging_enable(void)
+void paging_enable(void)
{
cr0_set(cr0_get() | 0x80000000);
}
-static void paging_switch_dir(u32 dir)
-{
- cr3_set(dir);
-}
-
-extern void paging_invalidate_tlb(void);
-
void page_fault_handler(struct regs *r)
{
+ print("--- PAGE FAULT! ---\n");
+
// Check error code
const char *type = (r->err_code & 1) ? "present" : "non-present";
const char *operation = (r->err_code & 2) ? "write" : "read";
@@ -46,8 +49,8 @@ void page_fault_handler(struct regs *r)
struct page_dir *dir = NULL;
if (proc && proc->page_dir) {
dir = proc->page_dir;
- printf("Stack is at %x, entry at %x\n", virtual_to_physical(dir, proc->regs.ebp),
- virtual_to_physical(dir, proc->entry));
+ /* printf("Stack is at %x, entry at %x\n", virtual_to_physical(dir, proc->regs.ebp), */
+ /* virtual_to_physical(dir, proc->entry)); */
} else {
dir = &kernel_dir;
}
@@ -163,7 +166,7 @@ void physical_free(struct memory_range range)
* Virtual
*/
-#define PDI(vaddr) (((vaddr) >> 22) & 0x03ff)
+#define PDI(vaddr) ((vaddr) >> 22)
#define PTI(vaddr) (((vaddr) >> 12) & 0x03ff)
u8 virtual_present(struct page_dir *dir, u32 vaddr)
@@ -413,19 +416,20 @@ void memory_backup_dir(struct page_dir **backup)
static u8 memory_bypass_validity = 0;
void memory_bypass_enable(void)
{
- memory_bypass_validity = 1;
+ /* memory_bypass_validity = 1; */
}
void memory_bypass_disable(void)
{
- memory_bypass_validity = 0;
+ /* memory_bypass_validity = 0; */
}
// TODO: Limit by proc stack and data range
u8 memory_valid(const void *addr)
{
+ /* return ((u32)addr) / PAGE_SIZE / PAGE_COUNT >= PAGE_KERNEL_COUNT; */
if (proc_current() && !memory_bypass_validity)
- return ((u32)addr) / PAGE_SIZE / PAGE_COUNT >= PAGE_KERNEL_COUNT;
+ return (u32)addr >= 0x100000;
else
return 1;
}
@@ -503,9 +507,10 @@ void memory_install(struct mem_info *mem_info, struct vid_info *vid_info)
memory_map_identity(&kernel_dir, memory_range_around(STACK_START - STACK_SIZE, STACK_SIZE),
MEMORY_NONE);
- // Map VBE data
+ // Map framebuffer
memory_map_identity(&kernel_dir, memory_range_around((u32)vid_info->vbe, 0x1000),
MEMORY_NONE);
+ fb_map_buffer(virtual_kernel_dir(), vid_info);
// Unmap NULL byte/page
struct memory_range zero = memory_range(0, PAGE_SIZE);
diff --git a/kernel/features/proc.c b/kernel/features/proc.c
index cd0fc8d..5d3c8aa 100644
--- a/kernel/features/proc.c
+++ b/kernel/features/proc.c
@@ -59,7 +59,7 @@ void scheduler(struct regs *regs)
}
memory_switch_dir(((struct proc *)current->data)->page_dir);
- memcpy(regs, &((struct proc *)current->data)->regs, sizeof(struct regs));
+ memcpy(regs, &((struct proc *)current->data)->regs, sizeof(*regs));
if (regs->cs != GDT_USER_CODE_OFFSET) {
regs->gs = GDT_USER_DATA_OFFSET;
@@ -81,11 +81,13 @@ void proc_print(void)
{
struct node *node = proc_list->head;
- printf("\nPROCESSES\n");
+ printf("--- PROCESSES ---\n");
struct proc *proc = NULL;
while (node && (proc = node->data)) {
- printf("Process %d: %s [%s]\n", proc->pid, proc->name,
- proc->state == PROC_RUNNING ? "RUNNING" : "SLEEPING");
+ printf("Process %d: %s [%s] [entry: %x; stack: %x]\n", proc->pid, proc->name,
+ proc->state == PROC_RUNNING ? "RUNNING" : "SLEEPING",
+ virtual_to_physical(proc->page_dir, proc->entry),
+ virtual_to_physical(proc->page_dir, proc->regs.ebp));
node = node->next;
}
printf("\n");
@@ -145,9 +147,10 @@ void proc_exit(struct proc *proc, int status)
printf("Process %s exited with status %d (%s)\n", proc->name, status,
status == 0 ? "success" : "error");
+ virtual_destroy_dir(proc->page_dir);
proc_clear_quantum(); // TODO: Add quantum to each process struct?
- sti();
- hlt();
+
+ // The caller has to yield itself
}
void proc_yield(struct regs *r)
@@ -497,13 +500,13 @@ void proc_init(void)
// Idle proc
struct proc *kernel_proc = proc_make(PROC_PRIV_NONE);
- assert(bin_load("/bin/idle", kernel_proc) == 0);
+ assert(elf_load("/bin/idle", kernel_proc) == 0);
kernel_proc->state = PROC_SLEEPING;
idle_proc = list_add(proc_list, kernel_proc);
// Init proc (root)
struct node *new = list_add(proc_list, proc_make(PROC_PRIV_ROOT));
- assert(bin_load("/bin/init", new->data) == 0);
+ assert(elf_load("/bin/init", new->data) == 0);
current = new;
proc_stack_push(new->data, 0);
diff --git a/kernel/features/syscall.c b/kernel/features/syscall.c
index b0b37ac..7d68d93 100644
--- a/kernel/features/syscall.c
+++ b/kernel/features/syscall.c
@@ -72,16 +72,19 @@ static void syscall_handler(struct regs *r)
case SYS_EXEC: {
char *path = (char *)r->ebx;
struct proc *proc = proc_make(PROC_PRIV_NONE);
- r->eax = (u32)bin_load(path, proc);
- if (r->eax != 0)
+ r->eax = (u32)elf_load(path, proc);
+ if (r->eax != 0) {
proc_exit(proc, -r->eax);
- // TODO: Reimplement argc,argv
- proc_stack_push(proc, 0);
- proc_yield(r);
+ } else {
+ // TODO: Reimplement argc,argv
+ proc_stack_push(proc, 0);
+ proc_yield(r);
+ }
break;
}
case SYS_EXIT: {
proc_exit(proc_current(), (int)r->ebx);
+ proc_yield(r);
break;
}
case SYS_BOOT: { // TODO: Move
diff --git a/kernel/inc/fb.h b/kernel/inc/fb.h
index 212230b..3b545fd 100644
--- a/kernel/inc/fb.h
+++ b/kernel/inc/fb.h
@@ -4,7 +4,9 @@
#define FB_H
#include <boot.h>
+#include <mm.h>
+void fb_map_buffer(struct page_dir *dir, struct vid_info *boot);
void fb_install(struct vid_info *boot);
#endif
diff --git a/kernel/inc/load.h b/kernel/inc/load.h
index bd3b10d..28bdc54 100644
--- a/kernel/inc/load.h
+++ b/kernel/inc/load.h
@@ -6,6 +6,106 @@
#include <def.h>
#include <proc.h>
+/**
+ * ELF
+ */
+
+#define ELF_MAG0 0x7F
+#define ELF_MAG1 'E'
+#define ELF_MAG2 'L'
+#define ELF_MAG3 'F'
+
+#define ELF_IDENT_COUNT 16
+#define ELF_IDENT_MAG0 0
+#define ELF_IDENT_MAG1 1
+#define ELF_IDENT_MAG2 2
+#define ELF_IDENT_MAG3 3
+
+#define ELF_IDENT_CLASS 4
+#define ELF_IDENT_CLASS_NONE 0
+#define ELF_IDENT_CLASS_32 1
+#define ELF_IDENT_CLASS_64 2
+
+#define ELF_IDENT_DATA 5
+#define ELF_IDENT_DATA_NONE 0
+#define ELF_IDENT_DATA_LSB 1
+#define ELF_IDENT_DATA_MSB 2
+
+#define ELF_IDENT_VERSION 6
+#define ELF_IDENT_OSABI 7
+#define ELF_IDENT_ABIVERSION 8
+#define ELF_IDENT_PAD 9
+
+#define ELF_ETYPE_NONE 0
+#define ELF_ETYPE_REL 1
+#define ELF_ETYPE_EXEC 2
+#define ELF_ETYPE_DYN 3
+#define ELF_ETYPE_CORE 4
+
+#define ELF_MACHINE_NONE 0
+#define ELF_MACHINE_SPARC 2
+#define ELF_MACHINE_386 3
+#define ELF_MACHINE_SPARC32PLUS 18
+#define ELF_MACHINE_SPARCV9 43
+#define ELF_MACHINE_AMD64 62
+
+#define ELF_FLAG_SPARC_EXT_MASK 0xffff00
+#define ELF_FLAG_SPARC_32PLUS 0x000100
+#define ELF_FLAG_SPARC_SUN_US1 0x000200
+#define ELF_FLAG_SPARC_HAL_R1 0x000400
+#define ELF_FLAG_SPARC_SUN_US3 0x000800
+#define ELF_FLAG_SPARCV9_MM 0x3
+#define ELF_FLAG_SPARCV9_TSO 0x0
+#define ELF_FLAG_SPARCV9_PSO 0x1
+#define ELF_FLAG_SPARCV9_RMO 0x2
+
+#define ELF_PROGRAM_X 0x1
+#define ELF_PROGRAM_W 0x2
+#define ELF_PROGRAM_R 0x4
+
+#define ELF_SECTION_TYPE_NULL 0
+#define ELF_SECTION_TYPE_PROGBITS 1
+#define ELF_SECTION_TYPE_SYMTAB 2
+#define ELF_SECTION_TYPE_STRTAB 3
+#define ELF_SECTION_TYPE_RELA 4
+#define ELF_SECTION_TYPE_HASH 5
+#define ELF_SECTION_TYPE_DYNAMIC 6
+#define ELF_SECTION_TYPE_NOTE 7
+#define ELF_SECTION_TYPE_NOBITS 8
+#define ELF_SECTION_TYPE_REL 9
+#define ELF_SECTION_TYPE_SHLIB 10
+#define ELF_SECTION_TYPE_DYNSYM 11
+#define ELF_SECTION_TYPE_COUNT 12
+
+struct PACKED elf_header {
+ u8 ident[ELF_IDENT_COUNT];
+ u16 type;
+ u16 machine;
+ u32 version;
+ u32 entry;
+ u32 phoff;
+ u32 shoff;
+ u32 flags;
+ u16 ehsize;
+ u16 phentsize;
+ u16 phnum;
+ u16 shentsize;
+ u16 shnum;
+ u16 shstrndx;
+};
+
+struct elf_program {
+ u32 type;
+ u32 offset;
+ u32 vaddr;
+ u32 paddr;
+ u32 filesz;
+ u32 memsz;
+ u32 flags;
+ u32 align;
+};
+
s32 bin_load(const char *path, struct proc *proc);
+s32 elf_load(const char *path, struct proc *proc);
#endif
diff --git a/kernel/inc/mm.h b/kernel/inc/mm.h
index 98dcf46..5a307b2 100644
--- a/kernel/inc/mm.h
+++ b/kernel/inc/mm.h
@@ -13,6 +13,13 @@ struct memory_range {
};
/**
+ * Lowlevel paging
+ */
+
+void paging_enable(void);
+void page_fault_handler(struct regs *r);
+
+/**
* Physical
*/
@@ -109,6 +116,4 @@ u8 memory_valid(const void *addr);
void memory_install(struct mem_info *mem_info, struct vid_info *vid_info);
-void page_fault_handler(struct regs *r);
-
#endif
diff --git a/kernel/link.ld b/kernel/link.ld
index 5a63e33..fbe8a8c 100644
--- a/kernel/link.ld
+++ b/kernel/link.ld
@@ -1,7 +1,7 @@
OUTPUT_FORMAT("binary")
OUTPUT_ARCH(i386)
ENTRY(kernel_main)
-phys = 0x00050000;
+phys = 0x00009000;
SECTIONS
{
diff --git a/kernel/main.c b/kernel/main.c
index 3b75c7d..3ff0463 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -21,16 +21,14 @@
void kernel_main(struct mem_info *mem_info, struct vid_info *vid_info); // Decl
void kernel_main(struct mem_info *mem_info, struct vid_info *vid_info)
{
- // Clear stack
- for (u32 i = 0; i < STACK_SIZE; i++)
- ((u8 *)STACK_START)[-i] = 0;
-
// Serial connection
serial_install();
serial_print("\nKernel was compiled at " __TIME__ " on " __DATE__ "\n");
serial_print("Serial connected.\n");
memory_install(mem_info, vid_info);
+ memory_switch_dir(virtual_kernel_dir());
+ paging_enable();
cpu_enable_features();
cpu_print();