Compare commits

..

No commits in common. "b9b45c5e45d1b9e0730ff77d830fe3f2cf0a3549" and "de49dcc01a364b5f75711839083bb1a4b3c5b039" have entirely different histories.

11 changed files with 100 additions and 150 deletions

View File

@ -15,13 +15,12 @@ class SharedPtr {
} }
SharedPtr(const SharedPtr<T>& other) SharedPtr(const SharedPtr<T>& other)
: init_(other.init_), ptr_(other.ptr_), ref_cnt_(other.ref_cnt_) { : ptr_(other.ptr_), ref_cnt_(other.ref_cnt_) {
(*ref_cnt_)++; (*ref_cnt_)++;
} }
SharedPtr& operator=(const SharedPtr<T>& other) { SharedPtr& operator=(const SharedPtr<T>& other) {
Cleanup(); Cleanup();
init_ = other.init_;
ptr_ = other.ptr_; ptr_ = other.ptr_;
ref_cnt_ = other.ref_cnt_; ref_cnt_ = other.ref_cnt_;
(*ref_cnt_)++; (*ref_cnt_)++;
@ -30,33 +29,14 @@ class SharedPtr {
~SharedPtr() { Cleanup(); } ~SharedPtr() { Cleanup(); }
T& operator*() { T& operator*() { return *ptr_; }
CheckValid(); const T& operator*() const { return *ptr_; }
return *ptr_; T* operator->() { return ptr_; }
} const T* operator->() const { return ptr_; }
const T& operator*() const {
CheckValid();
return *ptr_;
}
T* operator->() {
CheckValid();
return ptr_;
}
const T* operator->() const {
CheckValid();
return ptr_;
}
T* ptr() { T* ptr() { return ptr_; }
CheckValid();
return ptr_;
}
bool operator==(const SharedPtr<T>& other) { bool operator==(const SharedPtr<T>& other) { return ptr_ == other.ptr_; }
CheckValid();
other.CheckValid();
return ptr_ == other.ptr_;
}
bool empty() { return !init_; } bool empty() { return !init_; }
@ -75,12 +55,6 @@ class SharedPtr {
delete ref_cnt_; delete ref_cnt_;
} }
} }
void CheckValid() const {
if (!init_) {
panic("Accessing invalid shared ptr");
}
}
}; };
template <typename T, class... A> template <typename T, class... A>

View File

@ -46,9 +46,17 @@ typedef struct {
uint64_t align; uint64_t align;
} Elf64ProgramHeader; } Elf64ProgramHeader;
void badmemcpy(uint64_t base, uint64_t offset, uint64_t dest) {
uint8_t* ptr = reinterpret_cast<uint8_t*>(base);
uint8_t* dest_ptr = reinterpret_cast<uint8_t*>(dest);
for (uint64_t i = 0; i < offset; i++) {
dest_ptr[i] = ptr[i];
}
}
} // namespace } // namespace
uint64_t LoadElfProgram(uint64_t cr3, uint64_t base, uint64_t offset) { uint64_t LoadElfProgram(uint64_t base, uint64_t offset) {
Elf64Header* header = reinterpret_cast<Elf64Header*>(base); Elf64Header* header = reinterpret_cast<Elf64Header*>(base);
dbgln("phoff: %u phnum: %u", header->phoff, header->phnum); dbgln("phoff: %u phnum: %u", header->phoff, header->phnum);
Elf64ProgramHeader* programs = Elf64ProgramHeader* programs =
@ -60,8 +68,8 @@ uint64_t LoadElfProgram(uint64_t cr3, uint64_t base, uint64_t offset) {
"filesz: %u, memsz: %u, align: %u", "filesz: %u, memsz: %u, align: %u",
program.type, program.flags, program.offset, program.vaddr, program.type, program.flags, program.offset, program.vaddr,
program.paddr, program.filesz, program.memsz, program.align); program.paddr, program.filesz, program.memsz, program.align);
CopyIntoNonResidentProcess(base + program.offset, program.filesz, cr3, EnsureResident(program.vaddr, program.memsz);
program.vaddr); badmemcpy(base + program.offset, program.filesz, program.vaddr);
} }
return header->entry; return header->entry;
} }

View File

@ -3,4 +3,4 @@
#include <stdint.h> #include <stdint.h>
// Loads the elf program and returns its entry point. // Loads the elf program and returns its entry point.
uint64_t LoadElfProgram(uint64_t cr3, uint64_t base, uint64_t length); uint64_t LoadElfProgram(uint64_t base, uint64_t length);

View File

@ -25,11 +25,6 @@ const limine_file& GetInitProgram() {
void LoadInitProgram() { void LoadInitProgram() {
const limine_file& init_prog = GetInitProgram(); const limine_file& init_prog = GetInitProgram();
SharedPtr<Process> proc = MakeShared<Process>(); gProcMan->InsertProcess(
gProcMan->InsertProcess(proc); new Process(reinterpret_cast<uint64_t>(init_prog.address)));
uint64_t entry =
LoadElfProgram(proc->cr3(), reinterpret_cast<uint64_t>(init_prog.address),
init_prog.size);
proc->CreateThread(entry);
} }

View File

@ -39,155 +39,121 @@ uint64_t ShiftForEntryIndexing(uint64_t addr, uint64_t offset) {
addr &= ~0xFFFF0000'00000000; addr &= ~0xFFFF0000'00000000;
addr >>= offset; addr >>= offset;
addr <<= 3; addr <<= 3;
return addr & 0xFF8; return addr;
} }
uint64_t* Pml4Entry(uint64_t cr3, uint64_t addr) { uint64_t* Pml4Entry(uint64_t addr) {
cr3 += boot::GetHigherHalfDirectMap(); return reinterpret_cast<uint64_t*>(PML_RECURSE |
return reinterpret_cast<uint64_t*>(cr3 |
ShiftForEntryIndexing(addr, PML_OFFSET)); ShiftForEntryIndexing(addr, PML_OFFSET));
} }
uint64_t* PageDirectoryPointerEntry(uint64_t pdp_phys, uint64_t addr) { uint64_t* PageDirectoryPointerEntry(uint64_t addr) {
pdp_phys += boot::GetHigherHalfDirectMap(); return reinterpret_cast<uint64_t*>(PDP_RECURSE |
pdp_phys &= ~0xFFF;
return reinterpret_cast<uint64_t*>(pdp_phys |
ShiftForEntryIndexing(addr, PDP_OFFSET)); ShiftForEntryIndexing(addr, PDP_OFFSET));
} }
uint64_t* PageDirectoryEntry(uint64_t pd_phys, uint64_t addr) { uint64_t* PageDirectoryEntry(uint64_t addr) {
pd_phys += boot::GetHigherHalfDirectMap(); return reinterpret_cast<uint64_t*>(PD_RECURSE |
pd_phys &= ~0xFFF;
return reinterpret_cast<uint64_t*>(pd_phys |
ShiftForEntryIndexing(addr, PD_OFFSET)); ShiftForEntryIndexing(addr, PD_OFFSET));
} }
uint64_t* PageTableEntry(uint64_t pt_phys, uint64_t addr) { uint64_t* PageTableEntry(uint64_t addr) {
pt_phys += boot::GetHigherHalfDirectMap(); return reinterpret_cast<uint64_t*>(PT_RECURSE |
pt_phys &= ~0xFFF;
return reinterpret_cast<uint64_t*>(pt_phys |
ShiftForEntryIndexing(addr, PT_OFFSET)); ShiftForEntryIndexing(addr, PT_OFFSET));
} }
uint64_t PagePhysIfResident(uint64_t cr3, uint64_t virt) { bool PageDirectoryPointerLoaded(uint64_t addr) {
uint64_t* pml4_entry = Pml4Entry(cr3, virt); return *Pml4Entry(addr) & PRESENT_BIT;
if (!(*pml4_entry & PRESENT_BIT)) {
return false;
}
uint64_t* pdp_entry = PageDirectoryPointerEntry(*pml4_entry, virt);
if (!(*pdp_entry & PRESENT_BIT)) {
return false;
}
uint64_t* pd_entry = PageDirectoryEntry(*pdp_entry, virt);
if (!(*pd_entry & PRESENT_BIT)) {
return false;
}
uint64_t* pt_entry = PageTableEntry(*pd_entry, virt);
if (!(*pt_entry & PRESENT_BIT)) {
return false;
}
return *pt_entry & ~0xFFF;
} }
uint64_t MapPage(uint64_t cr3, uint64_t virt) { bool PageDirectoryLoaded(uint64_t addr) {
return PageDirectoryPointerLoaded(addr) &&
(*PageDirectoryPointerEntry(addr) & PRESENT_BIT);
}
bool PageTableLoaded(uint64_t addr) {
return PageDirectoryLoaded(addr) && (*PageDirectoryEntry(addr) & PRESENT_BIT);
}
void MapPage(uint64_t virt, uint64_t phys) {
if (PageLoaded(virt)) {
panic("Allocating Over Existing Page: %m", virt);
}
uint64_t access_bits = PRESENT_BIT | READ_WRITE_BIT; uint64_t access_bits = PRESENT_BIT | READ_WRITE_BIT;
uint64_t higher_half = 0xffff8000'00000000; uint64_t higher_half = 0xffff8000'00000000;
if ((virt & higher_half) != higher_half) { if ((virt & higher_half) != higher_half) {
access_bits |= USER_MODE_BIT; access_bits |= USER_MODE_BIT;
} }
uint64_t* pml4_entry = Pml4Entry(cr3, virt); if (!PageDirectoryPointerLoaded(virt)) {
if (!(*pml4_entry & PRESENT_BIT)) {
uint64_t page = phys_mem::AllocatePage(); uint64_t page = phys_mem::AllocatePage();
*pml4_entry = page | access_bits; *Pml4Entry(virt) = page | access_bits;
ZeroOutPage(PageDirectoryPointerEntry(*pml4_entry, virt)); ZeroOutPage(PageDirectoryPointerEntry(virt));
} }
uint64_t* pdp_entry = PageDirectoryPointerEntry(*pml4_entry, virt); if (!PageDirectoryLoaded(virt)) {
if (!(*pdp_entry & PRESENT_BIT)) {
uint64_t page = phys_mem::AllocatePage(); uint64_t page = phys_mem::AllocatePage();
*pdp_entry = page | access_bits; *PageDirectoryPointerEntry(virt) = page | access_bits;
ZeroOutPage(PageDirectoryEntry(*pdp_entry, virt)); ZeroOutPage(PageDirectoryEntry(virt));
} }
uint64_t* pd_entry = PageDirectoryEntry(*pdp_entry, virt); if (!PageTableLoaded(virt)) {
if (!(*pd_entry & PRESENT_BIT)) {
uint64_t page = phys_mem::AllocatePage(); uint64_t page = phys_mem::AllocatePage();
*(pd_entry) = page | access_bits; *PageDirectoryEntry(virt) = page | access_bits;
ZeroOutPage(PageTableEntry(*pd_entry, virt)); ZeroOutPage(PageTableEntry(virt));
} }
uint64_t* pt_entry = PageTableEntry(*pd_entry, virt); *PageTableEntry(virt) = PageAlign(phys) | access_bits;
if (!(*pt_entry & PRESENT_BIT)) { ZeroOutPage(reinterpret_cast<uint64_t*>(virt));
uint64_t phys = phys_mem::AllocatePage();
*pt_entry = PageAlign(phys) | access_bits;
ZeroOutPage(reinterpret_cast<uint64_t*>(boot::GetHigherHalfDirectMap() +
PageAlign(phys)));
return phys;
} else {
panic("Page already allocated.");
return 0;
}
} }
uint64_t Pml4Index(uint64_t addr) { return (addr >> PML_OFFSET) & 0x1FF; } uint64_t Pml4Index(uint64_t addr) { return (addr >> PML_OFFSET) & 0x1FF; }
} // namespace
uint64_t CurrCr3() { void InitPaging() {
uint64_t pml4_addr = 0; uint64_t pml4_addr = 0;
asm volatile("mov %%cr3, %0;" : "=r"(pml4_addr)); asm volatile("mov %%cr3, %0;" : "=r"(pml4_addr));
return pml4_addr; uint64_t* pml4_virtual =
} reinterpret_cast<uint64_t*>(boot::GetHigherHalfDirectMap() + pml4_addr);
} // namespace uint64_t recursive_entry = pml4_addr | PRESENT_BIT | READ_WRITE_BIT;
pml4_virtual[0x1FE] = recursive_entry;
}
void InitializePml4(uint64_t pml4_physical_addr) { void InitializePml4(uint64_t pml4_physical_addr) {
uint64_t* pml4_virtual = reinterpret_cast<uint64_t*>( uint64_t* pml4_virtual = reinterpret_cast<uint64_t*>(
boot::GetHigherHalfDirectMap() + pml4_physical_addr); boot::GetHigherHalfDirectMap() + pml4_physical_addr);
uint64_t curr_cr3 = CurrCr3();
// Map the recursive entry.
uint64_t recursive_entry = pml4_physical_addr | PRESENT_BIT | READ_WRITE_BIT;
pml4_virtual[0x1FE] = recursive_entry;
// Map the kernel entry. // Map the kernel entry.
// This should contain the heap at 0xFFFFFFFF'40000000 // This should contain the heap at 0xFFFFFFFF'40000000
uint64_t kernel_addr = 0xFFFFFFFF'80000000; uint64_t kernel_addr = 0xFFFFFFFF'80000000;
pml4_virtual[Pml4Index(kernel_addr)] = *Pml4Entry(curr_cr3, kernel_addr); pml4_virtual[Pml4Index(kernel_addr)] = *Pml4Entry(kernel_addr);
// Map the HHDM. // Map the HHDM.
// This is necessary to access values off of the kernel stack. // This is necessary to access values off of the kernel stack.
uint64_t hhdm = boot::GetHigherHalfDirectMap(); uint64_t hhdm = boot::GetHigherHalfDirectMap();
pml4_virtual[Pml4Index(hhdm)] = *Pml4Entry(curr_cr3, hhdm); pml4_virtual[Pml4Index(hhdm)] = *Pml4Entry(hhdm);
} }
uint64_t AllocatePageIfNecessary(uint64_t addr, uint64_t cr3) { void AllocatePage(uint64_t addr) {
if (cr3 == 0) { uint64_t physical_page = phys_mem::AllocatePage();
cr3 = CurrCr3(); MapPage(addr, physical_page);
}
uint64_t phys = PagePhysIfResident(cr3, addr);
if (phys) {
return phys;
}
return MapPage(cr3, addr);
} }
void EnsureResident(uint64_t addr, uint64_t size) { void EnsureResident(uint64_t addr, uint64_t size) {
uint64_t max = addr + size; uint64_t max = addr + size;
addr = PageAlign(addr); addr = PageAlign(addr);
while (addr < max) { while (addr < max) {
AllocatePageIfNecessary(addr); if (!PageLoaded(addr)) {
AllocatePage(addr);
}
addr += 0x1000; addr += 0x1000;
} }
} }
void CopyIntoNonResidentProcess(uint64_t base, uint64_t size, uint64_t dest_cr3, bool PageLoaded(uint64_t addr) {
uint64_t dest_virt) { return PageTableLoaded(addr) && (*PageTableEntry(addr) & PRESENT_BIT);
if (size > 0x1000) {
panic("Unimplemented NR copy > 1 page");
}
if (dest_virt & 0xFFF) {
panic("Unimplemented NR copy to non page aligned");
}
uint64_t phys = AllocatePageIfNecessary(dest_virt, dest_cr3);
uint8_t* src = reinterpret_cast<uint8_t*>(base);
uint8_t* dest =
reinterpret_cast<uint8_t*>(phys + boot::GetHigherHalfDirectMap());
for (uint64_t i = 0; i < size; i++) {
dest[i] = src[i];
}
} }

