diff --git a/.github/workflows/build_tests.yml b/.github/workflows/build_tests.yml
index 44b8760..88f75fd 100644
--- a/.github/workflows/build_tests.yml
+++ b/.github/workflows/build_tests.yml
@@ -29,6 +29,9 @@ jobs:
     - name: Install mtools
       run: sudo apt install mtools
 
+    - name: Install xorriso
+      run: sudo apt install xorriso
+
     - name: Download gcc
       if: steps.cached-binaries.outputs.cache-hit != 'true'
       run: >
diff --git a/Makefile b/Makefile
index 555fb50..f1f6fcc 100644
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,7 @@ ifeq ($(TOOLCHAIN), gcc)
 else ifeq ($(TOOLCHAIN), clang)
 	X_CC = clang
 	X_LD = ld.lld
+	LD_FLAGS += -z lrodata-after-bss
 else
 	$(error "Unknown compiler toolchain")
 endif
@@ -42,9 +43,9 @@ ISO_IMAGE_FILENAME := $(IMAGE_BASE_NAME)-$(ARCH_PREFIX)-$(VERSION).iso
 
 default: build
 
-.PHONY: default build run clean debug tests gdb todolist
+.PHONY: default build run clean debug tests gdb todolist examples
 
-build: $(BUILD_FOLDER)/$(ISO_IMAGE_FILENAME)
+build: examples $(BUILD_FOLDER)/$(ISO_IMAGE_FILENAME)
 
 clean:
 	-rm -rf $(BUILD_FOLDER)
@@ -53,6 +54,12 @@ clean:
 run: $(BUILD_FOLDER)/$(ISO_IMAGE_FILENAME)
 	$(QEMU_SYSTEM) -cdrom $(BUILD_FOLDER)/$(ISO_IMAGE_FILENAME)
 
+examples:
+	echo "Building Examples"
+	mkdir -p $(BUILD_FOLDER)/examples
+	${ASM_COMPILER} -g -felf64 -Fdwarf examples/example_syscall.s -o $(BUILD_FOLDER)/examples/example_syscall.o
+	$(X_LD) $(LD_FLAGS) -g $(BUILD_FOLDER)/examples/example_syscall.o -o $(BUILD_FOLDER)/examples/example_syscall.elf -e loop -T examples/linker_script_$(SMALL_PAGES).ld
+
 debug: DEBUG=1
 debug: CFLAGS += $(C_DEBUG_FLAGS)
 debug: ASM_FLAGS += $(ASM_DEBUG_FLAGS)
@@ -61,12 +68,12 @@ debug: $(BUILD_FOLDER)/$(ISO_IMAGE_FILENAME)
 	# qemu-system-x86_64 -monitor unix:qemu-monitor-socket,server,nowait -cpu qemu64,+x2apic  -cdrom $(BUILD_FOLDER)/$(ISO_IMAGE_FILENAME) -serial file:dreamos64.log -m 1G -d int -no-reboot -no-shutdown
 	$(QEMU_SYSTEM) -monitor unix:qemu-monitor-socket,server,nowait -cpu qemu64,+x2apic  -cdrom $(BUILD_FOLDER)/$(ISO_IMAGE_FILENAME) -serial stdio -m 2G  -no-reboot -no-shutdown
 
-$(BUILD_FOLDER)/$(ISO_IMAGE_FILENAME): $(BUILD_FOLDER)/kernel.bin grub.cfg
+$(BUILD_FOLDER)/$(ISO_IMAGE_FILENAME): $(BUILD_FOLDER)/kernel.bin grub.cfg examples
 	mkdir -p $(BUILD_FOLDER)/isofiles/boot/grub
 	cp grub.cfg $(BUILD_FOLDER)/isofiles/boot/grub
 	cp $(BUILD_FOLDER)/kernel.bin $(BUILD_FOLDER)/isofiles/boot
 	cp $(BUILD_FOLDER)/kernel.map $(BUILD_FOLDER)/isofiles/boot
-	cp example.elf $(BUILD_FOLDER)/isofiles
+	cp $(BUILD_FOLDER)/examples/example_syscall.elf $(BUILD_FOLDER)/isofiles
 	grub-mkrescue -o $(BUILD_FOLDER)/$(ISO_IMAGE_FILENAME) $(BUILD_FOLDER)/isofiles
 
 $(BUILD_FOLDER)/%.o: src/%.s
@@ -88,7 +95,7 @@ $(BUILD_FOLDER)/kernel.bin: $(OBJ_ASM_FILE) $(OBJ_C_FILE) $(OBJ_FONT_FILE) src/l
 	echo $(OBJ_ASM_FILE)
 	echo $(OBJ_FONT_FILE)
 	echo $(IS_WORKFLOW)
-	$(X_LD) -n -o $(BUILD_FOLDER)/kernel.bin -T src/linker.ld $(OBJ_ASM_FILE) $(OBJ_C_FILE) $(OBJ_FONT_FILE) -Map $(BUILD_FOLDER)/kernel.map
+	$(X_LD) $(LD_FLAGS)  -n -o $(BUILD_FOLDER)/kernel.bin -T src/linker.ld $(OBJ_ASM_FILE) $(OBJ_C_FILE) $(OBJ_FONT_FILE) -Map $(BUILD_FOLDER)/kernel.map
 
 gdb: DEBUG=1
 gdb: CFLAGS += $(C_DEBUG_FLAGS)
@@ -103,7 +110,7 @@ tests:
 	${TOOLCHAIN} ${TESTFLAGS} tests/test_kheap.c tests/test_common.c src/kernel/mem/kheap.c src/kernel/mem/bitmap.c src/kernel/mem/pmm.c src/kernel/mem/mmap.c src/kernel/mem/vmm_util.c -o tests/test_kheap.o
 	${TOOLCHAIN} ${TESTFLAGS} tests/test_vm.c tests/test_common.c src/kernel/arch/x86_64/system/vm.c src/kernel/mem/vmm_util.c  -o tests/test_vm.o
 	${TOOLCHAIN} ${TESTFLAGS} tests/test_vfs.c tests/test_common.c src/fs/vfs.c src/drivers/fs/ustar.c -o tests/test_vfs.o
