mirror of
https://github.com/usatiuk/ficus.git
synced 2025-10-29 00:27:52 +01:00
user mode tasks (kind of)
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
|
||||
add_executable(kernel.elf)
|
||||
|
||||
target_compile_options(kernel.elf PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-fstack-protector-all>)
|
||||
target_compile_options(kernel.elf PUBLIC $<$<COMPILE_LANGUAGE:C>:-fstack-protector-all>)
|
||||
target_compile_options(kernel.elf PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-fstack-protector-all -Wno-pointer-arith>)
|
||||
target_compile_options(kernel.elf PUBLIC $<$<COMPILE_LANGUAGE:C>:-fstack-protector-all -Wno-pointer-arith>)
|
||||
|
||||
add_subdirectory(./arch/)
|
||||
add_subdirectory(./kernel/)
|
||||
|
||||
@@ -187,6 +187,12 @@ void stress_tester() {
|
||||
remove_self();
|
||||
}
|
||||
|
||||
void user_task() {
|
||||
while (true) {
|
||||
__builtin_ia32_pause();
|
||||
}
|
||||
}
|
||||
|
||||
void ktask_main() {
|
||||
struct tty_funcs serial_tty = {.putchar = write_serial};
|
||||
add_tty(serial_tty);
|
||||
@@ -201,6 +207,8 @@ void ktask_main() {
|
||||
new_ktask(templates_tester, "templates_tester2");
|
||||
new_ktask(stress_tester, "stress_tester");
|
||||
|
||||
new_utask(user_task, "user");
|
||||
|
||||
remove_self();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ static inline void invlpg(void *m) {
|
||||
|
||||
AddressSpace::AddressSpace() {
|
||||
PML4 = static_cast<uint64_t *>(get4k());
|
||||
for (int j = 0; j < 512; j++)
|
||||
PML4[j] = 0;
|
||||
}
|
||||
|
||||
AddressSpace::AddressSpace(uint64_t *PML4) : PML4(PML4) {}
|
||||
@@ -121,7 +123,8 @@ int AddressSpace::map(void *virt, void *real, uint32_t flags) {
|
||||
|
||||
uint64_t *ptsb = (uint64_t *) HHDM_P2V((*pdee & 0x000FFFFFFFFFF000ULL));
|
||||
uint64_t *ptse = &ptsb[ptsi];
|
||||
*ptse = ((uint64_t) real & 0x000FFFFFFFFFF000ULL) | (flags & 0xFFF) | PAGE_PRESENT;
|
||||
// FIXME:
|
||||
*ptse = ((uint64_t) real & 0x000FFFFFFFFFF000ULL) | (flags & 0xFFF) | PAGE_PRESENT | PAGE_USER;
|
||||
invlpg((void *) ((uint64_t) virt & 0x000FFFFFFFFFF000ULL));
|
||||
return 1;
|
||||
}
|
||||
@@ -204,7 +207,8 @@ void map_hddm(uint64_t *pml4) {
|
||||
uint64_t *pdpeb = (uint64_t *) (*pml4e & 0x000FFFFFFFFFF000ULL);
|
||||
uint64_t *pdpee = &pdpeb[pdpei];
|
||||
assert2((!(*pdpee & PAGE_PRESENT)), "HHDM area is already mapped!");
|
||||
*pdpee = PAGE_RW | PAGE_PRESENT | PAGE_PS;
|
||||
// FIXME:
|
||||
*pdpee = PAGE_RW | PAGE_PRESENT | PAGE_PS | PAGE_USER;
|
||||
*pdpee |= (uint64_t) real & (uint64_t) 0x000FFFFFFFFFF000ULL;
|
||||
}
|
||||
_tlb_flush();
|
||||
|
||||
@@ -8,6 +8,16 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
|
||||
#define KERN_V2P(a) ((((uintptr_t) (a) + kernel_phys_base) & ~kernel_virt_base))
|
||||
#define KERN_P2V(a) ((((uintptr_t) (a) -kernel_phys_base) | kernel_virt_base))
|
||||
|
||||
#define HHDM_BEGIN 0xfffff80000000000ULL
|
||||
#define HHDM_SIZE 32ULL// In GB
|
||||
#define HHDM_V2P(a) ((((uintptr_t) (a)) & ~HHDM_BEGIN))
|
||||
#define HHDM_P2V(a) ((((uintptr_t) (a)) | HHDM_BEGIN))
|
||||
|
||||
class AddressSpace {
|
||||
public:
|
||||
AddressSpace();
|
||||
@@ -18,6 +28,14 @@ public:
|
||||
int map(void *virt, void *real, uint32_t flags);
|
||||
int unmap(void *virt);
|
||||
|
||||
uint64_t *get_cr3() {
|
||||
return PML4;
|
||||
}
|
||||
|
||||
uint64_t *get_cr3_phys() {
|
||||
return (uint64_t *) HHDM_V2P(PML4);
|
||||
}
|
||||
|
||||
private:
|
||||
// Pointer to PML4 in HDDM
|
||||
uint64_t *PML4;
|
||||
@@ -29,16 +47,6 @@ extern uintptr_t kernel_phys_base;
|
||||
extern uintptr_t kernel_virt_base;
|
||||
void limine_kern_save_response();
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
|
||||
#define KERN_V2P(a) ((((uintptr_t) (a) + kernel_phys_base) & ~kernel_virt_base))
|
||||
#define KERN_P2V(a) ((((uintptr_t) (a) -kernel_phys_base) | kernel_virt_base))
|
||||
|
||||
#define HHDM_BEGIN 0xfffff80000000000ULL
|
||||
#define HHDM_SIZE 32ULL// In GB
|
||||
#define HHDM_V2P(a) ((((uintptr_t) (a)) & ~HHDM_BEGIN))
|
||||
#define HHDM_P2V(a) ((((uintptr_t) (a)) | HHDM_BEGIN))
|
||||
|
||||
#define PAGE_PS (1 << 7)
|
||||
#define PAGE_RW (1 << 1)
|
||||
#define PAGE_USER (1 << 2)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "LockGuard.hpp"
|
||||
#include "SkipList.hpp"
|
||||
#include "Spinlock.hpp"
|
||||
#include "VMA.hpp"
|
||||
#include "asserts.hpp"
|
||||
#include "gdt.hpp"
|
||||
#include "kmem.hpp"
|
||||
@@ -23,7 +24,7 @@ void sanity_check_frame(struct task_frame *cur_frame) {
|
||||
assert2((void *) cur_frame->ip != NULL, "Sanity check");
|
||||
assert2((void *) cur_frame->sp != NULL, "Sanity check");
|
||||
assert2(cur_frame->guard == IDT_GUARD, "IDT Guard wrong!");
|
||||
assert2((cur_frame->ss == GDTSEL(gdt_data) || cur_frame->ss == GDTSEL(gdt_data_user)), "SS wrong!");
|
||||
assert2((cur_frame->ss == GDTSEL(gdt_data) || cur_frame->ss == GDTSEL(gdt_data_user)) | 0x3, "SS wrong!");
|
||||
}
|
||||
|
||||
std::atomic<uint64_t> max_pid = 0;
|
||||
@@ -123,6 +124,50 @@ struct Task *new_ktask(void (*fn)(), const char *name) {
|
||||
}
|
||||
return newt;
|
||||
}
|
||||
struct Task *new_utask(void (*fn)(), const char *name) {
|
||||
struct Task *newt = static_cast<Task *>(kmalloc(sizeof(struct Task)));
|
||||
newt->stack = static_cast<uint64_t *>(kmalloc(TASK_SS));
|
||||
newt->name = static_cast<char *>(kmalloc(strlen(name) + 1));
|
||||
newt->fxsave = static_cast<char *>(kmalloc(512));
|
||||
strcpy(name, newt->name);
|
||||
|
||||
newt->frame.sp = ((((uintptr_t) newt->stack) + (TASK_SS - 9) - 1) & (~0xFULL)) + 8;// Ensure 16byte alignment
|
||||
// It should be aligned before call, therefore on function entry it should be misaligned by 8 bytes
|
||||
assert((newt->frame.sp & 0xFULL) == 8);
|
||||
|
||||
newt->frame.ip = (uint64_t) fn;
|
||||
newt->frame.cs = GDTSEL(gdt_code_user) | 0x3;
|
||||
newt->frame.ss = GDTSEL(gdt_data_user) | 0x3;
|
||||
|
||||
for (int i = 0; i < 512; i++) newt->fxsave[i] = 0;
|
||||
|
||||
newt->frame.flags = flags();
|
||||
newt->frame.guard = IDT_GUARD;
|
||||
newt->addressSpace = new AddressSpace();
|
||||
newt->vma = new VMA(newt->addressSpace);
|
||||
newt->state = TS_RUNNING;
|
||||
newt->mode = TASKMODE_USER;
|
||||
newt->pid = max_pid.fetch_add(1);
|
||||
newt->used_time = 0;
|
||||
|
||||
newt->vma->map_kern();
|
||||
|
||||
sanity_check_frame(&newt->frame);
|
||||
|
||||
auto new_node = NextTasks.create_node(newt);
|
||||
|
||||
{
|
||||
LockGuard l(NextTasks_lock);
|
||||
NextTasks.emplace_front(new_node);
|
||||
}
|
||||
|
||||
{
|
||||
LockGuard l(AllTasks_lock);
|
||||
AllTasks.add(newt->pid, newt);
|
||||
}
|
||||
return newt;
|
||||
}
|
||||
|
||||
|
||||
void remove_self() {
|
||||
{
|
||||
@@ -220,9 +265,12 @@ extern "C" void switch_task(struct task_frame *cur_frame) {
|
||||
uint64_t prevSwitchMicros = lastSwitchMicros;
|
||||
lastSwitchMicros = micros;
|
||||
|
||||
AddressSpace *oldspace = nullptr;
|
||||
|
||||
if (RunningTask) {
|
||||
RunningTask->val->frame = *cur_frame;
|
||||
__builtin_memcpy(RunningTask->val->fxsave, temp_fxsave, 512);
|
||||
oldspace = RunningTask->val->addressSpace;
|
||||
RunningTask->val->used_time.fetch_add(lastSwitchMicros - prevSwitchMicros);
|
||||
if (RunningTask->val->state == TS_RUNNING) {
|
||||
NextTasks.emplace_front(RunningTask);
|
||||
@@ -240,6 +288,16 @@ extern "C" void switch_task(struct task_frame *cur_frame) {
|
||||
*cur_frame = RunningTask->val->frame;
|
||||
__builtin_memcpy(temp_fxsave, RunningTask->val->fxsave, 512);
|
||||
|
||||
AddressSpace *newspace = RunningTask->val->addressSpace;
|
||||
|
||||
if (newspace != oldspace) {
|
||||
uint64_t real_new_cr3 = (uint64_t) HHDM_V2P(newspace->get_cr3());
|
||||
__asm__ volatile("movq %[real_new_cr3], %%cr3"
|
||||
:
|
||||
: [real_new_cr3] "r"(real_new_cr3)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
sanity_check_frame(cur_frame);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,11 +24,15 @@ enum TaskState {
|
||||
TS_BLOCKED
|
||||
};
|
||||
|
||||
struct AddressSpace;
|
||||
class VMA;
|
||||
|
||||
struct Task {
|
||||
struct task_frame frame;
|
||||
uint64_t pid;
|
||||
std::atomic<uint64_t> used_time;
|
||||
struct AddressSpace *addressSpace;
|
||||
AddressSpace *addressSpace;
|
||||
VMA *vma;
|
||||
uint64_t *stack;
|
||||
char *fxsave;
|
||||
char *name;
|
||||
@@ -42,6 +46,7 @@ List<Task *>::Node *extract_running_task_node();
|
||||
|
||||
void init_tasks();
|
||||
struct Task *new_ktask(void (*fn)(), const char *name);
|
||||
struct Task *new_utask(void (*fn)(), const char *name);
|
||||
void remove_self();
|
||||
void sleep_self(uint64_t diff);
|
||||
|
||||
|
||||
37
src/kernel/VMA.cpp
Normal file
37
src/kernel/VMA.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Created by Stepan Usatiuk on 26.10.2023.
|
||||
//
|
||||
|
||||
#include "VMA.hpp"
|
||||
|
||||
#include "asserts.hpp"
|
||||
#include "kmem.hpp"
|
||||
#include "memman.hpp"
|
||||
#include "paging.hpp"
|
||||
|
||||
VMA::VMA(AddressSpace *space) : space(space) {
|
||||
}
|
||||
|
||||
void VMA::mark_taken(void *addr, size_t length) {
|
||||
}
|
||||
|
||||
void VMA::map_kern() {
|
||||
for (uintptr_t i = (uint64_t) (0xFFF8000000000000ULL >> 39) & 0x01FF; i < 512; i++) {
|
||||
space->get_cr3()[i] = KERN_AddressSpace->get_cr3()[i];
|
||||
}
|
||||
}
|
||||
|
||||
void *VMA::mmap_phys(void *v_addr, void *real_addr, size_t length, int flags) {
|
||||
assert((((uintptr_t) v_addr) & PAGE_SIZE) == 0);
|
||||
|
||||
for (size_t i = 0; i < length; i += PAGE_SIZE) {
|
||||
space->map(v_addr + i, real_addr + i, flags);
|
||||
}
|
||||
return v_addr;
|
||||
}
|
||||
void *VMA::mmap_mem_any(size_t length, int prot, int flags) {
|
||||
return nullptr;
|
||||
}
|
||||
int VMA::munmap(void *addr, size_t length) {
|
||||
return 0;
|
||||
}
|
||||
31
src/kernel/VMA.hpp
Normal file
31
src/kernel/VMA.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// Created by Stepan Usatiuk on 26.10.2023.
|
||||
//
|
||||
|
||||
#ifndef OS2_VMA_HPP
|
||||
#define OS2_VMA_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
class AddressSpace;
|
||||
|
||||
class VMA {
|
||||
public:
|
||||
VMA(AddressSpace *space);
|
||||
|
||||
void mark_taken(void *addr, size_t length);
|
||||
|
||||
/// Map all higher-half pages into the address space
|
||||
/// By linking them to same entries as kernel
|
||||
void map_kern();
|
||||
void *mmap_phys(void *v_addr, void *real_addr, size_t length, int flags);
|
||||
void *mmap_mem_any(size_t length, int prot, int flags);
|
||||
int munmap(void *addr, size_t length);
|
||||
|
||||
private:
|
||||
AddressSpace *space = nullptr;
|
||||
};
|
||||
|
||||
|
||||
#endif//OS2_VMA_HPP
|
||||
Reference in New Issue
Block a user