Refactor memory allocation implementation and add KernelReserve flag to memory mappings

This commit is contained in:
EnderIce2 2024-03-19 03:57:30 +02:00
parent 1bd58a309f
commit b35045e7ca
Signed by untrusted user who does not match committer: enderice2
GPG Key ID: EACC3AD603BAB4DD
9 changed files with 610 additions and 562 deletions

View File

@ -122,13 +122,13 @@ NIF void MapFramebuffer(PageTable *PT)
{ {
vmm.OptimizedMap(bInfo.Framebuffer[itrfb].BaseAddress, vmm.OptimizedMap(bInfo.Framebuffer[itrfb].BaseAddress,
bInfo.Framebuffer[itrfb].BaseAddress, bInfo.Framebuffer[itrfb].BaseAddress,
fbSize, RW | G); fbSize, RW | G | KRsv);
} }
else else
{ {
vmm.Map(bInfo.Framebuffer[itrfb].BaseAddress, vmm.Map(bInfo.Framebuffer[itrfb].BaseAddress,
bInfo.Framebuffer[itrfb].BaseAddress, bInfo.Framebuffer[itrfb].BaseAddress,
fbSize, RW | G); fbSize, RW | G | KRsv);
} }
itrfb++; itrfb++;
} }
@ -190,7 +190,7 @@ NIF void MapKernel(PageTable *PT)
{ {
for (k = BootstrapStart; k < BootstrapEnd; k += PAGE_SIZE) for (k = BootstrapStart; k < BootstrapEnd; k += PAGE_SIZE)
{ {
vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G); vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G | KRsv);
KernelAllocator.ReservePage((void *)BaseKernelMapAddress); KernelAllocator.ReservePage((void *)BaseKernelMapAddress);
BaseKernelMapAddress += PAGE_SIZE; BaseKernelMapAddress += PAGE_SIZE;
} }
@ -204,7 +204,7 @@ NIF void MapKernel(PageTable *PT)
/* Text section */ /* Text section */
for (k = KernelTextStart; k < KernelTextEnd; k += PAGE_SIZE) for (k = KernelTextStart; k < KernelTextEnd; k += PAGE_SIZE)
{ {
vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G); vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G | KRsv);
KernelAllocator.ReservePage((void *)BaseKernelMapAddress); KernelAllocator.ReservePage((void *)BaseKernelMapAddress);
BaseKernelMapAddress += PAGE_SIZE; BaseKernelMapAddress += PAGE_SIZE;
} }
@ -212,7 +212,7 @@ NIF void MapKernel(PageTable *PT)
/* Data section */ /* Data section */
for (k = KernelDataStart; k < KernelDataEnd; k += PAGE_SIZE) for (k = KernelDataStart; k < KernelDataEnd; k += PAGE_SIZE)
{ {
vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G); vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G | KRsv);
KernelAllocator.ReservePage((void *)BaseKernelMapAddress); KernelAllocator.ReservePage((void *)BaseKernelMapAddress);
BaseKernelMapAddress += PAGE_SIZE; BaseKernelMapAddress += PAGE_SIZE;
} }
@ -220,7 +220,7 @@ NIF void MapKernel(PageTable *PT)
/* Read only data section */ /* Read only data section */
for (k = KernelRoDataStart; k < KernelRoDataEnd; k += PAGE_SIZE) for (k = KernelRoDataStart; k < KernelRoDataEnd; k += PAGE_SIZE)
{ {
vmm.Map((void *)k, (void *)BaseKernelMapAddress, G); vmm.Map((void *)k, (void *)BaseKernelMapAddress, G | KRsv);
KernelAllocator.ReservePage((void *)BaseKernelMapAddress); KernelAllocator.ReservePage((void *)BaseKernelMapAddress);
BaseKernelMapAddress += PAGE_SIZE; BaseKernelMapAddress += PAGE_SIZE;
} }
@ -228,7 +228,7 @@ NIF void MapKernel(PageTable *PT)
/* Block starting symbol section */ /* Block starting symbol section */
for (k = KernelBssStart; k < KernelBssEnd; k += PAGE_SIZE) for (k = KernelBssStart; k < KernelBssEnd; k += PAGE_SIZE)
{ {
vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G); vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G | KRsv);
KernelAllocator.ReservePage((void *)BaseKernelMapAddress); KernelAllocator.ReservePage((void *)BaseKernelMapAddress);
BaseKernelMapAddress += PAGE_SIZE; BaseKernelMapAddress += PAGE_SIZE;
} }
@ -240,7 +240,7 @@ NIF void MapKernel(PageTable *PT)
{ {
for (k = KernelFileStart; k < KernelFileEnd; k += PAGE_SIZE) for (k = KernelFileStart; k < KernelFileEnd; k += PAGE_SIZE)
{ {
vmm.Map((void *)k, (void *)k, G); vmm.Map((void *)k, (void *)k, G | KRsv);
KernelAllocator.ReservePage((void *)k); KernelAllocator.ReservePage((void *)k);
} }
} }

View File

