Add printf, gdb support, fix gdt
diff --git a/src/.gdbinit b/src/.gdbinit
new file mode 100644
index 0000000..24efe1e
--- /dev/null
+++ b/src/.gdbinit
@@ -0,0 +1 @@
+target remote localhost:1234
diff --git a/src/Makefile b/src/Makefile
index 7383c59..23ef8f4 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,4 +1,4 @@
-SOURCES = boot.o main.o descriptor_tables.o mem.o vga.o gdt_flush.o idt.o interrupts.o
+SOURCES = boot.o main.o descriptor_tables.o mem.o vga.o gdt_flush.o idt.o interrupts.o log.o
 CFLAGS = -nostdlib -nostdinc -fno-builtin -fno-stack-protector -ffreestanding -m32 -O2 -g
 LDFLAGS = -Tlink.ld -melf_i386
 ASMFLAGS = -felf
@@ -7,9 +7,18 @@
 	ld $(LDFLAGS) -o $@ $^
 
 clean:
-	rm -f *.o *.bin *.elf
+	rm -f *.o *.bin *.elf ../bin/*.iso
 
-qemu: install
+debug: kernel.elf
+	qemu-system-i386 -s -S -kernel kernel.elf &
+	@echo run "target remote localhost:1234" to connect to qemu
+	gdb
+	@pkill qemu-system-i38
+
+qemu: kernel.elf
+	qemu-system-i386 -monitor stdio -kernel kernel.elf
+
+qemu-iso: install
 	qemu-system-i386 -monitor stdio ../bin/bluejay.iso
 
 .s.o:
@@ -17,6 +26,7 @@
 
 install: kernel.elf
 	cp kernel.elf ../boot/
+	rm -f ../bin/bluejay.iso
 	grub-mkrescue -o ../bin/bluejay.iso ..
 
-.PHONY: install qemu clean
+.PHONY: install qemu clean qemu-iso debug
diff --git a/src/boot.s b/src/boot.s
index 5c4381c..c71ef40 100644
--- a/src/boot.s
+++ b/src/boot.s
@@ -27,11 +27,11 @@
 	dd  start
 
 	[global start]
-	[extern main]				; C code
+	[extern kmain]				; C code
 
 start:
 	push ebx					; Holds multiboot header location
 
 	cli
-	call main
+	call kmain
 	jmp $
diff --git a/src/descriptor_tables.c b/src/descriptor_tables.c
index 3b121b1..36e6f8f 100644
--- a/src/descriptor_tables.c
+++ b/src/descriptor_tables.c
@@ -52,6 +52,7 @@
 
 void init_gdt()
 {
+	vga_write("Initializing GDT...\n");
 	gdt_pointer.limit = sizeof(struct gdt_entry) * 5 - 1;
 	gdt_pointer.base = (uint)&gdt_entries;
 
@@ -61,6 +62,9 @@
 	gdt_set_gate(3, 0, ~0, 0xfa, 0xcf);   // User mode code segment
 	gdt_set_gate(4, 0, ~0, 0xf2, 0xcf);   // User mode data segment
 
+	for (volatile uint i = 0; i < 0x1000; i++)
+	{} // waste some time, for some reason this helps
+	
 	gdt_flush((uint) &gdt_pointer);
 
 	vga_write("GDT Initialized\n");
diff --git a/src/descriptor_tables.h b/src/descriptor_tables.h
index d918f4a..6f3fb89 100644
--- a/src/descriptor_tables.h
+++ b/src/descriptor_tables.h
@@ -16,7 +16,7 @@
 			uint a_dpl  : 2;
 			uint a_dt   : 1;
 			uint a_type : 4;
-		};
+		} __attribute__((packed));
 
 		uchar access;
 	};
@@ -29,7 +29,7 @@
 			uint g_d    : 1;
 			uint g_zero : 2; /* includes A */
 			uint g_len  : 4;
-		};
+		} __attribute__((packed));
 		
 		uchar granularity;
 	};
@@ -59,7 +59,7 @@
 			uchar f_p     : 1;
 			uchar f_dpl   : 2;
 			uchar f_const : 5;
-		};
+		} __attribute__((packed));
 		
 		uchar flags;
 	};
diff --git a/src/interrupts.c b/src/interrupts.c
index 615f367..c8ded7c 100644
--- a/src/interrupts.c
+++ b/src/interrupts.c
@@ -11,5 +11,7 @@
 
 void isr_handler(struct registers regs)
 {
-	vga_write("Interrupt triggered\n");
+	vga_write("Interrupt triggered! ");
+	vga_putx(regs.interrupt_number);
+	vga_write("\n");
 }
