Function comments (v1)

This commit is contained in:
2026-03-13 12:51:29 +01:00
parent 8e2a612d88
commit 8026c33639
25 changed files with 560 additions and 48 deletions

View File

@@ -14,11 +14,20 @@
uint64_t gdt_entries[NUM_GDT_ENTRIES];
struct GDTR gdtr;
/*
* gdt_load - Loads Global Descriptor Table
*/
static void gdt_load()
{
asm("lgdt %0" : : "m"(gdtr));
}
/*
* gdt_flush - Flushes the Global Descriptor Table
*
* This function loads new Segment Selectors to make
* the GDT changes take effect
*/
static void gdt_flush()
{
// Here, 0x8 is the kernel code selector
@@ -42,6 +51,15 @@ static void gdt_flush()
);
}
/*
* gdt_init - Global Descriptor Table initialization
*
* This function loads a new GDT in the CPU.
* It contains a null descriptor, kernel code and data
* segments, and user code and data segments.
* However, we do not use segmentation to manage memory on
* 64-bit x86, as it's deprecated. Instead, we use paging.
*/
void gdt_init()
{
// Null descriptor (required)

View File

@@ -23,6 +23,15 @@ static uintptr_t end;
// Kernel root table (level 4)
extern uint64_t *kernel_pml4;
/*
* kheap_init - Kernel heap initialization
*
* This function physically allocates and maps enough pages
* of memory for KHEAP_SIZE, which is defined in config.h.
*
* It then creates one big heap block, which will be the
* base for a linked list.
*/
void kheap_init()
{
kheap_start = ALIGN_UP(kernel_virt_base + KERNEL_SIZE, PAGE_SIZE);
@@ -53,6 +62,18 @@ void kheap_init()
DEBUG("Kernel heap initialized, head=0x%p, size=%u bytes", head, head->size);
}
/*
* kmalloc - Kernel memory allocation
* @size: number of bytes to allocate
*
* Looks for a big enough free block and marks it
* as taken. Each block of memory is preceded by
* the linked list header.
*
* Return:
* <ptr> - Pointer to at least <size> bytes of usable memory
* NULL - No more memory, or no valid size given
*/
void* kmalloc(size_t size)
{
// No size, no memory allocated!
@@ -92,6 +113,14 @@ void* kmalloc(size_t size)
return NULL;
}
/*
* kfree - Kernel memory freeing
* @ptr: pointer to memory region to free
*
* Marks the memory block beginning at <ptr>
* as free. Also merges adjacent free blocks
* to lessen fragmentation.
*/
void kfree(void* ptr)
{
// Nothing to free
@@ -113,8 +142,17 @@ void kfree(void* ptr)
}
}
// Should alloc enough for a stack (at least 64kb) to be used for a process.
// Should return a pointer to top of the stack (as stack grows DOWNWARDS)
/*
* kalloc_stack - Stack memory allocation
*
* Allocates a memory region of at least PROCESS_STACK_SIZE,
* to be used as a stack for a process. The pointer returned
* points to the end of the region, as the stack grows downwards.
*
* Return:
* <ptr> - Pointer to a region after at least PROCESS_STACK_SIZE bytes of usable memory
* NULL - No more memory
*/
void* kalloc_stack()
{
uint8_t* ptr = kmalloc(PROCESS_STACK_SIZE); // As it's out of kmalloc, stack is already mapped into kernel space

View File

@@ -16,6 +16,19 @@
// We use the "restrict" keyword on pointers so that the compiler knows it can
// do more optimization on them (and as it's a much used function, it's good to
// be able to do that)
/*
* memcpy - Copy memory from one place to another
* @dest: pointer to the destination region
* @src: pointer to the source region
* @n: amount of bytes to copy
*
* This function copies n bytes of memory from
* src to dest.
*
* Return:
* <dest> - Pointer to destination region
*/
void* memcpy(void* restrict dest, const void* restrict src, size_t n)
{
uint8_t* restrict pdest = (uint8_t* restrict)dest;
@@ -28,6 +41,18 @@ void* memcpy(void* restrict dest, const void* restrict src, size_t n)
return dest;
}
/*
* memset - Sets a memory region to given byte
* @s: pointer to memory region
* @c: byte to be written
* @n: amount of bytes to write
*
* This function writes n times the byte c
* to the memory region pointed to by s.
*
* Return:
* <s> - Pointer to memory region
*/
void* memset(void* s, int c, size_t n)
{
uint8_t* p = (uint8_t*)s;
@@ -39,6 +64,18 @@ void* memset(void* s, int c, size_t n)
return s;
}
/*
* memmove - Move memory from one place to another
* @dest: pointer to the destination region
* @src: pointer to the source region
* @n: amount of bytes to move
*
* This function moves n bytes of memory from
* src to dest.
*
* Return:
* <dest> - Pointer to destination region
*/
void* memmove(void *dest, const void* src, size_t n)
{
uint8_t* pdest = (uint8_t*)dest;
@@ -56,6 +93,20 @@ void* memmove(void *dest, const void* src, size_t n)
return dest;
}
/*
* memcmp - Compare two memory regions
* @s1: pointer to the first region
* @s2: pointer to the second region
* @n: amount of bytes to compare
*
* This function compares n bytes of memory
* bewteen regions pointed to by s1 and s2.
*
* Return:
* %0 - if s1 and s2 are equal
* %-1 - if s1 is smaller than s2
* %1 - if s1 is greater than s2
*/
int memcmp(const void* s1, const void* s2, size_t n)
{
const uint8_t* p1 = (const uint8_t*)s1;

View File

@@ -24,17 +24,41 @@ If we use 1GB huge pages: PML4 -> PDPT -> 1gb pages
4KB (regular size): PML4 -> PDPT -> PD -> PT -> 4kb pages
*/
/*
* load_cr3 - Load a new value into the CR3 register
* @value: the value to load
*
* This function is used to load the physical address
* of the root page table (PML4), to switch the paging
* structures the CPU sees and uses.
*/
void load_cr3(uint64_t value) {
asm volatile ("mov %0, %%cr3" :: "r"(value) : "memory");
}
// To flush TLB
/*
* invlpg - Invalidates a Translation Lookaside Buffer entry
* @addr: page memory address
*
* This function is used to flush at least the TLB entrie(s)
* for the page that contains the <addr> address.
*/
static inline void invlpg(void *addr)
{
asm volatile("invlpg (%0)" :: "r"(addr) : "memory");
}
// Allocates a 512-entry 64bit page table/directory/whatever (zeroed)
/*
* alloc_page_table - Page table allocation
*
* This function allocates enough memory for a 512-entry
* 64-bit page table, for any level (PML4/3/2).
*
* Memory allocated here is zeroed.
*
* Return:
* <virt> - Pointer to allocated page table
*/
static uint64_t* alloc_page_table()
{
uint64_t* virt = (uint64_t*)PHYS_TO_VIRT(pmm_alloc());
@@ -49,10 +73,19 @@ static uint64_t* alloc_page_table()
__attribute__((aligned(4096)))
uint64_t *kernel_pml4;
// Map a page, taking virt and phys address. This will go through the paging structures
// beginning at the given root table, translate the virtual address in indexes in
// page table/directories, and then mapping the correct page table entry with the
// given physical address + flags
/*
* paging_map_page - Mapping a memory page
* @root_table: Address of the PML4
* @virt: Virtual address
* @phys: Physical address
* @flags: Flags to set on page
*
* This function maps the physical address <phys> to the virtual
* address <virt>, using the paging structures beginning at
* <root_table>. <flags> can be set according to the PTE_FLAGS enum.
*
* If a page table/directory entry is not present yet, it creates it.
*/
void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_t flags)
{
virt = PAGE_ALIGN_DOWN(virt);
@@ -102,6 +135,15 @@ void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_
uint64_t kernel_phys_base;
uint64_t kernel_virt_base;
/*
* paging_init - Paging initialization
* @boot_ctx: Boot context structure
*
* This function initializes new paging structures, to replace
* the ones given by the bootloader.
*
* It maps the kernel, the HHDM space, and the framebuffer.
*/
void paging_init(struct boot_context boot_ctx)
{
// We should map the kernel, GDT, IDT, stack, framebuffer.

View File

@@ -41,12 +41,15 @@ extern uint64_t hhdm_off;
// Page entry special bits
// Bits set on a parent (directory, table) fall back to their children
#define PTE_PRESENT (1ULL << 0)
#define PTE_WRITABLE (1ULL << 1)
#define PTE_USER (1ULL << 2)
#define PTE_PWT (1ULL << 3)
#define PTE_PCD (1ULL << 4)
#define PTE_HUGE (1ULL << 7)
#define PTE_NOEXEC (1ULL << 63)
enum PTE_FLAGS
{
PTE_PRESENT = (1ULL << 0),
PTE_WRITABLE = (1ULL << 1),
PTE_USER = (1ULL << 2),
PTE_PWT = (1ULL << 3),
PTE_PCD = (1ULL << 4),
PTE_HUGE = (1ULL << 7),
PTE_NOEXEC = (1ULL << 63)
};
#endif

View File

@@ -24,13 +24,16 @@ First we'll have to discover the physical memory layout,
and for that we can use a Limine request.
*/
/*
We will look for the biggest usable physical memory region
and use this for the bitmap. The reserved memory will be ignored.
*/
struct limine_memmap_entry* biggest_entry;
/*
* pmm_find_biggest_usable_region - Finding the biggest free memory region
* @memmap: Limine memory map
* @hhdm: Limine HHDM offset
*
* This function uses the memory map provided by the bootloader
* to find the single biggest free memory region we can use.
*/
static void pmm_find_biggest_usable_region(struct limine_memmap_response* memmap, struct limine_hhdm_response* hhdm)
{
// Max length of a usable memory region
@@ -62,6 +65,14 @@ uint64_t hhdm_off;
static uintptr_t g_freelist = 0;
/*
* pmm_alloc - Allocate a physical page
*
* This function allocates a single physical page (frame)
*
* Return:
* <addr> - Address for the allocated page
*/
uintptr_t pmm_alloc()
{
if (!g_freelist) {
@@ -72,12 +83,22 @@ uintptr_t pmm_alloc()
return addr;
}
/*
* pmm_free - Frees a memory page
* @addr: Address to the page
*/
void pmm_free(uintptr_t addr)
{
*(uintptr_t*) PHYS_TO_VIRT(addr) = g_freelist;
g_freelist = addr;
}
/*
* pmm_init_freelist - PMM freelist initialization
*
* This function marks the biggest memory region as
* free, so we can use it in pmm_alloc.
*/
static void pmm_init_freelist()
{
// We simply call pmm_free() on each page that is marked USABLE
@@ -93,6 +114,13 @@ static void pmm_init_freelist()
DEBUG("%u frames in freelist, available for use (%u bytes)", page_count, page_count*PAGE_SIZE);
}
/*
* pmm_init - Physical memory manager initialization
* @boot_ctx: Boot context structure
*
* This function prepares the PMM for use.
* The PMM works with a freelist.
*/
void pmm_init(struct boot_context boot_ctx)
{
hhdm_off = boot_ctx.hhdm->offset;

View File

@@ -24,6 +24,14 @@ void* vmm_pt_root = 0;
// Linked list head for virtual memory objects
struct vm_object* vm_objs = NULL;
/*
* Will have to be rewritten and expanded,
* to prepare for userspace.
* The platform-agnostic flags will be removed
* because as long as the kernel is x86 only,
* we don't need over complication.
* Plus I don't plan to port to other architectures
*/
uint64_t convert_x86_vm_flags(size_t flags)
{