Assignment of SOS operating system The file lmemman.c has one incomplete functio
ID: 3791817 • Letter: A
Question
Assignment of SOS operating system
The file lmemman.c has one incomplete function with TODO blocks. Finish these blocks to complete the assignment.
bool init_logical_memory(PCB *p, uint32_t code_size);
This function initializes a process’ logical address space. This involves allocating frames for the process code, stacks, page directory and page tables, and then setting them up. The PCB is passed in the argument p, and the number of bytes in the process’ code and data is in the argument code_size. The function should return TRUE if all goes well; otherwise FALSE. Any frames allocated in the function must be freed if FALSE is returned.
This should be able to work under SOS operating system.
Here is the lmenman.c file:
////////////////////////////////////////////////////////
// The NAIVE Logical Memory Manager
//
// Divides memory into 4KB pages and allocates from them
#include "kernel_only.h"
// kernel page directory will be placed at frame 257
PDE *k_page_directory = (PDE *)(0xC0101000);
// page table entries for the 768th page directory entry will be placed
// at frame 258; 768th entry corresponds to virtual address range
// 3GB to 3GB+4MB-1 (0xC0000000 to 0xC03FFFFF)
PTE *pages_768 = (PTE *)(0xC0102000);
/*** Initialize logical memory for a process ***/
// Allocates physical memory and sets up page tables;
// we need to allocate memory to hold the program code and
// data, the stack, the page directory, and the required
// page tables
// called by runprogram.c; this function does not load the
// program from disk to memory (done in scheduler.c)
bool init_logical_memory(PCB *p, uint32_t code_size) {
// TODO: see background material on what this function should
// do. High-level objectives are:
// 1) calculate the number of frames necessary for program code,
// user-mode stack and kernel-mode stack
// 2) allocate frames for above
// 3) determine beginning physical address of program code,
// user-mode stack and kernel-mode stack
// 4) calculate the number of frames necessary for page directory
// and page tables
// 5) allocate frames for above
// 6) set up page directory and page tables
// 7) set mem struct in PCB: start_code, end_code, start_stack,
// start_brk, brk, and page_directory
// Return value: TRUE if everything goes well; FALSE if allocation
// of frames failed (you should dealloc any frames that may
// have already been allocated before returning)
// TODO: uncomment following line when you start working in
// this function
return FALSE;
}
/*** Initialize kernel's page directory and table ***/
void init_kernel_pages(void) {
uint32_t i;
// set up kernel page directory (users cannot touch this)
for (i=0; i<1024; i++) k_page_directory[i] = 0;
k_page_directory[768] = ((uint32_t)pages_768-KERNEL_BASE) | PDE_PRESENT | PDE_READ_WRITE;
// map virtual (0xC0000000--0xC03FFFFF) to physical (0--0x3FFFFF)
for (i=0; i<1024; i++)
pages_768[i] = (i*4096) | PTE_PRESENT | PTE_READ_WRITE | PTE_GLOBAL;
// load page directory
load_CR3((uint32_t)k_page_directory-KERNEL_BASE);
}
/*** Load CR3 with page directory ***/
void load_CR3(uint32_t pd) {
asm volatile ("movl %0, %%eax ": :"m"(pd));
asm volatile ("movl %eax, %cr3 ");
}
/*** Allocate logical memory for kernel***/
// Allocates pages for kernel and returns logical address of allocated memory
// Note: Kernel uses 0xC0000000 to 0xC0400000 for now
void *alloc_kernel_pages(uint32_t n_pages) {
uint32_t p_alloc_base; // physical address of allocated memory
uint32_t l_alloc_base; // logical address of allocated memory
int i;
p_alloc_base = (uint32_t)alloc_frames(n_pages, KERNEL_ALLOC);
if (p_alloc_base==NULL) return NULL;
// Note: page table update is not necessary since first 4MB is already
// mapped and kernel allocation is always from first 4MB
// adding KERNEL_BASE converts address to logical when allocation
// of kernel is from the first 4MB (see alloc_frames)
l_alloc_base = p_alloc_base + KERNEL_BASE;
// fill-zero the memory area
zero_out_pages((void *)l_alloc_base, n_pages);
return (void *)l_alloc_base;
}
/*** Deallocate one page ***/
// Deallocates the page corresponding to virtual address
// <loc>; p is the virtual address of page directory
void dealloc_page(void *loc, PDE *p) {
uint32_t pd_entry = (uint32_t)loc >> 22; // top 10 bits
uint32_t pt_entry = ((uint32_t)loc >> 12) & 0x000003FF; // next top 10 bits
int i;
// obtain page table corresponding to page directory entry
PTE *pt = (PTE *)(p[pd_entry] & 0xFFFFF000);
pt = (PTE *)((uint32_t)pt + KERNEL_BASE); // converting to virtual address
// deallocate the frame
dealloc_frames((void *)(pt[pt_entry] & 0xFFFFF000), 1);
// if user space address, then mark page table entry as not present
if ((uint32_t)loc < KERNEL_BASE)
pt[pt_entry] = 0;
}
/*** Deallocate all pages ***/
// Traverses the page directory and deallocs all allocated
// pages; p is the virtual address of page directory
void dealloc_all_pages(PDE *p) {
uint32_t pd_entry;
uint32_t pt_entry;
uint32_t i;
uint32_t loc = 0;
PTE *pt;
while (loc < 0xC0000000) { // only freeing user area of virtual memory
pd_entry = loc >> 22; // top 10 bits
if (p[pd_entry] != 0) { // page directory entry exists
pt = (PTE *)((p[pd_entry] & 0xFFFFF000) + KERNEL_BASE);
for (i=0; i<1024; i++) { // walk through page table
if (pt[i] == 0) continue;
dealloc_page((void *)(loc + i*4096), p);
}
// dealloc page table space and mark page directory entry not present
dealloc_frames((void *)(p[pd_entry] & 0xFFFFF000), 1);
p[pd_entry] = 0;
}
loc += 0x400000; // move ahead 4MB; the next page table
}
}
/*** Zero out pages ***/
// Ensure that page mappings exist before calling this function
void zero_out_pages(void *base, uint32_t n_pages) {
int i=0;
for (i=0; i<1024*n_pages; i++)
*((uint32_t *)((uint32_t)base + i)) = 0;
}
Explanation / Answer
////////////////////////////////////////////////////////
// The NAIVE Logical Memory Manager
//
// Divides memory into 4KB pages and allocates from them
#include "kernel_only.h"
// kernel page directory will be placed at frame 257
PDE *k_page_directory = (PDE *)(0xC0101000);
// page table entries for the 768th page directory entry will be placed
// at frame 258; 768th entry corresponds to virtual address range
// 3GB to 3GB+4MB-1 (0xC0000000 to 0xC03FFFFF)
PTE *pages_768 = (PTE *)(0xC0102000);
/*** Initialize logical memory for a process ***/
// Allocates physical memory and sets up page tables;
// we need to allocate memory to hold the program code and
// data, the stack, the page directory, and the required
// page tables
// called by runprogram.c; this function does not load the
// program from disk to memory (done in scheduler.c)
bool init_logical_memory(PCB *p, uint32_t code_size) {
// TODO: see background material on what this function should
// do. High-level objectives are:
// 1) calculate the number of frames necessary for program code,
// user-mode stack and kernel-mode stack
// 2) allocate frames for above
// 3) determine beginning physical address of program code,
// user-mode stack and kernel-mode stack
// 4) calculate the number of frames necessary for page directory
// and page tables
// 5) allocate frames for above
// 6) set up page directory and page tables
// 7) set mem struct in PCB: start_code, end_code, start_stack,
// start_brk, brk, and page_directory
// Return value: TRUE if everything goes well; FALSE if allocation
// of frames failed (you should dealloc any frames that may
// have already been allocated before returning)
// TODO: comment following line when you start working in
// this function
uint32_t codePages;
if(code_size % 4096 == 0) {
codePages= code_size / 4096;
}
else {
codePages = (uint32_t)(code_size / 4096 + 1);
}
sys_printf("We are allocating a kernel page ");
//cleared sets to zero, unused good
PDE *myPDE = (PDE*)alloc_kernel_pages(1);
//uint32_t n_pages, uint32_t base, PDE *page_directory, uint32_t mode
sys_printf("The location of the PDE is : %x ", myPDE);
//sys_printf("The location of the tempPDE is : %x ", tempPDE);
myPDE[768] = ((uint32_t)pages_768-KERNEL_BASE) | PDE_PRESENT | PDE_READ_WRITE;
sys_printf("The location of pde[768] is : %x ", &myPDE[768]);
//allocate pages tables
//mode -> bits get or'ed into page table entires
uint32_t codeRet = (uint32_t)alloc_user_pages(codePages, 0x0, myPDE, PTE_READ_WRITE);
sys_printf("codeRet is: %d ", codeRet);
if(codeRet == NULL){
sys_printf("We are failing when making a page for the code ");
dealloc_all_pages(myPDE);
return FALSE;
}
//BFBFFFF-16K+1 (16K=0x4000)
//can't we just do if(alloc_user_pages())
//base of user stack ((0xBFBFEFFF+1)%4096)
uint32_t stackRet = (uint32_t)alloc_user_pages(4, 0xBFBFC000, myPDE, PTE_READ_WRITE);
sys_printf("stackRet is: %d ", stackRet);
if(stackRet == NULL){
sys_printf("We are failing when making a page for the stack ");
dealloc_all_pages(myPDE);
return FALSE;
}
uint32_t testPDE = (uint32_t)myPDE - KERNEL_BASE;
sys_printf("The location of the real PDE is : %x ", testPDE);
//assigned correctly ?
//assigned correctly ?
p->mem.start_code = 0x0;
p->mem.end_code = code_size;
p->mem.start_brk = codePages * 4096;
p->mem.brk = p->mem.start_brk;
p->mem.start_stack = 0xBFBFFFFF - 0x1000; //0xBFBFEFFF kernal stack
p->mem.page_directory = (PDE*)((uint32_t)myPDE - KERNEL_BASE);
sys_printf("The real PDE is : %x ", p->mem.page_directory);
sys_printf("Looks like we are getting past the code ");
//deallocate frames if fails
return TRUE;
//return FALSE;
}
/*** Initialize kernel's page directory and table ***/
void init_kernel_pages(void) {
uint32_t i;
// set up kernel page directory (users cannot touch this)
for (i=0; i<1024; i++) k_page_directory[i] = 0;
k_page_directory[768] = ((uint32_t)pages_768-KERNEL_BASE) | PDE_PRESENT | PDE_READ_WRITE;
// map virtual (0xC0000000--0xC03FFFFF) to physical (0--0x3FFFFF)
for (i=0; i<1024; i++)
pages_768[i] = (i*4096) | PTE_PRESENT | PTE_READ_WRITE | PTE_GLOBAL;
// load page directory
load_CR3((uint32_t)k_page_directory-KERNEL_BASE);
}
/*** Load CR3 with page directory ***/
void load_CR3(uint32_t pd) {
asm volatile ("movl %0, %%eax ": :"m"(pd));
asm volatile ("movl %eax, %cr3 ");
}
/*** Allocate logical memory for kernel***/
// Allocates pages for kernel and returns logical address of allocated memory
// Note: Kernel uses 0xC0000000 to 0xC0400000 for now
void *alloc_kernel_pages(uint32_t n_pages) {
uint32_t p_alloc_base; // physical address of allocated memory
uint32_t l_alloc_base; // logical address of allocated memory
int i;
p_alloc_base = (uint32_t)alloc_frames(n_pages, KERNEL_ALLOC);
if (p_alloc_base==NULL) return NULL;
// Note: page table update is not necessary since first 4MB is already
// mapped and kernel allocation is always from first 4MB
// adding KERNEL_BASE converts address to logical when allocation
// of kernel is from the first 4MB (see alloc_frames)
l_alloc_base = p_alloc_base + KERNEL_BASE;
// fill-zero the memory area
zero_out_pages((void *)l_alloc_base, n_pages);
return (void *)l_alloc_base;
}
/*** Allocate logical memory for user ***/
// n_pages: the number of contiguous pages requested
// base: requested base address of first page; must be 4KB aligned;
// all pages must fit before hitting KERNEL_BASE
// page_directory: logical base address of process page directory
// mode: page modes (READ ONLY or READ+WRITE)
// Returns FALSE on failure, TRUE on success
//
// We also allocate frames for page tables if necessary
//
// 2016-02-24: Fixed some bugs:
// 1. Return type changed to bool, void* return type failed if called with base = 0
// 2. Fixed calculation of n_pde
// 3. Removed init of user pages to 0 (this failed because they aren't mapped in the kernel space)
// Requires corresponding update of declaration in kernel_only.h
bool alloc_user_pages(uint32_t n_pages, uint32_t base, PDE *page_directory, uint32_t mode) {
// some sanity check
if (base & 0x00000FFF != 0 || // base not 4KB aligned
base >= KERNEL_BASE || // base encroaching on kernel address space
(KERNEL_BASE - base)/4096 < n_pages || // some pages on kernel address space
n_pages == 0) return FALSE;
int i;
// allocate frames for the requested pages
uint32_t user_frames = (uint32_t)alloc_frames(n_pages, USER_ALLOC);
if (user_frames==NULL) return FALSE;
// how many new page tables we may need; some may be returned
uint32_t n_pde = (n_pages+1023) / 1024 + 1; // one page table maps 1024 pages
// allocate frames for the new page tables
uint32_t pt_frames = (uint32_t)alloc_frames(n_pde, KERNEL_ALLOC);
uint32_t pt_frames_used = 0; // we will track how many are used
if (pt_frames == NULL) {
dealloc_frames((void *)user_frames,n_pages);
return FALSE;
}
// set up page directory and page tables
PTE *l_pages;
uint32_t pd_entry = base >> 22; // start from this page directory entry
uint32_t pt_entry = (base >> 12) & 0x000003FF; // and this page table entry
for (i=0; i<n_pages; i++) {
// see if page directory entry is present
if ((uint32_t)(page_directory[pd_entry] & PDE_PRESENT) == 0) { // first time use (create the entry)
page_directory[pd_entry] = pt_frames | PDE_PRESENT | PDE_READ_WRITE | PDE_USER_SUPERVISOR;
zero_out_pages((void *)(pt_frames + KERNEL_BASE), 1);
pt_frames_used++;
pt_frames += 4096; // one page table takes up 4KB = 4096 bytes
}
// logical address pointer of page table
l_pages = (PTE *)((page_directory[pd_entry] & 0xFFFFF000) + KERNEL_BASE);
// write page table entries; if a mapping already exists, then referred frame
// is freed
if ((uint32_t)(l_pages[pt_entry] & PTE_PRESENT) != 0) { // mapping already present
dealloc_frames((void *)(l_pages[pt_entry] & 0xFFFFF000),1);
}
l_pages[pt_entry] = user_frames | mode | PTE_PRESENT | PTE_USER_SUPERVISOR;
user_frames += 4096; // one page is 4KB
pt_entry++;
if (pt_entry == 1024) { // time to move to next page directory entry
pd_entry++;
pt_entry = 0;
}
}
// return unused frames allocated for page tables
if (pt_frames_used != n_pde)
dealloc_frames((void *)pt_frames, (n_pde - pt_frames_used));
return TRUE;
}
/*** Deallocate one page ***/
// Deallocates the page corresponding to virtual address
// <loc>; p is the virtual address of page directory
void dealloc_page(void *loc, PDE *p) {
uint32_t pd_entry = (uint32_t)loc >> 22; // top 10 bits
uint32_t pt_entry = ((uint32_t)loc >> 12) & 0x000003FF; // next top 10 bits
int i;
// obtain page table corresponding to page directory entry
PTE *pt = (PTE *)(p[pd_entry] & 0xFFFFF000);
pt = (PTE *)((uint32_t)pt + KERNEL_BASE); // converting to virtual address
// deallocate the frame
dealloc_frames((void *)(pt[pt_entry] & 0xFFFFF000), 1);
// if user space address, then mark page table entry as not present
if ((uint32_t)loc < KERNEL_BASE)
pt[pt_entry] = 0;
}
/*** Deallocate all pages ***/
// Traverses the page directory and deallocs all allocated
// pages; p is the virtual address of page directory
void dealloc_all_pages(PDE *p) {
uint32_t pd_entry;
uint32_t pt_entry;
uint32_t i;
uint32_t loc = 0;
PTE *pt;
while (loc < 0xC0000000) { // only freeing user area of virtual memory
pd_entry = loc >> 22; // top 10 bits
if (p[pd_entry] != 0) { // page directory entry exists
pt = (PTE *)((p[pd_entry] & 0xFFFFF000) + KERNEL_BASE);
for (i=0; i<1024; i++) { // walk through page table
if (pt[i] == 0) continue;
dealloc_page((void *)(loc + i*4096), p);
}
// dealloc page table space and mark page directory entry not present
dealloc_frames((void *)(p[pd_entry] & 0xFFFFF000), 1);
p[pd_entry] = 0;
}
loc += 0x400000; // move ahead 4MB; the next page table
}
}
/*** Zero out pages ***/
// Ensure that page mappings exist before calling this function
void zero_out_pages(void *base, uint32_t n_pages) {
int i=0;
for (i=0; i<1024*n_pages; i++)
*((uint32_t *)((uint32_t)base + i)) = 0;
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.