Compare commits

..

No commits in common. "48fe2d4b04b06d3c734ab9112fbfa97c9aff9dc3" and "8c0478879324e0381d0aa6ed315d91eed84a6d34" have entirely different histories.

10 changed files with 15 additions and 340 deletions

View File

@ -12,8 +12,6 @@ set(SOURCES
src/boot/Init.cpp src/boot/Init.cpp
src/arch/Serial.cpp src/arch/Serial.cpp
src/arch/Timer.cpp src/arch/Timer.cpp
src/thread/Thread.cpp
src/thread/Scheduler.cpp
) )
if("${ARCH}" MATCHES "x86_64") if("${ARCH}" MATCHES "x86_64")
@ -24,7 +22,6 @@ if("${ARCH}" MATCHES "x86_64")
src/arch/x86_64/MMU.cpp src/arch/x86_64/MMU.cpp
src/arch/x86_64/CPU.cpp src/arch/x86_64/CPU.cpp
src/arch/x86_64/Timer.cpp src/arch/x86_64/Timer.cpp
src/arch/x86_64/Thread.cpp
) )
endif() endif()

View File

@ -48,7 +48,12 @@ load_tr:
ltr ax ltr ax
ret ret
extern switch_task global switch_task
switch_task:
cli
.loop:
hlt
jmp .loop
global kernel_yield global kernel_yield
kernel_yield: kernel_yield:

View File

@ -3,7 +3,6 @@
#include "arch/Timer.h" #include "arch/Timer.h"
#include "arch/x86_64/CPU.h" #include "arch/x86_64/CPU.h"
#include "arch/x86_64/IO.h" #include "arch/x86_64/IO.h"
#include "thread/Scheduler.h"
#include <cpuid.h> #include <cpuid.h>
#include <luna/Check.h> #include <luna/Check.h>
#include <luna/Result.h> #include <luna/Result.h>
@ -337,7 +336,6 @@ extern "C" void arch_interrupt_entry(Registers* regs)
else if (regs->isr == 32) else if (regs->isr == 32)
{ {
Timer::tick(); Timer::tick();
if (should_invoke_scheduler()) Scheduler::invoke(regs);
pic_eoi(regs); pic_eoi(regs);
} }
else else
@ -445,9 +443,3 @@ namespace CPU
task_state_segment.rsp[0] = top; task_state_segment.rsp[0] = top;
} }
} }
// called by kernel_yield
extern "C" void switch_task(Registers* regs)
{
Scheduler::switch_task(regs);
}

View File

@ -1,49 +0,0 @@
#include "thread/Thread.h"
#include <luna/String.h>
bool is_in_kernel(Registers* regs)
{
return regs->cs == 8;
}
void Thread::set_ip(u64 ip)
{
regs.rip = ip;
}
u64 Thread::ip()
{
return regs.rip;
}
void Thread::set_sp(u64 sp)
{
regs.rsp = sp;
}
u64 Thread::sp()
{
return regs.rsp;
}
void Thread::init_regs_kernel()
{
memset(&regs, 0, sizeof(Registers));
regs.cs = 0x08;
regs.ss = 0x10;
}
void Thread::set_arguments(u64 arg1, u64 arg2, u64 arg3, u64 arg4)
{
regs.rdi = arg1;
regs.rsi = arg2;
regs.rdx = arg3;
regs.rcx = arg4;
}
void switch_context(Thread* old_thread, Thread* new_thread, Registers* regs)
{
if (!old_thread->is_idle) memcpy(&old_thread->regs, regs, sizeof(Registers));
memcpy(regs, &new_thread->regs, sizeof(Registers));
}

View File

