:: commit f71e57af49a4fa4dfd44d772df0899f52dbe08f6

mintsuki <mintsuki@protonmail.com> — 2021-10-20 23:27

parents: 0506454005

everywhere: Implement pmm_free()

diff --git a/stage23/entry.s2.c b/stage23/entry.s2.c
index 62aaaea9..663ea65f 100644
--- a/stage23/entry.s2.c
+++ b/stage23/entry.s2.c
@@ -34,23 +34,25 @@ extern symbol stage3_addr;
 extern symbol limine_sys_size;
 
 static bool stage3_init(struct volume *part) {
-    struct file_handle stage3;
+    struct file_handle *stage3;
 
-    if (fopen(&stage3, part, "/limine.sys")
-     && fopen(&stage3, part, "/boot/limine.sys")) {
+    if ((stage3 = fopen(part, "/limine.sys")) == NULL
+     && (stage3 = fopen(part, "/boot/limine.sys")) == NULL) {
         return false;
     }
 
     stage3_found = true;
 
-    if (stage3.size != (size_t)limine_sys_size) {
+    if (stage3->size != (size_t)limine_sys_size) {
         print("limine.sys size incorrect.\n");
         return false;
     }
 
-    fread(&stage3, stage3_addr,
+    fread(stage3, stage3_addr,
           (uintptr_t)stage3_addr - 0x8000,
-          stage3.size - ((uintptr_t)stage3_addr - 0x8000));
+          stage3->size - ((uintptr_t)stage3_addr - 0x8000));
+
+    fclose(stage3);
 
     if (BUILD_ID != stage3_build_id) {
         print("limine.sys build ID mismatch.\n");
diff --git a/stage23/entry.s3.c b/stage23/entry.s3.c
index 9de0a3df..37b8e7e4 100644
--- a/stage23/entry.s3.c
+++ b/stage23/entry.s3.c
@@ -79,14 +79,16 @@ void uefi_entry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
             print("         Using the first volume containing a Limine configuration!\n");
 
             for (size_t i = 0; i < volume_index_i; i++) {
-                struct file_handle f;
+                struct file_handle *f;
 
-                if (fopen(&f, volume_index[i], "/limine.cfg")
-                 && fopen(&f, volume_index[i], "/boot/limine.cfg")
-                 && fopen(&f, volume_index[i], "/EFI/BOOT/limine.cfg")) {
+                if ((f = fopen(volume_index[i], "/limine.cfg")) == NULL
+                 && (f = fopen(volume_index[i], "/boot/limine.cfg")) == NULL
+                 && (f = fopen(volume_index[i], "/EFI/BOOT/limine.cfg")) == NULL) {
                     continue;
                 }
 
+                fclose(f);
+
                 if (volume_index[i]->backing_dev != NULL) {
                     boot_volume = volume_index[i]->backing_dev;
                 } else {
diff --git a/stage23/fs/echfs.h b/stage23/fs/echfs.h
index 38a684eb..bafce9b2 100644
--- a/stage23/fs/echfs.h
+++ b/stage23/fs/echfs.h
@@ -28,6 +28,7 @@ struct echfs_file_handle {
     uint64_t alloc_table_size;
     uint64_t alloc_table_offset;
     uint64_t dir_offset;
+    uint64_t file_block_count;
     uint64_t *alloc_map;
     struct echfs_dir_entry dir_entry;
 };
@@ -35,7 +36,8 @@ struct echfs_file_handle {
 int echfs_check_signature(struct volume *part);
 bool echfs_get_guid(struct guid *guid, struct volume *part);
 
-int echfs_open(struct echfs_file_handle *ret, struct volume *part, const char *filename);
-int echfs_read(struct echfs_file_handle *file, void *buf, uint64_t loc, uint64_t count);
+bool echfs_open(struct echfs_file_handle *ret, struct volume *part, const char *filename);
+void echfs_read(struct echfs_file_handle *file, void *buf, uint64_t loc, uint64_t count);
+void echfs_close(struct echfs_file_handle *file);
 
 #endif
diff --git a/stage23/fs/echfs.s2.c b/stage23/fs/echfs.s2.c
index c907b36a..c14546b6 100644
--- a/stage23/fs/echfs.s2.c
+++ b/stage23/fs/echfs.s2.c
@@ -26,7 +26,7 @@ static bool read_block(struct echfs_file_handle *file, void *buf, uint64_t block
     return volume_read(file->part, buf, (file->alloc_map[block] * file->block_size) + offset, count);
 }
 
-int echfs_read(struct echfs_file_handle *file, void *buf, uint64_t loc, uint64_t count) {
+void echfs_read(struct echfs_file_handle *file, void *buf, uint64_t loc, uint64_t count) {
     for (uint64_t progress = 0; progress < count;) {
         uint64_t block = (loc + progress) / file->block_size;
 
@@ -38,8 +38,6 @@ int echfs_read(struct echfs_file_handle *file, void *buf, uint64_t loc, uint64_t
         read_block(file, buf + progress, block, offset, chunk);
         progress += chunk;
     }
-
-    return 0;
 }
 
 int echfs_check_signature(struct volume *part) {
@@ -66,7 +64,12 @@ bool echfs_get_guid(struct guid *guid, struct volume *part) {
     return true;
 }
 
-int echfs_open(struct echfs_file_handle *ret, struct volume *part, const char *path) {
+void echfs_close(struct echfs_file_handle *file) {
+    pmm_free(file->alloc_map, file->file_block_count * sizeof(uint64_t));
+    pmm_free(file, sizeof(struct echfs_file_handle));
+}
+
+bool echfs_open(struct echfs_file_handle *ret, struct volume *part, const char *path) {
     ret->part = part;
 
     struct echfs_identity_table id_table;
@@ -74,7 +77,7 @@ int echfs_open(struct echfs_file_handle *ret, struct volume *part, const char *p
 
     if (strncmp(id_table.signature, "_ECH_FS_", 8)) {
         print("echfs: signature invalid\n");
-        return -1;
+        return false;
     }
 
     ret->block_size         = id_table.block_size;
@@ -121,16 +124,16 @@ next:;
         }
     }
 
-    return -1;
+    return false;
 
 found:;
     // Load the allocation map.
-    uint64_t file_block_count = DIV_ROUNDUP(ret->dir_entry.size, ret->block_size);
+    ret->file_block_count = DIV_ROUNDUP(ret->dir_entry.size, ret->block_size);
 
-    ret->alloc_map = ext_mem_alloc(file_block_count * sizeof(uint64_t));
+    ret->alloc_map = ext_mem_alloc(ret->file_block_count * sizeof(uint64_t));
 
     ret->alloc_map[0] = ret->dir_entry.payload;
-    for (uint64_t i = 1; i < file_block_count; i++) {
+    for (uint64_t i = 1; i < ret->file_block_count; i++) {
         // Read the next block.
         volume_read(ret->part,
             &ret->alloc_map[i],
@@ -138,5 +141,5 @@ found:;
             sizeof(uint64_t));
     }
 
-    return 0;
+    return true;
 }
diff --git a/stage23/fs/ext2.h b/stage23/fs/ext2.h
index e9541a09..baedaa77 100644
--- a/stage23/fs/ext2.h
+++ b/stage23/fs/ext2.h
@@ -125,7 +125,8 @@ struct ext2_file_handle {
 int ext2_check_signature(struct volume *part);
 bool ext2_get_guid(struct guid *guid, struct volume *part);
 
-int ext2_open(struct ext2_file_handle *ret, struct volume *part, const char *path);
-int ext2_read(struct ext2_file_handle *file, void *buf, uint64_t loc, uint64_t count);
+bool ext2_open(struct ext2_file_handle *ret, struct volume *part, const char *path);
+void ext2_read(struct ext2_file_handle *file, void *buf, uint64_t loc, uint64_t count);
+void ext2_close(struct ext2_file_handle *file);
 
 #endif
diff --git a/stage23/fs/ext2.s2.c b/stage23/fs/ext2.s2.c
index 8faa5a6d..6a617e6c 100644
--- a/stage23/fs/ext2.s2.c
+++ b/stage23/fs/ext2.s2.c
@@ -250,6 +250,8 @@ static bool ext2_parse_dirent(struct ext2_dir_entry *dir, struct ext2_file_handl
     bool escape = false;
     static char token[256];
 
+    bool ret;
+
 next:
     memset(token, 0, 256);
 
@@ -277,19 +279,24 @@ next:
 
         if (!strcmp(token, name)) {
             if (escape) {
-                return true;
+                ret = true;
+                goto out;
             } else {
                 // update the current inode
                 ext2_get_inode(&current_inode, fd, dir->inode);
                 while ((current_inode.i_mode & FMT_MASK) != S_IFDIR) {
                     if ((current_inode.i_mode & FMT_MASK) == S_IFLNK) {
-                        if (!symlink_to_inode(&current_inode, fd))
-                            return false;
+                        if (!symlink_to_inode(&current_inode, fd)) {
+                            ret = false;
+                            goto out;
+                        }
                     } else {
                         print("ext2: Part of path is not directory nor symlink\n");
-                        return false;
+                        ret = false;
+                        goto out;
                     }
                 }
+                pmm_free(alloc_map, current_inode.i_blocks_count * sizeof(uint32_t));
                 goto next;
             }
         }
@@ -297,10 +304,14 @@ next:
         i += dir->rec_len;
     }
 
-    return false;
+    ret = false;
+
+out:
+    pmm_free(alloc_map, current_inode.i_blocks_count * sizeof(uint32_t));
+    return ret;
 }
 
-int ext2_open(struct ext2_file_handle *ret, struct volume *part, const char *path) {
+bool ext2_open(struct ext2_file_handle *ret, struct volume *part, const char *path) {
     ret->part = part;
 
     volume_read(ret->part, &ret->sb, 1024, sizeof(struct ext2_superblock));
@@ -317,17 +328,17 @@ int ext2_open(struct ext2_file_handle *ret, struct volume *part, const char *pat
     struct ext2_dir_entry entry;
 
     if (!ext2_parse_dirent(&entry, ret, path))
-        return -1;
+        return false;
 
     ext2_get_inode(&ret->inode, ret, entry.inode);
 
     while ((ret->inode.i_mode & FMT_MASK) != S_IFREG) {
         if ((ret->inode.i_mode & FMT_MASK) == S_IFLNK) {
             if (!symlink_to_inode(&ret->inode, ret))
-                return -1;
+                return false;
         } else {
             print("ext2: Entity is not regular file nor symlink\n");
-            return -1;
+            return false;
         }
     }
 
@@ -335,11 +346,16 @@ int ext2_open(struct ext2_file_handle *ret, struct volume *part, const char *pat
 
     ret->alloc_map = create_alloc_map(ret, &ret->inode);
 
-    return 0;
+    return true;
+}
+
+void ext2_close(struct ext2_file_handle *file) {
+    pmm_free(file->alloc_map, file->inode.i_blocks_count * sizeof(uint32_t));
+    pmm_free(file, sizeof(struct ext2_file_handle));
 }
 
-int ext2_read(struct ext2_file_handle *file, void *buf, uint64_t loc, uint64_t count) {
-    return inode_read(buf, loc, count, &file->inode, file, file->alloc_map);
+void ext2_read(struct ext2_file_handle *file, void *buf, uint64_t loc, uint64_t count) {
+    inode_read(buf, loc, count, &file->inode, file, file->alloc_map);
 }
 
 static struct ext4_extent_header* ext4_find_leaf(struct ext4_extent_header* ext_block, uint32_t read_block, uint64_t block_size, struct volume *part) {
@@ -415,6 +431,8 @@ static int inode_read(void *buf, uint64_t loc, uint64_t count,
             } else {
                 panic("extent for block not found");
             }
+
+            pmm_free(leaf, fd->block_size);
         } else {
             block_index = alloc_map[block];
         }
diff --git a/stage23/fs/fat32.h b/stage23/fs/fat32.h
index 030c3b5b..92ccecd4 100644
--- a/stage23/fs/fat32.h
+++ b/stage23/fs/fat32.h
@@ -26,11 +26,13 @@ struct fat32_file_handle {
     uint32_t size_bytes;
     uint32_t size_clusters;
     uint32_t *cluster_chain;
+    size_t chain_len;
 };
 
 int fat32_check_signature(struct volume *part);
 
-int fat32_open(struct fat32_file_handle *ret, struct volume *part, const char *path);
-int fat32_read(struct fat32_file_handle *file, void *buf, uint64_t loc, uint64_t count);
+bool fat32_open(struct fat32_file_handle *ret, struct volume *part, const char *path);
+void fat32_read(struct fat32_file_handle *file, void *buf, uint64_t loc, uint64_t count);
+void fat32_close(struct fat32_file_handle *file);
 
 #endif
diff --git a/stage23/fs/fat32.s2.c b/stage23/fs/fat32.s2.c
index 03eebaac..e539900a 100644
--- a/stage23/fs/fat32.s2.c
+++ b/stage23/fs/fat32.s2.c
@@ -249,8 +249,9 @@ static int fat32_open_in(struct fat32_context* context, struct fat32_directory_e
 
         directory_entries = ext_mem_alloc(dir_chain_len * block_size);
 
-        if (!read_cluster_chain(context, directory_cluster_chain, directory_entries, 0, dir_chain_len * block_size))
-            return -1;
+        read_cluster_chain(context, directory_cluster_chain, directory_entries, 0, dir_chain_len * block_size);
+
+        pmm_free(directory_cluster_chain, dir_chain_len * sizeof(uint32_t));
     } else {
         dir_chain_len = DIV_ROUNDUP(context->root_entries * sizeof(struct fat32_directory_entry), block_size);
 
@@ -259,6 +260,8 @@ static int fat32_open_in(struct fat32_context* context, struct fat32_directory_e
         volume_read(context->part, directory_entries, context->root_start * FAT32_SECTOR_SIZE, context->root_entries * sizeof(struct fat32_directory_entry));
     }
 
+    int ret;
+
     for (size_t i = 0; i < (dir_chain_len * block_size) / sizeof(struct fat32_directory_entry); i++) {
         if (directory_entries[i].file_name_and_ext[0] == 0x00) {
             // no more entries here
@@ -295,7 +298,8 @@ static int fat32_open_in(struct fat32_context* context, struct fat32_directory_e
 
             if (!strcmp(current_lfn, name)) {
                 *file = directory_entries[i+1];
-                return 0;
+                ret = 0;
+                goto out;
             }
         }
 
@@ -310,12 +314,17 @@ static int fat32_open_in(struct fat32_context* context, struct fat32_directory_e
         }
         if (!strncmp(directory_entries[i].file_name_and_ext, fn, 8+3)) {
             *file = directory_entries[i];
-            return 0;
+            ret = 0;
+            goto out;
         }
     }
 
     // file not found
-    return -1;
+    ret = -1;
+
+out:
+    pmm_free(directory_entries, dir_chain_len * block_size);
+    return ret;
 }
 
 int fat32_check_signature(struct volume *part) {
@@ -323,13 +332,13 @@ int fat32_check_signature(struct volume *part) {
     return fat32_init_context(&context, part) == 0;
 }
 
-int fat32_open(struct fat32_file_handle* ret, struct volume *part, const char* path) {
+bool fat32_open(struct fat32_file_handle* ret, struct volume *part, const char* path) {
     struct fat32_context context;
     int r = fat32_init_context(&context, part);
 
     if (r) {
         print("fat32: context init failure (%d)\n", r);
-        return r;
+        return false;
     }
 
     struct fat32_directory_entry _current_directory;
@@ -379,7 +388,7 @@ int fat32_open(struct fat32_file_handle* ret, struct volume *part, const char* p
         }
 
         if ((r = fat32_open_in(&context, current_directory, &current_file, current_part)) != 0) {
-            return r;
+            return false;
         }
 
         if (expect_directory) {
@@ -392,13 +401,17 @@ int fat32_open(struct fat32_file_handle* ret, struct volume *part, const char* p
                 ret->first_cluster |= (uint64_t)current_file.cluster_num_high << 16;
             ret->size_clusters = DIV_ROUNDUP(current_file.file_size_bytes, FAT32_SECTOR_SIZE);
             ret->size_bytes = current_file.file_size_bytes;
-            size_t file_chain_len;
-            ret->cluster_chain = cache_cluster_chain(&context, ret->first_cluster, &file_chain_len);
-            return 0;
+            ret->cluster_chain = cache_cluster_chain(&context, ret->first_cluster, &ret->chain_len);
+            return true;
         }
     }
 }
 
-int fat32_read(struct fat32_file_handle* file, void* buf, uint64_t loc, uint64_t count) {
-    return !read_cluster_chain(&file->context, file->cluster_chain, buf, loc, count);
+void fat32_read(struct fat32_file_handle* file, void* buf, uint64_t loc, uint64_t count) {
+    read_cluster_chain(&file->context, file->cluster_chain, buf, loc, count);
+}
+
+void fat32_close(struct fat32_file_handle *file) {
+    pmm_free(file->cluster_chain, file->chain_len * sizeof(uint32_t));
+    pmm_free(file, sizeof(struct fat32_file_handle));
 }
diff --git a/stage23/fs/file.h b/stage23/fs/file.h
index 57d3a413..bfd3c0ee 100644
--- a/stage23/fs/file.h
+++ b/stage23/fs/file.h
@@ -13,16 +13,19 @@ bool fs_get_guid(struct guid *guid, struct volume *part);
 
 struct file_handle {
     bool       is_memfile;
+    bool       readall;
     void      *fd;
-    int      (*read)(void *fd, void *buf, uint64_t loc, uint64_t count);
+    void     (*read)(void *fd, void *buf, uint64_t loc, uint64_t count);
+    void     (*close)(void *fd);
     uint64_t   size;
 #if uefi == 1
     EFI_HANDLE efi_part_handle;
 #endif
 };
 
-int fopen(struct file_handle *ret, struct volume *part, const char *filename);
-int fread(struct file_handle *fd, void *buf, uint64_t loc, uint64_t count);
+struct file_handle *fopen(struct volume *part, const char *filename);
+void fread(struct file_handle *fd, void *buf, uint64_t loc, uint64_t count);
+void fclose(struct file_handle *fd);
 void *freadall(struct file_handle *fd, uint32_t type);
 
 #endif
diff --git a/stage23/fs/file.s2.c b/stage23/fs/file.s2.c
index 88d678d7..0ed22641 100644
--- a/stage23/fs/file.s2.c
+++ b/stage23/fs/file.s2.c
@@ -24,16 +24,18 @@ bool fs_get_guid(struct guid *guid, struct volume *part) {
     return false;
 }
 
-int fopen(struct file_handle *ret, struct volume *part, const char *filename) {
+struct file_handle *fopen(struct volume *part, const char *filename) {
+    struct file_handle *ret = ext_mem_alloc(sizeof(struct file_handle));
+
     ret->is_memfile = false;
+    ret->readall = false;
 
 #if bios == 1
     if (part->pxe) {
-        int r = tftp_open(ret, 0, 69, filename);
-        if (r)
-            return r;
-
-        return 0;
+        if (!tftp_open(ret, 0, 69, filename)) {
+            goto fail;
+        }
+        return ret;
     }
 #endif
 
@@ -44,95 +46,110 @@ int fopen(struct file_handle *ret, struct volume *part, const char *filename) {
     if (iso9660_check_signature(part)) {
         struct iso9660_file_handle *fd = ext_mem_alloc(sizeof(struct iso9660_file_handle));
 
-        int r = iso9660_open(fd, part, filename);
-        if (r)
-            return r;
+        if (!iso9660_open(fd, part, filename)) {
+            goto fail;
+        }
 
         ret->fd = (void *)fd;
         ret->read = (void *)iso9660_read;
+        ret->close = (void *)iso9660_close;
         ret->size = fd->size;
 
-        return 0;
+        return ret;
     }
 
     if (echfs_check_signature(part)) {
         struct echfs_file_handle *fd = ext_mem_alloc(sizeof(struct echfs_file_handle));
 
-        int r = echfs_open(fd, part, filename);
-        if (r)
-            return r;
+        if (!echfs_open(fd, part, filename)) {
+            goto fail;
+        }
 
-        ret->fd   = (void *)fd;
+        ret->fd = (void *)fd;
         ret->read = (void *)echfs_read;
+        ret->close = (void *)echfs_close;
         ret->size = fd->dir_entry.size;
 
-        return 0;
+        return ret;
     }
 
     if (ext2_check_signature(part)) {
         struct ext2_file_handle *fd = ext_mem_alloc(sizeof(struct ext2_file_handle));
 
-        int r = ext2_open(fd, part, filename);
-        if (r)
-            return r;
+        if (!ext2_open(fd, part, filename)) {
+            goto fail;
+        }
 
-        ret->fd   = (void *)fd;
+        ret->fd = (void *)fd;
         ret->read = (void *)ext2_read;
+        ret->close = (void *)ext2_close;
         ret->size = fd->size;
 
-        return 0;
+        return ret;
     }
 
     if (fat32_check_signature(part)) {
         struct fat32_file_handle *fd = ext_mem_alloc(sizeof(struct fat32_file_handle));
 
-        int r = fat32_open(fd, part, filename);
-
-        if (r)
-            return r;
+        if (!fat32_open(fd, part, filename)) {
+            goto fail;
+        }
 
-        ret->fd   = (void *)fd;
+        ret->fd = (void *)fd;
         ret->read = (void *)fat32_read;
+        ret->close = (void *)fat32_close;
         ret->size = fd->size_bytes;
 
-        return 0;
+        return ret;
     }
 
     if (ntfs_check_signature(part)) {
         struct ntfs_file_handle *fd = ext_mem_alloc(sizeof(struct ntfs_file_handle));
 
-        int r = ntfs_open(fd, part, filename);
-        if (r)
-            return r;
+        if (!ntfs_open(fd, part, filename)) {
+            goto fail;
+        }
 
         ret->fd = (void *)fd;
         ret->read = (void *)ntfs_read;
+        //ret->close = (void *)ntfs_close;
         ret->size = fd->size_bytes;
 
-        return 0;
+        return ret;
     }
 
-    return -1;
+fail:
+    pmm_free(ret, sizeof(struct file_handle));
+    return NULL;
+}
+
+void fclose(struct file_handle *fd) {
+    if (fd->is_memfile) {
+        if (fd->readall == false) {
+            pmm_free(fd->fd, fd->size);
+        }
+    } else {
+        fd->close(fd->fd);
+    }
+    pmm_free(fd, sizeof(struct file_handle));
 }
 
-int fread(struct file_handle *fd, void *buf, uint64_t loc, uint64_t count) {
+void fread(struct file_handle *fd, void *buf, uint64_t loc, uint64_t count) {
     if (fd->is_memfile) {
         memcpy(buf, fd->fd + loc, count);
-        return 0;
     } else {
-        return fd->read(fd->fd, buf, loc, count);
+        fd->read(fd->fd, buf, loc, count);
     }
 }
 
 void *freadall(struct file_handle *fd, uint32_t type) {
     if (fd->is_memfile) {
         memmap_alloc_range((uint64_t)(size_t)fd->fd, ALIGN_UP(fd->size, 4096), type, false, true, false, false);
+        fd->readall = true;
         return fd->fd;
     } else {
         void *ret = ext_mem_alloc_type(fd->size, type);
-        if (fd->read(fd->fd, ret, 0, fd->size)) {
-            panic("freadall error");
-        }
+        fd->read(fd->fd, ret, 0, fd->size);
         return ret;
     }
 }
diff --git a/stage23/fs/iso9660.h b/stage23/fs/iso9660.h
index 2819f325..8f13eccc 100644
--- a/stage23/fs/iso9660.h
+++ b/stage23/fs/iso9660.h
@@ -19,7 +19,8 @@ struct iso9660_file_handle {
 };
 
 int iso9660_check_signature(struct volume *vol);
-int iso9660_open(struct iso9660_file_handle *ret, struct volume *vol, const char *path);
-int iso9660_read(struct iso9660_file_handle *file, void *buf, uint64_t loc, uint64_t count);
+bool iso9660_open(struct iso9660_file_handle *ret, struct volume *vol, const char *path);
+void iso9660_read(struct iso9660_file_handle *file, void *buf, uint64_t loc, uint64_t count);
+void iso9660_close(struct iso9660_file_handle *file);
 
 #endif
diff --git a/stage23/fs/iso9660.s2.c b/stage23/fs/iso9660.s2.c
index 904597db..f8cedce2 100644
--- a/stage23/fs/iso9660.s2.c
+++ b/stage23/fs/iso9660.s2.c
@@ -76,7 +76,8 @@ struct iso9660_contexts_node {
     struct iso9660_context context;
     struct iso9660_contexts_node *next;
 };
-struct iso9660_contexts_node *contexts = NULL;
+
+static struct iso9660_contexts_node *contexts = NULL;
 
 static void iso9660_find_PVD(struct iso9660_volume_descriptor *desc, struct volume *vol) {
     uint32_t lba = ISO9660_FIRST_VOLUME_DESCRIPTOR;
@@ -207,7 +208,7 @@ int iso9660_check_signature(struct volume *vol) {
     return !strcmp(buf, "CD001");
 }
 
-int iso9660_open(struct iso9660_file_handle *ret, struct volume *vol, const char *path) {
+bool iso9660_open(struct iso9660_file_handle *ret, struct volume *vol, const char *path) {
     ret->context = iso9660_get_context(vol);
 
     while (*path == '/')
@@ -216,6 +217,8 @@ int iso9660_open(struct iso9660_file_handle *ret, struct volume *vol, const char
     struct iso9660_directory_entry *current = ret->context->root;
     uint32_t current_size = ret->context->root_size;
 
+    bool first = true;
+
     uint32_t next_sector = 0;
     uint32_t next_size = 0;
 
@@ -228,7 +231,7 @@ int iso9660_open(struct iso9660_file_handle *ret, struct volume *vol, const char
 
         struct iso9660_directory_entry *entry = iso9660_find(current, current_size, filename);
         if (!entry)
-            return 1;    // Not found :(
+            return false;    // Not found :(
 
         next_sector = entry->extent.little;
         next_size = entry->extent_size.little;
@@ -236,17 +239,27 @@ int iso9660_open(struct iso9660_file_handle *ret, struct volume *vol, const char
         if (*path++ == '\0')
             break;    // Found :)
 
+        if (!first) {
+            pmm_free(current, current_size);
+        }
+
         current_size = next_size;
         current = ext_mem_alloc(current_size);
+
+        first = false;
+
         volume_read(vol, current, next_sector * ISO9660_SECTOR_SIZE, current_size);
     }
 
     ret->LBA = next_sector;
     ret->size = next_size;
-    return 0;
+    return true;
 }
 
-int iso9660_read(struct iso9660_file_handle *file, void *buf, uint64_t loc, uint64_t count) {
+void iso9660_read(struct iso9660_file_handle *file, void *buf, uint64_t loc, uint64_t count) {
     volume_read(file->context->vol, buf, file->LBA * ISO9660_SECTOR_SIZE + loc, count);
-    return 0;
+}
+
+void iso9660_close(struct iso9660_file_handle *file) {
+    pmm_free(file, sizeof(struct iso9660_file_handle));
 }
diff --git a/stage23/lib/config.c b/stage23/lib/config.c
index dc549373..080a77ba 100644
--- a/stage23/lib/config.c
+++ b/stage23/lib/config.c
@@ -17,18 +17,20 @@ bool config_ready = false;
 static char *config_addr;
 
 int init_config_disk(struct volume *part) {
-    struct file_handle f;
+    struct file_handle *f;
 
-    if (fopen(&f, part, "/limine.cfg")
-     && fopen(&f, part, "/boot/limine.cfg")
-     && fopen(&f, part, "/EFI/BOOT/limine.cfg")) {
+    if ((f = fopen(part, "/limine.cfg")) == NULL
+     && (f = fopen(part, "/boot/limine.cfg")) == NULL
+     && (f = fopen(part, "/EFI/BOOT/limine.cfg")) == NULL) {
         return -1;
     }
 
-    size_t config_size = f.size + 1;
+    size_t config_size = f->size + 1;
     config_addr = ext_mem_alloc(config_size);
 
-    fread(&f, config_addr, 0, f.size);
+    fread(f, config_addr, 0, f->size);
+
+    fclose(f);
 
     return init_config(config_size);
 }
diff --git a/stage23/lib/elf.c b/stage23/lib/elf.c
index c99f633b..360b40c2 100644
--- a/stage23/lib/elf.c
+++ b/stage23/lib/elf.c
@@ -229,22 +229,34 @@ int elf64_load_section(uint8_t *elf, void *buffer, const char *name, size_t limi
     char *names = ext_mem_alloc(shstrtab.sh_size);
     memcpy(names, elf + (shstrtab.sh_offset), shstrtab.sh_size);
 
+    int ret;
+
     for (uint16_t i = 0; i < hdr.sh_num; i++) {
         struct elf64_shdr section;
         memcpy(&section, elf + (hdr.shoff + i * sizeof(struct elf64_shdr)),
                    sizeof(struct elf64_shdr));
 
         if (!strcmp(&names[section.sh_name], name)) {
-            if (section.sh_size > limit)
-                return 3;
-            if (section.sh_size < limit)
-                return 4;
+            if (section.sh_size > limit) {
+                ret = 3;
+                goto out;
+            }
+            if (section.sh_size < limit) {
+                ret = 4;
+                goto out;
+            }
             memcpy(buffer, elf + (section.sh_offset), section.sh_size);
-            return elf64_apply_relocations(elf, &hdr, buffer, section.sh_addr, section.sh_size, slide);
+            ret = elf64_apply_relocations(elf, &hdr, buffer, section.sh_addr, section.sh_size, slide);
+            goto out;
         }
     }
 
-    return 2;
+    ret = 2;
+
+out:
+    pmm_free(names, shstrtab.sh_size);
+
+    return ret;
 }
 
 /// SAFETY: The caller must ensure that the provided `elf` is a valid 64-bit
@@ -311,22 +323,34 @@ int elf32_load_section(uint8_t *elf, void *buffer, const char *name, size_t limi
     char *names = ext_mem_alloc(shstrtab.sh_size);
     memcpy(names, elf + (shstrtab.sh_offset), shstrtab.sh_size);
 
+    int ret;
+
     for (uint16_t i = 0; i < hdr.sh_num; i++) {
         struct elf32_shdr section;
         memcpy(&section, elf + (hdr.shoff + i * sizeof(struct elf32_shdr)),
                    sizeof(struct elf32_shdr));
 
         if (!strcmp(&names[section.sh_name], name)) {
-            if (section.sh_size > limit)
-                return 3;
-            if (section.sh_size < limit)
-                return 4;
+            if (section.sh_size > limit) {
+                ret = 3;
+                goto out;
+            }
+            if (section.sh_size < limit) {
+                ret = 4;
+                goto out;
+            }
             memcpy(buffer, elf + (section.sh_offset), section.sh_size);
-            return 0;
+            ret = 0;
+            goto out;
         }
     }
 
-    return 2;
+    ret = 2;
+
+out:
+    pmm_free(names, shstrtab.sh_size);
+
+    return ret;
 }
 
 static uint64_t elf64_max_align(uint8_t *elf) {
diff --git a/stage23/lib/gterm.c b/stage23/lib/gterm.c
index 5b96c404..ecc3bde3 100644
--- a/stage23/lib/gterm.c
+++ b/stage23/lib/gterm.c
@@ -671,12 +671,13 @@ bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height) {
 
     char *background_path = config_get_value(NULL, 0, "BACKGROUND_PATH");
     if (background_path != NULL) {
-        struct file_handle *bg_file = ext_mem_alloc(sizeof(struct file_handle));
-        if (uri_open(bg_file, background_path)) {
+        struct file_handle *bg_file;
+        if ((bg_file = uri_open(background_path)) != NULL) {
             background = ext_mem_alloc(sizeof(struct image));
             if (open_image(background, bg_file)) {
                 background = NULL;
             }
+            fclose(bg_file);
         }
     }
 
@@ -741,16 +742,16 @@ bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height) {
     if (menu_font == NULL)
         menu_font = config_get_value(NULL, 0, "TERMINAL_FONT");
     if (menu_font != NULL) {
-        struct file_handle f;
-        if (!uri_open(&f, menu_font)) {
+        struct file_handle *f;
+        if ((f = uri_open(menu_font)) == NULL) {
             print("menu: Could not open font file.\n");
         } else {
-            if (fread(&f, vga_font_bits, 0, font_bytes) == 0) {
-                if (menu_font_size != NULL) {
-                    vga_font_width = tmp_font_width;
-                    vga_font_height = tmp_font_height;
-                }
+            fread(f, vga_font_bits, 0, font_bytes);
+            if (menu_font_size != NULL) {
+                vga_font_width = tmp_font_width;
+                vga_font_height = tmp_font_height;
             }
+            fclose(f);
         }
     }
 
diff --git a/stage23/lib/uri.c b/stage23/lib/uri.c
index c7eb1519..4d9c2b33 100644
--- a/stage23/lib/uri.c
+++ b/stage23/lib/uri.c
@@ -86,63 +86,54 @@ static bool parse_bios_partition(char *loc, int *drive, int *partition) {
     return true;
 }
 
-static bool uri_hdd_dispatch(struct file_handle *fd, char *loc, char *path) {
+static struct file_handle *uri_hdd_dispatch(char *loc, char *path) {
     int drive, partition;
 
     if (!parse_bios_partition(loc, &drive, &partition))
-        return false;
+        return NULL;
 
     struct volume *volume = volume_get_by_coord(false, drive, partition);
 
     if (volume == NULL)
-        return false;
-
-    if (fopen(fd, volume, path))
-        return false;
+        return NULL;
 
-    return true;
+    return fopen(volume, path);
 }
 
-static bool uri_odd_dispatch(struct file_handle *fd, char *loc, char *path) {
+static struct file_handle *uri_odd_dispatch(char *loc, char *path) {
     int drive, partition;
 
     if (!parse_bios_partition(loc, &drive, &partition))
-        return false;
+        return NULL;
 
     struct volume *volume = volume_get_by_coord(true, drive, partition);
 
     if (volume == NULL)
-        return false;
-
-    if (fopen(fd, volume, path))
-        return false;
+        return NULL;
 
-    return true;
+    return fopen(volume, path);
 }
 
-static bool uri_guid_dispatch(struct file_handle *fd, char *guid_str, char *path) {
+static struct file_handle *uri_guid_dispatch(char *guid_str, char *path) {
     struct guid guid;
     if (!string_to_guid_be(&guid, guid_str))
-        return false;
+        return NULL;
 
     struct volume *volume = volume_get_by_guid(&guid);
     if (volume == NULL) {
         if (!string_to_guid_mixed(&guid, guid_str))
-            return false;
+            return NULL;
 
         volume = volume_get_by_guid(&guid);
         if (volume == NULL)
-            return false;
+            return NULL;
     }
 
-    if (fopen(fd, volume, path))
-        return false;
-
-    return true;
+    return fopen(volume, path);
 }
 
 #if bios == 1
-static bool uri_tftp_dispatch(struct file_handle *fd, char *root, char *path) {
+static struct file_handle *uri_tftp_dispatch(char *root, char *path) {
     uint32_t ip;
     if (!strcmp(root, "")) {
         ip = 0;
@@ -152,18 +143,19 @@ static bool uri_tftp_dispatch(struct file_handle *fd, char *root, char *path) {
         }
     }
 
-    if (tftp_open(fd, ip, 69, path)) {
-        return false;
+    struct file_handle *ret = ext_mem_alloc(sizeof(struct file_handle));
+    if (!tftp_open(ret, ip, 69, path)) {
+        return NULL;
     }
 
-    return true;
+    return ret;
 }
 #endif
 
-static bool uri_boot_dispatch(struct file_handle *fd, char *s_part, char *path) {
+static struct file_handle *uri_boot_dispatch(char *s_part, char *path) {
 #if bios == 1
     if (boot_volume->pxe)
-        return uri_tftp_dispatch(fd, s_part, path);
+        return uri_tftp_dispatch(s_part, path);
 #endif
 
     int partition;
@@ -181,16 +173,13 @@ static bool uri_boot_dispatch(struct file_handle *fd, char *s_part, char *path)
     struct volume *volume = volume_get_by_coord(boot_volume->is_optical,
                                                 boot_volume->index, partition);
     if (volume == NULL)
-        return false;
+        return NULL;
 
-    if (fopen(fd, volume, path))
-        return false;
-
-    return true;
+    return fopen(volume, path);
 }
 
-bool uri_open(struct file_handle *fd, char *uri) {
-    bool ret;
+struct file_handle *uri_open(char *uri) {
+    struct file_handle *ret;
 
     char *resource, *root, *path;
     uri_resolve(uri, &resource, &root, &path);
@@ -208,33 +197,33 @@ bool uri_open(struct file_handle *fd, char *uri) {
     if (!strcmp(resource, "bios")) {
         panic("bios:// resource is no longer supported. Check CONFIG.md for hdd:// and odd://");
     } else if (!strcmp(resource, "hdd")) {
-        ret = uri_hdd_dispatch(fd, root, path);
+        ret = uri_hdd_dispatch(root, path);
     } else if (!strcmp(resource, "odd")) {
-        ret = uri_odd_dispatch(fd, root, path);
+        ret = uri_odd_dispatch(root, path);
     } else if (!strcmp(resource, "boot")) {
-        ret = uri_boot_dispatch(fd, root, path);
+        ret = uri_boot_dispatch(root, path);
     } else if (!strcmp(resource, "guid")) {
-        ret = uri_guid_dispatch(fd, root, path);
+        ret = uri_guid_dispatch(root, path);
     } else if (!strcmp(resource, "uuid")) {
-        ret = uri_guid_dispatch(fd, root, path);
+        ret = uri_guid_dispatch(root, path);
 #if bios == 1
     } else if (!strcmp(resource, "tftp")) {
-        ret = uri_tftp_dispatch(fd, root, path);
+        ret = uri_tftp_dispatch(root, path);
 #endif
     } else {
         panic("Resource `%s` not valid.", resource);
     }
 
-    if (compressed && ret) {
-        struct file_handle compressed_fd = {0};
-        fread(fd, &compressed_fd.size, fd->size - 4, sizeof(uint32_t));
-        compressed_fd.fd = ext_mem_alloc(compressed_fd.size);
-        void *src = ext_mem_alloc(fd->size);
-        fread(fd, src, 0, fd->size);
-        if (tinf_gzip_uncompress(compressed_fd.fd, src, fd->size))
+    if (compressed && ret != NULL) {
+        struct file_handle *compressed_fd = ext_mem_alloc(sizeof(struct file_handle));
+        fread(ret, &compressed_fd->size, ret->size - 4, sizeof(uint32_t));
+        compressed_fd->fd = ext_mem_alloc(compressed_fd->size);
+        void *src = freadall(ret, MEMMAP_BOOTLOADER_RECLAIMABLE);
+        if (tinf_gzip_uncompress(compressed_fd->fd, src, ret->size))
             panic("tinf error");
-        compressed_fd.is_memfile = true;
-        *fd = compressed_fd;
+        fclose(ret);
+        compressed_fd->is_memfile = true;
+        ret = compressed_fd;
     }
 
     return ret;
diff --git a/stage23/lib/uri.h b/stage23/lib/uri.h
index 1fb65f43..a883a53a 100644
--- a/stage23/lib/uri.h
+++ b/stage23/lib/uri.h
@@ -5,6 +5,6 @@
 #include <fs/file.h>
 
 bool uri_resolve(char *uri, char **resource, char **root, char **path);
-bool uri_open(struct file_handle *fd, char *uri);
+struct file_handle *uri_open(char *uri);
 
 #endif
diff --git a/stage23/mm/pmm.h b/stage23/mm/pmm.h
index 5f6bcfa4..fce753e6 100644
--- a/stage23/mm/pmm.h
+++ b/stage23/mm/pmm.h
@@ -49,6 +49,8 @@ void *ext_mem_alloc_type(size_t count, uint32_t type);
 
 void *conv_mem_alloc(size_t count);
 
+void pmm_free(void *ptr, size_t length);
+
 #if uefi == 1
 void pmm_reclaim_uefi_mem(void);
 void pmm_release_uefi_mem(void);
diff --git a/stage23/mm/pmm.s2.c b/stage23/mm/pmm.s2.c
index 7dc7341f..984d68f6 100644
--- a/stage23/mm/pmm.s2.c
+++ b/stage23/mm/pmm.s2.c
@@ -563,6 +563,13 @@ struct e820_entry_t *get_raw_memmap(size_t *entry_count) {
 }
 #endif
 
+void pmm_free(void *ptr, size_t count) {
+    count = ALIGN_UP(count, 4096);
+    if (allocations_disallowed)
+        panic("Memory allocations disallowed");
+    memmap_alloc_range((uintptr_t)ptr, count, MEMMAP_USABLE, false, false, false, false);
+}
+
 void *ext_mem_alloc(size_t count) {
     return ext_mem_alloc_type(count, MEMMAP_BOOTLOADER_RECLAIMABLE);
 }
@@ -612,7 +619,7 @@ void *ext_mem_alloc_type(size_t count, uint32_t type) {
 }
 
 
-/// Compute and returns the amount of upper and lower memory till 
+/// Compute and returns the amount of upper and lower memory till
 /// the first hole.
 struct meminfo mmap_get_info(size_t mmap_count, struct e820_entry_t *mmap) {
     struct meminfo info = {0};
diff --git a/stage23/protos/chainload.c b/stage23/protos/chainload.c
index f773488c..9f8876b1 100644
--- a/stage23/protos/chainload.c
+++ b/stage23/protos/chainload.c
@@ -116,8 +116,8 @@ void chainload(char *config) {
     if (image_path == NULL)
         panic("chainload: IMAGE_PATH not specified");
 
-    struct file_handle *image = ext_mem_alloc(sizeof(struct file_handle));
-    if (!uri_open(image, image_path))
+    struct file_handle *image;
+    if ((image = uri_open(image_path)) == NULL)
         panic("chainload: Failed to open image with path `%s`. Is the path correct?", image_path);
 
     EFI_HANDLE efi_part_handle = image->efi_part_handle;
@@ -130,6 +130,9 @@ void chainload(char *config) {
         panic("chainload: Allocation failure");
     memcpy(ptr, _ptr, image_size);
 
+    pmm_free(_ptr, image->size);
+    fclose(image);
+
     term_deinit();
 
     size_t req_width = 0, req_height = 0, req_bpp = 0;
diff --git a/stage23/protos/linux.c b/stage23/protos/linux.c
index b578a9d5..4ddcc2f8 100644
--- a/stage23/protos/linux.c
+++ b/stage23/protos/linux.c
@@ -346,13 +346,13 @@ struct boot_params {
 // End of Linux code
 
 void linux_load(char *config, char *cmdline) {
-    struct file_handle *kernel = ext_mem_alloc(sizeof(struct file_handle));
+    struct file_handle *kernel;
 
     char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
     if (kernel_path == NULL)
         panic("linux: KERNEL_PATH not specified");
 
-    if (!uri_open(kernel, kernel_path))
+    if ((kernel = uri_open(kernel_path)) == NULL)
         panic("linux: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
 
     uint32_t signature;
@@ -441,11 +441,13 @@ void linux_load(char *config, char *cmdline) {
         if (module_path == NULL)
             break;
 
-        struct file_handle module;
-        if (!uri_open(&module, module_path))
+        struct file_handle *module;
+        if ((module = uri_open(module_path)) == NULL)
             panic("linux: Failed to open module with path `%s`. Is the path correct?", module_path);
 
-        size_of_all_modules += module.size;
+        size_of_all_modules += module->size;
+
+        fclose(module);
     }
 
     modules_mem_base -= size_of_all_modules;
@@ -464,15 +466,15 @@ void linux_load(char *config, char *cmdline) {
         if (module_path == NULL)
             break;
 
-        struct file_handle module;
-        if (!uri_open(&module, module_path))
+        struct file_handle *module;
+        if ((module = uri_open(module_path)) == NULL)
             panic("linux: Could not open `%s`", module_path);
 
         print("linux: Loading module `%s`...\n", module_path);
 
-        fread(&module, (void *)_modules_mem_base, 0, module.size);
+        fread(module, (void *)_modules_mem_base, 0, module->size);
 
-        _modules_mem_base += module.size;
+        _modules_mem_base += module->size;
     }
 
     if (size_of_all_modules != 0) {
diff --git a/stage23/protos/multiboot1.c b/stage23/protos/multiboot1.c
index 71eac9aa..727e02aa 100644
--- a/stage23/protos/multiboot1.c
+++ b/stage23/protos/multiboot1.c
@@ -24,7 +24,7 @@ __attribute__((noreturn)) void multiboot1_spinup_32(
 struct multiboot1_info multiboot1_info = {0};
 
 void multiboot1_load(char *config, char *cmdline) {
-    struct file_handle *kernel_file = ext_mem_alloc(sizeof(*kernel_file));
+    struct file_handle *kernel_file;
 
     char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
     if (kernel_path == NULL)
@@ -32,11 +32,13 @@ void multiboot1_load(char *config, char *cmdline) {
 
     print("multiboot1: Loading kernel `%s`...\n", kernel_path);
 
-    if (!uri_open(kernel_file, kernel_path))
+    if ((kernel_file = uri_open(kernel_path)) == NULL)
         panic("multiboot1: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
 
     uint8_t *kernel = freadall(kernel_file, MEMMAP_KERNEL_AND_MODULES);
 
+    fclose(kernel_file);
+
     struct multiboot1_header header = {0};
     size_t header_offset = 0;
 
@@ -134,8 +136,8 @@ void multiboot1_load(char *config, char *cmdline) {
 
             print("multiboot1: Loading module `%s`...\n", module_path);
 
-            struct file_handle f;
-            if (!uri_open(&f, module_path))
+            struct file_handle *f;
+            if ((f = uri_open(module_path)) == NULL)
                 panic("multiboot1: Failed to open module with path `%s`. Is the path correct?", module_path);
 
             char *module_cmdline = config_get_value(config, i, "MODULE_STRING");
@@ -143,16 +145,18 @@ void multiboot1_load(char *config, char *cmdline) {
             strcpy(lowmem_modstr, module_cmdline);
 
             void *module_addr = (void *)(uintptr_t)ALIGN_UP(kernel_top, 4096);
-            memmap_alloc_range((uintptr_t)module_addr, f.size, MEMMAP_KERNEL_AND_MODULES,
+            memmap_alloc_range((uintptr_t)module_addr, f->size, MEMMAP_KERNEL_AND_MODULES,
                                true, true, false, false);
-            kernel_top = (uintptr_t)module_addr + f.size;
-            fread(&f, module_addr, 0, f.size);
+            kernel_top = (uintptr_t)module_addr + f->size;
+            fread(f, module_addr, 0, f->size);
 
             m->begin   = (uint32_t)(size_t)module_addr;
-            m->end     = m->begin + f.size;
+            m->end     = m->begin + f->size;
             m->cmdline = (uint32_t)(size_t)lowmem_modstr;
             m->pad     = 0;
 
+            fclose(f);
+
             if (verbose) {
                 print("multiboot1: Requested module %u:\n", i);
                 print("            Path:   %s\n", module_path);
diff --git a/stage23/protos/multiboot2.c b/stage23/protos/multiboot2.c
index 25f1e41f..09236623 100644
--- a/stage23/protos/multiboot2.c
+++ b/stage23/protos/multiboot2.c
@@ -79,7 +79,7 @@ static size_t get_multiboot2_info_size(
 #define append_tag(P, TAG) ({ (P) += ALIGN_UP((TAG)->size, MULTIBOOT_TAG_ALIGN); })
 
 void multiboot2_load(char *config, char* cmdline) {
-    struct file_handle *kernel_file = ext_mem_alloc(sizeof(struct file_handle));
+    struct file_handle *kernel_file;
 
     char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
     if (kernel_path == NULL)
@@ -87,10 +87,13 @@ void multiboot2_load(char *config, char* cmdline) {
 
     print("multiboot2: Loading kernel `%s`...\n", kernel_path);
 
-    if (!uri_open(kernel_file, kernel_path))
+    if ((kernel_file = uri_open(kernel_path)) == NULL)
         panic("multiboot2: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
 
     uint8_t *kernel = freadall(kernel_file, MEMMAP_KERNEL_AND_MODULES);
+
+    fclose(kernel_file);
+
     struct multiboot_header *header = load_multiboot2_header(kernel);
 
     struct multiboot_header_tag_address *addresstag = NULL;
@@ -301,8 +304,8 @@ void multiboot2_load(char *config, char* cmdline) {
 
         print("multiboot2: Loading module `%s`...\n", module_path);
 
-        struct file_handle f;
-        if (!uri_open(&f, module_path))
+        struct file_handle *f;
+        if ((f = uri_open(module_path)) == NULL)
             panic("multiboot2: Failed to open module with path `%s`. Is the path correct?", module_path);
 
         char *module_cmdline = config_get_value(config, i, "MODULE_STRING");
@@ -314,20 +317,22 @@ void multiboot2_load(char *config, char* cmdline) {
             module_cmdline = "";
         }
 
-        memmap_alloc_range((uintptr_t)module_addr, f.size, MEMMAP_KERNEL_AND_MODULES,
+        memmap_alloc_range((uintptr_t)module_addr, f->size, MEMMAP_KERNEL_AND_MODULES,
                             true, true, false, false);
 
-        kernel_top = (uintptr_t)module_addr + f.size;
-        fread(&f, module_addr, 0, f.size);
+        kernel_top = (uintptr_t)module_addr + f->size;
+        fread(f, module_addr, 0, f->size);
 
         struct multiboot_tag_module *module_tag = (struct multiboot_tag_module *)(mb2_info + info_idx);
 
         module_tag->type = MULTIBOOT_TAG_TYPE_MODULE;
         module_tag->size = sizeof(struct multiboot_tag_module) + strlen(module_cmdline) + 1;
         module_tag->mod_start   = (uint32_t)(size_t)module_addr;
-        module_tag->mod_end     = module_tag->mod_start + f.size;
+        module_tag->mod_end     = module_tag->mod_start + f->size;
         strcpy(module_tag->cmdline, module_cmdline); // Copy over the command line
 
+        fclose(f);
+
         if (verbose) {
             print("multiboot2: Requested module %u:\n", i);
             print("            Path:   %s\n", module_path);
@@ -496,7 +501,7 @@ void multiboot2_load(char *config, char* cmdline) {
     //////////////////////////////////////////////
     {
         // NOTE: The multiboot2 specification does not say anything about if both
-        // smbios 32 and 64 bit entry points are present, then we pass both of them + smbios 
+        // smbios 32 and 64 bit entry points are present, then we pass both of them + smbios
         // support for grub2 is unimplemented. So, we are going to assume they expect us to
         // pass both of them if avaliable. Oh well...
         if (smbios_entry_32 != NULL) {
diff --git a/stage23/protos/stivale.c b/stage23/protos/stivale.c
index 5a7b0cf2..3dabb5d8 100644
--- a/stage23/protos/stivale.c
+++ b/stage23/protos/stivale.c
@@ -66,7 +66,7 @@ void stivale_load(char *config, char *cmdline) {
     stivale_struct.flags |= (1 << 1);    // we give colour information
     stivale_struct.flags |= (1 << 2);    // we give SMBIOS information
 
-    struct file_handle *kernel_file = ext_mem_alloc(sizeof(struct file_handle));
+    struct file_handle *kernel_file;
 
     char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
     if (kernel_path == NULL)
@@ -74,7 +74,7 @@ void stivale_load(char *config, char *cmdline) {
 
     print("stivale: Loading kernel `%s`...\n", kernel_path);
 
-    if (!uri_open(kernel_file, kernel_path))
+    if ((kernel_file = uri_open(kernel_path)) == NULL)
         panic("stivale: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
 
     char *kaslr_s = config_get_value(config, 0, "KASLR");
@@ -92,6 +92,8 @@ void stivale_load(char *config, char *cmdline) {
     int bits = elf_bits(kernel);
     bool loaded_by_anchor = false;
 
+    fclose(kernel_file);
+
     if (bits == -1) {
         struct stivale_anchor *anchor;
         if (!stivale_load_by_anchor((void **)&anchor, "STIVALE1 ANCHOR", kernel, kernel_file->size)) {
@@ -210,17 +212,19 @@ void stivale_load(char *config, char *cmdline) {
 
         print("stivale: Loading module `%s`...\n", module_path);
 
-        struct file_handle f;
-        if (!uri_open(&f, module_path))
+        struct file_handle *f;
+        if ((f = uri_open(module_path)) == NULL)
             panic("stivale: Failed to open module with path `%s`. Is the path correct?", module_path);
 
-        m->begin = REPORTED_ADDR((uint64_t)(size_t)freadall(&f, STIVALE_MMAP_KERNEL_AND_MODULES));
-        m->end   = m->begin + f.size;
+        m->begin = REPORTED_ADDR((uint64_t)(size_t)freadall(f, STIVALE_MMAP_KERNEL_AND_MODULES));
+        m->end   = m->begin + f->size;
         m->next  = 0;
 
         *prev_mod_ptr = REPORTED_ADDR((uint64_t)(size_t)m);
         prev_mod_ptr  = &m->next;
 
+        fclose(f);
+
         if (verbose) {
             print("stivale: Requested module %u:\n", i);
             print("         Path:   %s\n", module_path);
diff --git a/stage23/protos/stivale2.c b/stage23/protos/stivale2.c
index 5254273b..ed678c7e 100644
--- a/stage23/protos/stivale2.c
+++ b/stage23/protos/stivale2.c
@@ -62,7 +62,7 @@ void stivale2_term_callback(uint64_t, uint64_t, uint64_t, uint64_t);
 #endif
 
 void stivale2_load(char *config, char *cmdline, bool pxe, void *efi_system_table) {
-    struct file_handle *kernel_file = ext_mem_alloc(sizeof(struct file_handle));
+    struct file_handle *kernel_file;
 
     char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
     if (kernel_path == NULL)
@@ -70,7 +70,7 @@ void stivale2_load(char *config, char *cmdline, bool pxe, void *efi_system_table
 
     print("stivale2: Loading kernel `%s`...\n", kernel_path);
 
-    if (!uri_open(kernel_file, kernel_path))
+    if ((kernel_file = uri_open(kernel_path)) == NULL)
         panic("stivale2: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
 
     char *kaslr_s = config_get_value(config, 0, "KASLR");
@@ -91,6 +91,8 @@ void stivale2_load(char *config, char *cmdline, bool pxe, void *efi_system_table
     int bits = elf_bits(kernel);
     bool loaded_by_anchor = false;
 
+    fclose(kernel_file);
+
     if (bits == -1) {
         struct stivale2_anchor *anchor;
         if (!stivale_load_by_anchor((void **)&anchor, "STIVALE2 ANCHOR", kernel, kernel_file->size)) {
@@ -294,12 +296,14 @@ failed_to_load_header_section:
 
         print("stivale2: Loading module `%s`...\n", module_path);
 
-        struct file_handle f;
-        if (!uri_open(&f, module_path))
+        struct file_handle *f;
+        if ((f = uri_open(module_path)) == NULL)
             panic("stivale2: Failed to open module with path `%s`. Is the path correct?", module_path);
 
-        m->begin = REPORTED_ADDR((uint64_t)(size_t)freadall(&f, STIVALE2_MMAP_KERNEL_AND_MODULES));
-        m->end   = m->begin + f.size;
+        m->begin = REPORTED_ADDR((uint64_t)(size_t)freadall(f, STIVALE2_MMAP_KERNEL_AND_MODULES));
+        m->end   = m->begin + f->size;
+
+        fclose(f);
 
         if (verbose) {
             print("stivale2: Requested module %u:\n", i);
diff --git a/stage23/pxe/pxe.s2.c b/stage23/pxe/pxe.s2.c
index a49ff5c7..2516e225 100644
--- a/stage23/pxe/pxe.s2.c
+++ b/stage23/pxe/pxe.s2.c
@@ -50,7 +50,7 @@ void pxe_init(void) {
         panic("!pxe signature corrupted");
     }
     set_pxe_fp(bangpxe->rm_entry);
-    printv("pxe: Successfully initialized");
+    printv("pxe: Successfully initialized\n");
 }
 
 #endif
diff --git a/stage23/pxe/tftp.h b/stage23/pxe/tftp.h
index 60febf66..169f2819 100644
--- a/stage23/pxe/tftp.h
+++ b/stage23/pxe/tftp.h
@@ -38,7 +38,7 @@ struct pxenv_get_file_size {
 #define TFTP_CLOSE 0x21
 
 //server_ip and server_port can be 0 for default
-int tftp_open(struct file_handle *handle, uint32_t server_ip, uint16_t server_port, const char *name);
+bool tftp_open(struct file_handle *handle, uint32_t server_ip, uint16_t server_port, const char *name);
 
 uint32_t get_boot_server_info(void);
 
diff --git a/stage23/pxe/tftp.s2.c b/stage23/pxe/tftp.s2.c
index 510b4e5a..cfe27b3c 100644
--- a/stage23/pxe/tftp.s2.c
+++ b/stage23/pxe/tftp.s2.c
@@ -16,7 +16,7 @@ uint32_t get_boot_server_info(void) {
     return ph->sip;
 }
 
-int tftp_open(struct file_handle *handle, uint32_t server_ip, uint16_t server_port, const char *name) {
+bool tftp_open(struct file_handle *handle, uint32_t server_ip, uint16_t server_port, const char *name) {
     int ret = 0;
 
     if (!server_ip) {
@@ -26,7 +26,7 @@ int tftp_open(struct file_handle *handle, uint32_t server_ip, uint16_t server_po
     struct PXENV_UNDI_GET_INFORMATION undi_info = { 0 };
     ret = pxe_call(UNDI_GET_INFORMATION, ((uint16_t)rm_seg(&undi_info)), (uint16_t)rm_off(&undi_info));
     if (ret) {
-        return -1;
+        return false;
     }
 
     //TODO figure out a more proper way to do this.
@@ -39,7 +39,7 @@ int tftp_open(struct file_handle *handle, uint32_t server_ip, uint16_t server_po
     strcpy((char*)fsize.name, name);
     ret = pxe_call(TFTP_GET_FILE_SIZE, ((uint16_t)rm_seg(&fsize)), (uint16_t)rm_off(&fsize));
     if (ret) {
-        return -1;
+        return false;
     }
 
     handle->size = fsize.file_size;
@@ -56,7 +56,7 @@ int tftp_open(struct file_handle *handle, uint32_t server_ip, uint16_t server_po
     ret = pxe_call(TFTP_OPEN, ((uint16_t)rm_seg(&open)), (uint16_t)rm_off(&open));
     if (ret) {
         print("tftp: Failed to open file %x or bad packet size", open.status);
-        return -1;
+        return false;
     }
 
     mtu = open.packet_size;
@@ -94,7 +94,9 @@ int tftp_open(struct file_handle *handle, uint32_t server_ip, uint16_t server_po
         panic("tftp: Close failure");
     }
 
-    return 0;
+    pmm_free(buf, mtu);
+
+    return true;
 }
 
 #endif
tab: 248 wrap: offon