kalloc.[ch] from xv6, memory.[ch] containing memory probing algorithm and constants
This commit is contained in:
parent
58ed873401
commit
bd7959cc6c
5 changed files with 155 additions and 1 deletions
3
Makefile
3
Makefile
|
@ -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
75
kern/kalloc.c
Normal 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
33
kern/kalloc.h
Normal 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
29
lib/memory.c
Normal 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
16
lib/memory.h
Normal 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
|
Loading…
Add table
Reference in a new issue