feat: expose some more data from asm
+ 343
- 3
@@ -113,6 +113,11 @@ section .entry
 global _start
 _start:
 	mov esp, kernelStackStart
+	
+	push eax  ; video mode
+	push ebx  ; memory map
+	push ecx  ; number of lines printed
+	
 	call kearly
 	call kmain
 

...
@@ -125,3 +130,11 @@ align 16
 kernelStackEnd:
 	times 16384 db 0
 kernelStackStart:
+
+section .magic
+
+global crystalOSMagic
+crystalOSMagic: db "123113371338"
+
+global crystalOSVersion
+crystalOSVersion: db "0.1.0"

new file
kernel/idt_v2.cr
@@ -0,0 +1,270 @@
+lib KernelShim
+  fun outb(port : UInt16, value : UInt8)
+  fun wait()
+end
+
+module IDT
+  # Constants
+  IDT_ADDRESS = 0xc0007100_u32
+  KERNEL_CODE_SEGMENT_SELECTOR = 0x18_u16
+  INTERRUPT_GATE = 0x8e_u8
+
+  # Structs
+  struct IDTEntry
+    offset_low : UInt16
+    selector : UInt16
+    unused : UInt8
+    type : UInt8
+    offset_high : UInt16
+  end
+
+  struct IDTPointer
+    size : UInt16
+    address : UInt32
+  end
+
+  module Handlers
+    def self.handle_division_by_zero_exception
+      # handler code
+    end
+
+    def self.handle_debug_exception
+      # handler code
+    end
+
+    def self.handle_non_maskable_exception
+      # handler code
+    end
+
+    def self.handle_breakpoint_exception
+      # handler code
+    end
+
+    def self.handle_overflow_exception
+      # handler code
+    end
+
+    def self.handle_bound_range_exceeded_exception
+      # handler code
+    end
+
+    def self.handle_invalid_opcode_exception
+      # handler code
+    end
+
+    def self.handle_device_not_available_exception
+      # handler code
+    end
+
+    def self.handle_double_fault_exception
+      # handler code
+    end
+
+    def self.handle_invalid_tss_exception
+      # handler code
+    end
+
+    def self.handle_segment_not_present_exception
+      # handler code
+    end
+
+    def self.handle_stack_segment_fault_exception
+      # handler code
+    end
+
+    def self.handle_general_protection_fault_exception
+      # handler code
+    end
+
+    def self.handle_page_fault_exception
+      # handler code
+    end
+
+    def self.handle_x87_floating_point_exception
+      # handler code
+    end
+
+    def self.handle_alignment_check_exception
+      # handler code
+    end
+
+    def self.handle_machine_check_exception
+      # handler code
+    end
+
+    def self.handle_simd_floating_point_exception
+      # handler code
+    end
+
+    def self.handle_virtualisation_exception
+      # handler code
+    end
+
+    def self.handle_security_exception
+      # handler code
+    end
+
+    def self.handle_interrupt_request_0
+      # handler code
+    end
+
+    def self.handle_interrupt_request_1
+      # handler code
+    end
+
+    def self.handle_interrupt_request_2
+      # handler code
+    end
+
+    def self.handle_interrupt_request_3
+      # handler code
+    end
+
+    def self.handle_interrupt_request_4
+      # handler code
+    end
+
+    def self.handle_interrupt_request_5
+      # handler code
+    end
+
+    def self.handle_interrupt_request_6
+      # handler code
+    end
+
+    def self.handle_interrupt_request_7
+      # handler code
+    end
+
+    def self.handle_interrupt_request_8
+      # handler code
+    end
+
+    def self.handle_interrupt_request_9
+      # handler code
+    end
+
+    def self.handle_interrupt_request_10
+      # handler code
+    end
+
+    def self.handle_interrupt_request_11
+      # handler code
+    end
+
+    def self.handle_interrupt_request_12
+      # handler code
+    end
+
+    def self.handle_interrupt_request_13
+      # handler code
+    end
+
+    def self.handle_interrupt_request_14
+      # handler code
+    end
+
+    def self.handle_interrupt_request_15
+      # handler code
+    end
+  end
+
+  # Functions
+  def self.remap_pic
+    MASTER_PIC_COMMAND = 0x20_u8
+    MASTER_PIC_DATA = 0x21_u8
+    SLAVE_PIC_COMMAND = 0xa0_u8
+    SLAVE_PIC_DATA = 0xa1_u8
+
+    INIT_SEQUENCE_START = 0x11_u8
+    MASTER_PIC_OFFSET = 0x20_u8
+    SLAVE_PIC_OFFSET = 0x28_u8
+    MODE_8086 = 0x01_u8
+
+    KernelShim.outb(MASTER_PIC_COMMAND, INIT_SEQUENCE_START)
+    KernelShim.wait()
+    KernelShim.outb(SLAVE_PIC_COMMAND, INIT_SEQUENCE_START)
+    KernelShim.wait()
+    KernelShim.outb(MASTER_PIC_DATA, MASTER_PIC_OFFSET)
+    KernelShim.wait()
+    KernelShim.outb(SLAVE_PIC_DATA, SLAVE_PIC_OFFSET)
+    KernelShim.wait()
+    KernelShim.outb(MASTER_PIC_DATA, 0x04_u8) # Tells master there's a slave on IRQ2
+    KernelShim.wait()
+    KernelShim.outb(SLAVE_PIC_DATA, 0x02_u8) # Tells slave its cascade identity
+    KernelShim.wait()
+    KernelShim.outb(MASTER_PIC_DATA, MODE_8086)
+    KernelShim.wait()
+    KernelShim.outb(SLAVE_PIC_DATA, MODE_8086)
+    KernelShim.wait()
+    KernelShim.outb(MASTER_PIC_DATA, 0x00_u8) # Masks all interrupts (enable)
+    KernelShim.wait()
+    KernelShim.outb(SLAVE_PIC_DATA, 0x00_u8) # Masks all interrupts (enable)
+    KernelShim.wait()
+  end
+
+  def self.set_up_idt_entries(idt_entries : IDTEntry*)
+    handlers = [
+      Handlers.handle_division_by_zero_exception,
+      Handlers.handle_debug_exception,
+      Handlers.handle_non_maskable_exception,
+      Handlers.handle_breakpoint_exception,
+      Handlers.handle_overflow_exception,
+      Handlers.handle_bound_range_exceeded_exception,
+      Handlers.handle_invalid_opcode_exception,
+      Handlers.handle_device_not_available_exception,
+      Handlers.handle_double_fault_exception,
+      Handlers.handle_invalid_tss_exception,
+      Handlers.handle_segment_not_present_exception,
+      Handlers.handle_stack_segment_fault_exception,
+      Handlers.handle_general_protection_fault_exception,
+      Handlers.handle_page_fault_exception,
+      Handlers.handle_x87_floating_point_exception,
+      Handlers.handle_alignment_check_exception,
+      Handlers.handle_machine_check_exception,
+      Handlers.handle_simd_floating_point_exception,
+      Handlers.handle_virtualisation_exception,
+      Handlers.handle_security_exception,
+      Handlers.handle_interrupt_request_0,
+      Handlers.handle_interrupt_request_1,
+      Handlers.handle_interrupt_request_2,
+      Handlers.handle_interrupt_request_3,
+      Handlers.handle_interrupt_request_4,
+      Handlers.handle_interrupt_request_5,
+      Handlers.handle_interrupt_request_6,
+      Handlers.handle_interrupt_request_7,
+      Handlers.handle_interrupt_request_8,
+      Handlers.handle_interrupt_request_9,
+      Handlers.handle_interrupt_request_10,
+      Handlers.handle_interrupt_request_11,
+      Handlers.handle_interrupt_request_12,
+      Handlers.handle_interrupt_request_13,
+      Handlers.handle_interrupt_request_14,
+      Handlers.handle_interrupt_request_15,
+    ]
+
+    handlers.each_with_index do |handler, index|
+      idt_entries[index].offset_low = (handler.address & 0x0000ffff).to_u16
+      idt_entries[index].selector = KERNEL_CODE_SEGMENT_SELECTOR
+      idt_entries[index].unused = 0_u8
+      idt_entries[index].type = INTERRUPT_GATE
+      idt_entries[index].offset_high = ((handler.address & 0xffff0000) >> 16).to_u16
+    end
+  end
+
+  def self.load_idt(idt_entries : IDTEntry*)
+    idt_pointer = IDTPointer.new
+    idt_pointer.size = sizeof(IDTEntry) * 256
+    idt_pointer.address = IDT_ADDRESS
+
+    asm "lidt %{idt_pointer}" : : "m"(idt_pointer)
+    asm "sti" ::
+  end
+
+  def self.init
+    remap_pic
+    idt_entries = Pointer(IDTEntry).new(IDT_ADDRESS)
+    set_up_idt_entries(idt_entries)
+    load_idt(idt_entries)
+  end
+end

