Merge branch 'paging-fork' of https://github.com/stv0g/eduOS into stage6
This commit is contained in:
commit
2245eaecbb
3 changed files with 107 additions and 3 deletions
|
@ -58,6 +58,12 @@ static size_t* self[PAGE_LEVELS] = {
|
|||
(size_t *) 0xFFFFF000
|
||||
};
|
||||
|
||||
/** An other self-reference for page_map_copy() */
|
||||
static size_t * other[PAGE_LEVELS] = {
|
||||
(size_t *) 0xFF800000,
|
||||
(size_t *) 0xFFFFE000
|
||||
};
|
||||
|
||||
/* Addresses of child/parent tables */
|
||||
#define CHILD(map, lvl, vpn) &map[lvl-1][vpn<<PAGE_MAP_BITS]
|
||||
#define PARENT(map, lvl, vpn) &map[lvl+1][vpn>>PAGE_MAP_BITS]
|
||||
|
@ -142,6 +148,77 @@ int page_unmap(size_t viraddr, size_t npages)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int page_map_drop()
|
||||
{
|
||||
void traverse(int lvl, long vpn) {
|
||||
kprintf("traverse(lvl=%d, vpn=%#lx)\n", lvl, vpn);
|
||||
|
||||
long stop;
|
||||
for (stop=vpn+PAGE_MAP_ENTRIES; vpn<stop; vpn++) {
|
||||
if (self[lvl][vpn] & PG_PRESENT) {
|
||||
if (self[lvl][vpn] & PG_BOOT)
|
||||
continue;
|
||||
|
||||
// ost-order traversal
|
||||
if (lvl > 1)
|
||||
traverse(lvl-1, vpn<<PAGE_MAP_BITS);
|
||||
|
||||
kprintf("%#lx, ", self[lvl][vpn] & PAGE_MASK);
|
||||
//put_page(self[lvl][vpn] & PAGE_MASK);
|
||||
|
||||
atomic_int32_dec(¤t_task->user_usage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spinlock_irqsave_lock(¤t_task->page_lock);
|
||||
|
||||
traverse(PAGE_LEVELS-1, 0);
|
||||
|
||||
spinlock_irqsave_unlock(¤t_task->page_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int page_map_copy(size_t dest)
|
||||
{
|
||||
int traverse(int lvl, long vpn) {
|
||||
long stop;
|
||||
for (stop=vpn+PAGE_MAP_ENTRIES; vpn<stop; vpn++) {
|
||||
if (self[lvl][vpn] & PG_PRESENT) {
|
||||
size_t phyaddr = get_pages(1);
|
||||
if (BUILTIN_EXPECT(phyaddr, 0))
|
||||
return -ENOMEM;
|
||||
|
||||
other[lvl][vpn] = phyaddr;
|
||||
other[lvl][vpn] |= self[lvl][vpn] & ~PAGE_MASK;
|
||||
|
||||
memcpy(CHILD(other, lvl, vpn), CHILD(self, lvl, vpn), PAGE_SIZE);
|
||||
|
||||
// pre-order traversal
|
||||
if (lvl)
|
||||
traverse(lvl-1, vpn<<PAGE_MAP_BITS);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
spinlock_lock(&kslock);
|
||||
|
||||
// create another temporary self-reference
|
||||
self[PAGE_LEVELS-1][PAGE_MAP_ENTRIES-2] = dest | PG_PRESENT | PG_RW;
|
||||
|
||||
traverse(PAGE_LEVELS-1, 0);
|
||||
|
||||
// remove temporary self-reference
|
||||
self[PAGE_LEVELS-1][PAGE_MAP_ENTRIES-2] = 0;
|
||||
|
||||
spinlock_unlock(&kslock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void page_fault_handler(struct state *s)
|
||||
{
|
||||
size_t viraddr = read_cr2();
|
||||
|
|
|
@ -39,7 +39,9 @@
|
|||
|
||||
#include <eduos/stddef.h>
|
||||
#include <eduos/spinlock_types.h>
|
||||
|
||||
#include <asm/tasks_types.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -73,6 +75,12 @@ typedef struct task {
|
|||
void* stack;
|
||||
/// Task priority
|
||||
uint8_t prio;
|
||||
/// Physical address of root page table
|
||||
size_t page_map;
|
||||
/// Lock for page tables
|
||||
spinlock_irqsave_t page_lock;
|
||||
/// usage in number of pages (including page map tables)
|
||||
atomic_int32_t user_usage;
|
||||
/// next task in the queue
|
||||
struct task* next;
|
||||
/// previous task in the queue
|
||||
|
|
|
@ -34,14 +34,17 @@
|
|||
#include <eduos/spinlock.h>
|
||||
#include <eduos/errno.h>
|
||||
#include <eduos/syscall.h>
|
||||
#include <eduos/memory.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
|
||||
/** @brief Array of task structures (aka PCB)
|
||||
*
|
||||
* A task's id will be its position in this array.
|
||||
*/
|
||||
static task_t task_table[MAX_TASKS] = { \
|
||||
[0] = {0, TASK_IDLE, NULL, NULL, 0, NULL, NULL}, \
|
||||
[1 ... MAX_TASKS-1] = {0, TASK_INVALID, NULL, NULL, 0, NULL, NULL}};
|
||||
[0] = {0, TASK_IDLE, NULL, NULL, 0, 0, SPINLOCK_IRQSAVE_INIT, ATOMIC_INIT(0), NULL, NULL}, \
|
||||
[1 ... MAX_TASKS-1] = {0, TASK_INVALID, NULL, NULL, 0, 0, SPINLOCK_IRQSAVE_INIT, ATOMIC_INIT(0), NULL, NULL}};
|
||||
|
||||
static spinlock_irqsave_t table_lock = SPINLOCK_IRQSAVE_INIT;
|
||||
|
||||
|
@ -53,7 +56,7 @@ extern const void boot_stack;
|
|||
/** @brief helper function for the assembly code to determine the current task
|
||||
* @return Pointer to the task_t structure of current task
|
||||
*/
|
||||
task_t* get_current_task(void)
|
||||
task_t* get_current_task(void)
|
||||
{
|
||||
return current_task;
|
||||
}
|
||||
|
@ -118,6 +121,8 @@ static void NORETURN do_exit(int arg)
|
|||
|
||||
kprintf("Terminate task: %u, return value %d\n", curr_task->id, arg);
|
||||
|
||||
page_map_drop();
|
||||
|
||||
curr_task->status = TASK_FINISHED;
|
||||
reschedule();
|
||||
|
||||
|
@ -160,6 +165,8 @@ void NORETURN abort(void) {
|
|||
}
|
||||
|
||||
/** @brief Create a task with a specific entry point
|
||||
*
|
||||
* @todo Dont aquire table_lock for the whole task creation.
|
||||
*
|
||||
* @param id Pointer to a tid_t struct were the id shall be set
|
||||
* @param ep Pointer to the function the task shall start with
|
||||
|
@ -193,6 +200,17 @@ static int create_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio)
|
|||
task_table[i].stack = create_stack(i);
|
||||
task_table[i].prio = prio;
|
||||
|
||||
spinlock_irqsave_init(&task_table[i].page_lock);
|
||||
atomic_int32_set(&task_table[i].user_usage, 0);
|
||||
|
||||
/* Allocated new PGD or PML4 and copy page table */
|
||||
size_t map = get_pages(1);
|
||||
if (BUILTIN_EXPECT(map, 0))
|
||||
goto out;
|
||||
|
||||
page_map_copy(map);
|
||||
task_table[i].page_map = map;
|
||||
|
||||
if (id)
|
||||
*id = i;
|
||||
|
||||
|
@ -217,6 +235,7 @@ static int create_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio)
|
|||
}
|
||||
}
|
||||
|
||||
out:
|
||||
spinlock_irqsave_unlock(&table_lock);
|
||||
|
||||
return ret;
|
||||
|
|
Loading…
Add table
Reference in a new issue