tasking: isolate ring3 tasks
This commit is contained in:
+2
-1
@@ -58,7 +58,8 @@ void *get_physaddr(void *virtualaddr);
|
|||||||
uint32_t get_pte(void *virtualaddr);
|
uint32_t get_pte(void *virtualaddr);
|
||||||
void map_page(void* physaddr, void* virtualaddr, unsigned int flags);
|
void map_page(void* physaddr, void* virtualaddr, unsigned int flags);
|
||||||
void unmap_page(void *virtualaddr);
|
void unmap_page(void *virtualaddr);
|
||||||
|
int map_page_in_directory(uint32_t* pd_virt_addr, void* phys_addr, void* virt_addr, uint32_t flags);
|
||||||
void map_kernel_page(void* virtualaddr, unsigned int flags);
|
void map_kernel_page(void* virtualaddr, unsigned int flags);
|
||||||
void* setup_user_process(void* user_code_phys, uint32_t* user_stack_top);
|
void* setup_user_process(uint32_t* pd, void* user_code_phys, uint32_t* user_stack_top);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+1
-1
@@ -61,7 +61,7 @@ typedef struct Process
|
|||||||
uint32_t* page_directory; // Директория страниц
|
uint32_t* page_directory; // Директория страниц
|
||||||
} Process;
|
} Process;
|
||||||
|
|
||||||
Process* task_create(uint32_t func, void** args, uint32_t arg_count, uint32_t ring);
|
Process* task_create(uint32_t func, void** args, uint32_t arg_count, uint32_t ring, uint32_t* pagedir);
|
||||||
void scheduler_init();
|
void scheduler_init();
|
||||||
void schedule();
|
void schedule();
|
||||||
void scheduler_lock();
|
void scheduler_lock();
|
||||||
|
|||||||
+60
-5
@@ -18,7 +18,7 @@ uint32_t get_pte(void *virtualaddr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t next_user_virt = 0x00400000;
|
static uint32_t next_user_virt = 0x00400000;
|
||||||
void* setup_user_process(void* user_code_phys, uint32_t* user_stack_top) {
|
void* setup_user_process(uint32_t* pd, void* user_code_phys, uint32_t* user_stack_top) {
|
||||||
if ((uint32_t)user_code_phys & 0xFFF) {
|
if ((uint32_t)user_code_phys & 0xFFF) {
|
||||||
printf("SETUP_USER_PROCESS ERROR: user_code_phys not aligned\n");
|
printf("SETUP_USER_PROCESS ERROR: user_code_phys not aligned\n");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -36,12 +36,12 @@ void* setup_user_process(void* user_code_phys, uint32_t* user_stack_top) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unmap_page((void*)code_virt);
|
//unmap_page((void*)code_virt);
|
||||||
unmap_page((void*)stack_virt);
|
//unmap_page((void*)stack_virt);
|
||||||
|
|
||||||
|
|
||||||
map_page(user_code_phys, (void*)code_virt, 0x7);
|
map_page_in_directory(pd, user_code_phys, (void*)code_virt, 0x7);
|
||||||
map_page(stack_phys, (void*)stack_virt, 0x7);
|
map_page_in_directory(pd, stack_phys, (void*)stack_virt, 0x7);
|
||||||
|
|
||||||
// Verify mappings
|
// Verify mappings
|
||||||
uint32_t code_pte = get_pte((void*)code_virt);
|
uint32_t code_pte = get_pte((void*)code_virt);
|
||||||
@@ -140,6 +140,61 @@ void unmap_page(void *virtualaddr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps a physical page to a virtual address in a SPECIFIED page directory.
|
||||||
|
* pd_virt_addr: Kernel virtual address of the target page directory table.
|
||||||
|
* phys_addr: Physical address of the page to map.
|
||||||
|
* virt_addr: Virtual address to map to.
|
||||||
|
* flags: PTE flags (e.g., PAGE_PRESENT | PAGE_USER | PAGE_RW).
|
||||||
|
* Returns 0 on success, -1 on failure.
|
||||||
|
*/
|
||||||
|
int map_page_in_directory(uint32_t* pd_virt_addr, void* phys_addr, void* virt_addr, uint32_t flags) {
|
||||||
|
uint32_t pde_idx = (uint32_t)virt_addr >> 22;
|
||||||
|
uint32_t pte_idx = ((uint32_t)virt_addr >> 12) & 0x3FF;
|
||||||
|
|
||||||
|
uint32_t pde = pd_virt_addr[pde_idx];
|
||||||
|
uint32_t* pt_virt_for_modification; // Virtual address of the page table to write PTEs into
|
||||||
|
|
||||||
|
if (!(pde & PAGE_PRESENT)) {
|
||||||
|
// Page table not present, need to allocate one
|
||||||
|
void* pt_phys_addr = alloc_page();
|
||||||
|
if (!pt_phys_addr) {
|
||||||
|
printf("map_page_in_directory: alloc_page failed for new page table (VA: %x)\n", (uint32_t)virt_addr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a kernel virtual address for this new page table to initialize it
|
||||||
|
pt_virt_for_modification = (uint32_t*)phys_to_virt((uint32_t)pt_phys_addr);
|
||||||
|
|
||||||
|
// Temporarily map this new PT page into the *current* address space to zero it.
|
||||||
|
// This assumes map_page modifies the current CR3's address space.
|
||||||
|
map_page(pt_phys_addr, (void*)pt_virt_for_modification, PAGE_PRESENT | PAGE_RW);
|
||||||
|
memset(pt_virt_for_modification, 0, PAGE_SIZE);
|
||||||
|
// Now, point the PDE in the target page directory (pd_virt_addr) to the new page table.
|
||||||
|
// The PDE stores the PHYSICAL address of the page table.
|
||||||
|
pd_virt_addr[pde_idx] = (uint32_t)pt_phys_addr | PAGE_PRESENT | PAGE_RW | PAGE_USER; // Ensure PAGE_USER if PTEs will have USER bit
|
||||||
|
// Note: If map_page for the PT itself isn't needed long-term in current PD, you might unmap it.
|
||||||
|
// However, if phys_to_virt gives a stable kernel mapping, this explicit map/unmap might be simplified.
|
||||||
|
} else {
|
||||||
|
// Page table already exists. Get its physical address from PDE, then its kernel virtual address.
|
||||||
|
pt_virt_for_modification = (uint32_t*)phys_to_virt(pde & ~0xFFF);
|
||||||
|
// This assumes that any existing page table pointed to by a PDE is already
|
||||||
|
// accessible via its phys_to_virt address for modification.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the PTE entry in this page table
|
||||||
|
// Ensure phys_addr is page-aligned; flags should not include low 12 bits of phys_addr
|
||||||
|
pt_virt_for_modification[pte_idx] = ((uint32_t)phys_addr & ~0xFFF) | (flags & 0xFFF);
|
||||||
|
|
||||||
|
// When CR3 for the target task is loaded, TLB entries for virt_addr will be appropriately managed.
|
||||||
|
// If virt_addr was previously mapped by another process using this same PD (unlikely for new tasks),
|
||||||
|
// more complex TLB invalidation might be needed, but typically not for initial setup.
|
||||||
|
// invlpg may be needed here if you are re-mapping an address in a PD already in use by another CPU or
|
||||||
|
// if the PD is the current CR3 and the mapping changes. For setting up a new PD not yet in CR3, it's usually fine.
|
||||||
|
|
||||||
|
return 0; // Success
|
||||||
|
}
|
||||||
|
|
||||||
void map_kernel_page(void* virtualaddr, unsigned int flags) {
|
void map_kernel_page(void* virtualaddr, unsigned int flags) {
|
||||||
uint32_t virt = (uint32_t)virtualaddr & ~0xFFF; // Выравниваем по 4 КБ
|
uint32_t virt = (uint32_t)virtualaddr & ~0xFFF; // Выравниваем по 4 КБ
|
||||||
if (virt < 0xC0000000) while(1); // Ошибка: ядро только выше 3 ГБ
|
if (virt < 0xC0000000) while(1); // Ошибка: ядро только выше 3 ГБ
|
||||||
|
|||||||
+23
-33
@@ -22,7 +22,7 @@ extern Process* current;
|
|||||||
extern uint32_t pid_counter;
|
extern uint32_t pid_counter;
|
||||||
extern uint32_t task_count;
|
extern uint32_t task_count;
|
||||||
|
|
||||||
Process* task_create(uint32_t func, void** args, uint32_t arg_count, uint32_t ring)
|
Process* task_create(uint32_t func, void** args, uint32_t arg_count, uint32_t ring, uint32_t* pagedir)
|
||||||
{
|
{
|
||||||
void *p_physical = alloc_page();
|
void *p_physical = alloc_page();
|
||||||
Process* p = (Process*)((uint32_t)p_physical+0xC0000000);
|
Process* p = (Process*)((uint32_t)p_physical+0xC0000000);
|
||||||
@@ -56,6 +56,8 @@ Process* task_create(uint32_t func, void** args, uint32_t arg_count, uint32_t ri
|
|||||||
p->tf->eflags = FL_IF;
|
p->tf->eflags = FL_IF;
|
||||||
p->tf->eip = (uint32_t)func;
|
p->tf->eip = (uint32_t)func;
|
||||||
|
|
||||||
|
p->page_directory = pagedir;//(uint32_t*)create_page_dir();
|
||||||
|
|
||||||
if(ring == 3)
|
if(ring == 3)
|
||||||
{
|
{
|
||||||
void* user_stack_physical = alloc_page();
|
void* user_stack_physical = alloc_page();
|
||||||
@@ -63,7 +65,9 @@ Process* task_create(uint32_t func, void** args, uint32_t arg_count, uint32_t ri
|
|||||||
uint32_t user_stack_virtual_top = 0xBFFFF000 - ((p->pid -1) * (USTACKSIZE + 4096)); // Уникальный верх стека для каждого процесса
|
uint32_t user_stack_virtual_top = 0xBFFFF000 - ((p->pid -1) * (USTACKSIZE + 4096)); // Уникальный верх стека для каждого процесса
|
||||||
uint32_t user_stack_virtual_base = user_stack_virtual_top - USTACKSIZE;
|
uint32_t user_stack_virtual_base = user_stack_virtual_top - USTACKSIZE;
|
||||||
|
|
||||||
map_page(user_stack_physical, (void*)user_stack_virtual_base, PAGE_PRESENT | PAGE_RW | PAGE_USER); // Флаги 0x7
|
map_page_in_directory(p->page_directory, user_stack_physical, (void*)user_stack_virtual_base, PAGE_PRESENT | PAGE_RW | PAGE_USER); // Флаги 0x7
|
||||||
|
|
||||||
|
p->tf->usermode_esp = user_stack_virtual_top;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,8 +78,6 @@ Process* task_create(uint32_t func, void** args, uint32_t arg_count, uint32_t ri
|
|||||||
p->context->eip = (uint32_t)trapret;
|
p->context->eip = (uint32_t)trapret;
|
||||||
p->kesp = (uint32_t)sp;
|
p->kesp = (uint32_t)sp;
|
||||||
|
|
||||||
p->page_directory = (uint32_t*)create_page_dir();
|
|
||||||
|
|
||||||
p->next = 0;
|
p->next = 0;
|
||||||
|
|
||||||
if (!queue) {
|
if (!queue) {
|
||||||
@@ -141,13 +143,15 @@ void jump_usermode2(void) ;
|
|||||||
|
|
||||||
void scheduler_init()
|
void scheduler_init()
|
||||||
{
|
{
|
||||||
task_create((uint32_t)idle, NULL, 0, 0);
|
uint32_t* kernel_tasks_pagedir = (uint32_t*)create_page_dir();
|
||||||
|
|
||||||
|
task_create((uint32_t)idle, NULL, 0, 0, kernel_tasks_pagedir);
|
||||||
|
|
||||||
void* args1[] = {(void*)42, (void*)"ebalo"};
|
void* args1[] = {(void*)42, (void*)"ebalo"};
|
||||||
task_create((uint32_t)task1, args1, 2, 0);
|
task_create((uint32_t)task1, args1, 2, 0, kernel_tasks_pagedir);
|
||||||
void* args2[] = {(void*)69, (void*)420};
|
void* args2[] = {(void*)69, (void*)420};
|
||||||
task_create((uint32_t)task2, args2, 2, 0);
|
task_create((uint32_t)task2, args2, 2, 0, kernel_tasks_pagedir);
|
||||||
//jump_usermode2();
|
jump_usermode2();
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "../include/string.h"
|
#include "../include/string.h"
|
||||||
@@ -188,30 +192,16 @@ void jump_usermode2(void) {
|
|||||||
printf("Copied code to 0x%x (virt 0x%x)\n",
|
printf("Copied code to 0x%x (virt 0x%x)\n",
|
||||||
(uint32_t)code_phys, kernel_temp_virt);
|
(uint32_t)code_phys, kernel_temp_virt);
|
||||||
|
|
||||||
// Настраиваем Ring 3
|
uint32_t* proc_pd = (uint32_t*)create_page_dir();
|
||||||
uint32_t user_stack_top;
|
Process* p_task1 = task_create(0x400000, NULL, 0, 3, proc_pd);
|
||||||
uint32_t user_stack_top2;
|
|
||||||
void* user_code_virt = setup_user_process(code_phys, &user_stack_top);
|
if (map_page_in_directory(p_task1->page_directory,
|
||||||
if (!user_code_virt) {
|
code_phys,
|
||||||
printf("Failed to setup user process\n");
|
(void*)0x400000,
|
||||||
while (1);
|
PAGE_PRESENT | PAGE_RW | PAGE_USER) != 0) { // PAGE_USER is critical, PAGE_RW for now, can be R-X
|
||||||
|
|
||||||
|
printf("jump_usermode2: Failed to map user code into task's PD for PID %d\n", p_task1->pid);
|
||||||
|
// TODO: Terminate/cleanup p_task1, free code_phys_task1
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *second_user_code_virt = setup_user_process(second_code_phys, &user_stack_top2);
|
|
||||||
|
|
||||||
printf("user_code_virt: 0x%x, user_stack_top: 0x%x\n",
|
|
||||||
(uint32_t)user_code_virt, user_stack_top);
|
|
||||||
|
|
||||||
//map_page(alloc_page(), (void*)0x400000, 0x7);
|
|
||||||
map_page(alloc_page(), (void*)0x800000, 0x7);
|
|
||||||
map_page(alloc_page(), (void*)0x900000, 0x7);
|
|
||||||
|
|
||||||
uint32_t code_pte = get_pte(user_code_virt);
|
|
||||||
printf("Before iret: Code PTE at 0x%x: 0x%x (phys 0x%x, %s, %s)\n",
|
|
||||||
(uint32_t)user_code_virt, code_pte, code_pte & ~0xFFF,
|
|
||||||
(code_pte & 0x2) ? "writable" : "read-only",
|
|
||||||
(code_pte & 0x4) ? "user" : "supervisor");
|
|
||||||
|
|
||||||
task_create((uint32_t)user_code_virt, NULL, 0, 3);
|
|
||||||
//task_create((uint32_t)second_user_code_virt, NULL, 0, 3);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user