@ -1,35 +1,12 @@
#include "Log.h" #include "Log.h"
#include "arch/CPU.h" #include "arch/CPU.h"
#include "arch/Serial.h"
#include "arch/Timer.h" #include "arch/Timer.h"
#include "boot/Init.h" #include "boot/Init.h"
#include "config.h" #include "config.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "thread/Scheduler.h"
#include <luna/Result.h> #include <luna/Result.h>
#include <luna/Units.h> #include <luna/Units.h>
void print_in_loop()
{
while (true)
{
CPU::disable_interrupts();
Serial::printf("%lu", Scheduler::current()->id);
CPU::enable_interrupts();
}
}
void print_one_and_then_yield()
{
while (true)
{
CPU::disable_interrupts();
Serial::printf("%lu", Scheduler::current()->id);
kernel_yield();
CPU::enable_interrupts();
}
}
Result<void> init() Result<void> init()
{ {
kinfoln("Starting Moon %s", MOON_VERSION); kinfoln("Starting Moon %s", MOON_VERSION);
@ -40,6 +17,10 @@ Result<void> init()
Timer::init(); Timer::init();
CPU::platform_finish_init();
CPU::enable_interrupts();
char buffer[64]; char buffer[64];
to_dynamic_unit(MemoryManager::total(), buffer, sizeof(buffer)); to_dynamic_unit(MemoryManager::total(), buffer, sizeof(buffer));
kinfoln("Total memory: %s", buffer); kinfoln("Total memory: %s", buffer);
@ -50,20 +31,6 @@ Result<void> init()
to_dynamic_unit(MemoryManager::reserved(), buffer, sizeof(buffer)); to_dynamic_unit(MemoryManager::reserved(), buffer, sizeof(buffer));
kinfoln("Reserved memory: %s", buffer); kinfoln("Reserved memory: %s", buffer);
Scheduler::init();
TRY(Scheduler::new_kernel_thread(print_in_loop));
TRY(Scheduler::new_kernel_thread(print_in_loop));
TRY(Scheduler::new_kernel_thread(print_in_loop));
TRY(Scheduler::new_kernel_thread(print_in_loop));
TRY(Scheduler::new_kernel_thread(print_in_loop));
TRY(Scheduler::new_kernel_thread(print_in_loop));
TRY(Scheduler::new_kernel_thread(print_one_and_then_yield));
CPU::platform_finish_init();
CPU::enable_interrupts();
return {}; return {};
} }
@ -73,5 +40,5 @@ extern "C" [[noreturn]] void _start()
Init::early_init(); Init::early_init();
auto rc = init(); auto rc = init();
if (rc.has_error()) kerrorln("Runtime error: %s", rc.error_string()); if (rc.has_error()) kerrorln("Runtime error: %s", rc.error_string());
CPU::idle_loop(); CPU::efficient_halt();
} }

View File

@ -21,7 +21,6 @@ namespace KernelVM
void init() void init()
{ {
g_kernelvm_bitmap.initialize(bitmap_memory, sizeof(bitmap_memory)); g_kernelvm_bitmap.initialize(bitmap_memory, sizeof(bitmap_memory));
g_kernelvm_bitmap.clear(false);
} }
Result<u64> alloc_one_page() Result<u64> alloc_one_page()
@ -37,7 +36,7 @@ namespace KernelVM
return err(ENOMEM); return err(ENOMEM);
} }
bool find_several_pages_impl(usize count, u64& start_index) Result<u64> alloc_several_pages(usize count)
{ {
u64 first_free_index = 0; u64 first_free_index = 0;
u64 free_contiguous_pages = 0; u64 free_contiguous_pages = 0;
@ -57,22 +56,10 @@ namespace KernelVM
// Found enough contiguous free pages!! // Found enough contiguous free pages!!
if (free_contiguous_pages == count) if (free_contiguous_pages == count)
{ {
start_index = first_free_index;
return true;
}
}
return false;
}
Result<u64> alloc_several_pages(const usize count)
{
u64 start_index;
if (find_several_pages_impl(count, start_index))
{
g_kernelvm_bitmap.clear_region(start_index, count, true);
g_used_vm += ARCH_PAGE_SIZE * count; g_used_vm += ARCH_PAGE_SIZE * count;
return KERNEL_VM_RANGE_START + (start_index * ARCH_PAGE_SIZE); g_kernelvm_bitmap.clear_region(first_free_index, count, true);
return KERNEL_VM_RANGE_START + (first_free_index * ARCH_PAGE_SIZE);
}
} }
return err(ENOMEM); return err(ENOMEM);

View File

