Commit de1f3b4f authored by benkma's avatar benkma

Lab 08 Completed

parent 8bef8dfb
#include "lib.hh"
#include "kernel.hh"
#include "k-lock.hh"
static spinlock page_lock;
static uintptr_t next_free_pa;
static spinlock mem_lock;
//static uintptr_t next_free_pa;
const int NUMBER_OF_FRAMES = MEMSIZE_PHYSICAL / PAGESIZE; // 2MB / 4KB = 512 Frames
const int MIN_ORDER = 12; // 2^12 = 4KB
const int MAX_ORDER = 21; // 2^21 = 2MB
struct block {
bool isFree;
int order;
void* ka;
list_links link_;
static block *blockAtKernelAddress(void* ka);
static int minOrderForBlockOfSize(size_t sz);
static void split(int order);
block *buddy();
void cloalesce();
int frameNumber() {return ka2pa(ka)/PAGESIZE;};
};
block blocks[NUMBER_OF_FRAMES];
list<block, &block::link_> freeBlockList[MAX_ORDER + 1];
void test_kalloc();
//DEBUGGING
#pragma GCC push_options
#pragma GCC optimize("O0")
block *block::buddy() {
void *pBuddy = (void*)((uint64_t) ka ^ (1 << order));
return blockAtKernelAddress(pBuddy);
}
int block::minOrderForBlockOfSize(size_t sz) {
int order = msb(sz - 1);
if (order < MIN_ORDER) {
order = MIN_ORDER;
}
return order;
}
block *block::blockAtKernelAddress(void* ka) {
uint64_t pa = ka2pa(ka);
int frameNumber = pa/PAGESIZE;
return &blocks[frameNumber];
}
// init_kalloc
// Initialize stuff needed by `kalloc`. Called from `init_hardware`,
// after `physical_ranges` is initialized.
// 1-3: 3 * 4 = 4K = 12K
// 9-195: 151 * 4K = 682K
// 358-511: 154 * 4 = 4K = 616 K
void init_kalloc() {
// do nothing for now
auto irqs = mem_lock.lock();
for(int frameNumber = 0; frameNumber < NUMBER_OF_FRAMES; ++frameNumber){
void *pa =(void*) (frameNumber * PAGESIZE);
auto range = physical_ranges.find((uintptr_t) pa);
bool isFree = range->type() == mem_available;
block *pBlock = &blocks[frameNumber];
pBlock->isFree = isFree;
pBlock->order = MIN_ORDER;
pBlock->ka = pa2kptr<void*>((uintptr_t) pa);
//log_printf("frame %d is %s\n", frameNumber, (isFree ? "Free" : "Not Free"));
if (isFree) {
freeBlockList[MIN_ORDER].push_back(pBlock);
pBlock->cloalesce();
}
}
mem_lock.unlock(irqs);
test_kalloc();
}
......@@ -26,50 +94,122 @@ void init_kalloc() {
//
// The handout code does not free memory and allocates memory in units
// of pages.
#pragma GCC push_options
#pragma GCC optimize ("O0")
void* kalloc(size_t sz) {
if (sz == 0 || sz > PAGESIZE) {
if (sz == 0) {
return nullptr;
}
int order = block::minOrderForBlockOfSize(sz);
if(order > MAX_ORDER) {
return nullptr;
}
auto irqs = page_lock.lock();
auto irqs = mem_lock.lock();
void* ptr = nullptr;
// skip over reserved and kernel memory
auto range = physical_ranges.find(next_free_pa);
while (range != physical_ranges.end()) {
if (range->type() == mem_available) {
// use this page
ptr = pa2kptr<void*>(next_free_pa);
next_free_pa += PAGESIZE;
break;
} else {
// move to next range
next_free_pa = range->last();
++range;
}
if(freeBlockList[order].empty()){
block::split(order + 1);
}
block *pBlock = freeBlockList[order].pop_front();
page_lock.unlock(irqs);
if(pBlock) {
ptr = pBlock->ka;
pBlock->isFree = false;
assert(pBlock->order == order);
}
mem_lock.unlock(irqs);
if (ptr) {
// tell sanitizers the allocated page is accessible
asan_mark_memory(ka2pa(ptr), PAGESIZE, false);
// initialize to `int3`
memset(ptr, 0xCC, PAGESIZE);
log_printf("kalloc of order %d returning frame %d\n", pBlock->order, pBlock->frameNumber());
} else {
log_printf("kalloc of order %d failled\n", order);
}
return ptr;
}
//split a block at a particular order
void block::split(int order) {
//assert the passed-in parameter in legitimate
assert(order > MIN_ORDER && order <= MAX_ORDER + 1);
//if we are beyond the top, then there is nothing to split
if( order > MAX_ORDER ) {
return;
}
// if no block at this order, then try to split at a higher order (recursion)
if(freeBlockList[order].empty()) {
block::split(order + 1);
}
// check again to see if we can get a free block
// if not, fail
if(freeBlockList[order].empty()){
return;
}
block *fBlock = freeBlockList[order].pop_front();
// asssert that the data structure are proper
assert(fBlock->isFree && fBlock->order == order);
// reduce the order of the block obtained and get its buddy
--fBlock->order;
block *pBuddy = fBlock->buddy();
// fix up the buddy
pBuddy->order = fBlock->order;
pBuddy->isFree = true;
// add to the free block list
freeBlockList[fBlock->order].push_front(fBlock);
freeBlockList[pBuddy->order].push_front(pBuddy);
}
#pragma GCC pop_options
// kfree(ptr)
// Free a pointer previously returned by `kalloc`. Does nothing if
// `ptr == nullptr`.
void kfree(void* ptr) {
if (ptr) {
// tell sanitizers the freed page is inaccessible
asan_mark_memory(ka2pa(ptr), PAGESIZE, true);
if(!ptr){
return;
}
block *pBlock = block::blockAtKernelAddress(ptr);
assert(!(pBlock->isFree));
assert(pBlock->ka == ptr);
auto irqs = mem_lock.lock();
pBlock->isFree = true;
freeBlockList[pBlock->order].push_front(pBlock);
pBlock->cloalesce();
mem_lock.unlock(irqs);
}
void block::cloalesce() {
//log_printf("Cloalesce() frame %d(%d) \n", frameNumber(), order);
if (order == MAX_ORDER) {
return;
}
block *pBuddy = this->buddy();
if(!pBuddy->isFree || pBuddy->order != order){
return;
}
freeBlockList[order].erase(this);
freeBlockList[order].erase(pBuddy);
++this->order;
++pBuddy->order;
if (ka < pBuddy->ka){
freeBlockList[this->order].push_front(this);
cloalesce();
} else {
freeBlockList[pBuddy->order].push_front(pBuddy);
pBuddy->cloalesce();
}
log_printf("kfree not implemented yet\n");
}
......@@ -112,3 +252,41 @@ void operator delete[](void* ptr, std::align_val_t) noexcept {
void operator delete[](void* ptr, size_t, std::align_val_t) noexcept {
kfree(ptr);
}
void test_kalloc() {
void *p1;
void *p2;
p1 = kalloc(PAGESIZE);
assert(p1);
kfree(p1);
p2 = kalloc(PAGESIZE);
assert(p2);
kfree(p2);
assert(p1 == p2);
p1 = kalloc(PAGESIZE);
p2 = kalloc(PAGESIZE);
assert(p1);
assert(p2);
kfree(p1);
kfree(p2);
assert(p1 != p2);
p1 = kalloc(1 << 22); // 4 MB
assert(!p1);
p1 = kalloc(1 << 21); // 2 MB
assert(!p1);
p1 = kalloc(1 << 20); // 1 MB
assert(!p1);
p1 = kalloc(1 << 19); // 512 KB
p2 = kalloc(1 << 19);
assert(p1);
assert(!p2);
p2 = kalloc(1 << 18); //256 KB
assert(p2);
kfree(p2);
kfree(p1);
}
#pragma GCC pop_options
......@@ -233,7 +233,8 @@ uintptr_t proc::syscall(regstate* regs) {
}
return bufcache::get().sync(drop);
}
case SYSCALL_MAP_CONSOLE:
return syscall_map_console(regs);
default:
// no such system call
log_printf("%d: no such system call %u\n", id_, regs->reg_rax);
......@@ -241,7 +242,19 @@ uintptr_t proc::syscall(regstate* regs) {
}
}
// Debugging Information
#pragma GCC push_options
#pragma GCC optimize("O0")
int proc::syscall_map_console(regstate* regs) {
uintptr_t addr = regs->reg_rdi;
if(addr % PAGESIZE || addr > VA_LOWMAX) {
return E_INVAL;
}
vmiter(this, addr).map(CONSOLE_ADDR, PTE_PWU);
return 0;
}
#pragma GCC pop_options
// proc::syscall_fork(regs)
// Handle fork system call.
......
......@@ -74,6 +74,7 @@ struct __attribute__((aligned(4096))) proc {
private:
static int load_segment(const elf_program& ph, proc_loader& ld);
int syscall_map_console(regstate* reg);
};
#define NPROC 16
......
......@@ -270,7 +270,7 @@ struct bitset_view {
// Add new system calls here.
// Your numbers should be >=128 to avoid conflicts.
#define SYSCALL_MAP_CONSOLE 128
// System call error return values
......
#include "u-lib.hh"
#define ALLOC_SLOWDOWN 24
#define ALLOC_SLOWDOWN 1 /* 24 */
extern uint8_t end[];
......@@ -11,8 +11,14 @@ uint8_t* stack_bottom;
#pragma GCC optimize ("O0")
void process_main() {
sys_kdisplay(KDISPLAY_MEMVIEWER);
//sys_kdisplay(KDISPLAY_MEMVIEWER);
int error_code = sys_map_console(console);
assert(!error_code);
console_printf(0x5000, "Hello Professor Foster,\n");
console_printf(0x5000, "We are in week four of the quarter and I'm learning a lot of\n");
console_printf(0x5000, "C++ programming in OS!\n");
console_printf(0x5000, "--Matija Benko");
// Fork three new copies. (But ignore failures.)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
......@@ -46,7 +52,7 @@ void process_main() {
}
sys_yield();
if (rand() < RAND_MAX / 32) {
sys_pause();
//sys_pause();
}
}
......
......@@ -309,6 +309,12 @@ pid_t sys_clone(int (*function)(void*), void* arg, char* stack_top);
assert(false);
}
// sys_map_console(void*)
// Map the console at the user specified address. Return 0 on success, return E_INVAL on invalid address,
inline int sys_map_console(void* addr) {
return make_syscall(SYSCALL_MAP_CONSOLE, reinterpret_cast<uintptr_t>(addr));
}
// dprintf(fd, format, ...)
// Construct a string from `format` and pass it to `sys_write(fd)`.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment