Compare commits
No commits in common. "0ea9974512adb8cf58974646b0421669e2c6f96f" and "f0e14cf7e9380b222b220b2de3478b197481a888" have entirely different histories.
0ea9974512
...
f0e14cf7e9
14
apps/app.asm
14
apps/app.asm
@ -1,4 +1,18 @@
|
|||||||
section .text
|
section .text
|
||||||
global _start
|
global _start
|
||||||
_start:
|
_start:
|
||||||
|
mov eax, ecx
|
||||||
|
push rdx
|
||||||
|
mov eax, 1
|
||||||
|
mov edi, hello_world
|
||||||
|
mov esi, 14
|
||||||
int 42h
|
int 42h
|
||||||
|
nop
|
||||||
|
|
||||||
|
section .rodata
|
||||||
|
hello_world:
|
||||||
|
db 'Hello, world!', 0xa, 0
|
||||||
|
|
||||||
|
section .bss
|
||||||
|
array:
|
||||||
|
resb 10
|
@ -23,11 +23,19 @@ static bool can_write_segment(u32 flags)
|
|||||||
return can_write_segment(flags) && can_execute_segment(flags);
|
return can_write_segment(flags) && can_execute_segment(flags);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
ELFSegment::ELFSegment(u64 base, usize size) : m_base(base), m_size(size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
namespace ELFLoader
|
namespace ELFLoader
|
||||||
{
|
{
|
||||||
// FIXME: Check that all calls to read_contents() read the proper amount of bytes.
|
// FIXME: Check that all calls to read_contents() read the proper amount of bytes.
|
||||||
Result<ELFData> load(const TarStream::Entry& elf_entry, const TarStream& stream)
|
Result<ELFData> load(const TarStream::Entry& elf_entry, const TarStream& stream)
|
||||||
{
|
{
|
||||||
|
LinkedList<ELFSegment> segments;
|
||||||
|
|
||||||
|
auto guard = make_scope_guard([&] { segments.consume([](ELFSegment* segment) { delete segment; }); });
|
||||||
|
|
||||||
Elf64_Ehdr elf_header;
|
Elf64_Ehdr elf_header;
|
||||||
usize nread = stream.read_contents(elf_entry, &elf_header, 0, sizeof elf_header);
|
usize nread = stream.read_contents(elf_entry, &elf_header, 0, sizeof elf_header);
|
||||||
if (nread < sizeof elf_header)
|
if (nread < sizeof elf_header)
|
||||||
@ -93,6 +101,9 @@ namespace ELFLoader
|
|||||||
/*expect(!can_write_and_execute_segment(program_header.p_flags),
|
/*expect(!can_write_and_execute_segment(program_header.p_flags),
|
||||||
"Segment is both writable and executable");*/
|
"Segment is both writable and executable");*/
|
||||||
|
|
||||||
|
ELFSegment* segment = TRY(make<ELFSegment>(program_header.p_vaddr, program_header.p_memsz));
|
||||||
|
segments.append(segment);
|
||||||
|
|
||||||
int flags = MMU::User | MMU::NoExecute;
|
int flags = MMU::User | MMU::NoExecute;
|
||||||
if (can_write_segment(program_header.p_flags)) flags |= MMU::ReadWrite;
|
if (can_write_segment(program_header.p_flags)) flags |= MMU::ReadWrite;
|
||||||
else if (can_execute_segment(program_header.p_flags))
|
else if (can_execute_segment(program_header.p_flags))
|
||||||
@ -113,6 +124,14 @@ namespace ELFLoader
|
|||||||
else { kdbgln("ELF: Encountered non-loadable program header, skipping"); }
|
else { kdbgln("ELF: Encountered non-loadable program header, skipping"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
return ELFData { elf_header.e_entry };
|
if (segments.count() == 0)
|
||||||
|
{
|
||||||
|
kdbgln("Error while loading ELF: No loadable segments");
|
||||||
|
return err(ENOEXEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
guard.deactivate();
|
||||||
|
|
||||||
|
return ELFData { segments, elf_header.e_entry };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,8 +47,28 @@ typedef struct
|
|||||||
u64 p_align; /* Segment alignment */
|
u64 p_align; /* Segment alignment */
|
||||||
} Elf64_Phdr;
|
} Elf64_Phdr;
|
||||||
|
|
||||||
|
struct ELFSegment : public LinkedListNode<ELFSegment>
|
||||||
|
{
|
||||||
|
u64 base() const
|
||||||
|
{
|
||||||
|
return m_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
usize size() const
|
||||||
|
{
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
ELFSegment(u64 base, usize size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
u64 m_base;
|
||||||
|
usize m_size;
|
||||||
|
};
|
||||||
|
|
||||||
struct ELFData
|
struct ELFData
|
||||||
{
|
{
|
||||||
|
LinkedList<ELFSegment> segments;
|
||||||
u64 entry;
|
u64 entry;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,7 +31,6 @@ namespace MMU
|
|||||||
void flush_all();
|
void flush_all();
|
||||||
|
|
||||||
Result<PageDirectory*> create_page_directory_for_userspace();
|
Result<PageDirectory*> create_page_directory_for_userspace();
|
||||||
Result<void> delete_userspace_page_directory(PageDirectory* directory);
|
|
||||||
void setup_initial_page_directory();
|
void setup_initial_page_directory();
|
||||||
|
|
||||||
PageDirectory* kernel_page_directory();
|
PageDirectory* kernel_page_directory();
|
||||||
|
@ -187,5 +187,4 @@ ISR 20 ; virtualization exception (#VE)
|
|||||||
ISR_ERROR 21 ; control-protection exception (#CP)
|
ISR_ERROR 21 ; control-protection exception (#CP)
|
||||||
; ISR 22-31 reserved
|
; ISR 22-31 reserved
|
||||||
IRQ 32, 0 ; timer interrupt
|
IRQ 32, 0 ; timer interrupt
|
||||||
IRQ 33, 0 ; keyboard interrupt
|
IRQ 33, 0 ; keyboard interrupt
|
||||||
ISR 66 ; user exit
|
|
@ -107,12 +107,6 @@ extern "C" void arch_interrupt_entry(Registers* regs)
|
|||||||
scancode_queue.try_push(scancode);
|
scancode_queue.try_push(scancode);
|
||||||
pic_eoi(regs);
|
pic_eoi(regs);
|
||||||
}
|
}
|
||||||
else if (regs->isr == 66) // Exit!!
|
|
||||||
{
|
|
||||||
kdbgln("exiting from user task!!");
|
|
||||||
Scheduler::current()->state = ThreadState::Dying;
|
|
||||||
kernel_yield();
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
kwarnln("IRQ catched! Halting.");
|
kwarnln("IRQ catched! Halting.");
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include <luna/CString.h>
|
#include <luna/CString.h>
|
||||||
#include <luna/Result.h>
|
#include <luna/Result.h>
|
||||||
#include <luna/ScopeGuard.h>
|
|
||||||
#include <luna/SystemError.h>
|
#include <luna/SystemError.h>
|
||||||
|
|
||||||
#pragma GCC push_options
|
#pragma GCC push_options
|
||||||
@ -51,16 +50,11 @@ namespace MMU
|
|||||||
return l4_table()->entries[l4_index(addr)];
|
return l4_table()->entries[l4_index(addr)];
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr PageDirectory* raw_l3_table(u64 l4)
|
|
||||||
{
|
|
||||||
const u64 l3 = sign | (rindex << 39) | (rindex << 30) | (rindex << 21) | (l4 << 12);
|
|
||||||
return (PageDirectory*)l3;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr PageDirectory* l3_table(u64 addr)
|
constexpr PageDirectory* l3_table(u64 addr)
|
||||||
{
|
{
|
||||||
const u64 l4 = l4_index(addr);
|
const u64 l4 = l4_index(addr);
|
||||||
return raw_l3_table(l4);
|
const u64 l3 = sign | (rindex << 39) | (rindex << 30) | (rindex << 21) | (l4 << 12);
|
||||||
|
return (PageDirectory*)l3;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u64 l3_index(u64 addr)
|
constexpr u64 l3_index(u64 addr)
|
||||||
@ -73,17 +67,12 @@ namespace MMU
|
|||||||
return l3_table(addr)->entries[l3_index(addr)];
|
return l3_table(addr)->entries[l3_index(addr)];
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr PageDirectory* raw_l2_table(u64 l4, u64 l3)
|
|
||||||
{
|
|
||||||
const u64 l2 = sign | (rindex << 39) | (rindex << 30) | (l4 << 21) | (l3 << 12);
|
|
||||||
return (PageDirectory*)l2;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr PageDirectory* l2_table(u64 addr)
|
constexpr PageDirectory* l2_table(u64 addr)
|
||||||
{
|
{
|
||||||
const u64 l4 = l4_index(addr);
|
const u64 l4 = l4_index(addr);
|
||||||
const u64 l3 = l3_index(addr);
|
const u64 l3 = l3_index(addr);
|
||||||
return raw_l2_table(l4, l3);
|
const u64 l2 = sign | (rindex << 39) | (rindex << 30) | (l4 << 21) | (l3 << 12);
|
||||||
|
return (PageDirectory*)l2;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u64 l2_index(u64 addr)
|
constexpr u64 l2_index(u64 addr)
|
||||||
@ -96,18 +85,13 @@ namespace MMU
|
|||||||
return l2_table(addr)->entries[l2_index(addr)];
|
return l2_table(addr)->entries[l2_index(addr)];
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr PageDirectory* raw_l1_table(u64 l4, u64 l3, u64 l2)
|
|
||||||
{
|
|
||||||
const u64 l1 = sign | (rindex << 39) | (l4 << 30) | (l3 << 21) | (l2 << 12);
|
|
||||||
return (PageDirectory*)l1;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr PageDirectory* l1_table(u64 addr)
|
constexpr PageDirectory* l1_table(u64 addr)
|
||||||
{
|
{
|
||||||
const u64 l4 = l4_index(addr);
|
const u64 l4 = l4_index(addr);
|
||||||
const u64 l3 = l3_index(addr);
|
const u64 l3 = l3_index(addr);
|
||||||
const u64 l2 = l2_index(addr);
|
const u64 l2 = l2_index(addr);
|
||||||
return raw_l1_table(l4, l3, l2);
|
const u64 l1 = sign | (rindex << 39) | (l4 << 30) | (l3 << 21) | (l2 << 12);
|
||||||
|
return (PageDirectory*)l1;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u64 l1_index(u64 addr)
|
constexpr u64 l1_index(u64 addr)
|
||||||
@ -286,96 +270,6 @@ namespace MMU
|
|||||||
flush_all();
|
flush_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<PageDirectory*> create_page_directory_for_userspace()
|
|
||||||
{
|
|
||||||
u64 directory_virt = TRY(MemoryManager::alloc_for_kernel(1, MMU::ReadWrite | MMU::NoExecute));
|
|
||||||
u64 directory_phys = MMU::get_physical(directory_virt).value();
|
|
||||||
|
|
||||||
PageDirectory* directory = (PageDirectory*)directory_virt;
|
|
||||||
memset(directory, 0, ARCH_PAGE_SIZE);
|
|
||||||
PageTableEntry& recursive_entry = directory->entries[rindex];
|
|
||||||
recursive_entry.read_write = true;
|
|
||||||
recursive_entry.present = true;
|
|
||||||
recursive_entry.set_address(directory_phys);
|
|
||||||
|
|
||||||
directory->entries[511] = g_kernel_directory->entries[511];
|
|
||||||
|
|
||||||
// From now on, we're only going to use the physical address, since accessing the PageDirectory will be dealt
|
|
||||||
// with using recursive mapping. So let's make sure we don't leak any VM.
|
|
||||||
MemoryManager::unmap_weak_and_free_vm(directory_virt, 1);
|
|
||||||
|
|
||||||
return (PageDirectory*)directory_phys;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> delete_userspace_page_directory(PageDirectory* directory)
|
|
||||||
{
|
|
||||||
check(directory);
|
|
||||||
|
|
||||||
// Needed in order to access page tables using the recursive mapping system.
|
|
||||||
switch_page_directory(directory);
|
|
||||||
|
|
||||||
auto guard = make_scope_guard([&] {
|
|
||||||
check(g_kernel_directory);
|
|
||||||
switch_page_directory(g_kernel_directory);
|
|
||||||
MemoryManager::free_frame((u64)directory);
|
|
||||||
});
|
|
||||||
|
|
||||||
PageDirectory* table = l4_table();
|
|
||||||
|
|
||||||
// Let's iterate over every top-level entry, skipping the last two entries (recursive mapping and kernel pages)
|
|
||||||
for (u64 i = 0; i < 510; i++)
|
|
||||||
{
|
|
||||||
PageTableEntry& l4 = table->entries[i];
|
|
||||||
if (!l4.present) continue;
|
|
||||||
|
|
||||||
PageDirectory* pdp = raw_l3_table(i);
|
|
||||||
|
|
||||||
for (u64 j = 0; j < 512; j++)
|
|
||||||
{
|
|
||||||
PageTableEntry& l3 = pdp->entries[j];
|
|
||||||
if (!l3.present) continue;
|
|
||||||
if (l3.larger_pages)
|
|
||||||
{
|
|
||||||
// FIXME: Maybe we shouldn't delete some pages in an address space, such as shared memory.
|
|
||||||
TRY(MemoryManager::free_frame(l3.get_address()));
|
|
||||||
}
|
|
||||||
|
|
||||||
PageDirectory* pd = raw_l2_table(i, j);
|
|
||||||
|
|
||||||
for (u64 k = 0; k < 512; k++)
|
|
||||||
{
|
|
||||||
PageTableEntry& l2 = pd->entries[k];
|
|
||||||
if (!l2.present) continue;
|
|
||||||
if (l2.larger_pages)
|
|
||||||
{
|
|
||||||
// FIXME: Maybe we shouldn't delete some pages in an address space, such as shared memory.
|
|
||||||
TRY(MemoryManager::free_frame(l2.get_address()));
|
|
||||||
}
|
|
||||||
|
|
||||||
PageDirectory* pt = raw_l1_table(i, j, k);
|
|
||||||
|
|
||||||
for (u64 l = 0; l < 512; l++)
|
|
||||||
{
|
|
||||||
PageTableEntry& l1 = pt->entries[l];
|
|
||||||
if (!l1.present) continue;
|
|
||||||
|
|
||||||
// FIXME: Maybe we shouldn't delete some pages in an address space, such as shared memory.
|
|
||||||
TRY(MemoryManager::free_frame(l1.get_address()));
|
|
||||||
}
|
|
||||||
|
|
||||||
TRY(MemoryManager::free_frame(l2.get_address()));
|
|
||||||
}
|
|
||||||
|
|
||||||
TRY(MemoryManager::free_frame(l3.get_address()));
|
|
||||||
}
|
|
||||||
|
|
||||||
TRY(MemoryManager::free_frame(l4.get_address()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// No need to clean up manually, the ScopeGuard we set up earlier will do that for us.
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
PageDirectory* kernel_page_directory()
|
PageDirectory* kernel_page_directory()
|
||||||
{
|
{
|
||||||
return g_kernel_directory;
|
return g_kernel_directory;
|
||||||
|
@ -36,7 +36,7 @@ u64 IDTEntry::get_offset() const
|
|||||||
static IDTEntry idt[256];
|
static IDTEntry idt[256];
|
||||||
|
|
||||||
#define IDT_TA_InterruptGate 0b10001110
|
#define IDT_TA_InterruptGate 0b10001110
|
||||||
#define IDT_TA_UserCallableInterruptGate 0b11101110
|
#define IDT_TA_UserInterruptGate 0b11101110
|
||||||
#define IDT_TA_TrapGate 0b10001111
|
#define IDT_TA_TrapGate 0b10001111
|
||||||
|
|
||||||
struct [[gnu::packed]] IDTR
|
struct [[gnu::packed]] IDTR
|
||||||
@ -60,7 +60,6 @@ static void idt_add_handler(short num, void* handler, u8 type_attr)
|
|||||||
#define INT(x) extern "C" void _isr##x()
|
#define INT(x) extern "C" void _isr##x()
|
||||||
#define TRAP(x) idt_add_handler(x, (void*)_isr##x, IDT_TA_TrapGate)
|
#define TRAP(x) idt_add_handler(x, (void*)_isr##x, IDT_TA_TrapGate)
|
||||||
#define IRQ(x) idt_add_handler(x, (void*)_isr##x, IDT_TA_InterruptGate)
|
#define IRQ(x) idt_add_handler(x, (void*)_isr##x, IDT_TA_InterruptGate)
|
||||||
#define SYS(x) idt_add_handler(x, (void*)_isr##x, IDT_TA_UserCallableInterruptGate)
|
|
||||||
|
|
||||||
INT(0);
|
INT(0);
|
||||||
INT(1);
|
INT(1);
|
||||||
@ -84,7 +83,6 @@ INT(20);
|
|||||||
INT(21);
|
INT(21);
|
||||||
INT(32);
|
INT(32);
|
||||||
INT(33);
|
INT(33);
|
||||||
INT(66);
|
|
||||||
|
|
||||||
void setup_idt()
|
void setup_idt()
|
||||||
{
|
{
|
||||||
@ -112,7 +110,6 @@ void setup_idt()
|
|||||||
TRAP(21);
|
TRAP(21);
|
||||||
IRQ(32);
|
IRQ(32);
|
||||||
IRQ(33);
|
IRQ(33);
|
||||||
SYS(66);
|
|
||||||
|
|
||||||
static IDTR idtr;
|
static IDTR idtr;
|
||||||
idtr.limit = 0x0FFF;
|
idtr.limit = 0x0FFF;
|
||||||
|
@ -51,8 +51,7 @@ Result<void> init()
|
|||||||
kinfoln("Used memory: %s", to_dynamic_unit(MemoryManager::used()).release_value().chars());
|
kinfoln("Used memory: %s", to_dynamic_unit(MemoryManager::used()).release_value().chars());
|
||||||
kinfoln("Reserved memory: %s", to_dynamic_unit(MemoryManager::reserved()).release_value().chars());
|
kinfoln("Reserved memory: %s", to_dynamic_unit(MemoryManager::reserved()).release_value().chars());
|
||||||
|
|
||||||
Thread::init();
|
MMU::unmap(0x400000);
|
||||||
Scheduler::init();
|
|
||||||
|
|
||||||
TarStream::Entry entry;
|
TarStream::Entry entry;
|
||||||
while (TRY(g_initrd.read_next_entry().try_set_value_with_specific_error(entry, 0)))
|
while (TRY(g_initrd.read_next_entry().try_set_value_with_specific_error(entry, 0)))
|
||||||
@ -62,10 +61,18 @@ Result<void> init()
|
|||||||
kinfoln("Found file %s in initial ramdisk, of size %s", entry.name,
|
kinfoln("Found file %s in initial ramdisk, of size %s", entry.name,
|
||||||
to_dynamic_unit(entry.size).release_value().chars());
|
to_dynamic_unit(entry.size).release_value().chars());
|
||||||
|
|
||||||
if (!strcmp(entry.name, "bin/app")) { TRY(Scheduler::new_userspace_thread(entry, g_initrd)); }
|
if (!strcmp(entry.name, "bin/app"))
|
||||||
|
{
|
||||||
|
auto data = TRY(ELFLoader::load(entry, g_initrd));
|
||||||
|
data.segments.consume([](ELFSegment* segment) { delete segment; });
|
||||||
|
kinfoln("Loaded ELF with entry=%#.16lx", data.entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Thread::init();
|
||||||
|
Scheduler::init();
|
||||||
|
|
||||||
TRY(Scheduler::new_kernel_thread(heap_thread));
|
TRY(Scheduler::new_kernel_thread(heap_thread));
|
||||||
TRY(Scheduler::new_kernel_thread(reap_thread));
|
TRY(Scheduler::new_kernel_thread(reap_thread));
|
||||||
|
|
||||||
|
@ -309,15 +309,6 @@ namespace MemoryManager
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> unmap_weak_and_free_vm(u64 virt, usize count)
|
|
||||||
{
|
|
||||||
CHECK_PAGE_ALIGNED(virt);
|
|
||||||
|
|
||||||
KernelVM::free_several_pages(virt, count);
|
|
||||||
|
|
||||||
return unmap_weak(virt, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> remap_unaligned(u64 address, usize count, int flags)
|
Result<void> remap_unaligned(u64 address, usize count, int flags)
|
||||||
{
|
{
|
||||||
if (!is_aligned<ARCH_PAGE_SIZE>(address)) count++;
|
if (!is_aligned<ARCH_PAGE_SIZE>(address)) count++;
|
||||||
|
@ -30,7 +30,6 @@ namespace MemoryManager
|
|||||||
Result<void> unmap_owned(u64 virt, usize count);
|
Result<void> unmap_owned(u64 virt, usize count);
|
||||||
Result<void> unmap_owned_and_free_vm(u64 virt, usize count);
|
Result<void> unmap_owned_and_free_vm(u64 virt, usize count);
|
||||||
Result<void> unmap_weak(u64 virt, usize count);
|
Result<void> unmap_weak(u64 virt, usize count);
|
||||||
Result<void> unmap_weak_and_free_vm(u64 virt, usize count);
|
|
||||||
|
|
||||||
usize free();
|
usize free();
|
||||||
usize used();
|
usize used();
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include "ELF.h"
|
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "arch/CPU.h"
|
#include "arch/CPU.h"
|
||||||
#include "arch/MMU.h"
|
#include "arch/MMU.h"
|
||||||
@ -20,7 +19,6 @@ namespace Scheduler
|
|||||||
g_idle.init_regs_kernel();
|
g_idle.init_regs_kernel();
|
||||||
g_idle.set_ip((u64)CPU::idle_loop);
|
g_idle.set_ip((u64)CPU::idle_loop);
|
||||||
g_idle.state = ThreadState::Idle;
|
g_idle.state = ThreadState::Idle;
|
||||||
g_idle.is_kernel = true;
|
|
||||||
|
|
||||||
g_idle.ticks_left = 1;
|
g_idle.ticks_left = 1;
|
||||||
|
|
||||||
@ -62,8 +60,6 @@ namespace Scheduler
|
|||||||
|
|
||||||
thread->stack = thread_stack;
|
thread->stack = thread_stack;
|
||||||
|
|
||||||
thread->is_kernel = true;
|
|
||||||
|
|
||||||
g_threads.append(thread);
|
g_threads.append(thread);
|
||||||
|
|
||||||
kinfoln("CREATED THREAD: id %lu with ip %lx and sp %lx", thread->id, thread->ip(), thread->sp());
|
kinfoln("CREATED THREAD: id %lu with ip %lx and sp %lx", thread->id, thread->ip(), thread->sp());
|
||||||
@ -99,84 +95,13 @@ namespace Scheduler
|
|||||||
return new_kernel_thread_impl(thread);
|
return new_kernel_thread_impl(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result<void> create_stacks(Stack& user_stack, Stack& kernel_stack)
|
|
||||||
{
|
|
||||||
const u64 THREAD_STACK_BASE = 0x10000;
|
|
||||||
|
|
||||||
TRY(MemoryManager::alloc_at(THREAD_STACK_BASE, 4, MMU::ReadWrite | MMU::NoExecute | MMU::User));
|
|
||||||
|
|
||||||
auto guard = make_scope_guard([&] { MemoryManager::unmap_owned(THREAD_STACK_BASE, 4); });
|
|
||||||
|
|
||||||
u64 kernel_stack_base = TRY(MemoryManager::alloc_for_kernel(4, MMU::ReadWrite | MMU::NoExecute));
|
|
||||||
|
|
||||||
guard.deactivate();
|
|
||||||
|
|
||||||
user_stack = { THREAD_STACK_BASE, 4 * ARCH_PAGE_SIZE };
|
|
||||||
kernel_stack = { kernel_stack_base, 4 * ARCH_PAGE_SIZE };
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> new_userspace_thread(const TarStream::Entry& entry, const TarStream& stream)
|
|
||||||
{
|
|
||||||
Thread* thread = TRY(new_thread());
|
|
||||||
|
|
||||||
thread->is_kernel = false;
|
|
||||||
|
|
||||||
auto guard = make_scope_guard([&] { delete thread; });
|
|
||||||
|
|
||||||
auto directory = TRY(MMU::create_page_directory_for_userspace());
|
|
||||||
|
|
||||||
auto directory_guard = make_scope_guard([&] {
|
|
||||||
MMU::switch_page_directory(MMU::kernel_page_directory());
|
|
||||||
MemoryManager::free_frame((u64)directory);
|
|
||||||
});
|
|
||||||
|
|
||||||
MMU::switch_page_directory(directory);
|
|
||||||
|
|
||||||
thread->init_regs_user();
|
|
||||||
|
|
||||||
auto data = TRY(ELFLoader::load(entry, stream));
|
|
||||||
|
|
||||||
thread->set_ip(data.entry);
|
|
||||||
|
|
||||||
TRY(create_stacks(thread->stack, thread->kernel_stack));
|
|
||||||
thread->set_sp(thread->stack.top());
|
|
||||||
|
|
||||||
thread->directory = directory;
|
|
||||||
|
|
||||||
guard.deactivate();
|
|
||||||
directory_guard.deactivate();
|
|
||||||
|
|
||||||
kinfoln("CREATED USERSPACE THREAD: id %lu with ip %lx and sp %lx (ksp %lx)", thread->id, thread->ip(),
|
|
||||||
thread->sp(), thread->kernel_stack.top());
|
|
||||||
|
|
||||||
g_threads.append(thread);
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void reap_thread(Thread* thread)
|
void reap_thread(Thread* thread)
|
||||||
{
|
{
|
||||||
kinfoln("reap: reaping thread with id %zu", thread->id);
|
kinfoln("reap: reaping thread with id %zu", thread->id);
|
||||||
|
auto stack = thread->stack;
|
||||||
if (thread->is_kernel)
|
kinfoln("deleting thread stack @ %#lx, has %zu bytes of stack", stack.bottom(), stack.bytes());
|
||||||
{
|
// FIXME: Propagate errors I guess?
|
||||||
auto stack = thread->stack;
|
MemoryManager::unmap_owned_and_free_vm(stack.bottom(), stack.bytes() / ARCH_PAGE_SIZE).release_value();
|
||||||
// FIXME: Propagate errors I guess?
|
|
||||||
kinfoln("deleting stack @ %#lx", stack.bottom());
|
|
||||||
MemoryManager::unmap_owned_and_free_vm(stack.bottom(), stack.bytes() / ARCH_PAGE_SIZE).release_value();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto stack = thread->kernel_stack;
|
|
||||||
kinfoln("deleting kstack @ %#lx", stack.bottom());
|
|
||||||
// FIXME: Propagate errors I guess?
|
|
||||||
MemoryManager::unmap_owned_and_free_vm(stack.bottom(), stack.bytes() / ARCH_PAGE_SIZE).release_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!thread->is_kernel) MMU::delete_userspace_page_directory(thread->directory);
|
|
||||||
|
|
||||||
delete thread;
|
delete thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,15 +138,7 @@ namespace Scheduler
|
|||||||
|
|
||||||
void generic_switch_context(Thread* old_thread, Thread* new_thread, Registers* regs)
|
void generic_switch_context(Thread* old_thread, Thread* new_thread, Registers* regs)
|
||||||
{
|
{
|
||||||
if (old_thread != new_thread)
|
if (old_thread != new_thread) switch_context(old_thread, new_thread, regs);
|
||||||
{
|
|
||||||
switch_context(old_thread, new_thread, regs);
|
|
||||||
if (!new_thread->is_kernel)
|
|
||||||
{
|
|
||||||
MMU::switch_page_directory(new_thread->directory);
|
|
||||||
CPU::switch_kernel_stack(new_thread->kernel_stack.top());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_thread->is_idle())
|
if (new_thread->is_idle())
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "thread/Thread.h"
|
#include "thread/Thread.h"
|
||||||
#include <luna/TarStream.h>
|
|
||||||
|
|
||||||
namespace Scheduler
|
namespace Scheduler
|
||||||
{
|
{
|
||||||
@ -13,8 +12,6 @@ namespace Scheduler
|
|||||||
Result<void> new_kernel_thread(void (*func)(void));
|
Result<void> new_kernel_thread(void (*func)(void));
|
||||||
Result<void> new_kernel_thread(void (*func)(void*), void* arg);
|
Result<void> new_kernel_thread(void (*func)(void*), void* arg);
|
||||||
|
|
||||||
Result<void> new_userspace_thread(const TarStream::Entry& entry, const TarStream& stream);
|
|
||||||
|
|
||||||
Thread* pick_task();
|
Thread* pick_task();
|
||||||
|
|
||||||
void reap_thread(Thread* thread);
|
void reap_thread(Thread* thread);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "arch/MMU.h"
|
|
||||||
#include <luna/LinkedList.h>
|
#include <luna/LinkedList.h>
|
||||||
#include <luna/Result.h>
|
#include <luna/Result.h>
|
||||||
#include <luna/Stack.h>
|
#include <luna/Stack.h>
|
||||||
@ -33,14 +32,9 @@ struct Thread : public LinkedListNode<Thread>
|
|||||||
u64 sleep_ticks_left;
|
u64 sleep_ticks_left;
|
||||||
|
|
||||||
Stack stack;
|
Stack stack;
|
||||||
Stack kernel_stack;
|
|
||||||
|
|
||||||
ThreadState state = ThreadState::Runnable;
|
ThreadState state = ThreadState::Runnable;
|
||||||
|
|
||||||
bool is_kernel { true };
|
|
||||||
|
|
||||||
PageDirectory* directory;
|
|
||||||
|
|
||||||
bool is_idle()
|
bool is_idle()
|
||||||
{
|
{
|
||||||
return state == ThreadState::Idle;
|
return state == ThreadState::Idle;
|
||||||
|
Loading…
Reference in New Issue
Block a user