@ -1,144 +0,0 @@
#include "thread/Scheduler.h"
#include "Log.h"
#include "arch/CPU.h"
#include "arch/MMU.h"
#include "memory/KernelVM.h"
#include "memory/MemoryManager.h"
#include <luna/Stack.h>
static Thread g_idle;
static Thread* g_current = nullptr;
static const usize TICKS_PER_TIMESLICE = 20;
namespace Scheduler
{
void init()
{
g_idle.id = 0;
g_idle.init_regs_kernel();
g_idle.set_ip((u64)CPU::idle_loop);
g_idle.is_idle = true;
g_idle.ticks_left = 1;
// Map some stack for the idle task
u64 idle_stack_vm = KernelVM::alloc_one_page().release_value();
MemoryManager::alloc_at(idle_stack_vm, 1, MMU::NoExecute | MMU::ReadWrite).release_value();
Stack idle_stack{idle_stack_vm, ARCH_PAGE_SIZE};
g_idle.set_sp(idle_stack.top());
kinfoln("CREATED IDLE THREAD: id %lu with ip %lx and sp %lx", g_idle.id, g_idle.ip(), g_idle.sp());
g_current = &g_idle;
}
Thread* current()
{
return g_current;
}
Result<void> kernel_thread_alloc_stack_and_append_impl(Thread* thread)
{
// FIXME: We will leak the thread if VM allocation or alloc_at fail.
u64 thread_stack_vm = TRY(KernelVM::alloc_several_pages(4));
TRY(MemoryManager::alloc_at(thread_stack_vm, 4, MMU::NoExecute | MMU::ReadWrite));
Stack thread_stack{thread_stack_vm, ARCH_PAGE_SIZE * 4};
thread->set_sp(thread_stack.top());
g_threads.append(thread);
kinfoln("CREATED THREAD: id %lu with ip %lx and sp %lx", thread->id, thread->ip(), thread->sp());
return {};
}
Result<void> new_kernel_thread(u64 address)
{
Thread* thread = TRY(new_thread());
thread->init_regs_kernel();
thread->set_ip(address);
return kernel_thread_alloc_stack_and_append_impl(thread);
}
Result<void> new_kernel_thread(void (*func)(void))
{
Thread* thread = TRY(new_thread());
thread->init_regs_kernel();
thread->set_ip((u64)func);
return kernel_thread_alloc_stack_and_append_impl(thread);
}
Result<void> new_kernel_thread(void (*func)(void*), void* arg)
{
Thread* thread = TRY(new_thread());
thread->init_regs_kernel();
thread->set_ip((u64)func);
thread->set_arguments((u64)arg, 0, 0, 0);
return kernel_thread_alloc_stack_and_append_impl(thread);
}
Thread* pick_task()
{
Thread* old = g_current;
if (old->is_idle)
{
auto maybe_first = g_threads.last();
if (maybe_first.has_error()) // No threads!!
return &g_idle;
g_current = old = maybe_first.value();
}
do {
auto maybe_next = g_threads.next(g_current);
if (maybe_next.has_error()) g_current = g_threads.first().value();
else
g_current = maybe_next.value();
if (true) // FIXME: Check if the current task is runnable.
break;
} while (g_current != old);
return g_current;
}
void generic_switch_context(Thread* old_thread, Thread* new_thread, Registers* regs)
{
if (old_thread != new_thread) switch_context(old_thread, new_thread, regs);
if (new_thread->is_idle)
{
new_thread->ticks_left = 1; // The idle task only runs for 1 tick so we can check for new runnable tasks
// as fast as possible.
}
else
new_thread->ticks_left = TICKS_PER_TIMESLICE;
}
void switch_task(Registers* regs)
{
Thread* old_thread = g_current;
Thread* new_thread = pick_task();
generic_switch_context(old_thread, new_thread, regs);
}
void invoke(Registers* regs)
{
CPU::disable_interrupts();
g_current->ticks++;
if (is_in_kernel(regs)) g_current->ticks_in_kernel++;
else
g_current->ticks_in_user++;
g_current->ticks_left--;
if (!g_current->ticks_left) switch_task(regs);
}
}

View File

@ -1,19 +0,0 @@
#pragma once
#include "thread/Thread.h"
namespace Scheduler
{
void init();
Thread* current();
Result<void> new_kernel_thread(u64 address);
Result<void> new_kernel_thread(void (*func)(void));
Result<void> new_kernel_thread(void (*func)(void*), void* arg);
Thread* pick_task();
void switch_task(Registers* regs);
void invoke(Registers* regs);
}

View File

@ -1,15 +0,0 @@
#include "thread/Thread.h"
#include <luna/Alloc.h>
static u64 g_next_id = 1;
DoublyLinkedList<Thread> g_threads;
Result<Thread*> new_thread()
{
Thread* thread = TRY(make<Thread>());
thread->id = g_next_id++;
return thread;
}

View File

@ -1,46 +0,0 @@
#pragma once
#include "arch/CPU.h"
#include <luna/LinkedList.h>
#include <luna/Result.h>
#ifdef ARCH_X86_64
#include "arch/x86_64/CPU.h"
#else
#error "Unknown architecture."
#endif
struct Thread : public DoublyLinkedListNode<Thread>
{
Registers regs;
u64 id;
u64 ticks = 0;
u64 ticks_in_user = 0;
u64 ticks_in_kernel = 0;
u64 ticks_left;
bool is_idle = false;
void init_regs_kernel();
void init_regs_user();
void set_arguments(u64 arg1, u64 arg2, u64 arg3, u64 arg4);
void set_ip(u64 ip);
u64 ip();
void set_sp(u64 sp);
u64 sp();
};
void switch_context(Thread* old_thread, Thread* new_thread, Registers* regs);
bool is_in_kernel(Registers* regs);
Result<Thread*> new_thread();
Result<Thread*> create_idle_thread();
extern DoublyLinkedList<Thread> g_threads;