@@ -4,25 +4,55 @@ require "./irq.cr"
 require "./timer.cr"
 # require "./pmm.cr"
 
-lib LibBootstrap
+CRYSTAL_OS_MAGIC = "123113371338".to_unsafe
+
+lib KernelShim
   @[Packed]
   struct StartInfo
     multiboot_ptr : UInt32
     end_of_kernel : UInt32
   end
+  
+  fun crystalOSMagic   : UInt8
+  fun crystalOSVersion : UInt8
+  
+  fun kernelBssBlockStart : UInt64
+  fun kernelBssBlockEnd   : UInt64
 end
 
-fun kearly(info_ptr: LibBootstrap::StartInfo*)
+fun kearly(info_ptr: KernelShim::StartInfo*)
+  VGA.init
+
   # Get the startup info
   info = info_ptr.value
+  
+  # VGA.debug_print info
 end
 
 fun kmain
-  VGA.init
+  # todo: troubelshoot Pointer compare
+  # magic = KernelShim.crystalOSMagic.value
+  # if magic != CRYSTAL_OS_MAGIC.value
+  #   while (1)
+  #   end
+  #   return
+  # end
+  
+  # Zeroes the BSS block
+  # kernel_bss_block_size = (KernelShim.kernelBssBlockEnd.to_u64 - KernelShim.kernelBssBlockStart.to_u64).to_u32
+  # ptr = Pointer(UInt8).new(KernelShim.kernelBssBlockStart)
+  # i = 0
+  # while i < kernel_bss_block_size
+  #   ptr[i] = 0_u8
+  #   i += 1
+  # end
+
+  # Init VGA (+ module demo)
   VGA.puts(
     "[CrystalOS Kernel] Hello from Crystal.\n",
     color: VGA::Colors::BLACK_ON_CYAN,
   )