@ -38,7 +38,7 @@ namespace Memory
debug("AllocatedStack: %#lx", AllocatedStack); debug("AllocatedStack: %#lx", AllocatedStack);
memset(AllocatedStack, 0, USER_STACK_SIZE); memset(AllocatedStack, 0, USER_STACK_SIZE);
Virtual vmm = Virtual(this->vma->GetTable()); Virtual vmm = Virtual(this->vma->Table);
for (size_t i = 0; i < TO_PAGES(USER_STACK_SIZE); i++) for (size_t i = 0; i < TO_PAGES(USER_STACK_SIZE); i++)
{ {
void *VirtualPage = (void *)((uintptr_t)this->StackBottom - (i * PAGE_SIZE)); void *VirtualPage = (void *)((uintptr_t)this->StackBottom - (i * PAGE_SIZE));
@ -79,8 +79,8 @@ namespace Memory
if (this->UserMode) if (this->UserMode)
{ {
std::vector<AllocatedPages> ParentAllocatedPages = Parent->GetAllocatedPages(); std::list<AllocatedPages> ParentAllocatedPages = Parent->GetAllocatedPages();
Virtual vma(this->vma->GetTable()); Virtual vma(this->vma->Table);
foreach (auto Page in ParentAllocatedPages) foreach (auto Page in ParentAllocatedPages)
{ {
void *NewPhysical = this->vma->RequestPages(1); void *NewPhysical = this->vma->RequestPages(1);
@ -114,7 +114,7 @@ namespace Memory
debug("AllocatedStack: %#lx", AllocatedStack); debug("AllocatedStack: %#lx", AllocatedStack);
{ {
Virtual vmm = Virtual(vma->GetTable()); Virtual vmm = Virtual(vma->Table);
for (size_t i = 0; i < TO_PAGES(USER_STACK_SIZE); i++) for (size_t i = 0; i < TO_PAGES(USER_STACK_SIZE); i++)
{ {
void *VirtualPage = (void *)(USER_STACK_BASE + (i * PAGE_SIZE)); void *VirtualPage = (void *)(USER_STACK_BASE + (i * PAGE_SIZE));

View File

@ -17,51 +17,14 @@
#include <memory/vma.hpp> #include <memory/vma.hpp>
#include <memory/table.hpp> #include <memory/table.hpp>
#include <cpu.hpp>
#include <debug.h> #include <debug.h>
#include <bitset>
#include "../../kernel.h" #include "../../kernel.h"
namespace Memory namespace Memory
{ {
// ReadFSFunction(MEM_Read)
// {
// if (Size <= 0)
// Size = node->Length;
// if (RefOffset > node->Length)
// return 0;
// if ((node->Length - RefOffset) == 0)
// return 0; /* EOF */
// if (RefOffset + (off_t)Size > node->Length)
// Size = node->Length;
// memcpy(Buffer, (uint8_t *)(node->Address + RefOffset), Size);
// return Size;
// }
// WriteFSFunction(MEM_Write)
// {
// if (Size <= 0)
// Size = node->Length;
// if (RefOffset > node->Length)
// return 0;
// if (RefOffset + (off_t)Size > node->Length)
// Size = node->Length;
// memcpy((uint8_t *)(node->Address + RefOffset), Buffer, Size);
// return Size;
// }
// vfs::FileSystemOperations mem_op = {
// .Name = "mem",
// .Read = MEM_Read,
// .Write = MEM_Write,
// };
uint64_t VirtualMemoryArea::GetAllocatedMemorySize() uint64_t VirtualMemoryArea::GetAllocatedMemorySize()
{ {
SmartLock(MgrLock); SmartLock(MgrLock);
@ -71,120 +34,89 @@ namespace Memory
return FROM_PAGES(Size); return FROM_PAGES(Size);
} }
bool VirtualMemoryArea::Add(void *Address, size_t Count) void *VirtualMemoryArea::RequestPages(size_t Count, bool User, bool Protect)
{ {
SmartLock(MgrLock); function("%lld, %s, %s", Count,
function("%#lx, %lld", Address, Count); User ? "true" : "false",
Protect ? "true" : "false");
if (Address == nullptr)
{
error("Address is null!");
return false;
}
if (Count == 0)
{
error("Count is 0!");
return false;
}
for (size_t i = 0; i < AllocatedPagesList.size(); i++)
{
if (AllocatedPagesList[i].Address == Address)
{
error("Address already exists!");
return false;
}
else if ((uintptr_t)Address < (uintptr_t)AllocatedPagesList[i].Address)
{
if ((uintptr_t)Address + (Count * PAGE_SIZE) > (uintptr_t)AllocatedPagesList[i].Address)
{
error("Address intersects with an allocated page!");
return false;
}
}
else
{
if ((uintptr_t)AllocatedPagesList[i].Address + (AllocatedPagesList[i].PageCount * PAGE_SIZE) > (uintptr_t)Address)
{
error("Address intersects with an allocated page!");
return false;
}
}
}
AllocatedPagesList.push_back({Address, Count});
return true;
}
void *VirtualMemoryArea::RequestPages(size_t Count, bool User)
{
SmartLock(MgrLock);
function("%lld, %s", Count, User ? "true" : "false");
void *Address = KernelAllocator.RequestPages(Count); void *Address = KernelAllocator.RequestPages(Count);
memset(Address, 0, Count * PAGE_SIZE); memset(Address, 0, Count * PAGE_SIZE);
for (size_t i = 0; i < Count; i++)
{
int Flags = Memory::PTFlag::RW;
if (User)
Flags |= Memory::PTFlag::US;
void *AddressToMap = (void *)((uintptr_t)Address + (i * PAGE_SIZE)); int Flags = PTFlag::RW;
if (User)
Flags |= PTFlag::US;
if (Protect)
Flags |= PTFlag::KRsv;
Memory::Virtual vmm(this->Table); Virtual vmm(this->Table);
vmm.Map(AddressToMap, AddressToMap, Flags);
}
AllocatedPagesList.push_back({Address, Count}); SmartLock(MgrLock);
vmm.Map(Address, Address, FROM_PAGES(Count), Flags);
AllocatedPagesList.push_back({Address, Count, Protect});
debug("%#lx +{%#lx, %lld}", this, Address, Count);
return Address; return Address;
} }
void VirtualMemoryArea::FreePages(void *Address, size_t Count) void VirtualMemoryArea::FreePages(void *Address, size_t Count)
{ {
SmartLock(MgrLock);
function("%#lx, %lld", Address, Count); function("%#lx, %lld", Address, Count);
SmartLock(MgrLock);
forItr(itr, AllocatedPagesList) forItr(itr, AllocatedPagesList)
{ {
if (itr->Address == Address) if (itr->Address != Address)
continue;
if (itr->Protected)
{ {
/** TODO: Advanced checks. Allow if the page count is less than the requested one. error("Address %#lx is protected", Address);
* This will allow the user to free only a part of the allocated pages.
*
* But this will be in a separate function because we need to specify if we
* want to free from the start or from the end and return the new address.
*/
if (itr->PageCount != Count)
{
error("Page count mismatch! (Allocated: %lld, Requested: %lld)", itr->PageCount, Count);
return;
}
KernelAllocator.FreePages(Address, Count);
Memory::Virtual vmm(this->Table);
for (size_t i = 0; i < Count; i++)
{
void *AddressToMap = (void *)((uintptr_t)Address + (i * PAGE_SIZE));
vmm.Remap(AddressToMap, AddressToMap, Memory::PTFlag::RW);
// vmm.Unmap((void *)((uintptr_t)Address + (i * PAGE_SIZE)));
}
AllocatedPagesList.erase(itr);
return; return;
} }
/** TODO: Advanced checks. Allow if the page count is less than the requested one.
* This will allow the user to free only a part of the allocated pages.
*
* But this will be in a separate function because we need to specify if we
* want to free from the start or from the end and return the new address.
*/
if (itr->PageCount != Count)
{
error("Page count mismatch! (Allocated: %lld, Requested: %lld)",
itr->PageCount, Count);
return;
}
Virtual vmm(this->Table);
for (size_t i = 0; i < Count; i++)
{
void *AddressToMap = (void *)((uintptr_t)Address + (i * PAGE_SIZE));
vmm.Remap(AddressToMap, AddressToMap, PTFlag::RW);
}
KernelAllocator.FreePages(Address, Count);
AllocatedPagesList.erase(itr);
debug("%#lx -{%#lx, %lld}", this, Address, Count);
return;
} }
} }
void VirtualMemoryArea::DetachAddress(void *Address) void VirtualMemoryArea::DetachAddress(void *Address)
{ {
SmartLock(MgrLock);
function("%#lx", Address); function("%#lx", Address);
SmartLock(MgrLock);
forItr(itr, AllocatedPagesList) forItr(itr, AllocatedPagesList)
{ {
if (itr->Address == Address) if (itr->Address == Address)
{ {
if (itr->Protected)
{
error("Address %#lx is protected", Address);
return;
}
AllocatedPagesList.erase(itr); AllocatedPagesList.erase(itr);
return; return;
} }
@ -203,14 +135,14 @@ namespace Memory
Fixed ? "true" : "false", Fixed ? "true" : "false",
Shared ? "true" : "false"); Shared ? "true" : "false");
Memory::Virtual vmm(this->Table); Virtual vmm(this->Table);
// FIXME // FIXME
// for (uintptr_t j = uintptr_t(Address); // for (uintptr_t j = uintptr_t(Address);
// j < uintptr_t(Address) + Length; // j < uintptr_t(Address) + Length;
// j += PAGE_SIZE) // j += PAGE_SIZE)
// { // {
// if (vmm.Check((void *)j, Memory::G)) // if (vmm.Check((void *)j, G))
// { // {
// if (Fixed) // if (Fixed)
// return (void *)-EINVAL; // return (void *)-EINVAL;
@ -230,6 +162,12 @@ namespace Memory
} }
SmartLock(MgrLock); SmartLock(MgrLock);
if (vmm.Check(Address, PTFlag::KRsv))
{
error("Cannot create CoW region at %#lx", Address);
return (void *)-EPERM;
}
vmm.Unmap(Address, Length); vmm.Unmap(Address, Length);
vmm.Map(Address, nullptr, Length, PTFlag::CoW); vmm.Map(Address, nullptr, Length, PTFlag::CoW);
debug("CoW region created at range %#lx-%#lx for pt %#lx", debug("CoW region created at range %#lx-%#lx for pt %#lx",
@ -254,8 +192,10 @@ namespace Memory
bool VirtualMemoryArea::HandleCoW(uintptr_t PFA) bool VirtualMemoryArea::HandleCoW(uintptr_t PFA)
{ {
function("%#lx", PFA); function("%#lx", PFA);
Memory::Virtual vmm(this->Table); Virtual vmm(this->Table);
Memory::PageTableEntry *pte = vmm.GetPTE((void *)PFA); PageTableEntry *pte = vmm.GetPTE((void *)PFA);
debug("ctx: %#lx", this);
if (!pte) if (!pte)
{ {
@ -264,51 +204,51 @@ namespace Memory
return false; return false;
} }
if (pte->CopyOnWrite == true) if (!pte->CopyOnWrite)
{ {
foreach (auto sr in SharedRegions) debug("PFA %#lx is not CoW (pt %#lx) (flags %#lx)",
PFA, this->Table, pte->raw);
return false;
}
foreach (auto sr in SharedRegions)
{
uintptr_t Start = (uintptr_t)sr.Address;
uintptr_t End = (uintptr_t)sr.Address + sr.Length;
debug("Start: %#lx, End: %#lx (PFA: %#lx)",
Start, End, PFA);
if (PFA >= Start && PFA < End)
{ {
uintptr_t Start = (uintptr_t)sr.Address; if (sr.Shared)
uintptr_t End = (uintptr_t)sr.Address + sr.Length;
if (PFA >= Start && PFA < End)
{ {
debug("Start: %#lx, End: %#lx (PFA: %#lx)", fixme("Shared CoW");
Start, End, PFA); return false;
if (sr.Shared)
{
fixme("Shared CoW");
return false;
}
else
{
void *pAddr = this->RequestPages(1);
if (pAddr == nullptr)
return false;
memset(pAddr, 0, PAGE_SIZE);
assert(pte->Present == true);
pte->ReadWrite = sr.Write;
pte->UserSupervisor = sr.Read;
pte->ExecuteDisable = sr.Exec;
pte->CopyOnWrite = false;
debug("PFA %#lx is CoW (pt %#lx, flags %#lx)",
PFA, this->Table, pte->raw);
#if defined(a64)
CPU::x64::invlpg((void *)PFA);
#elif defined(a32)
CPU::x32::invlpg((void *)PFA);
#endif
return true;
}
} }
void *pAddr = this->RequestPages(1);
if (pAddr == nullptr)
return false;
memset(pAddr, 0, PAGE_SIZE);
assert(pte->Present == true);
pte->ReadWrite = sr.Write;
pte->UserSupervisor = sr.Read;
pte->ExecuteDisable = sr.Exec;
pte->CopyOnWrite = false;
debug("PFA %#lx is CoW (pt %#lx, flags %#lx)",
PFA, this->Table, pte->raw);
#if defined(a64)
CPU::x64::invlpg((void *)PFA);
#elif defined(a32)
CPU::x32::invlpg((void *)PFA);
#endif
return true;
} }
} }
debug("PFA %#lx is not CoW (pt %#lx)", debug("%#lx not found in CoW regions", PFA);
PFA, this->Table);
return false; return false;
} }
@ -318,11 +258,11 @@ namespace Memory
foreach (auto ap in AllocatedPagesList) foreach (auto ap in AllocatedPagesList)
{ {
KernelAllocator.FreePages(ap.Address, ap.PageCount); KernelAllocator.FreePages(ap.Address, ap.PageCount);
Memory::Virtual vmm(this->Table); Virtual vmm(this->Table);
for (size_t i = 0; i < ap.PageCount; i++) for (size_t i = 0; i < ap.PageCount; i++)
vmm.Remap((void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), vmm.Remap((void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)),
(void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), (void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)),
Memory::PTFlag::RW); PTFlag::RW);
} }
AllocatedPagesList.clear(); AllocatedPagesList.clear();
} }
@ -330,59 +270,66 @@ namespace Memory
void VirtualMemoryArea::Fork(VirtualMemoryArea *Parent) void VirtualMemoryArea::Fork(VirtualMemoryArea *Parent)
{ {
function("%#lx", Parent); function("%#lx", Parent);
assert(Parent);
if (Parent == nullptr) debug("parent apl:%d sr:%d [P:%#lx C:%#lx]",
{ Parent->AllocatedPagesList.size(), Parent->SharedRegions.size(),
error("Parent is null!"); Parent->Table, this->Table);
return; debug("ctx: this: %#lx parent: %#lx", this, Parent);
}
if (Parent->Table == nullptr) Virtual vmm(this->Table);
{
error("Parent's table is null!");
return;
}
Memory::Virtual vmm(this->Table);
SmartLock(MgrLock); SmartLock(MgrLock);
foreach (auto &ap in Parent->GetAllocatedPagesList()) foreach (auto &ap in Parent->AllocatedPagesList)
{ {
if (ap.Protected)
{
debug("Protected %#lx-%#lx", ap.Address,
(uintptr_t)ap.Address + (ap.PageCount * PAGE_SIZE));
continue; /* We don't want to modify these pages. */
}
MgrLock.Unlock(); MgrLock.Unlock();
void *Address = this->RequestPages(ap.PageCount); void *Address = this->RequestPages(ap.PageCount);
MgrLock.Lock(__FUNCTION__); MgrLock.Lock(__FUNCTION__);
if (Address == nullptr) if (Address == nullptr)
return; return;
memcpy(Address, ap.Address, ap.PageCount * PAGE_SIZE); memcpy(Address, ap.Address, FROM_PAGES(ap.PageCount));
// map these new allocated pages to be the same as the parent
for (size_t i = 0; i < ap.PageCount; i++) for (size_t i = 0; i < ap.PageCount; i++)
{ {
void *AddressToMap = (void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)); void *AddressToMap = (void *)((uintptr_t)ap.Address + (i * PAGE_SIZE));
void *RealAddress = (void *)((uintptr_t)Address + (i * PAGE_SIZE)); void *RealAddress = (void *)((uintptr_t)Address + (i * PAGE_SIZE));
#if defined(a86) #if defined(a86)
Memory::PageTableEntry *pte = vmm.GetPTE(AddressToMap); PageTableEntry *pte = vmm.GetPTE(AddressToMap);
uintptr_t Flags = 0; uintptr_t Flags = 0;
Flags |= pte->Present ? 1UL : 0; Flags |= pte->Present ? (uintptr_t)PTFlag::P : 0;
Flags |= pte->ReadWrite ? 2UL : 0; Flags |= pte->ReadWrite ? (uintptr_t)PTFlag::RW : 0;
Flags |= pte->UserSupervisor ? 4UL : 0; Flags |= pte->UserSupervisor ? (uintptr_t)PTFlag::US : 0;
Flags |= pte->CopyOnWrite ? 512UL : 0; Flags |= pte->CopyOnWrite ? (uintptr_t)PTFlag::CoW : 0;
Flags |= pte->KernelReserve ? (uintptr_t)PTFlag::KRsv : 0;
debug("Mapping %#lx to %#lx (flags %s/%s/%s/%s)", debug("Mapping %#lx to %#lx (flags %s/%s/%s/%s/%s)",
RealAddress, AddressToMap, RealAddress, AddressToMap,
Flags & PTFlag::P ? "P" : "-", Flags & PTFlag::P ? "P" : "-",
Flags & PTFlag::RW ? "RW" : "-", Flags & PTFlag::RW ? "RW" : "-",
Flags & PTFlag::US ? "US" : "-", Flags & PTFlag::US ? "US" : "-",
Flags & PTFlag::CoW ? "CoW" : "-"); Flags & PTFlag::CoW ? "CoW" : "-",
vmm.Map(AddressToMap, RealAddress, Flags); Flags & PTFlag::KRsv ? "KRsv" : "-");
MgrLock.Unlock();
this->Map(AddressToMap, RealAddress, PAGE_SIZE, Flags);
MgrLock.Lock(__FUNCTION__);
#else #else
#warning "Not implemented" #error "Not implemented"
#endif #endif
} }
debug("Forked %#lx-%#lx", ap.Address,
(uintptr_t)ap.Address + (ap.PageCount * PAGE_SIZE));
} }
foreach (auto &sr in Parent->GetSharedRegions()) foreach (auto &sr in Parent->SharedRegions)
{ {
MgrLock.Unlock(); MgrLock.Unlock();
void *Address = this->CreateCoWRegion(sr.Address, sr.Length, void *Address = this->CreateCoWRegion(sr.Address, sr.Length,
@ -392,53 +339,154 @@ namespace Memory
if (Address == nullptr) if (Address == nullptr)
return; return;
memcpy(Address, sr.Address, sr.Length); memcpy(Address, sr.Address, sr.Length);
debug("Forked CoW region %#lx-%#lx", sr.Address,
(uintptr_t)sr.Address + sr.Length);
} }
} }
VirtualMemoryArea::VirtualMemoryArea(PageTable *Table) int VirtualMemoryArea::Map(void *VirtualAddress, void *PhysicalAddress,
size_t Length, uint64_t Flags)
{ {
debug("+ %#lx %s", this, Virtual vmm(this->Table);
KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "");
SmartLock(MgrLock); SmartLock(MgrLock);
if (Table)
this->Table = Table; uintptr_t intVirtualAddress = (uintptr_t)VirtualAddress;
else uintptr_t intPhysicalAddress = (uintptr_t)PhysicalAddress;
for (uintptr_t va = intVirtualAddress;
va < intVirtualAddress + Length; va += PAGE_SIZE)
{
if (vmm.Check(VirtualAddress, PTFlag::KRsv))
{
error("Virtual address %#lx is reserved", VirtualAddress);
return -EPERM;
}
}
for (uintptr_t va = intPhysicalAddress;
va < intPhysicalAddress + Length; va += PAGE_SIZE)
{
if (vmm.Check(PhysicalAddress, PTFlag::KRsv))
{
error("Physical address %#lx is reserved", PhysicalAddress);
return -EPERM;
}
}
vmm.Map(VirtualAddress, PhysicalAddress, Length, Flags);
debug("Mapped %#lx-%#lx to %#lx-%#lx (flags %#lx)",
VirtualAddress, intVirtualAddress + Length,
PhysicalAddress, intPhysicalAddress + Length,
Flags);
return 0;
}
int VirtualMemoryArea::Remap(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags)
{
Virtual vmm(this->Table);
SmartLock(MgrLock);
if (vmm.Check(VirtualAddress, PTFlag::KRsv))
{
error("Virtual address %#lx is reserved", VirtualAddress);
return -EPERM;
}
if (vmm.Check(PhysicalAddress, PTFlag::KRsv))
{
error("Physical address %#lx is reserved", PhysicalAddress);
return -EPERM;
}
vmm.Remap(VirtualAddress, PhysicalAddress, Flags);
debug("Remapped %#lx to %#lx (flags %#lx)",
VirtualAddress, PhysicalAddress, Flags);
return 0;
}
int VirtualMemoryArea::Unmap(void *VirtualAddress, size_t Length)
{
Virtual vmm(this->Table);
SmartLock(MgrLock);
uintptr_t intVirtualAddress = (uintptr_t)VirtualAddress;
for (uintptr_t va = intVirtualAddress;
va < intVirtualAddress + Length; va += PAGE_SIZE)
{
if (vmm.Check(VirtualAddress, PTFlag::KRsv))
{
error("Virtual address %#lx is reserved", VirtualAddress);
return -EPERM;
}
}
vmm.Unmap(VirtualAddress, Length);
debug("Unmapped %#lx-%#lx", VirtualAddress, intVirtualAddress + Length);
return 0;
}
void *VirtualMemoryArea::__UserCheckAndGetAddress(void *Address, size_t Length)
{
Virtual vmm(this->Table);
SmartLock(MgrLock);
void *pAddress = this->Table->Get(Address);
if (pAddress == nullptr)
{
debug("Virtual address %#lx returns nullptr", Address);
return nullptr;
}
uintptr_t intAddress = (uintptr_t)Address;
intAddress = ALIGN_DOWN(intAddress, PAGE_SIZE);
for (uintptr_t va = intAddress; va < intAddress + Length; va += PAGE_SIZE)
{
if (vmm.Check((void *)va, PTFlag::US))
continue;
fixme("Unable to get address %#lx, page is not user accessible", va);
return nullptr;
}
return pAddress;
}
int VirtualMemoryArea::__UserCheck(void *Address, size_t Length)
{
Virtual vmm(this->Table);
SmartLock(MgrLock);
if (vmm.Check(Address, PTFlag::US))
return 0;
error("Address %#lx is not user accessible", Address);
return -EFAULT;
}
VirtualMemoryArea::VirtualMemoryArea(PageTable *_Table)
: Table(_Table)
{
SmartLock(MgrLock);
if (_Table == nullptr)
{ {
if (TaskManager) if (TaskManager)
{
Tasking::PCB *pcb = thisProcess;
assert(pcb);
this->Table = thisProcess->PageTable; this->Table = thisProcess->PageTable;
}
else else
#if defined(a64) this->Table = (PageTable *)CPU::PageTable();
this->Table = (PageTable *)CPU::x64::readcr3().raw;
#elif defined(a32)
this->Table = (PageTable *)CPU::x32::readcr3().raw;
#endif
} }
} }
VirtualMemoryArea::~VirtualMemoryArea() VirtualMemoryArea::~VirtualMemoryArea()
{ {
debug("- %#lx %s", this, /* No need to remap pages, the page table will be destroyed */
KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "");
#ifdef DEBUG
if (this->Table == KernelPageTable)
debug("Not remapping kernel page table allocated pages.");
#endif
SmartLock(MgrLock); SmartLock(MgrLock);
Memory::Virtual vmm(this->Table);
foreach (auto ap in AllocatedPagesList) foreach (auto ap in AllocatedPagesList)
{
KernelAllocator.FreePages(ap.Address, ap.PageCount); KernelAllocator.FreePages(ap.Address, ap.PageCount);
if (this->Table == KernelPageTable)
continue;
for (size_t i = 0; i < ap.PageCount; i++)
vmm.Remap((void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)),
(void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)),
Memory::PTFlag::RW);
}
} }
} }

View File

@ -424,13 +424,14 @@ nsa void DisplayDetailsScreen(CPU::ExceptionFrame *Frame)
{ {
Memory::Virtual vmm((Memory::PageTable *)Frame->cr3); Memory::Virtual vmm((Memory::PageTable *)Frame->cr3);
if (vmm.GetMapType((void *)Frame->cr2) != Memory::Virtual::FourKiB) if (vmm.GetMapType((void *)Frame->cr2) != Memory::Virtual::FourKiB)
ExPrint("Can't display page at address %#lx\n", Frame->cr2); ExPrint("Can't display page %#lx\n", Frame->cr2);
else else
{ {
Memory::PageTableEntry *pte = vmm.GetPTE((void *)Frame->cr2); Memory::PageTableEntry *pte = vmm.GetPTE((void *)Frame->cr2);
ExPrint("Page %#lx: P:%d W:%d U:%d G:%d CoW:%d NX:%d\n", ExPrint("Page %#lx: P:%d W:%d U:%d G:%d CoW:%d KRsv:%d NX:%d\n",
ALIGN_DOWN(Frame->cr2, 0x1000), pte->Present, pte->ReadWrite, ALIGN_DOWN(Frame->cr2, 0x1000), pte->Present, pte->ReadWrite,
pte->UserSupervisor, pte->Global, pte->CopyOnWrite, pte->ExecuteDisable); pte->UserSupervisor, pte->Global, pte->CopyOnWrite,
pte->KernelReserve, pte->ExecuteDisable);
} }
} }

View File

@ -19,7 +19,7 @@
#define __FENNIX_KERNEL_MEMORY_STACK_GUARD_H__ #define __FENNIX_KERNEL_MEMORY_STACK_GUARD_H__
#include <types.h> #include <types.h>
#include <vector> #include <list>
#include <memory/table.hpp> #include <memory/table.hpp>
@ -42,10 +42,10 @@ namespace Memory
bool UserMode = false; bool UserMode = false;
bool Expanded = false; bool Expanded = false;
VirtualMemoryArea *vma = nullptr; VirtualMemoryArea *vma = nullptr;
std::vector<AllocatedPages> AllocatedPagesList; std::list<AllocatedPages> AllocatedPagesList;
public: public:
std::vector<AllocatedPages> GetAllocatedPages() std::list<AllocatedPages> GetAllocatedPages()
{ {
return AllocatedPagesList; return AllocatedPagesList;
} }

View File

@ -59,7 +59,7 @@ namespace Memory
CoW = 1 << 9, CoW = 1 << 9,
/** @brief Available 1 */ /** @brief Available 1 */
AVL1 = 1 << 10, KRsv = 1 << 10,
/** @brief Available 2 */ /** @brief Available 2 */
AVL2 = 1 << 11, AVL2 = 1 << 11,
@ -119,7 +119,7 @@ namespace Memory
uintptr_t PageAttributeTable : 1; // 7 uintptr_t PageAttributeTable : 1; // 7
uintptr_t Global : 1; // 8 uintptr_t Global : 1; // 8
uintptr_t CopyOnWrite : 1; // 9 uintptr_t CopyOnWrite : 1; // 9
uintptr_t Available1 : 1; // 10 uintptr_t KernelReserve : 1; // 10
uintptr_t Available2 : 1; // 11 uintptr_t Available2 : 1; // 11
uintptr_t Address : 40; // 12-51 uintptr_t Address : 40; // 12-51
uintptr_t Available3 : 1; // 52 uintptr_t Available3 : 1; // 52
@ -142,7 +142,7 @@ namespace Memory
uintptr_t PageAttributeTable : 1; // 7 uintptr_t PageAttributeTable : 1; // 7
uintptr_t Global : 1; // 8 uintptr_t Global : 1; // 8
uintptr_t CopyOnWrite : 1; // 9 uintptr_t CopyOnWrite : 1; // 9
uintptr_t Available1 : 1; // 10 uintptr_t KernelReserve : 1; // 10
uintptr_t Available2 : 1; // 11 uintptr_t Available2 : 1; // 11
uintptr_t Address : 20; // 12-31 uintptr_t Address : 20; // 12-31
#elif defined(aa64) #elif defined(aa64)
@ -204,9 +204,22 @@ namespace Memory
uintptr_t Accessed : 1; // 5 uintptr_t Accessed : 1; // 5
uintptr_t CopyOnWrite : 1; // 6 uintptr_t CopyOnWrite : 1; // 6
uintptr_t PageSize : 1; // 7 uintptr_t PageSize : 1; // 7
uintptr_t Available1 : 4; // 8-11 uintptr_t KernelReserve : 1; // 8
uintptr_t Available2 : 1; // 9
uintptr_t Available3 : 1; // 10
uintptr_t Available4 : 1; // 11
uintptr_t Address : 40; // 12-51 uintptr_t Address : 40; // 12-51
uintptr_t Available2 : 11; // 52-62 uintptr_t Available5 : 1; // 52
uintptr_t Available6 : 1; // 53
uintptr_t Available7 : 1; // 54
uintptr_t Available8 : 1; // 55
uintptr_t Available9 : 1; // 56
uintptr_t Available10 : 1; // 57
uintptr_t Available11 : 1; // 58
uintptr_t Available12 : 1; // 59
uintptr_t Available13 : 1; // 60
uintptr_t Available14 : 1; // 61
uintptr_t Available15 : 1; // 62
uintptr_t ExecuteDisable : 1; // 63 uintptr_t ExecuteDisable : 1; // 63
}; };
@ -222,7 +235,7 @@ namespace Memory
uintptr_t PageSize : 1; // 7 uintptr_t PageSize : 1; // 7
uintptr_t Global : 1; // 8 uintptr_t Global : 1; // 8
uintptr_t CopyOnWrite : 1; // 9 uintptr_t CopyOnWrite : 1; // 9
uintptr_t Available1 : 1; // 10 uintptr_t KernelReserve : 1; // 10
uintptr_t Available2 : 1; // 11 uintptr_t Available2 : 1; // 11
uintptr_t PageAttributeTable : 1; // 12 uintptr_t PageAttributeTable : 1; // 12
uintptr_t Reserved0 : 8; // 13-20 uintptr_t Reserved0 : 8; // 13-20
@ -248,7 +261,10 @@ namespace Memory
uintptr_t Accessed : 1; // 5 uintptr_t Accessed : 1; // 5
uintptr_t CopyOnWrite : 1; // 6 uintptr_t CopyOnWrite : 1; // 6
uintptr_t PageSize : 1; // 7 uintptr_t PageSize : 1; // 7
uintptr_t Available1 : 4; // 8-11 uintptr_t KernelReserve : 1; // 8
uintptr_t Available2 : 1; // 9
uintptr_t Available3 : 1; // 10
uintptr_t Available4 : 1; // 11
uintptr_t Address : 20; // 12-31 uintptr_t Address : 20; // 12-31
}; };
@ -264,7 +280,7 @@ namespace Memory
uintptr_t PageSize : 1; // 7 uintptr_t PageSize : 1; // 7
uintptr_t Global : 1; // 8 uintptr_t Global : 1; // 8
uintptr_t CopyOnWrite : 1; // 9 uintptr_t CopyOnWrite : 1; // 9
uintptr_t Available1 : 1; // 10 uintptr_t KernelReserve : 1; // 10
uintptr_t Available2 : 1; // 11 uintptr_t Available2 : 1; // 11
uintptr_t PageAttributeTable : 1; // 12 uintptr_t PageAttributeTable : 1; // 12
uintptr_t Address0 : 8; // 13-20 uintptr_t Address0 : 8; // 13-20
@ -324,9 +340,22 @@ namespace Memory
uintptr_t Accessed : 1; // 5 uintptr_t Accessed : 1; // 5
uintptr_t CopyOnWrite : 1; // 6 uintptr_t CopyOnWrite : 1; // 6
uintptr_t PageSize : 1; // 7 uintptr_t PageSize : 1; // 7
uintptr_t Available1 : 4; // 8-11 uintptr_t KernelReserve : 1; // 8
uintptr_t Available2 : 1; // 9
uintptr_t Available3 : 1; // 10
uintptr_t Available4 : 1; // 11
uintptr_t Address : 40; // 12-51 uintptr_t Address : 40; // 12-51
uintptr_t Available2 : 11; // 52-62 uintptr_t Available5 : 1; // 52
uintptr_t Available6 : 1; // 53
uintptr_t Available7 : 1; // 54
uintptr_t Available8 : 1; // 55
uintptr_t Available9 : 1; // 56
uintptr_t Available10 : 1; // 57
uintptr_t Available11 : 1; // 58
uintptr_t Available12 : 1; // 59
uintptr_t Available13 : 1; // 60
uintptr_t Available14 : 1; // 61
uintptr_t Available15 : 1; // 62
uintptr_t ExecuteDisable : 1; // 63 uintptr_t ExecuteDisable : 1; // 63
}; };
@ -342,7 +371,7 @@ namespace Memory
uintptr_t PageSize : 1; // 7 uintptr_t PageSize : 1; // 7
uintptr_t Global : 1; // 8 uintptr_t Global : 1; // 8
uintptr_t CopyOnWrite : 1; // 9 uintptr_t CopyOnWrite : 1; // 9
uintptr_t Available1 : 1; // 10 uintptr_t KernelReserve : 1; // 10
uintptr_t Available2 : 1; // 11 uintptr_t Available2 : 1; // 11
uintptr_t PageAttributeTable : 1; // 12 uintptr_t PageAttributeTable : 1; // 12
uintptr_t Reserved0 : 17; // 13-29 uintptr_t Reserved0 : 17; // 13-29
@ -406,9 +435,22 @@ namespace Memory
uintptr_t Accessed : 1; // 5 uintptr_t Accessed : 1; // 5
uintptr_t CopyOnWrite : 1; // 6 uintptr_t CopyOnWrite : 1; // 6
uintptr_t Reserved0 : 1; // 7 uintptr_t Reserved0 : 1; // 7
uintptr_t Available1 : 4; // 8-11 uintptr_t KernelReserve : 1; // 8
uintptr_t Available2 : 1; // 9
uintptr_t Available3 : 1; // 10
uintptr_t Available4 : 1; // 11
uintptr_t Address : 40; // 12-51 uintptr_t Address : 40; // 12-51
uintptr_t Available2 : 11; // 52-62 uintptr_t Available5 : 1; // 52
uintptr_t Available6 : 1; // 53
uintptr_t Available7 : 1; // 54
uintptr_t Available8 : 1; // 55
uintptr_t Available9 : 1; // 56
uintptr_t Available10 : 1; // 57
uintptr_t Available11 : 1; // 58
uintptr_t Available12 : 1; // 59
uintptr_t Available13 : 1; // 60
uintptr_t Available14 : 1; // 61
uintptr_t Available15 : 1; // 62
uintptr_t ExecuteDisable : 1; // 63 uintptr_t ExecuteDisable : 1; // 63
}; };
#elif defined(aa64) #elif defined(aa64)
@ -460,9 +502,22 @@ namespace Memory
uintptr_t Accessed : 1; // 5 uintptr_t Accessed : 1; // 5
uintptr_t Available0 : 1; // 6 uintptr_t Available0 : 1; // 6
uintptr_t Reserved0 : 1; // 7 uintptr_t Reserved0 : 1; // 7
uintptr_t Available1 : 4; // 8-11 uintptr_t KernelReserve : 1; // 8
uintptr_t Available1 : 1; // 9
uintptr_t Available2 : 1; // 10
uintptr_t Available3 : 1; // 11
uintptr_t Address : 40; // 12-51 uintptr_t Address : 40; // 12-51
uintptr_t Available2 : 11; // 52-62 uintptr_t Available4 : 1; // 52
uintptr_t Available5 : 1; // 53
uintptr_t Available6 : 1; // 54
uintptr_t Available7 : 1; // 55
uintptr_t Available8 : 1; // 56
uintptr_t Available9 : 1; // 57
uintptr_t Available10 : 1; // 58
uintptr_t Available11 : 1; // 59
uintptr_t Available12 : 1; // 60
uintptr_t Available13 : 1; // 61
uintptr_t Available14 : 1; // 62
uintptr_t ExecuteDisable : 1; // 63 uintptr_t ExecuteDisable : 1; // 63
}; };
#elif defined(aa64) #elif defined(aa64)

