diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}
diff --git a/src/hlib/service/service.c b/src/hlib/service/service.c
new file mode 100644
index 0000000..1669154
--- /dev/null
+++ b/src/hlib/service/service.c
@@ -0,0 +1,39 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
+                 uintptr_t data2) {
+    return syscall(SYS_REQUEST, service, function, data1, data2);
+}
+
+uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
+}
+
+uint32_t getService(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+}
+
+uint32_t getFunction(uint32_t module, char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
+}
+
+uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
+
+uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
+    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
+}
+
+void *getPhysicalAddress(void *source) {
+    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
+               (U32(source) & 0xFFF));
+}
+
+uint32_t fork(void (f)(), void *a, void *b, void *c) {
+    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
+}
+

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}
diff --git a/src/hlib/service/service.c b/src/hlib/service/service.c
new file mode 100644
index 0000000..1669154
--- /dev/null
+++ b/src/hlib/service/service.c
@@ -0,0 +1,39 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
+                 uintptr_t data2) {
+    return syscall(SYS_REQUEST, service, function, data1, data2);
+}
+
+uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
+}
+
+uint32_t getService(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+}
+
+uint32_t getFunction(uint32_t module, char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
+}
+
+uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
+
+uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
+    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
+}
+
+void *getPhysicalAddress(void *source) {
+    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
+               (U32(source) & 0xFFF));
+}
+
+uint32_t fork(void (f)(), void *a, void *b, void *c) {
+    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
+}
+
diff --git a/src/hlib/stdio.c b/src/hlib/stdio.c
new file mode 100644
index 0000000..e717154
--- /dev/null
+++ b/src/hlib/stdio.c
@@ -0,0 +1,207 @@
+#include <hlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+char HEX_CHARS[] = "0123456789ABCDEF";
+
+void putHex(char **write, uintptr_t x) {
+    if (x == 0) {
+        **write = HEX_CHARS[x];
+        (*write)++;
+        **write = HEX_CHARS[x];
+        (*write)++;
+        return;
+    }
+    bool alreadyWriting = false;
+    for (int position = 3; position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            **write = HEX_CHARS[byte >> 4];
+            (*write)++;
+            **write = HEX_CHARS[byte & 0x0F];
+            (*write)++;
+        }
+    }
+}
+
+uint8_t hexLength(uintptr_t x) {
+    bool alreadyWriting = false;
+    uint8_t size = 0;
+    for (int position = sizeof(uintptr_t); position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            size += 2;
+        }
+    }
+    return MAX(size, 2);
+}
+
+uint32_t power(uintptr_t x, uintptr_t y) {
+    uintptr_t result = 1;
+    for (uintptr_t i = 0; i < y; i++) {
+        result *= x;
+    }
+    return result;
+}
+
+uint32_t intLength(intptr_t x) {
+    if (x == 0) {
+        return 1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        if (x / power(10, i) > 0) {
+            return i + 1;
+        }
+    }
+    return 1;
+}
+
+void addChar(char **write, char c) {
+    **write = c;
+    (*write)++;
+}
+
+void putInt(char **write, intptr_t x) {
+    if (x == 0) {
+        addChar(write, '0');
+        return;
+    }
+    if (x < 0) {
+        addChar(write, '-');
+        x *= -1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        uintptr_t n = x / power(10, i);
+        if (n) {
+            addChar(write, HEX_CHARS[n % 10]);
+        }
+    }
+}
+
+void putPadding(char **write, uintptr_t x) {
+    x = MIN(x, 10); // max 10 wide padding
+    for (intptr_t i = 0; i < x; i++) {
+        addChar(write, ' ');
+    }
+}
+
+uint32_t getInsertLength(char insertType, intptr_t x) {
+    switch (insertType) {
+    case 's':
+        return strlen((char *)x);
+    case 'x':
+        return hexLength(x);
+    case 'c':
+        return 1;
+    case 'i':
+        return intLength(x) + (x < 0);
+    case 'p':
+        return x;
+    }
+    return 0;
+}
+
+void stringInsert(char **write, uintptr_t x) {
+    char *string = (char *)x;
+    uint32_t length = strlen(string);
+    for (uint32_t position = 0; position < length; position++) {
+        **write = string[position];
+        (*write)++;
+    }
+}
+
+void handleInsert(char **write, char insertType, uintptr_t x) {
+    switch (insertType) {
+    case 's':
+        stringInsert(write, x);
+        return;
+    case 'x':
+        putHex(write, x);
+        return;
+    case 'c':
+        **write = x;
+        (*write)++;
+        return;
+    case 'i':
+        putInt(write, x);
+        return;
+    case 'p':
+        putPadding(write, x);
+        return;
+    }
+}
+uint32_t ioManager, logFunction;
+
+uint32_t printfSize(const char *format, va_list *valist) {
+    uint32_t size = 0;
+    for (; format[size] != 0; size++) {
+        if (format[size] == '%') {
+            char insertType = format[++size];
+            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
+            continue;
+        }
+    }
+    return size;
+}
+
+void _sprintf(char *data, const char *format, va_list *valist) {
+    char *write = data;
+    for (int i = 0; format[i] != 0; i++) {
+        if (format[i] == '%') {
+            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
+            continue;
+        }
+        *write = format[i];
+        write++;
+    }
+}
+
+void sprintf(char *data, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+}
+
+char *_asprintf(AllocationData allocationData, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    uint32_t size = printfSize(format, &valist);
+    char *data = malloc(size);
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    return data;
+}
+
+void _printf(AllocationData allocationData, const char *format, ...) {
+    // I have absolutely no idea why this line fixes an issue where the first
+    // printf operation consistently doesn't correctly insert its string
+    free(malloc(1));
+    va_list valist;
+    va_start(valist, format);
+    char *data = malloc(printfSize(format, &valist));
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    uintptr_t id = insertString(data);
+    request(ioManager, logFunction, id, 0);
+    discardString(id);
+    free(data);
+}
+
+void gets(char *buffer) {
+    static uint32_t function = 0;
+    if (!function) {
+        function = getFunction(ioManager, "gets");
+    }
+    uint32_t stringId = request(ioManager, function, 0, 0);
+    readString(stringId, buffer);
+}

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}
diff --git a/src/hlib/service/service.c b/src/hlib/service/service.c
new file mode 100644
index 0000000..1669154
--- /dev/null
+++ b/src/hlib/service/service.c
@@ -0,0 +1,39 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
+                 uintptr_t data2) {
+    return syscall(SYS_REQUEST, service, function, data1, data2);
+}
+
+uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
+}
+
+uint32_t getService(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+}
+
+uint32_t getFunction(uint32_t module, char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
+}
+
+uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
+
+uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
+    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
+}
+
+void *getPhysicalAddress(void *source) {
+    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
+               (U32(source) & 0xFFF));
+}
+
+uint32_t fork(void (f)(), void *a, void *b, void *c) {
+    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
+}
+
diff --git a/src/hlib/stdio.c b/src/hlib/stdio.c
new file mode 100644
index 0000000..e717154
--- /dev/null
+++ b/src/hlib/stdio.c
@@ -0,0 +1,207 @@
+#include <hlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+char HEX_CHARS[] = "0123456789ABCDEF";
+
+void putHex(char **write, uintptr_t x) {
+    if (x == 0) {
+        **write = HEX_CHARS[x];
+        (*write)++;
+        **write = HEX_CHARS[x];
+        (*write)++;
+        return;
+    }
+    bool alreadyWriting = false;
+    for (int position = 3; position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            **write = HEX_CHARS[byte >> 4];
+            (*write)++;
+            **write = HEX_CHARS[byte & 0x0F];
+            (*write)++;
+        }
+    }
+}
+
+uint8_t hexLength(uintptr_t x) {
+    bool alreadyWriting = false;
+    uint8_t size = 0;
+    for (int position = sizeof(uintptr_t); position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            size += 2;
+        }
+    }
+    return MAX(size, 2);
+}
+
+uint32_t power(uintptr_t x, uintptr_t y) {
+    uintptr_t result = 1;
+    for (uintptr_t i = 0; i < y; i++) {
+        result *= x;
+    }
+    return result;
+}
+
+uint32_t intLength(intptr_t x) {
+    if (x == 0) {
+        return 1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        if (x / power(10, i) > 0) {
+            return i + 1;
+        }
+    }
+    return 1;
+}
+
+void addChar(char **write, char c) {
+    **write = c;
+    (*write)++;
+}
+
+void putInt(char **write, intptr_t x) {
+    if (x == 0) {
+        addChar(write, '0');
+        return;
+    }
+    if (x < 0) {
+        addChar(write, '-');
+        x *= -1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        uintptr_t n = x / power(10, i);
+        if (n) {
+            addChar(write, HEX_CHARS[n % 10]);
+        }
+    }
+}
+
+void putPadding(char **write, uintptr_t x) {
+    x = MIN(x, 10); // max 10 wide padding
+    for (intptr_t i = 0; i < x; i++) {
+        addChar(write, ' ');
+    }
+}
+
+uint32_t getInsertLength(char insertType, intptr_t x) {
+    switch (insertType) {
+    case 's':
+        return strlen((char *)x);
+    case 'x':
+        return hexLength(x);
+    case 'c':
+        return 1;
+    case 'i':
+        return intLength(x) + (x < 0);
+    case 'p':
+        return x;
+    }
+    return 0;
+}
+
+void stringInsert(char **write, uintptr_t x) {
+    char *string = (char *)x;
+    uint32_t length = strlen(string);
+    for (uint32_t position = 0; position < length; position++) {
+        **write = string[position];
+        (*write)++;
+    }
+}
+
+void handleInsert(char **write, char insertType, uintptr_t x) {
+    switch (insertType) {
+    case 's':
+        stringInsert(write, x);
+        return;
+    case 'x':
+        putHex(write, x);
+        return;
+    case 'c':
+        **write = x;
+        (*write)++;
+        return;
+    case 'i':
+        putInt(write, x);
+        return;
+    case 'p':
+        putPadding(write, x);
+        return;
+    }
+}
+uint32_t ioManager, logFunction;
+
+uint32_t printfSize(const char *format, va_list *valist) {
+    uint32_t size = 0;
+    for (; format[size] != 0; size++) {
+        if (format[size] == '%') {
+            char insertType = format[++size];
+            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
+            continue;
+        }
+    }
+    return size;
+}
+
+void _sprintf(char *data, const char *format, va_list *valist) {
+    char *write = data;
+    for (int i = 0; format[i] != 0; i++) {
+        if (format[i] == '%') {
+            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
+            continue;
+        }
+        *write = format[i];
+        write++;
+    }
+}
+
+void sprintf(char *data, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+}
+
+char *_asprintf(AllocationData allocationData, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    uint32_t size = printfSize(format, &valist);
+    char *data = malloc(size);
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    return data;
+}
+
+void _printf(AllocationData allocationData, const char *format, ...) {
+    // I have absolutely no idea why this line fixes an issue where the first
+    // printf operation consistently doesn't correctly insert its string
+    free(malloc(1));
+    va_list valist;
+    va_start(valist, format);
+    char *data = malloc(printfSize(format, &valist));
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    uintptr_t id = insertString(data);
+    request(ioManager, logFunction, id, 0);
+    discardString(id);
+    free(data);
+}
+
+void gets(char *buffer) {
+    static uint32_t function = 0;
+    if (!function) {
+        function = getFunction(ioManager, "gets");
+    }
+    uint32_t stringId = request(ioManager, function, 0, 0);
+    readString(stringId, buffer);
+}
diff --git a/src/hlib/strings.c b/src/hlib/strings.c
new file mode 100644
index 0000000..78fff55
--- /dev/null
+++ b/src/hlib/strings.c
@@ -0,0 +1,38 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t strlen(char *string) {
+    if (!string) {
+        return 0;
+    }
+    uint32_t size = 0;
+    while (*string) {
+        string++;
+        size++;
+    }
+    return size;
+}
+
+void memcpy(void *from, void *to, uint32_t size) {
+    uint8_t *a = from, *b = to;
+    for (uint32_t i = 0; i < size; i++) {
+        b[i] = a[i];
+    }
+}
+
+uintptr_t insertString(char *string) {
+    return syscall(SYS_INSERT_STRING, U32(string), 0, 0, 0);
+}
+
+uintptr_t getStringLength(uintptr_t stringId) {
+    return syscall(SYS_GET_STRING_LENGTH, stringId, 0, 0, 0);
+}
+
+void readString(uintptr_t stringId, void *buffer) {
+    syscall(SYS_READ_STRING, stringId, U32(buffer), 0, 0);
+}
+
+void discardString(uintptr_t stringId) {
+    syscall(SYS_DISCARD_STRING, stringId, 0, 0, 0);
+}

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}
diff --git a/src/hlib/service/service.c b/src/hlib/service/service.c
new file mode 100644
index 0000000..1669154
--- /dev/null
+++ b/src/hlib/service/service.c
@@ -0,0 +1,39 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
+                 uintptr_t data2) {
+    return syscall(SYS_REQUEST, service, function, data1, data2);
+}
+
+uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
+}
+
+uint32_t getService(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+}
+
+uint32_t getFunction(uint32_t module, char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
+}
+
+uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
+
+uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
+    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
+}
+
+void *getPhysicalAddress(void *source) {
+    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
+               (U32(source) & 0xFFF));
+}
+
+uint32_t fork(void (f)(), void *a, void *b, void *c) {
+    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
+}
+
diff --git a/src/hlib/stdio.c b/src/hlib/stdio.c
new file mode 100644
index 0000000..e717154
--- /dev/null
+++ b/src/hlib/stdio.c
@@ -0,0 +1,207 @@
+#include <hlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+char HEX_CHARS[] = "0123456789ABCDEF";
+
+void putHex(char **write, uintptr_t x) {
+    if (x == 0) {
+        **write = HEX_CHARS[x];
+        (*write)++;
+        **write = HEX_CHARS[x];
+        (*write)++;
+        return;
+    }
+    bool alreadyWriting = false;
+    for (int position = 3; position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            **write = HEX_CHARS[byte >> 4];
+            (*write)++;
+            **write = HEX_CHARS[byte & 0x0F];
+            (*write)++;
+        }
+    }
+}
+
+uint8_t hexLength(uintptr_t x) {
+    bool alreadyWriting = false;
+    uint8_t size = 0;
+    for (int position = sizeof(uintptr_t); position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            size += 2;
+        }
+    }
+    return MAX(size, 2);
+}
+
+uint32_t power(uintptr_t x, uintptr_t y) {
+    uintptr_t result = 1;
+    for (uintptr_t i = 0; i < y; i++) {
+        result *= x;
+    }
+    return result;
+}
+
+uint32_t intLength(intptr_t x) {
+    if (x == 0) {
+        return 1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        if (x / power(10, i) > 0) {
+            return i + 1;
+        }
+    }
+    return 1;
+}
+
+void addChar(char **write, char c) {
+    **write = c;
+    (*write)++;
+}
+
+void putInt(char **write, intptr_t x) {
+    if (x == 0) {
+        addChar(write, '0');
+        return;
+    }
+    if (x < 0) {
+        addChar(write, '-');
+        x *= -1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        uintptr_t n = x / power(10, i);
+        if (n) {
+            addChar(write, HEX_CHARS[n % 10]);
+        }
+    }
+}
+
+void putPadding(char **write, uintptr_t x) {
+    x = MIN(x, 10); // max 10 wide padding
+    for (intptr_t i = 0; i < x; i++) {
+        addChar(write, ' ');
+    }
+}
+
+uint32_t getInsertLength(char insertType, intptr_t x) {
+    switch (insertType) {
+    case 's':
+        return strlen((char *)x);
+    case 'x':
+        return hexLength(x);
+    case 'c':
+        return 1;
+    case 'i':
+        return intLength(x) + (x < 0);
+    case 'p':
+        return x;
+    }
+    return 0;
+}
+
+void stringInsert(char **write, uintptr_t x) {
+    char *string = (char *)x;
+    uint32_t length = strlen(string);
+    for (uint32_t position = 0; position < length; position++) {
+        **write = string[position];
+        (*write)++;
+    }
+}
+
+void handleInsert(char **write, char insertType, uintptr_t x) {
+    switch (insertType) {
+    case 's':
+        stringInsert(write, x);
+        return;
+    case 'x':
+        putHex(write, x);
+        return;
+    case 'c':
+        **write = x;
+        (*write)++;
+        return;
+    case 'i':
+        putInt(write, x);
+        return;
+    case 'p':
+        putPadding(write, x);
+        return;
+    }
+}
+uint32_t ioManager, logFunction;
+
+uint32_t printfSize(const char *format, va_list *valist) {
+    uint32_t size = 0;
+    for (; format[size] != 0; size++) {
+        if (format[size] == '%') {
+            char insertType = format[++size];
+            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
+            continue;
+        }
+    }
+    return size;
+}
+
+void _sprintf(char *data, const char *format, va_list *valist) {
+    char *write = data;
+    for (int i = 0; format[i] != 0; i++) {
+        if (format[i] == '%') {
+            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
+            continue;
+        }
+        *write = format[i];
+        write++;
+    }
+}
+
+void sprintf(char *data, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+}
+
+char *_asprintf(AllocationData allocationData, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    uint32_t size = printfSize(format, &valist);
+    char *data = malloc(size);
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    return data;
+}
+
+void _printf(AllocationData allocationData, const char *format, ...) {
+    // I have absolutely no idea why this line fixes an issue where the first
+    // printf operation consistently doesn't correctly insert its string
+    free(malloc(1));
+    va_list valist;
+    va_start(valist, format);
+    char *data = malloc(printfSize(format, &valist));
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    uintptr_t id = insertString(data);
+    request(ioManager, logFunction, id, 0);
+    discardString(id);
+    free(data);
+}
+
+void gets(char *buffer) {
+    static uint32_t function = 0;
+    if (!function) {
+        function = getFunction(ioManager, "gets");
+    }
+    uint32_t stringId = request(ioManager, function, 0, 0);
+    readString(stringId, buffer);
+}
diff --git a/src/hlib/strings.c b/src/hlib/strings.c
new file mode 100644
index 0000000..78fff55
--- /dev/null
+++ b/src/hlib/strings.c
@@ -0,0 +1,38 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t strlen(char *string) {
+    if (!string) {
+        return 0;
+    }
+    uint32_t size = 0;
+    while (*string) {
+        string++;
+        size++;
+    }
+    return size;
+}
+
+void memcpy(void *from, void *to, uint32_t size) {
+    uint8_t *a = from, *b = to;
+    for (uint32_t i = 0; i < size; i++) {
+        b[i] = a[i];
+    }
+}
+
+uintptr_t insertString(char *string) {
+    return syscall(SYS_INSERT_STRING, U32(string), 0, 0, 0);
+}
+
+uintptr_t getStringLength(uintptr_t stringId) {
+    return syscall(SYS_GET_STRING_LENGTH, stringId, 0, 0, 0);
+}
+
+void readString(uintptr_t stringId, void *buffer) {
+    syscall(SYS_READ_STRING, stringId, U32(buffer), 0, 0);
+}
+
+void discardString(uintptr_t stringId) {
+    syscall(SYS_DISCARD_STRING, stringId, 0, 0, 0);
+}
diff --git a/src/include/hlib.h b/src/include/hlib.h
index a8da877..ed26b16 100644
--- a/src/include/hlib.h
+++ b/src/include/hlib.h
@@ -9,7 +9,7 @@
     void *data;
 } ListElement;
 
-#include "../userland/hlib/malloc.h"
+#include "../hlib/malloc.h"
 
 #define PTR(x) ((void *)(uintptr_t)(x))
 #define U32(x) ((uint32_t)(uintptr_t)(x))

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}
diff --git a/src/hlib/service/service.c b/src/hlib/service/service.c
new file mode 100644
index 0000000..1669154
--- /dev/null
+++ b/src/hlib/service/service.c
@@ -0,0 +1,39 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
+                 uintptr_t data2) {
+    return syscall(SYS_REQUEST, service, function, data1, data2);
+}
+
+uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
+}
+
+uint32_t getService(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+}
+
+uint32_t getFunction(uint32_t module, char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
+}
+
+uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
+
+uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
+    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
+}
+
+void *getPhysicalAddress(void *source) {
+    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
+               (U32(source) & 0xFFF));
+}
+
+uint32_t fork(void (f)(), void *a, void *b, void *c) {
+    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
+}
+
diff --git a/src/hlib/stdio.c b/src/hlib/stdio.c
new file mode 100644
index 0000000..e717154
--- /dev/null
+++ b/src/hlib/stdio.c
@@ -0,0 +1,207 @@
+#include <hlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+char HEX_CHARS[] = "0123456789ABCDEF";
+
+void putHex(char **write, uintptr_t x) {
+    if (x == 0) {
+        **write = HEX_CHARS[x];
+        (*write)++;
+        **write = HEX_CHARS[x];
+        (*write)++;
+        return;
+    }
+    bool alreadyWriting = false;
+    for (int position = 3; position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            **write = HEX_CHARS[byte >> 4];
+            (*write)++;
+            **write = HEX_CHARS[byte & 0x0F];
+            (*write)++;
+        }
+    }
+}
+
+uint8_t hexLength(uintptr_t x) {
+    bool alreadyWriting = false;
+    uint8_t size = 0;
+    for (int position = sizeof(uintptr_t); position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            size += 2;
+        }
+    }
+    return MAX(size, 2);
+}
+
+uint32_t power(uintptr_t x, uintptr_t y) {
+    uintptr_t result = 1;
+    for (uintptr_t i = 0; i < y; i++) {
+        result *= x;
+    }
+    return result;
+}
+
+uint32_t intLength(intptr_t x) {
+    if (x == 0) {
+        return 1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        if (x / power(10, i) > 0) {
+            return i + 1;
+        }
+    }
+    return 1;
+}
+
+void addChar(char **write, char c) {
+    **write = c;
+    (*write)++;
+}
+
+void putInt(char **write, intptr_t x) {
+    if (x == 0) {
+        addChar(write, '0');
+        return;
+    }
+    if (x < 0) {
+        addChar(write, '-');
+        x *= -1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        uintptr_t n = x / power(10, i);
+        if (n) {
+            addChar(write, HEX_CHARS[n % 10]);
+        }
+    }
+}
+
+void putPadding(char **write, uintptr_t x) {
+    x = MIN(x, 10); // max 10 wide padding
+    for (intptr_t i = 0; i < x; i++) {
+        addChar(write, ' ');
+    }
+}
+
+uint32_t getInsertLength(char insertType, intptr_t x) {
+    switch (insertType) {
+    case 's':
+        return strlen((char *)x);
+    case 'x':
+        return hexLength(x);
+    case 'c':
+        return 1;
+    case 'i':
+        return intLength(x) + (x < 0);
+    case 'p':
+        return x;
+    }
+    return 0;
+}
+
+void stringInsert(char **write, uintptr_t x) {
+    char *string = (char *)x;
+    uint32_t length = strlen(string);
+    for (uint32_t position = 0; position < length; position++) {
+        **write = string[position];
+        (*write)++;
+    }
+}
+
+void handleInsert(char **write, char insertType, uintptr_t x) {
+    switch (insertType) {
+    case 's':
+        stringInsert(write, x);
+        return;
+    case 'x':
+        putHex(write, x);
+        return;
+    case 'c':
+        **write = x;
+        (*write)++;
+        return;
+    case 'i':
+        putInt(write, x);
+        return;
+    case 'p':
+        putPadding(write, x);
+        return;
+    }
+}
+uint32_t ioManager, logFunction;
+
+uint32_t printfSize(const char *format, va_list *valist) {
+    uint32_t size = 0;
+    for (; format[size] != 0; size++) {
+        if (format[size] == '%') {
+            char insertType = format[++size];
+            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
+            continue;
+        }
+    }
+    return size;
+}
+
+void _sprintf(char *data, const char *format, va_list *valist) {
+    char *write = data;
+    for (int i = 0; format[i] != 0; i++) {
+        if (format[i] == '%') {
+            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
+            continue;
+        }
+        *write = format[i];
+        write++;
+    }
+}
+
+void sprintf(char *data, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+}
+
+char *_asprintf(AllocationData allocationData, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    uint32_t size = printfSize(format, &valist);
+    char *data = malloc(size);
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    return data;
+}
+
+void _printf(AllocationData allocationData, const char *format, ...) {
+    // I have absolutely no idea why this line fixes an issue where the first
+    // printf operation consistently doesn't correctly insert its string
+    free(malloc(1));
+    va_list valist;
+    va_start(valist, format);
+    char *data = malloc(printfSize(format, &valist));
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    uintptr_t id = insertString(data);
+    request(ioManager, logFunction, id, 0);
+    discardString(id);
+    free(data);
+}
+
+void gets(char *buffer) {
+    static uint32_t function = 0;
+    if (!function) {
+        function = getFunction(ioManager, "gets");
+    }
+    uint32_t stringId = request(ioManager, function, 0, 0);
+    readString(stringId, buffer);
+}
diff --git a/src/hlib/strings.c b/src/hlib/strings.c
new file mode 100644
index 0000000..78fff55
--- /dev/null
+++ b/src/hlib/strings.c
@@ -0,0 +1,38 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t strlen(char *string) {
+    if (!string) {
+        return 0;
+    }
+    uint32_t size = 0;
+    while (*string) {
+        string++;
+        size++;
+    }
+    return size;
+}
+
+void memcpy(void *from, void *to, uint32_t size) {
+    uint8_t *a = from, *b = to;
+    for (uint32_t i = 0; i < size; i++) {
+        b[i] = a[i];
+    }
+}
+
+uintptr_t insertString(char *string) {
+    return syscall(SYS_INSERT_STRING, U32(string), 0, 0, 0);
+}
+
+uintptr_t getStringLength(uintptr_t stringId) {
+    return syscall(SYS_GET_STRING_LENGTH, stringId, 0, 0, 0);
+}
+
+void readString(uintptr_t stringId, void *buffer) {
+    syscall(SYS_READ_STRING, stringId, U32(buffer), 0, 0);
+}
+
+void discardString(uintptr_t stringId) {
+    syscall(SYS_DISCARD_STRING, stringId, 0, 0, 0);
+}
diff --git a/src/include/hlib.h b/src/include/hlib.h
index a8da877..ed26b16 100644
--- a/src/include/hlib.h
+++ b/src/include/hlib.h
@@ -9,7 +9,7 @@
     void *data;
 } ListElement;
 
-#include "../userland/hlib/malloc.h"
+#include "../hlib/malloc.h"
 
 #define PTR(x) ((void *)(uintptr_t)(x))
 #define U32(x) ((uint32_t)(uintptr_t)(x))
diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile
deleted file mode 100644
index 4870f51..0000000
--- a/src/userland/hlib/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-CC = i686-elf-gcc
-CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
-LD = i686-elf-ld
-LD_FLAGS = -z max-page-size=0x1000 
-AS = nasm
-ASFlAGS = -felf32
-
-BUILD_FOLDER = build
-
-SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
-OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
-
-../../../initrd/hlib: $(OBJS)
-	@echo "linking the honey OS c libary"
-	@$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r
-	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
-
-$(BUILD_FOLDER)/%.asm.o: %.asm
-	@echo "asembling $<"
-	@mkdir -p $(dir $@)
-	@$(AS) $(ASFlAGS) $< -o $@
-
-$(BUILD_FOLDER)/%.c.o: %.c
-	@echo "compiling $<"
-	@mkdir -p $(dir $@)
-	@$(CC) $(CCFLAGS) -r $< -o $@
-
-clean:
-	@echo "clearing build folder"
-	@rm -r $(BUILD_FOLDER)

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}
diff --git a/src/hlib/service/service.c b/src/hlib/service/service.c
new file mode 100644
index 0000000..1669154
--- /dev/null
+++ b/src/hlib/service/service.c
@@ -0,0 +1,39 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
+                 uintptr_t data2) {
+    return syscall(SYS_REQUEST, service, function, data1, data2);
+}
+
+uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
+}
+
+uint32_t getService(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+}
+
+uint32_t getFunction(uint32_t module, char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
+}
+
+uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
+
+uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
+    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
+}
+
+void *getPhysicalAddress(void *source) {
+    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
+               (U32(source) & 0xFFF));
+}
+
+uint32_t fork(void (f)(), void *a, void *b, void *c) {
+    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
+}
+
diff --git a/src/hlib/stdio.c b/src/hlib/stdio.c
new file mode 100644
index 0000000..e717154
--- /dev/null
+++ b/src/hlib/stdio.c
@@ -0,0 +1,207 @@
+#include <hlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+char HEX_CHARS[] = "0123456789ABCDEF";
+
+void putHex(char **write, uintptr_t x) {
+    if (x == 0) {
+        **write = HEX_CHARS[x];
+        (*write)++;
+        **write = HEX_CHARS[x];
+        (*write)++;
+        return;
+    }
+    bool alreadyWriting = false;
+    for (int position = 3; position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            **write = HEX_CHARS[byte >> 4];
+            (*write)++;
+            **write = HEX_CHARS[byte & 0x0F];
+            (*write)++;
+        }
+    }
+}
+
+uint8_t hexLength(uintptr_t x) {
+    bool alreadyWriting = false;
+    uint8_t size = 0;
+    for (int position = sizeof(uintptr_t); position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            size += 2;
+        }
+    }
+    return MAX(size, 2);
+}
+
+uint32_t power(uintptr_t x, uintptr_t y) {
+    uintptr_t result = 1;
+    for (uintptr_t i = 0; i < y; i++) {
+        result *= x;
+    }
+    return result;
+}
+
+uint32_t intLength(intptr_t x) {
+    if (x == 0) {
+        return 1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        if (x / power(10, i) > 0) {
+            return i + 1;
+        }
+    }
+    return 1;
+}
+
+void addChar(char **write, char c) {
+    **write = c;
+    (*write)++;
+}
+
+void putInt(char **write, intptr_t x) {
+    if (x == 0) {
+        addChar(write, '0');
+        return;
+    }
+    if (x < 0) {
+        addChar(write, '-');
+        x *= -1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        uintptr_t n = x / power(10, i);
+        if (n) {
+            addChar(write, HEX_CHARS[n % 10]);
+        }
+    }
+}
+
+void putPadding(char **write, uintptr_t x) {
+    x = MIN(x, 10); // max 10 wide padding
+    for (intptr_t i = 0; i < x; i++) {
+        addChar(write, ' ');
+    }
+}
+
+uint32_t getInsertLength(char insertType, intptr_t x) {
+    switch (insertType) {
+    case 's':
+        return strlen((char *)x);
+    case 'x':
+        return hexLength(x);
+    case 'c':
+        return 1;
+    case 'i':
+        return intLength(x) + (x < 0);
+    case 'p':
+        return x;
+    }
+    return 0;
+}
+
+void stringInsert(char **write, uintptr_t x) {
+    char *string = (char *)x;
+    uint32_t length = strlen(string);
+    for (uint32_t position = 0; position < length; position++) {
+        **write = string[position];
+        (*write)++;
+    }
+}
+
+void handleInsert(char **write, char insertType, uintptr_t x) {
+    switch (insertType) {
+    case 's':
+        stringInsert(write, x);
+        return;
+    case 'x':
+        putHex(write, x);
+        return;
+    case 'c':
+        **write = x;
+        (*write)++;
+        return;
+    case 'i':
+        putInt(write, x);
+        return;
+    case 'p':
+        putPadding(write, x);
+        return;
+    }
+}
+uint32_t ioManager, logFunction;
+
+uint32_t printfSize(const char *format, va_list *valist) {
+    uint32_t size = 0;
+    for (; format[size] != 0; size++) {
+        if (format[size] == '%') {
+            char insertType = format[++size];
+            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
+            continue;
+        }
+    }
+    return size;
+}
+
+void _sprintf(char *data, const char *format, va_list *valist) {
+    char *write = data;
+    for (int i = 0; format[i] != 0; i++) {
+        if (format[i] == '%') {
+            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
+            continue;
+        }
+        *write = format[i];
+        write++;
+    }
+}
+
+void sprintf(char *data, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+}
+
+char *_asprintf(AllocationData allocationData, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    uint32_t size = printfSize(format, &valist);
+    char *data = malloc(size);
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    return data;
+}
+
+void _printf(AllocationData allocationData, const char *format, ...) {
+    // I have absolutely no idea why this line fixes an issue where the first
+    // printf operation consistently doesn't correctly insert its string
+    free(malloc(1));
+    va_list valist;
+    va_start(valist, format);
+    char *data = malloc(printfSize(format, &valist));
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    uintptr_t id = insertString(data);
+    request(ioManager, logFunction, id, 0);
+    discardString(id);
+    free(data);
+}
+
+void gets(char *buffer) {
+    static uint32_t function = 0;
+    if (!function) {
+        function = getFunction(ioManager, "gets");
+    }
+    uint32_t stringId = request(ioManager, function, 0, 0);
+    readString(stringId, buffer);
+}
diff --git a/src/hlib/strings.c b/src/hlib/strings.c
new file mode 100644
index 0000000..78fff55
--- /dev/null
+++ b/src/hlib/strings.c
@@ -0,0 +1,38 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t strlen(char *string) {
+    if (!string) {
+        return 0;
+    }
+    uint32_t size = 0;
+    while (*string) {
+        string++;
+        size++;
+    }
+    return size;
+}
+
+void memcpy(void *from, void *to, uint32_t size) {
+    uint8_t *a = from, *b = to;
+    for (uint32_t i = 0; i < size; i++) {
+        b[i] = a[i];
+    }
+}
+
+uintptr_t insertString(char *string) {
+    return syscall(SYS_INSERT_STRING, U32(string), 0, 0, 0);
+}
+
+uintptr_t getStringLength(uintptr_t stringId) {
+    return syscall(SYS_GET_STRING_LENGTH, stringId, 0, 0, 0);
+}
+
+void readString(uintptr_t stringId, void *buffer) {
+    syscall(SYS_READ_STRING, stringId, U32(buffer), 0, 0);
+}
+
+void discardString(uintptr_t stringId) {
+    syscall(SYS_DISCARD_STRING, stringId, 0, 0, 0);
+}
diff --git a/src/include/hlib.h b/src/include/hlib.h
index a8da877..ed26b16 100644
--- a/src/include/hlib.h
+++ b/src/include/hlib.h
@@ -9,7 +9,7 @@
     void *data;
 } ListElement;
 
-#include "../userland/hlib/malloc.h"
+#include "../hlib/malloc.h"
 
 #define PTR(x) ((void *)(uintptr_t)(x))
 #define U32(x) ((uint32_t)(uintptr_t)(x))
diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile
deleted file mode 100644
index 4870f51..0000000
--- a/src/userland/hlib/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-CC = i686-elf-gcc
-CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
-LD = i686-elf-ld
-LD_FLAGS = -z max-page-size=0x1000 
-AS = nasm
-ASFlAGS = -felf32
-
-BUILD_FOLDER = build
-
-SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
-OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
-
-../../../initrd/hlib: $(OBJS)
-	@echo "linking the honey OS c libary"
-	@$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r
-	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
-
-$(BUILD_FOLDER)/%.asm.o: %.asm
-	@echo "asembling $<"
-	@mkdir -p $(dir $@)
-	@$(AS) $(ASFlAGS) $< -o $@
-
-$(BUILD_FOLDER)/%.c.o: %.c
-	@echo "compiling $<"
-	@mkdir -p $(dir $@)
-	@$(CC) $(CCFLAGS) -r $< -o $@
-
-clean:
-	@echo "clearing build folder"
-	@rm -r $(BUILD_FOLDER)
diff --git a/src/userland/hlib/compile_flags.txt b/src/userland/hlib/compile_flags.txt
deleted file mode 100644
index a432e7b..0000000
--- a/src/userland/hlib/compile_flags.txt
+++ /dev/null
@@ -1,6 +0,0 @@
--I./include
--I../../include
-clang
--fms-extensions
--Wno-microsoft-anon-tag
--Wno-incompatible-library-redeclaration

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}
diff --git a/src/hlib/service/service.c b/src/hlib/service/service.c
new file mode 100644
index 0000000..1669154
--- /dev/null
+++ b/src/hlib/service/service.c
@@ -0,0 +1,39 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
+                 uintptr_t data2) {
+    return syscall(SYS_REQUEST, service, function, data1, data2);
+}
+
+uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
+}
+
+uint32_t getService(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+}
+
+uint32_t getFunction(uint32_t module, char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
+}
+
+uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
+
+uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
+    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
+}
+
+void *getPhysicalAddress(void *source) {
+    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
+               (U32(source) & 0xFFF));
+}
+
+uint32_t fork(void (f)(), void *a, void *b, void *c) {
+    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
+}
+
diff --git a/src/hlib/stdio.c b/src/hlib/stdio.c
new file mode 100644
index 0000000..e717154
--- /dev/null
+++ b/src/hlib/stdio.c
@@ -0,0 +1,207 @@
+#include <hlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+char HEX_CHARS[] = "0123456789ABCDEF";
+
+void putHex(char **write, uintptr_t x) {
+    if (x == 0) {
+        **write = HEX_CHARS[x];
+        (*write)++;
+        **write = HEX_CHARS[x];
+        (*write)++;
+        return;
+    }
+    bool alreadyWriting = false;
+    for (int position = 3; position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            **write = HEX_CHARS[byte >> 4];
+            (*write)++;
+            **write = HEX_CHARS[byte & 0x0F];
+            (*write)++;
+        }
+    }
+}
+
+uint8_t hexLength(uintptr_t x) {
+    bool alreadyWriting = false;
+    uint8_t size = 0;
+    for (int position = sizeof(uintptr_t); position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            size += 2;
+        }
+    }
+    return MAX(size, 2);
+}
+
+uint32_t power(uintptr_t x, uintptr_t y) {
+    uintptr_t result = 1;
+    for (uintptr_t i = 0; i < y; i++) {
+        result *= x;
+    }
+    return result;
+}
+
+uint32_t intLength(intptr_t x) {
+    if (x == 0) {
+        return 1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        if (x / power(10, i) > 0) {
+            return i + 1;
+        }
+    }
+    return 1;
+}
+
+void addChar(char **write, char c) {
+    **write = c;
+    (*write)++;
+}
+
+void putInt(char **write, intptr_t x) {
+    if (x == 0) {
+        addChar(write, '0');
+        return;
+    }
+    if (x < 0) {
+        addChar(write, '-');
+        x *= -1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        uintptr_t n = x / power(10, i);
+        if (n) {
+            addChar(write, HEX_CHARS[n % 10]);
+        }
+    }
+}
+
+void putPadding(char **write, uintptr_t x) {
+    x = MIN(x, 10); // max 10 wide padding
+    for (intptr_t i = 0; i < x; i++) {
+        addChar(write, ' ');
+    }
+}
+
+uint32_t getInsertLength(char insertType, intptr_t x) {
+    switch (insertType) {
+    case 's':
+        return strlen((char *)x);
+    case 'x':
+        return hexLength(x);
+    case 'c':
+        return 1;
+    case 'i':
+        return intLength(x) + (x < 0);
+    case 'p':
+        return x;
+    }
+    return 0;
+}
+
+void stringInsert(char **write, uintptr_t x) {
+    char *string = (char *)x;
+    uint32_t length = strlen(string);
+    for (uint32_t position = 0; position < length; position++) {
+        **write = string[position];
+        (*write)++;
+    }
+}
+
+void handleInsert(char **write, char insertType, uintptr_t x) {
+    switch (insertType) {
+    case 's':
+        stringInsert(write, x);
+        return;
+    case 'x':
+        putHex(write, x);
+        return;
+    case 'c':
+        **write = x;
+        (*write)++;
+        return;
+    case 'i':
+        putInt(write, x);
+        return;
+    case 'p':
+        putPadding(write, x);
+        return;
+    }
+}
+uint32_t ioManager, logFunction;
+
+uint32_t printfSize(const char *format, va_list *valist) {
+    uint32_t size = 0;
+    for (; format[size] != 0; size++) {
+        if (format[size] == '%') {
+            char insertType = format[++size];
+            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
+            continue;
+        }
+    }
+    return size;
+}
+
+void _sprintf(char *data, const char *format, va_list *valist) {
+    char *write = data;
+    for (int i = 0; format[i] != 0; i++) {
+        if (format[i] == '%') {
+            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
+            continue;
+        }
+        *write = format[i];
+        write++;
+    }
+}
+
+void sprintf(char *data, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+}
+
+char *_asprintf(AllocationData allocationData, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    uint32_t size = printfSize(format, &valist);
+    char *data = malloc(size);
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    return data;
+}
+
+void _printf(AllocationData allocationData, const char *format, ...) {
+    // I have absolutely no idea why this line fixes an issue where the first
+    // printf operation consistently doesn't correctly insert its string
+    free(malloc(1));
+    va_list valist;
+    va_start(valist, format);
+    char *data = malloc(printfSize(format, &valist));
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    uintptr_t id = insertString(data);
+    request(ioManager, logFunction, id, 0);
+    discardString(id);
+    free(data);
+}
+
+void gets(char *buffer) {
+    static uint32_t function = 0;
+    if (!function) {
+        function = getFunction(ioManager, "gets");
+    }
+    uint32_t stringId = request(ioManager, function, 0, 0);
+    readString(stringId, buffer);
+}
diff --git a/src/hlib/strings.c b/src/hlib/strings.c
new file mode 100644
index 0000000..78fff55
--- /dev/null
+++ b/src/hlib/strings.c
@@ -0,0 +1,38 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t strlen(char *string) {
+    if (!string) {
+        return 0;
+    }
+    uint32_t size = 0;
+    while (*string) {
+        string++;
+        size++;
+    }
+    return size;
+}
+
+void memcpy(void *from, void *to, uint32_t size) {
+    uint8_t *a = from, *b = to;
+    for (uint32_t i = 0; i < size; i++) {
+        b[i] = a[i];
+    }
+}
+
+uintptr_t insertString(char *string) {
+    return syscall(SYS_INSERT_STRING, U32(string), 0, 0, 0);
+}
+
+uintptr_t getStringLength(uintptr_t stringId) {
+    return syscall(SYS_GET_STRING_LENGTH, stringId, 0, 0, 0);
+}
+
+void readString(uintptr_t stringId, void *buffer) {
+    syscall(SYS_READ_STRING, stringId, U32(buffer), 0, 0);
+}
+
+void discardString(uintptr_t stringId) {
+    syscall(SYS_DISCARD_STRING, stringId, 0, 0, 0);
+}
diff --git a/src/include/hlib.h b/src/include/hlib.h
index a8da877..ed26b16 100644
--- a/src/include/hlib.h
+++ b/src/include/hlib.h
@@ -9,7 +9,7 @@
     void *data;
 } ListElement;
 
-#include "../userland/hlib/malloc.h"
+#include "../hlib/malloc.h"
 
 #define PTR(x) ((void *)(uintptr_t)(x))
 #define U32(x) ((uint32_t)(uintptr_t)(x))
diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile
deleted file mode 100644
index 4870f51..0000000
--- a/src/userland/hlib/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-CC = i686-elf-gcc
-CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
-LD = i686-elf-ld
-LD_FLAGS = -z max-page-size=0x1000 
-AS = nasm
-ASFlAGS = -felf32
-
-BUILD_FOLDER = build
-
-SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
-OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
-
-../../../initrd/hlib: $(OBJS)
-	@echo "linking the honey OS c libary"
-	@$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r
-	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
-
-$(BUILD_FOLDER)/%.asm.o: %.asm
-	@echo "asembling $<"
-	@mkdir -p $(dir $@)
-	@$(AS) $(ASFlAGS) $< -o $@
-
-$(BUILD_FOLDER)/%.c.o: %.c
-	@echo "compiling $<"
-	@mkdir -p $(dir $@)
-	@$(CC) $(CCFLAGS) -r $< -o $@
-
-clean:
-	@echo "clearing build folder"
-	@rm -r $(BUILD_FOLDER)
diff --git a/src/userland/hlib/compile_flags.txt b/src/userland/hlib/compile_flags.txt
deleted file mode 100644
index a432e7b..0000000
--- a/src/userland/hlib/compile_flags.txt
+++ /dev/null
@@ -1,6 +0,0 @@
--I./include
--I../../include
-clang
--fms-extensions
--Wno-microsoft-anon-tag
--Wno-incompatible-library-redeclaration
diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h
deleted file mode 100644
index 2025b24..0000000
--- a/src/userland/hlib/include/syscalls.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef SYSCALLS_H
-#define SYSCALLS_H
-
-#include <stdbool.h>
-#include <stdint.h>
-
-typedef enum {
-    SYS_RUN = 0,
-    SYS_CREATE_FUNCTION = 1,
-    SYS_REQUEST = 2,
-    SYS_IO_IN = 3,
-    SYS_IO_OUT = 4,
-    SYS_LOAD_INITRD = 5,
-    SYS_GET_SERVICE = 6,
-    SYS_GET_FUNCTION = 7,
-    SYS_SUBSCRIBE_INTERRUPT = 8,
-    SYS_CREATE_EVENT = 9,
-    SYS_GET_EVENT = 10,
-    SYS_FIRE_EVENT = 11,
-    SYS_SUBSCRIBE_EVENT = 12,
-    SYS_GET_SERVICE_ID = 13,
-    SYS_INSERT_STRING = 14,
-    SYS_GET_STRING_LENGTH = 15,
-    SYS_READ_STRING = 16,
-    SYS_DISCARD_STRING = 17,
-    SYS_REQUEST_MEMORY = 18,
-    SYS_LOOKUP_SYMBOL = 19,
-    SYS_STACK_CONTAINS = 20,
-    SYS_AWAIT = 21,
-    SYS_GET_PHYSICAL = 22,
-    SYS_FORK = 23,
-} SyscallIds;
-
-extern uint32_t getFunction(uint32_t module, char *name);
-
-#endif

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}
diff --git a/src/hlib/service/service.c b/src/hlib/service/service.c
new file mode 100644
index 0000000..1669154
--- /dev/null
+++ b/src/hlib/service/service.c
@@ -0,0 +1,39 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
+                 uintptr_t data2) {
+    return syscall(SYS_REQUEST, service, function, data1, data2);
+}
+
+uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
+}
+
+uint32_t getService(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+}
+
+uint32_t getFunction(uint32_t module, char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
+}
+
+uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
+
+uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
+    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
+}
+
+void *getPhysicalAddress(void *source) {
+    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
+               (U32(source) & 0xFFF));
+}
+
+uint32_t fork(void (f)(), void *a, void *b, void *c) {
+    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
+}
+
diff --git a/src/hlib/stdio.c b/src/hlib/stdio.c
new file mode 100644
index 0000000..e717154
--- /dev/null
+++ b/src/hlib/stdio.c
@@ -0,0 +1,207 @@
+#include <hlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+char HEX_CHARS[] = "0123456789ABCDEF";
+
+void putHex(char **write, uintptr_t x) {
+    if (x == 0) {
+        **write = HEX_CHARS[x];
+        (*write)++;
+        **write = HEX_CHARS[x];
+        (*write)++;
+        return;
+    }
+    bool alreadyWriting = false;
+    for (int position = 3; position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            **write = HEX_CHARS[byte >> 4];
+            (*write)++;
+            **write = HEX_CHARS[byte & 0x0F];
+            (*write)++;
+        }
+    }
+}
+
+uint8_t hexLength(uintptr_t x) {
+    bool alreadyWriting = false;
+    uint8_t size = 0;
+    for (int position = sizeof(uintptr_t); position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            size += 2;
+        }
+    }
+    return MAX(size, 2);
+}
+
+uint32_t power(uintptr_t x, uintptr_t y) {
+    uintptr_t result = 1;
+    for (uintptr_t i = 0; i < y; i++) {
+        result *= x;
+    }
+    return result;
+}
+
+uint32_t intLength(intptr_t x) {
+    if (x == 0) {
+        return 1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        if (x / power(10, i) > 0) {
+            return i + 1;
+        }
+    }
+    return 1;
+}
+
+void addChar(char **write, char c) {
+    **write = c;
+    (*write)++;
+}
+
+void putInt(char **write, intptr_t x) {
+    if (x == 0) {
+        addChar(write, '0');
+        return;
+    }
+    if (x < 0) {
+        addChar(write, '-');
+        x *= -1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        uintptr_t n = x / power(10, i);
+        if (n) {
+            addChar(write, HEX_CHARS[n % 10]);
+        }
+    }
+}
+
+void putPadding(char **write, uintptr_t x) {
+    x = MIN(x, 10); // max 10 wide padding
+    for (intptr_t i = 0; i < x; i++) {
+        addChar(write, ' ');
+    }
+}
+
+uint32_t getInsertLength(char insertType, intptr_t x) {
+    switch (insertType) {
+    case 's':
+        return strlen((char *)x);
+    case 'x':
+        return hexLength(x);
+    case 'c':
+        return 1;
+    case 'i':
+        return intLength(x) + (x < 0);
+    case 'p':
+        return x;
+    }
+    return 0;
+}
+
+void stringInsert(char **write, uintptr_t x) {
+    char *string = (char *)x;
+    uint32_t length = strlen(string);
+    for (uint32_t position = 0; position < length; position++) {
+        **write = string[position];
+        (*write)++;
+    }
+}
+
+void handleInsert(char **write, char insertType, uintptr_t x) {
+    switch (insertType) {
+    case 's':
+        stringInsert(write, x);
+        return;
+    case 'x':
+        putHex(write, x);
+        return;
+    case 'c':
+        **write = x;
+        (*write)++;
+        return;
+    case 'i':
+        putInt(write, x);
+        return;
+    case 'p':
+        putPadding(write, x);
+        return;
+    }
+}
+uint32_t ioManager, logFunction;
+
+uint32_t printfSize(const char *format, va_list *valist) {
+    uint32_t size = 0;
+    for (; format[size] != 0; size++) {
+        if (format[size] == '%') {
+            char insertType = format[++size];
+            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
+            continue;
+        }
+    }
+    return size;
+}
+
+void _sprintf(char *data, const char *format, va_list *valist) {
+    char *write = data;
+    for (int i = 0; format[i] != 0; i++) {
+        if (format[i] == '%') {
+            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
+            continue;
+        }
+        *write = format[i];
+        write++;
+    }
+}
+
+void sprintf(char *data, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+}
+
+char *_asprintf(AllocationData allocationData, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    uint32_t size = printfSize(format, &valist);
+    char *data = malloc(size);
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    return data;
+}
+
+void _printf(AllocationData allocationData, const char *format, ...) {
+    // I have absolutely no idea why this line fixes an issue where the first
+    // printf operation consistently doesn't correctly insert its string
+    free(malloc(1));
+    va_list valist;
+    va_start(valist, format);
+    char *data = malloc(printfSize(format, &valist));
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    uintptr_t id = insertString(data);
+    request(ioManager, logFunction, id, 0);
+    discardString(id);
+    free(data);
+}
+
+void gets(char *buffer) {
+    static uint32_t function = 0;
+    if (!function) {
+        function = getFunction(ioManager, "gets");
+    }
+    uint32_t stringId = request(ioManager, function, 0, 0);
+    readString(stringId, buffer);
+}
diff --git a/src/hlib/strings.c b/src/hlib/strings.c
new file mode 100644
index 0000000..78fff55
--- /dev/null
+++ b/src/hlib/strings.c
@@ -0,0 +1,38 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t strlen(char *string) {
+    if (!string) {
+        return 0;
+    }
+    uint32_t size = 0;
+    while (*string) {
+        string++;
+        size++;
+    }
+    return size;
+}
+
+void memcpy(void *from, void *to, uint32_t size) {
+    uint8_t *a = from, *b = to;
+    for (uint32_t i = 0; i < size; i++) {
+        b[i] = a[i];
+    }
+}
+
+uintptr_t insertString(char *string) {
+    return syscall(SYS_INSERT_STRING, U32(string), 0, 0, 0);
+}
+
+uintptr_t getStringLength(uintptr_t stringId) {
+    return syscall(SYS_GET_STRING_LENGTH, stringId, 0, 0, 0);
+}
+
+void readString(uintptr_t stringId, void *buffer) {
+    syscall(SYS_READ_STRING, stringId, U32(buffer), 0, 0);
+}
+
+void discardString(uintptr_t stringId) {
+    syscall(SYS_DISCARD_STRING, stringId, 0, 0, 0);
+}
diff --git a/src/include/hlib.h b/src/include/hlib.h
index a8da877..ed26b16 100644
--- a/src/include/hlib.h
+++ b/src/include/hlib.h
@@ -9,7 +9,7 @@
     void *data;
 } ListElement;
 
-#include "../userland/hlib/malloc.h"
+#include "../hlib/malloc.h"
 
 #define PTR(x) ((void *)(uintptr_t)(x))
 #define U32(x) ((uint32_t)(uintptr_t)(x))
diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile
deleted file mode 100644
index 4870f51..0000000
--- a/src/userland/hlib/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-CC = i686-elf-gcc
-CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
-LD = i686-elf-ld
-LD_FLAGS = -z max-page-size=0x1000 
-AS = nasm
-ASFlAGS = -felf32
-
-BUILD_FOLDER = build
-
-SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
-OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
-
-../../../initrd/hlib: $(OBJS)
-	@echo "linking the honey OS c libary"
-	@$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r
-	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
-
-$(BUILD_FOLDER)/%.asm.o: %.asm
-	@echo "asembling $<"
-	@mkdir -p $(dir $@)
-	@$(AS) $(ASFlAGS) $< -o $@
-
-$(BUILD_FOLDER)/%.c.o: %.c
-	@echo "compiling $<"
-	@mkdir -p $(dir $@)
-	@$(CC) $(CCFLAGS) -r $< -o $@
-
-clean:
-	@echo "clearing build folder"
-	@rm -r $(BUILD_FOLDER)
diff --git a/src/userland/hlib/compile_flags.txt b/src/userland/hlib/compile_flags.txt
deleted file mode 100644
index a432e7b..0000000
--- a/src/userland/hlib/compile_flags.txt
+++ /dev/null
@@ -1,6 +0,0 @@
--I./include
--I../../include
-clang
--fms-extensions
--Wno-microsoft-anon-tag
--Wno-incompatible-library-redeclaration
diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h
deleted file mode 100644
index 2025b24..0000000
--- a/src/userland/hlib/include/syscalls.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef SYSCALLS_H
-#define SYSCALLS_H
-
-#include <stdbool.h>
-#include <stdint.h>
-
-typedef enum {
-    SYS_RUN = 0,
-    SYS_CREATE_FUNCTION = 1,
-    SYS_REQUEST = 2,
-    SYS_IO_IN = 3,
-    SYS_IO_OUT = 4,
-    SYS_LOAD_INITRD = 5,
-    SYS_GET_SERVICE = 6,
-    SYS_GET_FUNCTION = 7,
-    SYS_SUBSCRIBE_INTERRUPT = 8,
-    SYS_CREATE_EVENT = 9,
-    SYS_GET_EVENT = 10,
-    SYS_FIRE_EVENT = 11,
-    SYS_SUBSCRIBE_EVENT = 12,
-    SYS_GET_SERVICE_ID = 13,
-    SYS_INSERT_STRING = 14,
-    SYS_GET_STRING_LENGTH = 15,
-    SYS_READ_STRING = 16,
-    SYS_DISCARD_STRING = 17,
-    SYS_REQUEST_MEMORY = 18,
-    SYS_LOOKUP_SYMBOL = 19,
-    SYS_STACK_CONTAINS = 20,
-    SYS_AWAIT = 21,
-    SYS_GET_PHYSICAL = 22,
-    SYS_FORK = 23,
-} SyscallIds;
-
-extern uint32_t getFunction(uint32_t module, char *name);
-
-#endif
diff --git a/src/userland/hlib/io.c b/src/userland/hlib/io.c
deleted file mode 100644
index 5a6c3f3..0000000
--- a/src/userland/hlib/io.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <hlib.h>
-#include <syscalls.h>
-
-uint32_t ioIn(uint16_t port, uint8_t size) {
-    return syscall(SYS_IO_IN, size, port, 0, 0);
-}
-
-void ioOut(uint16_t port, uint32_t value, uint8_t size) {
-    syscall(SYS_IO_OUT, size, port, value, 0);
-}
-
-void subscribeInterrupt(uint32_t intNo, void *handler) {
-    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
-}

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}
diff --git a/src/hlib/service/service.c b/src/hlib/service/service.c
new file mode 100644
index 0000000..1669154
--- /dev/null
+++ b/src/hlib/service/service.c
@@ -0,0 +1,39 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
+                 uintptr_t data2) {
+    return syscall(SYS_REQUEST, service, function, data1, data2);
+}
+
+uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
+}
+
+uint32_t getService(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+}
+
+uint32_t getFunction(uint32_t module, char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
+}
+
+uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
+
+uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
+    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
+}
+
+void *getPhysicalAddress(void *source) {
+    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
+               (U32(source) & 0xFFF));
+}
+
+uint32_t fork(void (f)(), void *a, void *b, void *c) {
+    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
+}
+
diff --git a/src/hlib/stdio.c b/src/hlib/stdio.c
new file mode 100644
index 0000000..e717154
--- /dev/null
+++ b/src/hlib/stdio.c
@@ -0,0 +1,207 @@
+#include <hlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+char HEX_CHARS[] = "0123456789ABCDEF";
+
+void putHex(char **write, uintptr_t x) {
+    if (x == 0) {
+        **write = HEX_CHARS[x];
+        (*write)++;
+        **write = HEX_CHARS[x];
+        (*write)++;
+        return;
+    }
+    bool alreadyWriting = false;
+    for (int position = 3; position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            **write = HEX_CHARS[byte >> 4];
+            (*write)++;
+            **write = HEX_CHARS[byte & 0x0F];
+            (*write)++;
+        }
+    }
+}
+
+uint8_t hexLength(uintptr_t x) {
+    bool alreadyWriting = false;
+    uint8_t size = 0;
+    for (int position = sizeof(uintptr_t); position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            size += 2;
+        }
+    }
+    return MAX(size, 2);
+}
+
+uint32_t power(uintptr_t x, uintptr_t y) {
+    uintptr_t result = 1;
+    for (uintptr_t i = 0; i < y; i++) {
+        result *= x;
+    }
+    return result;
+}
+
+uint32_t intLength(intptr_t x) {
+    if (x == 0) {
+        return 1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        if (x / power(10, i) > 0) {
+            return i + 1;
+        }
+    }
+    return 1;
+}
+
+void addChar(char **write, char c) {
+    **write = c;
+    (*write)++;
+}
+
+void putInt(char **write, intptr_t x) {
+    if (x == 0) {
+        addChar(write, '0');
+        return;
+    }
+    if (x < 0) {
+        addChar(write, '-');
+        x *= -1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        uintptr_t n = x / power(10, i);
+        if (n) {
+            addChar(write, HEX_CHARS[n % 10]);
+        }
+    }
+}
+
+void putPadding(char **write, uintptr_t x) {
+    x = MIN(x, 10); // max 10 wide padding
+    for (intptr_t i = 0; i < x; i++) {
+        addChar(write, ' ');
+    }
+}
+
+uint32_t getInsertLength(char insertType, intptr_t x) {
+    switch (insertType) {
+    case 's':
+        return strlen((char *)x);
+    case 'x':
+        return hexLength(x);
+    case 'c':
+        return 1;
+    case 'i':
+        return intLength(x) + (x < 0);
+    case 'p':
+        return x;
+    }
+    return 0;
+}
+
+void stringInsert(char **write, uintptr_t x) {
+    char *string = (char *)x;
+    uint32_t length = strlen(string);
+    for (uint32_t position = 0; position < length; position++) {
+        **write = string[position];
+        (*write)++;
+    }
+}
+
+void handleInsert(char **write, char insertType, uintptr_t x) {
+    switch (insertType) {
+    case 's':
+        stringInsert(write, x);
+        return;
+    case 'x':
+        putHex(write, x);
+        return;
+    case 'c':
+        **write = x;
+        (*write)++;
+        return;
+    case 'i':
+        putInt(write, x);
+        return;
+    case 'p':
+        putPadding(write, x);
+        return;
+    }
+}
+uint32_t ioManager, logFunction;
+
+uint32_t printfSize(const char *format, va_list *valist) {
+    uint32_t size = 0;
+    for (; format[size] != 0; size++) {
+        if (format[size] == '%') {
+            char insertType = format[++size];
+            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
+            continue;
+        }
+    }
+    return size;
+}
+
+void _sprintf(char *data, const char *format, va_list *valist) {
+    char *write = data;
+    for (int i = 0; format[i] != 0; i++) {
+        if (format[i] == '%') {
+            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
+            continue;
+        }
+        *write = format[i];
+        write++;
+    }
+}
+
+void sprintf(char *data, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+}
+
+char *_asprintf(AllocationData allocationData, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    uint32_t size = printfSize(format, &valist);
+    char *data = malloc(size);
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    return data;
+}
+
+void _printf(AllocationData allocationData, const char *format, ...) {
+    // I have absolutely no idea why this line fixes an issue where the first
+    // printf operation consistently doesn't correctly insert its string
+    free(malloc(1));
+    va_list valist;
+    va_start(valist, format);
+    char *data = malloc(printfSize(format, &valist));
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    uintptr_t id = insertString(data);
+    request(ioManager, logFunction, id, 0);
+    discardString(id);
+    free(data);
+}
+
+void gets(char *buffer) {
+    static uint32_t function = 0;
+    if (!function) {
+        function = getFunction(ioManager, "gets");
+    }
+    uint32_t stringId = request(ioManager, function, 0, 0);
+    readString(stringId, buffer);
+}
diff --git a/src/hlib/strings.c b/src/hlib/strings.c
new file mode 100644
index 0000000..78fff55
--- /dev/null
+++ b/src/hlib/strings.c
@@ -0,0 +1,38 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t strlen(char *string) {
+    if (!string) {
+        return 0;
+    }
+    uint32_t size = 0;
+    while (*string) {
+        string++;
+        size++;
+    }
+    return size;
+}
+
+void memcpy(void *from, void *to, uint32_t size) {
+    uint8_t *a = from, *b = to;
+    for (uint32_t i = 0; i < size; i++) {
+        b[i] = a[i];
+    }
+}
+
+uintptr_t insertString(char *string) {
+    return syscall(SYS_INSERT_STRING, U32(string), 0, 0, 0);
+}
+
+uintptr_t getStringLength(uintptr_t stringId) {
+    return syscall(SYS_GET_STRING_LENGTH, stringId, 0, 0, 0);
+}
+
+void readString(uintptr_t stringId, void *buffer) {
+    syscall(SYS_READ_STRING, stringId, U32(buffer), 0, 0);
+}
+
+void discardString(uintptr_t stringId) {
+    syscall(SYS_DISCARD_STRING, stringId, 0, 0, 0);
+}
diff --git a/src/include/hlib.h b/src/include/hlib.h
index a8da877..ed26b16 100644
--- a/src/include/hlib.h
+++ b/src/include/hlib.h
@@ -9,7 +9,7 @@
     void *data;
 } ListElement;
 
-#include "../userland/hlib/malloc.h"
+#include "../hlib/malloc.h"
 
 #define PTR(x) ((void *)(uintptr_t)(x))
 #define U32(x) ((uint32_t)(uintptr_t)(x))
diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile
deleted file mode 100644
index 4870f51..0000000
--- a/src/userland/hlib/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-CC = i686-elf-gcc
-CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
-LD = i686-elf-ld
-LD_FLAGS = -z max-page-size=0x1000 
-AS = nasm
-ASFlAGS = -felf32
-
-BUILD_FOLDER = build
-
-SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
-OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
-
-../../../initrd/hlib: $(OBJS)
-	@echo "linking the honey OS c libary"
-	@$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r
-	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
-
-$(BUILD_FOLDER)/%.asm.o: %.asm
-	@echo "asembling $<"
-	@mkdir -p $(dir $@)
-	@$(AS) $(ASFlAGS) $< -o $@
-
-$(BUILD_FOLDER)/%.c.o: %.c
-	@echo "compiling $<"
-	@mkdir -p $(dir $@)
-	@$(CC) $(CCFLAGS) -r $< -o $@
-
-clean:
-	@echo "clearing build folder"
-	@rm -r $(BUILD_FOLDER)
diff --git a/src/userland/hlib/compile_flags.txt b/src/userland/hlib/compile_flags.txt
deleted file mode 100644
index a432e7b..0000000
--- a/src/userland/hlib/compile_flags.txt
+++ /dev/null
@@ -1,6 +0,0 @@
--I./include
--I../../include
-clang
--fms-extensions
--Wno-microsoft-anon-tag
--Wno-incompatible-library-redeclaration
diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h
deleted file mode 100644
index 2025b24..0000000
--- a/src/userland/hlib/include/syscalls.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef SYSCALLS_H
-#define SYSCALLS_H
-
-#include <stdbool.h>
-#include <stdint.h>
-
-typedef enum {
-    SYS_RUN = 0,
-    SYS_CREATE_FUNCTION = 1,
-    SYS_REQUEST = 2,
-    SYS_IO_IN = 3,
-    SYS_IO_OUT = 4,
-    SYS_LOAD_INITRD = 5,
-    SYS_GET_SERVICE = 6,
-    SYS_GET_FUNCTION = 7,
-    SYS_SUBSCRIBE_INTERRUPT = 8,
-    SYS_CREATE_EVENT = 9,
-    SYS_GET_EVENT = 10,
-    SYS_FIRE_EVENT = 11,
-    SYS_SUBSCRIBE_EVENT = 12,
-    SYS_GET_SERVICE_ID = 13,
-    SYS_INSERT_STRING = 14,
-    SYS_GET_STRING_LENGTH = 15,
-    SYS_READ_STRING = 16,
-    SYS_DISCARD_STRING = 17,
-    SYS_REQUEST_MEMORY = 18,
-    SYS_LOOKUP_SYMBOL = 19,
-    SYS_STACK_CONTAINS = 20,
-    SYS_AWAIT = 21,
-    SYS_GET_PHYSICAL = 22,
-    SYS_FORK = 23,
-} SyscallIds;
-
-extern uint32_t getFunction(uint32_t module, char *name);
-
-#endif
diff --git a/src/userland/hlib/io.c b/src/userland/hlib/io.c
deleted file mode 100644
index 5a6c3f3..0000000
--- a/src/userland/hlib/io.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <hlib.h>
-#include <syscalls.h>
-
-uint32_t ioIn(uint16_t port, uint8_t size) {
-    return syscall(SYS_IO_IN, size, port, 0, 0);
-}
-
-void ioOut(uint16_t port, uint32_t value, uint8_t size) {
-    syscall(SYS_IO_OUT, size, port, value, 0);
-}
-
-void subscribeInterrupt(uint32_t intNo, void *handler) {
-    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
-}
diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld
deleted file mode 100644
index e38b0df..0000000
--- a/src/userland/hlib/link.ld
+++ /dev/null
@@ -1,12 +0,0 @@
-OUTPUT_ARCH(i386)
-
-SECTIONS {
-    . = 0xFF000000;
-
-    .hlib : {
-        *(.text)
-        *(.rodata)
-        *(.data)
-        *(.bss)
-    }
-}

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}
diff --git a/src/hlib/service/service.c b/src/hlib/service/service.c
new file mode 100644
index 0000000..1669154
--- /dev/null
+++ b/src/hlib/service/service.c
@@ -0,0 +1,39 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
+                 uintptr_t data2) {
+    return syscall(SYS_REQUEST, service, function, data1, data2);
+}
+
+uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
+}
+
+uint32_t getService(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+}
+
+uint32_t getFunction(uint32_t module, char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
+}
+
+uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
+
+uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
+    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
+}
+
+void *getPhysicalAddress(void *source) {
+    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
+               (U32(source) & 0xFFF));
+}
+
+uint32_t fork(void (f)(), void *a, void *b, void *c) {
+    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
+}
+
diff --git a/src/hlib/stdio.c b/src/hlib/stdio.c
new file mode 100644
index 0000000..e717154
--- /dev/null
+++ b/src/hlib/stdio.c
@@ -0,0 +1,207 @@
+#include <hlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+char HEX_CHARS[] = "0123456789ABCDEF";
+
+void putHex(char **write, uintptr_t x) {
+    if (x == 0) {
+        **write = HEX_CHARS[x];
+        (*write)++;
+        **write = HEX_CHARS[x];
+        (*write)++;
+        return;
+    }
+    bool alreadyWriting = false;
+    for (int position = 3; position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            **write = HEX_CHARS[byte >> 4];
+            (*write)++;
+            **write = HEX_CHARS[byte & 0x0F];
+            (*write)++;
+        }
+    }
+}
+
+uint8_t hexLength(uintptr_t x) {
+    bool alreadyWriting = false;
+    uint8_t size = 0;
+    for (int position = sizeof(uintptr_t); position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            size += 2;
+        }
+    }
+    return MAX(size, 2);
+}
+
+uint32_t power(uintptr_t x, uintptr_t y) {
+    uintptr_t result = 1;
+    for (uintptr_t i = 0; i < y; i++) {
+        result *= x;
+    }
+    return result;
+}
+
+uint32_t intLength(intptr_t x) {
+    if (x == 0) {
+        return 1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        if (x / power(10, i) > 0) {
+            return i + 1;
+        }
+    }
+    return 1;
+}
+
+void addChar(char **write, char c) {
+    **write = c;
+    (*write)++;
+}
+
+void putInt(char **write, intptr_t x) {
+    if (x == 0) {
+        addChar(write, '0');
+        return;
+    }
+    if (x < 0) {
+        addChar(write, '-');
+        x *= -1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        uintptr_t n = x / power(10, i);
+        if (n) {
+            addChar(write, HEX_CHARS[n % 10]);
+        }
+    }
+}
+
+void putPadding(char **write, uintptr_t x) {
+    x = MIN(x, 10); // max 10 wide padding
+    for (intptr_t i = 0; i < x; i++) {
+        addChar(write, ' ');
+    }
+}
+
+uint32_t getInsertLength(char insertType, intptr_t x) {
+    switch (insertType) {
+    case 's':
+        return strlen((char *)x);
+    case 'x':
+        return hexLength(x);
+    case 'c':
+        return 1;
+    case 'i':
+        return intLength(x) + (x < 0);
+    case 'p':
+        return x;
+    }
+    return 0;
+}
+
+void stringInsert(char **write, uintptr_t x) {
+    char *string = (char *)x;
+    uint32_t length = strlen(string);
+    for (uint32_t position = 0; position < length; position++) {
+        **write = string[position];
+        (*write)++;
+    }
+}
+
+void handleInsert(char **write, char insertType, uintptr_t x) {
+    switch (insertType) {
+    case 's':
+        stringInsert(write, x);
+        return;
+    case 'x':
+        putHex(write, x);
+        return;
+    case 'c':
+        **write = x;
+        (*write)++;
+        return;
+    case 'i':
+        putInt(write, x);
+        return;
+    case 'p':
+        putPadding(write, x);
+        return;
+    }
+}
+uint32_t ioManager, logFunction;
+
+uint32_t printfSize(const char *format, va_list *valist) {
+    uint32_t size = 0;
+    for (; format[size] != 0; size++) {
+        if (format[size] == '%') {
+            char insertType = format[++size];
+            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
+            continue;
+        }
+    }
+    return size;
+}
+
+void _sprintf(char *data, const char *format, va_list *valist) {
+    char *write = data;
+    for (int i = 0; format[i] != 0; i++) {
+        if (format[i] == '%') {
+            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
+            continue;
+        }
+        *write = format[i];
+        write++;
+    }
+}
+
+void sprintf(char *data, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+}
+
+char *_asprintf(AllocationData allocationData, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    uint32_t size = printfSize(format, &valist);
+    char *data = malloc(size);
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    return data;
+}
+
+void _printf(AllocationData allocationData, const char *format, ...) {
+    // I have absolutely no idea why this line fixes an issue where the first
+    // printf operation consistently doesn't correctly insert its string
+    free(malloc(1));
+    va_list valist;
+    va_start(valist, format);
+    char *data = malloc(printfSize(format, &valist));
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    uintptr_t id = insertString(data);
+    request(ioManager, logFunction, id, 0);
+    discardString(id);
+    free(data);
+}
+
+void gets(char *buffer) {
+    static uint32_t function = 0;
+    if (!function) {
+        function = getFunction(ioManager, "gets");
+    }
+    uint32_t stringId = request(ioManager, function, 0, 0);
+    readString(stringId, buffer);
+}
diff --git a/src/hlib/strings.c b/src/hlib/strings.c
new file mode 100644
index 0000000..78fff55
--- /dev/null
+++ b/src/hlib/strings.c
@@ -0,0 +1,38 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t strlen(char *string) {
+    if (!string) {
+        return 0;
+    }
+    uint32_t size = 0;
+    while (*string) {
+        string++;
+        size++;
+    }
+    return size;
+}
+
+void memcpy(void *from, void *to, uint32_t size) {
+    uint8_t *a = from, *b = to;
+    for (uint32_t i = 0; i < size; i++) {
+        b[i] = a[i];
+    }
+}
+
+uintptr_t insertString(char *string) {
+    return syscall(SYS_INSERT_STRING, U32(string), 0, 0, 0);
+}
+
+uintptr_t getStringLength(uintptr_t stringId) {
+    return syscall(SYS_GET_STRING_LENGTH, stringId, 0, 0, 0);
+}
+
+void readString(uintptr_t stringId, void *buffer) {
+    syscall(SYS_READ_STRING, stringId, U32(buffer), 0, 0);
+}
+
+void discardString(uintptr_t stringId) {
+    syscall(SYS_DISCARD_STRING, stringId, 0, 0, 0);
+}
diff --git a/src/include/hlib.h b/src/include/hlib.h
index a8da877..ed26b16 100644
--- a/src/include/hlib.h
+++ b/src/include/hlib.h
@@ -9,7 +9,7 @@
     void *data;
 } ListElement;
 
-#include "../userland/hlib/malloc.h"
+#include "../hlib/malloc.h"
 
 #define PTR(x) ((void *)(uintptr_t)(x))
 #define U32(x) ((uint32_t)(uintptr_t)(x))
diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile
deleted file mode 100644
index 4870f51..0000000
--- a/src/userland/hlib/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-CC = i686-elf-gcc
-CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
-LD = i686-elf-ld
-LD_FLAGS = -z max-page-size=0x1000 
-AS = nasm
-ASFlAGS = -felf32
-
-BUILD_FOLDER = build
-
-SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
-OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
-
-../../../initrd/hlib: $(OBJS)
-	@echo "linking the honey OS c libary"
-	@$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r
-	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
-
-$(BUILD_FOLDER)/%.asm.o: %.asm
-	@echo "asembling $<"
-	@mkdir -p $(dir $@)
-	@$(AS) $(ASFlAGS) $< -o $@
-
-$(BUILD_FOLDER)/%.c.o: %.c
-	@echo "compiling $<"
-	@mkdir -p $(dir $@)
-	@$(CC) $(CCFLAGS) -r $< -o $@
-
-clean:
-	@echo "clearing build folder"
-	@rm -r $(BUILD_FOLDER)
diff --git a/src/userland/hlib/compile_flags.txt b/src/userland/hlib/compile_flags.txt
deleted file mode 100644
index a432e7b..0000000
--- a/src/userland/hlib/compile_flags.txt
+++ /dev/null
@@ -1,6 +0,0 @@
--I./include
--I../../include
-clang
--fms-extensions
--Wno-microsoft-anon-tag
--Wno-incompatible-library-redeclaration
diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h
deleted file mode 100644
index 2025b24..0000000
--- a/src/userland/hlib/include/syscalls.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef SYSCALLS_H
-#define SYSCALLS_H
-
-#include <stdbool.h>
-#include <stdint.h>
-
-typedef enum {
-    SYS_RUN = 0,
-    SYS_CREATE_FUNCTION = 1,
-    SYS_REQUEST = 2,
-    SYS_IO_IN = 3,
-    SYS_IO_OUT = 4,
-    SYS_LOAD_INITRD = 5,
-    SYS_GET_SERVICE = 6,
-    SYS_GET_FUNCTION = 7,
-    SYS_SUBSCRIBE_INTERRUPT = 8,
-    SYS_CREATE_EVENT = 9,
-    SYS_GET_EVENT = 10,
-    SYS_FIRE_EVENT = 11,
-    SYS_SUBSCRIBE_EVENT = 12,
-    SYS_GET_SERVICE_ID = 13,
-    SYS_INSERT_STRING = 14,
-    SYS_GET_STRING_LENGTH = 15,
-    SYS_READ_STRING = 16,
-    SYS_DISCARD_STRING = 17,
-    SYS_REQUEST_MEMORY = 18,
-    SYS_LOOKUP_SYMBOL = 19,
-    SYS_STACK_CONTAINS = 20,
-    SYS_AWAIT = 21,
-    SYS_GET_PHYSICAL = 22,
-    SYS_FORK = 23,
-} SyscallIds;
-
-extern uint32_t getFunction(uint32_t module, char *name);
-
-#endif
diff --git a/src/userland/hlib/io.c b/src/userland/hlib/io.c
deleted file mode 100644
index 5a6c3f3..0000000
--- a/src/userland/hlib/io.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <hlib.h>
-#include <syscalls.h>
-
-uint32_t ioIn(uint16_t port, uint8_t size) {
-    return syscall(SYS_IO_IN, size, port, 0, 0);
-}
-
-void ioOut(uint16_t port, uint32_t value, uint8_t size) {
-    syscall(SYS_IO_OUT, size, port, value, 0);
-}
-
-void subscribeInterrupt(uint32_t intNo, void *handler) {
-    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
-}
diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld
deleted file mode 100644
index e38b0df..0000000
--- a/src/userland/hlib/link.ld
+++ /dev/null
@@ -1,12 +0,0 @@
-OUTPUT_ARCH(i386)
-
-SECTIONS {
-    . = 0xFF000000;
-
-    .hlib : {
-        *(.text)
-        *(.rodata)
-        *(.data)
-        *(.bss)
-    }
-}
diff --git a/src/userland/hlib/list.c b/src/userland/hlib/list.c
deleted file mode 100644
index ffc0ed6..0000000
--- a/src/userland/hlib/list.c
+++ /dev/null
@@ -1,78 +0,0 @@
-#include <hlib.h>
-
-void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
-    ListElement *element = malloc(sizeof(ListElement));
-    element->data = data;
-    element->next = NULL;
-    if (!*list) {
-        *list = element;
-        return;
-    }
-    ListElement *current = *list;
-    while (current->next) {
-        current = current->next;
-    }
-    current->next = element;
-}
-
-void *listPopFirst(ListElement **list) {
-    if (!*list) {
-        return NULL;
-    }
-    ListElement *resultElement = *list;
-    void *result = resultElement->data;
-    *list = (*list)->next;
-    free(resultElement);
-    return result;
-}
-
-uint32_t listCount(ListElement *list) {
-    uint32_t i = 0;
-    foreach (list, void *, element, { i++; })
-        ;
-    return i;
-}
-
-void *listGet(ListElement *list, uint32_t position) {
-    for (uint32_t i = 0; i < position; i++) {
-        list = list->next;
-    }
-    return list->data;
-}
-
-bool listRemoveValue(ListElement **list, void *value) {
-    if (!*list) {
-        return false;
-    }
-    ListElement *element = *list, *previous = NULL;
-    while (element) {
-        if (element->data == value) {
-            if (previous) {
-                previous->next = element->next;
-            } else {
-                *list = element->next;
-            }
-            free(element);
-            return true;
-        }
-        previous = element;
-        element = element->next;
-    }
-    return false;
-}
-
-void listClear(ListElement **list, bool freeData) {
-    ListElement *current = *list;
-    if (!current) {
-        return;
-    }
-    while (current->next) {
-        if (freeData) {
-            free(current->data);
-        }
-        ListElement *next = current->next;
-        free(current);
-        current = next;
-    }
-    *list = NULL;
-}

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}
diff --git a/src/hlib/service/service.c b/src/hlib/service/service.c
new file mode 100644
index 0000000..1669154
--- /dev/null
+++ b/src/hlib/service/service.c
@@ -0,0 +1,39 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
+                 uintptr_t data2) {
+    return syscall(SYS_REQUEST, service, function, data1, data2);
+}
+
+uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
+}
+
+uint32_t getService(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+}
+
+uint32_t getFunction(uint32_t module, char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
+}
+
+uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
+
+uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
+    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
+}
+
+void *getPhysicalAddress(void *source) {
+    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
+               (U32(source) & 0xFFF));
+}
+
+uint32_t fork(void (f)(), void *a, void *b, void *c) {
+    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
+}
+
diff --git a/src/hlib/stdio.c b/src/hlib/stdio.c
new file mode 100644
index 0000000..e717154
--- /dev/null
+++ b/src/hlib/stdio.c
@@ -0,0 +1,207 @@
+#include <hlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+char HEX_CHARS[] = "0123456789ABCDEF";
+
+void putHex(char **write, uintptr_t x) {
+    if (x == 0) {
+        **write = HEX_CHARS[x];
+        (*write)++;
+        **write = HEX_CHARS[x];
+        (*write)++;
+        return;
+    }
+    bool alreadyWriting = false;
+    for (int position = 3; position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            **write = HEX_CHARS[byte >> 4];
+            (*write)++;
+            **write = HEX_CHARS[byte & 0x0F];
+            (*write)++;
+        }
+    }
+}
+
+uint8_t hexLength(uintptr_t x) {
+    bool alreadyWriting = false;
+    uint8_t size = 0;
+    for (int position = sizeof(uintptr_t); position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            size += 2;
+        }
+    }
+    return MAX(size, 2);
+}
+
+uint32_t power(uintptr_t x, uintptr_t y) {
+    uintptr_t result = 1;
+    for (uintptr_t i = 0; i < y; i++) {
+        result *= x;
+    }
+    return result;
+}
+
+uint32_t intLength(intptr_t x) {
+    if (x == 0) {
+        return 1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        if (x / power(10, i) > 0) {
+            return i + 1;
+        }
+    }
+    return 1;
+}
+
+void addChar(char **write, char c) {
+    **write = c;
+    (*write)++;
+}
+
+void putInt(char **write, intptr_t x) {
+    if (x == 0) {
+        addChar(write, '0');
+        return;
+    }
+    if (x < 0) {
+        addChar(write, '-');
+        x *= -1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        uintptr_t n = x / power(10, i);
+        if (n) {
+            addChar(write, HEX_CHARS[n % 10]);
+        }
+    }
+}
+
+void putPadding(char **write, uintptr_t x) {
+    x = MIN(x, 10); // max 10 wide padding
+    for (intptr_t i = 0; i < x; i++) {
+        addChar(write, ' ');
+    }
+}
+
+uint32_t getInsertLength(char insertType, intptr_t x) {
+    switch (insertType) {
+    case 's':
+        return strlen((char *)x);
+    case 'x':
+        return hexLength(x);
+    case 'c':
+        return 1;
+    case 'i':
+        return intLength(x) + (x < 0);
+    case 'p':
+        return x;
+    }
+    return 0;
+}
+
+void stringInsert(char **write, uintptr_t x) {
+    char *string = (char *)x;
+    uint32_t length = strlen(string);
+    for (uint32_t position = 0; position < length; position++) {
+        **write = string[position];
+        (*write)++;
+    }
+}
+
+void handleInsert(char **write, char insertType, uintptr_t x) {
+    switch (insertType) {
+    case 's':
+        stringInsert(write, x);
+        return;
+    case 'x':
+        putHex(write, x);
+        return;
+    case 'c':
+        **write = x;
+        (*write)++;
+        return;
+    case 'i':
+        putInt(write, x);
+        return;
+    case 'p':
+        putPadding(write, x);
+        return;
+    }
+}
+uint32_t ioManager, logFunction;
+
+uint32_t printfSize(const char *format, va_list *valist) {
+    uint32_t size = 0;
+    for (; format[size] != 0; size++) {
+        if (format[size] == '%') {
+            char insertType = format[++size];
+            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
+            continue;
+        }
+    }
+    return size;
+}
+
+void _sprintf(char *data, const char *format, va_list *valist) {
+    char *write = data;
+    for (int i = 0; format[i] != 0; i++) {
+        if (format[i] == '%') {
+            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
+            continue;
+        }
+        *write = format[i];
+        write++;
+    }
+}
+
+void sprintf(char *data, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+}
+
+char *_asprintf(AllocationData allocationData, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    uint32_t size = printfSize(format, &valist);
+    char *data = malloc(size);
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    return data;
+}
+
+void _printf(AllocationData allocationData, const char *format, ...) {
+    // I have absolutely no idea why this line fixes an issue where the first
+    // printf operation consistently doesn't correctly insert its string
+    free(malloc(1));
+    va_list valist;
+    va_start(valist, format);
+    char *data = malloc(printfSize(format, &valist));
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    uintptr_t id = insertString(data);
+    request(ioManager, logFunction, id, 0);
+    discardString(id);
+    free(data);
+}
+
+void gets(char *buffer) {
+    static uint32_t function = 0;
+    if (!function) {
+        function = getFunction(ioManager, "gets");
+    }
+    uint32_t stringId = request(ioManager, function, 0, 0);
+    readString(stringId, buffer);
+}
diff --git a/src/hlib/strings.c b/src/hlib/strings.c
new file mode 100644
index 0000000..78fff55
--- /dev/null
+++ b/src/hlib/strings.c
@@ -0,0 +1,38 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t strlen(char *string) {
+    if (!string) {
+        return 0;
+    }
+    uint32_t size = 0;
+    while (*string) {
+        string++;
+        size++;
+    }
+    return size;
+}
+
+void memcpy(void *from, void *to, uint32_t size) {
+    uint8_t *a = from, *b = to;
+    for (uint32_t i = 0; i < size; i++) {
+        b[i] = a[i];
+    }
+}
+
+uintptr_t insertString(char *string) {
+    return syscall(SYS_INSERT_STRING, U32(string), 0, 0, 0);
+}
+
+uintptr_t getStringLength(uintptr_t stringId) {
+    return syscall(SYS_GET_STRING_LENGTH, stringId, 0, 0, 0);
+}
+
+void readString(uintptr_t stringId, void *buffer) {
+    syscall(SYS_READ_STRING, stringId, U32(buffer), 0, 0);
+}
+
+void discardString(uintptr_t stringId) {
+    syscall(SYS_DISCARD_STRING, stringId, 0, 0, 0);
+}
diff --git a/src/include/hlib.h b/src/include/hlib.h
index a8da877..ed26b16 100644
--- a/src/include/hlib.h
+++ b/src/include/hlib.h
@@ -9,7 +9,7 @@
     void *data;
 } ListElement;
 