+  # puts KernelShim.crystalOSVersion
   # PMM.init # Physical Memory Init
   TinyAllocI386.init
   IRQ.init

@@ -20,12 +20,19 @@ SECTIONS
 	{
 		*(.data .data.*)
 	}
+	
+	.magic ALIGN(4k) : AT(ADDR(.magic))
+	{
+	  *(.magic .magic.*)
+	}
 
 	/* Not actually *in* the image. */
 	.bss ALIGN(4k) : AT(ADDR(.bss))
 	{
+		PROVIDE(kernelBssBlockStart = .);
 		*(COMMON)
 		*(.bss .bss.*)
+		PROVIDE(kernelBssBlockEnd = .);
 	}
 
   .modules ALIGN(4k) : AT(ADDR(.modules))

prelude/crystal_core/pointer.cr
@@ -46,4 +46,16 @@ struct Pointer(T)
   def memset(dest : Pointer, value : UInt8, size : USize)
     Intrinsics.memset dest.address, value, size
   end
+  
+  def malloc_atomic(size : UInt32)
+    ptr = realloc(size)
+    if ptr.null?
+      ptr = realloc(size)
+      raise "Out of memory" if ptr.null?
+    else
+      ptr = realloc(size)
+    end
+    ptr
+  end
+
 end

prelude/crystal_core/string.cr
@@ -138,6 +138,14 @@ class String
     str_header.value = {TYPE_ID, bytesize.to_i, size.to_i}
     str.as(String)
   end
+  
+  def self.new(byte : UInt8)
+    (new(1) { |buffer|
+      buffer[0] = byte
+      buffer[1] = 0u8
+      {1, 1}
+    }).not_nil!
+  end
 
   def self.new(bytes : Slice(UInt8))
     (new(bytes.size + 1) { |buffer|