diff --git a/src/kint.h b/src/kint.h
index 5b363aa..0184443 100644
--- a/src/kint.h
+++ b/src/kint.h
@@ -6,3 +6,11 @@
 typedef unsigned long ulong;
 
 typedef unsigned long long size_t;
+
+typedef uchar bool;
+
+enum
+{
+	false = 0,
+	true,
+};
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..19959e7
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,63 @@
+#include "log.h"
+#include "kint.h"
+#include "vga.h"
+#include "stdarg.h"
+
+void kprintf(const char *format, ...)
+{
+	va_list args;
+	va_start(args, format);
+
+	while (*format)
+	{
+		if (*format == '%')
+		{
+			format++;
+			
+			switch (*format)
+			{
+			case 'd':
+			{
+				uint x = (uint) va_arg(args, uint);
+				vga_putd(x);
+				break;
+			}
+				
+			case 'x':
+			{
+				// consider hex always unsigned
+				uint x = (uint) va_arg(args, uint);
+				vga_putx(x);
+				break;
+			}
+
+			case 's':
+			{
+				char *s = va_arg(args, char *);
+				vga_write(s);
+				break;
+			}
+			}
+			format++;
+		}
+		else
+		{
+			vga_put(*format);
+			format++;
+		}
+	}
+
+	va_end(args);
+}
+
+void kassert_int(bool condition, const char *message, const char *file, const int line)
+{
+	if (!condition)
+	{
+		vga_set_color(LIGHT_RED, BLACK);
+		kprintf("ASSERTION FAILED: %s:%d\n%s\n", file, line, message);
+		
+		while (1)
+		{}
+	}
+}
diff --git a/src/log.h b/src/log.h
new file mode 100644
index 0000000..48da93e
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "kint.h"
+
+void kprintf(const char *format, ...);
+void kassert_int(bool condition, const char *message, const char *file, const int line);
+
+#define kassert(cond, msg) kassert_int((cond), (msg), __FILE__, __LINE__)
diff --git a/src/main.c b/src/main.c
index 4854924..f5b6200 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,19 +1,24 @@
 #include "vga.h"
+#include "log.h"
 #include "descriptor_tables.h"
 
-int main(void *mboot)
+int kmain(void *mboot)
 {
 	vga_clear();
 	vga_set_color(LIGHT_BLUE, BLACK);
 	vga_write("Hello!\nWelcome to Bluejay OS\n");
-
 	vga_set_color(WHITE, BLACK);
 
-	init_idt();
+	init_descriptor_tables();
 
-	//init_descriptor_tables();
+	vga_set_color(LIGHT_GREEN, BLACK);
+	vga_write("Setup complete!\n");
+	vga_set_color(WHITE, BLACK);
 
-	//asm volatile("int $0x03");
+	kassert(0, "should fail");
+
+	while (1)
+	{}
 	
 	return 0xCAFEBABE;
 }