-#include "../userland/hlib/malloc.h"
+#include "../hlib/malloc.h"
 
 #define PTR(x) ((void *)(uintptr_t)(x))
 #define U32(x) ((uint32_t)(uintptr_t)(x))
diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile
deleted file mode 100644
index 4870f51..0000000
--- a/src/userland/hlib/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-CC = i686-elf-gcc
-CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
-LD = i686-elf-ld
-LD_FLAGS = -z max-page-size=0x1000 
-AS = nasm
-ASFlAGS = -felf32
-
-BUILD_FOLDER = build
-
-SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
-OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
-
-../../../initrd/hlib: $(OBJS)
-	@echo "linking the honey OS c libary"
-	@$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r
-	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
-
-$(BUILD_FOLDER)/%.asm.o: %.asm
-	@echo "asembling $<"
-	@mkdir -p $(dir $@)
-	@$(AS) $(ASFlAGS) $< -o $@
-
-$(BUILD_FOLDER)/%.c.o: %.c
-	@echo "compiling $<"
-	@mkdir -p $(dir $@)
-	@$(CC) $(CCFLAGS) -r $< -o $@
-
-clean:
-	@echo "clearing build folder"
-	@rm -r $(BUILD_FOLDER)
diff --git a/src/userland/hlib/compile_flags.txt b/src/userland/hlib/compile_flags.txt
deleted file mode 100644
index a432e7b..0000000
--- a/src/userland/hlib/compile_flags.txt
+++ /dev/null
@@ -1,6 +0,0 @@
--I./include
--I../../include
-clang
--fms-extensions
--Wno-microsoft-anon-tag
--Wno-incompatible-library-redeclaration
diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h
deleted file mode 100644
index 2025b24..0000000
--- a/src/userland/hlib/include/syscalls.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef SYSCALLS_H
-#define SYSCALLS_H
-
-#include <stdbool.h>
-#include <stdint.h>
-
-typedef enum {
-    SYS_RUN = 0,
-    SYS_CREATE_FUNCTION = 1,
-    SYS_REQUEST = 2,
-    SYS_IO_IN = 3,
-    SYS_IO_OUT = 4,
-    SYS_LOAD_INITRD = 5,
-    SYS_GET_SERVICE = 6,
-    SYS_GET_FUNCTION = 7,
-    SYS_SUBSCRIBE_INTERRUPT = 8,
-    SYS_CREATE_EVENT = 9,
-    SYS_GET_EVENT = 10,
-    SYS_FIRE_EVENT = 11,
-    SYS_SUBSCRIBE_EVENT = 12,
-    SYS_GET_SERVICE_ID = 13,
-    SYS_INSERT_STRING = 14,
-    SYS_GET_STRING_LENGTH = 15,
-    SYS_READ_STRING = 16,
-    SYS_DISCARD_STRING = 17,
-    SYS_REQUEST_MEMORY = 18,
-    SYS_LOOKUP_SYMBOL = 19,
-    SYS_STACK_CONTAINS = 20,
-    SYS_AWAIT = 21,
-    SYS_GET_PHYSICAL = 22,
-    SYS_FORK = 23,
-} SyscallIds;
-
-extern uint32_t getFunction(uint32_t module, char *name);
-
-#endif
diff --git a/src/userland/hlib/io.c b/src/userland/hlib/io.c
deleted file mode 100644
index 5a6c3f3..0000000
--- a/src/userland/hlib/io.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <hlib.h>
-#include <syscalls.h>
-
-uint32_t ioIn(uint16_t port, uint8_t size) {
-    return syscall(SYS_IO_IN, size, port, 0, 0);
-}
-
-void ioOut(uint16_t port, uint32_t value, uint8_t size) {
-    syscall(SYS_IO_OUT, size, port, value, 0);
-}
-
-void subscribeInterrupt(uint32_t intNo, void *handler) {
-    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
-}
diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld
deleted file mode 100644
index e38b0df..0000000
--- a/src/userland/hlib/link.ld
+++ /dev/null
@@ -1,12 +0,0 @@
-OUTPUT_ARCH(i386)
-
-SECTIONS {
-    . = 0xFF000000;
-
-    .hlib : {
-        *(.text)
-        *(.rodata)
-        *(.data)
-        *(.bss)
-    }
-}
diff --git a/src/userland/hlib/list.c b/src/userland/hlib/list.c
deleted file mode 100644
index ffc0ed6..0000000
--- a/src/userland/hlib/list.c
+++ /dev/null
@@ -1,78 +0,0 @@
-#include <hlib.h>
-
-void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
-    ListElement *element = malloc(sizeof(ListElement));
-    element->data = data;
-    element->next = NULL;
-    if (!*list) {
-        *list = element;
-        return;
-    }
-    ListElement *current = *list;
-    while (current->next) {
-        current = current->next;
-    }
-    current->next = element;
-}
-
-void *listPopFirst(ListElement **list) {
-    if (!*list) {
-        return NULL;
-    }
-    ListElement *resultElement = *list;
-    void *result = resultElement->data;
-    *list = (*list)->next;
-    free(resultElement);
-    return result;
-}
-
-uint32_t listCount(ListElement *list) {
-    uint32_t i = 0;
-    foreach (list, void *, element, { i++; })
-        ;
-    return i;
-}
-
-void *listGet(ListElement *list, uint32_t position) {
-    for (uint32_t i = 0; i < position; i++) {
-        list = list->next;
-    }
-    return list->data;
-}
-
-bool listRemoveValue(ListElement **list, void *value) {
-    if (!*list) {
-        return false;
-    }
-    ListElement *element = *list, *previous = NULL;
-    while (element) {
-        if (element->data == value) {
-            if (previous) {
-                previous->next = element->next;
-            } else {
-                *list = element->next;
-            }
-            free(element);
-            return true;
-        }
-        previous = element;
-        element = element->next;
-    }
-    return false;
-}
-
-void listClear(ListElement **list, bool freeData) {
-    ListElement *current = *list;
-    if (!current) {
-        return;
-    }
-    while (current->next) {
-        if (freeData) {
-            free(current->data);
-        }
-        ListElement *next = current->next;
-        free(current);
-        current = next;
-    }
-    *list = NULL;
-}
diff --git a/src/userland/hlib/main.c b/src/userland/hlib/main.c
deleted file mode 100644
index 43ac97d..0000000
--- a/src/userland/hlib/main.c
+++ /dev/null
@@ -1,84 +0,0 @@
-#include "include/syscalls.h"
-#include <hlib.h>
-#include <stdint.h>
-
-uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
-                 uint32_t parameter2, uint32_t parameter3) {
-    uint32_t esp;
-    asm("push %%eax" ::"a"(&&end)); // end: return address
-    asm("mov %%esp, %%eax" : "=a"(esp));
-    asm("sysenter\n"
-        :
-        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
-          "S"(parameter3), "D"(esp));
-// eax is set by the kernel as the return value
-end:
-    // the 0x1C comes from the number of parameters / local variables do handle
-    // this function with care or it will break everything
-    asm("add $0x1C, %%esp\n"
-        "pop %%ebp\n"
-        "ret" ::);
-    // don't go here! ret returns with the correct value
-    return 0;
-}
-
-uint32_t loadFromInitrd(char *name) {
-    uintptr_t id = insertString(name);
-    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
-    if (!service) {
-        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
-    }
-    return service;
-}
-
-uint32_t loadFromInitrdUninitialized(char *name) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
-}
-
-void requestName(char *service, char *provider, uintptr_t data1,
-                 uintptr_t data2) {
-    uint32_t serviceId = getService(service);
-    uint32_t providerId = getFunction(serviceId, provider);
-    request(serviceId, providerId, data1, data2);
-}
-
-void *requestMemory(uint32_t pageCount, void *targetAddress,
-                    void *physicalAddress) {
-    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
-                       U32(physicalAddress), 0));
-}
-
-void *getPage() { return requestMemory(1, NULL, NULL); }
-
-void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
-
-void freePage(void *location) {}
-
-void memset(void *_target, uint8_t byte, uint32_t size) {
-    uint8_t *target = _target;
-    for (uint32_t i = 0; i < size; i++) {
-        *target = byte;
-        target++;
-    }
-}
-
-bool stackContains(uint32_t serviceId) {
-    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
-}
-
-#define REQUEST1(returnType, functionName, service, function)                  \
-    returnType functionName(uint32_t data) {                                   \
-        static uint32_t serviceId = 0;                                         \
-        if (!serviceId) {                                                      \
-            serviceId = getService(service);                                   \
-            serviceId = getService(service);                                   \
-        }                                                                      \
-        static uint32_t functionId = 0;                                        \
-        if (!functionId) {                                                     \
-            functionId = getFunction(serviceId, function);                     \
-        }                                                                      \
-        return (returnType)request(serviceId, functionId, data, 0);            \
-    }
-
-REQUEST1(void, sleep, "pit", "sleep")

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}
diff --git a/src/hlib/service/service.c b/src/hlib/service/service.c
new file mode 100644
index 0000000..1669154
--- /dev/null
+++ b/src/hlib/service/service.c
@@ -0,0 +1,39 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
+                 uintptr_t data2) {
+    return syscall(SYS_REQUEST, service, function, data1, data2);
+}
+
+uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
+}
+
+uint32_t getService(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+}
+
+uint32_t getFunction(uint32_t module, char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
+}
+
+uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
+
+uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
+    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
+}
+
+void *getPhysicalAddress(void *source) {
+    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
+               (U32(source) & 0xFFF));
+}
+
+uint32_t fork(void (f)(), void *a, void *b, void *c) {
+    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
+}
+
diff --git a/src/hlib/stdio.c b/src/hlib/stdio.c
new file mode 100644
index 0000000..e717154
--- /dev/null
+++ b/src/hlib/stdio.c
@@ -0,0 +1,207 @@
+#include <hlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+char HEX_CHARS[] = "0123456789ABCDEF";
+
+void putHex(char **write, uintptr_t x) {
+    if (x == 0) {
+        **write = HEX_CHARS[x];
+        (*write)++;
+        **write = HEX_CHARS[x];
+        (*write)++;
+        return;
+    }
+    bool alreadyWriting = false;
+    for (int position = 3; position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            **write = HEX_CHARS[byte >> 4];
+            (*write)++;
+            **write = HEX_CHARS[byte & 0x0F];
+            (*write)++;
+        }
+    }
+}
+
+uint8_t hexLength(uintptr_t x) {
+    bool alreadyWriting = false;
+    uint8_t size = 0;
+    for (int position = sizeof(uintptr_t); position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            size += 2;
+        }
+    }
+    return MAX(size, 2);
+}
+
+uint32_t power(uintptr_t x, uintptr_t y) {
+    uintptr_t result = 1;
+    for (uintptr_t i = 0; i < y; i++) {
+        result *= x;
+    }
+    return result;
+}
+
+uint32_t intLength(intptr_t x) {
+    if (x == 0) {
+        return 1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        if (x / power(10, i) > 0) {
+            return i + 1;
+        }
+    }
+    return 1;
+}
+
+void addChar(char **write, char c) {
+    **write = c;
+    (*write)++;
+}
+
+void putInt(char **write, intptr_t x) {
+    if (x == 0) {
+        addChar(write, '0');
+        return;
+    }
+    if (x < 0) {
+        addChar(write, '-');
+        x *= -1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        uintptr_t n = x / power(10, i);
+        if (n) {
+            addChar(write, HEX_CHARS[n % 10]);
+        }
+    }
+}
+
+void putPadding(char **write, uintptr_t x) {
+    x = MIN(x, 10); // max 10 wide padding
+    for (intptr_t i = 0; i < x; i++) {
+        addChar(write, ' ');
+    }
+}
+
+uint32_t getInsertLength(char insertType, intptr_t x) {
+    switch (insertType) {
+    case 's':
+        return strlen((char *)x);
+    case 'x':
+        return hexLength(x);
+    case 'c':
+        return 1;
+    case 'i':
+        return intLength(x) + (x < 0);
+    case 'p':
+        return x;
+    }
+    return 0;
+}
+
+void stringInsert(char **write, uintptr_t x) {
+    char *string = (char *)x;
+    uint32_t length = strlen(string);
+    for (uint32_t position = 0; position < length; position++) {
+        **write = string[position];
+        (*write)++;
+    }
+}
+
+void handleInsert(char **write, char insertType, uintptr_t x) {
+    switch (insertType) {
+    case 's':
+        stringInsert(write, x);
+        return;
+    case 'x':
+        putHex(write, x);
+        return;
+    case 'c':
+        **write = x;
+        (*write)++;
+        return;
+    case 'i':
+        putInt(write, x);
+        return;
+    case 'p':
+        putPadding(write, x);
+        return;
+    }
+}
+uint32_t ioManager, logFunction;
+
+uint32_t printfSize(const char *format, va_list *valist) {
+    uint32_t size = 0;
+    for (; format[size] != 0; size++) {
+        if (format[size] == '%') {
+            char insertType = format[++size];
+            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
+            continue;
+        }
+    }
+    return size;
+}
+
+void _sprintf(char *data, const char *format, va_list *valist) {
+    char *write = data;
+    for (int i = 0; format[i] != 0; i++) {
+        if (format[i] == '%') {
+            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
+            continue;
+        }
+        *write = format[i];
+        write++;
+    }
+}
+
+void sprintf(char *data, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+}
+
+char *_asprintf(AllocationData allocationData, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    uint32_t size = printfSize(format, &valist);
+    char *data = malloc(size);
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    return data;
+}
+
+void _printf(AllocationData allocationData, const char *format, ...) {
+    // I have absolutely no idea why this line fixes an issue where the first
+    // printf operation consistently doesn't correctly insert its string
+    free(malloc(1));
+    va_list valist;
+    va_start(valist, format);
+    char *data = malloc(printfSize(format, &valist));
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    uintptr_t id = insertString(data);
+    request(ioManager, logFunction, id, 0);
+    discardString(id);
+    free(data);
+}
+
+void gets(char *buffer) {
+    static uint32_t function = 0;
+    if (!function) {
+        function = getFunction(ioManager, "gets");
+    }
+    uint32_t stringId = request(ioManager, function, 0, 0);
+    readString(stringId, buffer);
+}
diff --git a/src/hlib/strings.c b/src/hlib/strings.c
new file mode 100644
index 0000000..78fff55
--- /dev/null
+++ b/src/hlib/strings.c
@@ -0,0 +1,38 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t strlen(char *string) {
+    if (!string) {
+        return 0;
+    }
+    uint32_t size = 0;
+    while (*string) {
+        string++;
+        size++;
+    }
+    return size;
+}
+
+void memcpy(void *from, void *to, uint32_t size) {
+    uint8_t *a = from, *b = to;
+    for (uint32_t i = 0; i < size; i++) {
+        b[i] = a[i];
+    }
+}
+
+uintptr_t insertString(char *string) {
+    return syscall(SYS_INSERT_STRING, U32(string), 0, 0, 0);
+}
+
+uintptr_t getStringLength(uintptr_t stringId) {
+    return syscall(SYS_GET_STRING_LENGTH, stringId, 0, 0, 0);
+}
+
+void readString(uintptr_t stringId, void *buffer) {
+    syscall(SYS_READ_STRING, stringId, U32(buffer), 0, 0);
+}
+
+void discardString(uintptr_t stringId) {
+    syscall(SYS_DISCARD_STRING, stringId, 0, 0, 0);
+}
diff --git a/src/include/hlib.h b/src/include/hlib.h
index a8da877..ed26b16 100644
--- a/src/include/hlib.h
+++ b/src/include/hlib.h
@@ -9,7 +9,7 @@
     void *data;
 } ListElement;
 
-#include "../userland/hlib/malloc.h"
+#include "../hlib/malloc.h"
 
 #define PTR(x) ((void *)(uintptr_t)(x))
 #define U32(x) ((uint32_t)(uintptr_t)(x))
diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile
deleted file mode 100644
index 4870f51..0000000
--- a/src/userland/hlib/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-CC = i686-elf-gcc
-CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
-LD = i686-elf-ld
-LD_FLAGS = -z max-page-size=0x1000 
-AS = nasm
-ASFlAGS = -felf32
-
-BUILD_FOLDER = build
-
-SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
-OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
-
-../../../initrd/hlib: $(OBJS)
-	@echo "linking the honey OS c libary"
-	@$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r
-	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
-
-$(BUILD_FOLDER)/%.asm.o: %.asm
-	@echo "asembling $<"
-	@mkdir -p $(dir $@)
-	@$(AS) $(ASFlAGS) $< -o $@
-
-$(BUILD_FOLDER)/%.c.o: %.c
-	@echo "compiling $<"
-	@mkdir -p $(dir $@)
-	@$(CC) $(CCFLAGS) -r $< -o $@
-
-clean:
-	@echo "clearing build folder"
-	@rm -r $(BUILD_FOLDER)
diff --git a/src/userland/hlib/compile_flags.txt b/src/userland/hlib/compile_flags.txt
deleted file mode 100644
index a432e7b..0000000
--- a/src/userland/hlib/compile_flags.txt
+++ /dev/null
@@ -1,6 +0,0 @@
--I./include
--I../../include
-clang
--fms-extensions
--Wno-microsoft-anon-tag
--Wno-incompatible-library-redeclaration
diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h
deleted file mode 100644
index 2025b24..0000000
--- a/src/userland/hlib/include/syscalls.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef SYSCALLS_H
-#define SYSCALLS_H
-
-#include <stdbool.h>
-#include <stdint.h>
-
-typedef enum {
-    SYS_RUN = 0,
-    SYS_CREATE_FUNCTION = 1,
-    SYS_REQUEST = 2,
-    SYS_IO_IN = 3,
-    SYS_IO_OUT = 4,
-    SYS_LOAD_INITRD = 5,
-    SYS_GET_SERVICE = 6,
-    SYS_GET_FUNCTION = 7,
-    SYS_SUBSCRIBE_INTERRUPT = 8,
-    SYS_CREATE_EVENT = 9,
-    SYS_GET_EVENT = 10,
-    SYS_FIRE_EVENT = 11,
-    SYS_SUBSCRIBE_EVENT = 12,
-    SYS_GET_SERVICE_ID = 13,
-    SYS_INSERT_STRING = 14,
-    SYS_GET_STRING_LENGTH = 15,
-    SYS_READ_STRING = 16,
-    SYS_DISCARD_STRING = 17,
-    SYS_REQUEST_MEMORY = 18,
-    SYS_LOOKUP_SYMBOL = 19,
-    SYS_STACK_CONTAINS = 20,
-    SYS_AWAIT = 21,
-    SYS_GET_PHYSICAL = 22,
-    SYS_FORK = 23,
-} SyscallIds;
-
-extern uint32_t getFunction(uint32_t module, char *name);
-
-#endif
diff --git a/src/userland/hlib/io.c b/src/userland/hlib/io.c
deleted file mode 100644
index 5a6c3f3..0000000
--- a/src/userland/hlib/io.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <hlib.h>
-#include <syscalls.h>
-
-uint32_t ioIn(uint16_t port, uint8_t size) {
-    return syscall(SYS_IO_IN, size, port, 0, 0);
-}
-
-void ioOut(uint16_t port, uint32_t value, uint8_t size) {
-    syscall(SYS_IO_OUT, size, port, value, 0);
-}
-
-void subscribeInterrupt(uint32_t intNo, void *handler) {
-    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
-}
diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld
deleted file mode 100644
index e38b0df..0000000
--- a/src/userland/hlib/link.ld
+++ /dev/null
@@ -1,12 +0,0 @@
-OUTPUT_ARCH(i386)
-
-SECTIONS {
-    . = 0xFF000000;
-
-    .hlib : {
-        *(.text)
-        *(.rodata)
-        *(.data)
-        *(.bss)
-    }
-}
diff --git a/src/userland/hlib/list.c b/src/userland/hlib/list.c
deleted file mode 100644
index ffc0ed6..0000000
--- a/src/userland/hlib/list.c
+++ /dev/null
@@ -1,78 +0,0 @@
-#include <hlib.h>
-
-void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
-    ListElement *element = malloc(sizeof(ListElement));
-    element->data = data;
-    element->next = NULL;
-    if (!*list) {
-        *list = element;
-        return;
-    }
-    ListElement *current = *list;
-    while (current->next) {
-        current = current->next;
-    }
-    current->next = element;
-}
-
-void *listPopFirst(ListElement **list) {
-    if (!*list) {
-        return NULL;
-    }
-    ListElement *resultElement = *list;
-    void *result = resultElement->data;
-    *list = (*list)->next;
-    free(resultElement);
-    return result;
-}
-
-uint32_t listCount(ListElement *list) {
-    uint32_t i = 0;
-    foreach (list, void *, element, { i++; })
-        ;
-    return i;
-}
-
-void *listGet(ListElement *list, uint32_t position) {
-    for (uint32_t i = 0; i < position; i++) {
-        list = list->next;
-    }
-    return list->data;
-}
-
-bool listRemoveValue(ListElement **list, void *value) {
-    if (!*list) {
-        return false;
-    }
-    ListElement *element = *list, *previous = NULL;
-    while (element) {
-        if (element->data == value) {
-            if (previous) {
-                previous->next = element->next;
-            } else {
-                *list = element->next;
-            }
-            free(element);
-            return true;
-        }
-        previous = element;
-        element = element->next;
-    }
-    return false;
-}
-
-void listClear(ListElement **list, bool freeData) {
-    ListElement *current = *list;
-    if (!current) {
-        return;
-    }
-    while (current->next) {
-        if (freeData) {
-            free(current->data);
-        }
-        ListElement *next = current->next;
-        free(current);
-        current = next;
-    }
-    *list = NULL;
-}
diff --git a/src/userland/hlib/main.c b/src/userland/hlib/main.c
deleted file mode 100644
index 43ac97d..0000000
--- a/src/userland/hlib/main.c
+++ /dev/null
@@ -1,84 +0,0 @@
-#include "include/syscalls.h"
-#include <hlib.h>
-#include <stdint.h>
-
-uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
-                 uint32_t parameter2, uint32_t parameter3) {
-    uint32_t esp;
-    asm("push %%eax" ::"a"(&&end)); // end: return address
-    asm("mov %%esp, %%eax" : "=a"(esp));
-    asm("sysenter\n"
-        :
-        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
-          "S"(parameter3), "D"(esp));
-// eax is set by the kernel as the return value
-end:
-    // the 0x1C comes from the number of parameters / local variables do handle
-    // this function with care or it will break everything
-    asm("add $0x1C, %%esp\n"
-        "pop %%ebp\n"
-        "ret" ::);
-    // don't go here! ret returns with the correct value
-    return 0;
-}
-
-uint32_t loadFromInitrd(char *name) {
-    uintptr_t id = insertString(name);
-    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
-    if (!service) {
-        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
-    }
-    return service;
-}
-
-uint32_t loadFromInitrdUninitialized(char *name) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
-}
-
-void requestName(char *service, char *provider, uintptr_t data1,
-                 uintptr_t data2) {
-    uint32_t serviceId = getService(service);
-    uint32_t providerId = getFunction(serviceId, provider);
-    request(serviceId, providerId, data1, data2);
-}
-
-void *requestMemory(uint32_t pageCount, void *targetAddress,
-                    void *physicalAddress) {
-    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
-                       U32(physicalAddress), 0));
-}
-
-void *getPage() { return requestMemory(1, NULL, NULL); }
-
-void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
-
-void freePage(void *location) {}
-
-void memset(void *_target, uint8_t byte, uint32_t size) {
-    uint8_t *target = _target;
-    for (uint32_t i = 0; i < size; i++) {
-        *target = byte;
-        target++;
-    }
-}
-
-bool stackContains(uint32_t serviceId) {
-    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
-}
-
-#define REQUEST1(returnType, functionName, service, function)                  \
-    returnType functionName(uint32_t data) {                                   \
-        static uint32_t serviceId = 0;                                         \
-        if (!serviceId) {                                                      \
-            serviceId = getService(service);                                   \
-            serviceId = getService(service);                                   \
-        }                                                                      \
-        static uint32_t functionId = 0;                                        \
-        if (!functionId) {                                                     \
-            functionId = getFunction(serviceId, function);                     \
-        }                                                                      \
-        return (returnType)request(serviceId, functionId, data, 0);            \
-    }
-
-REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/userland/hlib/malloc.c b/src/userland/hlib/malloc.c
deleted file mode 120000
index 022d82b..0000000
--- a/src/userland/hlib/malloc.c
+++ /dev/null
@@ -1 +0,0 @@
-../../kernel/memory/malloc.c
\ No newline at end of file

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}
diff --git a/src/hlib/service/service.c b/src/hlib/service/service.c
new file mode 100644
index 0000000..1669154
--- /dev/null
+++ b/src/hlib/service/service.c
@@ -0,0 +1,39 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
+                 uintptr_t data2) {
+    return syscall(SYS_REQUEST, service, function, data1, data2);
+}
+
+uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
+}
+
+uint32_t getService(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+}
+
+uint32_t getFunction(uint32_t module, char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
+}
+
+uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
+
+uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
+    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
+}
+
+void *getPhysicalAddress(void *source) {
+    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
+               (U32(source) & 0xFFF));
+}
+
+uint32_t fork(void (f)(), void *a, void *b, void *c) {
+    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
+}
+
diff --git a/src/hlib/stdio.c b/src/hlib/stdio.c
new file mode 100644
index 0000000..e717154
--- /dev/null
+++ b/src/hlib/stdio.c
@@ -0,0 +1,207 @@
+#include <hlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+char HEX_CHARS[] = "0123456789ABCDEF";
+
+void putHex(char **write, uintptr_t x) {
+    if (x == 0) {
+        **write = HEX_CHARS[x];
+        (*write)++;
+        **write = HEX_CHARS[x];
+        (*write)++;
+        return;
+    }
+    bool alreadyWriting = false;
+    for (int position = 3; position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            **write = HEX_CHARS[byte >> 4];
+            (*write)++;
+            **write = HEX_CHARS[byte & 0x0F];
+            (*write)++;
+        }
+    }
+}
+
+uint8_t hexLength(uintptr_t x) {
+    bool alreadyWriting = false;
+    uint8_t size = 0;
+    for (int position = sizeof(uintptr_t); position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            size += 2;
+        }
+    }
+    return MAX(size, 2);
+}
+
+uint32_t power(uintptr_t x, uintptr_t y) {
+    uintptr_t result = 1;
+    for (uintptr_t i = 0; i < y; i++) {
+        result *= x;
+    }
+    return result;
+}
+
+uint32_t intLength(intptr_t x) {
+    if (x == 0) {
+        return 1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        if (x / power(10, i) > 0) {
+            return i + 1;
+        }
+    }
+    return 1;
+}
+
+void addChar(char **write, char c) {
+    **write = c;
+    (*write)++;
+}
+
+void putInt(char **write, intptr_t x) {
+    if (x == 0) {
+        addChar(write, '0');
+        return;
+    }
+    if (x < 0) {
+        addChar(write, '-');
+        x *= -1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        uintptr_t n = x / power(10, i);
+        if (n) {
+            addChar(write, HEX_CHARS[n % 10]);
+        }
+    }
+}
+
+void putPadding(char **write, uintptr_t x) {
+    x = MIN(x, 10); // max 10 wide padding
+    for (intptr_t i = 0; i < x; i++) {
+        addChar(write, ' ');
+    }
+}
+
+uint32_t getInsertLength(char insertType, intptr_t x) {
+    switch (insertType) {
+    case 's':
+        return strlen((char *)x);
+    case 'x':
+        return hexLength(x);
+    case 'c':
+        return 1;
+    case 'i':
+        return intLength(x) + (x < 0);
+    case 'p':
+        return x;
+    }
+    return 0;
+}
+
+void stringInsert(char **write, uintptr_t x) {
+    char *string = (char *)x;
+    uint32_t length = strlen(string);
+    for (uint32_t position = 0; position < length; position++) {
+        **write = string[position];
+        (*write)++;
+    }
+}
+
+void handleInsert(char **write, char insertType, uintptr_t x) {
+    switch (insertType) {
+    case 's':
+        stringInsert(write, x);
+        return;
+    case 'x':
+        putHex(write, x);
+        return;
+    case 'c':
+        **write = x;
+        (*write)++;
+        return;
+    case 'i':
+        putInt(write, x);
+        return;
+    case 'p':
+        putPadding(write, x);
+        return;
+    }
+}
+uint32_t ioManager, logFunction;
+
+uint32_t printfSize(const char *format, va_list *valist) {
+    uint32_t size = 0;
+    for (; format[size] != 0; size++) {
+        if (format[size] == '%') {
+            char insertType = format[++size];
+            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
+            continue;
+        }
+    }
+    return size;
+}
+
+void _sprintf(char *data, const char *format, va_list *valist) {
+    char *write = data;
+    for (int i = 0; format[i] != 0; i++) {
+        if (format[i] == '%') {
+            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
+            continue;
+        }
+        *write = format[i];
+        write++;
+    }
+}
+
+void sprintf(char *data, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+}
+
+char *_asprintf(AllocationData allocationData, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    uint32_t size = printfSize(format, &valist);
+    char *data = malloc(size);
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    return data;
+}
+
+void _printf(AllocationData allocationData, const char *format, ...) {
+    // I have absolutely no idea why this line fixes an issue where the first
+    // printf operation consistently doesn't correctly insert its string
+    free(malloc(1));
+    va_list valist;
+    va_start(valist, format);
+    char *data = malloc(printfSize(format, &valist));
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    uintptr_t id = insertString(data);
+    request(ioManager, logFunction, id, 0);
+    discardString(id);
+    free(data);
+}
+
+void gets(char *buffer) {
+    static uint32_t function = 0;
+    if (!function) {
+        function = getFunction(ioManager, "gets");
+    }
+    uint32_t stringId = request(ioManager, function, 0, 0);
+    readString(stringId, buffer);
+}
diff --git a/src/hlib/strings.c b/src/hlib/strings.c
new file mode 100644
index 0000000..78fff55
--- /dev/null
+++ b/src/hlib/strings.c
@@ -0,0 +1,38 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t strlen(char *string) {
+    if (!string) {
+        return 0;
+    }
+    uint32_t size = 0;
+    while (*string) {
+        string++;
+        size++;
+    }
+    return size;
+}
+
+void memcpy(void *from, void *to, uint32_t size) {
+    uint8_t *a = from, *b = to;
+    for (uint32_t i = 0; i < size; i++) {
+        b[i] = a[i];
+    }
+}
+
+uintptr_t insertString(char *string) {
+    return syscall(SYS_INSERT_STRING, U32(string), 0, 0, 0);
+}
+
+uintptr_t getStringLength(uintptr_t stringId) {
+    return syscall(SYS_GET_STRING_LENGTH, stringId, 0, 0, 0);
+}
+
+void readString(uintptr_t stringId, void *buffer) {
+    syscall(SYS_READ_STRING, stringId, U32(buffer), 0, 0);
+}
+
+void discardString(uintptr_t stringId) {
+    syscall(SYS_DISCARD_STRING, stringId, 0, 0, 0);
+}
diff --git a/src/include/hlib.h b/src/include/hlib.h
index a8da877..ed26b16 100644
--- a/src/include/hlib.h
+++ b/src/include/hlib.h
@@ -9,7 +9,7 @@
     void *data;
 } ListElement;
 
