tasking: isolate ring3 tasks

This commit is contained in:
2025-06-01 01:24:31 +03:00
parent f47a4a451d
commit 8fea7a8ec6
4 changed files with 86 additions and 40 deletions
+60 -5
View File
@@ -18,7 +18,7 @@ uint32_t get_pte(void *virtualaddr) {
}
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) {
printf("SETUP_USER_PROCESS ERROR: user_code_phys not aligned\n");
return 0;
@@ -36,12 +36,12 @@ void* setup_user_process(void* user_code_phys, uint32_t* user_stack_top) {
return 0;
}
unmap_page((void*)code_virt);
unmap_page((void*)stack_virt);
//unmap_page((void*)code_virt);
//unmap_page((void*)stack_virt);
map_page(user_code_phys, (void*)code_virt, 0x7);
map_page(stack_phys, (void*)stack_virt, 0x7);
map_page_in_directory(pd, user_code_phys, (void*)code_virt, 0x7);
map_page_in_directory(pd, stack_phys, (void*)stack_virt, 0x7);
// Verify mappings
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) {
uint32_t virt = (uint32_t)virtualaddr & ~0xFFF; // Выравниваем по 4 КБ
if (virt < 0xC0000000) while(1); // Ошибка: ядро только выше 3 ГБ