commit a42aab766721c5946fdde075fff28d2e1b29440b
Author: sam <multisniperism@gmail.com>
Date:   Sat Feb 24 20:24:22 2024 +1300

    first commit

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..36305ee
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+obj/*
+radix.iso
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..05722e6
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,34 @@
+KERNEL=obj/radix.bin
+ISO=radix.iso
+
+CC=gcc
+LD=ld
+CFLAGS=-ffreestanding -fno-stack-protector -fno-stack-check -O3 -Wall -Wextra -Werror -m32 -Isrc
+LDFLAGS=-T linker.ld -m elf_i386
+NASMFLAGS=-f elf32
+
+CFILES=$(shell cd src && find -L * -type f -name '*.c')
+ASMFILES=$(shell cd src && find -L * -type f -name '*.asm')
+OBJ=$(addprefix obj/,$(CFILES:.c=.c.o) $(ASMFILES:.asm=.asm.o))
+
+$(ISO): $(KERNEL) isolinux.cfg
+	cp isolinux.cfg cdroot/isolinux/
+	cp $(KERNEL) cdroot/
+	mkisofs -o $(ISO) -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table cdroot/
+
+$(KERNEL): makedir linker.ld $(OBJ)
+	$(LD) $(LDFLAGS) $(OBJ) -o $@
+
+obj/%.c.o: src/%.c
+	$(CC) $(CFLAGS) -c $< -o $@
+obj/%.asm.o: src/%.asm
+	nasm $(NASMFLAGS) $< -o $@
+
+makedir:
+	mkdir -p obj
+
+run: $(ISO)
+	qemu-system-i386 -boot d -cdrom $(ISO) -m 1G -enable-kvm -cpu host -serial stdio
+
+clean:
+	rm -rf $(OBJ) $(KERNEL)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/cdroot/isolinux/isolinux.bin b/cdroot/isolinux/isolinux.bin
new file mode 100644
index 0000000..995cd2d
Binary files /dev/null and b/cdroot/isolinux/isolinux.bin differ
diff --git a/cdroot/isolinux/isolinux.cfg b/cdroot/isolinux/isolinux.cfg
new file mode 100644
index 0000000..2a41f17
--- /dev/null
+++ b/cdroot/isolinux/isolinux.cfg
@@ -0,0 +1,4 @@
+DEFAULT radix
+LABEL radix
+  KERNEL mboot.c32
+  APPEND /radix.bin
diff --git a/cdroot/isolinux/ldlinux.c32 b/cdroot/isolinux/ldlinux.c32
new file mode 100644
index 0000000..e43c6cd
Binary files /dev/null and b/cdroot/isolinux/ldlinux.c32 differ
diff --git a/cdroot/isolinux/libcom32.c32 b/cdroot/isolinux/libcom32.c32
new file mode 100644
index 0000000..73d3f8d
Binary files /dev/null and b/cdroot/isolinux/libcom32.c32 differ
diff --git a/cdroot/isolinux/mboot.c32 b/cdroot/isolinux/mboot.c32
new file mode 100644
index 0000000..22ab5cc
Binary files /dev/null and b/cdroot/isolinux/mboot.c32 differ
diff --git a/cdroot/radix.bin b/cdroot/radix.bin
new file mode 100755
index 0000000..92db9d1
Binary files /dev/null and b/cdroot/radix.bin differ
diff --git a/isolinux.cfg b/isolinux.cfg
new file mode 100644
index 0000000..2a41f17
--- /dev/null
+++ b/isolinux.cfg
@@ -0,0 +1,4 @@
+DEFAULT radix
+LABEL radix
+  KERNEL mboot.c32
+  APPEND /radix.bin
diff --git a/linker.ld b/linker.ld
new file mode 100644
index 0000000..0e93f9b
--- /dev/null
+++ b/linker.ld
@@ -0,0 +1,28 @@
+ENTRY(_start)
+
+SECTIONS
+{
+	. = 1M;
+
+	.text BLOCK(4K) : ALIGN(4K)
+	{
+		*(.multiboot)
+		*(.text)
+	}
+
+	.rodata BLOCK(4K) : ALIGN(4K)
+	{
+		*(.rodata)
+	}
+
+	.data BLOCK(4K) : ALIGN(4K)
+	{
+		*(.data)
+	}
+
+	.bss BLOCK(4K) : ALIGN(4K)
+	{
+		*(COMMON)
+		*(.bss)
+	}
+}
diff --git a/src/boot.asm b/src/boot.asm
new file mode 100644
index 0000000..bc45745
--- /dev/null
+++ b/src/boot.asm
@@ -0,0 +1,36 @@
+extern kernel_main
+
+MBALIGN		equ 1 << 0
+MEMINFO		equ 1 << 1
+VIDINFO		equ 1 << 2
+MBFLAGS		equ MBALIGN | MEMINFO | VIDINFO
+MAGIC		equ 0x1BADB002
+CHECKSUM 	equ -(MAGIC + MBFLAGS)
+
+section .multiboot
+align 4
+	dd MAGIC
+	dd MBFLAGS
+	dd CHECKSUM
+	dd 0, 0, 0, 0, 0
+	dd 0
+	dd 320, 200, 8
+
+section .bss
+align 16
+stack_bottom:
+resb 16384
+stack_top:
+
+section .text
+global _start:function (_start.end - _start)
+_start:
+	mov esp, stack_top
+	push ebx
+	push eax
+	
+	call kernel_main
+	cli
+.hang:
+	jmp .hang
+.end:
diff --git a/src/ctype.c b/src/ctype.c
new file mode 100644
index 0000000..6a3efa7
--- /dev/null
+++ b/src/ctype.c
@@ -0,0 +1,5 @@
+#include <ctype.h>
+
+int isdigit(char c) {
+  return c >= '0' && c <= '9';
+}
diff --git a/src/ctype.h b/src/ctype.h
new file mode 100644
index 0000000..c27dc9e
--- /dev/null
+++ b/src/ctype.h
@@ -0,0 +1,6 @@
+#ifndef __CTYPE_H__
+#define __CTYPE_H__
+
+int isdigit(char arg);
+
+#endif
diff --git a/src/hcf.asm b/src/hcf.asm
new file mode 100644
index 0000000..23c911d
--- /dev/null
+++ b/src/hcf.asm
@@ -0,0 +1,7 @@
+global hcf
+
+hcf:
+	cli
+.loop:
+	hlt
+	jmp .loop
diff --git a/src/hcf.h b/src/hcf.h
new file mode 100644
index 0000000..9ca36eb
--- /dev/null
+++ b/src/hcf.h
@@ -0,0 +1,6 @@
+#ifndef __HCF_H__
+#define __HCF_H__
+
+void hcf();
+
+#endif
diff --git a/src/kernel.c b/src/kernel.c
new file mode 100644
index 0000000..1904027
--- /dev/null
+++ b/src/kernel.c
@@ -0,0 +1,241 @@
+#include <multiboot.h>
+#include <stdio.h>
+#include <hcf.h>
+#include <vga.h>
+
+#include <string.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+void putpixel(unsigned char* addr, int pos_x, int pos_y, unsigned char VGA_COLOR)
+{
+    unsigned char* location = addr + 320 * pos_y + pos_x;
+    *location = VGA_COLOR;
+}
+
+static inline void outb(uint16_t port, uint8_t val)
+{
+    __asm__ volatile ( "outb %b0, %w1" : : "a"(val), "Nd"(port) : "memory");
+    /* There's an outb %al, $imm8 encoding, for compile-time constant port numbers that fit in 8b. (N constraint).
+     * Wider immediate constants would be truncated at assemble-time (e.g. "i" constraint).
+     * The  outb  %al, %dx  encoding is the only option for all other cases.
+     * %1 expands to %dx because  port  is a uint16_t.  %w1 could be used if we had the port number a wider C type */
+}
+
+static inline uint8_t inb(uint16_t port)
+{
+    uint8_t ret;
+    __asm__ volatile ( "inb %w1, %b0"
+                   : "=a"(ret)
+                   : "Nd"(port)
+                   : "memory");
+    return ret;
+}
+
+#define PORT 0x3f8          // COM1
+ 
+static int init_serial() {
+   outb(PORT + 1, 0x00);    // Disable all interrupts
+   outb(PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
+   outb(PORT + 0, 0x03);    // Set divisor to 3 (lo byte) 38400 baud
+   outb(PORT + 1, 0x00);    //                  (hi byte)
+   outb(PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
+   outb(PORT + 2, 0xC7);    // Enable FIFO, clear them, with 14-byte threshold
+   outb(PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
+   outb(PORT + 4, 0x1E);    // Set in loopback mode, test the serial chip
+   outb(PORT + 0, 0xAE);    // Test serial chip (send byte 0xAE and check if serial returns same byte)
+ 
+   // Check if serial is faulty (i.e: not same byte as sent)
+   if(inb(PORT + 0) != 0xAE) {
+      return 1;
+   }
+ 
+   // If serial is not faulty set it in normal operation mode
+   // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
+   outb(PORT + 4, 0x0F);
+   return 0;
+}
+
+int is_transmit_empty() {
+   return inb(PORT + 5) & 0x20;
+}
+ 
+void write_serial(char a) {
+   while (is_transmit_empty() == 0);
+ 
+   outb(PORT,a);
+}
+
+void serial_puts(const char* s) {
+	do {
+		write_serial(*s);
+	} while(*++s != '\0');
+}
+
+void sprintf(const char* fmt, ...) {
+	va_list args;
+	va_start(args, fmt);	
+
+	for(int i = 0; fmt[i] != '\0'; i++)
+	{
+		switch(fmt[i])
+		{
+		case '%':
+			i++;
+
+			char buf[512];
+
+			size_t width = 0;
+			char padding_char = fmt[i];
+			if(isdigit(fmt[i]) || fmt[i] == ' ') {
+				i++;
+				int pos = 0;
+				while(isdigit(fmt[i])) {
+					buf[pos++] = fmt[i++];
+				}
+				buf[pos] = '\0';
+				width = atoi(buf);
+			}
+
+			const char* out = 0;
+
+			if(fmt[i] == 's')
+				out = va_arg(args, const char*);
+			if(fmt[i] == 'd')
+				out = itoa(va_arg(args, int), buf, 10);
+			if(fmt[i] == 'u')
+				out = ultoa(va_arg(args, uint32_t), buf, 10);
+			if(fmt[i] == 'x')
+				out = ultoa(va_arg(args, uint32_t), buf, 16);
+			if(fmt[i] == 'c')
+				write_serial(va_arg(args, int));
+
+			size_t len = strlen(out);
+			if(width > len) {
+				char padding[256];
+				size_t j = 0;
+				for(; j < width - len; j++)
+					padding[j] = padding_char;
+				padding[j] = '\0';
+				serial_puts(padding);
+			}
+
+			serial_puts(out);
+			break;
+		default:
+			write_serial(fmt[i]);
+			break;
+		}
+	}
+
+	va_end(args);
+}
+
+#define CHECK_FLAG(flags,bit)   ((flags) & (1 << (bit)))
+
+void kernel_main(uint32_t magic, multiboot_info_t* mbi) {
+	init_vga();
+	init_serial();
+
+	if(magic != MULTIBOOT_BOOTLOADER_MAGIC) {
+		printf("Invalid bootloader magic: %x", magic);
+		hcf();
+	}
+
+	printf("flags: 0x%x\n", mbi->flags);
+
+	uint32_t mem_total = mbi->mem_upper - mbi->mem_lower;
+	printf("mem_lower: %uKB, mem_upper: %uKB, mem_total: %uKB\n", mbi->mem_lower, mbi->mem_upper, mem_total);
+
+	//sprintf("checking for flag");
+//if (CHECK_FLAG (mbi->flags, 12))
+    //{
+	//sprintf("flag present");
+      multiboot_uint32_t color;
+      unsigned i;
+      void *fb = (void *) (unsigned long) mbi->framebuffer_addr;
+
+sprintf("fb_addr: %x, fb_width: %u, fb_height: %u", fb, mbi->framebuffer_width, mbi->framebuffer_height);
+
+      switch (mbi->framebuffer_type)
+        {
+        case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
+          {
+		  //sprintf("indexed");
+            unsigned best_distance, distance;
+            struct multiboot_color *palette;
+            
+            palette = (struct multiboot_color *) mbi->framebuffer_palette_addr;
+
+            color = 0;
+            best_distance = 4*256*256;
+            
+            for (i = 0; i < mbi->framebuffer_palette_num_colors; i++)
+              {
+                distance = (0xff - palette[i].blue) * (0xff - palette[i].blue)
+                  + palette[i].red * palette[i].red
+                  + palette[i].green * palette[i].green;
+                if (distance < best_distance)
+                  {
+                    color = i;
+                    best_distance = distance;
+                  }
+              }
+          }
+          break;
+
+        case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
+          color = ((1 << mbi->framebuffer_blue_mask_size) - 1) 
+            << mbi->framebuffer_blue_field_position;
+          break;
+
+        case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT:
+          color = '\\' | 0x0100;
+          break;
+
+        default:
+          color = 0xffffffff;
+          break;
+        }
+      for (i = 0; i < mbi->framebuffer_width
+             && i < mbi->framebuffer_height; i++)
+        {
+          switch (mbi->framebuffer_bpp)
+            {
+            case 8:
+              {
+                multiboot_uint8_t *pixel = fb + mbi->framebuffer_pitch * i + i;
+                *pixel = color;
+              }
+              break;
+            case 15:
+            case 16:
+              {
+                multiboot_uint16_t *pixel
+                  = fb + mbi->framebuffer_pitch * i + 2 * i;
+                *pixel = color;
+              }
+              break;
+            case 24:
+              {
+                multiboot_uint32_t *pixel
+                  = fb + mbi->framebuffer_pitch * i + 3 * i;
+                *pixel = (color & 0xffffff) | (*pixel & 0xff000000);
+              }
+              break;
+
+            case 32:
+              {
+                multiboot_uint32_t *pixel
+                  = fb + mbi->framebuffer_pitch * i + 4 * i;
+                *pixel = color;
+              }
+              break;
+            }
+        }
+    //}
+
+	hcf();
+}
diff --git a/src/multiboot.h b/src/multiboot.h
new file mode 100644
index 0000000..1ba51c4
--- /dev/null
+++ b/src/multiboot.h
@@ -0,0 +1,274 @@
+/*  multiboot.h - Multiboot header file.  */
+/*  Copyright (C) 1999,2003,2007,2008,2009,2010  Free Software Foundation, Inc.
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to
+ *  deal in the Software without restriction, including without limitation the
+ *  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ *  sell copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in
+ *  all copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY
+ *  DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+ *  IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef MULTIBOOT_HEADER
+#define MULTIBOOT_HEADER 1
+
+/* How many bytes from the start of the file we search for the header.  */
+#define MULTIBOOT_SEARCH			8192
+#define MULTIBOOT_HEADER_ALIGN			4
+
+/* The magic field should contain this.  */
+#define MULTIBOOT_HEADER_MAGIC			0x1BADB002
+
+/* This should be in %eax.  */
+#define MULTIBOOT_BOOTLOADER_MAGIC		0x2BADB002
+
+/* Alignment of multiboot modules.  */
+#define MULTIBOOT_MOD_ALIGN			0x00001000
+
+/* Alignment of the multiboot info structure.  */
+#define MULTIBOOT_INFO_ALIGN			0x00000004
+
+/* Flags set in the 'flags' member of the multiboot header.  */
+
+/* Align all boot modules on i386 page (4KB) boundaries.  */
+#define MULTIBOOT_PAGE_ALIGN			0x00000001
+
+/* Must pass memory information to OS.  */
+#define MULTIBOOT_MEMORY_INFO			0x00000002
+
+/* Must pass video information to OS.  */
+#define MULTIBOOT_VIDEO_MODE			0x00000004
+
+/* This flag indicates the use of the address fields in the header.  */
+#define MULTIBOOT_AOUT_KLUDGE			0x00010000
+
+/* Flags to be set in the 'flags' member of the multiboot info structure.  */
+
+/* is there basic lower/upper memory information? */
+#define MULTIBOOT_INFO_MEMORY			0x00000001
+/* is there a boot device set? */
+#define MULTIBOOT_INFO_BOOTDEV			0x00000002
+/* is the command-line defined? */
+#define MULTIBOOT_INFO_CMDLINE			0x00000004
+/* are there modules to do something with? */
+#define MULTIBOOT_INFO_MODS			0x00000008
+
+/* These next two are mutually exclusive */
+
+/* is there a symbol table loaded? */
+#define MULTIBOOT_INFO_AOUT_SYMS		0x00000010
+/* is there an ELF section header table? */
+#define MULTIBOOT_INFO_ELF_SHDR			0X00000020
+
+/* is there a full memory map? */
+#define MULTIBOOT_INFO_MEM_MAP			0x00000040
+
+/* Is there drive info?  */
+#define MULTIBOOT_INFO_DRIVE_INFO		0x00000080
+
+/* Is there a config table?  */
+#define MULTIBOOT_INFO_CONFIG_TABLE		0x00000100
+
+/* Is there a boot loader name?  */
+#define MULTIBOOT_INFO_BOOT_LOADER_NAME		0x00000200
+
+/* Is there a APM table?  */
+#define MULTIBOOT_INFO_APM_TABLE		0x00000400
+
+/* Is there video information?  */
+#define MULTIBOOT_INFO_VBE_INFO		        0x00000800
+#define MULTIBOOT_INFO_FRAMEBUFFER_INFO	        0x00001000
+
+#ifndef ASM_FILE
+
+typedef unsigned char		multiboot_uint8_t;
+typedef unsigned short		multiboot_uint16_t;
+typedef unsigned int		multiboot_uint32_t;
+typedef unsigned long long	multiboot_uint64_t;
+
+struct multiboot_header
+{
+  /* Must be MULTIBOOT_MAGIC - see above.  */
+  multiboot_uint32_t magic;
+
+  /* Feature flags.  */
+  multiboot_uint32_t flags;
+
+  /* The above fields plus this one must equal 0 mod 2^32. */
+  multiboot_uint32_t checksum;
+
+  /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set.  */
+  multiboot_uint32_t header_addr;
+  multiboot_uint32_t load_addr;
+  multiboot_uint32_t load_end_addr;
+  multiboot_uint32_t bss_end_addr;
+  multiboot_uint32_t entry_addr;
+
+  /* These are only valid if MULTIBOOT_VIDEO_MODE is set.  */
+  multiboot_uint32_t mode_type;
+  multiboot_uint32_t width;
+  multiboot_uint32_t height;
+  multiboot_uint32_t depth;
+};
+
+/* The symbol table for a.out.  */
+struct multiboot_aout_symbol_table
+{
+  multiboot_uint32_t tabsize;
+  multiboot_uint32_t strsize;
+  multiboot_uint32_t addr;
+  multiboot_uint32_t reserved;
+};
+typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
+
+/* The section header table for ELF.  */
+struct multiboot_elf_section_header_table
+{
+  multiboot_uint32_t num;
+  multiboot_uint32_t size;
+  multiboot_uint32_t addr;
+  multiboot_uint32_t shndx;
+};
+typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
+
+struct multiboot_info
+{
+  /* Multiboot info version number */
+  multiboot_uint32_t flags;
+
+  /* Available memory from BIOS */
+  multiboot_uint32_t mem_lower;
+  multiboot_uint32_t mem_upper;
+
+  /* "root" partition */
+  multiboot_uint32_t boot_device;
+
+  /* Kernel command line */
+  multiboot_uint32_t cmdline;
+
+  /* Boot-Module list */
+  multiboot_uint32_t mods_count;
+  multiboot_uint32_t mods_addr;
+
+  union
+  {
+    multiboot_aout_symbol_table_t aout_sym;
+    multiboot_elf_section_header_table_t elf_sec;
+  } u;
+
+  /* Memory Mapping buffer */
+  multiboot_uint32_t mmap_length;
+  multiboot_uint32_t mmap_addr;
+
+  /* Drive Info buffer */
+  multiboot_uint32_t drives_length;
+  multiboot_uint32_t drives_addr;
+
+  /* ROM configuration table */
+  multiboot_uint32_t config_table;
+
+  /* Boot Loader Name */
+  multiboot_uint32_t boot_loader_name;
+
+  /* APM table */
+  multiboot_uint32_t apm_table;
+
+  /* Video */
+  multiboot_uint32_t vbe_control_info;
+  multiboot_uint32_t vbe_mode_info;
+  multiboot_uint16_t vbe_mode;
+  multiboot_uint16_t vbe_interface_seg;
+  multiboot_uint16_t vbe_interface_off;
+  multiboot_uint16_t vbe_interface_len;
+
+  multiboot_uint64_t framebuffer_addr;
+  multiboot_uint32_t framebuffer_pitch;
+  multiboot_uint32_t framebuffer_width;
+  multiboot_uint32_t framebuffer_height;
+  multiboot_uint8_t framebuffer_bpp;
+#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
+#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB     1
+#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT	2
+  multiboot_uint8_t framebuffer_type;
+  union
+  {
+    struct
+    {
+      multiboot_uint32_t framebuffer_palette_addr;
+      multiboot_uint16_t framebuffer_palette_num_colors;
+    };
+    struct
+    {
+      multiboot_uint8_t framebuffer_red_field_position;
+      multiboot_uint8_t framebuffer_red_mask_size;
+      multiboot_uint8_t framebuffer_green_field_position;
+      multiboot_uint8_t framebuffer_green_mask_size;
+      multiboot_uint8_t framebuffer_blue_field_position;
+      multiboot_uint8_t framebuffer_blue_mask_size;
+    };
+  };
+};
+typedef struct multiboot_info multiboot_info_t;
+
+struct multiboot_color
+{
+  multiboot_uint8_t red;
+  multiboot_uint8_t green;
+  multiboot_uint8_t blue;
+};
+
+struct multiboot_mmap_entry
+{
+  multiboot_uint32_t size;
+  multiboot_uint64_t addr;
+  multiboot_uint64_t len;
+#define MULTIBOOT_MEMORY_AVAILABLE		1
+#define MULTIBOOT_MEMORY_RESERVED		2
+#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE       3
+#define MULTIBOOT_MEMORY_NVS                    4
+#define MULTIBOOT_MEMORY_BADRAM                 5
+  multiboot_uint32_t type;
+} __attribute__((packed));
+typedef struct multiboot_mmap_entry multiboot_memory_map_t;
+
+struct multiboot_mod_list
+{
+  /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
+  multiboot_uint32_t mod_start;
+  multiboot_uint32_t mod_end;
+
+  /* Module command line */
+  multiboot_uint32_t cmdline;
+
+  /* padding to take it to 16 bytes (must be zero) */
+  multiboot_uint32_t pad;
+};
+typedef struct multiboot_mod_list multiboot_module_t;
+
+/* APM BIOS info.  */
+struct multiboot_apm_info
+{
+  multiboot_uint16_t version;
+  multiboot_uint16_t cseg;
+  multiboot_uint32_t offset;
+  multiboot_uint16_t cseg_16;
+  multiboot_uint16_t dseg;
+  multiboot_uint16_t flags;
+  multiboot_uint16_t cseg_len;
+  multiboot_uint16_t cseg_16_len;
+  multiboot_uint16_t dseg_len;
+};
+
+#endif /* ! ASM_FILE */
+
+#endif /* ! MULTIBOOT_HEADER */
diff --git a/src/stdio.c b/src/stdio.c
new file mode 100644
index 0000000..f1c9678
--- /dev/null
+++ b/src/stdio.c
@@ -0,0 +1,76 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <vga.h>
+
+void putc(char ch) {
+	vga_putc(ch);
+}
+
+void puts(const char* str) {
+	do {
+		putc(*str);
+	} while(*++str != '\0');
+}
+
+void printf(const char* fmt, ...) {
+	va_list args;
+	va_start(args, fmt);	
+
+	for(int i = 0; fmt[i] != '\0'; i++)
+	{
+		switch(fmt[i])
+		{
+		case '%':
+			i++;
+
+			char buf[512];
+
+			size_t width = 0;
+			char padding_char = fmt[i];
+			if(isdigit(fmt[i]) || fmt[i] == ' ') {
+				i++;
+				int pos = 0;
+				while(isdigit(fmt[i])) {
+					buf[pos++] = fmt[i++];
+				}
+				buf[pos] = '\0';
+				width = atoi(buf);
+			}
+
+			const char* out = 0;
+
+			if(fmt[i] == 's')
+				out = va_arg(args, const char*);
+			if(fmt[i] == 'd')
+				out = itoa(va_arg(args, int), buf, 10);
+			if(fmt[i] == 'u')
+				out = ultoa(va_arg(args, uint32_t), buf, 10);
+			if(fmt[i] == 'x')
+				out = ultoa(va_arg(args, uint32_t), buf, 16);
+			if(fmt[i] == 'c')
+				putc(va_arg(args, int));
+
+			size_t len = strlen(out);
+			if(width > len) {
+				char padding[256];
+				size_t j = 0;
+				for(; j < width - len; j++)
+					padding[j] = padding_char;
+				padding[j] = '\0';
+				puts(padding);
+			}
+
+			puts(out);
+			break;
+		default:
+			putc(fmt[i]);
+			break;
+		}
+	}
+
+	va_end(args);
+}
diff --git a/src/stdio.h b/src/stdio.h
new file mode 100644
index 0000000..35a69fe
--- /dev/null
+++ b/src/stdio.h
@@ -0,0 +1,9 @@
+#ifndef __STDIO_H__
+#define __STDIO_H__
+#include <stdint.h>
+
+void putc(char ch);
+void puts(const char* str);
+void printf(const char* fmt, ...);
+
+#endif
diff --git a/src/stdlib.c b/src/stdlib.c
new file mode 100644
index 0000000..4d12dcf
--- /dev/null
+++ b/src/stdlib.c
@@ -0,0 +1,77 @@
+#include <stdlib.h>
+#include <ctype.h>
+
+const char* itoa(int value, char* str, int base)
+{
+	char* rc;
+	char* ptr;
+	char* low;
+	
+	if (base < 2 || base > 36)
+	{
+		*str = '\0';
+		return str;
+	}
+	rc = ptr = str;	
+	if (value < 0 && base == 10)
+	{
+		*ptr++ = '-';
+	}
+
+	low = ptr;
+	do
+	{
+		*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + value % base];
+		value /= base;
+	} while (value);
+
+	*ptr-- = '\0';
+	while (low < ptr)
+	{
+		char tmp = *low;
+		*low++ = *ptr;
+		*ptr-- = tmp;
+	}
+	return rc;
+}
+
+const char* ultoa(uint32_t value, char* str, int base)
+{
+	char* rc;
+	char* ptr;
+	char* low;
+	
+	if (base < 2 || base > 36)
+	{
+		*str = '\0';
+		return str;
+	}
+	rc = ptr = str;	
+
+	low = ptr;
+	do
+	{
+		*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + value % base];
+		value /= base;
+	} while (value);
+
+	*ptr-- = '\0';
+	while (low < ptr)
+	{
+		char tmp = *low;
+		*low++ = *ptr;
+		*ptr-- = tmp;
+	}
+	return rc;
+}
+
+int atoi(const char* str) {
+	int value = 0;
+  	while(isdigit(*str)) {
+		value *= 10;
+		value += (*str)-'0';
+		str++;
+  	}
+
+  	return value;
+}
diff --git a/src/stdlib.h b/src/stdlib.h
new file mode 100644
index 0000000..dc98a47
--- /dev/null
+++ b/src/stdlib.h
@@ -0,0 +1,9 @@
+#ifndef __STDLIB_H__
+#define __STDLIB_H__
+#include <stdint.h>
+
+const char* itoa(int value, char* str, int base);
+const char* ultoa(uint32_t value, char* str, int base);
+int atoi(const char* str);
+
+#endif
diff --git a/src/string.c b/src/string.c
new file mode 100644
index 0000000..8ac0dbe
--- /dev/null
+++ b/src/string.c
@@ -0,0 +1,8 @@
+#include <string.h>
+
+size_t strlen(const char* str) {
+	size_t len = 0;
+	while (str[len])
+		len++;
+	return len;
+}
diff --git a/src/string.h b/src/string.h
new file mode 100644
index 0000000..7a3003c
--- /dev/null
+++ b/src/string.h
@@ -0,0 +1,7 @@
+#ifndef __STRING_H__
+#define __STRING_H__
+#include <stddef.h>
+
+size_t strlen(const char* str);
+
+#endif
diff --git a/src/vga.c b/src/vga.c
new file mode 100644
index 0000000..ce72f9d
--- /dev/null
+++ b/src/vga.c
@@ -0,0 +1,39 @@
+#include <vga.h>
+#include <stdio.h>
+
+struct vga_terminal vga_term = { 0 };
+uint16_t* VGA = (uint16_t*)0xb8000;
+
+void vga_putc(char ch) {
+	if(ch == '\n') {
+		vga_term.x = 0;
+		vga_term.y++;
+	} else {
+		int index = vga_term.y * VGA_WIDTH + vga_term.x;
+
+		VGA[index] = ch | (vga_term.fg | vga_term.bg << 4) << 8;
+
+		vga_term.x++;
+		if(vga_term.x > VGA_WIDTH) {
+			vga_term.x = 0;
+			vga_term.y++;
+		}
+	}
+}
+
+void vga_clear() {
+	vga_term.x = 0;
+	vga_term.y = 0;
+	for(int i = 0; i < VGA_WIDTH * VGA_HEIGHT; i++)
+		putc(' ');
+}
+
+void init_vga(void) {
+	vga_term.fg = 7;
+	vga_term.bg = 0;
+
+	vga_clear();
+
+	vga_term.x = 0;
+	vga_term.y = 0;
+}
diff --git a/src/vga.h b/src/vga.h
new file mode 100644
index 0000000..807033b
--- /dev/null
+++ b/src/vga.h
@@ -0,0 +1,20 @@
+#ifndef __VGA_H__
+#define __VGA_H__
+#include <stdint.h>
+
+#define VGA_WIDTH 80
+#define VGA_HEIGHT 25
+
+struct vga_terminal {
+	uint8_t bg;
+	uint8_t fg;
+	uint8_t x;
+	uint8_t y;
+};
+
+extern struct vga_terminal vga_term;
+
+void init_vga(void);
+void vga_putc(char ch);
+
+#endif