kalloc.[ch] from xv6, memory.[ch] containing memory probing algorithm and constants

This commit is contained in:
Imbus 2025-06-26 13:27:35 +02:00
parent 58ed873401
commit bd7959cc6c
5 changed files with 155 additions and 1 deletions

View file

@ -18,6 +18,7 @@ CFLAGS += -ffreestanding -fno-common -nostdlib -mno-relax
CFLAGS += -I. CFLAGS += -I.
CFLAGS += -Ilib CFLAGS += -Ilib
CFLAGS += -Ikern
CFLAGS += -fno-stack-protector # Prevents code that needs libc / runtime support CFLAGS += -fno-stack-protector # Prevents code that needs libc / runtime support
CFLAGS += -MD # Generate header dependency files (.d) CFLAGS += -MD # Generate header dependency files (.d)
@ -27,7 +28,7 @@ CFLAGS += -fno-omit-frame-pointer # More reliable backtraces in GDB
all: kernel.elf all: kernel.elf
kernel.elf: entry.o start.o lib/string.o lib/proc.o lib/spinlock.o lib/proc.o lib/uart.o lib/panic.o kernel.elf: entry.o start.o lib/string.o lib/proc.o lib/spinlock.o lib/proc.o lib/uart.o lib/panic.o kern/kalloc.o lib/memory.o
@echo LD $@ @echo LD $@
@$(LD) $(LDFLAGS) -o $@ $^ @$(LD) $(LDFLAGS) -o $@ $^

75
kern/kalloc.c Normal file
View file

@ -0,0 +1,75 @@
#include <kalloc.h>
#include <memory.h>
#include <panic.h>
#include <riscv.h>
#include <spinlock.h>
#include <string.h>
#include <types.h>
// Physical memory allocator, for user processes,
// kernel stacks, page-table pages,
// and pipe buffers. Allocates whole 4096-byte pages.
/** Free list of physical pages. */
void freerange(void *physaddr_start, void *physaddr_end);
/** First address after kernel. Provided kernel.ld */
extern char kernel_end[];
/** A run is a node in the free list. */
struct Run {
struct Run *next;
};
/** Kernel memory allocator. */
struct {
struct Spinlock lock;
struct Run *freelist;
} kmem;
void kalloc_init() {
initlock(&kmem.lock, "kmem");
freerange(kernel_end, (void *)PHYSTOP);
}
void freerange(void *physaddr_start, void *physaddr_end) {
char *p;
p = (char *)PGROUNDUP((u64)physaddr_start);
for (; p + PGSIZE <= (char *)physaddr_end; p += PGSIZE) kfree(p);
}
void kfree(void *pa) {
struct Run *r;
// Assert that page is a ligned to a page boundary and that its correctly
// sized
if (((u64)pa % PGSIZE) != 0 || (char *)pa < kernel_end ||
(u64)pa >= PHYSTOP)
panic("kfree");
// Fill with junk to catch dangling refs.
memset(pa, 1, PGSIZE);
r = (struct Run *)pa;
acquire(&kmem.lock);
r->next = kmem.freelist;
kmem.freelist = r;
release(&kmem.lock);
}
void *kalloc(void) {
struct Run *r;
acquire(&kmem.lock);
r = kmem.freelist;
if (r)
kmem.freelist = r->next;
release(&kmem.lock);
if (r)
memset((char *)r, 5, PGSIZE); // fill with junk
return (void *)r;
}

33
kern/kalloc.h Normal file
View file

@ -0,0 +1,33 @@
#ifndef KALLOC_KERNEL_H
#define KALLOC_KERNEL_H
/**
* Kernel memory allocator
*
* Allocate one 4096-byte page of physical memory.
* Returns a pointer that the kernel can use.
* Returns 0 if the memory cannot be allocated.
* See: kalloc.c
*/
void *kalloc(void);
/**
* Kernel memory allocator
*
* Free the page of physical memory pointed at by pa,
* which normally should have been returned by a
* call to kalloc(). (The exception is when
* initializing the allocator; see kinit above.)
* See: kalloc.c
*/
void kfree(void *);
/**
* Initialize kernel memory allocator
*
* Called by main() on the way to the kernel's main loop.
* See: kalloc.c
*/
void kalloc_init(void);
#endif

29
lib/memory.c Normal file
View file

@ -0,0 +1,29 @@
#include <memory.h>
#include <string.h>
#include <uart.h>
#define MAX_PROBE_SIZE (256 * 1024 * 1024) // Probe up to 256 MiB max
#define PROBE_STEP 0x1000 // Probe every 4 KiB page
size_t probe_memory(void) {
volatile u32 *addr;
u32 test_pattern = 0xA5A5A5A5;
size_t detected = 0;
for (size_t offset = 4096 * 16; offset < MAX_PROBE_SIZE;
offset += PROBE_STEP) {
addr = (volatile u32 *)(KERNBASE + offset);
u32 old = *addr;
*addr = test_pattern;
if (*addr != test_pattern) {
break; // Memory not readable/writable here, stop probing
}
*addr = old; // restore original data
detected = offset + PROBE_STEP;
}
return detected;
}

16
lib/memory.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef MEMORY_KERNEL_H
#define MEMORY_KERNEL_H
#include <types.h>
/* These are hardcoded for now */
#define KERNBASE 0x80000000L
#define PHYSTOP (KERNBASE + 128 * 1024 * 1024)
/**
* Returns size in bytes of detected RAM In qemu, it requires a trap handler to
* handle the interrupt when accessing unavailable memory.
*/
size_t probe_memory(void);
#endif