-	${TOOLCHAIN} ${TESTFLAGS} tests/test_utils.c src/kernel/mem/vmm_util.c -o tests/test_utils.o
+	${TOOLCHAIN} ${TESTFLAGS} tests/test_utils.c tests/test_common.c  src/kernel/mem/vmm_util.c -o tests/test_utils.o
 	${TOOLCHAIN} ${TESTFLAGS} tests/test_window.c tests/test_common.c  src/kernel/graphics/window.c -o tests/test_window.o
 	./tests/test_mem.o && ./tests/test_kheap.o && ./tests/test_number_conversion.o && ./tests/test_vm.o && ./tests/test_vfs.o && ./tests/test_utils.o && ./tests/test_window.o
 
diff --git a/README.md b/README.md
index 35fb5e0..2cf9e93 100644
--- a/README.md
+++ b/README.md
@@ -40,6 +40,7 @@ But at kernel level several things have been implemented:
 * Basic Virtual Memory implementation
 * Initial Userspace support (so far can run only an idle userspace thread)
 * Basic syscall mechanism (altough no real syscalls are implemented, just one that prints the string "example")
+* Initial basic ELF support (from kernel module)
 
 ## Prerequisites:
 
diff --git a/build/Common.mk b/build/Common.mk
index ab99e86..6f1f28e 100644
--- a/build/Common.mk
+++ b/build/Common.mk
@@ -26,6 +26,8 @@ CFLAGS := -std=gnu99 \
         -mno-red-zone \
         -mno-sse \
         -mcmodel=large \
+        -fno-pie \
+        -fno-pic \
         -fno-stack-protector
 
 CFLAGS += $(DEF_FLAGS)
@@ -46,5 +48,7 @@ TESTFLAGS := -std=gnu99 \
         -DSMALL_PAGES=0 \
         -D_TEST_=1
 
+LD_FLAGS :=
+
 PRJ_FOLDERS := src
 TEST_FOLDER := tests
diff --git a/docs/kernel/Syscalls.md b/docs/kernel/Syscalls.md
index 6ccb337..180df38 100644
--- a/docs/kernel/Syscalls.md
+++ b/docs/kernel/Syscalls.md
@@ -4,7 +4,7 @@ The syscalls are called using the interrupt vector `0x80`. Arguments depend on t
 
 # Syscalls List
 
-## 0x01 TEST
+## 0x00 TEST
 
 The first syscall is reserved for test purpose, and it should be never used.
 
diff --git a/example.elf b/example.elf
deleted file mode 100644
index fdd036b..0000000
Binary files a/example.elf and /dev/null differ
diff --git a/examples/example_syscall.s b/examples/example_syscall.s
new file mode 100644
index 0000000..84b6ebc
--- /dev/null
+++ b/examples/example_syscall.s
@@ -0,0 +1,7 @@
+extern loop
+[bits 64]
+loop:
+    mov rdi, 0x63
+    mov rsi, 0x1
+    int 0x80
+    jmp loop
diff --git a/examples/linker_script_0.ld b/examples/linker_script_0.ld
new file mode 100644
index 0000000..e0b3640
--- /dev/null
+++ b/examples/linker_script_0.ld
@@ -0,0 +1,31 @@
+ENTRY(loop)
+
+SECTIONS {
+
+	. = 4M;
+
+	.text : ALIGN (2M)
+	{
+		*(.text)
+		*(.text.*)
+	}
+
+	.rodata : ALIGN (2M)
+	{
+		*(.rodata)
+		*(.rodata.*)
+	}
+
+	.data : ALIGN (2M)
+	{
+		*(.data)
+		*(.data.*)
+	}
+
+	.bss : ALIGN (2M)
+	{
+		*(.bss)
+	}
+
+}
+
diff --git a/examples/linker_script_1.ld b/examples/linker_script_1.ld
new file mode 100644
index 0000000..bea1f48
--- /dev/null
+++ b/examples/linker_script_1.ld
@@ -0,0 +1,31 @@
+ENTRY(loop)
+
+SECTIONS {
+
+	. = 4M;
+
+	.text : ALIGN (4K)
+	{
+		*(.text)
+		*(.text.*)
+	}
+
+	.rodata : ALIGN (4K)
+	{
+		*(.rodata)
+		*(.rodata.*)
+	}
+
+	.data : ALIGN (4K)
+	{
+		*(.data)
+		*(.data.*)
+	}
+
+	.bss : ALIGN (4K)
+	{
+		*(.bss)
+	}
+
+}
+
diff --git a/grub.cfg b/grub.cfg
index 41d4d64..d5e0cce 100644
--- a/grub.cfg
+++ b/grub.cfg
@@ -3,7 +3,7 @@ set default=0
 
 menuentry "DreamOs64" {
     multiboot2 /boot/kernel.bin                  // Path to the loader executable
-    module2 /example.elf
+    module2 /example_syscall.elf
     boot
      // More modules may be added here in the form 'module <path> "<cmdline>"'
 }
diff --git a/src/include/kernel/loaders/elf.h b/src/include/kernel/loaders/elf.h
index b334132..50806ba 100644
--- a/src/include/kernel/loaders/elf.h
+++ b/src/include/kernel/loaders/elf.h
@@ -87,5 +87,7 @@ void load_elf(uintptr_t elf_start, uint64_t size);
 bool parse_section_header(Elf64_Ehdr *elf_start, uint64_t size, executable_loader_type type);
 
 Elf64_Half loop_phdrs(Elf64_Ehdr* e_phdr, Elf64_Half phdr_entries);
+Elf64_Phdr *read_phdr(Elf64_Ehdr* e_hdr, Elf64_Half phdr_entry_number);
 
+uint64_t elf_flags_to_memory_flags(Elf64_Word flags);
 #endif
diff --git a/src/include/kernel/mem/hh_direct_map.h b/src/include/kernel/mem/hh_direct_map.h
index d2420f3..4e58db2 100644
--- a/src/include/kernel/mem/hh_direct_map.h
+++ b/src/include/kernel/mem/hh_direct_map.h
@@ -11,6 +11,7 @@
 void early_map_physical_memory(uint64_t end_of_reserved_area);
 
 void *hhdm_get_variable ( uintptr_t phys_address );