-#include "../userland/hlib/malloc.h"
+#include "../hlib/malloc.h"
 
 #define PTR(x) ((void *)(uintptr_t)(x))
 #define U32(x) ((uint32_t)(uintptr_t)(x))
diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile
deleted file mode 100644
index 4870f51..0000000
--- a/src/userland/hlib/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-CC = i686-elf-gcc
-CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
-LD = i686-elf-ld
-LD_FLAGS = -z max-page-size=0x1000 
-AS = nasm
-ASFlAGS = -felf32
-
-BUILD_FOLDER = build
-
-SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
-OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
-
-../../../initrd/hlib: $(OBJS)
-	@echo "linking the honey OS c libary"
-	@$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r
-	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
-
-$(BUILD_FOLDER)/%.asm.o: %.asm
-	@echo "asembling $<"
-	@mkdir -p $(dir $@)
-	@$(AS) $(ASFlAGS) $< -o $@
-
-$(BUILD_FOLDER)/%.c.o: %.c
-	@echo "compiling $<"
-	@mkdir -p $(dir $@)
-	@$(CC) $(CCFLAGS) -r $< -o $@
-
-clean:
-	@echo "clearing build folder"
-	@rm -r $(BUILD_FOLDER)
diff --git a/src/userland/hlib/compile_flags.txt b/src/userland/hlib/compile_flags.txt
deleted file mode 100644
index a432e7b..0000000
--- a/src/userland/hlib/compile_flags.txt
+++ /dev/null
@@ -1,6 +0,0 @@
--I./include
--I../../include
-clang
--fms-extensions
--Wno-microsoft-anon-tag
--Wno-incompatible-library-redeclaration
diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h
deleted file mode 100644
index 2025b24..0000000
--- a/src/userland/hlib/include/syscalls.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef SYSCALLS_H
-#define SYSCALLS_H
-
-#include <stdbool.h>
-#include <stdint.h>
-
-typedef enum {
-    SYS_RUN = 0,
-    SYS_CREATE_FUNCTION = 1,
-    SYS_REQUEST = 2,
-    SYS_IO_IN = 3,
-    SYS_IO_OUT = 4,
-    SYS_LOAD_INITRD = 5,
-    SYS_GET_SERVICE = 6,
-    SYS_GET_FUNCTION = 7,
-    SYS_SUBSCRIBE_INTERRUPT = 8,
-    SYS_CREATE_EVENT = 9,
-    SYS_GET_EVENT = 10,
-    SYS_FIRE_EVENT = 11,
-    SYS_SUBSCRIBE_EVENT = 12,
-    SYS_GET_SERVICE_ID = 13,
-    SYS_INSERT_STRING = 14,
-    SYS_GET_STRING_LENGTH = 15,
-    SYS_READ_STRING = 16,
-    SYS_DISCARD_STRING = 17,
-    SYS_REQUEST_MEMORY = 18,
-    SYS_LOOKUP_SYMBOL = 19,
-    SYS_STACK_CONTAINS = 20,
-    SYS_AWAIT = 21,
-    SYS_GET_PHYSICAL = 22,
-    SYS_FORK = 23,
-} SyscallIds;
-
-extern uint32_t getFunction(uint32_t module, char *name);
-
-#endif
diff --git a/src/userland/hlib/io.c b/src/userland/hlib/io.c
deleted file mode 100644
index 5a6c3f3..0000000
--- a/src/userland/hlib/io.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <hlib.h>
-#include <syscalls.h>
-
-uint32_t ioIn(uint16_t port, uint8_t size) {
-    return syscall(SYS_IO_IN, size, port, 0, 0);
-}
-
-void ioOut(uint16_t port, uint32_t value, uint8_t size) {
-    syscall(SYS_IO_OUT, size, port, value, 0);
-}
-
-void subscribeInterrupt(uint32_t intNo, void *handler) {
-    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
-}
diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld
deleted file mode 100644
index e38b0df..0000000
--- a/src/userland/hlib/link.ld
+++ /dev/null
@@ -1,12 +0,0 @@
-OUTPUT_ARCH(i386)
-
-SECTIONS {
-    . = 0xFF000000;
-
-    .hlib : {
-        *(.text)
-        *(.rodata)
-        *(.data)
-        *(.bss)
-    }
-}
diff --git a/src/userland/hlib/list.c b/src/userland/hlib/list.c
deleted file mode 100644
index ffc0ed6..0000000
--- a/src/userland/hlib/list.c
+++ /dev/null
@@ -1,78 +0,0 @@
-#include <hlib.h>
-
-void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
-    ListElement *element = malloc(sizeof(ListElement));
-    element->data = data;
-    element->next = NULL;
-    if (!*list) {
-        *list = element;
-        return;
-    }
-    ListElement *current = *list;
-    while (current->next) {
-        current = current->next;
-    }
-    current->next = element;
-}
-
-void *listPopFirst(ListElement **list) {
-    if (!*list) {
-        return NULL;
-    }
-    ListElement *resultElement = *list;
-    void *result = resultElement->data;
-    *list = (*list)->next;
-    free(resultElement);
-    return result;
-}
-
-uint32_t listCount(ListElement *list) {
-    uint32_t i = 0;
-    foreach (list, void *, element, { i++; })
-        ;
-    return i;
-}
-
-void *listGet(ListElement *list, uint32_t position) {
-    for (uint32_t i = 0; i < position; i++) {
-        list = list->next;
-    }
-    return list->data;
-}
-
-bool listRemoveValue(ListElement **list, void *value) {
-    if (!*list) {
-        return false;
-    }
-    ListElement *element = *list, *previous = NULL;
-    while (element) {
-        if (element->data == value) {
-            if (previous) {
-                previous->next = element->next;
-            } else {
-                *list = element->next;
-            }
-            free(element);
-            return true;
-        }
-        previous = element;
-        element = element->next;
-    }
-    return false;
-}
-
-void listClear(ListElement **list, bool freeData) {
-    ListElement *current = *list;
-    if (!current) {
-        return;
-    }
-    while (current->next) {
-        if (freeData) {
-            free(current->data);
-        }
-        ListElement *next = current->next;
-        free(current);
-        current = next;
-    }
-    *list = NULL;
-}
diff --git a/src/userland/hlib/main.c b/src/userland/hlib/main.c
deleted file mode 100644
index 43ac97d..0000000
--- a/src/userland/hlib/main.c
+++ /dev/null
@@ -1,84 +0,0 @@
-#include "include/syscalls.h"
-#include <hlib.h>
-#include <stdint.h>
-
-uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
-                 uint32_t parameter2, uint32_t parameter3) {
-    uint32_t esp;
-    asm("push %%eax" ::"a"(&&end)); // end: return address
-    asm("mov %%esp, %%eax" : "=a"(esp));
-    asm("sysenter\n"
-        :
-        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
-          "S"(parameter3), "D"(esp));
-// eax is set by the kernel as the return value
-end:
-    // the 0x1C comes from the number of parameters / local variables do handle
-    // this function with care or it will break everything
-    asm("add $0x1C, %%esp\n"
-        "pop %%ebp\n"
-        "ret" ::);
-    // don't go here! ret returns with the correct value
-    return 0;
-}
-
-uint32_t loadFromInitrd(char *name) {
-    uintptr_t id = insertString(name);
-    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
-    if (!service) {
-        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
-    }
-    return service;
-}
-
-uint32_t loadFromInitrdUninitialized(char *name) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
-}
-
-void requestName(char *service, char *provider, uintptr_t data1,
-                 uintptr_t data2) {
-    uint32_t serviceId = getService(service);
-    uint32_t providerId = getFunction(serviceId, provider);
-    request(serviceId, providerId, data1, data2);
-}
-
-void *requestMemory(uint32_t pageCount, void *targetAddress,
-                    void *physicalAddress) {
-    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
-                       U32(physicalAddress), 0));
-}
-
-void *getPage() { return requestMemory(1, NULL, NULL); }
-
-void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
-
-void freePage(void *location) {}
-
-void memset(void *_target, uint8_t byte, uint32_t size) {
-    uint8_t *target = _target;
-    for (uint32_t i = 0; i < size; i++) {
-        *target = byte;
-        target++;
-    }
-}
-
-bool stackContains(uint32_t serviceId) {
-    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
-}
-
-#define REQUEST1(returnType, functionName, service, function)                  \
-    returnType functionName(uint32_t data) {                                   \
-        static uint32_t serviceId = 0;                                         \
-        if (!serviceId) {                                                      \
-            serviceId = getService(service);                                   \
-            serviceId = getService(service);                                   \
-        }                                                                      \
-        static uint32_t functionId = 0;                                        \
-        if (!functionId) {                                                     \
-            functionId = getFunction(serviceId, function);                     \
-        }                                                                      \
-        return (returnType)request(serviceId, functionId, data, 0);            \
-    }
-
-REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/userland/hlib/malloc.c b/src/userland/hlib/malloc.c
deleted file mode 120000
index 022d82b..0000000
--- a/src/userland/hlib/malloc.c
+++ /dev/null
@@ -1 +0,0 @@
-../../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/userland/hlib/malloc.h b/src/userland/hlib/malloc.h
deleted file mode 120000
index 8a56b0a..0000000
--- a/src/userland/hlib/malloc.h
+++ /dev/null
@@ -1 +0,0 @@
-../../kernel/memory/malloc.h
\ No newline at end of file

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}
diff --git a/src/hlib/service/service.c b/src/hlib/service/service.c
new file mode 100644
index 0000000..1669154
--- /dev/null
+++ b/src/hlib/service/service.c
@@ -0,0 +1,39 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
+                 uintptr_t data2) {
+    return syscall(SYS_REQUEST, service, function, data1, data2);
+}
+
+uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
+}
+
+uint32_t getService(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+}
+
+uint32_t getFunction(uint32_t module, char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
+}
+
+uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
+
+uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
+    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
+}
+
+void *getPhysicalAddress(void *source) {
+    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
+               (U32(source) & 0xFFF));
+}
+
+uint32_t fork(void (f)(), void *a, void *b, void *c) {
+    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
+}
+
diff --git a/src/hlib/stdio.c b/src/hlib/stdio.c
new file mode 100644
index 0000000..e717154
--- /dev/null
+++ b/src/hlib/stdio.c
@@ -0,0 +1,207 @@
+#include <hlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+char HEX_CHARS[] = "0123456789ABCDEF";
+
+void putHex(char **write, uintptr_t x) {
+    if (x == 0) {
+        **write = HEX_CHARS[x];
+        (*write)++;
+        **write = HEX_CHARS[x];
+        (*write)++;
+        return;
+    }
+    bool alreadyWriting = false;
+    for (int position = 3; position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            **write = HEX_CHARS[byte >> 4];
+            (*write)++;
+            **write = HEX_CHARS[byte & 0x0F];
+            (*write)++;
+        }
+    }
+}
+
+uint8_t hexLength(uintptr_t x) {
+    bool alreadyWriting = false;
+    uint8_t size = 0;
+    for (int position = sizeof(uintptr_t); position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            size += 2;
+        }
+    }
+    return MAX(size, 2);
+}
+
+uint32_t power(uintptr_t x, uintptr_t y) {
+    uintptr_t result = 1;
+    for (uintptr_t i = 0; i < y; i++) {
+        result *= x;
+    }
+    return result;
+}
+
+uint32_t intLength(intptr_t x) {
+    if (x == 0) {
+        return 1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        if (x / power(10, i) > 0) {
+            return i + 1;
+        }
+    }
+    return 1;
+}
+
+void addChar(char **write, char c) {
+    **write = c;
+    (*write)++;
+}
+
+void putInt(char **write, intptr_t x) {
+    if (x == 0) {
+        addChar(write, '0');
+        return;
+    }
+    if (x < 0) {
+        addChar(write, '-');
+        x *= -1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        uintptr_t n = x / power(10, i);
+        if (n) {
+            addChar(write, HEX_CHARS[n % 10]);
+        }
+    }
+}
+
+void putPadding(char **write, uintptr_t x) {
+    x = MIN(x, 10); // max 10 wide padding
+    for (intptr_t i = 0; i < x; i++) {
+        addChar(write, ' ');
+    }
+}
+
+uint32_t getInsertLength(char insertType, intptr_t x) {
+    switch (insertType) {
+    case 's':
+        return strlen((char *)x);
+    case 'x':
+        return hexLength(x);
+    case 'c':
+        return 1;
+    case 'i':
+        return intLength(x) + (x < 0);
+    case 'p':
+        return x;
+    }
+    return 0;
+}
+
+void stringInsert(char **write, uintptr_t x) {
+    char *string = (char *)x;
+    uint32_t length = strlen(string);
+    for (uint32_t position = 0; position < length; position++) {
+        **write = string[position];
+        (*write)++;
+    }
+}
+
+void handleInsert(char **write, char insertType, uintptr_t x) {
+    switch (insertType) {
+    case 's':
+        stringInsert(write, x);
+        return;
+    case 'x':
+        putHex(write, x);
+        return;
+    case 'c':
+        **write = x;
+        (*write)++;
+        return;
+    case 'i':
+        putInt(write, x);
+        return;
+    case 'p':
+        putPadding(write, x);
+        return;
+    }
+}
+uint32_t ioManager, logFunction;
+
+uint32_t printfSize(const char *format, va_list *valist) {
+    uint32_t size = 0;
+    for (; format[size] != 0; size++) {
+        if (format[size] == '%') {
+            char insertType = format[++size];
+            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
+            continue;
+        }
+    }
+    return size;
+}
+
+void _sprintf(char *data, const char *format, va_list *valist) {
+    char *write = data;
+    for (int i = 0; format[i] != 0; i++) {
+        if (format[i] == '%') {
+            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
+            continue;
+        }
+        *write = format[i];
+        write++;
+    }
+}
+
+void sprintf(char *data, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+}
+
+char *_asprintf(AllocationData allocationData, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    uint32_t size = printfSize(format, &valist);
+    char *data = malloc(size);
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    return data;
+}
+
+void _printf(AllocationData allocationData, const char *format, ...) {
+    // I have absolutely no idea why this line fixes an issue where the first
+    // printf operation consistently doesn't correctly insert its string
+    free(malloc(1));
+    va_list valist;
+    va_start(valist, format);
+    char *data = malloc(printfSize(format, &valist));
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    uintptr_t id = insertString(data);
+    request(ioManager, logFunction, id, 0);
+    discardString(id);
+    free(data);
+}
+
+void gets(char *buffer) {
+    static uint32_t function = 0;
+    if (!function) {
+        function = getFunction(ioManager, "gets");
+    }
+    uint32_t stringId = request(ioManager, function, 0, 0);
+    readString(stringId, buffer);
+}
diff --git a/src/hlib/strings.c b/src/hlib/strings.c
new file mode 100644
index 0000000..78fff55
--- /dev/null
+++ b/src/hlib/strings.c
@@ -0,0 +1,38 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t strlen(char *string) {
+    if (!string) {
+        return 0;
+    }
+    uint32_t size = 0;
+    while (*string) {
+        string++;
+        size++;
+    }
+    return size;
+}
+
+void memcpy(void *from, void *to, uint32_t size) {
+    uint8_t *a = from, *b = to;
+    for (uint32_t i = 0; i < size; i++) {
+        b[i] = a[i];
+    }
+}
+
+uintptr_t insertString(char *string) {
+    return syscall(SYS_INSERT_STRING, U32(string), 0, 0, 0);
+}
+
+uintptr_t getStringLength(uintptr_t stringId) {
+    return syscall(SYS_GET_STRING_LENGTH, stringId, 0, 0, 0);
+}
+
+void readString(uintptr_t stringId, void *buffer) {
+    syscall(SYS_READ_STRING, stringId, U32(buffer), 0, 0);
+}
+
+void discardString(uintptr_t stringId) {
+    syscall(SYS_DISCARD_STRING, stringId, 0, 0, 0);
+}
diff --git a/src/include/hlib.h b/src/include/hlib.h
index a8da877..ed26b16 100644
--- a/src/include/hlib.h
+++ b/src/include/hlib.h
@@ -9,7 +9,7 @@
     void *data;
 } ListElement;
 
-#include "../userland/hlib/malloc.h"
+#include "../hlib/malloc.h"
 
 #define PTR(x) ((void *)(uintptr_t)(x))
 #define U32(x) ((uint32_t)(uintptr_t)(x))
diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile
deleted file mode 100644
index 4870f51..0000000
--- a/src/userland/hlib/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-CC = i686-elf-gcc
-CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
-LD = i686-elf-ld
-LD_FLAGS = -z max-page-size=0x1000 
-AS = nasm
-ASFlAGS = -felf32
-
-BUILD_FOLDER = build
-
-SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
-OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
-
-../../../initrd/hlib: $(OBJS)
-	@echo "linking the honey OS c libary"
-	@$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r
-	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
-
-$(BUILD_FOLDER)/%.asm.o: %.asm
-	@echo "asembling $<"
-	@mkdir -p $(dir $@)
-	@$(AS) $(ASFlAGS) $< -o $@
-
-$(BUILD_FOLDER)/%.c.o: %.c
-	@echo "compiling $<"
-	@mkdir -p $(dir $@)
-	@$(CC) $(CCFLAGS) -r $< -o $@
-
-clean:
-	@echo "clearing build folder"
-	@rm -r $(BUILD_FOLDER)
diff --git a/src/userland/hlib/compile_flags.txt b/src/userland/hlib/compile_flags.txt
deleted file mode 100644
index a432e7b..0000000
--- a/src/userland/hlib/compile_flags.txt
+++ /dev/null
@@ -1,6 +0,0 @@
--I./include
--I../../include
-clang
--fms-extensions
--Wno-microsoft-anon-tag
--Wno-incompatible-library-redeclaration
diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h
deleted file mode 100644
index 2025b24..0000000
--- a/src/userland/hlib/include/syscalls.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef SYSCALLS_H
-#define SYSCALLS_H
-
-#include <stdbool.h>
-#include <stdint.h>
-
-typedef enum {
-    SYS_RUN = 0,
-    SYS_CREATE_FUNCTION = 1,
-    SYS_REQUEST = 2,
-    SYS_IO_IN = 3,
-    SYS_IO_OUT = 4,
-    SYS_LOAD_INITRD = 5,
-    SYS_GET_SERVICE = 6,
-    SYS_GET_FUNCTION = 7,
-    SYS_SUBSCRIBE_INTERRUPT = 8,
-    SYS_CREATE_EVENT = 9,
-    SYS_GET_EVENT = 10,
-    SYS_FIRE_EVENT = 11,
-    SYS_SUBSCRIBE_EVENT = 12,
-    SYS_GET_SERVICE_ID = 13,
-    SYS_INSERT_STRING = 14,
-    SYS_GET_STRING_LENGTH = 15,
-    SYS_READ_STRING = 16,
-    SYS_DISCARD_STRING = 17,
-    SYS_REQUEST_MEMORY = 18,
-    SYS_LOOKUP_SYMBOL = 19,
-    SYS_STACK_CONTAINS = 20,
-    SYS_AWAIT = 21,
-    SYS_GET_PHYSICAL = 22,
-    SYS_FORK = 23,
-} SyscallIds;
-
-extern uint32_t getFunction(uint32_t module, char *name);
-
-#endif
diff --git a/src/userland/hlib/io.c b/src/userland/hlib/io.c
deleted file mode 100644
index 5a6c3f3..0000000
--- a/src/userland/hlib/io.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <hlib.h>
-#include <syscalls.h>
-
-uint32_t ioIn(uint16_t port, uint8_t size) {
-    return syscall(SYS_IO_IN, size, port, 0, 0);
-}
-
-void ioOut(uint16_t port, uint32_t value, uint8_t size) {
-    syscall(SYS_IO_OUT, size, port, value, 0);
-}
-
-void subscribeInterrupt(uint32_t intNo, void *handler) {
-    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
-}
diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld
deleted file mode 100644
index e38b0df..0000000
--- a/src/userland/hlib/link.ld
+++ /dev/null
@@ -1,12 +0,0 @@
-OUTPUT_ARCH(i386)
-
-SECTIONS {
-    . = 0xFF000000;
-
-    .hlib : {
-        *(.text)
-        *(.rodata)
-        *(.data)
-        *(.bss)
-    }
-}
diff --git a/src/userland/hlib/list.c b/src/userland/hlib/list.c
deleted file mode 100644
index ffc0ed6..0000000
--- a/src/userland/hlib/list.c
+++ /dev/null
@@ -1,78 +0,0 @@
-#include <hlib.h>
-
-void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
-    ListElement *element = malloc(sizeof(ListElement));
-    element->data = data;
-    element->next = NULL;
-    if (!*list) {
-        *list = element;
-        return;
-    }
-    ListElement *current = *list;
-    while (current->next) {
-        current = current->next;
-    }
-    current->next = element;
-}
-
-void *listPopFirst(ListElement **list) {
-    if (!*list) {
-        return NULL;
-    }
-    ListElement *resultElement = *list;
-    void *result = resultElement->data;
-    *list = (*list)->next;
-    free(resultElement);
-    return result;
-}
-
-uint32_t listCount(ListElement *list) {
-    uint32_t i = 0;
-    foreach (list, void *, element, { i++; })
-        ;
-    return i;
-}
-
-void *listGet(ListElement *list, uint32_t position) {
-    for (uint32_t i = 0; i < position; i++) {
-        list = list->next;
-    }
-    return list->data;
-}
-
-bool listRemoveValue(ListElement **list, void *value) {
-    if (!*list) {
-        return false;
-    }
-    ListElement *element = *list, *previous = NULL;
-    while (element) {
-        if (element->data == value) {
-            if (previous) {
-                previous->next = element->next;
-            } else {
-                *list = element->next;
-            }
-            free(element);
-            return true;
-        }
-        previous = element;
-        element = element->next;
-    }
-    return false;
-}
-
-void listClear(ListElement **list, bool freeData) {
-    ListElement *current = *list;
-    if (!current) {
-        return;
-    }
-    while (current->next) {
-        if (freeData) {
-            free(current->data);
-        }
-        ListElement *next = current->next;
-        free(current);
-        current = next;
-    }
-    *list = NULL;
-}
diff --git a/src/userland/hlib/main.c b/src/userland/hlib/main.c
deleted file mode 100644
index 43ac97d..0000000
--- a/src/userland/hlib/main.c
+++ /dev/null
@@ -1,84 +0,0 @@
-#include "include/syscalls.h"
-#include <hlib.h>
-#include <stdint.h>
-
-uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
-                 uint32_t parameter2, uint32_t parameter3) {
-    uint32_t esp;
-    asm("push %%eax" ::"a"(&&end)); // end: return address
-    asm("mov %%esp, %%eax" : "=a"(esp));
-    asm("sysenter\n"
-        :
-        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
-          "S"(parameter3), "D"(esp));
-// eax is set by the kernel as the return value
-end:
-    // the 0x1C comes from the number of parameters / local variables do handle
-    // this function with care or it will break everything
-    asm("add $0x1C, %%esp\n"
-        "pop %%ebp\n"
-        "ret" ::);
-    // don't go here! ret returns with the correct value
-    return 0;
-}
-
-uint32_t loadFromInitrd(char *name) {
-    uintptr_t id = insertString(name);
-    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
-    if (!service) {
-        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
-    }
-    return service;
-}
-
-uint32_t loadFromInitrdUninitialized(char *name) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
-}
-
-void requestName(char *service, char *provider, uintptr_t data1,
-                 uintptr_t data2) {
-    uint32_t serviceId = getService(service);
-    uint32_t providerId = getFunction(serviceId, provider);
-    request(serviceId, providerId, data1, data2);
-}
-
-void *requestMemory(uint32_t pageCount, void *targetAddress,
-                    void *physicalAddress) {
-    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
-                       U32(physicalAddress), 0));
-}
-
-void *getPage() { return requestMemory(1, NULL, NULL); }
-
-void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
-
-void freePage(void *location) {}
-
-void memset(void *_target, uint8_t byte, uint32_t size) {
-    uint8_t *target = _target;
-    for (uint32_t i = 0; i < size; i++) {
-        *target = byte;
-        target++;
-    }
-}
-
-bool stackContains(uint32_t serviceId) {
-    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
-}
-
-#define REQUEST1(returnType, functionName, service, function)                  \
-    returnType functionName(uint32_t data) {                                   \
-        static uint32_t serviceId = 0;                                         \
-        if (!serviceId) {                                                      \
-            serviceId = getService(service);                                   \
-            serviceId = getService(service);                                   \
-        }                                                                      \
-        static uint32_t functionId = 0;                                        \
-        if (!functionId) {                                                     \
-            functionId = getFunction(serviceId, function);                     \
-        }                                                                      \
-        return (returnType)request(serviceId, functionId, data, 0);            \
-    }
-
-REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/userland/hlib/malloc.c b/src/userland/hlib/malloc.c
deleted file mode 120000
index 022d82b..0000000
--- a/src/userland/hlib/malloc.c
+++ /dev/null
@@ -1 +0,0 @@
-../../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/userland/hlib/malloc.h b/src/userland/hlib/malloc.h
deleted file mode 120000
index 8a56b0a..0000000
--- a/src/userland/hlib/malloc.h
+++ /dev/null
@@ -1 +0,0 @@
-../../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/userland/hlib/service/events.c b/src/userland/hlib/service/events.c
deleted file mode 100644
index 9429c44..0000000
--- a/src/userland/hlib/service/events.c
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <hlib.h>
-#include <stdint.h>
-#include <syscalls.h>
-
-uint32_t createEvent(char *name) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
-}
-
-uintptr_t hashString(char *string) {
-    uintptr_t hash = 0;
-    for (uintptr_t i = 0; string[i]; i++) {
-        hash = 257 * hash + string[i];
-    }
-    return hash;
-}
-
-uint32_t getEvent(uint32_t service, char *name) {
-    uintptr_t id = hashString(name);
-    return syscall(SYS_GET_EVENT, service, id, 0, 0);
-}
-
-void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
-    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
-}
-
-void fireEvent(uint32_t eventNumber, uint32_t data) {
-    fireEventCode(eventNumber, data, 0);
-}
-
-void subscribeEvent(uint32_t service, uint32_t event,
-                    void(handler)(void *, uint32_t)) {
-    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
-}
-
-uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
-    return syscall(SYS_AWAIT, service, event, code, 0);
-}
-
-uint32_t await(uint32_t service, uint32_t event) {
-    return awaitCode(service, event, 0);
-}
-
-uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
-    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
-}
-
-uint32_t createDirectEvent(uint32_t id) {
-    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
-}
-
-uint32_t createDirectEventSave(uint32_t id) {
-    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
-    if (existingEvent) {
-        return existingEvent;
-    }
-    return createDirectEvent(id);
-}

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}
diff --git a/src/hlib/service/service.c b/src/hlib/service/service.c
new file mode 100644
index 0000000..1669154
--- /dev/null
+++ b/src/hlib/service/service.c
@@ -0,0 +1,39 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
+                 uintptr_t data2) {
+    return syscall(SYS_REQUEST, service, function, data1, data2);
+}
+
+uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
+}
+
+uint32_t getService(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+}
+
+uint32_t getFunction(uint32_t module, char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
+}
+
+uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
+
+uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
+    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
+}
+
+void *getPhysicalAddress(void *source) {
+    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
+               (U32(source) & 0xFFF));
+}
+
+uint32_t fork(void (f)(), void *a, void *b, void *c) {
+    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
+}
+
diff --git a/src/hlib/stdio.c b/src/hlib/stdio.c
new file mode 100644
index 0000000..e717154
--- /dev/null
+++ b/src/hlib/stdio.c
@@ -0,0 +1,207 @@
+#include <hlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+char HEX_CHARS[] = "0123456789ABCDEF";
+
+void putHex(char **write, uintptr_t x) {
+    if (x == 0) {
+        **write = HEX_CHARS[x];
+        (*write)++;
+        **write = HEX_CHARS[x];
+        (*write)++;
+        return;
+    }
+    bool alreadyWriting = false;
+    for (int position = 3; position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            **write = HEX_CHARS[byte >> 4];
+            (*write)++;
+            **write = HEX_CHARS[byte & 0x0F];
+            (*write)++;
+        }
+    }
+}
+
+uint8_t hexLength(uintptr_t x) {
+    bool alreadyWriting = false;
+    uint8_t size = 0;
+    for (int position = sizeof(uintptr_t); position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            size += 2;
+        }
+    }
+    return MAX(size, 2);
+}
+
+uint32_t power(uintptr_t x, uintptr_t y) {
+    uintptr_t result = 1;
+    for (uintptr_t i = 0; i < y; i++) {
+        result *= x;
+    }
+    return result;
+}
+
+uint32_t intLength(intptr_t x) {
+    if (x == 0) {
+        return 1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        if (x / power(10, i) > 0) {
+            return i + 1;
+        }
+    }
+    return 1;
+}
+
+void addChar(char **write, char c) {
+    **write = c;
+    (*write)++;
+}
+
+void putInt(char **write, intptr_t x) {
+    if (x == 0) {
+        addChar(write, '0');
+        return;
+    }
+    if (x < 0) {
+        addChar(write, '-');
+        x *= -1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        uintptr_t n = x / power(10, i);
+        if (n) {
+            addChar(write, HEX_CHARS[n % 10]);
+        }
+    }
+}
+
+void putPadding(char **write, uintptr_t x) {
+    x = MIN(x, 10); // max 10 wide padding
+    for (intptr_t i = 0; i < x; i++) {
+        addChar(write, ' ');
+    }
+}
+
+uint32_t getInsertLength(char insertType, intptr_t x) {
+    switch (insertType) {
+    case 's':
+        return strlen((char *)x);
+    case 'x':
+        return hexLength(x);
+    case 'c':
+        return 1;
+    case 'i':
+        return intLength(x) + (x < 0);
+    case 'p':
+        return x;
+    }
+    return 0;
+}
+
+void stringInsert(char **write, uintptr_t x) {
+    char *string = (char *)x;
+    uint32_t length = strlen(string);
+    for (uint32_t position = 0; position < length; position++) {
+        **write = string[position];
+        (*write)++;
+    }
+}
+
+void handleInsert(char **write, char insertType, uintptr_t x) {
+    switch (insertType) {
+    case 's':
+        stringInsert(write, x);
+        return;
+    case 'x':
+        putHex(write, x);
+        return;
+    case 'c':
+        **write = x;
+        (*write)++;
+        return;
+    case 'i':
+        putInt(write, x);
+        return;
+    case 'p':
+        putPadding(write, x);
+        return;
+    }
+}
+uint32_t ioManager, logFunction;
+
+uint32_t printfSize(const char *format, va_list *valist) {
+    uint32_t size = 0;
+    for (; format[size] != 0; size++) {
+        if (format[size] == '%') {
+            char insertType = format[++size];
+            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
+            continue;
+        }
+    }
+    return size;
+}
+
+void _sprintf(char *data, const char *format, va_list *valist) {
+    char *write = data;
+    for (int i = 0; format[i] != 0; i++) {
+        if (format[i] == '%') {
+            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
+            continue;
+        }
+        *write = format[i];
+        write++;
+    }
+}
+
+void sprintf(char *data, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+}
+
+char *_asprintf(AllocationData allocationData, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    uint32_t size = printfSize(format, &valist);
+    char *data = malloc(size);
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    return data;
+}
+
+void _printf(AllocationData allocationData, const char *format, ...) {
+    // I have absolutely no idea why this line fixes an issue where the first
+    // printf operation consistently doesn't correctly insert its string
+    free(malloc(1));
+    va_list valist;
+    va_start(valist, format);
+    char *data = malloc(printfSize(format, &valist));
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    uintptr_t id = insertString(data);
+    request(ioManager, logFunction, id, 0);
+    discardString(id);
+    free(data);
+}
+
+void gets(char *buffer) {
+    static uint32_t function = 0;
+    if (!function) {
+        function = getFunction(ioManager, "gets");
+    }
+    uint32_t stringId = request(ioManager, function, 0, 0);
+    readString(stringId, buffer);
+}
diff --git a/src/hlib/strings.c b/src/hlib/strings.c
new file mode 100644
index 0000000..78fff55
--- /dev/null
+++ b/src/hlib/strings.c
@@ -0,0 +1,38 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t strlen(char *string) {
+    if (!string) {
+        return 0;
+    }
+    uint32_t size = 0;
+    while (*string) {
+        string++;
+        size++;
+    }
+    return size;
+}
+
+void memcpy(void *from, void *to, uint32_t size) {
+    uint8_t *a = from, *b = to;
+    for (uint32_t i = 0; i < size; i++) {
+        b[i] = a[i];
+    }
+}
+
+uintptr_t insertString(char *string) {
+    return syscall(SYS_INSERT_STRING, U32(string), 0, 0, 0);
+}
+
+uintptr_t getStringLength(uintptr_t stringId) {
+    return syscall(SYS_GET_STRING_LENGTH, stringId, 0, 0, 0);
+}
+
+void readString(uintptr_t stringId, void *buffer) {
+    syscall(SYS_READ_STRING, stringId, U32(buffer), 0, 0);
+}
+
+void discardString(uintptr_t stringId) {
+    syscall(SYS_DISCARD_STRING, stringId, 0, 0, 0);
+}
diff --git a/src/include/hlib.h b/src/include/hlib.h
index a8da877..ed26b16 100644
--- a/src/include/hlib.h
+++ b/src/include/hlib.h
@@ -9,7 +9,7 @@
     void *data;
 } ListElement;
 
-#include "../userland/hlib/malloc.h"
+#include "../hlib/malloc.h"
 
 #define PTR(x) ((void *)(uintptr_t)(x))
 #define U32(x) ((uint32_t)(uintptr_t)(x))
diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile
deleted file mode 100644
index 4870f51..0000000
--- a/src/userland/hlib/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-CC = i686-elf-gcc
-CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
-LD = i686-elf-ld
-LD_FLAGS = -z max-page-size=0x1000 
-AS = nasm
-ASFlAGS = -felf32
-
-BUILD_FOLDER = build
-
-SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
-OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
-
-../../../initrd/hlib: $(OBJS)
-	@echo "linking the honey OS c libary"
-	@$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r
-	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
-
-$(BUILD_FOLDER)/%.asm.o: %.asm
-	@echo "asembling $<"
-	@mkdir -p $(dir $@)
-	@$(AS) $(ASFlAGS) $< -o $@
-
-$(BUILD_FOLDER)/%.c.o: %.c
-	@echo "compiling $<"
-	@mkdir -p $(dir $@)
-	@$(CC) $(CCFLAGS) -r $< -o $@
-
-clean:
-	@echo "clearing build folder"
-	@rm -r $(BUILD_FOLDER)
diff --git a/src/userland/hlib/compile_flags.txt b/src/userland/hlib/compile_flags.txt
deleted file mode 100644
index a432e7b..0000000
--- a/src/userland/hlib/compile_flags.txt
+++ /dev/null
@@ -1,6 +0,0 @@
--I./include
--I../../include
-clang
--fms-extensions
--Wno-microsoft-anon-tag
--Wno-incompatible-library-redeclaration
diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h
deleted file mode 100644
index 2025b24..0000000
--- a/src/userland/hlib/include/syscalls.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef SYSCALLS_H
-#define SYSCALLS_H
-
-#include <stdbool.h>
-#include <stdint.h>
-
-typedef enum {
-    SYS_RUN = 0,
-    SYS_CREATE_FUNCTION = 1,
-    SYS_REQUEST = 2,
-    SYS_IO_IN = 3,
-    SYS_IO_OUT = 4,
-    SYS_LOAD_INITRD = 5,
-    SYS_GET_SERVICE = 6,
-    SYS_GET_FUNCTION = 7,
-    SYS_SUBSCRIBE_INTERRUPT = 8,
-    SYS_CREATE_EVENT = 9,
-    SYS_GET_EVENT = 10,
-    SYS_FIRE_EVENT = 11,
-    SYS_SUBSCRIBE_EVENT = 12,
-    SYS_GET_SERVICE_ID = 13,
-    SYS_INSERT_STRING = 14,
-    SYS_GET_STRING_LENGTH = 15,
-    SYS_READ_STRING = 16,
-    SYS_DISCARD_STRING = 17,
-    SYS_REQUEST_MEMORY = 18,
-    SYS_LOOKUP_SYMBOL = 19,
-    SYS_STACK_CONTAINS = 20,
-    SYS_AWAIT = 21,
-    SYS_GET_PHYSICAL = 22,
-    SYS_FORK = 23,
-} SyscallIds;
-
-extern uint32_t getFunction(uint32_t module, char *name);
-
-#endif
diff --git a/src/userland/hlib/io.c b/src/userland/hlib/io.c
deleted file mode 100644
index 5a6c3f3..0000000
--- a/src/userland/hlib/io.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <hlib.h>
-#include <syscalls.h>
-
-uint32_t ioIn(uint16_t port, uint8_t size) {
-    return syscall(SYS_IO_IN, size, port, 0, 0);
-}
-
-void ioOut(uint16_t port, uint32_t value, uint8_t size) {
-    syscall(SYS_IO_OUT, size, port, value, 0);
-}
-
-void subscribeInterrupt(uint32_t intNo, void *handler) {
-    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
-}
diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld
deleted file mode 100644
index e38b0df..0000000
--- a/src/userland/hlib/link.ld
+++ /dev/null
@@ -1,12 +0,0 @@
-OUTPUT_ARCH(i386)
-
-SECTIONS {
-    . = 0xFF000000;
-
-    .hlib : {
-        *(.text)
-        *(.rodata)
-        *(.data)
-        *(.bss)
-    }
-}
diff --git a/src/userland/hlib/list.c b/src/userland/hlib/list.c
deleted file mode 100644
index ffc0ed6..0000000
--- a/src/userland/hlib/list.c
+++ /dev/null
@@ -1,78 +0,0 @@
-#include <hlib.h>
-
-void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
-    ListElement *element = malloc(sizeof(ListElement));
-    element->data = data;
-    element->next = NULL;
-    if (!*list) {
-        *list = element;
-        return;
-    }
-    ListElement *current = *list;
-    while (current->next) {
-        current = current->next;
-    }
-    current->next = element;
-}
-
-void *listPopFirst(ListElement **list) {
-    if (!*list) {
-        return NULL;
-    }
-    ListElement *resultElement = *list;
-    void *result = resultElement->data;
-    *list = (*list)->next;
-    free(resultElement);
-    return result;
-}
-
-uint32_t listCount(ListElement *list) {
-    uint32_t i = 0;
-    foreach (list, void *, element, { i++; })
-        ;
-    return i;
-}
-
-void *listGet(ListElement *list, uint32_t position) {
-    for (uint32_t i = 0; i < position; i++) {
-        list = list->next;
-    }
-    return list->data;
-}
-
-bool listRemoveValue(ListElement **list, void *value) {
-    if (!*list) {
-        return false;
-    }
-    ListElement *element = *list, *previous = NULL;
-    while (element) {
-        if (element->data == value) {
-            if (previous) {
-                previous->next = element->next;
-            } else {
-                *list = element->next;
-            }
-            free(element);
-            return true;
-        }
-        previous = element;
-        element = element->next;
-    }
-    return false;
-}
-
-void listClear(ListElement **list, bool freeData) {
-    ListElement *current = *list;
-    if (!current) {
-        return;
-    }
-    while (current->next) {
-        if (freeData) {
-            free(current->data);
-        }
-        ListElement *next = current->next;
-        free(current);
-        current = next;
-    }
-    *list = NULL;
-}
diff --git a/src/userland/hlib/main.c b/src/userland/hlib/main.c
deleted file mode 100644
index 43ac97d..0000000
--- a/src/userland/hlib/main.c
+++ /dev/null
@@ -1,84 +0,0 @@
-#include "include/syscalls.h"
-#include <hlib.h>
-#include <stdint.h>
-
-uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
-                 uint32_t parameter2, uint32_t parameter3) {
-    uint32_t esp;
-    asm("push %%eax" ::"a"(&&end)); // end: return address
-    asm("mov %%esp, %%eax" : "=a"(esp));
-    asm("sysenter\n"
-        :
-        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
-          "S"(parameter3), "D"(esp));
-// eax is set by the kernel as the return value
-end:
-    // the 0x1C comes from the number of parameters / local variables do handle
-    // this function with care or it will break everything
-    asm("add $0x1C, %%esp\n"
-        "pop %%ebp\n"
-        "ret" ::);
-    // don't go here! ret returns with the correct value
-    return 0;
-}
-
-uint32_t loadFromInitrd(char *name) {
-    uintptr_t id = insertString(name);
-    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
-    if (!service) {
-        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
-    }
-    return service;
-}
-
-uint32_t loadFromInitrdUninitialized(char *name) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
-}
-
-void requestName(char *service, char *provider, uintptr_t data1,
-                 uintptr_t data2) {
-    uint32_t serviceId = getService(service);
-    uint32_t providerId = getFunction(serviceId, provider);
-    request(serviceId, providerId, data1, data2);
-}
-
-void *requestMemory(uint32_t pageCount, void *targetAddress,
-                    void *physicalAddress) {
-    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
-                       U32(physicalAddress), 0));
-}
-
-void *getPage() { return requestMemory(1, NULL, NULL); }
-
-void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
-
-void freePage(void *location) {}
-
-void memset(void *_target, uint8_t byte, uint32_t size) {
-    uint8_t *target = _target;
-    for (uint32_t i = 0; i < size; i++) {
-        *target = byte;
-        target++;
-    }
-}
-
-bool stackContains(uint32_t serviceId) {
-    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
-}
-
-#define REQUEST1(returnType, functionName, service, function)                  \
-    returnType functionName(uint32_t data) {                                   \
-        static uint32_t serviceId = 0;                                         \
-        if (!serviceId) {                                                      \
-            serviceId = getService(service);                                   \
-            serviceId = getService(service);                                   \
-        }                                                                      \
-        static uint32_t functionId = 0;                                        \
-        if (!functionId) {                                                     \
-            functionId = getFunction(serviceId, function);                     \
-        }                                                                      \
-        return (returnType)request(serviceId, functionId, data, 0);            \
-    }
-
-REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/userland/hlib/malloc.c b/src/userland/hlib/malloc.c
deleted file mode 120000
index 022d82b..0000000
--- a/src/userland/hlib/malloc.c
+++ /dev/null
@@ -1 +0,0 @@
-../../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/userland/hlib/malloc.h b/src/userland/hlib/malloc.h
deleted file mode 120000
index 8a56b0a..0000000
--- a/src/userland/hlib/malloc.h
+++ /dev/null
@@ -1 +0,0 @@
-../../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/userland/hlib/service/events.c b/src/userland/hlib/service/events.c
deleted file mode 100644
index 9429c44..0000000
--- a/src/userland/hlib/service/events.c
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <hlib.h>
-#include <stdint.h>
-#include <syscalls.h>
-
-uint32_t createEvent(char *name) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
-}
-
-uintptr_t hashString(char *string) {
-    uintptr_t hash = 0;
-    for (uintptr_t i = 0; string[i]; i++) {
-        hash = 257 * hash + string[i];
-    }
-    return hash;
-}
-
-uint32_t getEvent(uint32_t service, char *name) {
-    uintptr_t id = hashString(name);
-    return syscall(SYS_GET_EVENT, service, id, 0, 0);
-}
-
-void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
-    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
-}
-
-void fireEvent(uint32_t eventNumber, uint32_t data) {
-    fireEventCode(eventNumber, data, 0);
-}
-
-void subscribeEvent(uint32_t service, uint32_t event,
-                    void(handler)(void *, uint32_t)) {
-    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
-}
-
-uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
-    return syscall(SYS_AWAIT, service, event, code, 0);
-}
-
-uint32_t await(uint32_t service, uint32_t event) {
-    return awaitCode(service, event, 0);
-}
-
-uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
-    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
-}
-
-uint32_t createDirectEvent(uint32_t id) {
-    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
-}
-
-uint32_t createDirectEventSave(uint32_t id) {
-    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
-    if (existingEvent) {
-        return existingEvent;
-    }
-    return createDirectEvent(id);
-}
diff --git a/src/userland/hlib/service/service.c b/src/userland/hlib/service/service.c
deleted file mode 100644
index 1669154..0000000
--- a/src/userland/hlib/service/service.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include <hlib.h>
-#include <stdint.h>
-#include <syscalls.h>
-
-uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
-                 uintptr_t data2) {
-    return syscall(SYS_REQUEST, service, function, data1, data2);
-}
-
-uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
-}
-
-uint32_t getService(char *name) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
-}
-
-uint32_t getFunction(uint32_t module, char *name) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
-}
-
-uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
-
-uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
-    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
-}
-
-void *getPhysicalAddress(void *source) {
-    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
-               (U32(source) & 0xFFF));
-}
-
-uint32_t fork(void (f)(), void *a, void *b, void *c) {
-    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
-}
-

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}
diff --git a/src/hlib/service/service.c b/src/hlib/service/service.c
new file mode 100644
index 0000000..1669154
--- /dev/null
+++ b/src/hlib/service/service.c
@@ -0,0 +1,39 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
+                 uintptr_t data2) {
+    return syscall(SYS_REQUEST, service, function, data1, data2);
+}
+
+uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
+}
+
+uint32_t getService(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+}
+
+uint32_t getFunction(uint32_t module, char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
+}
+
+uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
+
+uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
+    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
+}
+
+void *getPhysicalAddress(void *source) {
+    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
+               (U32(source) & 0xFFF));
+}
+
+uint32_t fork(void (f)(), void *a, void *b, void *c) {
+    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
+}
+
diff --git a/src/hlib/stdio.c b/src/hlib/stdio.c
new file mode 100644
index 0000000..e717154
--- /dev/null
+++ b/src/hlib/stdio.c
@@ -0,0 +1,207 @@
+#include <hlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+char HEX_CHARS[] = "0123456789ABCDEF";
+
+void putHex(char **write, uintptr_t x) {
+    if (x == 0) {
+        **write = HEX_CHARS[x];
+        (*write)++;
+        **write = HEX_CHARS[x];
+        (*write)++;
+        return;
+    }
+    bool alreadyWriting = false;
+    for (int position = 3; position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            **write = HEX_CHARS[byte >> 4];
+            (*write)++;
+            **write = HEX_CHARS[byte & 0x0F];
+            (*write)++;
+        }
+    }
+}
+
+uint8_t hexLength(uintptr_t x) {
+    bool alreadyWriting = false;
+    uint8_t size = 0;
+    for (int position = sizeof(uintptr_t); position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            size += 2;
+        }
+    }
+    return MAX(size, 2);
+}
+
+uint32_t power(uintptr_t x, uintptr_t y) {
+    uintptr_t result = 1;
+    for (uintptr_t i = 0; i < y; i++) {
+        result *= x;
+    }
+    return result;
+}
+
+uint32_t intLength(intptr_t x) {
+    if (x == 0) {
+        return 1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        if (x / power(10, i) > 0) {
+            return i + 1;
+        }
+    }
+    return 1;
+}
+
+void addChar(char **write, char c) {
+    **write = c;
+    (*write)++;
+}
+
+void putInt(char **write, intptr_t x) {
+    if (x == 0) {
+        addChar(write, '0');
+        return;
+    }
+    if (x < 0) {
+        addChar(write, '-');
+        x *= -1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        uintptr_t n = x / power(10, i);
+        if (n) {
+            addChar(write, HEX_CHARS[n % 10]);
+        }
+    }
+}
+
+void putPadding(char **write, uintptr_t x) {
+    x = MIN(x, 10); // max 10 wide padding
+    for (intptr_t i = 0; i < x; i++) {
+        addChar(write, ' ');
+    }
+}
+
+uint32_t getInsertLength(char insertType, intptr_t x) {
+    switch (insertType) {
+    case 's':
+        return strlen((char *)x);
+    case 'x':
+        return hexLength(x);
+    case 'c':
+        return 1;
+    case 'i':
+        return intLength(x) + (x < 0);
+    case 'p':
+        return x;
+    }
+    return 0;
+}
+
+void stringInsert(char **write, uintptr_t x) {
+    char *string = (char *)x;
+    uint32_t length = strlen(string);
+    for (uint32_t position = 0; position < length; position++) {
+        **write = string[position];
+        (*write)++;
+    }
+}
+
+void handleInsert(char **write, char insertType, uintptr_t x) {
+    switch (insertType) {
+    case 's':
+        stringInsert(write, x);
+        return;
+    case 'x':
+        putHex(write, x);
+        return;
+    case 'c':
+        **write = x;
+        (*write)++;
+        return;
+    case 'i':
+        putInt(write, x);
+        return;
+    case 'p':
+        putPadding(write, x);
+        return;
+    }
+}
+uint32_t ioManager, logFunction;
+
+uint32_t printfSize(const char *format, va_list *valist) {
+    uint32_t size = 0;
+    for (; format[size] != 0; size++) {
+        if (format[size] == '%') {
+            char insertType = format[++size];
+            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
+            continue;
+        }
+    }
+    return size;
+}
+
+void _sprintf(char *data, const char *format, va_list *valist) {
+    char *write = data;
+    for (int i = 0; format[i] != 0; i++) {
+        if (format[i] == '%') {
+            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
+            continue;
+        }
+        *write = format[i];
+        write++;
+    }
+}
+
+void sprintf(char *data, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+}
+
+char *_asprintf(AllocationData allocationData, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    uint32_t size = printfSize(format, &valist);
+    char *data = malloc(size);
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    return data;
+}
+
+void _printf(AllocationData allocationData, const char *format, ...) {
+    // I have absolutely no idea why this line fixes an issue where the first
+    // printf operation consistently doesn't correctly insert its string
+    free(malloc(1));
+    va_list valist;
+    va_start(valist, format);
+    char *data = malloc(printfSize(format, &valist));
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    uintptr_t id = insertString(data);
+    request(ioManager, logFunction, id, 0);
+    discardString(id);
+    free(data);
+}
+
+void gets(char *buffer) {
+    static uint32_t function = 0;
+    if (!function) {
+        function = getFunction(ioManager, "gets");
+    }
+    uint32_t stringId = request(ioManager, function, 0, 0);
+    readString(stringId, buffer);
+}
diff --git a/src/hlib/strings.c b/src/hlib/strings.c
new file mode 100644
index 0000000..78fff55
--- /dev/null
+++ b/src/hlib/strings.c
@@ -0,0 +1,38 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t strlen(char *string) {
+    if (!string) {
+        return 0;
+    }
+    uint32_t size = 0;
+    while (*string) {
+        string++;
+        size++;
+    }
+    return size;
+}
+
+void memcpy(void *from, void *to, uint32_t size) {
+    uint8_t *a = from, *b = to;
+    for (uint32_t i = 0; i < size; i++) {
+        b[i] = a[i];
+    }
+}
+
+uintptr_t insertString(char *string) {
+    return syscall(SYS_INSERT_STRING, U32(string), 0, 0, 0);
+}
+
+uintptr_t getStringLength(uintptr_t stringId) {
+    return syscall(SYS_GET_STRING_LENGTH, stringId, 0, 0, 0);
+}
+
+void readString(uintptr_t stringId, void *buffer) {
+    syscall(SYS_READ_STRING, stringId, U32(buffer), 0, 0);
+}
+
+void discardString(uintptr_t stringId) {
+    syscall(SYS_DISCARD_STRING, stringId, 0, 0, 0);
+}
diff --git a/src/include/hlib.h b/src/include/hlib.h
index a8da877..ed26b16 100644
--- a/src/include/hlib.h
+++ b/src/include/hlib.h
@@ -9,7 +9,7 @@
     void *data;
 } ListElement;
 