View File

@ -2,10 +2,10 @@
#include <stdint.h> #include <stdint.h>
void InitPaging();
void InitializePml4(uint64_t pml4_physical_addr); void InitializePml4(uint64_t pml4_physical_addr);
uint64_t AllocatePageIfNecessary(uint64_t addr, uint64_t cr3 = 0); void AllocatePage(uint64_t addr);
void EnsureResident(uint64_t addr, uint64_t size); void EnsureResident(uint64_t addr, uint64_t size);
void CopyIntoNonResidentProcess(uint64_t base, uint64_t size, uint64_t dest_cr3, bool PageLoaded(uint64_t addr);
uint64_t dest_virt);

View File

@ -22,13 +22,14 @@ SharedPtr<Process> Process::RootProcess() {
return proc; return proc;
} }
Process::Process() : id_(gNextId++), state_(RUNNING) { Process::Process(uint64_t elf_ptr) : id_(gNextId++), state_(RUNNING) {
cr3_ = phys_mem::AllocatePage(); cr3_ = phys_mem::AllocatePage();
InitializePml4(cr3_); InitializePml4(cr3_);
CreateThread(elf_ptr);
} }
void Process::CreateThread(uint64_t entry) { void Process::CreateThread(uint64_t elf_ptr) {
Thread* thread = new Thread(this, next_thread_id_++, entry); Thread* thread = new Thread(this, next_thread_id_++, elf_ptr);
threads_.PushBack(thread); threads_.PushBack(thread);
gScheduler->Enqueue(thread); gScheduler->Enqueue(thread);
} }

View File

@ -17,12 +17,12 @@ class Process {
FINISHED, FINISHED,
}; };
static SharedPtr<Process> RootProcess(); static SharedPtr<Process> RootProcess();
Process(); Process(uint64_t elf_ptr);
uint64_t id() const { return id_; } uint64_t id() const { return id_; }
uint64_t cr3() const { return cr3_; } uint64_t cr3() const { return cr3_; }
void CreateThread(uint64_t entry); void CreateThread(uint64_t elf_ptr);
SharedPtr<Thread> GetThread(uint64_t tid); SharedPtr<Thread> GetThread(uint64_t tid);
// Checks the state of all child threads and transitions to // Checks the state of all child threads and transitions to

View File

@ -23,8 +23,8 @@ SharedPtr<Thread> Thread::RootThread(Process* root_proc) {
return new Thread(root_proc); return new Thread(root_proc);
} }
Thread::Thread(const SharedPtr<Process>& proc, uint64_t tid, uint64_t entry) Thread::Thread(const SharedPtr<Process>& proc, uint64_t tid, uint64_t elf_ptr)
: process_(proc), id_(tid), rip_(entry) { : process_(proc), id_(tid), elf_ptr_(elf_ptr) {
uint64_t* stack = new uint64_t[512]; uint64_t* stack = new uint64_t[512];
uint64_t* stack_ptr = stack + 511; uint64_t* stack_ptr = stack + 511;
// 0: rip // 0: rip
@ -42,11 +42,12 @@ Thread::Thread(const SharedPtr<Process>& proc, uint64_t tid, uint64_t entry)
uint64_t Thread::pid() { return process_->id(); } uint64_t Thread::pid() { return process_->id(); }
void Thread::Init() { void Thread::Init() {
dbgln("[%u.%u] thread start.", pid(), id_); dbgln("[%u.%u]", pid(), id_);
uint64_t rip = LoadElfProgram(elf_ptr_, 0);
uint64_t rsp = 0x80000000; uint64_t rsp = 0x80000000;
EnsureResident(rsp - 1, 1); EnsureResident(rsp - 1, 1);
SetRsp0(rsp0_start_); SetRsp0(rsp0_start_);
jump_user_space(rip_, rsp); jump_user_space(rip, rsp);
} }
void Thread::Exit() { void Thread::Exit() {

View File

@ -11,13 +11,16 @@ class Thread {
public: public:
enum State { enum State {
UNSPECIFIED, UNSPECIFIED,
CREATED,
RUNNING, RUNNING,
RUNNABLE, RUNNABLE,
BLOCKED,
FINISHED, FINISHED,
}; };
static SharedPtr<Thread> RootThread(Process* root_proc); static SharedPtr<Thread> RootThread(Process* root_proc);
explicit Thread(const SharedPtr<Process>& proc, uint64_t tid, uint64_t entry); explicit Thread(const SharedPtr<Process>& proc, uint64_t tid,
uint64_t elf_ptr);
uint64_t tid() { return id_; }; uint64_t tid() { return id_; };
uint64_t pid(); uint64_t pid();
@ -42,8 +45,7 @@ class Thread {
uint64_t id_; uint64_t id_;
State state_ = RUNNABLE; State state_ = RUNNABLE;
// Startup Context for the thread. uint64_t elf_ptr_;
uint64_t rip_;
// Stack pointer to take on resume. // Stack pointer to take on resume.
// Stack will contain the full thread context. // Stack will contain the full thread context.

View File

@ -17,6 +17,9 @@ extern "C" void zion() {
InitGdt(); InitGdt();
InitIdt(); InitIdt();
dbgln("[boot] Init Paging.");
InitPaging();
dbgln("[boot] Init Physical Memory Manager."); dbgln("[boot] Init Physical Memory Manager.");
phys_mem::InitBootstrapPageAllocation(); phys_mem::InitBootstrapPageAllocation();
KernelHeap heap(0xFFFFFFFF'40000000, 0xFFFFFFFF'80000000); KernelHeap heap(0xFFFFFFFF'40000000, 0xFFFFFFFF'80000000);