+void *hhdm_get_phys_address(uintptr_t hhdm_address);
 void hhdm_map_physical_memory();
 
 #endif
diff --git a/src/include/kernel/mem/vmm_util.h b/src/include/kernel/mem/vmm_util.h
index f078768..300258e 100644
--- a/src/include/kernel/mem/vmm_util.h
+++ b/src/include/kernel/mem/vmm_util.h
@@ -20,6 +20,7 @@
 size_t get_number_of_pages_from_size(size_t size);
 size_t align_value_to_page(size_t value);
 size_t align_up(size_t value, size_t alignment);
+size_t align_down(size_t value, size_t alignment);
 bool is_address_aligned(size_t value, size_t alignment);
 
 size_t vm_parse_flags( size_t flags );
diff --git a/src/include/kernel/scheduling/scheduler.h b/src/include/kernel/scheduling/scheduler.h
index 522c5c1..b3a0d01 100644
--- a/src/include/kernel/scheduling/scheduler.h
+++ b/src/include/kernel/scheduling/scheduler.h
@@ -1,10 +1,10 @@
 #ifndef _SCHEDULER_H_
 #define _SCHEDULER_H_
 
+#include <cpu.h>
 #include <stdint.h>
 #include <thread.h>
 #include <task.h>
-#include <cpu.h>
 
 #define SCHEDULER_NUMBER_OF_TICKS   0x200
 #define SCHEDULER_MAX_THREAD_NUMBER 0x10
diff --git a/src/include/kernel/scheduling/task.h b/src/include/kernel/scheduling/task.h
index 5482456..ea0437b 100644
--- a/src/include/kernel/scheduling/task.h
+++ b/src/include/kernel/scheduling/task.h
@@ -1,6 +1,7 @@
 #ifndef _TASK_H
 #define _TASK_H
 
+#include <elf.h>
 #include <stddef.h>
 #include <stdbool.h>
 #include <thread.h>
@@ -27,14 +28,21 @@ struct task_t {
 
 extern size_t next_task_id;
 
-task_t* create_task( char *name, void (*_entry_point)(void *), void *args, bool is_supervisor );
+task_t* create_task( char *name, bool is_supervisor );
+task_t *create_task_from_func(char *name, void (*_entry_point)(void *), void *args, bool is_supervisor);
+task_t *create_task_from_elf(char *name, void *args, Elf64_Ehdr *elf_header);
+
 task_t* get_task( size_t task_id );
 
 bool add_thread_to_task_by_id( size_t task_id, thread_t* thread );
 bool add_thread_to_task( task_t* task, thread_t* thread );
+
 bool delete_thread_from_task( size_t thread_id, task_t *task );
-void prepare_virtual_memory_environment( task_t* task );
+
+void prepare_virtual_memory_environment(task_t* task);
+
 void print_thread_list( size_t task_id );
+
 bool remove_thread_from_task(size_t thread_id, task_t *task);
 
 #endif
diff --git a/src/include/kernel/scheduling/thread.h b/src/include/kernel/scheduling/thread.h
index fbe782c..b906e5d 100644
--- a/src/include/kernel/scheduling/thread.h
+++ b/src/include/kernel/scheduling/thread.h
@@ -42,7 +42,7 @@ struct thread_t {
 extern size_t next_thread_id;
 
 
-thread_t* create_thread(char* thread_name, void (*_entry_point)(void *) , void* arg, struct task_t* parent_task, bool is_supervisor);
+thread_t* create_thread(char* thread_name, void (*_entry_point)(void *) , void* arg, struct task_t* parent_task, bool is_supervisor, bool is_elf);
 void thread_execution_wrapper( void (*)(void *), void*);
 void thread_suicide_trap();
 void thread_sleep(size_t millis);
diff --git a/src/kernel/arch/x86_64/mem/vmm_mapping.c b/src/kernel/arch/x86_64/mem/vmm_mapping.c
index 2be11f8..0ffdc7a 100644
--- a/src/kernel/arch/x86_64/mem/vmm_mapping.c
+++ b/src/kernel/arch/x86_64/mem/vmm_mapping.c
@@ -24,7 +24,7 @@ void *map_phys_to_virt_addr_hh(void* physical_address, void* address, size_t fla
     uint8_t user_mode_status = 0;
 
     if ( !is_address_higher_half((uint64_t) address) ) {
-        pretty_log(Verbose, "address is in lower half");
+        pretty_logf(Verbose, "address is in lower half: 0x%x", address);
         flags = flags | VMM_FLAGS_USER_LEVEL;
         user_mode_status = VMM_FLAGS_USER_LEVEL;
     }
@@ -34,7 +34,6 @@ void *map_phys_to_virt_addr_hh(void* physical_address, void* address, size_t fla
     }
 
     if (pml4_root != NULL) {
-        //pml4_table = pml4_root;
         pretty_logf(Verbose, "Entries values pml4_e: 0x%d pdpr_e: 0x%d pd_e: 0x%d", pml4_e, pdpr_e, pd_e);
         pretty_logf(Verbose, "\taddress: 0x%x, phys_address: 0x%x", address, physical_address);
         pretty_logf(Verbose, "\tpdpr base_address: 0x%x", pml4_root[pml4_e] & VM_PAGE_TABLE_BASE_ADDRESS_MASK);
@@ -47,7 +46,6 @@ void *map_phys_to_virt_addr_hh(void* physical_address, void* address, size_t fla
             clean_new_table(new_table_hhdm);
             pdpr_root = new_table_hhdm;
         } else {
-            pretty_log(Verbose, "No need to allocate pml4");
             pdpr_root =  (uint64_t *) hhdm_get_variable((uintptr_t) pml4_root[pml4_e] & VM_PAGE_TABLE_BASE_ADDRESS_MASK);
         }
 
@@ -59,7 +57,6 @@ void *map_phys_to_virt_addr_hh(void* physical_address, void* address, size_t fla
             clean_new_table(new_table_hhdm);
             pd_root = new_table_hhdm;
         } else {
-            pretty_log(Verbose, "No need to allocate pdpr");
             pd_root =  (uint64_t *) hhdm_get_variable((uintptr_t) pdpr_root[pdpr_e] & VM_PAGE_TABLE_BASE_ADDRESS_MASK);
         }
 
@@ -72,7 +69,6 @@ void *map_phys_to_virt_addr_hh(void* physical_address, void* address, size_t fla
             clean_new_table(new_table_hhdm);
             pt_table = new_table_hhdm;
         } else {
-            pretty_log(Verbose, "No need to allocate pd");
             pt_table = (uint64_t *) hhdm_get_variable((uintptr_t) pd_root[pd_e] & VM_PAGE_TABLE_BASE_ADDRESS_MASK);
         }
 
@@ -84,7 +80,7 @@ void *map_phys_to_virt_addr_hh(void* physical_address, void* address, size_t fla
         }
 #elif SMALL_PAGES == 0
             pd_root[pd_e] = (uint64_t) (physical_address) | HUGEPAGE_BIT | flags | user_mode_status;
-            pretty_logf(Verbose, " PD Flags: 0x%x entry value pd_root[0x%x]: 0x%x", flags, pd_e, pd_root[pd_e]);
+            pretty_logf(Verbose, " PD Flags: 0x%x entry value pd_root[0x%x]: 0x%x - address: 0x%x", flags, pd_e, pd_root[pd_e], address);
             return address;
         }
 #endif
diff --git a/src/kernel/loaders/elf.c b/src/kernel/loaders/elf.c
index a7bd60f..85717f2 100644
--- a/src/kernel/loaders/elf.c
+++ b/src/kernel/loaders/elf.c
@@ -16,9 +16,13 @@ void load_elf(uintptr_t elf_start, uint64_t size) {
         Elf64_Half phdr_entsize = elf_header->e_phentsize;
         pretty_logf(Verbose, " Number of PHDR entries: 0x%x", phdr_entries);
         pretty_logf(Verbose, " PHDR Entry Size: 0x%x", phdr_entsize );
+        pretty_logf(Verbose, " ELF Entry point: 0x%x", elf_header->e_entry);
         Elf64_Half result = loop_phdrs(elf_header, phdr_entries);
         if (result > 0) {
             pretty_logf(Verbose, " Number of PT_LOAD entries: %d", result);
+            Elf64_Phdr *cur_phdr = read_phdr(elf_header, 0);
+            pretty_logf(Verbose, "\t[cur_phdr]: Type: 0x%x, Flags: 0x%x  -  Vaddr: 0x%x - aligned: 0x%x  - p_align: 0x%x - p_memsz: 0%x - p_offset: 0x%x", cur_phdr->p_type, cur_phdr->p_flags, cur_phdr->p_vaddr, align_value_to_page(cur_phdr->p_vaddr), cur_phdr->p_align, cur_phdr->p_memsz, cur_phdr->p_offset);
+            cur_phdr = read_phdr(elf_header, 1);
         }
     }
 }
@@ -28,7 +32,7 @@ Elf64_Half loop_phdrs(Elf64_Ehdr* e_hdr, Elf64_Half phdr_entries) {
     Elf64_Half number_of_pt_loads = 0;
     for (size_t i = 0; i < phdr_entries; i++) {
         Elf64_Phdr phdr = phdr_list[i];
-        pretty_logf(Verbose, "\t[%d]: Type: 0x%x, Flags: 0x%x  -  Vaddr: 0x%x - aligned: 0x%x ", i, phdr.p_type, phdr.p_flags, phdr.p_vaddr, align_value_to_page(phdr.p_vaddr));
+        pretty_logf(Verbose, "\t[%d]: Type: 0x%x, Flags: 0x%x  -  Vaddr: 0x%x - aligned: 0x%x - offset: 0x%x ", i, phdr.p_type, phdr.p_flags, phdr.p_vaddr, align_value_to_page(phdr.p_vaddr), phdr.p_offset);
         if ( is_address_aligned(phdr.p_vaddr, PAGE_SIZE_IN_BYTES) ) {
             pretty_log(Verbose, "\tThe address is aligned");
         } else {
@@ -39,6 +43,14 @@ Elf64_Half loop_phdrs(Elf64_Ehdr* e_hdr, Elf64_Half phdr_entries) {
     return number_of_pt_loads;
 }
 
+/**
+ * This function return the phdr entry at the pdhrd_entry_number provided.
+ *
+ *
+ * @param e_hdr the elf header
+ * @param phdr_entry_number the entry number we want to read
+ * @return  Elf64_Phdr * the selected P_hdr or NULL if not found.
+ */
 Elf64_Phdr *read_phdr(Elf64_Ehdr* e_hdr, Elf64_Half phdr_entry_number) {
     Elf64_Half phdr_entries = e_hdr->e_phnum;
 
@@ -48,7 +60,6 @@ Elf64_Phdr *read_phdr(Elf64_Ehdr* e_hdr, Elf64_Half phdr_entry_number) {
     }
 
     return NULL;
-
 }
 
 
@@ -91,3 +102,21 @@ bool parse_section_header(Elf64_Ehdr *elf_start, uint64_t size, executable_loade
     }
     return false;
 }
+
+/**
+ * This function given an elf p_hdr flag  returns the architecture dependent vmm flags
+ *
+ *
+ * @param flags elf flags
+ * @return architecture dependant flags
+ */
+uint64_t elf_flags_to_memory_flags(Elf64_Word flags) {
+    // This function will be movede into the arch dependant code
+    // Elf flags:
+    // 1 = Read
+    // 2 = Write
+    // 4 = Execute
+    // They can be mixed.
+    uint64_t flags_to_return = (flags & 0b10);
+    return flags_to_return;
+}
diff --git a/src/kernel/main.c b/src/kernel/main.c
index de945bc..d7bd8ea 100644
--- a/src/kernel/main.c
+++ b/src/kernel/main.c
@@ -118,7 +118,7 @@ void _init_basic_system(unsigned long addr){
     tag_start = (struct multiboot_tag *) (addr + _HIGHER_HALF_KERNEL_MEM_START + 8);
     _mmap_parse(tagmmap);
     pmm_setup(addr, mbi_size);
-     kernel_settings.kernel_uptime = 0;
+    kernel_settings.kernel_uptime = 0;
     kernel_settings.paging.page_root_address = p4_table;
     uint64_t p4_table_phys_address = (uint64_t) p4_table - _HIGHER_HALF_KERNEL_MEM_START;
     kernel_settings.paging.hhdm_page_root_address = (uint64_t*) hhdm_get_variable( (uintptr_t) p4_table_phys_address);
@@ -235,7 +235,7 @@ void kernel_start(unsigned long addr, unsigned long magic){
     init_apic();
     if (loaded_module != NULL) {
         if ( load_module_hh(loaded_module) ) {
-            pretty_log(Verbose, " The ELF module can be loaded succesfully" );
+            pretty_logf(Verbose, " The ELF module can be loaded succesfully (Phys addr: 0x%x)", loaded_module->mod_start );
             elf_module_start_phys = loaded_module->mod_start;
         }
     }
@@ -264,9 +264,13 @@ void kernel_start(unsigned long addr, unsigned long magic){
     #endif
     init_scheduler();
     char a = 'a';
-    task_t* idle_task = create_task("idle", idle, &a, true);
+    task_t* idle_task = create_task_from_func("idle", idle, &a, true);
     idle_thread = idle_task->threads;
-    task_t* userspace_task = create_task("userspace_idle", NULL, &a, false);
+    #if PAGE_SIZE_IN_BYTES == 0x200000
+    task_t* userspace_task = create_task_from_func("userspace_idle", NULL, &a, false);
+    #else
+    task_t* elf_task = create_task_from_elf("elf_idle", NULL, (Elf64_Ehdr *) hhdm_get_variable(elf_module_start_phys));
+    #endif
     //create_thread("ledi", noop2, &c, eldi_task);
     //create_task("sleeper", noop3, &d);
     //execute_runtime_tests();
diff --git a/src/kernel/mem/hh_direct_map.c b/src/kernel/mem/hh_direct_map.c
index 36c5158..43ca7c1 100644
--- a/src/kernel/mem/hh_direct_map.c
+++ b/src/kernel/mem/hh_direct_map.c
@@ -28,6 +28,17 @@ void *hhdm_get_variable ( uintptr_t phys_address ) {
     return NULL;
 }
 
+/**
+ * This is an helper function return the physical address given a hhdm one
+ *
+ *
+ * @return phys_address the physical address we want to retrieve
+ * @param hhdm_address of the physical address or NULL in case of error
+ */
+void *hhdm_get_phys_address(uintptr_t hhdm_address) {
+    return (void *)(hhdm_address - higherHalfDirectMapBase);
+}
+
 
 void hhdm_map_physical_memory() {
     // This function should be called only once, and the hhdm shouldn't change during the kernel uptime
@@ -42,15 +53,11 @@ void hhdm_map_physical_memory() {
     uint64_t address_to_map = 0;
     uint64_t virtual_address = higherHalfDirectMapBase;
 
-    pretty_logf(Verbose, "Virtual address: 0x%x", virtual_address);
+    pretty_logf(Verbose, "Virtual address: 0x%x -- hhdmBase: 0x%x", virtual_address, higherHalfDirectMapBase);
     pretty_logf(Verbose, "Vaddress: 0x%x - HigherHalf Initial entries: pml4: %d, pdpr: %d, pd: %d", virtual_address, PML4_ENTRY((uint64_t) higherHalfDirectMapBase), PDPR_ENTRY((uint64_t) higherHalfDirectMapBase), PD_ENTRY((uint64_t) higherHalfDirectMapBase));
 
     size_t current_pml4_entry = PML4_ENTRY((uint64_t) higherHalfDirectMapBase);
 
-/*    if (!(p4_table[current_pml4_entry] & 0b1) ) {
-        pretty_log(Fatal, "This shouldn't happen");
-    }*/
-
     uint64_t upper_address_to_map = (mmap_entries[_mmap_last_available_item].addr + mmap_entries[_mmap_last_available_item].len);
     pretty_logf(Verbose, "Last available item: %d -  Last address to map: 0x%x", _mmap_last_available_item, upper_address_to_map);
 
diff --git a/src/kernel/mem/mmap.c b/src/kernel/mem/mmap.c
index 3c220bb..65f10e6 100644
--- a/src/kernel/mem/mmap.c
+++ b/src/kernel/mem/mmap.c
@@ -89,11 +89,9 @@ bool _mmap_is_address_in_available_space(uint64_t address, uint64_t upper_limit)
         //pretty_logf(Verbose, "entry type: 0x%x - %d - 0x%x - address: 0x%x", current_entry->type, i, current_entry->addr, address);
         if(current_entry->addr + current_entry->len > address + upper_limit) {
             if(current_entry->type == _MMAP_AVAILABLE) {
-                //pretty_logf(Verbose, "Entry 0x%x is in an available space (with size: 0x%x", address, upper_limit );
                 // The address is in an available area, but we need to check if it is not overwriting something important.
-                uint64_t multiboot_address =_is_address_in_multiboot(address);
+                bool multiboot_address =_is_address_in_multiboot(address);
                 if(multiboot_address != 0) {
-                    pretty_log(Verbose, " This address is reserved by multiboot");
                     return false;
                 }
                 return true;
diff --git a/src/kernel/mem/pmm.c b/src/kernel/mem/pmm.c
index 93b2292..1a3b80d 100644
--- a/src/kernel/mem/pmm.c
+++ b/src/kernel/mem/pmm.c
@@ -82,33 +82,15 @@ void *pmm_alloc_frame(){
 
 void *pmm_prepare_new_pagetable() {
     if ( !pmm_initialized) {
-                while((!_mmap_is_address_in_available_space(anon_physical_memory_loc, PAGE_DIR_SIZE)) && anon_physical_memory_loc < memory_size_in_bytes) {
-                    pretty_logf(Verbose, " Current address: 0x%x - phys: 0x%x not available trying next 0x%x", anon_memory_loc, anon_physical_memory_loc,  memory_size_in_bytes);
-                    anon_memory_loc += PAGE_DIR_SIZE;
-                    anon_physical_memory_loc += PAGE_DIR_SIZE;
-                }
-                anon_memory_loc += PAGE_DIR_SIZE;
-                anon_physical_memory_loc += PAGE_DIR_SIZE;
-                return (void *)  (anon_physical_memory_loc - PAGE_DIR_SIZE);
-                /*if( _mmap_is_address_in_available_space(anon_physical_memory_loc, PAGE_DIR_SIZE) ) {
-                    // This space should be potentially safe
-                    anon_memory_loc += PAGE_DIR_SIZE;
-                    anon_physical_memory_loc += PAGE_DIR_SIZE;
-                    return (void *)  (anon_physical_memory_loc - PAGE_DIR_SIZE);
-                } else {
-                    // i suppose this shouldn't happen
-                    pretty_log(Fatal, " New location is not in available area, this most likely shouldn't happen");
-                }*/
-            /*} else {
-                // This is the tricky part, i need to map new memory. still in the anon area
-                // I need to check that it is not any of the reserved memory locations (i.e. faramebuffer)
-                // If yes it should probably panic
-
-            }*/
-            // Get the first available address and check if is in mapped area?
-            //return NULL;
+        while((!_mmap_is_address_in_available_space(anon_physical_memory_loc, PAGE_DIR_SIZE)) && anon_physical_memory_loc < memory_size_in_bytes) {
+            anon_memory_loc += PAGE_DIR_SIZE;
+            anon_physical_memory_loc += PAGE_DIR_SIZE;
+        }
+        //pretty_logf(Verbose, "Preparing new page table at: 0x%x - phys: 0x%x", anon_memory_loc, anon_physical_memory_loc);
+        anon_memory_loc += PAGE_DIR_SIZE;
+        anon_physical_memory_loc += PAGE_DIR_SIZE;
+        return (void *)  (anon_physical_memory_loc - PAGE_DIR_SIZE);
     }
-    //pretty_log(Verbose, "The pmm is initialized, using pmm_alloc_frame");
     return (void *) pmm_alloc_frame();
 }
 
diff --git a/src/kernel/mem/vmm_util.c b/src/kernel/mem/vmm_util.c
index 7dde342..a6dba2f 100644
--- a/src/kernel/mem/vmm_util.c
+++ b/src/kernel/mem/vmm_util.c
@@ -13,6 +13,10 @@ size_t align_up(size_t value, size_t alignment) {
     return ((value + alignment - 1) / alignment) * alignment;
 }
 
+size_t align_down(size_t value, size_t alignment) {
+    return (value / alignment) * alignment;
+}
+
 bool is_address_aligned(size_t value, size_t alignment) {
     if (value % alignment == 0) {
         return true;
diff --git a/src/kernel/scheduling/scheduler.c b/src/kernel/scheduling/scheduler.c
index 0c0a956..5d50d9e 100644
--- a/src/kernel/scheduling/scheduler.c
+++ b/src/kernel/scheduling/scheduler.c
@@ -1,4 +1,3 @@
-
 #include <framebuffer.h>
 #include <scheduler.h>
 #include <string.h>
diff --git a/src/kernel/scheduling/task.c b/src/kernel/scheduling/task.c
index 591d42d..94c8b83 100644
--- a/src/kernel/scheduling/task.c
+++ b/src/kernel/scheduling/task.c
@@ -1,46 +1,101 @@
+#include <elf.h>
 #include <hh_direct_map.h>
-#include <task.h>
-#include <scheduler.h>
+#include <kernel.h>
 #include <kheap.h>
-#include <string.h>
 #include <logging.h>
 #include <vm.h>
-#include <kernel.h>
+#include <pmm.h>
+#include <scheduler.h>
+#include <task.h>
+#include <string.h>
 #include <vmm.h>
 #include <vmm_mapping.h>
-#include <pmm.h>
+#include <vmm_util.h>
 
 extern uint64_t p4_table[];
 extern uint64_t p3_table[];
 extern uint64_t p3_table_hh[];
 
-task_t* create_task(char *name, void (*_entry_point)(void *), void *args, bool is_supervisor) {
+task_t* create_task(char *name, bool is_supervisor) {
     //disable interrupts while creating a task
-    asm("cli");
     task_t* new_task = (task_t*) kmalloc(sizeof(task_t));
     strcpy(new_task->task_name, name);
     new_task->parent = NULL;
     new_task->task_id = next_task_id++;
     pretty_logf(Verbose, "Task created with name: %s - Task id: %d", new_task->task_name, new_task->task_id);
-    prepare_virtual_memory_environment(new_task);
+    //prepare_virtual_memory_environment(new_task);
     if ( is_supervisor ){
         vmm_init(VMM_LEVEL_SUPERVISOR, &(new_task->vmm_data));
     } else {
         vmm_init(VMM_LEVEL_USER, &(new_task->vmm_data));
     }
-    if( is_supervisor) {
+    //scheduler_add_task(new_task);
+    //re-enable interrupts
+    return new_task;
+}
+
+task_t *create_task_from_elf(char *name, void *args, Elf64_Ehdr *elf_header){
+    asm("cli");
+    // I will not create a task from elf if is_supervisor is true.
+    task_t* new_task = create_task(name,  false);
+    prepare_virtual_memory_environment(new_task);
+    if(elf_header != NULL) {
+        //Here i will put the code to handle the case where an Elf is passed.
+        Elf64_Half phdr_entries = elf_header->e_phnum;
+        Elf64_Half phdr_entsize = elf_header->e_phentsize;
+        pretty_logf(Verbose, " Number of PHDR entries: 0x%x", phdr_entries);
+        pretty_logf(Verbose, " PHDR Entry Size: 0x%x", phdr_entsize );
+        pretty_logf(Verbose, " ELF Entry point: 0x%x", elf_header->e_entry);
+        Elf64_Phdr *phdr_list = (Elf64_Phdr*) ((uintptr_t) elf_header + elf_header->e_phoff);
+        for ( int i = 0; i < phdr_entries; i++) {
+            // I need first to compute the number of pages required for each phdr
+            // clear all the memory not used
+            // compute the entries for each page and insert them into the page tables.
+            Elf64_Phdr phdr = phdr_list[i];
+            size_t vmm_hdr_flags = elf_flags_to_memory_flags(phdr.p_type);
+            pretty_logf(Verbose, "\t[%d]: Type: 0x%x, Flags: 0x%x  -  Vaddr: 0x%x - aligned: 0x%x ", i, phdr.p_type, phdr.p_flags, phdr.p_vaddr, align_value_to_page(phdr.p_vaddr));
+            pretty_logf(Verbose, "\t\t - FileSz: 0x%x, Memsz: 0x%x, vmm flags: 0x%x - p_align: 0x%x - p_offset: 0x%x", phdr.p_filesz, phdr.p_memsz, vmm_hdr_flags, phdr.p_align, phdr.p_offset);
+            Elf64_Half mem_pages = (Elf64_Half) get_number_of_pages_from_size(phdr.p_memsz);
+            Elf64_Half filesz_pages = (Elf64_Half) get_number_of_pages_from_size(phdr.p_filesz);
+            uint64_t offset_address = (uint64_t) ((uint64_t) elf_header + (uint64_t) phdr.p_offset);
+            uint64_t vaddr_address = align_value_to_page(phdr.p_vaddr);
+            for (int j = 0; j < mem_pages; j++) {
+                pretty_logf(Verbose, "[%d]: Mapping: offset: 0x%x (virtual: 0x%x) in vaddr: 0x%x", j, hhdm_get_phys_address((uintptr_t) offset_address), offset_address, vaddr_address);
+                if ( !is_address_aligned((size_t) hhdm_get_phys_address(offset_address), PAGE_SIZE_IN_BYTES)) {
+                    pretty_log(Fatal, "Error: module elf phys address is not page aligned");
+                }
+
+                map_phys_to_virt_addr_hh(hhdm_get_phys_address(offset_address), (void *) vaddr_address, VMM_FLAGS_USER_LEVEL | vmm_hdr_flags | VMM_FLAGS_PRESENT, (uint64_t *) new_task->vmm_data.root_table_hhdm);
+                //I need a mem copy. I need to fopy the content of elf_header + phdr.p_offset into phdr.p_vaddr
+                offset_address += (uint64_t) phdr.p_align;
+                vaddr_address += (uint64_t) phdr.p_align;
+                //I need to allocate memory and map it into the new memory space,
+            }
+        }
+        thread_t* thread = create_thread(name, (void (*)(void *))elf_header->e_entry, args, new_task, false, true);
+        pretty_logf(Verbose, "Thread created: id: %d - Entry Point: 0x%x - elf header entry point: 0x%x", thread->tid, thread->execution_frame->rip, elf_header->e_entry);
+    }
+    // Create a new thread
+    scheduler_add_task(new_task);
+    asm("sti");
+    return new_task;
+}
+
+task_t *create_task_from_func(char *name, void (*_entry_point)(void *), void *args, bool is_supervisor) {
+    asm("cli");
+    task_t* new_task = create_task(name,  is_supervisor);
+    prepare_virtual_memory_environment(new_task);
+        if( is_supervisor) {
         pretty_logf(Verbose, "creating new supervisor thread: %s", name);
-        thread_t* thread = create_thread(name, _entry_point, args, new_task, is_supervisor);
+        thread_t* thread = create_thread(name, _entry_point, args, new_task, is_supervisor, false);
         new_task->threads = thread;
     } else {
         pretty_logf(Verbose, "creating new userspace thread %s", name);
-        thread_t* thread = create_thread(name, NULL, args, new_task, is_supervisor);
+        thread_t* thread = create_thread(name, NULL, args, new_task, is_supervisor, false);
         new_task->threads = thread;
     }
     scheduler_add_task(new_task);
-    //re-enable interrupts
     asm("sti");
-    return new_task;
 }
 
 void prepare_virtual_memory_environment(task_t* task) {
@@ -51,8 +106,7 @@ void prepare_virtual_memory_environment(task_t* task) {
     //pretty_logf(Verbose, "vm_root_page_table address: %x", task->vm_root_page_table);
     //identity_map_phys_address(task->vm_root_page_table, 0);
     // I will get the page frame first, then get virtual address to map it to with vmm_alloc, and then do the mapping on the virtual address.
-    // Technically the vmm_alloc is not needed, since i have the direct memory map already accessible, so i just need to access it through the direct map.
-
+    // Technically the vmm_alloc is not needed, since i have the direct memory map already accessible, so i just need to access it through the direct m
     //void* vm_root_vaddress = vmm_alloc(PAGE_SIZE_IN_BYTES, VMM_FLAGS_ADDRESS_ONLY, NULL);
     void* vm_root_vaddress = hhdm_get_variable ((uintptr_t) task->vm_root_page_table);
     task->vmm_data.root_table_hhdm = (uintptr_t) vm_root_vaddress;
diff --git a/src/kernel/scheduling/thread.c b/src/kernel/scheduling/thread.c
index a8f1415..1effa1b 100644
--- a/src/kernel/scheduling/thread.c
+++ b/src/kernel/scheduling/thread.c
@@ -14,7 +14,7 @@ unsigned char code_to_run[] = {
     0xeb, 0xfe
 };
 
-thread_t* create_thread(char* thread_name, void (*_entry_point)(void *), void* arg, task_t* parent_task, bool is_supervisor) {
+thread_t* create_thread(char* thread_name, void (*_entry_point)(void *), void* arg, task_t* parent_task, bool is_supervisor, bool is_elf) {
     // The first part is pretty trivial mostly bureaucray. Setting basic thread information like name, tid, parent...
     // Just like when registtering a new born child :D
     if ( parent_task == NULL) {
@@ -30,7 +30,9 @@ thread_t* create_thread(char* thread_name, void (*_entry_point)(void *), void* a
     new_thread->next = NULL;
     new_thread->next_sibling = NULL;
     new_thread->ticks = 0;
-    pretty_logf(Verbose, "Creating thread with arg: %c - arg: %x - name: %s - rip: %x", (char) *((char*) arg), arg, thread_name, _entry_point);
+    if (arg != NULL) {
+        pretty_logf(Verbose, "Creating thread with arg: %c - arg: %x - name: %s - rip: %x", (char) *((char*) arg), arg, thread_name, _entry_point);
+    }
 
     //Here we create a new execution frame to be used when switching to a newly created task
     new_thread->execution_frame = kmalloc(sizeof(cpu_status_t));
@@ -39,7 +41,12 @@ thread_t* create_thread(char* thread_name, void (*_entry_point)(void *), void* a
     if (!is_supervisor) {
         // This piece of code is temporary, just to test a userspace task, it run just an infinite loop.
         pretty_logf(Verbose, "vmm_data address: 0x%x", &(parent_task->vmm_data));
-        new_thread->execution_frame->rip = prepare_userspace_function(&(parent_task->vmm_data));
+        if (is_elf ) {
+            pretty_logf(Verbose, "Preparing to launch an ELF. entry_point = 0x%x", (uint64_t) _entry_point);
+            new_thread->execution_frame->rip = (uint64_t)_entry_point;
+        } else {
+            new_thread->execution_frame->rip = prepare_userspace_function(&(parent_task->vmm_data));
+        }
         pretty_logf(Verbose, "using userspace function address: 0x%x", new_thread->execution_frame->rip);
         new_thread->execution_frame->rdi = 0;
         new_thread->execution_frame->rsi = 0;
@@ -68,7 +75,6 @@ thread_t* create_thread(char* thread_name, void (*_entry_point)(void *), void* a
           while(1);
     }
     // We need to allocate a new stack for each thread
-    //void* stack_pointer = kmalloc(THREAD_DEFAULT_STACK_SIZE);
     void* stack_pointer = vmm_alloc(THREAD_DEFAULT_STACK_SIZE, VMM_FLAGS_PRESENT | VMM_FLAGS_WRITE_ENABLE | VMM_FLAGS_STACK, &(parent_task->vmm_data));
     if (stack_pointer == NULL) {
         pretty_log(Fatal, "rsp is null - PANIC!");
diff --git a/src/linker.ld b/src/linker.ld
index 42c11f0..1b7d586 100644
--- a/src/linker.ld
+++ b/src/linker.ld
@@ -22,20 +22,29 @@ SECTIONS {
 	{
 		*(.text)
 		*(.text.*)
+		*(.ltext)
+		*(.ltext.*)
 	}
 	.rodata ALIGN (4K) : AT (ADDR (.rodata) - _kern_virtual_offset)
 	{
 		*(.rodata)
 		*(.rodata.*)
+		*(.lrodata)
+		*(.lrodata.*)
 	}
 	.data ALIGN (4K) : AT (ADDR (.data) - _kern_virtual_offset)
 	{
 		*(.data)
 		*(.data.*)
+		*(.ldata)
+		*(.ldata.*)
 	}
 	.bss ALIGN (4K) : AT (ADDR (.bss) - _kern_virtual_offset)
 	{
 		*(.bss)
+		*(.lbss)
+		*(.bss.*)
+		*(.lbss.*)
 	}
 
     _kernel_end = .;
diff --git a/src/utils/utils.c b/src/utils/utils.c
index da54b4e..202211f 100644
--- a/src/utils/utils.c
+++ b/src/utils/utils.c
@@ -44,7 +44,6 @@ bool _is_address_in_multiboot(uint64_t address) {
         if (tag->type == MULTIBOOT_TAG_TYPE_MODULE) {
             struct multiboot_tag_module *loaded_module = (struct multiboot_tag_module *) tag;
             if (address >=  loaded_module->mod_start && address <= loaded_module->mod_end) {
-                pretty_logf(Verbose, "This address: 0x%x is reserved by a multiboot module", address );
                 return true;
             }
         }
diff --git a/tests/test_utils.c b/tests/test_utils.c
index 845a988..3b428d6 100644
--- a/tests/test_utils.c
+++ b/tests/test_utils.c
@@ -1,17 +1,24 @@
+#include <test_common.h>
 #include <vmm_util.h>
 #include <assert.h>
 #include <stdio.h>
 
+void test_utils();
+
 int main() {
     printf("Testing VMM Utility function  -\n");
+    test_utils();
+}
+
+void test_utils() {
     size_t number_of_pages = get_number_of_pages_from_size(0x900);
-    printf("\t [test_utils] (get_number_of_pages_from_size): Testing number of pages for 0x900, should be 1: %ld\n", number_of_pages);
+    printf("\t[test_utils] (get_number_of_pages_from_size): Testing number of pages for 0x900, should be 1: %ld\n", number_of_pages);
     assert(number_of_pages == 1);
     number_of_pages = get_number_of_pages_from_size(0x0);
-    printf("\t [test_utils] (get_number_of_pages_from_size): Testing number of pages for 0x0, should be 0: %ld\n", number_of_pages);
+    printf("\t[test_utils] (get_number_of_pages_from_size): Testing number of pages for 0x0, should be 0: %ld\n", number_of_pages);
     assert(align_value_to_page(0x100) == 0x200000);
-    printf("\t [test_utils] (align_value_to_page): Testing alignment for 0x100, should be 0x200000: %lx\n", align_value_to_page(0x100));
+    printf("\t[test_utils] (align_value_to_page): Testing alignment for 0x100, should be 0x200000: %lx\n", align_value_to_page(0x100));
     assert(align_value_to_page(0x200015) == 0x400000);
-    printf("\t [test_utils] (align_value_to_page):  Testing alignment for 0x100, should be 0x200015: %lx\n", align_value_to_page(0x200015));
-
+    pretty_assert(0x200000, align_down(0x3c7000, 0x200000), ==, "Testing align_down");
+    pretty_assert(0x600000, align_down(0x6c7000, 0x200000), ==, "Testing align_down");
 }