Files
riscv-operating-system-mooc/code/os/03-contextswitch/page.c
Wang Chen fd1d098906 Encapsulate some types related to cpu word length.
The purpose is to facilitate porting to RV64.

Signed-off-by: Wang Chen <wangchen20@iscas.ac.cn>
2024-03-27 14:30:53 +08:00

190 lines
4.1 KiB
C

#include "os.h"
/*
* Following global vars are defined in mem.S
*/
extern ptr_t TEXT_START;
extern ptr_t TEXT_END;
extern ptr_t DATA_START;
extern ptr_t DATA_END;
extern ptr_t RODATA_START;
extern ptr_t RODATA_END;
extern ptr_t BSS_START;
extern ptr_t BSS_END;
extern ptr_t HEAP_START;
extern ptr_t HEAP_SIZE;
/*
* _alloc_start points to the actual start address of heap pool
* _alloc_end points to the actual end address of heap pool
* _num_pages holds the actual max number of pages we can allocate.
*/
static ptr_t _alloc_start = 0;
static ptr_t _alloc_end = 0;
static uint32_t _num_pages = 0;
#define PAGE_SIZE 4096
#define PAGE_ORDER 12
#define PAGE_TAKEN (uint8_t)(1 << 0)
#define PAGE_LAST (uint8_t)(1 << 1)
/*
* Page Descriptor
* flags:
* - bit 0: flag if this page is taken(allocated)
* - bit 1: flag if this page is the last page of the memory block allocated
*/
struct Page {
uint8_t flags;
};
static inline void _clear(struct Page *page)
{
page->flags = 0;
}
static inline int _is_free(struct Page *page)
{
if (page->flags & PAGE_TAKEN) {
return 0;
} else {
return 1;
}
}
static inline void _set_flag(struct Page *page, uint8_t flags)
{
page->flags |= flags;
}
static inline int _is_last(struct Page *page)
{
if (page->flags & PAGE_LAST) {
return 1;
} else {
return 0;
}
}
/*
* align the address to the border of page(4K)
*/
static inline ptr_t _align_page(ptr_t address)
{
ptr_t order = (1 << PAGE_ORDER) - 1;
return (address + order) & (~order);
}
void page_init()
{
/*
* We reserved 8 Page (8 x 4096) to hold the Page structures.
* It should be enough to manage at most 128 MB (8 x 4096 x 4096)
*/
_num_pages = (HEAP_SIZE / PAGE_SIZE) - 8;
printf("HEAP_START = %x, HEAP_SIZE = %x, num of pages = %d\n", HEAP_START, HEAP_SIZE, _num_pages);
struct Page *page = (struct Page *)HEAP_START;
for (int i = 0; i < _num_pages; i++) {
_clear(page);
page++;
}
_alloc_start = _align_page(HEAP_START + 8 * PAGE_SIZE);
_alloc_end = _alloc_start + (PAGE_SIZE * _num_pages);
printf("TEXT: 0x%x -> 0x%x\n", TEXT_START, TEXT_END);
printf("RODATA: 0x%x -> 0x%x\n", RODATA_START, RODATA_END);
printf("DATA: 0x%x -> 0x%x\n", DATA_START, DATA_END);
printf("BSS: 0x%x -> 0x%x\n", BSS_START, BSS_END);
printf("HEAP: 0x%x -> 0x%x\n", _alloc_start, _alloc_end);
}
/*
* Allocate a memory block which is composed of contiguous physical pages
* - npages: the number of PAGE_SIZE pages to allocate
*/
void *page_alloc(int npages)
{
/* Note we are searching the page descriptor bitmaps. */
int found = 0;
struct Page *page_i = (struct Page *)HEAP_START;
for (int i = 0; i <= (_num_pages - npages); i++) {
if (_is_free(page_i)) {
found = 1;
/*
* meet a free page, continue to check if following
* (npages - 1) pages are also unallocated.
*/
struct Page *page_j = page_i + 1;
for (int j = i + 1; j < (i + npages); j++) {
if (!_is_free(page_j)) {
found = 0;
break;
}
page_j++;
}
/*
* get a memory block which is good enough for us,
* take housekeeping, then return the actual start
* address of the first page of this memory block
*/
if (found) {
struct Page *page_k = page_i;
for (int k = i; k < (i + npages); k++) {
_set_flag(page_k, PAGE_TAKEN);
page_k++;
}
page_k--;
_set_flag(page_k, PAGE_LAST);
return (void *)(_alloc_start + i * PAGE_SIZE);
}
}
page_i++;
}
return NULL;
}
/*
* Free the memory block
* - p: start address of the memory block
*/
void page_free(void *p)
{
/*
* Assert (TBD) if p is invalid
*/
if (!p || (ptr_t)p >= _alloc_end) {
return;
}
/* get the first page descriptor of this memory block */
struct Page *page = (struct Page *)HEAP_START;
page += ((ptr_t)p - _alloc_start)/ PAGE_SIZE;
/* loop and clear all the page descriptors of the memory block */
while (!_is_free(page)) {
if (_is_last(page)) {
_clear(page);
break;
} else {
_clear(page);
page++;;
}
}
}
void page_test()
{
void *p = page_alloc(2);
printf("p = 0x%x\n", p);
//page_free(p);
void *p2 = page_alloc(7);
printf("p2 = 0x%x\n", p2);
page_free(p2);
void *p3 = page_alloc(4);
printf("p3 = 0x%x\n", p3);
}