From f5f0f5ddae199121daebcd2213aabd81686cc074 Mon Sep 17 00:00:00 2001
From: Benji Dial <Benji3.141@gmail.com>
Date: Tue, 24 Dec 2019 22:31:22 -0500
Subject: [PATCH] start of 0.0.9 branch, using multiboot this time

---
 makefile            |  24 ++--
 src/bootloader.asm  | 277 --------------------------------------------
 src/kernel/files.c  |   2 +-
 src/kernel/files.h  |   4 +-
 src/kernel/link.ld  |  15 +--
 src/kernel/main.c   | 186 +++++++++++++++++++++++++----
 src/kernel/mem.c    |  21 +---
 src/kernel/mem.h    |  19 ++-
 src/kernel/misc.c   |  46 --------
 src/kernel/misc.h   |  27 -----
 src/kernel/proc.c   |   9 +-
 src/kernel/proc.h   |   4 +-
 src/kernel/stub.asm |  76 ++++++++++++
 src/kernel/vga.c    |  37 ++++++
 src/kernel/vga.h    |   2 +
 15 files changed, 325 insertions(+), 424 deletions(-)
 delete mode 100644 src/bootloader.asm
 delete mode 100644 src/kernel/misc.c
 delete mode 100644 src/kernel/misc.h
 create mode 100644 src/kernel/stub.asm

