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