--- /dev/null
+#include <config.h>
+#include <corax/types.h>
+#include <arch.h>
+#include <multiboot.h>
+#include <string.h>
+#include "frame.h"
+
+static u64_t *_frame_map;
+static u64_t _mem_end;
+
+#define FRAMES_PER_CHUNK (sizeof(*_frame_map) * BITS_PER_BYTE)
+
+#define ADDR_TO_FRAME(addr) ((addr) / FRAME_SIZE)
+#define FRAME_TO_CHUNK(frame) ((frame) / FRAMES_PER_CHUNK)
+#define FRAME_TO_INDEX(frame) ((frame) % FRAMES_PER_CHUNK)
+
+/*
+ * _frame_set - Mark a frame as in-use
+ *
+ * SYNOPSIS
+ * void _frame_set(const u64_t addr)
+ *
+ * DESCRIPTION
+ * The _frame_set() function marks the frame indicated by `addr' as in-use in the frame map.
+ * `addr' may be any address contained within the frame to be marked.
+ *
+ * RETURN VALUE
+ * void
+ *
+ * ERRORS
+ * This function does not return information about any error conditions.
+ */
+static inline void _frame_set(const u64_t addr)
+{
+ u64_t frame;
+
+ frame = ADDR_TO_FRAME(addr);
+ _frame_map[FRAME_TO_CHUNK(frame)] |= (1 << FRAME_TO_INDEX(frame));
+
+ return;
+}
+
+/*
+ * _frame_clear - Mark a frame as not-in-use
+ *
+ * SYNOPSIS
+ * void _frame_clear(const u64_t addr)
+ *
+ * DESCRIPTION
+ * The _frame_clear() function marks the frame indicated by `addr' as not-in-use in the frame
+ * map. `addr' may be any address contained within the frame to be marked.
+ *
+ * RETURN VALUE
+ * void
+ *
+ * ERRORS
+ * This function does not return information about any error conditions.
+ */
+static inline void _frame_clear(const u64_t addr)
+{
+ u64_t frame;
+
+ frame = ADDR_TO_FRAME(addr);
+ _frame_map[FRAME_TO_CHUNK(frame)] &= ~(1 << FRAME_TO_INDEX(frame));
+
+ return;
+}
+
+/*
+ * _frame_get - Return the state of a frame in the frame-map
+ *
+ * SYNOPSIS
+ * u64_t _frame_get(const u64_t addr)
+ *
+ * DESCRIPTION
+ * The _frame_get() function returns the state of the frame indicated by `addr' in the frame
+ * map. `addr' may be any address within the frame to be inquired about.
+ *
+ * RETURN VALUE
+ * Zero if the frame is not in use, or a non-zero value otherwise.
+ *
+ * ERRORS
+ * This function does not return information about any error conditions.
+ */
+static inline u64_t _frame_get(const u64_t addr)
+{
+ u64_t frame;
+
+ frame = ADDR_TO_FRAME(addr);
+
+ return(_frame_map[FRAME_TO_CHUNK(frame)] & (1 << FRAME_TO_INDEX(frame)));
+}
+
+/*
+ * _clear_available_frames() - Mark available memory as unused in the frame map
+ *
+ * SYNOPSIS
+ * void _clear_unused_frames(struct multiboot_info *info);
+ *
+ * DESCRIPTION
+ * The _clear_available_frames() function will iterate over the memory map from the multiboot
+ * information pointed to by `info', and mark all frames of memory regions that are available
+ * for general use as not-in-use in the frame map.
+ *
+ * RETURN VALUE
+ * void
+ *
+ * ERRORS
+ * This function does not signal any errors.
+ */
+void _clear_unused_frames(struct multiboot_info *info)
+{
+ struct memory_map *mmap;
+
+ for(mmap = (struct memory_map*)info->mmap_addr;
+ (void*)mmap < (void*)(info->mmap_addr + info->mmap_length);
+ mmap = (struct memory_map*)((void*)mmap + mmap->size + sizeof(mmap->size))) {
+ u64_t addr;
+
+ if(mmap->type != MEM_AVAILABLE) {
+ continue;
+ }
+
+ for(addr = mmap->addr; addr < (mmap->addr + mmap->len); addr += FRAME_SIZE) {
+ _frame_clear(addr);
+ }
+ }
+
+ return;
+}
+
+/*
+ * _get_memory_end() - Get the upper end of usable memory
+ *
+ * SYNOPSIS
+ * u64_t _get_memory_end(struct multiboot_info *info);
+ *
+ * DESCRIPTION
+ * The _get_memory_end() function determines the upper end of the usable memory by inspecting \
+the
+ * multiboot information pointed to by `info'. It iterates over the memory map provided by the
+ * bootloader and simply computes the end of the highest memory region that the bootloader
+ * recons to be available for use by the operating system.
+ *
+ * RETURN VALUE
+ * Upon success, the first address after the highest usable memory region is returned. If the
+ * address could not be determined, zero is returned.
+ *
+ * ERRORS
+ * This function does not signal any errors.
+ */
+static u64_t _get_memory_end(struct multiboot_info *info)
+{
+ struct memory_map *mmap;
+ u64_t mem_end;
+
+ mem_end = 0;
+
+ for(mmap = (struct memory_map*)info->mmap_addr;
+ (void*)mmap < (void*)(info->mmap_addr + info->mmap_length);
+ mmap = (struct memory_map*)((void*)mmap + mmap->size + sizeof(mmap->size))) {
+ if(mmap->type != MEM_AVAILABLE) {
+ continue;
+ }
+
+ if((mmap->addr + mmap->len) > mem_end) {
+ mem_end = mmap->addr + mmap->len;
+ }
+ }
+
+ return(mem_end);
+}
+
+/*
+ * frame_init - Initialize the frame map
+ *
+ * SYNOPSIS
+ * void frame_init(struct memory_map *mmap, const u32_t mmap_length)
+ *
+ * DESCRIPTION
+ * The frame_init() function initializes the frame map that is used to remember which frames
+ * in the systems are occupied or free. The size of the map is determined from the multiboot
+ * memory map pointed to by `mmap', and the frame map is initialized according to the memory
+ * regions in the memory map.
+ *
+ * RETURN VALUE
+ * void
+ *
+ * ERRORS
+ * This function does not return information about any error conditions.
+ */
+void frame_init(struct multiboot_info *info)
+{
+ extern u64_t _mem_start;
+ u64_t map_bytes;
+ u64_t num_frames;
+
+ _mem_end = _get_memory_end(info);
+
+ num_frames = _mem_end / FRAME_SIZE;
+ map_bytes = num_frames / BITS_PER_BYTE;
+
+ if(!ALIGNED(_mem_start, sizeof(*_frame_map))) {
+ _mem_start = ALIGN(_mem_start, sizeof(*_frame_map));
+ }
+ _frame_map = (u64_t*)((u32_t)_mem_start);
+
+ memset(_frame_map, 0xff, map_bytes);
+
+ dbg_printf("%lluKB of memory (%llu frames) to account for\n", _mem_end / 1024, num_frames);
+
+ _clear_unused_frames(info);
+
+ _mem_start += map_bytes;
+
+ return;
+}
+
+static int _n_free_frames_r(u64_t addr, unsigned n)
+{
+ while(n > 0) {
+ if(_frame_get(addr)) {
+ return(0);
+ }
+
+ addr -= FRAME_SIZE;
+ n--;
+ }
+
+ return(1);
+}
+
+static u64_t _find_contiguous_frames_r(const unsigned num_frames, const u64_t addr)
+{
+ u64_t cur_addr;
+ u64_t tsize;
+
+ tsize = (u64_t)num_frames * (u64_t)FRAME_SIZE;
+
+ for(cur_addr = addr; cur_addr > tsize; cur_addr -= FRAME_SIZE) {
+ if(_n_free_frames_r(cur_addr, num_frames)) {
+ return(cur_addr - tsize);
+ }
+ }
+
+ return(-1ULL);
+}
+
+u64_t frame_alloc(const u64_t size, const int flags)
+{
+ u64_t phys_size;
+ u64_t num_frames;
+ u64_t limit;
+ u64_t addr;
+
+ phys_size = ALIGN(size, FRAME_SIZE);
+ num_frames = phys_size / FRAME_SIZE;
+ limit = _mem_end;
+
+ if(flags & FRAME_ALLOC_4G && _mem_end >= 0x100000000LL) {
+ limit = 0xfffff000;
+ }
+
+// dbg_printf("frame_alloc(0x%016llx, 0x%02x) limit = 0x%016llx\n",
+// size, flags, limit);
+
+ addr = _find_contiguous_frames_r(num_frames, limit);
+
+// dbg_printf("addr = 0x%016llx\n", addr);
+
+ if(addr != -1ULL) {
+ while(num_frames > 0) {
+ _frame_set(addr + FRAME_SIZE * num_frames);
+ num_frames--;
+ }
+ }
+
+ return(addr);
+}
+
+void frame_free(const u64_t addr, const u64_t size)
+{
+ u64_t cur_addr;
+
+ for(cur_addr = addr; cur_addr < addr + size; cur_addr += FRAME_SIZE) {
+ _frame_clear(cur_addr);
+ }
+
+ return;
+}