View File

@ -22,12 +22,13 @@
#include <filesystem.hpp> #include <filesystem.hpp>
#include <bitmap.hpp> #include <bitmap.hpp>
#include <lock.hpp> #include <lock.hpp>
#include <vector> #include <list>
#include <memory/table.hpp> #include <memory/table.hpp>
namespace Memory namespace Memory
{ {
class VirtualMemoryArea class VirtualMemoryArea
{ {
public: public:
@ -35,6 +36,7 @@ namespace Memory
{ {
void *Address; void *Address;
size_t PageCount; size_t PageCount;
bool Protected;
}; };
struct SharedRegion struct SharedRegion
@ -49,30 +51,15 @@ namespace Memory
private: private:
NewLock(MgrLock); NewLock(MgrLock);
Bitmap PageBitmap; Bitmap PageBitmap;
PageTable *Table;
std::vector<AllocatedPages> AllocatedPagesList; std::list<AllocatedPages> AllocatedPagesList;
std::vector<SharedRegion> SharedRegions; std::list<SharedRegion> SharedRegions;
public: public:
PageTable *GetTable() { return Table; } PageTable *Table = nullptr;
void SetTable(PageTable *Table) { this->Table = Table; }
std::vector<AllocatedPages> &GetAllocatedPagesList()
{
return AllocatedPagesList;
}
std::vector<SharedRegion> &GetSharedRegions()
{
return SharedRegions;
}
uint64_t GetAllocatedMemorySize(); uint64_t GetAllocatedMemorySize();
bool Add(void *Address, size_t Count); void *RequestPages(size_t Count, bool User = false, bool Protect = false);
void *RequestPages(size_t Count, bool User = false);
void FreePages(void *Address, size_t Count); void FreePages(void *Address, size_t Count);
void DetachAddress(void *Address); void DetachAddress(void *Address);
@ -88,18 +75,45 @@ namespace Memory
* @param Shared Shared region * @param Shared Shared region
* @return Address of the region * @return Address of the region
*/ */
void *CreateCoWRegion(void *Address, void *CreateCoWRegion(void *Address, size_t Length,
size_t Length,
bool Read, bool Write, bool Exec, bool Read, bool Write, bool Exec,
bool Fixed, bool Shared); bool Fixed, bool Shared);
bool HandleCoW(uintptr_t PFA); bool HandleCoW(uintptr_t PFA);
void FreeAllPages(); void FreeAllPages();
void Fork(VirtualMemoryArea *Parent); void Fork(VirtualMemoryArea *Parent);
VirtualMemoryArea(PageTable *Table = nullptr); void Reserve(void *Address, size_t Length);
void Unreserve(void *Address, size_t Length);
int Map(void *VirtualAddress, void *PhysicalAddress,
size_t Length, uint64_t Flags);
int Remap(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags);
int Unmap(void *VirtualAddress, size_t Length);
void *__UserCheckAndGetAddress(void *Address, size_t Length);
int __UserCheck(void *Address, size_t Length);
template <typename T>
T UserCheckAndGetAddress(T Address, size_t Length = 0)
{
if (Length == 0)
Length = sizeof(T);
void *PhysAddr = __UserCheckAndGetAddress((void *)Address, Length);
if (PhysAddr == nullptr)
return {};
return T(PhysAddr);
}
template <typename T>
int UserCheck(T Address, size_t Length = 0)
{
if (Length == 0)
Length = sizeof(T);
return __UserCheck((void *)Address, Length);
}
VirtualMemoryArea(PageTable *Table);
~VirtualMemoryArea(); ~VirtualMemoryArea();
}; };
} }

