Add the ability to copy memory to non resident process.
Use/Test this by loading the user space elf from the kernel process before it starts rather than as a part of the first thread. This simplifies thread start a fair bit.
This commit is contained in:
parent
f6609983d2
commit
b9b45c5e45
|
@ -46,17 +46,9 @@ typedef struct {
|
|||
uint64_t align;
|
||||
} 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
|
||||
|
||||
uint64_t LoadElfProgram(uint64_t base, uint64_t offset) {
|
||||
uint64_t LoadElfProgram(uint64_t cr3, uint64_t base, uint64_t offset) {
|
||||
Elf64Header* header = reinterpret_cast<Elf64Header*>(base);
|
||||
dbgln("phoff: %u phnum: %u", header->phoff, header->phnum);
|
||||
Elf64ProgramHeader* programs =
|
||||
|
@ -68,8 +60,8 @@ uint64_t LoadElfProgram(uint64_t base, uint64_t offset) {
|
|||
"filesz: %u, memsz: %u, align: %u",
|
||||
program.type, program.flags, program.offset, program.vaddr,
|
||||
program.paddr, program.filesz, program.memsz, program.align);
|
||||
EnsureResident(program.vaddr, program.memsz);
|
||||
badmemcpy(base + program.offset, program.filesz, program.vaddr);
|
||||
CopyIntoNonResidentProcess(base + program.offset, program.filesz, cr3,
|
||||
program.vaddr);
|
||||
}
|
||||
return header->entry;
|
||||
}
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
#include <stdint.h>
|
||||
|
||||
// Loads the elf program and returns its entry point.
|
||||
uint64_t LoadElfProgram(uint64_t base, uint64_t length);
|
||||
uint64_t LoadElfProgram(uint64_t cr3, uint64_t base, uint64_t length);
|
||||
|
|
|
@ -25,6 +25,11 @@ const limine_file& GetInitProgram() {
|
|||
void LoadInitProgram() {
|
||||
const limine_file& init_prog = GetInitProgram();
|
||||
|
||||
gProcMan->InsertProcess(
|
||||
new Process(reinterpret_cast<uint64_t>(init_prog.address)));
|
||||
SharedPtr<Process> proc = MakeShared<Process>();
|
||||
gProcMan->InsertProcess(proc);
|
||||
|
||||
uint64_t entry =
|
||||
LoadElfProgram(proc->cr3(), reinterpret_cast<uint64_t>(init_prog.address),
|
||||
init_prog.size);
|
||||
proc->CreateThread(entry);
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ uint64_t* PageTableEntry(uint64_t pt_phys, uint64_t addr) {
|
|||
ShiftForEntryIndexing(addr, PT_OFFSET));
|
||||
}
|
||||
|
||||
bool IsPageResident(uint64_t cr3, uint64_t virt) {
|
||||
uint64_t PagePhysIfResident(uint64_t cr3, uint64_t virt) {
|
||||
uint64_t* pml4_entry = Pml4Entry(cr3, virt);
|
||||
if (!(*pml4_entry & PRESENT_BIT)) {
|
||||
return false;
|
||||
|
@ -86,10 +86,10 @@ bool IsPageResident(uint64_t cr3, uint64_t virt) {
|
|||
if (!(*pt_entry & PRESENT_BIT)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return *pt_entry & ~0xFFF;
|
||||
}
|
||||
|
||||
void MapPage(uint64_t cr3, uint64_t virt) {
|
||||
uint64_t MapPage(uint64_t cr3, uint64_t virt) {
|
||||
uint64_t access_bits = PRESENT_BIT | READ_WRITE_BIT;
|
||||
uint64_t higher_half = 0xffff8000'00000000;
|
||||
if ((virt & higher_half) != higher_half) {
|
||||
|
@ -121,8 +121,10 @@ void MapPage(uint64_t cr3, uint64_t virt) {
|
|||
*pt_entry = PageAlign(phys) | access_bits;
|
||||
ZeroOutPage(reinterpret_cast<uint64_t*>(boot::GetHigherHalfDirectMap() +
|
||||
PageAlign(phys)));
|
||||
return phys;
|
||||
} else {
|
||||
panic("Page already allocated.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,14 +154,15 @@ void InitializePml4(uint64_t pml4_physical_addr) {
|
|||
pml4_virtual[Pml4Index(hhdm)] = *Pml4Entry(curr_cr3, hhdm);
|
||||
}
|
||||
|
||||
void AllocatePageIfNecessary(uint64_t addr, uint64_t cr3) {
|
||||
uint64_t AllocatePageIfNecessary(uint64_t addr, uint64_t cr3) {
|
||||
if (cr3 == 0) {
|
||||
cr3 = CurrCr3();
|
||||
}
|
||||
if (IsPageResident(cr3, addr)) {
|
||||
return;
|
||||
uint64_t phys = PagePhysIfResident(cr3, addr);
|
||||
if (phys) {
|
||||
return phys;
|
||||
}
|
||||
MapPage(cr3, addr);
|
||||
return MapPage(cr3, addr);
|
||||
}
|
||||
|
||||
void EnsureResident(uint64_t addr, uint64_t size) {
|
||||
|
@ -170,3 +173,21 @@ void EnsureResident(uint64_t addr, uint64_t size) {
|
|||
addr += 0x1000;
|
||||
}
|
||||
}
|
||||
|
||||
void CopyIntoNonResidentProcess(uint64_t base, uint64_t size, uint64_t dest_cr3,
|
||||
uint64_t dest_virt) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,5 +4,8 @@
|
|||
|
||||
void InitializePml4(uint64_t pml4_physical_addr);
|
||||
|
||||
void AllocatePageIfNecessary(uint64_t addr, uint64_t cr3 = 0);
|
||||
uint64_t AllocatePageIfNecessary(uint64_t addr, uint64_t cr3 = 0);
|
||||
void EnsureResident(uint64_t addr, uint64_t size);
|
||||
|
||||
void CopyIntoNonResidentProcess(uint64_t base, uint64_t size, uint64_t dest_cr3,
|
||||
uint64_t dest_virt);
|
||||
|
|
|
@ -22,14 +22,13 @@ SharedPtr<Process> Process::RootProcess() {
|
|||
return proc;
|
||||
}
|
||||
|
||||
Process::Process(uint64_t elf_ptr) : id_(gNextId++), state_(RUNNING) {
|
||||
Process::Process() : id_(gNextId++), state_(RUNNING) {
|
||||
cr3_ = phys_mem::AllocatePage();
|
||||
InitializePml4(cr3_);
|
||||
CreateThread(elf_ptr);
|
||||
}
|
||||
|
||||
void Process::CreateThread(uint64_t elf_ptr) {
|
||||
Thread* thread = new Thread(this, next_thread_id_++, elf_ptr);
|
||||
void Process::CreateThread(uint64_t entry) {
|
||||
Thread* thread = new Thread(this, next_thread_id_++, entry);
|
||||
threads_.PushBack(thread);
|
||||
gScheduler->Enqueue(thread);
|
||||
}
|
||||
|
|
|
@ -17,12 +17,12 @@ class Process {
|
|||
FINISHED,
|
||||
};
|
||||
static SharedPtr<Process> RootProcess();
|
||||
Process(uint64_t elf_ptr);
|
||||
Process();
|
||||
|
||||
uint64_t id() const { return id_; }
|
||||
uint64_t cr3() const { return cr3_; }
|
||||
|
||||
void CreateThread(uint64_t elf_ptr);
|
||||
void CreateThread(uint64_t entry);
|
||||
SharedPtr<Thread> GetThread(uint64_t tid);
|
||||
|
||||
// Checks the state of all child threads and transitions to
|
||||
|
|
|
@ -23,8 +23,8 @@ SharedPtr<Thread> Thread::RootThread(Process* root_proc) {
|
|||
return new Thread(root_proc);
|
||||
}
|
||||
|
||||
Thread::Thread(const SharedPtr<Process>& proc, uint64_t tid, uint64_t elf_ptr)
|
||||
: process_(proc), id_(tid), elf_ptr_(elf_ptr) {
|
||||
Thread::Thread(const SharedPtr<Process>& proc, uint64_t tid, uint64_t entry)
|
||||
: process_(proc), id_(tid), rip_(entry) {
|
||||
uint64_t* stack = new uint64_t[512];
|
||||
uint64_t* stack_ptr = stack + 511;
|
||||
// 0: rip
|
||||
|
@ -42,12 +42,11 @@ Thread::Thread(const SharedPtr<Process>& proc, uint64_t tid, uint64_t elf_ptr)
|
|||
uint64_t Thread::pid() { return process_->id(); }
|
||||
|
||||
void Thread::Init() {
|
||||
dbgln("[%u.%u]", pid(), id_);
|
||||
uint64_t rip = LoadElfProgram(elf_ptr_, 0);
|
||||
dbgln("[%u.%u] thread start.", pid(), id_);
|
||||
uint64_t rsp = 0x80000000;
|
||||
EnsureResident(rsp - 1, 1);
|
||||
SetRsp0(rsp0_start_);
|
||||
jump_user_space(rip, rsp);
|
||||
jump_user_space(rip_, rsp);
|
||||
}
|
||||
|
||||
void Thread::Exit() {
|
||||
|
|
|
@ -11,16 +11,13 @@ class Thread {
|
|||
public:
|
||||
enum State {
|
||||
UNSPECIFIED,
|
||||
CREATED,
|
||||
RUNNING,
|
||||
RUNNABLE,
|
||||
BLOCKED,
|
||||
FINISHED,
|
||||
};
|
||||
static SharedPtr<Thread> RootThread(Process* root_proc);
|
||||
|
||||
explicit Thread(const SharedPtr<Process>& proc, uint64_t tid,
|
||||
uint64_t elf_ptr);
|
||||
explicit Thread(const SharedPtr<Process>& proc, uint64_t tid, uint64_t entry);
|
||||
|
||||
uint64_t tid() { return id_; };
|
||||
uint64_t pid();
|
||||
|
@ -45,7 +42,8 @@ class Thread {
|
|||
uint64_t id_;
|
||||
State state_ = RUNNABLE;
|
||||
|
||||
uint64_t elf_ptr_;
|
||||
// Startup Context for the thread.
|
||||
uint64_t rip_;
|
||||
|
||||
// Stack pointer to take on resume.
|
||||
// Stack will contain the full thread context.
|
||||
|
|
Loading…
Reference in New Issue