diff --git a/makefile b/makefile
index 229b665..cf5dc6a 100644
--- a/makefile
+++ b/makefile
@@ -1,18 +1,14 @@
-floppy: bootloader fs
-	mkfs.fat -C -f 1 -F 12 -n "PORTLAND OS" -R 2 -S 512 out/floppy.img 1440
-	mkdir out/floppy_mount
-	mount out/floppy.img out/floppy_mount
-	cp out/fs/* out/floppy_mount/
-	umount out/floppy_mount
-	dd if=obj/bootloader.bin of=out/floppy.img bs=1 seek=62 conv=notrunc
+floppy: kernel
+	#TODO
 
-bootloader: obj
-	nasm src/bootloader.asm -o obj/bootloader.bin
-
-kernel: obj fs
-	gcc src/kernel/*.c -o obj/kernel.elf -ffreestanding -nostdlib -m32 -fno-asynchronous-unwind-tables
-	ld obj/kernel.elf -o obj/kernel-stripped.elf -T src/kernel/link.ld -s --orphan-handling=discard -m elf_i386
-	objcopy obj/kernel-stripped.elf out/fs/kernel.sys -O binary
+kernel: obj out
+	nasm src/kernel/stub.asm -o obj/kstub.o -f elf32
+	gcc -c src/kernel/files.c -o obj/kfiles.o -ffreestanding -nostdlib -m32
+	gcc -c src/kernel/main.c  -o obj/kmain.o  -ffreestanding -nostdlib -m32
+	gcc -c src/kernel/mem.c   -o obj/kmem.o   -ffreestanding -nostdlib -m32
+	gcc -c src/kernel/proc.c  -o obj/kproc.o  -ffreestanding -nostdlib -m32
+	gcc -c src/kernel/vga.c   -o obj/kvga.o   -ffreestanding -nostdlib -m32
+	ld obj/k*.o -o out/kernel.elf -T src/kernel/link.ld -s --orphan-handling=discard -m elf_i386
 
 clean:
 	rm -r obj out
diff --git a/src/bootloader.asm b/src/bootloader.asm
deleted file mode 100644
index f18750c..0000000
--- a/src/bootloader.asm
+++ /dev/null
@@ -1,277 +0,0 @@
-;Copyright 2019 Benji Dial
-
-;Permission to use, copy, modify, and/or distribute this
-;software for any purpose with or without fee is hereby
-;granted, provided that the above copyright notice and this
-;permission notice appear in all copies.
-
-;THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS
-;ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-;IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
-;EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-;INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-;WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-;WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
-;TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
-;USE OR PERFORMANCE OF THIS SOFTWARE.
-
-kload equ 0x0010_0000
-
-global_info:;0x0500 - 0x05ff (0x0515)
-.fat      equ 0x0500;dword - pointer
-.root_dir equ 0x0504;dword - pointer
-.low_mem  equ 0x0508;word  - usable memory from 0 to 1MiB in kiB
-.mid_mem  equ 0x050a;word  - usable memory from 1MiB to 16MiB in kiB
-.mem_used equ 0x050c;word  - used memory from 0 to 1MiB in kiB
-.kernel_s equ 0x050e;word  - kernel image length in kiB
-                    ;dword - kernel use
-.high_mem equ 0x0514;word  - usable memory from 16MiB up in 64s of kiB
-
-fat_header:;0x7c03 - 0x7c3d
-.oem_name            equ 0x7c03;mkfs.fat    -
-.bytes_per_sector    equ 0x7c0b;0x0200      -
-.sectors_per_cluster equ 0x7c0d;0x01        -
-.reserved_sectors    equ 0x7c0e;0x0002      - handled
-.n_fats              equ 0x7c10;0x01        -
-.root_dir_entries    equ 0x7c11;            -
-.n_sectors           equ 0x7c13;0x0b40      -
-.media_type          equ 0x7c15;            -
-.sectors_per_fat     equ 0x7c16;            - handled
-.sectors_per_track   equ 0x7c18;0x0012      -
-.sides               equ 0x7c1a;0x0002      -
-.hidden_sectors      equ 0x7c1c;0x0000_0000 -
-.long_sectors        equ 0x7c20;0x0000_0000 -
-.drive_number        equ 0x7c24;            - ignored, used as scratch for real drive number
-.flags               equ 0x7c25;            -
-.signature           equ 0x7c26;0x29        - errors on other values
-.id                  equ 0x7c27;            -
-.label               equ 0x7c2b;PORTLAND OS -
-.fs_type             equ 0x7c36;FAT12       - errors on other values
-
-error_codes:
-.bad_fat_header      equ 0o000
-.insufficient_memory equ 0o001
-.no_kernel           equ 0o002
-.kernel_too_big      equ 0o003
-
-org 0x7c3e
-bits 16
-
-  ;Enable A20 line
-  in al, 0x92
-  or al, 0x02
-  out 0x92, al
-
-  ;Load second sector of bootloader
-  mov ah, 0x42
-  mov si, dap
-  int 0x13
-
-  ;Check FAT signature
-  test byte [fat_header.signature], 0x29
-  jne bad_fat_header
-  test word [fat_header.fs_type], 0x4146;FA
-  jne bad_fat_header
-  test word [fat_header.fs_type + 2], 0x3154;T1
-  jne bad_fat_header
-  test word [fat_header.fs_type + 4], 0x2032;2
-  jne bad_fat_header
-  test word [fat_header.fs_type + 6], 0x2020;
-  jne bad_fat_header
-
-  ;Store boot drive ID for later
-  mov byte [fat_header.drive_number], dl
-
-memory:
-  ;Get available low memory
-  int 0x12
-  mov word [global_info.low_mem], ax
-  mov word [global_info.mem_used], 0x0020
-
-  ;Get available mid and high memory
-  xor dx, dx
-  mov ax, 0xe801
-  int 0x15
-  test dx, dx
-  jnz .got
-  mov cx, ax
-  mov dx, bx
-.got:
-  mov word [global_info.mid_mem], cx
-  mov word [global_info.high_mem], dx
-
-  ;Load FAT
-  mov ax, word [fat_header.reserved_sectors]
-  mov word [dap.start], ax
-  xor eax, eax
-  mov ax, word [fat_header.sectors_per_fat]
-  call load_low
-  mov dword [global_info.fat], ebx
-
-load_root:
-  ;Load root directory
-  mov ax, word [fat_header.sectors_per_fat]
-  xor dh, dh
-  mov dl, word [fat_header.n_fats]
-  mul dx
-  add ax, [fat_header.reserved_sectors]
-  jnc .no_inc
-  inc dx
-.no_inc:
-  mov word [dap.start], ax
-  mov word [dap.start + 2], dx
-  mov ax, word [fat_header.root_dir_entries]
-  shr ax, 4
-  call load_low
-  mov dword [global_info.root_dir], ebx
-
-  ;Calculate end of root directory
-  xor ecx, ecx
-  mov cx, word [fat_header.root_dir_entries]
-  shl ecx, 5
-  add ecx, ebx
-  jc insufficient_memory
-
-find_kernel:
-  mov eax, 0x6e72_656b;kern
-  mov edx, 0x2020_6c65;el
-.loop:
-  ;Check name
-  test dword [ebx], eax
-  jne .next
-  test dword [ebx + 4], edx
-  jne .next
-  test word [ebx + 8], 0x7973;sy
-  jne .next
-  test byte [ebx + 10], 0x73;s
-  je .found
-.next:
-  ;Next record
-  add ebx, 32
-  test ebx, ecx
-  jne .loop
-
-  ;Got to end of directory
-  mov dl, error_codes.no_kernel
-  jmp error
-
-  ;ebx is pointer to entry
-  ;word [ebx + 26] is first cluster
-  ;dword [ebx + 28] is size
-.found:
-  ;Save size for later
-  mov eax, dword [ebx + 28]
-  shr eax, 10
-  test eax, 0x003f_0000
-  jz .store_size
-  mov dl, error_codes.kernel_too_big
-  jmp error
-.store_size:
-  mov word [global_info.kernel_s], ax
-
-  ;Save sector number for later
-  mov cx, [ebx + 26]
-
-  ;find 1kiB buffer
-  mov ax, 2
-  mov byte [load_low.ret_with_segment], 0xc3;ret
-  call load_low
-  shl ebx, 4
-
-load_kernel:
-  
-
-load_low:
-  ;ax in : number of sectors
-  ;qword [dap.start] in : starting sector
-
-  ;Store length in DAP
-  mov word [dap.length], ax
-
-  ;Calculate kiB used
-  dec ax
-  shr ax, 1
-  inc ax
-  mov dx, ax
-  add ax, word [global_info.mem_usage]
-
-  ;Fail if not enough is available
-  jc insufficient_memory
-  cmp ax, word [global_info.low_mem]
-  jg insufficient_memory
-
-  ;Check if address will fit in DAP
-  test ah, ah
-  jnz insufficient_memory
-
-  ;Commit usage
-  mov word [global_info.low_mem_usage], ax
-
-  ;Put address into DAP
-  xor ebx, ebx
-  mov bh, al
-  shr bx, 2
-  mov word [dap.segment], bx
-  mov word [dap.offset], 0x0000
-.ret_with_segment:
-
-  ;Load from disk
-  mov si, dap
-  mov ah, 0x42
-  int 0x13
-  shl ebx, 4
-  ret
-
-bad_fat_header:
-  mov dl, error_codes.bad_fat_header
-  jmp error
-
-insufficient_memory:
-  mov dl, error_codes.insufficient_memory
-  jmp error
-
-error:
-  ;Print error code (in octal)
-  mov ax, 0xb800
-  mov ds, ax
-  mov word [0], 0x0f72;E
-  mov ax, 0x0f00
-  mov al, dl
-  and al, 0x07
-  or al, 0x30
-  mov word [6], ax;bottom digit
-  shr dl, 3
-  mov al, dl
-  and al, 0x07
-  or al, 0x30
-  mov word [4], ax;middle digit
-  shr dl, 3
-  mov al, dl
-  or al, 0x30
-  mov word [2], ax;top digit
-
-  cli
-.halt:
-  hlt
-  jmp .halt
-
-gdt:
-dw 0x28
-dd gdt + 6
-dq 0x0000_0000_0000_0000
-dq 0x0040_9a00_0000_7fff;0x000000 - 0x007fff
-dq 0x0040_9200_0000_7fff
-dq 0x00c0_9a00_8000_0ff7;0x008000 - 0xffffff
-dq 0x00c0_9200_8000_0ff7
-
-dap:
-dw 0x0010
-.length  dw 0x0001
-.offset  dw 0x7e00
-.segment dw 0x0000
-.start   dq 0x0000_0000_0000_0001
-
-memory_usage:
-.low  dw ;word - used memory from 0 to 1MiB in kiB
-.mid  dw 0x0000;word - used memory from 1MiB to 16MiB in kiB
-.high dw 0x0000;word - used memory from 16MiB up in 64s of kiB
\ No newline at end of file
diff --git a/src/kernel/files.c b/src/kernel/files.c
index c17edd4..b42638a 100644
--- a/src/kernel/files.c
+++ b/src/kernel/files.c
@@ -24,7 +24,7 @@ uint16_t open_file(uint8_t *name) {
 }
 
 void close_file(uint16_t handle) {
-  FILE_HANDLES[handle].first_sector = 0;
+  file_table[handle].first_sector = 0;
 }
 
 void read_file(uint16_t handle, uint32_t length, void *buffer) {
diff --git a/src/kernel/files.h b/src/kernel/files.h
index 31ad21f..38e59f1 100644
--- a/src/kernel/files.h
+++ b/src/kernel/files.h
@@ -22,14 +22,14 @@ OF THIS SOFTWARE.
 #ifndef FILES_H
 #define FILES_H
 
-struct file_handle_info {
+struct file_info {
   uint16_t first_sector;
   uint16_t current_sector;
   uint8_t *io_buffer;
   uint32_t position;
 };
 
-#define FILE_HANDLES ((struct file_handle_info *)*(uint32_t *)0x0000050c)
+struct file_info *file_table;
 uint16_t open_file(uint8_t *name);
 void close_file(uint16_t handle);
 void read_file(uint16_t handle, uint32_t length, void *buffer);
diff --git a/src/kernel/link.ld b/src/kernel/link.ld
index aeb8974..7d160f2 100644
--- a/src/kernel/link.ld
+++ b/src/kernel/link.ld
@@ -1,13 +1,8 @@
-MEMORY {
-  kload : ORIGIN = 0x01000000, LENGTH = 0x01000000
-}
-
 SECTIONS {
   . = 0x01000000;
-  .text : {
-    _start = .;
-    *(.text)
-  } >kload
-  .rodata : { *(.rodata) } >kload
-  .data : { *(.data) *(.bss) } >kload
+  .mb_header : ALIGN(8)   { *(.mb_header) }
+  .text      : ALIGN(512) { *(.text)      }
+  .rodata    : ALIGN(512) { *(.rodata)    }
+  .data      : ALIGN(512) { *(.data)      }
+  .bss       : ALIGN(512) { *(.bss) }
 }
\ No newline at end of file
diff --git a/src/kernel/main.c b/src/kernel/main.c
index 9ad9d1c..74fd8bf 100644
--- a/src/kernel/main.c
+++ b/src/kernel/main.c
@@ -21,33 +21,177 @@ OF THIS SOFTWARE.
 #include "files.h"
 #include "mem.h"
 #include "proc.h"
-#include "misc.h"
+#include <stdbool.h>
 
-void _start(void) {
-  *(uint16_t *)0x0000200e = 0x0000;
+extern uint32_t info_pointer;
 
-  *(uint32_t *)0x0000050c = (uint32_t)allocate_pages(16 * sizeof(struct file_handle_info), 2);
-  for (struct file_handle_info *i = FILE_HANDLES, *l = FILE_HANDLES + 65536; i < l; ++i)
-    i->first_sector = 0;
+enum tag_type {
+  BOOT_COMMAND     =  1,
+  LOADER_NAME      =  2,
+  BOOT_MODULES     =  3,
+  MEMORY_INFO      =  4,
+  BOOT_DEVICE      =  5,
+  MEMORY_MAP       =  6,
+  VBE_INFO         =  7,
+  FBUF_INFO        =  8,
+  ELF_SYMBOLS      =  9,
+  APM_TABLE        = 10,
+  EFI_I386_TABLE   = 11,
+  EFI_AMD64_TABLE  = 12,
+  SMBIOS_TABLE     = 13,
+  RSDP_ACPI1       = 14,
+  RSDP_ACPI2       = 15,
+  NETWORK_INFO     = 16,
+  EFI_MEMORY_MAP   = 17,
+  EFI_SERVICES     = 18,
+  EFI_I386_HANDLE  = 19,
+  EFI_AMD64_HANDLE = 20,
+  IMAGE_BASE_ADDR  = 21
+};
 
-  *(uint32_t *)0x00000510 = (uint32_t)allocate_pages(16 * sizeof(struct proc_info), 2);
-  for (struct proc_info *i = PROCS, *l = PROCS + 65536; i < l; ++i)
-    i->memory_start = 0;
+struct tag_start {
+  uint32_t type;
+  uint32_t size;
+  uint8_t rest;
+} __attribute__ ((__packed__));
+
+struct boot_device_tag {
+  uint32_t bios_device;
+  uint32_t partition;
+  uint32_t subpartition;
+} __attribute__ ((__packed__));
+
+enum mem_type {
+  AVAILABLE = 1,
+  ACPI      = 3,
+  PRESERVE  = 4,
+  DEFECTIVE = 5
+};
+
+struct boot_device_tag boot_device;
+bool have_boot_device = false;
+bool have_mmap = false;
+
+enum error_codes {
+  NO_BOOT_DEVICE = 0,
+  NO_MMAP        = 1,
+  INSUFF_MEMORY  = 2
+};
+
+uint32_t main(void) {
+  uint32_t info_size = *(uint32_t *)info_pointer;
+  struct tag_start *tag_pointer = (struct tag_start *)(info_pointer + 2);
+
+  while (tag_pointer->type) {
+    switch (tag_pointer->type) {
+
+    case BOOT_DEVICE:
+      boot_device = *(struct boot_device_tag *)&tag_pointer->rest;
+      have_boot_device = true;
+      put_sz("Boot device: 0x");
+      put_32_hex(boot_device.bios_device);
+      if (boot_device.partition != 0xffffffff) {
+        put_sz(", 0x");
+        put_32_hex(boot_device.partition);
+        if (boot_device.subpartition != 0xffffffff) {
+          put_sz(", 0x");
+          put_32_hex(boot_device.subpartition);
+        }
+      }
+      put_char('\n');
+      break;
+
+    case MEMORY_MAP:
+      mmap_start = (struct mmap_entry *)((uint32_t)&tag_pointer->rest + 8);
+      uint32_t size = *(uint32_t *)&tag_pointer->rest;
+      struct mmap_entry *next = mmap_start;
+      struct mmap_entry **fill_last = &mmap_start;
+      uint32_t usable = 0;
+      while (next) {
+        if (!(next->base & 0xffffffff00000000)) {
+          *fill_last = next;
+          fill_last = &next->next;
+          if ((next->base + next->length - 1) & 0xffffffff00000000)
+            next->length = 1 + ~(next->base);
+          put_sz("Memory: 0x");
+          put_32_hex((uint32_t)(next->base >> 32));
+          put_char('_');
+          put_32_hex((uint32_t)next->base);
+          put_sz(" - ");
+          put_32_hex((uint32_t)(next->length >> 32));
+          put_char('_');
+          put_32_hex((uint32_t)next->length);
+          switch (next->whose) {
+          case AVAILABLE:
+            put_sz(": usable\n");
+            next->whose = FREE;
+            usable += next->length;
+            break;
+          case ACPI:
+            put_sz(": ACPI info\n");
+            next->whose = HARDWARE;
+            break;
+          case PRESERVE:
+            put_sz(": hardware use\n");
+            next->whose = HARDWARE;
+            break;
+          case DEFECTIVE:
+            put_sz(": defective\n");
+            next->whose = HARDWARE;
+            break;
+          default:
+            put_sz(": unrecognized type, assuming hardware use\n");
+            next->whose = HARDWARE;
+            break;
+          }
+        }
+        next = next->next = (struct mmap_entry *)((uint32_t)next + size);
+      }
+
+      put_sz("Total usable memory: 0x");
+      put_32_hex(usable);
+      put_char('\n');
+
+      bool clean;
+      do {
+        clean = true;
+        for (struct mmap_entry *current = mmap_start; current; current = current->next)
+          for (struct mmap_entry *against = mmap_start; against; against = against->next)
+            if ((current->base + current->length == against->base) &&
+                (current->whose == against->whose)) {
+              current->length += against->length;
+              if (against == mmap_start)
+                mmap_start = against->next;
+              else {
+                for (current = mmap_start; current->next != against; current = current->next)
+                  ;
+                current->next = against->next;
+              }
+              clean = false;
+            }
+      } while (clean);
+
+      have_mmap = true;
+      break;
 
-  uint16_t pages_free = 0, pages_total = 0;
-  for (uint16_t *i = MMAP; i < MMAP + 0x1000; ++i)
-    switch (*i) {
-    case 1:
-      continue;
-    case 0:
-      ++pages_free;
     default:
-      ++pages_total;
+      put_sz("Ignoring multiboot tag 0x");
+      put_32_hex(tag_pointer->type);
+      put_char('\n');
+
     }
-  put_16(pages_free);
-  put_sz(" of ");
-  put_16(pages_total);
-  put_sz(" pages free.\n");
+    tag_pointer = (struct tag_start *)((uint8_t *)tag_pointer + tag_pointer->size);
+  };
+
+  if (!have_boot_device)
+    return NO_BOOT_DEVICE;
+  if (!have_mmap)
+    return NO_MMAP;
+
+  if (!((proc_table = allocate_block(sizeof(struct proc_info) * 65536, KERNEL)) &&
+        (file_table = allocate_block(sizeof(struct file_info) * 65536, KERNEL))))
+    return INSUFF_MEMORY;
+  ;
 
   put_sz("Welcome to Portland version 0.0.8!\n");
   while (1)
diff --git a/src/kernel/mem.c b/src/kernel/mem.c
index 509c768..6544108 100644
--- a/src/kernel/mem.c
+++ b/src/kernel/mem.c
@@ -19,23 +19,10 @@ OF THIS SOFTWARE.
 
 #include "mem.h"
 
-void *allocate_pages(uint16_t n_pages, uint16_t proc_n) {
-  for (uint16_t *i = MMAP, *l = MMAP + 0x1000 - proc_n; ++i; i <= l)
-   outer_for:
-    if (!*i) {
-      for (uint16_t j = 1; j < n_pages; ++j)
-        if (i[j]) {
-          i += j + 1;
-          goto outer_for;
-        }
-      for (uint16_t j = 0; j < n_pages; ++j)
-        i[j] = proc_n;
-      return (void *)((i - MMAP) * 0x1000);
-    }
-  return (void *)0;
+void *allocate_block(uint32_t size, uint16_t proc_n) {
+  //TODO
 }
 
-void deallocate_pages(void *from, uint16_t n_pages) {
-  for (uint16_t *mb = MMAP + (uint32_t)from / 0x1000, *l = mb + n_pages; mb < l; ++mb)
-    *mb = 0;
+void deallocate_block(void *start) {
+  //TODO
 }
\ No newline at end of file
diff --git a/src/kernel/mem.h b/src/kernel/mem.h
index 2bfb3bf..1eb27bd 100644
--- a/src/kernel/mem.h
+++ b/src/kernel/mem.h
@@ -22,8 +22,21 @@ OF THIS SOFTWARE.
 #ifndef MEM_H
 #define MEM_H
 
-#define MMAP ((uint16_t *)0x00002000)
-void *allocate_pages(uint16_t n_pages, uint16_t proc_n);
-void deallocate_pages(void *from, uint16_t n_pages);
+enum special_mmap_codes {
+  FREE     = 0,
+  HARDWARE = 1,
+  KERNEL   = 2
+};
+
+struct mmap_entry {
+  uint64_t base;
+  uint64_t length;
+  uint32_t whose;
+  struct mmap_entry *next;
+} __attribute__ ((__packed__));
+
+struct mmap_entry *mmap_start;
+void *allocate_block(uint32_t size, uint16_t proc_n);
+void deallocate_block(void *start);
 
 #endif
\ No newline at end of file
diff --git a/src/kernel/misc.c b/src/kernel/misc.c
deleted file mode 100644
index d002345..0000000
--- a/src/kernel/misc.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-Copyright 2019 Benji Dial
-
-Permission to use, copy, modify, and/or distribute this
-software for any purpose with or without fee is hereby
-granted, provided that the above copyright notice and this
-permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS
-ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
-RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
-ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
-OF THIS SOFTWARE.
-*/
-
-#include "misc.h"
-#include "vga.h"
-#include <stdbool.h>
-
-void put_16(uint16_t n) {
-  bool s = false;
-  if (n / 10000) {
-    put_char((uint8_t)'0' + n / 10000);
-    s = true;
-  }
-  n %= 10000;
-  if (n / 1000 || s) {
-    put_char((uint8_t)'0' + n / 1000);
-    s = true;
-  }
-  n %= 1000;
-  if (n / 100 || s) {
-    put_char((uint8_t)'0' + n / 100);
-    s = true;
-  }
-  n %= 100;
-  if (n / 10 || s) {
-    put_char((uint8_t)'0' + n / 10);
-    s = true;
-  }
-  put_char((uint8_t)'0' + n % 10);
-}
\ No newline at end of file
diff --git a/src/kernel/misc.h b/src/kernel/misc.h
deleted file mode 100644
index d333f26..0000000
--- a/src/kernel/misc.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
-Copyright 2019 Benji Dial
-
-Permission to use, copy, modify, and/or distribute this
-software for any purpose with or without fee is hereby
-granted, provided that the above copyright notice and this
-permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS
-ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
-RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
-ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
-OF THIS SOFTWARE.
-*/
-
-#include <stdint.h>
-
-#ifndef MISC_H
-#define MISC_H
-
-void put_16(uint16_t n);
-
-#endif
\ No newline at end of file
diff --git a/src/kernel/proc.c b/src/kernel/proc.c
index a0fb863..84075d7 100644
--- a/src/kernel/proc.c
+++ b/src/kernel/proc.c
@@ -25,9 +25,10 @@ uint16_t new_proc(uint8_t *file) {
   uint16_t handle = open_file(file);
   if (handle)
     for (uint16_t id = 3; id; ++id)
-      if (!PROCS[id].memory_start) {
+      if (!proc_table[id].memory_start) {
         uint32_t size = get_size(id);
-        void *mem = PROCS[id].memory_start = allocate_pages(PROCS[id].n_pages = (size - 1) / 4096 + 1, id);
+        void *mem;
+        proc_table[id].memory_end = size + (proc_table[id].memory_start = allocate_block(size, id));
         read_file(handle, size, mem);
         close_file(handle);
         //Process file header and make new process
@@ -38,6 +39,6 @@ uint16_t new_proc(uint8_t *file) {
 }
 
 void end_proc(uint16_t id) {
-  deallocate_pages(PROCS[id].memory_start, PROCS[id].n_pages);
-  PROCS[id].memory_start = 0;
+  deallocate_block(proc_table[id].memory_start);
+  proc_table[id].memory_start = 0;
 }
\ No newline at end of file
diff --git a/src/kernel/proc.h b/src/kernel/proc.h
index 893b84e..261ae6b 100644
--- a/src/kernel/proc.h
+++ b/src/kernel/proc.h
@@ -24,10 +24,10 @@ OF THIS SOFTWARE.
 
 struct proc_info {
   void *memory_start;
-  uint16_t n_pages;
+  void *memory_end;
 };
 
-#define PROCS ((struct proc_info *)*(uint32_t *)0x00000510)
+struct proc_info *proc_table;
 uint16_t new_proc(uint8_t *file);
 void end_proc(uint16_t id);
 
diff --git a/src/kernel/stub.asm b/src/kernel/stub.asm
new file mode 100644
index 0000000..2c097d3
--- /dev/null
+++ b/src/kernel/stub.asm
@@ -0,0 +1,76 @@
+;Copyright 2019 Benji Dial
+
+;Permission to use, copy, modify, and/or distribute this
+;software for any purpose with or without fee is hereby
+;granted, provided that the above copyright notice and this
+;permission notice appear in all copies.
+
+;THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS
+;ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+;IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
+;EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+;INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+;RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+;ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+;ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+;OF THIS SOFTWARE.
+
+extern main
+
+section .mb_header
+dd 0xe852_50d6;magic
+dd 0x0000_0000;architecture - i386
+dd mb_end - $$;length
+dd 0x17adaf2a - mb_end + $$;check
+
+;tags
+dw 0x0001;info request
+dw 0x0000;flags
+dd mb_end - $$ - 16
+dd 5;boot device
+dd 6;memory map
+
+mb_end:
+
+section .text
+bits 32
+_start:
+  mov dword [info_pointer], ebx
+  mov esp, stack
+  call main
+  mov edx, eax
+
+  mov eax, 0x20f0_20f0
+  mov ebx, 0x000b_8000
+  mov ecx, 0x000b_8fa0
+clear_screen_loop:
+  mov dword [ebx], eax
+  add ebx, 4
+  test ebx, ecx
+  jne clear_screen_loop
+
+  mov dword [0x000b_8000], 0xf072_f045
+  mov dword [0x000b_8004], 0xf06f_f072
+  mov dword [0x000b_8008], 0xf020_f072
+
+  mov ebx, 0x000b_8022
+error_number_loop:
+  mov al, dl
+  and al, 0x07
+  or al, 0x30
+  mov byte [ebx], al
+  sub ebx, 2
+  shr edx, 3
+  test ebx, 0x000b_800a
+  jne error_number_loop
+
+  cli
+halt:
+  hlt
+  jmp halt
+
+section .bss
+global info_pointer
+info_pointer resd 1
+resb 0x1000 - $ + $$
+stack:
\ No newline at end of file
diff --git a/src/kernel/vga.c b/src/kernel/vga.c
index 046dda7..e3e2516 100644
--- a/src/kernel/vga.c
+++ b/src/kernel/vga.c
@@ -18,6 +18,7 @@ OF THIS SOFTWARE.
 */
 
 #include "vga.h"
+#include <stdbool.h>
 
 uint16_t cursor_pos = 0;
 uint8_t color = 0xf0;
@@ -62,6 +63,42 @@ void put_sz(uint8_t *sz) {
     put_char(*(sz++));
 }
 
+void put_16(uint16_t n) {
+  bool s = false;
+  if (n / 10000) {
+    put_char((uint8_t)'0' + n / 10000);
+    s = true;
+  }
+  n %= 10000;
+  if (n / 1000 || s) {
+    put_char((uint8_t)'0' + n / 1000);
+    s = true;
+  }
+  n %= 1000;
+  if (n / 100 || s) {
+    put_char((uint8_t)'0' + n / 100);
+    s = true;
+  }
+  n %= 100;
+  if (n / 10 || s) {
+    put_char((uint8_t)'0' + n / 10);
+    s = true;
+  }
+  put_char((uint8_t)'0' + n % 10);
+}
+
+void put_32_hex(uint32_t n) {
+  for (uint8_t i = 0; i < 4; ++i) {
+    put_char(n / 0xf0000000 + (n < 0xa0000000 ? (uint8_t)'0' : (uint8_t)'a' - 1));
+    n <<= 4;
+  }
+  put_char('_');
+  for (uint8_t i = 0; i < 4; ++i) {
+    put_char(n / 0xf0000000 + (n < 0xa0000000 ? (uint8_t)'0' : (uint8_t)'a' - 1));
+    n <<= 4;
+  }
+}
+
 void move_cursor(uint8_t col, uint8_t row) {
   cursor_pos = (col + row * cols) * 2;
 }
diff --git a/src/kernel/vga.h b/src/kernel/vga.h
index 74a5d04..2214f27 100644
--- a/src/kernel/vga.h
+++ b/src/kernel/vga.h
@@ -25,6 +25,8 @@ OF THIS SOFTWARE.
 #define VGA_BUFFER ((uint8_t *)0x000b8000)
 void put_char(uint8_t ch);
 void put_sz(uint8_t *s);
+void put_16(uint16_t n);
+void put_32_hex(uint32_t n);
 void move_cursor(uint8_t col, uint8_t row);
 void set_color(uint8_t c);