View File

@ -65,9 +65,14 @@ void linux_fork_return(void *tableAddr)
static ssize_t linux_read(SysFrm *, int fd, void *buf, size_t count) static ssize_t linux_read(SysFrm *, int fd, void *buf, size_t count)
{ {
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
void *pBuf = pcb->PageTable->Get(buf); Memory::VirtualMemoryArea *vma = pcb->vma;
void *pBuf = vma->UserCheckAndGetAddress(buf, count);
if (pBuf == nullptr)
return -EFAULT;
function("%d, %p, %d", fd, buf, count); function("%d, %p, %d", fd, buf, count);
vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors;
ssize_t ret = fdt->_read(fd, pBuf, count); ssize_t ret = fdt->_read(fd, pBuf, count);
if (ret >= 0) if (ret >= 0)
@ -79,9 +84,14 @@ static ssize_t linux_read(SysFrm *, int fd, void *buf, size_t count)
static ssize_t linux_write(SysFrm *, int fd, const void *buf, size_t count) static ssize_t linux_write(SysFrm *, int fd, const void *buf, size_t count)
{ {
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
const void *pBuf = pcb->PageTable->Get((void *)buf); Memory::VirtualMemoryArea *vma = pcb->vma;
const void *pBuf = vma->UserCheckAndGetAddress(buf, count);
if (pBuf == nullptr)
return -EFAULT;
function("%d, %p, %d", fd, buf, count); function("%d, %p, %d", fd, buf, count);
vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors;
ssize_t ret = fdt->_write(fd, pBuf, count); ssize_t ret = fdt->_write(fd, pBuf, count);
if (ret) if (ret)
@ -93,7 +103,11 @@ static ssize_t linux_write(SysFrm *, int fd, const void *buf, size_t count)
static int linux_open(SysFrm *sf, const char *pathname, int flags, mode_t mode) static int linux_open(SysFrm *sf, const char *pathname, int flags, mode_t mode)
{ {
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
const char *pPathname = pcb->PageTable->Get(pathname); Memory::VirtualMemoryArea *vma = pcb->vma;
const char *pPathname = vma->UserCheckAndGetAddress(pathname, PAGE_SIZE);
if (pPathname == nullptr)
return -EFAULT;
function("%s, %d, %d", pPathname, flags, mode); function("%s, %d, %d", pPathname, flags, mode);
@ -130,14 +144,11 @@ static int linux_stat(SysFrm *, const char *pathname, struct stat *statbuf)
{ {
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors;
Memory::Virtual vmm(pcb->PageTable); Memory::VirtualMemoryArea *vma = pcb->vma;
if (!vmm.Check((void *)pathname, Memory::US)) auto pPathname = vma->UserCheckAndGetAddress(pathname, PAGE_SIZE);
{ if (pPathname == nullptr)
debug("Invalid address %#lx", pathname);
return -EFAULT; return -EFAULT;
}
auto pPathname = pcb->PageTable->Get(pathname);
return fdt->_stat(pPathname, statbuf); return fdt->_stat(pPathname, statbuf);
} }
@ -148,14 +159,11 @@ static int linux_fstat(SysFrm *, int fd, struct stat *statbuf)
#undef fstat #undef fstat
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors;
Memory::Virtual vmm(pcb->PageTable); Memory::VirtualMemoryArea *vma = pcb->vma;
if (!vmm.Check((void *)statbuf, Memory::US)) auto pStatbuf = vma->UserCheckAndGetAddress(statbuf);
{ if (pStatbuf == nullptr)
debug("Invalid address %#lx", statbuf);
return -EFAULT; return -EFAULT;
}
auto pStatbuf = pcb->PageTable->Get(statbuf);
return fdt->_fstat(fd, pStatbuf); return fdt->_fstat(fd, pStatbuf);
} }
@ -166,22 +174,12 @@ static int linux_lstat(SysFrm *, const char *pathname, struct stat *statbuf)
#undef lstat #undef lstat
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors;
Memory::Virtual vmm(pcb->PageTable); Memory::VirtualMemoryArea *vma = pcb->vma;
if (!vmm.Check((void *)pathname, Memory::US)) auto pPathname = vma->UserCheckAndGetAddress(pathname, PAGE_SIZE);
{ auto pStatbuf = vma->UserCheckAndGetAddress(statbuf);
debug("Invalid address %#lx", pathname); if (pPathname == nullptr || pStatbuf == nullptr)
return -EFAULT; return -EFAULT;
}
if (!vmm.Check((void *)statbuf, Memory::US))
{
debug("Invalid address %#lx", statbuf);
return -EFAULT;
}
auto pPathname = pcb->PageTable->Get(pathname);
auto pStatbuf = pcb->PageTable->Get(statbuf);
return fdt->_lstat(pPathname, pStatbuf); return fdt->_lstat(pPathname, pStatbuf);
} }
@ -291,7 +289,6 @@ static void *linux_mmap(SysFrm *, void *addr, size_t length, int prot,
if (p_Read) if (p_Read)
{ {
Memory::Virtual vmm = Memory::Virtual(pcb->PageTable);
void *pBuf = vma->RequestPages(TO_PAGES(length)); void *pBuf = vma->RequestPages(TO_PAGES(length));
debug("created buffer at %#lx-%#lx", debug("created buffer at %#lx-%#lx",
pBuf, (uintptr_t)pBuf + length); pBuf, (uintptr_t)pBuf + length);
@ -305,30 +302,34 @@ static void *linux_mmap(SysFrm *, void *addr, size_t length, int prot,
if (m_Shared) if (m_Shared)
return (void *)-ENOSYS; return (void *)-ENOSYS;
if (vmm.CheckRegion(addr, Memory::G)) int mRet = vma->Map(addr, pBuf, length, mFlags);
if (mRet < 0)
{ {
debug("Address range %#lx-%#lx has a global page", debug("Failed to map file: %s", strerror(mRet));
addr, (uintptr_t)addr + length); return (void *)(uintptr_t)mRet;
// return (void *)-EINVAL;
} }
vmm.Map(addr, pBuf, length, mFlags);
off_t oldOff = fdt->_lseek(fildes, 0, SEEK_CUR); off_t oldOff = fdt->_lseek(fildes, 0, SEEK_CUR);
fdt->_lseek(fildes, offset, SEEK_SET); fdt->_lseek(fildes, offset, SEEK_SET);
ssize_t ret = fdt->_read(fildes, pBuf, length); ssize_t ret = fdt->_read(fildes, pBuf, length);
fdt->_lseek(fildes, oldOff, SEEK_SET); fdt->_lseek(fildes, oldOff, SEEK_SET);
if (ret < 0) if (ret < 0)
{ {
debug("Failed to read file"); debug("Failed to read file");
return (void *)-ret; return (void *)ret;
} }
return addr; return addr;
} }
else else
vmm.Map(pBuf, pBuf, length, mFlags); {
int mRet = vma->Map(pBuf, pBuf, length, mFlags);
if (mRet < 0)
{
debug("Failed to map file: %s", strerror(mRet));
return (void *)(uintptr_t)mRet;
}
}
off_t oldOff = fdt->_lseek(fildes, 0, SEEK_CUR); off_t oldOff = fdt->_lseek(fildes, 0, SEEK_CUR);
fdt->_lseek(fildes, offset, SEEK_SET); fdt->_lseek(fildes, offset, SEEK_SET);
@ -340,7 +341,7 @@ static void *linux_mmap(SysFrm *, void *addr, size_t length, int prot,
if (ret < 0) if (ret < 0)
{ {
debug("Failed to read file"); debug("Failed to read file");
return (void *)-ret; return (void *)ret;
} }
return pBuf; return pBuf;
} }
@ -349,10 +350,9 @@ static void *linux_mmap(SysFrm *, void *addr, size_t length, int prot,
return (void *)-ENOSYS; return (void *)-ENOSYS;
} }
intptr_t ret = (intptr_t)vma->CreateCoWRegion(addr, length, void *ret = vma->CreateCoWRegion(addr, length,
p_Read, p_Write, p_Exec, p_Read, p_Write, p_Exec,
m_Fixed, m_Shared); m_Fixed, m_Shared);
return (void *)ret; return (void *)ret;
} }
#undef __FENNIX_KERNEL_SYSCALLS_LIST_H__ #undef __FENNIX_KERNEL_SYSCALLS_LIST_H__
@ -378,58 +378,56 @@ static int linux_mprotect(SysFrm *, void *addr, size_t len, int prot)
i < uintptr_t(addr) + len; i < uintptr_t(addr) + len;
i += PAGE_SIZE) i += PAGE_SIZE)
{ {
if (likely(!vmm.Check((void *)i, Memory::G))) if (unlikely(vmm.Check((void *)i, Memory::G)))
{
Memory::PageTableEntry *pte = vmm.GetPTE(addr);
if (pte == nullptr)
{
debug("Page %#lx is not mapped inside %#lx",
(void *)i, pcb->PageTable);
fixme("Page %#lx is not mapped", (void *)i);
continue;
return -ENOMEM;
}
if (!pte->Present ||
(!pte->UserSupervisor && p_Read) ||
(!pte->ReadWrite && p_Write))
{
debug("Page %p is not mapped with the correct permissions",
(void *)i);
return -EACCES;
}
// pte->Present = !p_None;
pte->UserSupervisor = p_Read;
pte->ReadWrite = p_Write;
// pte->ExecuteDisable = p_Exec;
debug("Changed permissions of page %#lx to %s %s %s %s",
(void *)i,
(prot & sc_PROT_NONE) ? "None" : "",
p_Read ? "Read" : "",
p_Write ? "Write" : "",
(prot & sc_PROT_EXEC) ? "Exec" : "");
#if defined(a64)
CPU::x64::invlpg(addr);
#elif defined(a32)
CPU::x32::invlpg(addr);
#elif defined(aa64)
asmv("dsb sy");
asmv("tlbi vae1is, %0"
:
: "r"(addr)
: "memory");
asmv("dsb sy");
asmv("isb");
#endif
}
else
{ {
warn("%p is a global page", (void *)i); warn("%p is a global page", (void *)i);
return -ENOMEM; return -ENOMEM;
} }
Memory::PageTableEntry *pte = vmm.GetPTE(addr);
if (pte == nullptr)
{
debug("Page %#lx is not mapped inside %#lx",
(void *)i, pcb->PageTable);
fixme("Page %#lx is not mapped", (void *)i);
continue;
return -ENOMEM;
}
if (!pte->Present ||
(!pte->UserSupervisor && p_Read) ||
(!pte->ReadWrite && p_Write))
{
debug("Page %p is not mapped with the correct permissions",
(void *)i);
return -EACCES;
}
// pte->Present = !p_None;
pte->UserSupervisor = p_Read;
pte->ReadWrite = p_Write;
// pte->ExecuteDisable = p_Exec;
debug("Changed permissions of page %#lx to %s %s %s %s",
(void *)i,
(prot & sc_PROT_NONE) ? "None" : "",
p_Read ? "Read" : "",
p_Write ? "Write" : "",
(prot & sc_PROT_EXEC) ? "Exec" : "");
#if defined(a64)
CPU::x64::invlpg(addr);
#elif defined(a32)
CPU::x32::invlpg(addr);
#elif defined(aa64)
asmv("dsb sy");
asmv("tlbi vae1is, %0"
:
: "r"(addr)
: "memory");
asmv("dsb sy");
asmv("isb");
#endif
} }
return 0; return 0;
@ -446,21 +444,7 @@ static int linux_munmap(SysFrm *, void *addr, size_t length)
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
Memory::VirtualMemoryArea *vma = pcb->vma; Memory::VirtualMemoryArea *vma = pcb->vma;
Memory::Virtual vmm = Memory::Virtual(pcb->PageTable); vma->FreePages((void *)addr, TO_PAGES(length));
for (uintptr_t i = uintptr_t(addr);
i < uintptr_t(addr) + length;
i += PAGE_SIZE)
{
if (likely(!vmm.Check((void *)i, Memory::G)))
vmm.Remap((void *)i, (void *)i, Memory::P | Memory::RW);
else
warn("%p is a global page", (void *)i);
}
/* TODO: Check if the page is allocated
and not only mapped */
vma->FreePages((void *)addr, TO_PAGES(length) + 1);
return 0; return 0;
} }
@ -478,14 +462,11 @@ static int linux_ioctl(SysFrm *, int fd, unsigned long request, void *argp)
{ {
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors;
Memory::Virtual vmm(pcb->PageTable); Memory::VirtualMemoryArea *vma = pcb->vma;
if (!vmm.Check((void *)argp, Memory::US)) auto pArgp = vma->UserCheckAndGetAddress(argp);
{ if (pArgp == nullptr)
debug("Invalid address %#lx", argp);
return -EFAULT; return -EFAULT;
}
auto pArgp = pcb->PageTable->Get(argp);
return fdt->_ioctl(fd, request, pArgp); return fdt->_ioctl(fd, request, pArgp);
} }
@ -494,7 +475,11 @@ static int linux_ioctl(SysFrm *, int fd, unsigned long request, void *argp)
static ssize_t linux_readv(SysFrm *sf, int fildes, const struct iovec *iov, int iovcnt) static ssize_t linux_readv(SysFrm *sf, int fildes, const struct iovec *iov, int iovcnt)
{ {
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
const struct iovec *pIov = pcb->PageTable->Get(iov); Memory::VirtualMemoryArea *vma = pcb->vma;
const struct iovec *pIov = vma->UserCheckAndGetAddress(iov, sizeof(struct iovec) * iovcnt);
if (pIov == nullptr)
return -EFAULT;
ssize_t Total = 0; ssize_t Total = 0;
for (int i = 0; i < iovcnt; i++) for (int i = 0; i < iovcnt; i++)
@ -533,7 +518,11 @@ static ssize_t linux_readv(SysFrm *sf, int fildes, const struct iovec *iov, int
static ssize_t linux_writev(SysFrm *sf, int fildes, const struct iovec *iov, int iovcnt) static ssize_t linux_writev(SysFrm *sf, int fildes, const struct iovec *iov, int iovcnt)
{ {
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
const struct iovec *pIov = pcb->PageTable->Get(iov); Memory::VirtualMemoryArea *vma = pcb->vma;
const struct iovec *pIov = vma->UserCheckAndGetAddress(iov, sizeof(struct iovec) * iovcnt);
if (pIov == nullptr)
return -EFAULT;
ssize_t Total = 0; ssize_t Total = 0;
for (int i = 0; i < iovcnt; i++) for (int i = 0; i < iovcnt; i++)
@ -572,10 +561,14 @@ static ssize_t linux_writev(SysFrm *sf, int fildes, const struct iovec *iov, int
static int linux_access(SysFrm *, const char *pathname, int mode) static int linux_access(SysFrm *, const char *pathname, int mode)
{ {
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
auto pPathname = pcb->PageTable->Get(pathname); Memory::VirtualMemoryArea *vma = pcb->vma;
auto pPathname = vma->UserCheckAndGetAddress(pathname);
if (pPathname == nullptr)
return -EFAULT;
stub; stub;
debug("access(%s, %d)", (char *)pPathname, mode); fixme("access(%s, %d)", (char *)pPathname, mode);
return 0; return 0;
} }
@ -583,7 +576,9 @@ static int linux_access(SysFrm *, const char *pathname, int mode)
static int linux_pipe(SysFrm *, int pipefd[2]) static int linux_pipe(SysFrm *, int pipefd[2])
{ {
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
int *pPipefd = pcb->PageTable->Get(pipefd); Memory::VirtualMemoryArea *vma = pcb->vma;
int *pPipefd = vma->UserCheckAndGetAddress(pipefd);
debug("pipefd=%#lx", pPipefd); debug("pipefd=%#lx", pPipefd);
fixme("pipefd=[%d, %d]", pPipefd[0], pPipefd[1]); fixme("pipefd=[%d, %d]", pPipefd[0], pPipefd[1]);
return -ENOSYS; return -ENOSYS;
@ -618,22 +613,12 @@ static int linux_nanosleep(SysFrm *,
struct timespec *rem) struct timespec *rem)
{ {
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
Memory::Virtual vmm(pcb->PageTable); Memory::VirtualMemoryArea *vma = pcb->vma;
if (!vmm.Check((void *)req, Memory::US)) auto pReq = vma->UserCheckAndGetAddress(req);
{ auto pRem = vma->UserCheckAndGetAddress(rem);
debug("Invalid address %#lx", req); if (pReq == nullptr || pRem == nullptr)
return -EFAULT; return -EFAULT;
}
if (rem && !vmm.Check((void *)rem, Memory::US))
{
debug("Invalid address %#lx", rem);
return -EFAULT;
}
auto pReq = pcb->PageTable->Get(req);
auto pRem = rem ? pcb->PageTable->Get(rem) : 0;
if (pReq->tv_nsec < 0 || pReq->tv_nsec > 999999999) if (pReq->tv_nsec < 0 || pReq->tv_nsec > 999999999)
{ {
@ -711,7 +696,7 @@ static pid_t linux_fork(SysFrm *sf)
} }
NewProcess->PageTable = Parent->PageTable->Fork(); NewProcess->PageTable = Parent->PageTable->Fork();
NewProcess->vma->SetTable(NewProcess->PageTable); NewProcess->vma->Table = NewProcess->PageTable;
NewProcess->vma->Fork(Parent->vma); NewProcess->vma->Fork(Parent->vma);
NewProcess->ProgramBreak->SetTable(NewProcess->PageTable); NewProcess->ProgramBreak->SetTable(NewProcess->PageTable);
NewProcess->FileDescriptors->Fork(Parent->FileDescriptors); NewProcess->FileDescriptors->Fork(Parent->FileDescriptors);
@ -778,64 +763,36 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn
/* FIXME: exec doesn't follow the UNIX standard /* FIXME: exec doesn't follow the UNIX standard
The pid, open files, etc. should be preserved */ The pid, open files, etc. should be preserved */
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
Memory::Virtual vmm = Memory::Virtual(pcb->PageTable); Memory::VirtualMemoryArea *vma = pcb->vma;
if (pathname == nullptr || auto pPathname = vma->UserCheckAndGetAddress(pathname, PAGE_SIZE);
!vmm.Check((void *)pathname, Memory::US) || auto pArgv = vma->UserCheckAndGetAddress(argv, 1/*MAX_ARG*/); /* MAX_ARG is too much? */
!vmm.Check((void *)argv, Memory::US) || auto pEnvp = vma->UserCheckAndGetAddress(envp, 1/*MAX_ARG*/);
!vmm.Check((void *)envp, Memory::US)) if (pPathname == nullptr || pArgv == nullptr || pEnvp == nullptr)
return -ENOENT;
if (!vmm.Check((void *)pathname, Memory::US))
{
debug("Invalid address %#lx", pathname);
return -EFAULT; return -EFAULT;
}
if (!vmm.Check((void *)argv, Memory::US))
{
debug("Invalid address %#lx", argv);
return -EFAULT;
}
if (!vmm.Check((void *)envp, Memory::US))
{
debug("Invalid address %#lx", envp);
return -EFAULT;
}
auto pPathname = pcb->PageTable->Get(pathname);
auto pArgv = pcb->PageTable->Get(argv);
auto pEnvp = pcb->PageTable->Get(envp);
function("%s %#lx %#lx", pPathname, pArgv, pEnvp); function("%s %#lx %#lx", pPathname, pArgv, pEnvp);
int argvLen = 0; int argvLen = 0;
for (argvLen = 0; MAX_ARG; argvLen++) for (argvLen = 0; MAX_ARG; argvLen++)
{ {
if (vma->UserCheck(pArgv[argvLen]) < 0)
break;
auto arg = pcb->PageTable->Get(pArgv[argvLen]); auto arg = pcb->PageTable->Get(pArgv[argvLen]);
if (arg == nullptr) if (arg == nullptr)
break; break;
if (!vmm.Check((void *)arg, Memory::US))
{
debug("Invalid address %#lx", arg);
return -EFAULT;
}
} }
int envpLen = 0; int envpLen = 0;
for (envpLen = 0; MAX_ARG; envpLen++) for (envpLen = 0; MAX_ARG; envpLen++)
{ {
if (vma->UserCheck(pEnvp[envpLen]) < 0)
break;
auto arg = pcb->PageTable->Get(pEnvp[envpLen]); auto arg = pcb->PageTable->Get(pEnvp[envpLen]);
if (arg == nullptr) if (arg == nullptr)
break; break;
if (!vmm.Check((void *)arg, Memory::US))
{
debug("Invalid address %#lx", arg);
return -EFAULT;
}
} }
char **safe_argv = (char **)pcb->vma->RequestPages(TO_PAGES(argvLen * sizeof(char *))); char **safe_argv = (char **)pcb->vma->RequestPages(TO_PAGES(argvLen * sizeof(char *)));
@ -1011,13 +968,7 @@ static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus,
inefficient and should be rewritten */ inefficient and should be rewritten */
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
Memory::Virtual vmm(pcb->PageTable); Memory::VirtualMemoryArea *vma = pcb->vma;
if (!vmm.Check(rusage, Memory::US) && rusage != nullptr)
{
debug("Invalid address %#lx", rusage);
return -EFAULT;
}
if (pid == -1) if (pid == -1)
{ {
@ -1052,7 +1003,9 @@ static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus,
size_t uTime = child->Info.UserTime; size_t uTime = child->Info.UserTime;
size_t _maxrss = child->GetSize(); size_t _maxrss = child->GetSize();
struct rusage *pRusage = pcb->PageTable->Get(rusage); struct rusage *pRusage = vma->UserCheckAndGetAddress(rusage);
if (pRusage == nullptr)
return -EFAULT;
pRusage->ru_utime.tv_sec = uTime / 1000000000000000; /* Seconds */ pRusage->ru_utime.tv_sec = uTime / 1000000000000000; /* Seconds */
pRusage->ru_utime.tv_usec = uTime / 1000000000; /* Microseconds */ pRusage->ru_utime.tv_usec = uTime / 1000000000; /* Microseconds */
@ -1071,7 +1024,9 @@ static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus,
{ {
if (wstatus != nullptr) if (wstatus != nullptr)
{ {
int *pWstatus = pcb->PageTable->Get(wstatus); int *pWstatus = vma->UserCheckAndGetAddress(wstatus);
if (pWstatus == nullptr)
return -EFAULT;
*pWstatus = 0; *pWstatus = 0;
bool ProcessExited = true; bool ProcessExited = true;
@ -1098,7 +1053,9 @@ static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus,
size_t uTime = child->Info.UserTime; size_t uTime = child->Info.UserTime;
size_t _maxrss = child->GetSize(); size_t _maxrss = child->GetSize();
struct rusage *pRusage = pcb->PageTable->Get(rusage); struct rusage *pRusage = vma->UserCheckAndGetAddress(rusage);
if (pRusage == nullptr)
return -EFAULT;
pRusage->ru_utime.tv_sec = uTime / 1000000000000000; /* Seconds */ pRusage->ru_utime.tv_sec = uTime / 1000000000000000; /* Seconds */
pRusage->ru_utime.tv_usec = uTime / 1000000000; /* Microseconds */ pRusage->ru_utime.tv_usec = uTime / 1000000000; /* Microseconds */
@ -1172,7 +1129,9 @@ static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus,
if (wstatus != nullptr) if (wstatus != nullptr)
{ {
int *pWstatus = pcb->PageTable->Get(wstatus); int *pWstatus = vma->UserCheckAndGetAddress(wstatus);
if (pWstatus == nullptr)
return -EFAULT;
*pWstatus = 0; *pWstatus = 0;
bool ProcessExited = true; bool ProcessExited = true;
@ -1211,7 +1170,9 @@ static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus,
size_t uTime = tPcb->Info.UserTime; size_t uTime = tPcb->Info.UserTime;
size_t _maxrss = tPcb->GetSize(); size_t _maxrss = tPcb->GetSize();
struct rusage *pRusage = pcb->PageTable->Get(rusage); struct rusage *pRusage = vma->UserCheckAndGetAddress(rusage);
if (pRusage == nullptr)
return -EFAULT;
pRusage->ru_utime.tv_sec = uTime / 1000000000000000; /* Seconds */ pRusage->ru_utime.tv_sec = uTime / 1000000000000000; /* Seconds */
pRusage->ru_utime.tv_usec = uTime / 1000000000; /* Microseconds */ pRusage->ru_utime.tv_usec = uTime / 1000000000; /* Microseconds */
@ -1265,15 +1226,11 @@ static int linux_uname(SysFrm *, struct utsname *buf)
assert(sizeof(struct utsname) < PAGE_SIZE); assert(sizeof(struct utsname) < PAGE_SIZE);
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
Memory::Virtual vmm(pcb->PageTable); Memory::VirtualMemoryArea *vma = pcb->vma;
if (!vmm.Check(buf, Memory::US)) auto pBuf = vma->UserCheckAndGetAddress(buf);
{ if (pBuf == nullptr)
debug("Invalid address %#lx", buf);
return -EFAULT; return -EFAULT;
}
auto pBuf = pcb->PageTable->Get(buf);
struct utsname uname = struct utsname uname =
{ {
@ -1337,11 +1294,11 @@ static int linux_uname(SysFrm *, struct utsname *buf)
return 0; return 0;
} }
/* https://man7.org/linux/man-pages/man2/fcntl.2.html */
static int linux_fcntl(SysFrm *, int fd, int cmd, void *arg) static int linux_fcntl(SysFrm *, int fd, int cmd, void *arg)
{ {
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors;
Memory::Virtual vmm(pcb->PageTable);
switch (cmd) switch (cmd)
{ {
@ -1386,9 +1343,13 @@ static int linux_creat(SysFrm *, const char *pathname, mode_t mode)
static int linux_mkdir(SysFrm *, const char *pathname, mode_t mode) static int linux_mkdir(SysFrm *, const char *pathname, mode_t mode)
{ {
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
Memory::VirtualMemoryArea *vma = pcb->vma;
fixme("semi-stub"); fixme("semi-stub");
const char *pPathname = pcb->PageTable->Get(pathname); const char *pPathname = vma->UserCheckAndGetAddress(pathname);
if (!pPathname)
return -EFAULT;
vfs::Node *n = fs->Create(pPathname, vfs::DIRECTORY, pcb->CurrentWorkingDirectory); vfs::Node *n = fs->Create(pPathname, vfs::DIRECTORY, pcb->CurrentWorkingDirectory);
if (!n) if (!n)
return -EEXIST; return -EEXIST;
@ -1409,15 +1370,13 @@ static ssize_t linux_readlink(SysFrm *, const char *pathname,
} }
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
Memory::Virtual vmm(pcb->PageTable); Memory::VirtualMemoryArea *vma = pcb->vma;
if (!vmm.Check((void *)buf, Memory::US))
{ const char *pPath = vma->UserCheckAndGetAddress(pathname);
warn("Invalid address %#lx", buf); char *pBuf = vma->UserCheckAndGetAddress(buf);
return -EFAULT; if (pPath == nullptr || pBuf == nullptr)
} return -EFAULT;
const char *pPath = pcb->PageTable->Get(pathname);
char *pBuf = pcb->PageTable->Get(buf);
function("%s %#lx %ld", pPath, buf, bufsiz); function("%s %#lx %ld", pPath, buf, bufsiz);
vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors;
int fd = fdt->_open(pPath, O_RDONLY, 0); int fd = fdt->_open(pPath, O_RDONLY, 0);
@ -1479,19 +1438,10 @@ static pid_t linux_getppid(SysFrm *)
static int linux_arch_prctl(SysFrm *, int code, unsigned long addr) static int linux_arch_prctl(SysFrm *, int code, unsigned long addr)
{ {
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
Memory::Virtual vmm(pcb->PageTable); Memory::VirtualMemoryArea *vma = pcb->vma;
if (!vmm.Check((void *)addr)) if (vma->UserCheck(addr) < 0)
{
debug("Invalid address %#lx", addr);
return -EFAULT; return -EFAULT;
}
if (!vmm.Check((void *)addr, Memory::US))
{
debug("Address %#lx is not user accessible", addr);
return -EPERM;
}
switch (code) switch (code)
{ {
@ -1577,6 +1527,7 @@ static int linux_reboot(SysFrm *, int magic, int magic2, int cmd, void *arg)
} }
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
Memory::VirtualMemoryArea *vma = pcb->vma;
debug("cmd=%#x arg=%#lx", cmd, arg); debug("cmd=%#x arg=%#lx", cmd, arg);
switch ((unsigned int)cmd) switch ((unsigned int)cmd)
@ -1610,14 +1561,10 @@ static int linux_reboot(SysFrm *, int magic, int magic2, int cmd, void *arg)
} }
case LINUX_REBOOT_CMD_RESTART2: case LINUX_REBOOT_CMD_RESTART2:
{ {
Memory::Virtual vmm(pcb->PageTable); void *pArg = vma->__UserCheckAndGetAddress(arg, sizeof(void *));
if (!vmm.Check(arg, Memory::US)) if (pArg == nullptr)
{
debug("Invalid address %#lx", arg);
return -EFAULT; return -EFAULT;
}
void *pArg = pcb->PageTable->Get(arg);
KPrint("Restarting system with command '%s'", KPrint("Restarting system with command '%s'",
(const char *)pArg); (const char *)pArg);
@ -1656,24 +1603,17 @@ static int linux_sigaction(SysFrm *, int signum,
} }
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
Memory::Virtual vmm(pcb->PageTable); Memory::VirtualMemoryArea *vma = pcb->vma;
if (oldact && !vmm.Check(oldact, Memory::US))
{
debug("Invalid address %#lx", oldact);
return -EFAULT;
}
if (act && !vmm.Check((void *)act, Memory::US))
{
debug("Invalid address %#lx", act);
return -EFAULT;
}
debug("signum=%d act=%#lx oldact=%#lx", signum, act, oldact); debug("signum=%d act=%#lx oldact=%#lx", signum, act, oldact);
auto pOldact = pcb->PageTable->Get(oldact); if (vma->UserCheck(act) < 0 && act != nullptr)
return -EFAULT;
if (vma->UserCheck(oldact) < 0 && oldact != nullptr)
return -EFAULT;
auto pAct = pcb->PageTable->Get(act); auto pAct = pcb->PageTable->Get(act);
auto pOldact = pcb->PageTable->Get(oldact);
int ret = 0; int ret = 0;
if (pOldact) if (pOldact)
@ -1701,6 +1641,13 @@ static int linux_sigprocmask(SysFrm *, int how, const sigset_t *set,
} }
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
Memory::VirtualMemoryArea *vma = pcb->vma;
if (vma->UserCheck(set) < 0 && set != nullptr)
return -EFAULT;
if (vma->UserCheck(oldset) < 0 && oldset != nullptr)
return -EFAULT;
const sigset_t *pSet = (const sigset_t *)pcb->PageTable->Get((void *)set); const sigset_t *pSet = (const sigset_t *)pcb->PageTable->Get((void *)set);
sigset_t *pOldset = (sigset_t *)pcb->PageTable->Get(oldset); sigset_t *pOldset = (sigset_t *)pcb->PageTable->Get(oldset);
@ -1761,6 +1708,7 @@ static ssize_t linux_getdents64(SysFrm *, int fd, struct linux_dirent64 *dirp,
{ {
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors;
Memory::VirtualMemoryArea *vma = pcb->vma;
if (count < sizeof(struct linux_dirent64)) if (count < sizeof(struct linux_dirent64))
{ {
@ -1783,7 +1731,10 @@ static ssize_t linux_getdents64(SysFrm *, int fd, struct linux_dirent64 *dirp,
return -ENOTDIR; return -ENOTDIR;
} }
auto pDirp = pcb->PageTable->Get(dirp); auto pDirp = vma->UserCheckAndGetAddress(dirp);
if (pDirp == nullptr)
return -EFAULT;
UNUSED(pDirp); UNUSED(pDirp);
stub; stub;
return -ENOSYS; return -ENOSYS;
@ -1795,15 +1746,11 @@ static int linux_clock_gettime(SysFrm *, clockid_t clockid, struct timespec *tp)
static_assert(sizeof(struct timespec) < PAGE_SIZE); static_assert(sizeof(struct timespec) < PAGE_SIZE);
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
Memory::Virtual vmm(pcb->PageTable); Memory::VirtualMemoryArea *vma = pcb->vma;
if (!vmm.Check(tp, Memory::US)) timespec *pTp = vma->UserCheckAndGetAddress(tp);
{ if (pTp == nullptr)
debug("Invalid address %#lx", tp);
return -EFAULT; return -EFAULT;
}
timespec *pTp = pcb->PageTable->Get(tp);
/* FIXME: This is not correct? */ /* FIXME: This is not correct? */
switch (clockid) switch (clockid)
@ -1875,23 +1822,11 @@ static long linux_newfstatat(SysFrm *, int dfd, const char *filename,
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors;
Memory::Virtual vmm(pcb->PageTable); Memory::VirtualMemoryArea *vma = pcb->vma;
if (flag) if (flag)
fixme("flag %#x is stub", flag); fixme("flag %#x is stub", flag);
if (!filename)
{
debug("Invalid filename %#lx", filename);
return -EFAULT;
}
if (!statbuf)
{
debug("Invalid statbuf %#lx", statbuf);
return -EFAULT;
}
if (dfd == AT_FDCWD) if (dfd == AT_FDCWD)
{ {
fixme("dfd AT_FDCWD is stub"); fixme("dfd AT_FDCWD is stub");
@ -1906,8 +1841,10 @@ static long linux_newfstatat(SysFrm *, int dfd, const char *filename,
return -EBADF; return -EBADF;
} }
const char *pFilename = pcb->PageTable->Get(filename); const char *pFilename = vma->UserCheckAndGetAddress(filename);
struct stat *pStatbuf = pcb->PageTable->Get(statbuf); struct stat *pStatbuf = vma->UserCheckAndGetAddress(statbuf);
if (pFilename == nullptr || pStatbuf == nullptr)
return -EFAULT;
debug("%s %#lx %#lx", pFilename, filename, statbuf); debug("%s %#lx %#lx", pFilename, filename, statbuf);
return fdt->_stat(pFilename, pStatbuf); return fdt->_stat(pFilename, pStatbuf);
@ -1920,7 +1857,12 @@ static int linux_pipe2(SysFrm *sf, int pipefd[2], int flags)
return linux_pipe(sf, pipefd); return linux_pipe(sf, pipefd);
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
int *pPipefd = pcb->PageTable->Get(pipefd); Memory::VirtualMemoryArea *vma = pcb->vma;
int *pPipefd = vma->UserCheckAndGetAddress(pipefd);
if (pPipefd == nullptr)
return -EFAULT;
debug("pipefd=%#lx", pPipefd); debug("pipefd=%#lx", pPipefd);
fixme("pipefd=[%d, %d] flags=%#x", pPipefd[0], pPipefd[1], flags); fixme("pipefd=[%d, %d] flags=%#x", pPipefd[0], pPipefd[1], flags);
return -ENOSYS; return -ENOSYS;
@ -1934,22 +1876,15 @@ static int linux_prlimit64(SysFrm *, pid_t pid, int resource,
static_assert(sizeof(struct rlimit) < PAGE_SIZE); static_assert(sizeof(struct rlimit) < PAGE_SIZE);
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
Memory::Virtual vmm(pcb->PageTable); Memory::VirtualMemoryArea *vma = pcb->vma;
if (old_limit && !vmm.Check(old_limit, Memory::US)) auto pOldLimit = vma->UserCheckAndGetAddress(old_limit);
{ auto pNewLimit = vma->UserCheckAndGetAddress(new_limit);
debug("Invalid address %#lx", old_limit); if (pOldLimit == nullptr && old_limit != nullptr)
return -EFAULT; return -EFAULT;
}
if (new_limit && !vmm.Check((void *)new_limit, Memory::US)) if (pNewLimit == nullptr && new_limit != nullptr)
{
debug("Invalid address %#lx", new_limit);
return -EFAULT; return -EFAULT;
}
auto pOldLimit = pcb->PageTable->Get(old_limit);
auto pNewLimit = pcb->PageTable->Get(new_limit);
UNUSED(pOldLimit); UNUSED(pOldLimit);
UNUSED(pNewLimit); UNUSED(pNewLimit);
@ -1992,13 +1927,7 @@ static ssize_t linux_getrandom(SysFrm *, void *buf,
size_t buflen, unsigned int flags) size_t buflen, unsigned int flags)
{ {
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
Memory::Virtual vmm(pcb->PageTable); Memory::VirtualMemoryArea *vma = pcb->vma;
if (!vmm.Check(buf, Memory::US))
{
debug("Invalid address %#lx", buf);
return -EFAULT;
}
if (flags & GRND_NONBLOCK) if (flags & GRND_NONBLOCK)
fixme("GRND_NONBLOCK not implemented"); fixme("GRND_NONBLOCK not implemented");
@ -2011,6 +1940,10 @@ static ssize_t linux_getrandom(SysFrm *, void *buf,
return -EINVAL; return -EINVAL;
} }
auto pBuf = vma->UserCheckAndGetAddress(buf, buflen);
if (pBuf == nullptr)
return -EFAULT;
if (flags & GRND_RANDOM) if (flags & GRND_RANDOM)
{ {
uint16_t random; uint16_t random;
@ -2019,7 +1952,7 @@ static ssize_t linux_getrandom(SysFrm *, void *buf,
random = Random::rand16(); random = Random::rand16();
{ {
Memory::SwapPT swap(pcb->PageTable); Memory::SwapPT swap(pcb->PageTable);
((uint8_t *)buf)[i] = uint8_t(random & 0xFF); ((uint8_t *)pBuf)[i] = uint8_t(random & 0xFF);
} }
} }
return buflen; return buflen;

View File

@ -454,7 +454,7 @@ namespace Tasking
else else
this->SetState(Ready); this->SetState(Ready);
this->vma = new Memory::VirtualMemoryArea(this->Parent->PageTable); this->vma = this->Parent->vma;
#if defined(a64) #if defined(a64)
this->Registers.rip = EntryPoint; this->Registers.rip = EntryPoint;
@ -507,13 +507,13 @@ namespace Tasking
{ {
this->Stack = new Memory::StackGuard(true, this->vma); this->Stack = new Memory::StackGuard(true, this->vma);
gsTCB *gsT = (gsTCB *)this->vma->RequestPages(TO_PAGES(sizeof(gsTCB))); gsTCB *gsT = (gsTCB *)this->vma->RequestPages(TO_PAGES(sizeof(gsTCB)), false, true);
#ifdef DEBUG #ifdef DEBUG
gsT->__stub = 0xFFFFFFFFFFFFFFFF; gsT->__stub = 0xFFFFFFFFFFFFFFFF;
#endif #endif
gsT->ScPages = TO_PAGES(STACK_SIZE); gsT->ScPages = TO_PAGES(STACK_SIZE);
gsT->SyscallStackBase = this->vma->RequestPages(gsT->ScPages); gsT->SyscallStackBase = this->vma->RequestPages(gsT->ScPages, false, true);
gsT->SyscallStack = (void *)((uintptr_t)gsT->SyscallStackBase + STACK_SIZE - 0x10); gsT->SyscallStack = (void *)((uintptr_t)gsT->SyscallStackBase + STACK_SIZE - 0x10);
debug("New syscall stack created: %#lx (base: %#lx) with gs base at %#lx", debug("New syscall stack created: %#lx (base: %#lx) with gs base at %#lx",
gsT->SyscallStack, gsT->SyscallStackBase, gsT); gsT->SyscallStack, gsT->SyscallStackBase, gsT);
@ -641,9 +641,6 @@ namespace Tasking
/* Free CPU Stack */ /* Free CPU Stack */
delete this->Stack; delete this->Stack;
/* Free all allocated memory */
delete this->vma;
/* Free Name */ /* Free Name */
delete[] this->Name; delete[] this->Name;