Foliensatz 6: Frame- und Seitenverwaltung
v1.1, 11.11.2014
|
〈global variables〉≡
page_table video_pt __attribute__ ((aligned (409↩ …6))); // must be aligned! |
|
〈initialize system〉≡
for (int i=0; i<1024; i++) { // null entries: fill_page_desc ( &(video_pt.pds[i]), false,fal↩ …se,false,false,0 ); }; KMAP ( &(video_pt.pds[0xB8]), 0xB8*4096 ); // ↩ …one page of video RAM // enter new table in page directory KMAPD ( &(current_pd->ptds[0]), (unsigned int) (↩ …&video_pt) - 0xC0000000 ); gdt_flush(); |
|
〈remove video mapping〉≡
// null entry: fill_page_desc ( &(video_pt.pds[0xB8]), false,fa↩ …lse,false,false,0 ); gdt_flush(); |
Verwalten der Page Frames (phys. Speicher)
|
〈constants〉≡
#define MEM_SIZE 1024*1024*64 // 64 MByte #define MAX_ADDRESS MEM_SIZE-1 // last val↩ …id physical address #define PAGE_SIZE 4096 // Intel: 4↩ …K pages #define NUMBER_OF_FRAMES MEM_SIZE/PAGE_SIZE |
|
〈global variables〉+≡
unsigned int free_frames = NUMBER_OF_FRAMES; |
|
〈global variables〉+≡
char place_for_ftable[NUMBER_OF_FRAMES/8]; unsigned int* ftable = (unsigned int*)(&place_fo↩ …r_ftable); |
|
〈initialize system〉+≡
memset (ftable, 0, NUMBER_OF_FRAMES/8); // all ↩ …frames are free |
|
〈initialize system〉+≡
memset (ftable, 0xff, 128); free_frames -= 1024; |
Abfragen / Ändern der Bits in ftable
|
〈macro definitions〉≡
#define INDEX_FROM_BIT(b) (b/32) // 32 bits in↩ … an unsigned int #define OFFSET_FROM_BIT(b) (b%32) |
|
〈function implementations〉≡
static void set_frame (unsigned int frame_addr) ↩ …{ unsigned int frame = frame_addr / PAGE_SIZE; unsigned int index = INDEX_FROM_BIT (frame); unsigned int offset = OFFSET_FROM_BIT (frame); ftable[index] |= (1 << offset); } static void clear_frame (unsigned int frame_addr↩ …) { unsigned int frame = frame_addr / PAGE_SIZE; unsigned int index = INDEX_FROM_BIT (frame); unsigned int offset = OFFSET_FROM_BIT (frame); ftable[index] &= ~(1 << offset); } |
|
〈function implementations〉+≡
static unsigned int test_frame (unsigned int fra↩ …me_addr) { // returns true if frame is in use (false if f↩ …rame is free) unsigned int frame = frame_addr / PAGE_SIZE; unsigned int index = INDEX_FROM_BIT (frame); unsigned int offset = OFFSET_FROM_BIT (frame); return ((ftable[index] & (1 << offset)) >> offset); } |
〈example call of test_frame〉≡
if ( test_frame (address) ) { // result non-0 (true); frame is not available } else { // result 0 (false); frame is available } |
|
〈global variables〉+≡
page_table kernel_pt_ram[16] __attribute__ ((ali↩ …gned (4096))); |
|
〈initialize system〉+≡
unsigned int fid; for (fid=0; fid<NUMBER_OF_FRAMES; fid++) { 〈map page starting at 0xD0000000 + PAGE_SIZE*fid to frame fid〉 } |
|
〈map page starting at 0xD0000000 + PAGE_SIZE*fid to frame fid〉≡
KMAP ( &(kernel_pt_ram[fid/1024].pds[fid%1024]),↩ … fid*PAGE_SIZE ); |
|
〈initialize system〉+≡
unsigned int physaddr; for (int i=0; i<16; i++) { // get physical address of kernel_pt_ram[i] physaddr = (unsigned int)(&(kernel_pt_ram[i]))↩ … - 0xc0000000; KMAPD ( &(current_pd->ptds[832+i]), physaddr )↩ …; }; kputs ("Physical RAM (64 MB) mapped to 0xD000000↩ …0-0xD3FFFFFF.\n"); |
|
〈macro definitions〉+≡
#define PHYSICAL(x) ((x)+0xd0000000) |
|
〈initialize system〉+≡
VIDEORAM=0xD00B8000; textmemptr = (unsigned short *)VIDEORAM; 〈remove video mapping〉 |
|
〈function prototypes〉≡
unsigned int pageno_to_frameno (unsigned int pag↩ …eno); |
〈function implementations〉+≡
unsigned int pageno_to_frameno (unsigned int pageno) { unsigned int pdindex = pageno/1024; unsigned int ptindex = pageno%1024; if ( ! current_pd->ptds[pdindex].present ) { return -1; // we don't have that page table } else { // get the page table page_table* pt = (page_table*) ( PHYSICAL(current_pd->ptds[pdindex].frame_addr << 12) ); // note: frame_addr holds a physical address. luckily we have a mapping // of physical address space to 0xd000.0000 and above... if ( pt->pds[ptindex].present ) { return pt->pds[ptindex].frame_addr; } else { return -1; // we don't have that page }; }; }; |
〈macro definitions〉+≡
/* Peek and Poke for virtual addresses */ #define PEEK(addr) (*(unsigned char *)(addr)) #define POKE(addr, b) (*(unsigned char *)(addr) = (b)) /* Peek and Poke for physical addresses 0..64 MB */ #define PEEKPH(addr) (*(unsigned char *)(PHYSICAL(addr))) #define POKEPH(addr, b) (*(unsigned char *)(PHYSICAL(addr)) = (b)) #define PEEK_UINT(addr) (*(unsigned int *)(addr)) #define POKE_UINT(addr, b) (*(unsigned int *)(addr) = (b)) #define PEEKPH_UINT(addr) (*(unsigned int *)(PHYSICAL(addr))) #define POKEPH_UINT(addr, b) (*(unsigned int *)(PHYSICAL(addr)) = (b)) |
〈peek and poke example〉≡
unsigned int testvar; unsigned int address = (unsigned int)&testvar; POKE (address, 0x12); POKE (address+1, 0x34); POKE (address+2, 0x56); POKE (address+3, 0x78); printf ("32-bit value: %x\n", PEEK_UINT (address)); |
Verwaltung der Rahmen
|
〈function implementations〉+≡
int request_new_frame () { 〈find a free frame und reserve it〉 }; |
|
〈find a free frame und reserve it〉≡
unsigned int frameid; boolean found=false; for (frameid = 0; frameid < NUMBER_OF_FRAMES; fr↩ …ameid++) { if ( !test_frame (frameid*4096) ) { found=true; break; // frame found }; } |
|
〈find a free frame und reserve it〉+≡
if (found) { set_frame (frameid*4096); free_frames--; return frameid; } else { return -1; } |
|
〈function implementations〉+≡
void release_frame (unsigned int frameaddr) { if ( test_frame (frameaddr) ) { // only do work if frame is marked as used clear_frame (frameaddr); free_frames++; }; }; |
|
〈constants〉+≡
#define NULL ((void*) 0) |
Verwaltung der Seiten (virtueller Speicher)
|
〈function implementations〉+≡
unsigned int* request_new_page (int need_more_pa↩ …ges) { unsigned int newframeid = request_new_frame ()↩ …; if (newframeid == -1) return NULL; // exit ↩ …if no frame was found 〈enter frame in page table〉 }; |
|
〈enter frame in page table〉≡
unsigned int pageno = -1; for (unsigned int i=0xc0000; i<1024*1024; i++) { if ( mmu_p (current_as, i) == -1 ) { // mmu_p() is similar to pageno_to_frameno() pageno = i; break; // end loop, unmapped page was ↩ …found }; }; if ( pageno == -1 ) { return NULL; // we found no page -- whole 4 ↩ …GB are mapped??? }; |
|
〈enter frame in page table〉+≡
unsigned int pdindex = pageno/1024; unsigned int ptindex = pageno%1024; page_table* pt; if (ptindex == 0) { // last entry!! 〈create new page table〉 newframeid = request_new_frame (); // get yet↩ … another frame if (newframeid == -1) { return NULL; // exit if↩ … no frame was found // note: we're not removing the new page tab↩ …le since we assume // it will be used soon anyway } }; |
|
〈global variables〉+≡
short int DEBUG=0; |
〈enter frame in page table〉+≡
if ( ! current_pd->ptds[pdindex].present ) { // we don't have that page table -- this should not happen! kputs ("FAIL! No page table entry\n"); return NULL; } else { // get the page table pt = (page_table*)( PHYSICAL(current_pd->ptds[pdindex].frame_addr << 12) ); // finally: enter the frame address KMAP ( &(pt->pds[ptindex]), newframeid * PAGE_SIZE ); // invalidate cache entry asm volatile ("invlpg %0" : : "m"(*(char*)(pageno<<12)) ); }; |
|
〈enter frame in page table〉+≡
memset ((unsigned int*) (pageno*4096), 0, 4096); return ((unsigned int*) (pageno*4096)); |
|
〈create new page table〉≡
// create a new page table in there page_table* pt = (page_table*) PHYSICAL(newframeid<<12); memset (pt, 0, PAGE_SIZE); |
|
〈create new page table〉+≡
// KMAPD ( &(current_pd-> ptds[pdindex]), newframeid << 12 ); |
〈create new page table〉+≡
int asid; page_directory* tmp_pd; for (asid=0; asid<1024; asid++) { if (!address_spaces[asid].free // is this address space in use? && asid != create_as) // do not modify an address space which is cur- // rently created via create_new_address_space { tmp_pd = address_spaces[asid].pd; KMAPD ( &(tmp_pd->ptds[pdindex]), newframeid << 12 ); } } |
Freigeben einer Seite ist leichter:
|
〈function implementations〉+≡
void release_page (unsigned int pageno) { 〈remove page to frame mapping from page table〉 〈release corresponding frame〉 }; |
|
〈remove page to frame mapping from page table〉≡
// int frameno = pageno_to_frameno (pageno); //↩ … we will need this later int frameno = mmu_p (current_as, pageno); // we↩ … will need this later if ( frameno == -1 ) return; // ex↩ …it if no such page |
|
〈remove page to frame mapping from page table〉+≡
unsigned int pdindex = pageno/1024; unsigned int ptindex = pageno%1024; page_table* pt; pt = (page_table*)( PHYSICAL(current_pd->ptds [pdindex].frame_addr << 12) ); // write null page descriptor fill_page_desc ( &(pt->pds[ptindex]), false, fal↩ …se, false, false, 0 ); |
|
〈release corresponding frame〉≡
release_frame (frameno<<12); // expects an address, not an ID // note: release_frame increases free_frames |
|
〈function implementations〉+≡
void release_page_range (unsigned int start_page↩ …no, unsigned int end_pageno) { for (int i = start_pageno; i < end_pageno+1; i↩ …++ ) release_page (i); }; |