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 += -Ilib
|
||||
CFLAGS += -Ikern
|
||||
|
||||
CFLAGS += -fno-stack-protector # Prevents code that needs libc / runtime support
|
||||
CFLAGS += -MD # Generate header dependency files (.d)
|
||||
|
@ -27,7 +28,7 @@ CFLAGS += -fno-omit-frame-pointer # More reliable backtraces in GDB
|
|||
|
||||
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 $@
|
||||
@$(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