-#include "../userland/hlib/malloc.h"
+#include "../hlib/malloc.h"
 
 #define PTR(x) ((void *)(uintptr_t)(x))
 #define U32(x) ((uint32_t)(uintptr_t)(x))
diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile
deleted file mode 100644
index 4870f51..0000000
--- a/src/userland/hlib/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-CC = i686-elf-gcc
-CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
-LD = i686-elf-ld
-LD_FLAGS = -z max-page-size=0x1000 
-AS = nasm
-ASFlAGS = -felf32
-
-BUILD_FOLDER = build
-
-SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
-OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
-
-../../../initrd/hlib: $(OBJS)
-	@echo "linking the honey OS c libary"
-	@$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r
-	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
-
-$(BUILD_FOLDER)/%.asm.o: %.asm
-	@echo "asembling $<"
-	@mkdir -p $(dir $@)
-	@$(AS) $(ASFlAGS) $< -o $@
-
-$(BUILD_FOLDER)/%.c.o: %.c
-	@echo "compiling $<"
-	@mkdir -p $(dir $@)
-	@$(CC) $(CCFLAGS) -r $< -o $@
-
-clean:
-	@echo "clearing build folder"
-	@rm -r $(BUILD_FOLDER)
diff --git a/src/userland/hlib/compile_flags.txt b/src/userland/hlib/compile_flags.txt
deleted file mode 100644
index a432e7b..0000000
--- a/src/userland/hlib/compile_flags.txt
+++ /dev/null
@@ -1,6 +0,0 @@
--I./include
--I../../include
-clang
--fms-extensions
--Wno-microsoft-anon-tag
--Wno-incompatible-library-redeclaration
diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h
deleted file mode 100644
index 2025b24..0000000
--- a/src/userland/hlib/include/syscalls.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef SYSCALLS_H
-#define SYSCALLS_H
-
-#include <stdbool.h>
-#include <stdint.h>
-
-typedef enum {
-    SYS_RUN = 0,
-    SYS_CREATE_FUNCTION = 1,
-    SYS_REQUEST = 2,
-    SYS_IO_IN = 3,
-    SYS_IO_OUT = 4,
-    SYS_LOAD_INITRD = 5,
-    SYS_GET_SERVICE = 6,
-    SYS_GET_FUNCTION = 7,
-    SYS_SUBSCRIBE_INTERRUPT = 8,
-    SYS_CREATE_EVENT = 9,
-    SYS_GET_EVENT = 10,
-    SYS_FIRE_EVENT = 11,
-    SYS_SUBSCRIBE_EVENT = 12,
-    SYS_GET_SERVICE_ID = 13,
-    SYS_INSERT_STRING = 14,
-    SYS_GET_STRING_LENGTH = 15,
-    SYS_READ_STRING = 16,
-    SYS_DISCARD_STRING = 17,
-    SYS_REQUEST_MEMORY = 18,
-    SYS_LOOKUP_SYMBOL = 19,
-    SYS_STACK_CONTAINS = 20,
-    SYS_AWAIT = 21,
-    SYS_GET_PHYSICAL = 22,
-    SYS_FORK = 23,
-} SyscallIds;
-
-extern uint32_t getFunction(uint32_t module, char *name);
-
-#endif
diff --git a/src/userland/hlib/io.c b/src/userland/hlib/io.c
deleted file mode 100644
index 5a6c3f3..0000000
--- a/src/userland/hlib/io.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <hlib.h>
-#include <syscalls.h>
-
-uint32_t ioIn(uint16_t port, uint8_t size) {
-    return syscall(SYS_IO_IN, size, port, 0, 0);
-}
-
-void ioOut(uint16_t port, uint32_t value, uint8_t size) {
-    syscall(SYS_IO_OUT, size, port, value, 0);
-}
-
-void subscribeInterrupt(uint32_t intNo, void *handler) {
-    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
-}
diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld
deleted file mode 100644
index e38b0df..0000000
--- a/src/userland/hlib/link.ld
+++ /dev/null
@@ -1,12 +0,0 @@
-OUTPUT_ARCH(i386)
-
-SECTIONS {
-    . = 0xFF000000;
-
-    .hlib : {
-        *(.text)
-        *(.rodata)
-        *(.data)
-        *(.bss)
-    }
-}
diff --git a/src/userland/hlib/list.c b/src/userland/hlib/list.c
deleted file mode 100644
index ffc0ed6..0000000
--- a/src/userland/hlib/list.c
+++ /dev/null
@@ -1,78 +0,0 @@
-#include <hlib.h>
-
-void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
-    ListElement *element = malloc(sizeof(ListElement));
-    element->data = data;
-    element->next = NULL;
-    if (!*list) {
-        *list = element;
-        return;
-    }
-    ListElement *current = *list;
-    while (current->next) {
-        current = current->next;
-    }
-    current->next = element;
-}
-
-void *listPopFirst(ListElement **list) {
-    if (!*list) {
-        return NULL;
-    }
-    ListElement *resultElement = *list;
-    void *result = resultElement->data;
-    *list = (*list)->next;
-    free(resultElement);
-    return result;
-}
-
-uint32_t listCount(ListElement *list) {
-    uint32_t i = 0;
-    foreach (list, void *, element, { i++; })
-        ;
-    return i;
-}
-
-void *listGet(ListElement *list, uint32_t position) {
-    for (uint32_t i = 0; i < position; i++) {
-        list = list->next;
-    }
-    return list->data;
-}
-
-bool listRemoveValue(ListElement **list, void *value) {
-    if (!*list) {
-        return false;
-    }
-    ListElement *element = *list, *previous = NULL;
-    while (element) {
-        if (element->data == value) {
-            if (previous) {
-                previous->next = element->next;
-            } else {
-                *list = element->next;
-            }
-            free(element);
-            return true;
-        }
-        previous = element;
-        element = element->next;
-    }
-    return false;
-}
-
-void listClear(ListElement **list, bool freeData) {
-    ListElement *current = *list;
-    if (!current) {
-        return;
-    }
-    while (current->next) {
-        if (freeData) {
-            free(current->data);
-        }
-        ListElement *next = current->next;
-        free(current);
-        current = next;
-    }
-    *list = NULL;
-}
diff --git a/src/userland/hlib/main.c b/src/userland/hlib/main.c
deleted file mode 100644
index 43ac97d..0000000
--- a/src/userland/hlib/main.c
+++ /dev/null
@@ -1,84 +0,0 @@
-#include "include/syscalls.h"
-#include <hlib.h>
-#include <stdint.h>
-
-uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
-                 uint32_t parameter2, uint32_t parameter3) {
-    uint32_t esp;
-    asm("push %%eax" ::"a"(&&end)); // end: return address
-    asm("mov %%esp, %%eax" : "=a"(esp));
-    asm("sysenter\n"
-        :
-        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
-          "S"(parameter3), "D"(esp));
-// eax is set by the kernel as the return value
-end:
-    // the 0x1C comes from the number of parameters / local variables do handle
-    // this function with care or it will break everything
-    asm("add $0x1C, %%esp\n"
-        "pop %%ebp\n"
-        "ret" ::);
-    // don't go here! ret returns with the correct value
-    return 0;
-}
-
-uint32_t loadFromInitrd(char *name) {
-    uintptr_t id = insertString(name);
-    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
-    if (!service) {
-        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
-    }
-    return service;
-}
-
-uint32_t loadFromInitrdUninitialized(char *name) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
-}
-
-void requestName(char *service, char *provider, uintptr_t data1,
-                 uintptr_t data2) {
-    uint32_t serviceId = getService(service);
-    uint32_t providerId = getFunction(serviceId, provider);
-    request(serviceId, providerId, data1, data2);
-}
-
-void *requestMemory(uint32_t pageCount, void *targetAddress,
-                    void *physicalAddress) {
-    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
-                       U32(physicalAddress), 0));
-}
-
-void *getPage() { return requestMemory(1, NULL, NULL); }
-
-void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
-
-void freePage(void *location) {}
-
-void memset(void *_target, uint8_t byte, uint32_t size) {
-    uint8_t *target = _target;
-    for (uint32_t i = 0; i < size; i++) {
-        *target = byte;
-        target++;
-    }
-}
-
-bool stackContains(uint32_t serviceId) {
-    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
-}
-
-#define REQUEST1(returnType, functionName, service, function)                  \
-    returnType functionName(uint32_t data) {                                   \
-        static uint32_t serviceId = 0;                                         \
-        if (!serviceId) {                                                      \
-            serviceId = getService(service);                                   \
-            serviceId = getService(service);                                   \
-        }                                                                      \
-        static uint32_t functionId = 0;                                        \
-        if (!functionId) {                                                     \
-            functionId = getFunction(serviceId, function);                     \
-        }                                                                      \
-        return (returnType)request(serviceId, functionId, data, 0);            \
-    }
-
-REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/userland/hlib/malloc.c b/src/userland/hlib/malloc.c
deleted file mode 120000
index 022d82b..0000000
--- a/src/userland/hlib/malloc.c
+++ /dev/null
@@ -1 +0,0 @@
-../../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/userland/hlib/malloc.h b/src/userland/hlib/malloc.h
deleted file mode 120000
index 8a56b0a..0000000
--- a/src/userland/hlib/malloc.h
+++ /dev/null
@@ -1 +0,0 @@
-../../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/userland/hlib/service/events.c b/src/userland/hlib/service/events.c
deleted file mode 100644
index 9429c44..0000000
--- a/src/userland/hlib/service/events.c
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <hlib.h>
-#include <stdint.h>
-#include <syscalls.h>
-
-uint32_t createEvent(char *name) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
-}
-
-uintptr_t hashString(char *string) {
-    uintptr_t hash = 0;
-    for (uintptr_t i = 0; string[i]; i++) {
-        hash = 257 * hash + string[i];
-    }
-    return hash;
-}
-
-uint32_t getEvent(uint32_t service, char *name) {
-    uintptr_t id = hashString(name);
-    return syscall(SYS_GET_EVENT, service, id, 0, 0);
-}
-
-void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
-    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
-}
-
-void fireEvent(uint32_t eventNumber, uint32_t data) {
-    fireEventCode(eventNumber, data, 0);
-}
-
-void subscribeEvent(uint32_t service, uint32_t event,
-                    void(handler)(void *, uint32_t)) {
-    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
-}
-
-uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
-    return syscall(SYS_AWAIT, service, event, code, 0);
-}
-
-uint32_t await(uint32_t service, uint32_t event) {
-    return awaitCode(service, event, 0);
-}
-
-uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
-    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
-}
-
-uint32_t createDirectEvent(uint32_t id) {
-    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
-}
-
-uint32_t createDirectEventSave(uint32_t id) {
-    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
-    if (existingEvent) {
-        return existingEvent;
-    }
-    return createDirectEvent(id);
-}
diff --git a/src/userland/hlib/service/service.c b/src/userland/hlib/service/service.c
deleted file mode 100644
index 1669154..0000000
--- a/src/userland/hlib/service/service.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include <hlib.h>
-#include <stdint.h>
-#include <syscalls.h>
-
-uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
-                 uintptr_t data2) {
-    return syscall(SYS_REQUEST, service, function, data1, data2);
-}
-
-uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
-}
-
-uint32_t getService(char *name) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
-}
-
-uint32_t getFunction(uint32_t module, char *name) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
-}
-
-uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
-
-uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
-    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
-}
-
-void *getPhysicalAddress(void *source) {
-    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
-               (U32(source) & 0xFFF));
-}
-
-uint32_t fork(void (f)(), void *a, void *b, void *c) {
-    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
-}
-
diff --git a/src/userland/hlib/stdio.c b/src/userland/hlib/stdio.c
deleted file mode 100644
index e717154..0000000
--- a/src/userland/hlib/stdio.c
+++ /dev/null
@@ -1,207 +0,0 @@
-#include <hlib.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-char HEX_CHARS[] = "0123456789ABCDEF";
-
-void putHex(char **write, uintptr_t x) {
-    if (x == 0) {
-        **write = HEX_CHARS[x];
-        (*write)++;
-        **write = HEX_CHARS[x];
-        (*write)++;
-        return;
-    }
-    bool alreadyWriting = false;
-    for (int position = 3; position >= 0; position--) {
-        uint8_t byte = (x >> (position * 8)) & 0xFF;
-        if (byte != 0x00 && !alreadyWriting) {
-            alreadyWriting = true;
-        }
-        if (alreadyWriting) {
-            **write = HEX_CHARS[byte >> 4];
-            (*write)++;
-            **write = HEX_CHARS[byte & 0x0F];
-            (*write)++;
-        }
-    }
-}
-
-uint8_t hexLength(uintptr_t x) {
-    bool alreadyWriting = false;
-    uint8_t size = 0;
-    for (int position = sizeof(uintptr_t); position >= 0; position--) {
-        uint8_t byte = (x >> (position * 8)) & 0xFF;
-        if (byte != 0x00 && !alreadyWriting) {
-            alreadyWriting = true;
-        }
-        if (alreadyWriting) {
-            size += 2;
-        }
-    }
-    return MAX(size, 2);
-}
-
-uint32_t power(uintptr_t x, uintptr_t y) {
-    uintptr_t result = 1;
-    for (uintptr_t i = 0; i < y; i++) {
-        result *= x;
-    }
-    return result;
-}
-
-uint32_t intLength(intptr_t x) {
-    if (x == 0) {
-        return 1;
-    }
-    for (intptr_t i = 10; i >= 0; i--) {
-        if (x / power(10, i) > 0) {
-            return i + 1;
-        }
-    }
-    return 1;
-}
-
-void addChar(char **write, char c) {
-    **write = c;
-    (*write)++;
-}
-
-void putInt(char **write, intptr_t x) {
-    if (x == 0) {
-        addChar(write, '0');
-        return;
-    }
-    if (x < 0) {
-        addChar(write, '-');
-        x *= -1;
-    }
-    for (intptr_t i = 10; i >= 0; i--) {
-        uintptr_t n = x / power(10, i);
-        if (n) {
-            addChar(write, HEX_CHARS[n % 10]);
-        }
-    }
-}
-
-void putPadding(char **write, uintptr_t x) {
-    x = MIN(x, 10); // max 10 wide padding
-    for (intptr_t i = 0; i < x; i++) {
-        addChar(write, ' ');
-    }
-}
-
-uint32_t getInsertLength(char insertType, intptr_t x) {
-    switch (insertType) {
-    case 's':
-        return strlen((char *)x);
-    case 'x':
-        return hexLength(x);
-    case 'c':
-        return 1;
-    case 'i':
-        return intLength(x) + (x < 0);
-    case 'p':
-        return x;
-    }
-    return 0;
-}
-
-void stringInsert(char **write, uintptr_t x) {
-    char *string = (char *)x;
-    uint32_t length = strlen(string);
-    for (uint32_t position = 0; position < length; position++) {
-        **write = string[position];
-        (*write)++;
-    }
-}
-
-void handleInsert(char **write, char insertType, uintptr_t x) {
-    switch (insertType) {
-    case 's':
-        stringInsert(write, x);
-        return;
-    case 'x':
-        putHex(write, x);
-        return;
-    case 'c':
-        **write = x;
-        (*write)++;
-        return;
-    case 'i':
-        putInt(write, x);
-        return;
-    case 'p':
-        putPadding(write, x);
-        return;
-    }
-}
-uint32_t ioManager, logFunction;
-
-uint32_t printfSize(const char *format, va_list *valist) {
-    uint32_t size = 0;
-    for (; format[size] != 0; size++) {
-        if (format[size] == '%') {
-            char insertType = format[++size];
-            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
-            continue;
-        }
-    }
-    return size;
-}
-
-void _sprintf(char *data, const char *format, va_list *valist) {
-    char *write = data;
-    for (int i = 0; format[i] != 0; i++) {
-        if (format[i] == '%') {
-            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
-            continue;
-        }
-        *write = format[i];
-        write++;
-    }
-}
-
-void sprintf(char *data, const char *format, ...) {
-    va_list valist;
-    va_start(valist, format);
-    _sprintf(data, format, &valist);
-    va_end(valist);
-}
-
-char *_asprintf(AllocationData allocationData, const char *format, ...) {
-    va_list valist;
-    va_start(valist, format);
-    uint32_t size = printfSize(format, &valist);
-    char *data = malloc(size);
-    va_start(valist, format);
-    _sprintf(data, format, &valist);
-    va_end(valist);
-    return data;
-}
-
-void _printf(AllocationData allocationData, const char *format, ...) {
-    // I have absolutely no idea why this line fixes an issue where the first
-    // printf operation consistently doesn't correctly insert its string
-    free(malloc(1));
-    va_list valist;
-    va_start(valist, format);
-    char *data = malloc(printfSize(format, &valist));
-    va_start(valist, format);
-    _sprintf(data, format, &valist);
-    va_end(valist);
-    uintptr_t id = insertString(data);
-    request(ioManager, logFunction, id, 0);
-    discardString(id);
-    free(data);
-}
-
-void gets(char *buffer) {
-    static uint32_t function = 0;
-    if (!function) {
-        function = getFunction(ioManager, "gets");
-    }
-    uint32_t stringId = request(ioManager, function, 0, 0);
-    readString(stringId, buffer);
-}

diff --git a/Makefile b/Makefile
index fdd033b..6a72399 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%)
 USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%)
 
-run: build initrd user/hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
+run: build initrd hlib $(USER_PROGRAM_NAMES) $(IMAGE_FILE)
 	@echo "starting qemu"
 	@$(EMU) $(EMUFLAGS)
 
@@ -71,6 +71,10 @@
 	@echo "compiling userspace program $<"
 	@make -C $<
 
