summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAda Christine <adachristine18@gmail.com>2022-02-24 01:58:07 +0000
committerAda Christine <adachristine18@gmail.com>2022-02-24 01:58:07 +0000
commit1923e47fd296399180eaf19b990d5e951d71ccd2 (patch)
tree2c61fa3d29321c3cf8e31a6ca1b1edcc053cb8f1
parent4fa48a2a7814c2f7d3992533313df283c3aa2652 (diff)
many changes
- boot time memory allocation has changed. the fractal page map has been replaced by a single self-mapped page giving 2MiB of ready virtual space to play with without needing a fully-initialized memory manager. this scheme may be repeated for other purposes - the page stack has now been totally overhauled to make use of sparse allocation and all of the ugly init_*() procedures are gone. long live the new interface. also reference counting is a thing now. sort of. - found a bug in vmt_init_node where insertion did not use the root node as the parent in the case of no predecessor node. whoops.
-rw-r--r--api/kernel/entry.h69
-rw-r--r--api/kernel/memory/range.h6
-rw-r--r--kc/api/kc.h13
-rw-r--r--kc/boot/kc_main.c266
-rw-r--r--kc/core/Makefile5
-rw-r--r--kc/core/kcc_memory.c2
-rw-r--r--kc/core/memory.c641
-rw-r--r--kc/core/memory.h45
-rw-r--r--kc/core/memory/memory.c628
-rw-r--r--kc/core/memory/page_early.c95
-rw-r--r--kc/core/memory/page_early.h8
-rw-r--r--kc/core/memory/page_stack.c215
-rw-r--r--kc/core/memory/page_stack.h18
-rw-r--r--kc/core/task.c4
-rw-r--r--kc/core/vm_object.h9
-rw-r--r--kc/core/vm_tree.c55
-rw-r--r--kc/core/vm_tree.h10
-rw-r--r--kc/kc.ld11
18 files changed, 1305 insertions, 795 deletions
diff --git a/api/kernel/entry.h b/api/kernel/entry.h
index eb7043c..460b677 100644
--- a/api/kernel/entry.h
+++ b/api/kernel/entry.h
@@ -3,33 +3,56 @@
#include <stddef.h>
#include <kernel/memory/range.h>
+enum video_pixel_format
+{
+ NO_VIDEO_FORMAT,
+ RGBA32BPP_VIDEO_FORMAT,
+ BGRA32BPP_VIDEO_FORMAT
+};
+
+enum acpi_version
+{
+ ACPI_LEGACY,
+ ACPI_CURRENT
+};
+
+struct kc_boot_data_buffer
+{
+ unsigned char *base;
+ unsigned char *current;
+ size_t max_size;
+ size_t available_size;
+};
+
+struct kc_boot_memory_data
+{
+ struct memory_range *entries;
+ size_t count;
+};
+
+struct kc_boot_video_data
+{
+ struct memory_range framebuffer;
+ uint16_t width;
+ uint16_t height;
+ size_t pitch;
+ enum video_pixel_format format;
+};
+
+struct kc_boot_acpi_data
+{
+ void *rsdp;
+ enum acpi_version version;
+};
+
typedef int (*kc_entry_func)(void *parameters);
struct kc_boot_data
{
- struct
- {
- void *base;
- size_t size;
- } object_space;
- struct
- {
- struct memory_range *base;
- size_t entries;
- } phys_memory_map;
- struct
- {
- struct memory_range range;
- size_t pitch; // line stride in bytes
- uint16_t width; // width in pixels
- uint16_t height; // height in pixels
- uint8_t format; // pixel format
- } framebuffer_info;
- struct
- {
- void *rsdp;
- uint8_t version;
- } acpi_info;
+ struct kc_boot_data_buffer buffer;
+ struct kc_boot_memory_data memory;
+ struct kc_boot_video_data video;
+ struct kc_boot_acpi_data acpi;
};
struct kc_boot_data *get_boot_data(void);
diff --git a/api/kernel/memory/range.h b/api/kernel/memory/range.h
index 90b3354..0084bbb 100644
--- a/api/kernel/memory/range.h
+++ b/api/kernel/memory/range.h
@@ -7,10 +7,14 @@ typedef uintptr_t phys_addr_t;
enum memory_range_type
{
- UNUSABLE_MEMORY,
+ // types for physical pages
RESERVED_MEMORY,
SYSTEM_MEMORY,
AVAILABLE_MEMORY,
+ // types for firmware pages with unknown backing
+ FIRMWARE_MEMORY,
+ // types for other addresses that are not physical
+ MMIO_MEMORY,
INVALID_MEMORY = 0xff
};
diff --git a/kc/api/kc.h b/kc/api/kc.h
index c3390b2..b4a6682 100644
--- a/kc/api/kc.h
+++ b/kc/api/kc.h
@@ -1,11 +1,12 @@
#pragma once
-extern char kc_image_base;
-extern char kc_text_begin;
-extern char kc_text_end;
-extern char kc_rodata_begin;
-extern char kc_data_begin;
-extern char kc_data_end;
+extern unsigned char kc_image_base;
+extern unsigned char kc_text_begin;
+extern unsigned char kc_text_end;
+extern unsigned char kc_rodata_begin;
+extern unsigned char kc_data_begin;
+extern unsigned char kc_data_end;
+extern unsigned char kc_image_end;
#define KC_EXPORT __attribute__((visibility("default")))
diff --git a/kc/boot/kc_main.c b/kc/boot/kc_main.c
index 1686ce4..5b32ee6 100644
--- a/kc/boot/kc_main.c
+++ b/kc/boot/kc_main.c
@@ -9,6 +9,9 @@
#include "../lib/elf.h"
+#define KERNEL_IMAGE_BASE 0xffffffff80000000
+#define OBJECT_SPACE_SIZE 131072
+
struct efi_memory_map
{
struct memory_range buffer;
@@ -18,27 +21,11 @@ struct efi_memory_map
UINT32 descver;
};
-struct efi_video_data
-{
- struct memory_range buffer;
- UINT32 width;
- UINT32 height;
- UINT32 pitch;
- EFI_GRAPHICS_PIXEL_FORMAT format;
- EFI_PIXEL_BITMASK mask;
-};
-
-struct efi_acpi_data
-{
- void *rsdp;
- int rsdp_version;
-};
-
struct efi_boot_data
{
- struct efi_memory_map memory_map;
- struct efi_video_data video_data;
- struct efi_acpi_data acpi_data;
+ struct efi_memory_map memory;
+ struct kc_boot_video_data video;
+ struct kc_boot_acpi_data acpi;
};
struct efi_loader_image kernel_image =
@@ -46,6 +33,8 @@ struct efi_loader_image kernel_image =
.path = L"\\adasoft\\sophia\\kernel.os"
};
+static void *boot_data_alloc(size_t size);
+
static struct efi_loader_interface *loader_interface;
static struct efi_boot_data boot_data;
static EFI_BOOT_SERVICES *e_bs = NULL;
@@ -56,6 +45,24 @@ static struct kc_boot_data *k_boot_data;
static void *object_space_base;
static size_t object_space_size;
+static void *boot_data_alloc(size_t size)
+{
+ size = (size + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1);
+
+ if (size > k_boot_data->buffer.available_size)
+ {
+ return NULL;
+ }
+
+ k_boot_data->buffer.available_size -= size;
+
+ void *buffer = k_boot_data->buffer.current;
+
+ k_boot_data->buffer.current += size;
+
+ return buffer;
+}
+
static inline void debug()
{
__asm__ volatile
@@ -82,7 +89,7 @@ uint64_t *new_page_table(void)
{
EFI_PHYSICAL_ADDRESS table;
EFI_STATUS status;
-
+
status = loader_interface->page_alloc(SystemMemoryType, page_size(1), &table);
if (EFI_ERROR(status))
@@ -111,7 +118,6 @@ enum page_type get_page_type(Elf64_Phdr *phdr)
return INVALID_PAGE_TYPE;
}
-#define KERNEL_IMAGE_BASE 0xffffffff80000000
static void create_kernel_maps(Elf64_Ehdr *ehdr, void *base)
{
@@ -125,10 +131,10 @@ static void create_kernel_maps(Elf64_Ehdr *ehdr, void *base)
uint64_t phys_begin = phdrs[i].p_offset + (uintptr_t)ehdr;
size_t size = phdrs[i].p_memsz;
map_pages(system_page_map,
- virt_begin,
- phys_begin,
- get_page_type(&phdrs[i]),
- size);
+ virt_begin,
+ phys_begin,
+ get_page_type(&phdrs[i]),
+ size);
}
}
@@ -139,12 +145,54 @@ static void create_kernel_maps(Elf64_Ehdr *ehdr, void *base)
// this is where any temporary mappings will be set up
// including the boot data tables that will be passed into the kernel
// and also the temporary window that the kernel will continue to use
- //
+
map_page(
system_page_map,
-1ULL,
(uint64_t)get_page_table(system_page_map, -1ULL, 1),
DATA_PAGE_TYPE);
+
+ object_space_base = (unsigned char *)-page_size(2);
+ object_space_size = page_size(2) - page_size(1);
+}
+
+static size_t calculate_pixel_size(EFI_PIXEL_BITMASK bitmask)
+{
+ (void)bitmask;
+ return 0;
+}
+
+static size_t get_video_pitch(
+ UINTN scanline_pixels,
+ EFI_GRAPHICS_PIXEL_FORMAT format,
+ EFI_PIXEL_BITMASK bitmask)
+{
+ switch (format)
+ {
+ case PixelBlueGreenRedReserved8BitPerColor:
+ case PixelRedGreenBlueReserved8BitPerColor:
+ return sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * scanline_pixels;
+ case PixelBitMask:
+ return calculate_pixel_size(bitmask) * scanline_pixels;
+ default:
+ return 0;
+ }
+}
+
+static enum video_pixel_format get_video_format(
+ EFI_GRAPHICS_PIXEL_FORMAT format)
+{
+ switch (format)
+ {
+ case PixelBlueGreenRedReserved8BitPerColor:
+ return BGRA32BPP_VIDEO_FORMAT;
+ case PixelRedGreenBlueReserved8BitPerColor:
+ return RGBA32BPP_VIDEO_FORMAT;
+ case PixelBitMask:
+ return NO_VIDEO_FORMAT;
+ default:
+ return 0;
+ }
}
static void collect_video_data(void)
@@ -161,18 +209,24 @@ static void collect_video_data(void)
}
else
{
- plog(L"found graphics device\r\n");
EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *mode = gop_interface->Mode;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info = mode->Info;
+ plog(L"found graphics device\r\n");
- boot_data.video_data.buffer.base = mode->FrameBufferBase;
- boot_data.video_data.buffer.size = mode->FrameBufferSize;
-
- boot_data.video_data.width = info->HorizontalResolution;
- boot_data.video_data.height = info->VerticalResolution;
- boot_data.video_data.pitch = info->PixelsPerScanLine;
- boot_data.video_data.format = info->PixelFormat;
- boot_data.video_data.mask = info->PixelInformation;
+ boot_data.video = (struct kc_boot_video_data){
+ {
+ RESERVED_MEMORY,
+ mode->FrameBufferBase,
+ mode->FrameBufferSize
+ },
+ info->HorizontalResolution,
+ info->VerticalResolution,
+ get_video_pitch(
+ info->PixelsPerScanLine,
+ info->PixelFormat,
+ info->PixelInformation),
+ get_video_format(info->PixelFormat)
+ };
}
}
@@ -196,8 +250,8 @@ static void collect_acpi_data(void)
{
plog(L"found ACPI RSDP 2.0\r\n");
// if we find the RSDP 2.0 table we can leave it at that
- boot_data.acpi_data.rsdp = config_table[i].VendorTable;
- boot_data.acpi_data.rsdp_version = 2;
+ boot_data.acpi.rsdp = config_table[i].VendorTable;
+ boot_data.acpi.version = ACPI_CURRENT;
break;
}
// if we get through the table without finding a v2 RSDP
@@ -209,8 +263,8 @@ static void collect_acpi_data(void)
sizeof(EFI_GUID)))
{
plog(L"found ACPI RSDP 1.0\r\n");
- boot_data.acpi_data.rsdp = config_table[i].VendorTable;
- boot_data.acpi_data.rsdp_version = 1;
+ boot_data.acpi.rsdp = config_table[i].VendorTable;
+ boot_data.acpi.version = ACPI_LEGACY;
// we must keep looking for the ACPI2.0 table GUID because
// it might be beyond this entry
continue;
@@ -222,22 +276,22 @@ static void collect_memory_map(void)
{
EFI_STATUS status;
- boot_data.memory_map.size = 0;
+ boot_data.memory.size = 0;
- status = e_bs->GetMemoryMap(&boot_data.memory_map.size,
+ status = e_bs->GetMemoryMap(&boot_data.memory.size,
NULL,
- &boot_data.memory_map.key,
+ &boot_data.memory.key,
NULL,
NULL);
if (EFI_BUFFER_TOO_SMALL == status)
{
plog(L"getting memory map size\r\n");
- boot_data.memory_map.buffer.size = boot_data.memory_map.size +=
+ boot_data.memory.buffer.size = boot_data.memory.size +=
EFI_PAGE_SIZE;
status = loader_interface->page_alloc(SystemMemoryType,
- boot_data.memory_map.buffer.size,
- (EFI_PHYSICAL_ADDRESS *)&boot_data.memory_map.buffer.base);
+ boot_data.memory.buffer.size,
+ (EFI_PHYSICAL_ADDRESS *)&boot_data.memory.buffer.base);
}
if (EFI_ERROR(status))
@@ -248,14 +302,14 @@ static void collect_memory_map(void)
if (!EFI_ERROR(status))
{
plog(L"got the memory map size\r\n");
- boot_data.memory_map.size = boot_data.memory_map.buffer.size;
+ boot_data.memory.size = boot_data.memory.buffer.size;
plog(L"getting memory map\r\n");
- status = e_bs->GetMemoryMap(&boot_data.memory_map.size,
- (EFI_MEMORY_DESCRIPTOR *)boot_data.memory_map.buffer.base,
- &boot_data.memory_map.key,
- &boot_data.memory_map.descsize,
- &boot_data.memory_map.descver);
+ status = e_bs->GetMemoryMap(&boot_data.memory.size,
+ (EFI_MEMORY_DESCRIPTOR *)boot_data.memory.buffer.base,
+ &boot_data.memory.key,
+ &boot_data.memory.descsize,
+ &boot_data.memory.descver);
}
if (EFI_ERROR(status))
@@ -268,67 +322,76 @@ static void collect_memory_map(void)
static void collect_boot_data(void)
{
+ plog(L"collecting boot data\r\n");
collect_video_data();
collect_acpi_data();
collect_memory_map();
}
-static void *kobject_alloc(size_t size)
+static void convert_acpi_data(void)
{
- if (!k_boot_data)
- return NULL;
- if (size > k_boot_data->object_space.size)
- return NULL;
-
- void *block = k_boot_data->object_space.base;
- k_boot_data->object_space.base = (void *)(size +
- (char *)k_boot_data->object_space.base);
- k_boot_data->object_space.size -= size;
+ k_boot_data->acpi = boot_data.acpi;
+}
- return block;
+static void convert_video_data(void)
+{
+ k_boot_data->video = boot_data.video;
}
static void convert_memory_map(void)
{
- k_boot_data->phys_memory_map.entries = boot_data.memory_map.size /
- boot_data.memory_map.descsize;
- k_boot_data->phys_memory_map.base = (struct memory_range *)kobject_alloc(
- k_boot_data->phys_memory_map.entries *
- sizeof(*k_boot_data->phys_memory_map.base));
-
- struct memory_range *ranges = k_boot_data->phys_memory_map.base;
+ k_boot_data->memory.count =
+ boot_data.memory.size / boot_data.memory.descsize;
+ k_boot_data->memory.entries =
+ boot_data_alloc(sizeof(struct memory_range) *
+ k_boot_data->memory.count);
- for (size_t i = 0; i < k_boot_data->phys_memory_map.entries; i++)
+ for (size_t i = 0; i < k_boot_data->memory.count; i++)
{
EFI_MEMORY_DESCRIPTOR *desc;
- desc = (EFI_MEMORY_DESCRIPTOR *)(boot_data.memory_map.buffer.base +
+ desc = (EFI_MEMORY_DESCRIPTOR *)(boot_data.memory.buffer.base +
i *
- boot_data.memory_map.descsize);
+ boot_data.memory.descsize);
enum memory_range_type type;
phys_addr_t base;
size_t size;
-
+
base = desc->PhysicalStart;
size = desc->NumberOfPages * EFI_PAGE_SIZE;
-
+
switch (desc->Type)
{
case EfiConventionalMemory:
case EfiBootServicesData:
case EfiBootServicesCode:
+ case EfiLoaderCode:
+ case EfiLoaderData:
type = AVAILABLE_MEMORY;
break;
case SystemMemoryType:
type = SYSTEM_MEMORY;
break;
+ case EfiRuntimeServicesData:
+ case EfiRuntimeServicesCode:
+ case EfiACPIReclaimMemory:
+ case EfiACPIMemoryNVS:
+ case EfiPalCode:
+ type = FIRMWARE_MEMORY;
+ break;
+ case EfiMemoryMappedIO:
+ case EfiMemoryMappedIOPortSpace:
+ type = MMIO_MEMORY;
+ break;
+ case EfiUnusableMemory:
+ type = INVALID_MEMORY;
+ break;
default:
type = RESERVED_MEMORY;
}
-
- ranges[i].type = type;
- ranges[i].base = base;
- ranges[i].size = size;
+
+ k_boot_data->memory.entries[i]
+ = (struct memory_range){type, base, size};
}
}
@@ -340,7 +403,7 @@ static EFI_STATUS enter_kernel(Elf64_Ehdr *ehdr)
collect_boot_data();
status = e_bs->ExitBootServices(loader_interface->image_handle,
- boot_data.memory_map.key);
+ boot_data.memory.key);
if (EFI_ERROR(status))
{
@@ -350,15 +413,18 @@ static EFI_STATUS enter_kernel(Elf64_Ehdr *ehdr)
set_page_map(system_page_map);
- while (true)
- __asm__("cli;hlt");
-
k_boot_data = (struct kc_boot_data *)object_space_base;
- k_boot_data->object_space.base = sizeof(*k_boot_data) +
- (char *)object_space_base;
- k_boot_data->object_space.size = object_space_size;
+ k_boot_data->buffer.base = (unsigned char *)k_boot_data;
+ k_boot_data->buffer.max_size = object_space_size;
+
+ k_boot_data->buffer.current =
+ k_boot_data->buffer.base + sizeof(*k_boot_data);
+ k_boot_data->buffer.available_size =
+ k_boot_data->buffer.max_size - sizeof(*k_boot_data);
convert_memory_map();
+ convert_video_data();
+ convert_acpi_data();
kc_entry_func kernel_entry = (kc_entry_func)
(KERNEL_IMAGE_BASE + ehdr->e_entry);
@@ -390,8 +456,6 @@ EFI_STATUS kc_main(struct efi_loader_interface *interface)
!EFI_ERROR((status = interface->image_alloc(&kernel_image))) &&
!EFI_ERROR((status = interface->image_load(&kernel_image))))
{
- plog(L"collecting boot data\r\n");
-
plog(L"creating page tables\r\n");
system_page_map = new_page_table();
// parasitic map of uefi page tables is this ok???????
@@ -402,36 +466,30 @@ EFI_STATUS kc_main(struct efi_loader_interface *interface)
plog(L"mapping kernel pages\r\n");
create_kernel_maps(ehdr, (void *)KERNEL_IMAGE_BASE);
- object_space_base =
- (void *)(page_align(kernel_image.buffer_size,1) +
- (char *)KERNEL_IMAGE_BASE);
-
- // add a tail of 64KiB to the kernel image
- uint64_t object_space_end = (uintptr_t)object_space_base +
- page_size(1) * 16;
- object_space_size = object_space_end -
- (uintptr_t)object_space_base;
+ // set up the object space buffer
+ // this will be discarded after boot time (maybe idk)
+ plog(L"creating object space buffer\r\n");
EFI_PHYSICAL_ADDRESS object_space_phys_base;
+ UINTN object_space_phys_size = OBJECT_SPACE_SIZE;
- status = loader_interface->page_alloc(SystemMemoryType,
- object_space_size,
+ status = loader_interface->page_alloc(
+ SystemMemoryType,
+ object_space_phys_size,
&object_space_phys_base);
if (EFI_ERROR(status))
{
- plog(L"failed allocating object space");
+ plog(L"failed allocating physical buffer for object space\r\n");
debug();
}
- map_pages(system_page_map,
+ map_pages(
+ system_page_map,
(uintptr_t)object_space_base,
object_space_phys_base,
DATA_PAGE_TYPE,
- object_space_size);
-
- e_bs->SetMem((void *)object_space_phys_base, object_space_size, 0);
-
+ object_space_phys_size);
enter_kernel(ehdr);
}
diff --git a/kc/core/Makefile b/kc/core/Makefile
index 6651ca6..9b8983a 100644
--- a/kc/core/Makefile
+++ b/kc/core/Makefile
@@ -1,7 +1,7 @@
include ../../defaults.mk
include ../defaults.mk
-VPATH := ../../lib ../ cpu/
+VPATH := ../../lib ../ cpu/ memory/
TARGET := kernel.os
.DEFAULT: $(TARGET)
@@ -13,7 +13,8 @@ SOBJS :=
GOBJS := entry_x86_64.o reloc_x86_64.o kprint.o serial.o port.o mmu.o \
kc_main.o memory.o memset.o memcpy.o memmove.o memcmp.o cpu.o \
vm_tree.o exceptions.o panic.o msr.o task.o cpu_task.o irq.o \
- kcc_memory.o string.o pic8259.o pic8259_isr.o pit8253.o
+ kcc_memory.o string.o pic8259.o pic8259_isr.o pit8253.o \
+ page_early.o page_stack.o
IOBJS :=
# __attribute__((interrupt)) requires -mgeneral-regs-only
diff --git a/kc/core/kcc_memory.c b/kc/core/kcc_memory.c
index 1f3a813..e1d2382 100644
--- a/kc/core/kcc_memory.c
+++ b/kc/core/kcc_memory.c
@@ -5,7 +5,7 @@
KC_EXPORT
kc_phys_addr kcc_page_alloc(void)
{
- return page_alloc();
+ return page_alloc(PAGE_ALLOC_ANY);
}
KC_EXPORT
diff --git a/kc/core/memory.c b/kc/core/memory.c
deleted file mode 100644
index bef6cd2..0000000
--- a/kc/core/memory.c
+++ /dev/null
@@ -1,641 +0,0 @@
-#include "memory.h"
-#include "kprint.h"
-#include "panic.h"
-#include "vm_tree.h"
-#include "vm_object.h"
-#include "cpu/mmu.h"
-
-#include <stdint.h>
-
-#include <kc.h>
-
-/* kernel virtual space guarantees
- *
- * the loader must set up the address space as follows
- * 1. kernel virtual space is 2GiB in size on 2GiB alignment.
- * 2. mappings begin at +0x7fc00000. this mapping space is sparse and its
- * own mapping tables begin at +0x7fffe000.
- * 3. There is at least 64KiB of mapped pages following the kc_image_end symbol.
- */
-
-#define kpm1_index(v) (((uint64_t)v >> pte_index_bits(1)) & 0x7ffff)
-#define kpm2_index(v) (((uint64_t)v >> pte_index_bits(2)) & 0x3ff)
-
-#define align_next(v, a) (((uint64_t)v + a - 1) & ~(a - 1))
-
-static int core_image_handler(uint32_t code, void *address);
-static int core_vmobject_handler(uint32_t code, void *address);
-
-struct page
-{
- uint32_t next: 31;
- uint32_t used: 1;
-};
-
-static struct page * const page_array = (struct page *)0xffffffd800000000;
-static int first_free_page_index = -1;
-static size_t page_array_entries = 0;
-static size_t free_pages = 0;
-
-// the temporary mapping place. never use this permanently.
-static void *const vm_temp = (void *)0xffffffffffa00000;
-static uint64_t *const kernel_pm1 = (uint64_t *)0xffffffffffc00000;
-static uint64_t *const kernel_pm2 = (uint64_t *)0xffffffffffffe000;
-
-static uint64_t *get_kernel_pm1e(void *vaddr);
-static uint64_t *get_kernel_pm2e(void *vaddr);
-static void *page_map_at(void *vaddr, phys_addr_t paddr, enum page_map_flags flags);
-
-static struct vm_tree core_vm_tree;
-
-static struct vm_tree_node core_image_node;
-static struct vm_tree_node core_vmobject_node;
-static struct vm_tree_node core_pagemaps_node;
-
-static struct vm_object core_image_object = {.type = TRANSLATION_VM_OBJECT};
-static struct vm_object core_vmobject = {.type = ANONYMOUS_VM_OBJECT};
-
-static size_t vm_object_space_size = 0x1000000; // 16MiB to start.
-static void *vm_next_free = NULL;
-
-static struct memory_range init_grab_pages(
- struct memory_range *ranges,
- int count,
- size_t size)
-{
- struct memory_range request = {SYSTEM_MEMORY,
- 0,
- align_next(size, page_size(1))};
-
- for (int i = 0; i < count; i++)
- {
- if (ranges[i].type != AVAILABLE_MEMORY ||
- ranges[i].base < (1 << 20)) // leave pages below 1MiB alone.
- {
- continue;
- }
- else if (ranges[i].size > request.size)
- {
- request.base = ranges[i].base;
- ranges[i].base += request.size;
- ranges[i].size -= request.size;
- return request;
- }
- }
-
- request.type = INVALID_MEMORY;
- return request;
-}
-
-static size_t init_get_max_paddr(struct memory_range *ranges, int count)
-{
- phys_addr_t max_paddr = 0;
-
- // get the highest usable physical address in all memory ranges.
- for (int i = 0; i < count; i++)
- {
- if (ranges[i].type != AVAILABLE_MEMORY)
- {
- continue;
- }
-
- if ((ranges[i].base + ranges[i].size - 1) > max_paddr)
- {
- max_paddr = ranges[i].base + ranges[i].size - 1;
- }
- }
-
- return max_paddr;
-}
-
-static phys_addr_t get_kernel_pm4_phys(void)
-{
- return mmu_get_map();
-}
-
-static phys_addr_t get_kernel_pm3_phys(void)
-{
- phys_addr_t pm3_phys;
- // make a temporary mapping to read pm4
- uint64_t *pm4 = page_map_at(vm_temp,
- get_kernel_pm4_phys(),
- CONTENT_RODATA|SIZE_2M);
-
- // pm3_phys is in pm4.
- pm3_phys = page_address(pm4[pte_index(&kc_image_base, 4)], 1);
- // never leave a temporary mapping
- page_unmap(pm4);
-
- return pm3_phys;
-}
-
-static void init_map_page_array_pm2(struct memory_range *pm2_pages)
-{
- // now we need to write the physical address of each pm2 page for the
- // page_array in the kernel's pm3.
- uint64_t *pm3 = page_map_at(vm_temp,
- get_kernel_pm3_phys(),
- CONTENT_RWDATA|SIZE_2M);
-
- // the first index is NOT zero!
- for (size_t i = 0; i < (pm2_pages->size / PAGE_SIZE); i++)
- {
- pm3[pte_index(page_array, 3) + i] = (
- pm2_pages->base + i *
- PAGE_SIZE)|PAGE_NX|PAGE_WR|PAGE_PR;
- }
- // never forget to unmap temporary mappings.
- page_unmap(pm3);
-}
-
-static void init_create_page_array_map(struct memory_range *pages,
- struct memory_range *maps)
-{
- // indices for page_array always start at 0
- size_t entry_count = pages->size / PAGE_SIZE;
-
- // every 512 entries we need to re-map and clean.
- for (size_t i = 0; i < entry_count; i += PAGE_TABLE_INDEX_MASK)
- {
- uint64_t *pm1 = page_map_at(
- vm_temp,
- maps->base + i * PAGE_SIZE,
- CONTENT_RWDATA|SIZE_2M);
- memset(pm1, 0, PAGE_SIZE);
- for (size_t j = 0;
- (j < PAGE_TABLE_INDEX_MASK) && ((j + i) < entry_count);
- j++)
- {
- pm1[j] = (pages->base + (i + j) * PAGE_SIZE)|
- PAGE_NX|PAGE_WR|PAGE_PR;
- }
-
- page_unmap(pm1);
- }
-}
-
-static void init_set_memory_range(struct memory_range *range)
-{
- for (size_t i = 0; i < range->size / PAGE_SIZE; i++)
- {
- if (range->base / PAGE_SIZE + i > page_array_entries)
- {
- return;
- }
-
- if (range->type == AVAILABLE_MEMORY)
- {
- page_free(range->base + PAGE_SIZE * i);
- }
- else
- {
- struct page *page = &page_array[range->base / PAGE_SIZE + i];
- page->used = 1;
- }
- }
-}
-
-static void init_populate_page_array(struct memory_range *ranges, int count)
-{
- for (int i = 0; i < count; i++)
- {
- init_set_memory_range(&ranges[i]);
- }
-}
-
-static void init_create_page_array(struct memory_range *ranges, int count)
-{
- // the highest actual physical memory address.
- size_t max_paddr = init_get_max_paddr(ranges, count);
- page_array_entries = max_paddr / page_size(1);
- size_t page_array_size = page_array_entries * sizeof(struct page);
-
- // the physical pages that will contain page_array
- struct memory_range pa_pages = init_grab_pages(ranges, count, page_array_size);
-
- // the number of page tables needed to map pa_pages
- // this will be 1 on systems with less than 2GB of memory.
- size_t pm1_count = page_count(pa_pages.size, 2);
- struct memory_range pm1_pages = init_grab_pages(ranges,
- count,
- pm1_count * page_size(1));
-
- init_create_page_array_map(&pa_pages, &pm1_pages);
-
- // the number of page directories needed to map pa_pages
- // this will be 1 on systems with less than 1TB of memory.
- // who the fuck has 1TB of memory lol
- size_t pm2_count = page_count(pa_pages.size, 3);
- struct memory_range pm2_pages = init_grab_pages(ranges,
- count,
- pm2_count * page_size(1));
-
- init_create_page_array_map(&pm1_pages, &pm2_pages);
-
- // ok here goes
- init_map_page_array_pm2(&pm2_pages);
-
- memset(page_array, 0, page_array_size);
-
- init_populate_page_array(ranges, count);
- init_populate_page_array(&pa_pages, 1);
- init_populate_page_array(&pm1_pages, 1);
- init_populate_page_array(&pm2_pages, 1);
-}
-
-static void *page_map_at(void *vaddr,
- phys_addr_t paddr,
- enum page_map_flags flags)
-{
- uint64_t entry = PAGE_PR;
-
- switch (flags & CONTENT_MASK)
- {
- case CONTENT_RODATA:
- entry |= PAGE_NX;
- break;
- case CONTENT_RWDATA:
- entry |= PAGE_NX|PAGE_WR;
- break;
- default:
- break;
- }
-
- size_t offset;
- uint64_t *pte;
-
- switch (flags & SIZE_MASK)
- {
- case SIZE_2M:
- entry |= page_address(paddr, 2)|PAGE_LG;
- offset = page_offset(paddr, 2);
- pte = get_kernel_pm2e(vaddr);
- break;
- case SIZE_4K:
- entry |= page_address(paddr, 1);
- offset = page_offset(paddr, 1);
- pte = get_kernel_pm1e(vaddr);
- break;
- default:
- offset = 0;
- pte = NULL;
- }
-
- if (!pte)
- {
- return NULL;
- }
-
- *pte = entry;
- return (char *)vaddr + offset;
-}
-
-static void init_vm_node(
- struct vm_tree_node *node,
- struct vm_object *object,
- void *base,
- void *head)
-{
- memset(node, 0, sizeof(*node));
- node->key =
- (struct vm_tree_key)
- {
- (uintptr_t)base,
- (size_t)head - (size_t)base
- };
-
- if (!vmt_search_key(&core_vm_tree, &node->key))
- {
- kputs("inserting node\n");
- struct vm_tree_node *p = vmn_predecessor_key(
- core_vm_tree.root,
- &node->key);
- vmt_insert(
- &core_vm_tree,
- node,
- p,
- vmn_child_direction(node, p));
- node->object = object;
- }
- else
- {
- kputs("fatal: attempt to insert overlapping vm node\n");
- PANIC(GENERAL_PANIC);
- }
-}
-
-void memory_init(void)
-{
- struct kc_boot_data *boot_data = get_boot_data();
-
- init_create_page_array(
- boot_data->phys_memory_map.base,
- boot_data->phys_memory_map.entries);
-
- void * object_space_head = (void *)page_align(
- boot_data->object_space.size +
- (uintptr_t)boot_data->object_space.base, 1);
-
- kputs("static vm node 1\n");
- init_vm_node(
- &core_image_node,
- &core_image_object,
- &kc_image_base,
- object_space_head);
- core_image_node.object->handler = core_image_handler;
-
- kputs("static vm node 2\n");
- init_vm_node(
- &core_vmobject_node,
- &core_vmobject,
- object_space_head,
- (char *)object_space_head + vm_object_space_size);
- core_vmobject_node.object->handler = core_vmobject_handler;
-
- kputs("static vm node 3\n");
- init_vm_node(&core_pagemaps_node, NULL, vm_temp, (void *)-1);
- vm_next_free = (char *)object_space_head + vm_object_space_size;
-}
-
-void *page_map(phys_addr_t paddr, enum page_map_flags flags)
-{
- (void)paddr;
- (void)flags;
- return NULL;
-}
-
-void page_unmap(void *vaddr)
-{
- uint64_t *pte = get_kernel_pm2e(vaddr);
-
- if (pte && !(*pte & PAGE_LG))
- {
- pte = get_kernel_pm1e(vaddr);
- }
-
- if (pte)
- {
- *pte = 0;
- }
- mmu_invalidate(vaddr);
-}
-
-phys_addr_t page_alloc(void)
-{
- int index = first_free_page_index;
-
- if (index > 0)
- {
- page_array[index].used = 1;
- first_free_page_index = page_array[index].next;
- free_pages--;
- }
-
- return (phys_addr_t)index * page_size(1);
-}
-
-void page_free(phys_addr_t paddr)
-{
- int index = paddr / page_size(1);
-
- if ((size_t)index > page_array_entries)
- {
- return;
- }
-
- page_array[index].used = 0;
- page_array[index].next = first_free_page_index;
- first_free_page_index = index;
- free_pages++;
-}
-
-struct heap_header
-{
- size_t size;
- struct heap_header *next;
-};
-
-static struct heap_header *heap_root = (void *)-1;
-
-void *heap_alloc(size_t size)
-{
- // simple first-fit allocator, allocates downward from the head
- // of the first block of sufficient size
- // TODO: join heap blocks if there is not one of sufficient size
- void *block = NULL;
-
- // first attempt at allocation
- if ((void *)-1 == heap_root)
- {
- heap_root = NULL;
- struct heap_header *header = (void *)core_vmobject_node.key.address;
- header->size = core_vmobject_node.key.size - sizeof(header->size);
- heap_free((char *)header + sizeof(*header));
- }
-
- struct heap_header *header = heap_root;
- size = align_next(size, sizeof(*header));
-
- while (header)
- {
- if (header->size > size)
- {
- break;
- }
- header = header->next;
- }
-
- if (header)
- {
- header->size -= size + sizeof(*header);
- header = (struct heap_header *)((char *)header + header->size);
- header->size = size;
- header->next = NULL;
- block = (char *)header + sizeof(*header);
- }
-
- return block;
-}
-
-void heap_free(void *block)
-{
- struct heap_header *header = (void *)
- ((char *)block - sizeof(*header));
-
- header->next = heap_root;
- heap_root = header;
-}
-
-void *memory_alloc(size_t size)
-{
- // allocations larger than page-size should just get an anonymous vm_object
- if (size < 4096)
- {
- return heap_alloc(size);
- }
- else
- {
- return vm_alloc(size);
- }
-}
-
-void memory_free(void *block)
-{
- // a little complicated to implement
- //
- // 1. find the vm_object that owns the block
- // a. if the vm_object is a heap, call heap_free()
- // b. if the vm_object is an anonymous vm_area, call vm_free().
- // c. if the object is any other kind issue a bug warning and do nothing
- (void)block;
-}
-
-void *vm_alloc_at(void *address, size_t size)
-{
- // TODO: all of the vm_tree code is a bit of a mess. needs to be cleaned
- // up and streamlined.
- struct vm_tree_key key = {(uintptr_t)address, size};
-
- // 1. check that there's a gap at the given location
- struct vm_tree_node *node = vmt_search_key( &core_vm_tree, &key);
-
- if (!node)
- {
- node = heap_alloc(sizeof(*node));
- init_vm_node(node, &core_vmobject, address, (char *)address + size);
- }
- else
- {
- return NULL;
- }
-
- return address;
-}
-
-void *vm_alloc(size_t size)
-{
- // TODO: gap-finding algorithm for failed allocations
- void *address = vm_alloc_at(vm_next_free, size);
-
- if (address)
- {
- vm_next_free = (char *)address + size;
- return address;
- }
-
- return NULL;
-}
-
-static uint64_t *get_kernel_pm1e(void *vaddr)
-{
- return &kernel_pm1[kpm1_index(vaddr)];
-}
-
-static uint64_t *get_kernel_pm2e(void *vaddr)
-{
- return &kernel_pm2[kpm2_index(vaddr)];
-}
-
-int anonymous_page_handler(uint32_t code, void *address)
-{
- kputs("anonymous space fault\n");
- if (code & PAGE_PR)
- {
- kputs("can't fault a present page\n");
- // there's no reason a protection violation should happen
- // in anonymous space
- PANIC(UNHANDLED_FAULT);
- }
- // kernel page mappings are built different
- if (address >= (void *)&kc_image_base)
- {
- uint64_t *pm2e = get_kernel_pm2e(address);
-
- if (!page_address(*pm2e, 1))
- {
- // create a page table and install it
- phys_addr_t pm1_phys = page_alloc();
- if (pm1_phys)
- {
- uint64_t *pm1;
- pm1 = page_map_at(vm_temp, pm1_phys, CONTENT_RWDATA|SIZE_2M);
- // zero the page
- memset(pm1, 0, PAGE_SIZE);
- // put the table where it goes
- *pm2e = page_address(pm1_phys, 1)|PAGE_WR|PAGE_PR;
- page_unmap(pm1);
- }
- else
- {
- PANIC(OUT_OF_MEMORY);
- }
- }
-
- uint64_t *pm1e = get_kernel_pm1e(address);
-
- if (pm1e)
- {
- phys_addr_t page_phys = page_alloc();
- if (page_phys)
- {
- *pm1e = page_address(page_phys, 1)|PAGE_WR|PAGE_PR;
- // clear a potentially dirty page.
- memset((void *)page_address(address, 1), 0, page_size(1));
- }
- }
- }
-
- return 0;
-}
-
-int page_fault_handler(uint8_t vector, uint32_t code)
-{
- (void)vector;
- void *address;
- __asm__ volatile ("movq %%cr2, %0" : "=r"(address));
- kprintf("page fault code=%d, pfla=%#lx\n", code, address);
- struct vm_object *o = vmt_get_object(&core_vm_tree, address);
- int result = 1;
- if (o)
- {
- kputs("found memory manager object\n");
- if (o->handler)
- {
- result = o->handler(code, address);
- }
- if (result)
- {
- PANIC(UNHANDLED_FAULT);
- }
- }
- else
- {
- kputs("didn't find memory object\n");
- PANIC(UNHANDLED_FAULT);
- }
-
- return 0;
-}
-
-int general_protection_handler(uint8_t vector, uint32_t code)
-{
- //TODO: implement #gp handler
- (void)vector;
- (void)code;
- kputs("general protection violation\n");
- PANIC(UNHANDLED_FAULT);
- return 0;
-}
-
-static int core_image_handler(uint32_t code, void *address)
-{
- (void) code;
- (void) address;
- return 1;
-}
-
-static int core_vmobject_handler(uint32_t code, void *address)
-{
- return anonymous_page_handler(code, address);
-}
-
diff --git a/kc/core/memory.h b/kc/core/memory.h
index 526d8ca..ea86912 100644
--- a/kc/core/memory.h
+++ b/kc/core/memory.h
@@ -1,11 +1,15 @@
#pragma once
-#include <lib.h>
-
#include <kernel/entry.h>
#include <kernel/memory/paging.h>
#include <kernel/memory/range.h>
+#include <lib.h>
+
+#include <core/memory.h>
+
+#include "vm_tree.h"
+
typedef int (*memory_space_handler_func)(uint32_t code, void *vaddr);
enum page_map_flags
@@ -21,20 +25,53 @@ enum page_map_flags
SIZE_MASK = 0xc,
};
+enum page_alloc_flags
+{
+ PAGE_ALLOC_NONE,
+ PAGE_ALLOC_LOW,
+ PAGE_ALLOC_CONV,
+ PAGE_ALLOC_HIGH,
+ PAGE_ALLOC_ANY
+};
+
+enum vm_alloc_flags
+{
+ VM_ALLOC_ANY = 0,
+ VM_ALLOC_CACHE = 1,
+ VM_ALLOC_CORE = 2,
+ VM_ALLOC_TYPE_MASK = 3,
+
+ VM_ALLOC_IMMEDIATE = 4,
+ VM_ALLOC_ACTION_MASK = 4,
+
+ VM_ALLOC_ANONYMOUS = 8,
+ VM_ALLOC_DIRECT = 16,
+ VM_ALLOC_TRANSLATE = 24,
+ VM_ALLOC_MECHANISM_MASK = 24,
+};
+
void memory_init(void);
+void page_set_present(kc_phys_addr page);
+void page_set_allocated(kc_phys_addr page);
+void page_set_free(kc_phys_addr page);
+
void *page_map(phys_addr_t paddr, enum page_map_flags flags);
void page_unmap(void *vaddr);
-phys_addr_t page_alloc(void);
+phys_addr_t page_alloc(enum page_alloc_flags flags);
void page_free(phys_addr_t paddr);
void *heap_alloc(size_t size);
void heap_free(void *block);
-void *vm_alloc(size_t size);
+void *vm_alloc(size_t size, enum vm_alloc_flags flags);
void vm_free(void *block);
void *memory_alloc(size_t size);
void memory_free(void *block);
+struct vm_tree *vm_get_tree(void);
+
+int anonymous_page_handler(struct vm_tree_node *, uint32_t, void *);
+
diff --git a/kc/core/memory/memory.c b/kc/core/memory/memory.c
new file mode 100644
index 0000000..1a33629
--- /dev/null
+++ b/kc/core/memory/memory.c
@@ -0,0 +1,628 @@
+/* kernel virtual space guarantees
+ * the loader must set up the address space as follows
+ * 1. kernel virtual space is 2GiB in size on 2GiB alignment.
+ * 2. the very top of address space must have a single self-mapped
+ * that manages the top 2MiB of space.
+ * 3. that top 2MiB of space contains a bump-allocated buffer of some size
+ * recorded in the boot data structures
+ */
+
+#include "page_early.h"
+#include "page_stack.h"
+
+#include "memory.h"
+#include "kprint.h"
+#include "panic.h"
+#include "vm_object.h"
+#include "cpu/mmu.h"
+
+#include <stdint.h>
+
+#include <kc.h>
+#include <core/memory.h>
+
+#define align_next(x, a) (x + a - 1) & ~(a - 1)
+
+static void *temp_page_map(kc_phys_addr paddr, enum page_map_flags flags);
+static void temp_page_unmap(void *address);
+
+static void *page_map_at(
+ void *vaddr,
+ phys_addr_t paddr,
+ enum page_map_flags flags);
+
+enum vm_core_state_items
+{
+ KERNEL_VM_STATE,
+ HEAP_VM_STATE,
+ STACK_VM_STATE,
+ TEMPS_VM_STATE
+};
+
+struct vm_core_static_state
+{
+ struct vm_tree_node node;
+ struct vm_object *object;
+};
+
+static struct vm_core_state
+{
+ struct vm_tree tree;
+ struct vm_object global_null;
+ struct vm_object global_anonymous;
+ struct vm_object global_direct;
+ struct vm_object global_translate;
+ struct vm_core_static_state statics[4];
+ kc_phys_addr zero_page;
+ void *first_free;
+} vm_state = {
+ {0},
+ {NULL_VM_OBJECT, NULL},
+ {ANONYMOUS_VM_OBJECT, anonymous_page_handler},
+ {DIRECT_VM_OBJECT, NULL},
+ {TRANSLATION_VM_OBJECT, NULL},
+ {
+ {{0}, &vm_state.global_null},
+ {{0}, &vm_state.global_anonymous},
+ {{0}, &vm_state.global_anonymous},
+ {{0}, &vm_state.global_null},
+ },
+ 0,
+ NULL
+};
+
+static struct vm_temp_state
+{
+ uint64_t *table;
+ int first_free;
+}
+temp_state;
+
+struct vm_tree *vm_get_tree(void)
+{
+ return &vm_state.tree;
+}
+
+void page_init(void)
+{
+ kprintf("initializing page frame allocator\n");
+ page_early_init();
+ page_stack_init();
+}
+
+void page_init_final(void)
+{
+ kprintf("finishing page frame allocator initialization\n");
+ page_early_final();
+}
+
+
+void page_set_present(kc_phys_addr page)
+{
+ page_stack_set_present(page);
+}
+
+int page_get_present(kc_phys_addr page)
+{
+ return page_stack_get_present(page);
+}
+
+void page_set_allocated(kc_phys_addr page)
+{
+ page_stack_set_allocated(page);
+}
+
+void page_set_free(kc_phys_addr page)
+{
+ page_stack_set_free(page);
+}
+
+kc_phys_addr page_alloc(enum page_alloc_flags type)
+{
+ kc_phys_addr paddr = 0;
+ if ((paddr = page_stack_alloc(type)) > 0)
+ {
+ return paddr;
+ }
+ else
+ {
+ return page_early_alloc(type);
+ }
+}
+
+void page_free(kc_phys_addr page)
+{
+ page_stack_free(page);
+}
+
+static void *map_tableset(void *vaddr, uint64_t *tables[4])
+{
+ uint64_t current_phys;
+ uint64_t *current_pte;
+ // pml4 is guaranteed to be present. no checks necessary.
+ //
+
+ current_phys = page_address(mmu_get_map(), 1);
+ tables[3] = temp_page_map(current_phys, CONTENT_RWDATA);
+ int n = 3;
+
+ while (n)
+ {
+ if (tables[n])
+ {
+ current_pte = &tables[n][pte_index(vaddr, n+1)];
+
+ if (!page_address(*current_pte, 1))
+ {
+ current_phys = page_alloc(PAGE_ALLOC_CONV);
+ if (current_phys)
+ {
+ tables[n-1] = temp_page_map(current_phys, CONTENT_RWDATA);
+ memset(tables[n-1], 0, page_size(1));
+ *current_pte = current_phys |= PAGE_NX|PAGE_WR|PAGE_PR;
+ }
+ else
+ {
+ kprintf("error: failed allocating memory for page table\n");
+ PANIC(OUT_OF_MEMORY);
+ }
+ }
+ else
+ {
+ current_phys = page_address(*current_pte, 1);
+ tables[n-1] = temp_page_map(current_phys, CONTENT_RWDATA);
+ }
+ }
+ n--;
+ }
+
+ if (tables[0])
+ {
+ current_pte = &tables[0][pte_index(vaddr, 1)];
+ }
+
+ return vaddr;
+}
+
+static void *page_map_at(
+ void *vaddr,
+ phys_addr_t paddr,
+ enum page_map_flags flags)
+{
+ // TODO: add checks to prevent attempts to map reserved addreses
+ //
+ uint64_t *mapset[4] = {NULL};
+
+ if (vaddr != map_tableset(vaddr, mapset))
+ {
+ PANIC(GENERAL_PANIC);
+ }
+
+ uint64_t entry = PAGE_PR;
+
+ switch (flags & CONTENT_MASK)
+ {
+ case CONTENT_RODATA:
+ entry |= PAGE_NX;
+ break;
+ case CONTENT_RWDATA:
+ entry |= PAGE_NX|PAGE_WR;
+ break;
+ default:
+ break;
+ }
+
+ size_t offset;
+
+ switch (flags & SIZE_MASK)
+ {
+ case SIZE_1G:
+ offset = page_offset(paddr, 3);
+ break;
+ case SIZE_2M:
+ offset = page_offset(paddr, 2);
+ break;
+ case 0:
+ case SIZE_4K:
+ offset = page_offset(paddr, 1);
+ break;
+ default:
+ vaddr = NULL;
+ }
+ if (vaddr)
+ {
+ mapset[0][pte_index(vaddr, 1)] = page_address(paddr, 1) | entry;
+ }
+
+ for (int i = 0; i < 4; i++)
+ {
+ if (mapset[i])
+ {
+ temp_page_unmap(mapset[i]);
+ }
+ }
+
+ return (char *)vaddr + offset;
+}
+
+#define VM_HEAP_SIZE 16 * page_size(2)
+
+static void *temp_page_alloc(void)
+{
+ int index = temp_state.first_free;
+
+ // do not allocate the 511th index!!
+ if (index > -1 && index < 511)
+ {
+ temp_state.first_free = temp_state.table[index] >> 1;
+ temp_state.table[index] = 0;
+ }
+ else
+ {
+ return NULL;
+ }
+
+ return (void *)-((512ULL - index) << 12);
+}
+
+static void temp_page_free(void *address)
+{
+ int index = pte_index(address, 1);
+
+ if (index > -1 && index < 511)
+ {
+ temp_state.table[index] = temp_state.first_free << 1;
+ temp_state.first_free = index;
+ }
+}
+
+static void *temp_page_map(kc_phys_addr paddr, enum page_map_flags flags)
+{
+ uint64_t entry = PAGE_PR;
+ size_t offset = 0;
+
+ switch (flags & SIZE_MASK)
+ {
+ case 0:
+ case SIZE_4K:
+ offset = page_offset(paddr, 1);
+ break;
+ default:
+ return NULL;
+ }
+
+ switch (flags & CONTENT_MASK)
+ {
+ case CONTENT_RODATA:
+ entry |= PAGE_NX;
+ break;
+ case CONTENT_RWDATA:
+ entry |= PAGE_NX|PAGE_WR;
+ break;
+ default:
+ break;
+ }
+
+ unsigned char *vaddr = temp_page_alloc();
+
+ if (vaddr)
+ {
+ vaddr += offset;
+ temp_state.table[pte_index(vaddr, 1)] = page_address(paddr, 1) | entry;
+ }
+
+ return vaddr;
+}
+
+static void temp_page_unmap(void *vaddr)
+{
+ temp_page_free(vaddr);
+ mmu_invalidate(vaddr);
+}
+
+static void vm_init(void)
+{
+ kprintf("initializing vm state\n");
+ struct kc_boot_data *boot_data = get_boot_data();
+ struct vm_core_static_state *states = &vm_state.statics[0];
+
+ // initialize the static vm node entries
+ struct
+ {
+ unsigned char *base;
+ unsigned char *head;
+ } vm_ranges[] = {
+ {&kc_image_base, &kc_image_end},
+ {&kc_image_end, &kc_image_end + VM_HEAP_SIZE},
+ {
+ boot_data->buffer.base - page_size(1) * 2,
+ boot_data->buffer.base - page_size(1)
+ },
+ {
+ boot_data->buffer.current,
+ boot_data->buffer.current + boot_data->buffer.max_size,
+ }
+ };
+
+ vm_state.first_free = &kc_image_end;
+
+ for (int i = 0; i <= TEMPS_VM_STATE; i++)
+ {
+ vmt_init_node
+ (
+ vm_get_tree(),
+ &states[i].node,
+ states[i].object,
+ (void *)vm_ranges[i].base,
+ (void *)vm_ranges[i].head
+ );
+ }
+
+ // init the temporary mappings table state
+ temp_state.table = (uint64_t *)-page_size(1);
+ temp_state.first_free = -1;
+ for (int index = 0; index < 512; index++)
+ {
+ // i love these array-based linked list stacks
+ if (!(temp_state.table[index] & PAGE_PR))
+ {
+ temp_page_free((void *)-((512ULL - index) << 12));
+ }
+ }
+
+ page_init();
+
+ vm_state.zero_page = page_alloc(PAGE_ALLOC_CONV);
+ if (!vm_state.zero_page)
+ {
+ kprintf("failed allocating for zero page\n");
+ PANIC(GENERAL_PANIC);
+ }
+
+ void *zero_temp = temp_page_map(vm_state.zero_page, CONTENT_RWDATA);
+
+ if (!zero_temp)
+ {
+ kprintf("failed mapping zero page for initialization\n");
+ PANIC(GENERAL_PANIC);
+ }
+
+ // make the zero page live up to its name;
+ memset(zero_temp, 0, page_size(1));
+ temp_page_unmap(zero_temp);
+
+ page_init_final();
+}
+
+void memory_init(void)
+{
+ vm_init();
+}
+
+void *page_map(phys_addr_t page, enum page_map_flags flags)
+{
+ void *vm_page = vm_alloc(4096, VM_ALLOC_TRANSLATE);
+ if (vm_page)
+ {
+ page_map_at(vm_page, page, flags);
+ }
+ return NULL;
+}
+
+void page_unmap(void *vaddr)
+{
+ (void)vaddr;
+}
+
+struct heap_header
+{
+ size_t size;
+ struct heap_header *next;
+};
+
+static struct heap_header *heap_root = (void *)-1ULL;
+
+void *heap_alloc(size_t size)
+{
+ // simple first-fit allocator, allocates downward from the head
+ // of the first block of sufficient size
+ // TODO: join heap blocks if there is not one of sufficient size
+ void *block = NULL;
+ struct heap_header *header;
+
+ // first attempt at allocation
+ if ((void *)-1ULL == heap_root)
+ {
+ struct vm_tree_node *heap_node = &vm_state.statics[HEAP_VM_STATE].node;
+ kprintf("initializing heap at %#lx of %zu bytes\n",
+ heap_node->key.address, heap_node->key.size);
+ heap_root = NULL;
+ header = (struct heap_header *)heap_node->key.address;
+ header->size = heap_node->key.size - sizeof(header->size);
+ heap_free((char *)header + sizeof(*header));
+ }
+ else
+ {
+ header = heap_root;
+ }
+ size = align_next(size, sizeof(*header));
+
+ while (header)
+ {
+ if (header->size > size)
+ {
+ break;
+ }
+ header = header->next;
+ }
+
+ if (header)
+ {
+ header->size -= size + sizeof(*header);
+ header = (struct heap_header *)((char *)header + header->size);
+ header->size = size;
+ header->next = NULL;
+ block = (char *)header + sizeof(*header);
+ }
+
+ return block;
+}
+
+void heap_free(void *block)
+{
+ struct heap_header *header = (void *)
+ ((char *)block - sizeof(*header));
+
+ header->next = heap_root;
+ heap_root = header;
+}
+
+void *memory_alloc(size_t size)
+{
+ // allocations larger than page-size should just get an anonymous vm_object
+ if (size < 4096)
+ {
+ return heap_alloc(size);
+ }
+ else
+ {
+ return vm_alloc(size, VM_ALLOC_ANY|VM_ALLOC_ANONYMOUS);
+ }
+}
+
+void memory_free(void *block)
+{
+ // a little complicated to implement
+ //
+ // 1. find the vm_object that owns the block
+ // a. if the vm_object is a heap, call heap_free()
+ // b. if the vm_object is an anonymous vm_area, call vm_free().
+ // c. if the object is any other kind issue a bug warning and do nothing
+ (void)block;
+}
+
+void *vm_alloc_at(void *address, size_t size, enum vm_alloc_flags flags)
+{
+ struct vm_tree_key key = {(uintptr_t)address, size};
+ struct vm_tree_node *node;
+ struct vm_object *object;
+
+ switch (flags & VM_ALLOC_MECHANISM_MASK)
+ {
+ case VM_ALLOC_ANONYMOUS:
+ object = &vm_state.global_anonymous;
+ break;
+ case VM_ALLOC_DIRECT:
+ object = &vm_state.global_direct;
+ break;
+ case VM_ALLOC_TRANSLATE:
+ object = &vm_state.global_translate;
+ break;
+ default:
+ return NULL;
+ }
+
+ if (!vmt_search_key(vm_get_tree(), &key) &&
+ (node = heap_alloc(sizeof(*node))))
+ {
+ vmt_init_node(
+ vm_get_tree(),
+ node,
+ object,
+ address,
+ (void *)((char *)address + size));
+ }
+
+ return address;
+}
+
+void *vm_alloc(size_t size, enum vm_alloc_flags flags)
+{
+ (void)flags;
+ // TODO implement a proper allocator here rather than this bump allocator.
+ char *address = vm_state.first_free;
+
+ if (address == vm_alloc_at(address, size, flags))
+ {
+ vm_state.first_free = address + size;
+ return address;
+ }
+
+ return NULL;
+}
+
+int anonymous_page_handler(
+ struct vm_tree_node *node,
+ uint32_t code,
+ void *address)
+{
+ (void)node;
+
+ if (!(code & 1))
+ {
+ // map the zero page read-only to the address
+ page_map_at(
+ address,
+ vm_state.zero_page,
+ CONTENT_RODATA|SIZE_4K);
+ }
+
+ if ((code & 1) && (code & 2)) // page fault write violation on present page
+ {
+ mmu_invalidate(address);
+ kc_phys_addr paddr = page_alloc(PAGE_ALLOC_CONV);
+
+ if (!paddr)
+ {
+ kprintf("got zero from page_alloc :|\n");
+ PANIC(OUT_OF_MEMORY);
+ }
+ page_map_at(
+ address,
+ page_alloc(PAGE_ALLOC_CONV),
+ CONTENT_RWDATA|SIZE_4K);
+ // NULL out the whole page
+ // TODO: thread to clean dirty pages.
+ memset((void *)page_address(address, 1), 0, page_size(1));
+ }
+
+ return 0;
+}
+
+int page_fault_handler(uint8_t vector, uint32_t code)
+{
+ (void)vector;
+
+ void *address;
+ __asm__ volatile ("movq %%cr2, %0" : "=r"(address));
+
+ struct vm_tree_key key = {(uintptr_t)address, sizeof(uint64_t)};
+ struct vm_tree_node *node = vmt_search_key(vm_get_tree(), &key);
+
+ if (!node)
+ {
+ kprintf("error: page fault in unmanaged address %#lx\n",
+ address);
+ PANIC(UNHANDLED_FAULT);
+ }
+
+ if (!node->object->handler)
+ {
+ kprintf("error: vm object at %p has no fault handler\n");
+ PANIC(UNHANDLED_FAULT);
+ }
+
+ return node->object->handler(node, code, address);
+}
+
+int general_protection_handler(uint8_t vector, uint32_t code)
+{
+ //TODO: implement #gp handler
+ (void)vector;
+ (void)code;
+
+ kputs("general protection violation\n");
+ PANIC(UNHANDLED_FAULT);
+ return 0;
+}
+
diff --git a/kc/core/memory/page_early.c b/kc/core/memory/page_early.c
new file mode 100644
index 0000000..7f1d0eb
--- /dev/null
+++ b/kc/core/memory/page_early.c
@@ -0,0 +1,95 @@
+#include "page_early.h"
+#include "kprint.h"
+#include "panic.h"
+
+static struct page_early_state
+{
+ struct memory_range *first;
+ struct memory_range *current;
+ struct memory_range *last;
+}
+early_state;
+
+void page_early_init(void)
+{
+ kprintf("initializing early page frame allocator\n");
+ struct kc_boot_data *boot_data = get_boot_data();
+
+ early_state.first = &boot_data->memory.entries[0];
+ early_state.last = &boot_data->memory.entries[boot_data->memory.count];
+ early_state.current = early_state.first;
+}
+
+void page_early_final(void)
+{
+ if (early_state.first)
+ {
+ kprintf("finalizing early page allocator\n");
+ for (struct memory_range *current = early_state.first;
+ current < early_state.last;
+ current++)
+ {
+ while (current->size >= page_size(1))
+ {
+ current->size -= page_size(1);
+
+ enum memory_range_type type = current->type;
+ kc_phys_addr page = current->base + current->size;
+ // all pages are gonna be set allocated first
+ // to initialize the tracking structure at the other side
+ // and make setting the page free as simple as
+ // calling page_free();
+ page_set_allocated(page);
+
+ switch (type)
+ {
+ case RESERVED_MEMORY:
+ case SYSTEM_MEMORY:
+ page_set_present(page);
+ break;
+ case AVAILABLE_MEMORY:
+ page_set_present(page);
+ page_free(page);
+ break;
+ case FIRMWARE_MEMORY:
+ case MMIO_MEMORY:
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ early_state = (struct page_early_state){NULL, NULL, NULL};
+ }
+}
+
+kc_phys_addr page_early_alloc(enum page_alloc_flags type)
+{
+ // TODO: support low/conv/high allocations in early_alloc.
+ // currently we only have conventional allocations enforced
+ // by the conditions of the scanning loop
+ (void)type;
+
+ while(early_state.current)
+ {
+ if ((early_state.current->type == AVAILABLE_MEMORY) &&
+ (early_state.current->base > 0x10000) &&
+ (early_state.current->size > page_size(1)))
+ {
+ early_state.current->size -= page_size(1);
+ return early_state.current->base + early_state.current->size;
+ }
+
+ if (early_state.current == early_state.last)
+ {
+ early_state.current = NULL;
+ break;
+ }
+ early_state.current++;
+ }
+
+ kprintf("error: early allocator has run out of memory\n");
+ PANIC(OUT_OF_MEMORY);
+}
+
diff --git a/kc/core/memory/page_early.h b/kc/core/memory/page_early.h
new file mode 100644
index 0000000..3cd5b4e
--- /dev/null
+++ b/kc/core/memory/page_early.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "memory.h"
+
+void page_early_init(void);
+void page_early_final(void);
+kc_phys_addr page_early_alloc(enum page_alloc_flags type);
+
diff --git a/kc/core/memory/page_stack.c b/kc/core/memory/page_stack.c
new file mode 100644
index 0000000..92c5cff
--- /dev/null
+++ b/kc/core/memory/page_stack.c
@@ -0,0 +1,215 @@
+#include "page_stack.h"
+#include "vm_tree.h"
+#include "vm_object.h"
+
+#include <kc.h>
+
+#define PAGE_STACK_CACHE_SIZE (1ULL << 32)
+#define page_stack_index(x) (x / page_size(1))
+#define page_stack_address(x) (x * page_size(1))
+
+struct page
+{
+ uint32_t present: 1; // a physical page is at this location
+ uint32_t allocated: 1; // this physical page has been taken
+ int32_t next_refs; // allocated = 0: the index of the next page in the list
+ // allocated = 1: the number of references this page has
+};
+
+static struct page_stack_state
+{
+ struct vm_tree_node node;
+ struct vm_object object;
+ struct page *stack;
+ int32_t free_count[3];
+ int32_t total_count[3];
+ int32_t first_free[3];
+}
+stack_state = {
+ {0},
+ {ANONYMOUS_VM_OBJECT, anonymous_page_handler},
+ NULL,
+ {0,0,0},
+ {0,0,0},
+ {-1,-1,-1}
+};
+
+static enum page_alloc_flags stack_type(kc_phys_addr page);
+static void stack_push(kc_phys_addr page);
+static kc_phys_addr stack_pop(enum page_alloc_flags type);
+
+void page_stack_init(void)
+{
+ vmt_init_node(
+ vm_get_tree(),
+ &stack_state.node,
+ &stack_state.object,
+ &kc_image_base - PAGE_STACK_CACHE_SIZE,
+ &kc_image_base);
+
+ stack_state.stack = (struct page *)stack_state.node.key.address;
+}
+
+kc_phys_addr page_stack_alloc(enum page_alloc_flags type)
+{
+ kc_phys_addr page = stack_pop(type);
+ if (page)
+ {
+ page_stack_inc_ref(page);
+ }
+ return page;
+}
+
+void page_stack_free(kc_phys_addr page)
+{
+ // immediately release a reference
+ int referents = page_stack_dec_ref(page);
+
+ // freeing a page only makes sense for present physical pages
+ if (!page_stack_get_present(page))
+ {
+ return;
+ }
+
+ // only actually free the page if it has no more references
+ if (referents == 0)
+ {
+ page_stack_set_free(page);
+ stack_push(page);
+ }
+}
+
+int page_stack_get_present(kc_phys_addr page)
+{
+ unsigned index = page_stack_index(page);
+ return stack_state.stack[index].present;
+}
+
+void page_stack_set_present(kc_phys_addr page)
+{
+ unsigned index = page_stack_index(page);
+ stack_state.stack[index].present = 1;
+}
+
+void page_stack_set_allocated(kc_phys_addr page)
+{
+ unsigned index = page_stack_index(page);
+ stack_state.stack[index].allocated = 1;
+ stack_state.stack[index].next_refs = 1;
+}
+
+void page_stack_set_free(kc_phys_addr page)
+{
+ unsigned index = page_stack_index(page);
+ stack_state.stack[index].allocated = 0;
+ stack_state.stack[index].next_refs = -1;
+}
+
+int page_stack_inc_ref(kc_phys_addr page)
+{
+ unsigned index = page_stack_index(page);
+ // taking a reference only makes sense for an allocated page
+ if (stack_state.stack[index].allocated)
+ {
+ return ++stack_state.stack[index].next_refs;
+ }
+
+ return -1;
+}
+
+int page_stack_dec_ref(kc_phys_addr page)
+{
+ unsigned index = page_stack_index(page);
+ // releasing a reference only makes sense for an allocated page
+ if (stack_state.stack[index].allocated)
+ {
+ // releasing a reference only makes sense if the refcount is > 0
+ if (stack_state.stack[index].next_refs > 0)
+ {
+ stack_state.stack[index].next_refs--;
+ }
+ return stack_state.stack[index].next_refs;
+ }
+
+ return -1;
+}
+
+static enum page_alloc_flags stack_type(kc_phys_addr page)
+{
+ // the page stack type only makes sense for physical pages
+ if (!page_stack_get_present(page))
+ {
+ return PAGE_ALLOC_NONE;
+ }
+
+ // pages above 4GiB physical are high memory
+ if (page > -1U)
+ {
+ return PAGE_ALLOC_HIGH;
+ }
+
+ // pages below 1MiB are low memory
+ else if (page < 0x100000)
+ {
+ return PAGE_ALLOC_LOW;
+ }
+
+ // all other pages are conventional memory
+ return PAGE_ALLOC_CONV;
+}
+
+static void stack_push(kc_phys_addr page)
+{
+ enum page_alloc_flags type = stack_type(page);
+
+ // stack push only makes sense for pages in a physical stack
+ if ((type < PAGE_ALLOC_LOW) || type > PAGE_ALLOC_HIGH)
+ {
+ return;
+ }
+
+ unsigned index = page_stack_index(page);
+ stack_state.stack[index].next_refs = stack_state.first_free[type - 1];
+ stack_state.first_free[type - 1] = index;
+ stack_state.free_count[type - 1]++;
+}
+
+static kc_phys_addr stack_pop(enum page_alloc_flags type)
+{
+ int pop_stack_index = -1;
+ int pop_stack_last = -1;
+
+ // pops only make sense for pages with a stack type
+ if ((type < PAGE_ALLOC_LOW) || (type > PAGE_ALLOC_HIGH))
+ {
+ return 0;
+ }
+
+ // do allocations in a high-to-low order if we're allocating any
+ if (type == PAGE_ALLOC_ANY)
+ {
+ pop_stack_index = PAGE_ALLOC_HIGH;
+ pop_stack_last = PAGE_ALLOC_LOW;
+ }
+ else
+ {
+ pop_stack_index = type;
+ pop_stack_last = type;
+ }
+
+ for (; pop_stack_last <= pop_stack_index; --pop_stack_index)
+ {
+ if (stack_state.first_free[pop_stack_index - 1] > 0)
+ {
+ unsigned index = stack_state.first_free[pop_stack_index-1];
+ stack_state.first_free[pop_stack_index-1] =
+ stack_state.stack[index].next_refs;
+ page_stack_set_allocated(page_stack_address(index));
+ stack_state.free_count[pop_stack_index - 1]--;
+ return page_stack_address(index);
+ }
+ }
+
+ return 0;
+}
+
diff --git a/kc/core/memory/page_stack.h b/kc/core/memory/page_stack.h
new file mode 100644
index 0000000..92d7222
--- /dev/null
+++ b/kc/core/memory/page_stack.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "memory.h"
+
+void page_stack_init(void);
+
+kc_phys_addr page_stack_alloc(enum page_alloc_flags type);
+void page_stack_free(kc_phys_addr page);
+
+int page_stack_get_present(kc_phys_addr page);
+void page_stack_set_present(kc_phys_addr page);
+
+void page_stack_set_allocated(kc_phys_addr page);
+void page_stack_set_free(kc_phys_addr page);
+
+int page_stack_inc_ref(kc_phys_addr page);
+int page_stack_dec_ref(kc_phys_addr page);
+
diff --git a/kc/core/task.c b/kc/core/task.c
index f9a8fc8..e43dbe0 100644
--- a/kc/core/task.c
+++ b/kc/core/task.c
@@ -73,7 +73,7 @@ noreturn void task_init(void)
// XXX: unfuck this mess at some point
// XXX: make this also not demand-allocated or it's gonna fail
- char *kernel_rsp0 = vm_alloc(4096);
+ char *kernel_rsp0 = vm_alloc(4096, VM_ALLOC_ANY);
kernel_rsp0[1] = 0;
*get_tss_rsp0() = (uintptr_t)kernel_rsp0 + 4096;
@@ -169,7 +169,7 @@ void update_time(void)
static struct kc_thread *create_thread(void (*thread_f)(void))
{
- char *task_bottom = vm_alloc(16384);
+ char *task_bottom = vm_alloc(16384, VM_ALLOC_ANY);
struct kc_thread *thread =
(struct kc_thread *)(task_bottom + 16384 - sizeof(*thread));
diff --git a/kc/core/vm_object.h b/kc/core/vm_object.h
index d1de145..c8e93f8 100644
--- a/kc/core/vm_object.h
+++ b/kc/core/vm_object.h
@@ -1,6 +1,11 @@
#pragma once
-typedef int (*vm_object_handler_func)(uint32_t code, void *address);
+#include "vm_tree.h"
+
+typedef int (*vm_object_handler_func)(
+ struct vm_tree_node *node,
+ uint32_t code,
+ void *address);
enum vm_object_type
{
@@ -8,8 +13,6 @@ enum vm_object_type
DIRECT_VM_OBJECT, // a 1:1 physical-to-virtual mapping
TRANSLATION_VM_OBJECT, // a mapping between a physical and virtual address range
ANONYMOUS_VM_OBJECT, // a mapping that has no definite physical location
- KC_IMAGE_VM_OBJECT, // a kernel component image
- KC_HEAP_VM_OBJECT, // a kernel component heap
// TODO: more to come
};
diff --git a/kc/core/vm_tree.c b/kc/core/vm_tree.c
index 7218d90..cca32bb 100644
--- a/kc/core/vm_tree.c
+++ b/kc/core/vm_tree.c
@@ -28,10 +28,11 @@
// The full text of the CC-BY-SA 3.0 license can be found here:
// https://en.wikipedia.org/wiki/Wikipedia:Text_of_Creative_Commons_Attribution-ShareAlike_3.0_Unported_License
-#include <stddef.h>
-#include <stdint.h>
-
#include "vm_tree.h"
+#include "panic.h"
+#include "kprint.h"
+
+#include <lib.h>
#define assert(expr)
@@ -66,6 +67,52 @@ static int compare_key(struct vm_tree_key const * const k1,
return compare(k1->address, k1->size, k2->address, k2->size);
}
+void vmt_init_node(
+ struct vm_tree *tree,
+ struct vm_tree_node *node,
+ struct vm_object *object,
+ void *base,
+ void *head)
+{
+ memset(node, 0, sizeof(*node));
+ node->key =
+ (struct vm_tree_key)
+ {
+ (uintptr_t)base,
+ (uintptr_t)head - (uintptr_t)base
+ };
+
+ struct vm_tree_node *ek = NULL;
+ if (!(ek = vmt_search_key(tree, &node->key)))
+ {
+ struct vm_tree_node *p = vmn_predecessor_key(
+ tree->root,
+ &node->key);
+ if (!p)
+ {
+ // the tree root should be in place of a missing predecessor
+ p = tree->root;
+ }
+ vmt_insert(
+ tree,
+ node,
+ p,
+ vmn_child_direction(node, p));
+ node->object = object;
+ }
+ else
+ {
+ kprintf("fatal: attempt to insert overlapping vm node\n"
+ "node 1: %p: %p @ %zu bytes\n"
+ "node 2: %p: %p @ %zu bytes\n",
+ node->key.address, node->key.size,
+ ek->key.address, ek->key.size);
+
+ PANIC(GENERAL_PANIC);
+ }
+
+}
+
static struct vm_tree_node* RotateDirRoot(
struct vm_tree* T, // red–black tree
struct vm_tree_node* P, // root of subtree (may be the root of T)
@@ -236,7 +283,7 @@ enum vm_tree_direction vmn_child_direction(
struct vm_tree_node *p
)
{
- if (p && compare_key(&p->key, &n->key) > 0)
+ if (p && (compare_key(&p->key, &n->key) > 0))
{
return LEFT;
}
diff --git a/kc/core/vm_tree.h b/kc/core/vm_tree.h
index b2a64e2..a1d40c4 100644
--- a/kc/core/vm_tree.h
+++ b/kc/core/vm_tree.h
@@ -30,6 +30,9 @@
// The full text of the CC-BY-SA 3.0 license can be found here:
// https://en.wikipedia.org/wiki/Wikipedia:Text_of_Creative_Commons_Attribution-ShareAlike_3.0_Unported_License
+#include <stdint.h>
+#include <stddef.h>
+
enum vm_tree_direction
{
LEFT,
@@ -77,6 +80,13 @@ enum vm_tree_direction vmn_child_direction(
struct vm_tree_node *n,
struct vm_tree_node *p);
+void vmt_init_node(
+ struct vm_tree *tree,
+ struct vm_tree_node *node,
+ struct vm_object *object,
+ void *base,
+ void *head);
+
void vmt_delete(struct vm_tree*, struct vm_tree_node*);
struct vm_tree_node *vmt_search_key(struct vm_tree *, struct vm_tree_key *);
diff --git a/kc/kc.ld b/kc/kc.ld
index dc158f3..76e096a 100644
--- a/kc/kc.ld
+++ b/kc/kc.ld
@@ -35,11 +35,11 @@ SECTIONS
.text : ALIGN(4K)
{
- PROVIDE(kc_text_begin = .);
+ PROVIDE_HIDDEN(kc_text_begin = .);
*(.text.start)
*(.text)
. = ALIGN(4K);
- PROVIDE(kc_text_end = .);
+ PROVIDE_HIDDEN(kc_text_end = .);
} =0xcc
.dynamic : ALIGN(4K)
@@ -49,7 +49,7 @@ SECTIONS
.data :
{
- PROVIDE(kc_data_begin = .);
+ PROVIDE_HIDDEN(kc_data_begin = .);
*(.rodata)
*(.data)
}
@@ -63,9 +63,12 @@ SECTIONS
.bss :
{
*(.bss)
- PROVIDE(kc_data_end = .);
+ . = ALIGN(4K);
+ PROVIDE_HIDDEN(kc_data_end = .);
}
+ PROVIDE_HIDDEN(kc_image_end = .);
+
/DISCARD/ :
{
*(.eh_frame)