diff --git a/src/stdarg.h b/src/stdarg.h
new file mode 100644
index 0000000..3af5dbb
--- /dev/null
+++ b/src/stdarg.h
@@ -0,0 +1,127 @@
+/* Copyright (C) 1989-2020 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+/*
+ * ISO C Standard:  7.15  Variable arguments  <stdarg.h>
+ */
+
+#ifndef _STDARG_H
+#ifndef _ANSI_STDARG_H_
+#ifndef __need___va_list
+#define _STDARG_H
+#define _ANSI_STDARG_H_
+#endif /* not __need___va_list */
+#undef __need___va_list
+
+/* Define __gnuc_va_list.  */
+
+#ifndef __GNUC_VA_LIST
+#define __GNUC_VA_LIST
+typedef __builtin_va_list __gnuc_va_list;
+#endif
+
+/* Define the standard macros for the user,
+   if this invocation was from the user program.  */
+#ifdef _STDARG_H
+
+#define va_start(v,l)	__builtin_va_start(v,l)
+#define va_end(v)	__builtin_va_end(v)
+#define va_arg(v,l)	__builtin_va_arg(v,l)
+#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L \
+    || __cplusplus + 0 >= 201103L
+#define va_copy(d,s)	__builtin_va_copy(d,s)
+#endif
+#define __va_copy(d,s)	__builtin_va_copy(d,s)
+
+/* Define va_list, if desired, from __gnuc_va_list. */
+/* We deliberately do not define va_list when called from
+   stdio.h, because ANSI C says that stdio.h is not supposed to define
+   va_list.  stdio.h needs to have access to that data type,
+   but must not use that name.  It should use the name __gnuc_va_list,
+   which is safe because it is reserved for the implementation.  */
+
+#ifdef _BSD_VA_LIST
+#undef _BSD_VA_LIST
+#endif
+
+#if defined(__svr4__) || (defined(_SCO_DS) && !defined(__VA_LIST))
+/* SVR4.2 uses _VA_LIST for an internal alias for va_list,
+   so we must avoid testing it and setting it here.
+   SVR4 uses _VA_LIST as a flag in stdarg.h, but we should
+   have no conflict with that.  */
+#ifndef _VA_LIST_
+#define _VA_LIST_
+#ifdef __i860__
+#ifndef _VA_LIST
+#define _VA_LIST va_list
+#endif
+#endif /* __i860__ */
+typedef __gnuc_va_list va_list;
+#ifdef _SCO_DS
+#define __VA_LIST
+#endif
+#endif /* _VA_LIST_ */
+#else /* not __svr4__ || _SCO_DS */
+
+/* The macro _VA_LIST_ is the same thing used by this file in Ultrix.
+   But on BSD NET2 we must not test or define or undef it.
+   (Note that the comments in NET 2's ansi.h
+   are incorrect for _VA_LIST_--see stdio.h!)  */
+#if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__) || defined(WINNT)
+/* The macro _VA_LIST_DEFINED is used in Windows NT 3.5  */
+#ifndef _VA_LIST_DEFINED
+/* The macro _VA_LIST is used in SCO Unix 3.2.  */
+#ifndef _VA_LIST
+/* The macro _VA_LIST_T_H is used in the Bull dpx2  */
+#ifndef _VA_LIST_T_H
+/* The macro __va_list__ is used by BeOS.  */
+#ifndef __va_list__
+typedef __gnuc_va_list va_list;
+#endif /* not __va_list__ */
+#endif /* not _VA_LIST_T_H */
+#endif /* not _VA_LIST */
+#endif /* not _VA_LIST_DEFINED */
+#if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__))
+#define _VA_LIST_
+#endif
+#ifndef _VA_LIST
+#define _VA_LIST
+#endif
+#ifndef _VA_LIST_DEFINED
+#define _VA_LIST_DEFINED
+#endif
+#ifndef _VA_LIST_T_H
+#define _VA_LIST_T_H
+#endif
+#ifndef __va_list__
+#define __va_list__
+#endif
+
+#endif /* not _VA_LIST_, except on certain systems */
+
+#endif /* not __svr4__ */
+
+#endif /* _STDARG_H */
+
+#endif /* not _ANSI_STDARG_H_ */
+#endif /* not _STDARG_H */
diff --git a/src/vga.c b/src/vga.c
index 1b10833..11fbc0c 100644
--- a/src/vga.c
+++ b/src/vga.c
@@ -1,5 +1,6 @@
 #include "vga.h"
 #include "mem.h"
+#include "log.h"
 
 static uint cursor_x = 0;
 static uint cursor_y = 0;
@@ -88,24 +89,44 @@
 
 void vga_putd(uint d)
 {
-	
+	char str[48];
+	memset(str, 0, 48);
+	uint i = 0;
+
+	while (d > 0 && i < 48) // should never be more than 48 digits anyway
+	{
+		str[i++] = (d % 10) + '0';
+		d /= 10;
+	}
+
+	for (uint j = i; j; j--)
+	{
+		vga_put(str[j - 1]);
+	}
 }
 
-static void vga_put_nibble(uchar n)
+static bool vga_put_nibble(uchar n, bool first)
 {
+	if (first && n == 0)
+		return true;
+	
 	if (n <= 9)
 		vga_put('0' + n);
 	else
 		vga_put('A' + n - 10);
+
+	return false;
 }
 
 void vga_putx(uint x)
 {
+	bool first = true;
+
 	for (uint mask = 0xFF000000, shift = 24; mask; mask >>= 8, shift -= 8)
 	{
 		uchar byte = (x & mask) >> shift;
 
-		vga_put_nibble((byte & 0xf0) >> 8);
-		vga_put_nibble(byte & 0x0f);
+		first = vga_put_nibble((byte & 0xf0) >> 8, first);
+		first = vga_put_nibble(byte & 0x0f, first);
 	}
 }
diff --git a/src/vga.h b/src/vga.h
index 0968ca1..9c7ba16 100644
--- a/src/vga.h
+++ b/src/vga.h
@@ -24,6 +24,7 @@
 
 void vga_set_color(enum vga_colors fg, enum vga_colors bg);
 void vga_put(char c);
+void vga_putd(uint d);
 void vga_putx(uint x);
 void vga_clear();
 void vga_write(char *c);