+hlib:
+	@echo "compiling userspace honey-os library"
+	@make -C src/hlib
+
 clean:
 	@echo "clearing build folder"
 	@rm -r $(BUILD_FOLDER) initrd src/userland/*/build
diff --git a/src/hlib/Makefile b/src/hlib/Makefile
new file mode 100644
index 0000000..2eb5937
--- /dev/null
+++ b/src/hlib/Makefile
@@ -0,0 +1,30 @@
+CC = i686-elf-gcc
+CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
+LD = i686-elf-ld
+LD_FLAGS = -z max-page-size=0x1000 
+AS = nasm
+ASFlAGS = -felf32
+
+BUILD_FOLDER = build
+
+SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
+OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
+
+../../initrd/hlib: $(OBJS)
+	@echo "linking the honey OS c libary"
+	@$(LD) $(LD_FLAGS) -o ../../build/hlib.o $(OBJS) -T link.ld -r
+	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
+
+$(BUILD_FOLDER)/%.asm.o: %.asm
+	@echo "asembling $<"
+	@mkdir -p $(dir $@)
+	@$(AS) $(ASFlAGS) $< -o $@
+
+$(BUILD_FOLDER)/%.c.o: %.c
+	@echo "compiling $<"
+	@mkdir -p $(dir $@)
+	@$(CC) $(CCFLAGS) -r $< -o $@
+
+clean:
+	@echo "clearing build folder"
+	@rm -r $(BUILD_FOLDER)
diff --git a/src/hlib/compile_flags.txt b/src/hlib/compile_flags.txt
new file mode 100644
index 0000000..a432e7b
--- /dev/null
+++ b/src/hlib/compile_flags.txt
@@ -0,0 +1,6 @@
+-I./include
+-I../../include
+clang
+-fms-extensions
+-Wno-microsoft-anon-tag
+-Wno-incompatible-library-redeclaration
diff --git a/src/hlib/include/syscalls.h b/src/hlib/include/syscalls.h
new file mode 100644
index 0000000..2025b24
--- /dev/null
+++ b/src/hlib/include/syscalls.h
@@ -0,0 +1,36 @@
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+    SYS_RUN = 0,
+    SYS_CREATE_FUNCTION = 1,
+    SYS_REQUEST = 2,
+    SYS_IO_IN = 3,
+    SYS_IO_OUT = 4,
+    SYS_LOAD_INITRD = 5,
+    SYS_GET_SERVICE = 6,
+    SYS_GET_FUNCTION = 7,
+    SYS_SUBSCRIBE_INTERRUPT = 8,
+    SYS_CREATE_EVENT = 9,
+    SYS_GET_EVENT = 10,
+    SYS_FIRE_EVENT = 11,
+    SYS_SUBSCRIBE_EVENT = 12,
+    SYS_GET_SERVICE_ID = 13,
+    SYS_INSERT_STRING = 14,
+    SYS_GET_STRING_LENGTH = 15,
+    SYS_READ_STRING = 16,
+    SYS_DISCARD_STRING = 17,
+    SYS_REQUEST_MEMORY = 18,
+    SYS_LOOKUP_SYMBOL = 19,
+    SYS_STACK_CONTAINS = 20,
+    SYS_AWAIT = 21,
+    SYS_GET_PHYSICAL = 22,
+    SYS_FORK = 23,
+} SyscallIds;
+
+extern uint32_t getFunction(uint32_t module, char *name);
+
+#endif
diff --git a/src/hlib/io.c b/src/hlib/io.c
new file mode 100644
index 0000000..5a6c3f3
--- /dev/null
+++ b/src/hlib/io.c
@@ -0,0 +1,14 @@
+#include <hlib.h>
+#include <syscalls.h>
+
+uint32_t ioIn(uint16_t port, uint8_t size) {
+    return syscall(SYS_IO_IN, size, port, 0, 0);
+}
+
+void ioOut(uint16_t port, uint32_t value, uint8_t size) {
+    syscall(SYS_IO_OUT, size, port, value, 0);
+}
+
+void subscribeInterrupt(uint32_t intNo, void *handler) {
+    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
+}
diff --git a/src/hlib/link.ld b/src/hlib/link.ld
new file mode 100644
index 0000000..e38b0df
--- /dev/null
+++ b/src/hlib/link.ld
@@ -0,0 +1,12 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0xFF000000;
+
+    .hlib : {
+        *(.text)
+        *(.rodata)
+        *(.data)
+        *(.bss)
+    }
+}
diff --git a/src/hlib/list.c b/src/hlib/list.c
new file mode 100644
index 0000000..ffc0ed6
--- /dev/null
+++ b/src/hlib/list.c
@@ -0,0 +1,78 @@
+#include <hlib.h>
+
+void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
+    ListElement *element = malloc(sizeof(ListElement));
+    element->data = data;
+    element->next = NULL;
+    if (!*list) {
+        *list = element;
+        return;
+    }
+    ListElement *current = *list;
+    while (current->next) {
+        current = current->next;
+    }
+    current->next = element;
+}
+
+void *listPopFirst(ListElement **list) {
+    if (!*list) {
+        return NULL;
+    }
+    ListElement *resultElement = *list;
+    void *result = resultElement->data;
+    *list = (*list)->next;
+    free(resultElement);
+    return result;
+}
+
+uint32_t listCount(ListElement *list) {
+    uint32_t i = 0;
+    foreach (list, void *, element, { i++; })
+        ;
+    return i;
+}
+
+void *listGet(ListElement *list, uint32_t position) {
+    for (uint32_t i = 0; i < position; i++) {
+        list = list->next;
+    }
+    return list->data;
+}
+
+bool listRemoveValue(ListElement **list, void *value) {
+    if (!*list) {
+        return false;
+    }
+    ListElement *element = *list, *previous = NULL;
+    while (element) {
+        if (element->data == value) {
+            if (previous) {
+                previous->next = element->next;
+            } else {
+                *list = element->next;
+            }
+            free(element);
+            return true;
+        }
+        previous = element;
+        element = element->next;
+    }
+    return false;
+}
+
+void listClear(ListElement **list, bool freeData) {
+    ListElement *current = *list;
+    if (!current) {
+        return;
+    }
+    while (current->next) {
+        if (freeData) {
+            free(current->data);
+        }
+        ListElement *next = current->next;
+        free(current);
+        current = next;
+    }
+    *list = NULL;
+}
diff --git a/src/hlib/main.c b/src/hlib/main.c
new file mode 100644
index 0000000..43ac97d
--- /dev/null
+++ b/src/hlib/main.c
@@ -0,0 +1,84 @@
+#include "include/syscalls.h"
+#include <hlib.h>
+#include <stdint.h>
+
+uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
+                 uint32_t parameter2, uint32_t parameter3) {
+    uint32_t esp;
+    asm("push %%eax" ::"a"(&&end)); // end: return address
+    asm("mov %%esp, %%eax" : "=a"(esp));
+    asm("sysenter\n"
+        :
+        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
+          "S"(parameter3), "D"(esp));
+// eax is set by the kernel as the return value
+end:
+    // the 0x1C comes from the number of parameters / local variables do handle
+    // this function with care or it will break everything
+    asm("add $0x1C, %%esp\n"
+        "pop %%ebp\n"
+        "ret" ::);
+    // don't go here! ret returns with the correct value
+    return 0;
+}
+
+uint32_t loadFromInitrd(char *name) {
+    uintptr_t id = insertString(name);
+    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+    if (!service) {
+        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
+    }
+    return service;
+}
+
+uint32_t loadFromInitrdUninitialized(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
+}
+
+void requestName(char *service, char *provider, uintptr_t data1,
+                 uintptr_t data2) {
+    uint32_t serviceId = getService(service);
+    uint32_t providerId = getFunction(serviceId, provider);
+    request(serviceId, providerId, data1, data2);
+}
+
+void *requestMemory(uint32_t pageCount, void *targetAddress,
+                    void *physicalAddress) {
+    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
+                       U32(physicalAddress), 0));
+}
+
+void *getPage() { return requestMemory(1, NULL, NULL); }
+
+void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
+
+void freePage(void *location) {}
+
+void memset(void *_target, uint8_t byte, uint32_t size) {
+    uint8_t *target = _target;
+    for (uint32_t i = 0; i < size; i++) {
+        *target = byte;
+        target++;
+    }
+}
+
+bool stackContains(uint32_t serviceId) {
+    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
+}
+
+#define REQUEST1(returnType, functionName, service, function)                  \
+    returnType functionName(uint32_t data) {                                   \
+        static uint32_t serviceId = 0;                                         \
+        if (!serviceId) {                                                      \
+            serviceId = getService(service);                                   \
+            serviceId = getService(service);                                   \
+        }                                                                      \
+        static uint32_t functionId = 0;                                        \
+        if (!functionId) {                                                     \
+            functionId = getFunction(serviceId, function);                     \
+        }                                                                      \
+        return (returnType)request(serviceId, functionId, data, 0);            \
+    }
+
+REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/hlib/malloc.c b/src/hlib/malloc.c
new file mode 120000
index 0000000..3eec597
--- /dev/null
+++ b/src/hlib/malloc.c
@@ -0,0 +1 @@
+../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/hlib/malloc.h b/src/hlib/malloc.h
new file mode 120000
index 0000000..26dc6d5
--- /dev/null
+++ b/src/hlib/malloc.h
@@ -0,0 +1 @@
+../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/hlib/service/events.c b/src/hlib/service/events.c
new file mode 100644
index 0000000..9429c44
--- /dev/null
+++ b/src/hlib/service/events.c
@@ -0,0 +1,58 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t createEvent(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uintptr_t hashString(char *string) {
+    uintptr_t hash = 0;
+    for (uintptr_t i = 0; string[i]; i++) {
+        hash = 257 * hash + string[i];
+    }
+    return hash;
+}
+
+uint32_t getEvent(uint32_t service, char *name) {
+    uintptr_t id = hashString(name);
+    return syscall(SYS_GET_EVENT, service, id, 0, 0);
+}
+
+void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
+    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
+}
+
+void fireEvent(uint32_t eventNumber, uint32_t data) {
+    fireEventCode(eventNumber, data, 0);
+}
+
+void subscribeEvent(uint32_t service, uint32_t event,
+                    void(handler)(void *, uint32_t)) {
+    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
+}
+
+uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
+    return syscall(SYS_AWAIT, service, event, code, 0);
+}
+
+uint32_t await(uint32_t service, uint32_t event) {
+    return awaitCode(service, event, 0);
+}
+
+uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
+    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
+}
+
+uint32_t createDirectEvent(uint32_t id) {
+    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
+}
+
+uint32_t createDirectEventSave(uint32_t id) {
+    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
+    if (existingEvent) {
+        return existingEvent;
+    }
+    return createDirectEvent(id);
+}
diff --git a/src/hlib/service/service.c b/src/hlib/service/service.c
new file mode 100644
index 0000000..1669154
--- /dev/null
+++ b/src/hlib/service/service.c
@@ -0,0 +1,39 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
+                 uintptr_t data2) {
+    return syscall(SYS_REQUEST, service, function, data1, data2);
+}
+
+uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
+}
+
+uint32_t getService(char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
+}
+
+uint32_t getFunction(uint32_t module, char *name) {
+    uintptr_t id = insertString(name);
+    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
+}
+
+uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
+
+uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
+    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
+}
+
+void *getPhysicalAddress(void *source) {
+    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
+               (U32(source) & 0xFFF));
+}
+
+uint32_t fork(void (f)(), void *a, void *b, void *c) {
+    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
+}
+
diff --git a/src/hlib/stdio.c b/src/hlib/stdio.c
new file mode 100644
index 0000000..e717154
--- /dev/null
+++ b/src/hlib/stdio.c
@@ -0,0 +1,207 @@
+#include <hlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+char HEX_CHARS[] = "0123456789ABCDEF";
+
+void putHex(char **write, uintptr_t x) {
+    if (x == 0) {
+        **write = HEX_CHARS[x];
+        (*write)++;
+        **write = HEX_CHARS[x];
+        (*write)++;
+        return;
+    }
+    bool alreadyWriting = false;
+    for (int position = 3; position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            **write = HEX_CHARS[byte >> 4];
+            (*write)++;
+            **write = HEX_CHARS[byte & 0x0F];
+            (*write)++;
+        }
+    }
+}
+
+uint8_t hexLength(uintptr_t x) {
+    bool alreadyWriting = false;
+    uint8_t size = 0;
+    for (int position = sizeof(uintptr_t); position >= 0; position--) {
+        uint8_t byte = (x >> (position * 8)) & 0xFF;
+        if (byte != 0x00 && !alreadyWriting) {
+            alreadyWriting = true;
+        }
+        if (alreadyWriting) {
+            size += 2;
+        }
+    }
+    return MAX(size, 2);
+}
+
+uint32_t power(uintptr_t x, uintptr_t y) {
+    uintptr_t result = 1;
+    for (uintptr_t i = 0; i < y; i++) {
+        result *= x;
+    }
+    return result;
+}
+
+uint32_t intLength(intptr_t x) {
+    if (x == 0) {
+        return 1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        if (x / power(10, i) > 0) {
+            return i + 1;
+        }
+    }
+    return 1;
+}
+
+void addChar(char **write, char c) {
+    **write = c;
+    (*write)++;
+}
+
+void putInt(char **write, intptr_t x) {
+    if (x == 0) {
+        addChar(write, '0');
+        return;
+    }
+    if (x < 0) {
+        addChar(write, '-');
+        x *= -1;
+    }
+    for (intptr_t i = 10; i >= 0; i--) {
+        uintptr_t n = x / power(10, i);
+        if (n) {
+            addChar(write, HEX_CHARS[n % 10]);
+        }
+    }
+}
+
+void putPadding(char **write, uintptr_t x) {
+    x = MIN(x, 10); // max 10 wide padding
+    for (intptr_t i = 0; i < x; i++) {
+        addChar(write, ' ');
+    }
+}
+
+uint32_t getInsertLength(char insertType, intptr_t x) {
+    switch (insertType) {
+    case 's':
+        return strlen((char *)x);
+    case 'x':
+        return hexLength(x);
+    case 'c':
+        return 1;
+    case 'i':
+        return intLength(x) + (x < 0);
+    case 'p':
+        return x;
+    }
+    return 0;
+}
+
+void stringInsert(char **write, uintptr_t x) {
+    char *string = (char *)x;
+    uint32_t length = strlen(string);
+    for (uint32_t position = 0; position < length; position++) {
+        **write = string[position];
+        (*write)++;
+    }
+}
+
+void handleInsert(char **write, char insertType, uintptr_t x) {
+    switch (insertType) {
+    case 's':
+        stringInsert(write, x);
+        return;
+    case 'x':
+        putHex(write, x);
+        return;
+    case 'c':
+        **write = x;
+        (*write)++;
+        return;
+    case 'i':
+        putInt(write, x);
+        return;
+    case 'p':
+        putPadding(write, x);
+        return;
+    }
+}
+uint32_t ioManager, logFunction;
+
+uint32_t printfSize(const char *format, va_list *valist) {
+    uint32_t size = 0;
+    for (; format[size] != 0; size++) {
+        if (format[size] == '%') {
+            char insertType = format[++size];
+            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
+            continue;
+        }
+    }
+    return size;
+}
+
+void _sprintf(char *data, const char *format, va_list *valist) {
+    char *write = data;
+    for (int i = 0; format[i] != 0; i++) {
+        if (format[i] == '%') {
+            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
+            continue;
+        }
+        *write = format[i];
+        write++;
+    }
+}
+
+void sprintf(char *data, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+}
+
+char *_asprintf(AllocationData allocationData, const char *format, ...) {
+    va_list valist;
+    va_start(valist, format);
+    uint32_t size = printfSize(format, &valist);
+    char *data = malloc(size);
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    return data;
+}
+
+void _printf(AllocationData allocationData, const char *format, ...) {
+    // I have absolutely no idea why this line fixes an issue where the first
+    // printf operation consistently doesn't correctly insert its string
+    free(malloc(1));
+    va_list valist;
+    va_start(valist, format);
+    char *data = malloc(printfSize(format, &valist));
+    va_start(valist, format);
+    _sprintf(data, format, &valist);
+    va_end(valist);
+    uintptr_t id = insertString(data);
+    request(ioManager, logFunction, id, 0);
+    discardString(id);
+    free(data);
+}
+
+void gets(char *buffer) {
+    static uint32_t function = 0;
+    if (!function) {
+        function = getFunction(ioManager, "gets");
+    }
+    uint32_t stringId = request(ioManager, function, 0, 0);
+    readString(stringId, buffer);
+}
diff --git a/src/hlib/strings.c b/src/hlib/strings.c
new file mode 100644
index 0000000..78fff55
--- /dev/null
+++ b/src/hlib/strings.c
@@ -0,0 +1,38 @@
+#include <hlib.h>
+#include <stdint.h>
+#include <syscalls.h>
+
+uint32_t strlen(char *string) {
+    if (!string) {
+        return 0;
+    }
+    uint32_t size = 0;
+    while (*string) {
+        string++;
+        size++;
+    }
+    return size;
+}
+
+void memcpy(void *from, void *to, uint32_t size) {
+    uint8_t *a = from, *b = to;
+    for (uint32_t i = 0; i < size; i++) {
+        b[i] = a[i];
+    }
+}
+
+uintptr_t insertString(char *string) {
+    return syscall(SYS_INSERT_STRING, U32(string), 0, 0, 0);
+}
+
+uintptr_t getStringLength(uintptr_t stringId) {
+    return syscall(SYS_GET_STRING_LENGTH, stringId, 0, 0, 0);
+}
+
+void readString(uintptr_t stringId, void *buffer) {
+    syscall(SYS_READ_STRING, stringId, U32(buffer), 0, 0);
+}
+
+void discardString(uintptr_t stringId) {
+    syscall(SYS_DISCARD_STRING, stringId, 0, 0, 0);
+}
diff --git a/src/include/hlib.h b/src/include/hlib.h
index a8da877..ed26b16 100644
--- a/src/include/hlib.h
+++ b/src/include/hlib.h
@@ -9,7 +9,7 @@
     void *data;
 } ListElement;
 
-#include "../userland/hlib/malloc.h"
+#include "../hlib/malloc.h"
 
 #define PTR(x) ((void *)(uintptr_t)(x))
 #define U32(x) ((uint32_t)(uintptr_t)(x))
diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile
deleted file mode 100644
index 4870f51..0000000
--- a/src/userland/hlib/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-CC = i686-elf-gcc
-CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0
-LD = i686-elf-ld
-LD_FLAGS = -z max-page-size=0x1000 
-AS = nasm
-ASFlAGS = -felf32
-
-BUILD_FOLDER = build
-
-SOURCE_FILES := $(shell find . -name "*.c" -or -name "*.asm")
-OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o)
-
-../../../initrd/hlib: $(OBJS)
-	@echo "linking the honey OS c libary"
-	@$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r
-	@$(LD) $(LD_FLAGS) -o $@ $(OBJS) -T link.ld
-
-$(BUILD_FOLDER)/%.asm.o: %.asm
-	@echo "asembling $<"
-	@mkdir -p $(dir $@)
-	@$(AS) $(ASFlAGS) $< -o $@
-
-$(BUILD_FOLDER)/%.c.o: %.c
-	@echo "compiling $<"
-	@mkdir -p $(dir $@)
-	@$(CC) $(CCFLAGS) -r $< -o $@
-
-clean:
-	@echo "clearing build folder"
-	@rm -r $(BUILD_FOLDER)
diff --git a/src/userland/hlib/compile_flags.txt b/src/userland/hlib/compile_flags.txt
deleted file mode 100644
index a432e7b..0000000
--- a/src/userland/hlib/compile_flags.txt
+++ /dev/null
@@ -1,6 +0,0 @@
--I./include
--I../../include
-clang
--fms-extensions
--Wno-microsoft-anon-tag
--Wno-incompatible-library-redeclaration
diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h
deleted file mode 100644
index 2025b24..0000000
--- a/src/userland/hlib/include/syscalls.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef SYSCALLS_H
-#define SYSCALLS_H
-
-#include <stdbool.h>
-#include <stdint.h>
-
-typedef enum {
-    SYS_RUN = 0,
-    SYS_CREATE_FUNCTION = 1,
-    SYS_REQUEST = 2,
-    SYS_IO_IN = 3,
-    SYS_IO_OUT = 4,
-    SYS_LOAD_INITRD = 5,
-    SYS_GET_SERVICE = 6,
-    SYS_GET_FUNCTION = 7,
-    SYS_SUBSCRIBE_INTERRUPT = 8,
-    SYS_CREATE_EVENT = 9,
-    SYS_GET_EVENT = 10,
-    SYS_FIRE_EVENT = 11,
-    SYS_SUBSCRIBE_EVENT = 12,
-    SYS_GET_SERVICE_ID = 13,
-    SYS_INSERT_STRING = 14,
-    SYS_GET_STRING_LENGTH = 15,
-    SYS_READ_STRING = 16,
-    SYS_DISCARD_STRING = 17,
-    SYS_REQUEST_MEMORY = 18,
-    SYS_LOOKUP_SYMBOL = 19,
-    SYS_STACK_CONTAINS = 20,
-    SYS_AWAIT = 21,
-    SYS_GET_PHYSICAL = 22,
-    SYS_FORK = 23,
-} SyscallIds;
-
-extern uint32_t getFunction(uint32_t module, char *name);
-
-#endif
diff --git a/src/userland/hlib/io.c b/src/userland/hlib/io.c
deleted file mode 100644
index 5a6c3f3..0000000
--- a/src/userland/hlib/io.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <hlib.h>
-#include <syscalls.h>
-
-uint32_t ioIn(uint16_t port, uint8_t size) {
-    return syscall(SYS_IO_IN, size, port, 0, 0);
-}
-
-void ioOut(uint16_t port, uint32_t value, uint8_t size) {
-    syscall(SYS_IO_OUT, size, port, value, 0);
-}
-
-void subscribeInterrupt(uint32_t intNo, void *handler) {
-    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
-}
diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld
deleted file mode 100644
index e38b0df..0000000
--- a/src/userland/hlib/link.ld
+++ /dev/null
@@ -1,12 +0,0 @@
-OUTPUT_ARCH(i386)
-
-SECTIONS {
-    . = 0xFF000000;
-
-    .hlib : {
-        *(.text)
-        *(.rodata)
-        *(.data)
-        *(.bss)
-    }
-}
diff --git a/src/userland/hlib/list.c b/src/userland/hlib/list.c
deleted file mode 100644
index ffc0ed6..0000000
--- a/src/userland/hlib/list.c
+++ /dev/null
@@ -1,78 +0,0 @@
-#include <hlib.h>
-
-void _listAdd(AllocationData allocationData, ListElement **list, void *data) {
-    ListElement *element = malloc(sizeof(ListElement));
-    element->data = data;
-    element->next = NULL;
-    if (!*list) {
-        *list = element;
-        return;
-    }
-    ListElement *current = *list;
-    while (current->next) {
-        current = current->next;
-    }
-    current->next = element;
-}
-
-void *listPopFirst(ListElement **list) {
-    if (!*list) {
-        return NULL;
-    }
-    ListElement *resultElement = *list;
-    void *result = resultElement->data;
-    *list = (*list)->next;
-    free(resultElement);
-    return result;
-}
-
-uint32_t listCount(ListElement *list) {
-    uint32_t i = 0;
-    foreach (list, void *, element, { i++; })
-        ;
-    return i;
-}
-
-void *listGet(ListElement *list, uint32_t position) {
-    for (uint32_t i = 0; i < position; i++) {
-        list = list->next;
-    }
-    return list->data;
-}
-
-bool listRemoveValue(ListElement **list, void *value) {
-    if (!*list) {
-        return false;
-    }
-    ListElement *element = *list, *previous = NULL;
-    while (element) {
-        if (element->data == value) {
-            if (previous) {
-                previous->next = element->next;
-            } else {
-                *list = element->next;
-            }
-            free(element);
-            return true;
-        }
-        previous = element;
-        element = element->next;
-    }
-    return false;
-}
-
-void listClear(ListElement **list, bool freeData) {
-    ListElement *current = *list;
-    if (!current) {
-        return;
-    }
-    while (current->next) {
-        if (freeData) {
-            free(current->data);
-        }
-        ListElement *next = current->next;
-        free(current);
-        current = next;
-    }
-    *list = NULL;
-}
diff --git a/src/userland/hlib/main.c b/src/userland/hlib/main.c
deleted file mode 100644
index 43ac97d..0000000
--- a/src/userland/hlib/main.c
+++ /dev/null
@@ -1,84 +0,0 @@
-#include "include/syscalls.h"
-#include <hlib.h>
-#include <stdint.h>
-
-uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
-                 uint32_t parameter2, uint32_t parameter3) {
-    uint32_t esp;
-    asm("push %%eax" ::"a"(&&end)); // end: return address
-    asm("mov %%esp, %%eax" : "=a"(esp));
-    asm("sysenter\n"
-        :
-        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
-          "S"(parameter3), "D"(esp));
-// eax is set by the kernel as the return value
-end:
-    // the 0x1C comes from the number of parameters / local variables do handle
-    // this function with care or it will break everything
-    asm("add $0x1C, %%esp\n"
-        "pop %%ebp\n"
-        "ret" ::);
-    // don't go here! ret returns with the correct value
-    return 0;
-}
-
-uint32_t loadFromInitrd(char *name) {
-    uintptr_t id = insertString(name);
-    uint32_t service = syscall(SYS_GET_SERVICE, id, 0, 0, 0);
-    if (!service) {
-        return syscall(SYS_LOAD_INITRD, id, 1, 0, 0);
-    }
-    return service;
-}
-
-uint32_t loadFromInitrdUninitialized(char *name) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_LOAD_INITRD, id, 0, 0, 0);
-}
-
-void requestName(char *service, char *provider, uintptr_t data1,
-                 uintptr_t data2) {
-    uint32_t serviceId = getService(service);
-    uint32_t providerId = getFunction(serviceId, provider);
-    request(serviceId, providerId, data1, data2);
-}
-
-void *requestMemory(uint32_t pageCount, void *targetAddress,
-                    void *physicalAddress) {
-    return PTR(syscall(SYS_REQUEST_MEMORY, pageCount, U32(targetAddress),
-                       U32(physicalAddress), 0));
-}
-
-void *getPage() { return requestMemory(1, NULL, NULL); }
-
-void *getPagesCount(uint32_t count) { return requestMemory(count, NULL, NULL); }
-
-void freePage(void *location) {}
-
-void memset(void *_target, uint8_t byte, uint32_t size) {
-    uint8_t *target = _target;
-    for (uint32_t i = 0; i < size; i++) {
-        *target = byte;
-        target++;
-    }
-}
-
-bool stackContains(uint32_t serviceId) {
-    return syscall(SYS_STACK_CONTAINS, serviceId, 0, 0, 0);
-}
-
-#define REQUEST1(returnType, functionName, service, function)                  \
-    returnType functionName(uint32_t data) {                                   \
-        static uint32_t serviceId = 0;                                         \
-        if (!serviceId) {                                                      \
-            serviceId = getService(service);                                   \
-            serviceId = getService(service);                                   \
-        }                                                                      \
-        static uint32_t functionId = 0;                                        \
-        if (!functionId) {                                                     \
-            functionId = getFunction(serviceId, function);                     \
-        }                                                                      \
-        return (returnType)request(serviceId, functionId, data, 0);            \
-    }
-
-REQUEST1(void, sleep, "pit", "sleep")
diff --git a/src/userland/hlib/malloc.c b/src/userland/hlib/malloc.c
deleted file mode 120000
index 022d82b..0000000
--- a/src/userland/hlib/malloc.c
+++ /dev/null
@@ -1 +0,0 @@
-../../kernel/memory/malloc.c
\ No newline at end of file
diff --git a/src/userland/hlib/malloc.h b/src/userland/hlib/malloc.h
deleted file mode 120000
index 8a56b0a..0000000
--- a/src/userland/hlib/malloc.h
+++ /dev/null
@@ -1 +0,0 @@
-../../kernel/memory/malloc.h
\ No newline at end of file
diff --git a/src/userland/hlib/service/events.c b/src/userland/hlib/service/events.c
deleted file mode 100644
index 9429c44..0000000
--- a/src/userland/hlib/service/events.c
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <hlib.h>
-#include <stdint.h>
-#include <syscalls.h>
-
-uint32_t createEvent(char *name) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
-}
-
-uintptr_t hashString(char *string) {
-    uintptr_t hash = 0;
-    for (uintptr_t i = 0; string[i]; i++) {
-        hash = 257 * hash + string[i];
-    }
-    return hash;
-}
-
-uint32_t getEvent(uint32_t service, char *name) {
-    uintptr_t id = hashString(name);
-    return syscall(SYS_GET_EVENT, service, id, 0, 0);
-}
-
-void fireEventCode(uint32_t eventNumber, uint32_t data, uint32_t code) {
-    syscall(SYS_FIRE_EVENT, eventNumber, data, code, 0);
-}
-
-void fireEvent(uint32_t eventNumber, uint32_t data) {
-    fireEventCode(eventNumber, data, 0);
-}
-
-void subscribeEvent(uint32_t service, uint32_t event,
-                    void(handler)(void *, uint32_t)) {
-    syscall(SYS_SUBSCRIBE_EVENT, service, event, U32(handler), 0);
-}
-
-uint32_t awaitCode(uint32_t service, uint32_t event, uint32_t code) {
-    return syscall(SYS_AWAIT, service, event, code, 0);
-}
-
-uint32_t await(uint32_t service, uint32_t event) {
-    return awaitCode(service, event, 0);
-}
-
-uint32_t getDirectEvent(uint32_t serviceId, uint32_t id) {
-    return syscall(SYS_GET_EVENT, serviceId, id, 0, 0);
-}
-
-uint32_t createDirectEvent(uint32_t id) {
-    return syscall(SYS_CREATE_EVENT, id, 0, 0, 0);
-}
-
-uint32_t createDirectEventSave(uint32_t id) {
-    uint32_t existingEvent = getDirectEvent(getServiceId(), id);
-    if (existingEvent) {
-        return existingEvent;
-    }
-    return createDirectEvent(id);
-}
diff --git a/src/userland/hlib/service/service.c b/src/userland/hlib/service/service.c
deleted file mode 100644
index 1669154..0000000
--- a/src/userland/hlib/service/service.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include <hlib.h>
-#include <stdint.h>
-#include <syscalls.h>
-
-uint32_t request(uint32_t service, uint32_t function, uintptr_t data1,
-                 uintptr_t data2) {
-    return syscall(SYS_REQUEST, service, function, data1, data2);
-}
-
-uint32_t createFunction(char *name, int32_t(handler)(void *, uint32_t)) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_CREATE_FUNCTION, id, U32(handler), 0, 0);
-}
-
-uint32_t getService(char *name) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_GET_SERVICE, id, 0, 0, 0);
-}
-
-uint32_t getFunction(uint32_t module, char *name) {
-    uintptr_t id = insertString(name);
-    return syscall(SYS_GET_FUNCTION, module, id, 0, 0);
-}
-
-uint32_t getServiceId() { return syscall(SYS_GET_SERVICE_ID, 0, 0, 0, 0); }
-
-uint32_t lookupSymbol(uint32_t serviceId, uint32_t address) {
-    return syscall(SYS_LOOKUP_SYMBOL, serviceId, address, 0, 0);
-}
-
-void *getPhysicalAddress(void *source) {
-    return PTR(syscall(SYS_GET_PHYSICAL, U32(source) & ~0xFFF, 0, 0, 0) |
-               (U32(source) & 0xFFF));
-}
-
-uint32_t fork(void (f)(), void *a, void *b, void *c) {
-    return syscall(SYS_FORK, U32(f), U32(a), U32(b), U32(c));
-}
-
diff --git a/src/userland/hlib/stdio.c b/src/userland/hlib/stdio.c
deleted file mode 100644
index e717154..0000000
--- a/src/userland/hlib/stdio.c
+++ /dev/null
@@ -1,207 +0,0 @@
-#include <hlib.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-char HEX_CHARS[] = "0123456789ABCDEF";
-
-void putHex(char **write, uintptr_t x) {
-    if (x == 0) {
-        **write = HEX_CHARS[x];
-        (*write)++;
-        **write = HEX_CHARS[x];
-        (*write)++;
-        return;
-    }
-    bool alreadyWriting = false;
-    for (int position = 3; position >= 0; position--) {
-        uint8_t byte = (x >> (position * 8)) & 0xFF;
-        if (byte != 0x00 && !alreadyWriting) {
-            alreadyWriting = true;
-        }
-        if (alreadyWriting) {
-            **write = HEX_CHARS[byte >> 4];
-            (*write)++;
-            **write = HEX_CHARS[byte & 0x0F];
-            (*write)++;
-        }
-    }
-}
-
-uint8_t hexLength(uintptr_t x) {
-    bool alreadyWriting = false;
-    uint8_t size = 0;
-    for (int position = sizeof(uintptr_t); position >= 0; position--) {
-        uint8_t byte = (x >> (position * 8)) & 0xFF;
-        if (byte != 0x00 && !alreadyWriting) {
-            alreadyWriting = true;
-        }
-        if (alreadyWriting) {
-            size += 2;
-        }
-    }
-    return MAX(size, 2);
-}
-
-uint32_t power(uintptr_t x, uintptr_t y) {
-    uintptr_t result = 1;
-    for (uintptr_t i = 0; i < y; i++) {
-        result *= x;
-    }
-    return result;
-}
-
-uint32_t intLength(intptr_t x) {
-    if (x == 0) {
-        return 1;
-    }
-    for (intptr_t i = 10; i >= 0; i--) {
-        if (x / power(10, i) > 0) {
-            return i + 1;
-        }
-    }
-    return 1;
-}
-
-void addChar(char **write, char c) {
-    **write = c;
-    (*write)++;
-}
-
-void putInt(char **write, intptr_t x) {
-    if (x == 0) {
-        addChar(write, '0');
-        return;
-    }
-    if (x < 0) {
-        addChar(write, '-');
-        x *= -1;
-    }
-    for (intptr_t i = 10; i >= 0; i--) {
-        uintptr_t n = x / power(10, i);
-        if (n) {
-            addChar(write, HEX_CHARS[n % 10]);
-        }
-    }
-}
-
-void putPadding(char **write, uintptr_t x) {
-    x = MIN(x, 10); // max 10 wide padding
-    for (intptr_t i = 0; i < x; i++) {
-        addChar(write, ' ');
-    }
-}
-
-uint32_t getInsertLength(char insertType, intptr_t x) {
-    switch (insertType) {
-    case 's':
-        return strlen((char *)x);
-    case 'x':
-        return hexLength(x);
-    case 'c':
-        return 1;
-    case 'i':
-        return intLength(x) + (x < 0);
-    case 'p':
-        return x;
-    }
-    return 0;
-}
-
-void stringInsert(char **write, uintptr_t x) {
-    char *string = (char *)x;
-    uint32_t length = strlen(string);
-    for (uint32_t position = 0; position < length; position++) {
-        **write = string[position];
-        (*write)++;
-    }
-}
-
-void handleInsert(char **write, char insertType, uintptr_t x) {
-    switch (insertType) {
-    case 's':
-        stringInsert(write, x);
-        return;
-    case 'x':
-        putHex(write, x);
-        return;
-    case 'c':
-        **write = x;
-        (*write)++;
-        return;
-    case 'i':
-        putInt(write, x);
-        return;
-    case 'p':
-        putPadding(write, x);
-        return;
-    }
-}
-uint32_t ioManager, logFunction;
-
-uint32_t printfSize(const char *format, va_list *valist) {
-    uint32_t size = 0;
-    for (; format[size] != 0; size++) {
-        if (format[size] == '%') {
-            char insertType = format[++size];
-            size += getInsertLength(insertType, va_arg(*valist, uintptr_t));
-            continue;
-        }
-    }
-    return size;
-}
-
-void _sprintf(char *data, const char *format, va_list *valist) {
-    char *write = data;
-    for (int i = 0; format[i] != 0; i++) {
-        if (format[i] == '%') {
-            handleInsert(&write, format[++i], va_arg(*valist, uintptr_t));
-            continue;
-        }
-        *write = format[i];
-        write++;
-    }
-}
-
-void sprintf(char *data, const char *format, ...) {
-    va_list valist;
-    va_start(valist, format);
-    _sprintf(data, format, &valist);
-    va_end(valist);
-}
-
-char *_asprintf(AllocationData allocationData, const char *format, ...) {
-    va_list valist;
-    va_start(valist, format);
-    uint32_t size = printfSize(format, &valist);
-    char *data = malloc(size);
-    va_start(valist, format);
-    _sprintf(data, format, &valist);
-    va_end(valist);
-    return data;
-}
-
-void _printf(AllocationData allocationData, const char *format, ...) {
-    // I have absolutely no idea why this line fixes an issue where the first
-    // printf operation consistently doesn't correctly insert its string
-    free(malloc(1));
-    va_list valist;
-    va_start(valist, format);
-    char *data = malloc(printfSize(format, &valist));
-    va_start(valist, format);
-    _sprintf(data, format, &valist);
-    va_end(valist);
-    uintptr_t id = insertString(data);
-    request(ioManager, logFunction, id, 0);
-    discardString(id);
-    free(data);
-}
-
-void gets(char *buffer) {
-    static uint32_t function = 0;
-    if (!function) {
-        function = getFunction(ioManager, "gets");
-    }
-    uint32_t stringId = request(ioManager, function, 0, 0);
-    readString(stringId, buffer);
-}
diff --git a/src/userland/hlib/strings.c b/src/userland/hlib/strings.c
deleted file mode 100644
index 78fff55..0000000
--- a/src/userland/hlib/strings.c
+++ /dev/null
@@ -1,38 +0,0 @@
-#include <hlib.h>
-#include <stdint.h>
-#include <syscalls.h>
-
-uint32_t strlen(char *string) {
-    if (!string) {
-        return 0;
-    }
-    uint32_t size = 0;
-    while (*string) {
-        string++;
-        size++;
-    }
-    return size;
-}
-
-void memcpy(void *from, void *to, uint32_t size) {
-    uint8_t *a = from, *b = to;
-    for (uint32_t i = 0; i < size; i++) {
-        b[i] = a[i];
-    }
-}
-
-uintptr_t insertString(char *string) {
-    return syscall(SYS_INSERT_STRING, U32(string), 0, 0, 0);
-}
-
-uintptr_t getStringLength(uintptr_t stringId) {
-    return syscall(SYS_GET_STRING_LENGTH, stringId, 0, 0, 0);
-}
-
-void readString(uintptr_t stringId, void *buffer) {
-    syscall(SYS_READ_STRING, stringId, U32(buffer), 0, 0);
-}
-
-void discardString(uintptr_t stringId) {
-    syscall(SYS_DISCARD_STRING, stringId, 0, 0, 0);
-}