Compare commits

...

4 Commits

Author SHA1 Message Date
25a460e3c6 Scheduler: clear user tasks' registers 2022-10-12 17:12:06 +02:00
136c0b3ae9 Scheduler: add a reset_task function
This can be used later to implement execve()
2022-10-12 17:08:45 +02:00
4e3ef9593d Scheduler: Move ELF image freeing to ELFLoader 2022-10-12 17:08:17 +02:00
a6f0a7056f Scheduler: Set the user_task field in a Task at creation time
We were previously looking at its segment registers to see if they were user-like, but this method is bad.
What is the task was executing a system call?

So now, we store that value at creation time.
2022-10-12 17:07:39 +02:00
6 changed files with 50 additions and 10 deletions

View File

@ -6,4 +6,5 @@ namespace ELFLoader
{
ELFImage* load_elf_from_address(uintptr_t addr);
ELFImage* load_elf_from_filesystem(const char* filename);
void release_elf_image(ELFImage* image);
}

View File

@ -22,4 +22,6 @@ namespace Scheduler
void reap_task(Task* task);
void reap_tasks();
void reset_task(Task* task, ELFImage* new_image);
}

View File

@ -36,6 +36,8 @@ struct Task
char floating_region[512] __attribute__((aligned(16)));
bool floating_saved = false;
bool user_task = true;
bool is_user_task();
ELFImage* image = nullptr;

View File

@ -104,8 +104,10 @@ ELFImage* ELFLoader::load_elf_from_address(uintptr_t addr)
return 0;
}
uint64_t pages = Utilities::get_blocks_from_size(PAGE_SIZE, (phdr->p_vaddr % PAGE_SIZE) + phdr->p_memsz);
void* buffer = MemoryManager::get_pages_at(phdr->p_vaddr, pages,
phdr->p_flags & 2 ? MAP_READ_WRITE | MAP_USER : MAP_USER);
void* buffer = (void*)((uint64_t)MemoryManager::get_pages_at(
Utilities::round_down_to_nearest_page(phdr->p_vaddr), pages,
phdr->p_flags & 2 ? MAP_READ_WRITE | MAP_USER : MAP_USER) +
(phdr->p_vaddr % PAGE_SIZE));
memcpy(buffer, (void*)(addr + phdr->p_offset), phdr->p_filesz);
memset((void*)((uint64_t)buffer + phdr->p_filesz), 0, phdr->p_memsz - phdr->p_filesz);
image = (ELFImage*)krealloc(image, (sizeof(ELFImage) - sizeof(ELFSection)) +
@ -123,4 +125,15 @@ ELFImage* ELFLoader::load_elf_from_address(uintptr_t addr)
return 0;
}
return image;
}
void ELFLoader::release_elf_image(ELFImage* image)
{
for (uint64_t i = 0; i < image->section_count; i++)
{
ELFSection& section = image->sections[i];
kdbgln("Freeing up section %lx, was using %ld pages", section.base, section.pages);
MemoryManager::release_pages((void*)Utilities::round_down_to_nearest_page(section.base), section.pages);
}
kfree(image);
}

View File

@ -41,6 +41,7 @@ void Scheduler::init()
idle_task.regs.ss = 0x10;
idle_task.regs.rflags = (1 << 21) | (1 << 9);
idle_task.task_sleep = 1000;
idle_task.user_task = false;
idle_task.state = idle_task.Idle;
base_task = new Task;
@ -51,6 +52,7 @@ void Scheduler::init()
sched_current_task->next_task = sched_current_task;
sched_current_task->prev_task = sched_current_task;
sched_current_task->state = sched_current_task->Running;
sched_current_task->user_task = false;
task_num++;
// the other registers will be saved next task switch
@ -61,6 +63,7 @@ void Scheduler::add_kernel_task(void (*task)(void))
{
Task* new_task = new Task;
ASSERT(new_task);
new_task->user_task = false;
new_task->id = free_tid++;
new_task->regs.rip = (uint64_t)task;
new_task->allocated_stack =
@ -88,6 +91,8 @@ void Scheduler::add_user_task(void* task)
{
Task* new_task = new Task;
ASSERT(new_task);
memset(&new_task->regs, 0, sizeof(Context));
new_task->user_task = true;
new_task->id = free_tid++;
new_task->regs.rip = (uint64_t)task;
new_task->allocated_stack = (uint64_t)MemoryManager::get_pages(
@ -116,6 +121,7 @@ void Scheduler::load_user_task(const char* filename)
kinfoln("Loading user task: %s", filename);
Task* new_task = new Task;
ASSERT(new_task);
memset(&new_task->regs, 0, sizeof(Context));
new_task->id = free_tid++;
ELFImage* image = ELFLoader::load_elf_from_filesystem(filename);
if (!image)
@ -124,6 +130,7 @@ void Scheduler::load_user_task(const char* filename)
delete new_task;
return;
}
new_task->user_task = true;
new_task->regs.rip = image->entry;
new_task->image = image;
new_task->allocated_stack = (uint64_t)MemoryManager::get_pages(
@ -147,6 +154,26 @@ void Scheduler::load_user_task(const char* filename)
new_task->id, new_task->regs.rsp, task_num);
}
void Scheduler::reset_task(Task* task, ELFImage* new_image)
{
memset(&task->regs, 0, sizeof(Context));
task->state = task->Running;
task->regs.rip = new_image->entry;
task->image = new_image;
task->allocated_stack = (uint64_t)MemoryManager::get_pages(
TASK_PAGES_IN_STACK, MAP_READ_WRITE | MAP_USER); // 16 KB is enough for everyone, right?
task->regs.rsp = Utilities::get_top_of_stack(task->allocated_stack, TASK_PAGES_IN_STACK);
task->regs.cs = 0x18 | 0x03;
task->regs.ss = 0x20 | 0x03;
task->regs.ds = 0x20 | 0x03;
task->regs.rflags = (1 << 21) | (1 << 9); // enable interrupts
task->task_sleep = 0;
task->task_time = 0;
task->cpu_time = 0;
kinfoln("Resetting task: loaded at %lx, tid %ld, stack at %lx, total tasks: %ld", task->regs.rip, task->id,
task->regs.rsp, task_num);
}
void Scheduler::reap_task(Task* task)
{
ASSERT(!Interrupts::is_in_handler());
@ -158,14 +185,9 @@ void Scheduler::reap_task(Task* task)
MemoryManager::release_pages((void*)exiting_task->allocated_stack, TASK_PAGES_IN_STACK);
if (exiting_task->image) // FIXME: Also free pages the task has mmap-ed but not munmap-ed.
{
for (uint64_t i = 0; i < exiting_task->image->section_count; i++)
{
ELFSection& section = exiting_task->image->sections[i];
kdbgln("Task was using region %lx, which used %ld pages", section.base, section.pages);
MemoryManager::release_pages((void*)section.base, section.pages);
}
kfree(exiting_task->image);
ELFLoader::release_elf_image(exiting_task->image);
}
for (int i = 0; i < TASK_MAX_FDS; i++) { exiting_task->files[i].close(); }
delete exiting_task;
}

View File

@ -25,5 +25,5 @@ void task_restore_floating(Task& task)
bool Task::is_user_task()
{
return (regs.cs & 3) > 0;
return user_task;
}