mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 14:38:11 +00:00
Kernel: Wrap process address spaces in SpinlockProtected
This forces anyone who wants to look into and/or manipulate an address space to lock it. And this replaces the previous, more flimsy, manual spinlock use. Note that pointers *into* the address space are not safe to use after you unlock the space. We've got many issues like this, and we'll have to track those down as wlel.
This commit is contained in:
parent
d6ef18f587
commit
cf16b2c8e6
38 changed files with 708 additions and 627 deletions
|
@ -35,7 +35,7 @@ void handle_crash(Kernel::RegisterState const& regs, char const* description, in
|
|||
dump_registers(regs);
|
||||
|
||||
if (crashed_in_kernel) {
|
||||
process.address_space().dump_regions();
|
||||
process.address_space().with([&](auto& space) { space->dump_regions(); });
|
||||
PANIC("Crash in ring 0");
|
||||
}
|
||||
|
||||
|
|
|
@ -303,10 +303,16 @@ void page_fault_handler(TrapFrame* trap)
|
|||
};
|
||||
|
||||
VirtualAddress userspace_sp = VirtualAddress { regs.userspace_sp() };
|
||||
if (!faulted_in_kernel && !MM.validate_user_stack(current_thread->process().address_space(), userspace_sp)) {
|
||||
|
||||
if (!faulted_in_kernel) {
|
||||
bool has_valid_stack_pointer = current_thread->process().address_space().with([&](auto& space) {
|
||||
return MM.validate_user_stack(*space, userspace_sp);
|
||||
});
|
||||
if (!has_valid_stack_pointer) {
|
||||
dbgln("Invalid stack pointer: {}", userspace_sp);
|
||||
return handle_crash(regs, "Bad stack on page fault", SIGSEGV);
|
||||
}
|
||||
}
|
||||
|
||||
PageFault fault { regs.exception_code, VirtualAddress { fault_address } };
|
||||
auto response = MM.handle_page_fault(fault);
|
||||
|
|
|
@ -55,6 +55,7 @@ u32 RecursiveSpinlock::lock()
|
|||
|
||||
void RecursiveSpinlock::unlock(u32 prev_flags)
|
||||
{
|
||||
VERIFY_INTERRUPTS_DISABLED();
|
||||
VERIFY(m_recursions > 0);
|
||||
VERIFY(m_lock.load(AK::memory_order_relaxed) == FlatPtr(&Processor::current()));
|
||||
if (--m_recursions == 0) {
|
||||
|
|
|
@ -46,7 +46,8 @@ Coredump::Coredump(NonnullLockRefPtr<Process> process, NonnullLockRefPtr<OpenFil
|
|||
, m_description(move(description))
|
||||
{
|
||||
m_num_program_headers = 0;
|
||||
m_process->address_space().region_tree().with([&](auto& region_tree) {
|
||||
m_process->address_space().with([&](auto& space) {
|
||||
space->region_tree().with([&](auto& region_tree) {
|
||||
for (auto& region : region_tree.regions()) {
|
||||
#if !INCLUDE_USERSPACE_HEAP_MEMORY_IN_COREDUMPS
|
||||
if (looks_like_userspace_heap_region(region))
|
||||
|
@ -58,6 +59,7 @@ Coredump::Coredump(NonnullLockRefPtr<Process> process, NonnullLockRefPtr<OpenFil
|
|||
++m_num_program_headers;
|
||||
}
|
||||
});
|
||||
});
|
||||
++m_num_program_headers; // +1 for NOTE segment
|
||||
}
|
||||
|
||||
|
@ -135,7 +137,8 @@ ErrorOr<void> Coredump::write_elf_header()
|
|||
ErrorOr<void> Coredump::write_program_headers(size_t notes_size)
|
||||
{
|
||||
size_t offset = sizeof(ElfW(Ehdr)) + m_num_program_headers * sizeof(ElfW(Phdr));
|
||||
m_process->address_space().region_tree().with([&](auto& region_tree) {
|
||||
m_process->address_space().with([&](auto& space) {
|
||||
space->region_tree().with([&](auto& region_tree) {
|
||||
for (auto& region : region_tree.regions()) {
|
||||
|
||||
#if !INCLUDE_USERSPACE_HEAP_MEMORY_IN_COREDUMPS
|
||||
|
@ -168,6 +171,7 @@ ErrorOr<void> Coredump::write_program_headers(size_t notes_size)
|
|||
[[maybe_unused]] auto rc = m_description->write(UserOrKernelBuffer::for_kernel_buffer(reinterpret_cast<uint8_t*>(&phdr)), sizeof(ElfW(Phdr)));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ElfW(Phdr) notes_pheader {};
|
||||
notes_pheader.p_type = PT_NOTE;
|
||||
|
@ -188,7 +192,8 @@ ErrorOr<void> Coredump::write_regions()
|
|||
{
|
||||
u8 zero_buffer[PAGE_SIZE] = {};
|
||||
|
||||
return m_process->address_space().region_tree().with([&](auto& region_tree) -> ErrorOr<void> {
|
||||
return m_process->address_space().with([&](auto& space) {
|
||||
return space->region_tree().with([&](auto& region_tree) -> ErrorOr<void> {
|
||||
for (auto& region : region_tree.regions()) {
|
||||
VERIFY(!region.is_kernel());
|
||||
|
||||
|
@ -220,6 +225,7 @@ ErrorOr<void> Coredump::write_regions()
|
|||
}
|
||||
return {};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ErrorOr<void> Coredump::write_notes_segment(ReadonlyBytes notes_segment)
|
||||
|
@ -279,7 +285,8 @@ ErrorOr<void> Coredump::create_notes_threads_data(auto& builder) const
|
|||
ErrorOr<void> Coredump::create_notes_regions_data(auto& builder) const
|
||||
{
|
||||
size_t region_index = 0;
|
||||
return m_process->address_space().region_tree().with([&](auto& region_tree) -> ErrorOr<void> {
|
||||
return m_process->address_space().with([&](auto& space) {
|
||||
return space->region_tree().with([&](auto& region_tree) -> ErrorOr<void> {
|
||||
for (auto const& region : region_tree.regions()) {
|
||||
|
||||
#if !INCLUDE_USERSPACE_HEAP_MEMORY_IN_COREDUMPS
|
||||
|
@ -308,6 +315,7 @@ ErrorOr<void> Coredump::create_notes_regions_data(auto& builder) const
|
|||
}
|
||||
return {};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ErrorOr<void> Coredump::create_notes_metadata_data(auto& builder) const
|
||||
|
@ -344,7 +352,6 @@ ErrorOr<void> Coredump::create_notes_segment_data(auto& builder) const
|
|||
|
||||
ErrorOr<void> Coredump::write()
|
||||
{
|
||||
SpinlockLocker lock(m_process->address_space().get_lock());
|
||||
ScopedAddressSpaceSwitcher switcher(m_process);
|
||||
|
||||
auto builder = TRY(KBufferBuilder::try_create());
|
||||
|
|
|
@ -116,7 +116,7 @@ ErrorOr<void> KCOVDevice::ioctl(OpenFileDescription&, unsigned request, Userspac
|
|||
}
|
||||
}
|
||||
|
||||
ErrorOr<Memory::Region*> KCOVDevice::mmap(Process& process, OpenFileDescription&, Memory::VirtualRange const& range, u64 offset, int prot, bool shared)
|
||||
ErrorOr<Memory::Region*> KCOVDevice::mmap(Process& process, Memory::AddressSpace& address_space, OpenFileDescription&, Memory::VirtualRange const& range, u64 offset, int prot, bool shared)
|
||||
{
|
||||
auto pid = process.pid();
|
||||
auto maybe_kcov_instance = proc_instance->get(pid);
|
||||
|
@ -126,8 +126,7 @@ ErrorOr<Memory::Region*> KCOVDevice::mmap(Process& process, OpenFileDescription&
|
|||
if (!kcov_instance->vmobject())
|
||||
return ENOBUFS; // mmaped, before KCOV_SETBUFSIZE
|
||||
|
||||
return process.address_space().allocate_region_with_vmobject(
|
||||
range, *kcov_instance->vmobject(), offset, {}, prot, shared);
|
||||
return address_space.allocate_region_with_vmobject(range, *kcov_instance->vmobject(), offset, {}, prot, shared);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ public:
|
|||
static void free_process();
|
||||
|
||||
// ^File
|
||||
ErrorOr<Memory::Region*> mmap(Process&, OpenFileDescription&, Memory::VirtualRange const&, u64 offset, int prot, bool shared) override;
|
||||
ErrorOr<Memory::Region*> mmap(Process&, Memory::AddressSpace&, OpenFileDescription&, Memory::VirtualRange const&, u64 offset, int prot, bool shared) override;
|
||||
ErrorOr<NonnullLockRefPtr<OpenFileDescription>> open(int options) override;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -42,7 +42,7 @@ ErrorOr<size_t> MemoryDevice::read(OpenFileDescription&, u64 offset, UserOrKerne
|
|||
return length;
|
||||
}
|
||||
|
||||
ErrorOr<Memory::Region*> MemoryDevice::mmap(Process& process, OpenFileDescription&, Memory::VirtualRange const& range, u64 offset, int prot, bool shared)
|
||||
ErrorOr<Memory::Region*> MemoryDevice::mmap(Process&, Memory::AddressSpace& address_space, OpenFileDescription&, Memory::VirtualRange const& range, u64 offset, int prot, bool shared)
|
||||
{
|
||||
auto viewed_address = PhysicalAddress(offset);
|
||||
|
||||
|
@ -63,7 +63,7 @@ ErrorOr<Memory::Region*> MemoryDevice::mmap(Process& process, OpenFileDescriptio
|
|||
|
||||
auto vmobject = TRY(Memory::AnonymousVMObject::try_create_for_physical_range(viewed_address, range.size()));
|
||||
|
||||
return process.address_space().allocate_region_with_vmobject(
|
||||
return address_space.allocate_region_with_vmobject(
|
||||
range,
|
||||
move(vmobject),
|
||||
0,
|
||||
|
|
|
@ -19,7 +19,7 @@ public:
|
|||
static NonnullLockRefPtr<MemoryDevice> must_create();
|
||||
~MemoryDevice();
|
||||
|
||||
virtual ErrorOr<Memory::Region*> mmap(Process&, OpenFileDescription&, Memory::VirtualRange const&, u64 offset, int prot, bool shared) override;
|
||||
virtual ErrorOr<Memory::Region*> mmap(Process&, Memory::AddressSpace&, OpenFileDescription&, Memory::VirtualRange const&, u64 offset, int prot, bool shared) override;
|
||||
|
||||
private:
|
||||
MemoryDevice();
|
||||
|
|
|
@ -17,12 +17,12 @@ AnonymousFile::AnonymousFile(NonnullLockRefPtr<Memory::AnonymousVMObject> vmobje
|
|||
|
||||
AnonymousFile::~AnonymousFile() = default;
|
||||
|
||||
ErrorOr<Memory::Region*> AnonymousFile::mmap(Process& process, OpenFileDescription&, Memory::VirtualRange const& range, u64 offset, int prot, bool shared)
|
||||
ErrorOr<Memory::Region*> AnonymousFile::mmap(Process&, Memory::AddressSpace& address_space, OpenFileDescription&, Memory::VirtualRange const& range, u64 offset, int prot, bool shared)
|
||||
{
|
||||
if (offset != 0)
|
||||
return EINVAL;
|
||||
|
||||
return process.address_space().allocate_region_with_vmobject(range, m_vmobject, offset, {}, prot, shared);
|
||||
return address_space.allocate_region_with_vmobject(range, m_vmobject, offset, {}, prot, shared);
|
||||
}
|
||||
|
||||
ErrorOr<NonnullOwnPtr<KString>> AnonymousFile::pseudo_path(OpenFileDescription const&) const
|
||||
|
|
|
@ -20,7 +20,7 @@ public:
|
|||
|
||||
virtual ~AnonymousFile() override;
|
||||
|
||||
virtual ErrorOr<Memory::Region*> mmap(Process&, OpenFileDescription&, Memory::VirtualRange const&, u64 offset, int prot, bool shared) override;
|
||||
virtual ErrorOr<Memory::Region*> mmap(Process&, Memory::AddressSpace&, OpenFileDescription&, Memory::VirtualRange const&, u64 offset, int prot, bool shared) override;
|
||||
|
||||
private:
|
||||
virtual StringView class_name() const override { return "AnonymousFile"sv; }
|
||||
|
|
|
@ -35,7 +35,7 @@ ErrorOr<void> File::ioctl(OpenFileDescription&, unsigned, Userspace<void*>)
|
|||
return ENOTTY;
|
||||
}
|
||||
|
||||
ErrorOr<Memory::Region*> File::mmap(Process&, OpenFileDescription&, Memory::VirtualRange const&, u64, int, bool)
|
||||
ErrorOr<Memory::Region*> File::mmap(Process&, Memory::AddressSpace&, OpenFileDescription&, Memory::VirtualRange const&, u64, int, bool)
|
||||
{
|
||||
return ENODEV;
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ public:
|
|||
virtual ErrorOr<size_t> read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t) = 0;
|
||||
virtual ErrorOr<size_t> write(OpenFileDescription&, u64, UserOrKernelBuffer const&, size_t) = 0;
|
||||
virtual ErrorOr<void> ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg);
|
||||
virtual ErrorOr<Memory::Region*> mmap(Process&, OpenFileDescription&, Memory::VirtualRange const&, u64 offset, int prot, bool shared);
|
||||
virtual ErrorOr<Memory::Region*> mmap(Process&, Memory::AddressSpace&, OpenFileDescription&, Memory::VirtualRange const&, u64 offset, int prot, bool shared);
|
||||
virtual ErrorOr<struct stat> stat() const { return EBADF; }
|
||||
|
||||
// Although this might be better described "name" or "description", these terms already have other meanings.
|
||||
|
|
|
@ -85,7 +85,7 @@ ErrorOr<void> InodeFile::ioctl(OpenFileDescription& description, unsigned reques
|
|||
}
|
||||
}
|
||||
|
||||
ErrorOr<Memory::Region*> InodeFile::mmap(Process& process, OpenFileDescription& description, Memory::VirtualRange const& range, u64 offset, int prot, bool shared)
|
||||
ErrorOr<Memory::Region*> InodeFile::mmap(Process&, Memory::AddressSpace& address_space, OpenFileDescription& description, Memory::VirtualRange const& range, u64 offset, int prot, bool shared)
|
||||
{
|
||||
// FIXME: If PROT_EXEC, check that the underlying file system isn't mounted noexec.
|
||||
LockRefPtr<Memory::InodeVMObject> vmobject;
|
||||
|
@ -94,7 +94,7 @@ ErrorOr<Memory::Region*> InodeFile::mmap(Process& process, OpenFileDescription&
|
|||
else
|
||||
vmobject = TRY(Memory::PrivateInodeVMObject::try_create_with_inode(inode()));
|
||||
auto path = TRY(description.pseudo_path());
|
||||
return process.address_space().allocate_region_with_vmobject(range, vmobject.release_nonnull(), offset, path->view(), prot, shared);
|
||||
return address_space.allocate_region_with_vmobject(range, vmobject.release_nonnull(), offset, path->view(), prot, shared);
|
||||
}
|
||||
|
||||
ErrorOr<NonnullOwnPtr<KString>> InodeFile::pseudo_path(OpenFileDescription const&) const
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
virtual ErrorOr<size_t> read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t) override;
|
||||
virtual ErrorOr<size_t> write(OpenFileDescription&, u64, UserOrKernelBuffer const&, size_t) override;
|
||||
virtual ErrorOr<void> ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg) override;
|
||||
virtual ErrorOr<Memory::Region*> mmap(Process&, OpenFileDescription&, Memory::VirtualRange const&, u64 offset, int prot, bool shared) override;
|
||||
virtual ErrorOr<Memory::Region*> mmap(Process&, Memory::AddressSpace&, OpenFileDescription&, Memory::VirtualRange const&, u64 offset, int prot, bool shared) override;
|
||||
virtual ErrorOr<struct stat> stat() const override { return inode().metadata().stat(); }
|
||||
|
||||
virtual ErrorOr<NonnullOwnPtr<KString>> pseudo_path(OpenFileDescription const&) const override;
|
||||
|
|
|
@ -374,9 +374,9 @@ InodeMetadata OpenFileDescription::metadata() const
|
|||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<Memory::Region*> OpenFileDescription::mmap(Process& process, Memory::VirtualRange const& range, u64 offset, int prot, bool shared)
|
||||
ErrorOr<Memory::Region*> OpenFileDescription::mmap(Process& process, Memory::AddressSpace& address_space, Memory::VirtualRange const& range, u64 offset, int prot, bool shared)
|
||||
{
|
||||
return m_file->mmap(process, *this, range, offset, prot, shared);
|
||||
return m_file->mmap(process, address_space, *this, range, offset, prot, shared);
|
||||
}
|
||||
|
||||
ErrorOr<void> OpenFileDescription::truncate(u64 length)
|
||||
|
|
|
@ -92,7 +92,7 @@ public:
|
|||
RefPtr<Custody> custody();
|
||||
RefPtr<Custody const> custody() const;
|
||||
|
||||
ErrorOr<Memory::Region*> mmap(Process&, Memory::VirtualRange const&, u64 offset, int prot, bool shared);
|
||||
ErrorOr<Memory::Region*> mmap(Process&, Memory::AddressSpace&, Memory::VirtualRange const&, u64 offset, int prot, bool shared);
|
||||
|
||||
bool is_blocking() const;
|
||||
void set_blocking(bool b);
|
||||
|
|
|
@ -540,13 +540,33 @@ private:
|
|||
TRY(process_object.add("nfds"sv, process.fds().with_shared([](auto& fds) { return fds.open_count(); })));
|
||||
TRY(process_object.add("name"sv, process.name()));
|
||||
TRY(process_object.add("executable"sv, process.executable() ? TRY(process.executable()->try_serialize_absolute_path())->view() : ""sv));
|
||||
TRY(process_object.add("amount_virtual"sv, process.address_space().amount_virtual()));
|
||||
TRY(process_object.add("amount_resident"sv, process.address_space().amount_resident()));
|
||||
TRY(process_object.add("amount_dirty_private"sv, process.address_space().amount_dirty_private()));
|
||||
TRY(process_object.add("amount_clean_inode"sv, TRY(process.address_space().amount_clean_inode())));
|
||||
TRY(process_object.add("amount_shared"sv, process.address_space().amount_shared()));
|
||||
TRY(process_object.add("amount_purgeable_volatile"sv, process.address_space().amount_purgeable_volatile()));
|
||||
TRY(process_object.add("amount_purgeable_nonvolatile"sv, process.address_space().amount_purgeable_nonvolatile()));
|
||||
|
||||
size_t amount_virtual = 0;
|
||||
size_t amount_resident = 0;
|
||||
size_t amount_dirty_private = 0;
|
||||
size_t amount_clean_inode = 0;
|
||||
size_t amount_shared = 0;
|
||||
size_t amount_purgeable_volatile = 0;
|
||||
size_t amount_purgeable_nonvolatile = 0;
|
||||
|
||||
TRY(process.address_space().with([&](auto& space) -> ErrorOr<void> {
|
||||
amount_virtual = space->amount_virtual();
|
||||
amount_resident = space->amount_resident();
|
||||
amount_dirty_private = space->amount_dirty_private();
|
||||
amount_clean_inode = TRY(space->amount_clean_inode());
|
||||
amount_shared = space->amount_shared();
|
||||
amount_purgeable_volatile = space->amount_purgeable_volatile();
|
||||
amount_purgeable_nonvolatile = space->amount_purgeable_nonvolatile();
|
||||
return {};
|
||||
}));
|
||||
|
||||
TRY(process_object.add("amount_virtual"sv, amount_virtual));
|
||||
TRY(process_object.add("amount_resident"sv, amount_resident));
|
||||
TRY(process_object.add("amount_dirty_private"sv, amount_dirty_private));
|
||||
TRY(process_object.add("amount_clean_inode"sv, amount_clean_inode));
|
||||
TRY(process_object.add("amount_shared"sv, amount_shared));
|
||||
TRY(process_object.add("amount_purgeable_volatile"sv, amount_purgeable_volatile));
|
||||
TRY(process_object.add("amount_purgeable_nonvolatile"sv, amount_purgeable_nonvolatile));
|
||||
TRY(process_object.add("dumpable"sv, process.is_dumpable()));
|
||||
TRY(process_object.add("kernel"sv, process.is_kernel_process()));
|
||||
auto thread_array = TRY(process_object.add_array("threads"sv));
|
||||
|
|
|
@ -32,13 +32,13 @@ DisplayConnector::DisplayConnector(size_t framebuffer_resource_size, bool enable
|
|||
{
|
||||
}
|
||||
|
||||
ErrorOr<Memory::Region*> DisplayConnector::mmap(Process& process, OpenFileDescription&, Memory::VirtualRange const& range, u64 offset, int prot, bool shared)
|
||||
ErrorOr<Memory::Region*> DisplayConnector::mmap(Process&, Memory::AddressSpace& address_space, OpenFileDescription&, Memory::VirtualRange const& range, u64 offset, int prot, bool shared)
|
||||
{
|
||||
VERIFY(m_shared_framebuffer_vmobject);
|
||||
if (offset != 0)
|
||||
return Error::from_errno(ENOTSUP);
|
||||
|
||||
return process.address_space().allocate_region_with_vmobject(
|
||||
return address_space.allocate_region_with_vmobject(
|
||||
range,
|
||||
*m_shared_framebuffer_vmobject,
|
||||
0,
|
||||
|
|
|
@ -137,7 +137,7 @@ private:
|
|||
virtual bool can_write(OpenFileDescription const&, u64) const final override { return true; }
|
||||
virtual ErrorOr<size_t> read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t) override final;
|
||||
virtual ErrorOr<size_t> write(OpenFileDescription&, u64, UserOrKernelBuffer const&, size_t) override final;
|
||||
virtual ErrorOr<Memory::Region*> mmap(Process&, OpenFileDescription&, Memory::VirtualRange const&, u64, int, bool) override final;
|
||||
virtual ErrorOr<Memory::Region*> mmap(Process&, Memory::AddressSpace&, OpenFileDescription&, Memory::VirtualRange const&, u64, int, bool) override final;
|
||||
virtual ErrorOr<void> ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg) override final;
|
||||
virtual StringView class_name() const override final { return "DisplayConnector"sv; }
|
||||
|
||||
|
|
|
@ -53,8 +53,6 @@ public:
|
|||
|
||||
void remove_all_regions(Badge<Process>);
|
||||
|
||||
RecursiveSpinlock& get_lock() const { return m_lock; }
|
||||
|
||||
ErrorOr<size_t> amount_clean_inode() const;
|
||||
size_t amount_dirty_private() const;
|
||||
size_t amount_virtual() const;
|
||||
|
@ -66,8 +64,6 @@ public:
|
|||
private:
|
||||
AddressSpace(NonnullLockRefPtr<PageDirectory>, VirtualRange total_range);
|
||||
|
||||
mutable RecursiveSpinlock m_lock { LockRank::None };
|
||||
|
||||
LockRefPtr<PageDirectory> m_page_directory;
|
||||
|
||||
// NOTE: The total range is also in the RegionTree, but since it never changes,
|
||||
|
|
|
@ -646,40 +646,32 @@ Region* MemoryManager::kernel_region_from_vaddr(VirtualAddress address)
|
|||
return MM.m_region_tree.with([&](auto& region_tree) { return region_tree.find_region_containing(address); });
|
||||
}
|
||||
|
||||
Region* MemoryManager::find_user_region_from_vaddr_no_lock(AddressSpace& space, VirtualAddress vaddr)
|
||||
Region* MemoryManager::find_user_region_from_vaddr(AddressSpace& space, VirtualAddress vaddr)
|
||||
{
|
||||
VERIFY(space.get_lock().is_locked_by_current_processor());
|
||||
return space.find_region_containing({ vaddr, 1 });
|
||||
}
|
||||
|
||||
Region* MemoryManager::find_user_region_from_vaddr(AddressSpace& space, VirtualAddress vaddr)
|
||||
void MemoryManager::validate_syscall_preconditions(Process& process, RegisterState const& regs)
|
||||
{
|
||||
SpinlockLocker lock(space.get_lock());
|
||||
return find_user_region_from_vaddr_no_lock(space, vaddr);
|
||||
}
|
||||
bool should_crash = false;
|
||||
char const* crash_description = nullptr;
|
||||
int crash_signal = 0;
|
||||
|
||||
void MemoryManager::validate_syscall_preconditions(AddressSpace& space, RegisterState const& regs)
|
||||
{
|
||||
// We take the space lock once here and then use the no_lock variants
|
||||
// to avoid excessive spinlock recursion in this extremely common path.
|
||||
SpinlockLocker lock(space.get_lock());
|
||||
|
||||
auto unlock_and_handle_crash = [&lock, ®s](char const* description, int signal) {
|
||||
lock.unlock();
|
||||
handle_crash(regs, description, signal);
|
||||
auto unlock_and_handle_crash = [&](char const* description, int signal) {
|
||||
should_crash = true;
|
||||
crash_description = description;
|
||||
crash_signal = signal;
|
||||
};
|
||||
|
||||
{
|
||||
process.address_space().with([&](auto& space) -> void {
|
||||
VirtualAddress userspace_sp = VirtualAddress { regs.userspace_sp() };
|
||||
if (!MM.validate_user_stack_no_lock(space, userspace_sp)) {
|
||||
if (!MM.validate_user_stack(*space, userspace_sp)) {
|
||||
dbgln("Invalid stack pointer: {}", userspace_sp);
|
||||
return unlock_and_handle_crash("Bad stack on syscall entry", SIGSEGV);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
VirtualAddress ip = VirtualAddress { regs.ip() };
|
||||
auto* calling_region = MM.find_user_region_from_vaddr_no_lock(space, ip);
|
||||
auto* calling_region = MM.find_user_region_from_vaddr(*space, ip);
|
||||
if (!calling_region) {
|
||||
dbgln("Syscall from {:p} which has no associated region", ip);
|
||||
return unlock_and_handle_crash("Syscall from unknown region", SIGSEGV);
|
||||
|
@ -690,10 +682,14 @@ void MemoryManager::validate_syscall_preconditions(AddressSpace& space, Register
|
|||
return unlock_and_handle_crash("Syscall from writable memory", SIGSEGV);
|
||||
}
|
||||
|
||||
if (space.enforces_syscall_regions() && !calling_region->is_syscall_region()) {
|
||||
if (space->enforces_syscall_regions() && !calling_region->is_syscall_region()) {
|
||||
dbgln("Syscall from non-syscall region");
|
||||
return unlock_and_handle_crash("Syscall from non-syscall region", SIGSEGV);
|
||||
}
|
||||
});
|
||||
|
||||
if (should_crash) {
|
||||
handle_crash(regs, crash_description, crash_signal);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -830,12 +826,20 @@ ErrorOr<CommittedPhysicalPageSet> MemoryManager::commit_physical_pages(size_t pa
|
|||
dbgln("MM: Unable to commit {} pages, have only {}", page_count, m_system_memory_info.physical_pages_uncommitted);
|
||||
|
||||
Process::for_each([&](Process const& process) {
|
||||
size_t amount_resident = 0;
|
||||
size_t amount_shared = 0;
|
||||
size_t amount_virtual = 0;
|
||||
process.address_space().with([&](auto& space) {
|
||||
amount_resident = space->amount_resident();
|
||||
amount_shared = space->amount_shared();
|
||||
amount_virtual = space->amount_virtual();
|
||||
});
|
||||
dbgln("{}({}) resident:{}, shared:{}, virtual:{}",
|
||||
process.name(),
|
||||
process.pid(),
|
||||
process.address_space().amount_resident() / PAGE_SIZE,
|
||||
process.address_space().amount_shared() / PAGE_SIZE,
|
||||
process.address_space().amount_virtual() / PAGE_SIZE);
|
||||
amount_resident / PAGE_SIZE,
|
||||
amount_shared / PAGE_SIZE,
|
||||
amount_virtual / PAGE_SIZE);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
|
@ -1007,7 +1011,9 @@ ErrorOr<NonnullLockRefPtrVector<PhysicalPage>> MemoryManager::allocate_contiguou
|
|||
|
||||
void MemoryManager::enter_process_address_space(Process& process)
|
||||
{
|
||||
enter_address_space(process.address_space());
|
||||
process.address_space().with([](auto& space) {
|
||||
enter_address_space(*space);
|
||||
});
|
||||
}
|
||||
|
||||
void MemoryManager::enter_address_space(AddressSpace& space)
|
||||
|
@ -1100,23 +1106,15 @@ void MemoryManager::unquickmap_page()
|
|||
mm_data.m_quickmap_in_use.unlock(mm_data.m_quickmap_prev_flags);
|
||||
}
|
||||
|
||||
bool MemoryManager::validate_user_stack_no_lock(AddressSpace& space, VirtualAddress vaddr) const
|
||||
bool MemoryManager::validate_user_stack(AddressSpace& space, VirtualAddress vaddr) const
|
||||
{
|
||||
VERIFY(space.get_lock().is_locked_by_current_processor());
|
||||
|
||||
if (!is_user_address(vaddr))
|
||||
return false;
|
||||
|
||||
auto* region = find_user_region_from_vaddr_no_lock(space, vaddr);
|
||||
auto* region = find_user_region_from_vaddr(space, vaddr);
|
||||
return region && region->is_user() && region->is_stack();
|
||||
}
|
||||
|
||||
bool MemoryManager::validate_user_stack(AddressSpace& space, VirtualAddress vaddr) const
|
||||
{
|
||||
SpinlockLocker lock(space.get_lock());
|
||||
return validate_user_stack_no_lock(space, vaddr);
|
||||
}
|
||||
|
||||
void MemoryManager::unregister_kernel_region(Region& region)
|
||||
{
|
||||
VERIFY(region.is_kernel());
|
||||
|
|
|
@ -159,7 +159,6 @@ public:
|
|||
static void enter_process_address_space(Process&);
|
||||
static void enter_address_space(AddressSpace&);
|
||||
|
||||
bool validate_user_stack_no_lock(AddressSpace&, VirtualAddress) const;
|
||||
bool validate_user_stack(AddressSpace&, VirtualAddress) const;
|
||||
|
||||
enum class ShouldZeroFill {
|
||||
|
@ -222,8 +221,7 @@ public:
|
|||
}
|
||||
|
||||
static Region* find_user_region_from_vaddr(AddressSpace&, VirtualAddress);
|
||||
static Region* find_user_region_from_vaddr_no_lock(AddressSpace&, VirtualAddress);
|
||||
static void validate_syscall_preconditions(AddressSpace&, RegisterState const&);
|
||||
static void validate_syscall_preconditions(Process&, RegisterState const&);
|
||||
|
||||
void dump_kernel_regions();
|
||||
|
||||
|
|
|
@ -45,9 +45,6 @@ public:
|
|||
|
||||
void delete_all_regions_assuming_they_are_unmapped();
|
||||
|
||||
// FIXME: Access the region tree through a SpinlockProtected or similar.
|
||||
RecursiveSpinlock& get_lock() const { return m_lock; }
|
||||
|
||||
bool remove(Region&);
|
||||
|
||||
Region* find_region_containing(VirtualAddress);
|
||||
|
@ -58,9 +55,6 @@ private:
|
|||
ErrorOr<VirtualRange> allocate_range_specific(VirtualAddress base, size_t size);
|
||||
ErrorOr<VirtualRange> allocate_range_randomized(size_t size, size_t alignment = PAGE_SIZE);
|
||||
|
||||
// FIXME: We need a Region rank, but we don't know where to put it.
|
||||
RecursiveSpinlock mutable m_lock { LockRank::None };
|
||||
|
||||
IntrusiveRedBlackTree<&Region::m_tree_node> m_regions;
|
||||
VirtualRange const m_total_range;
|
||||
};
|
||||
|
|
|
@ -334,8 +334,6 @@ OwnPtr<PerformanceEventBuffer> PerformanceEventBuffer::try_create_with_size(size
|
|||
|
||||
ErrorOr<void> PerformanceEventBuffer::add_process(Process const& process, ProcessEventType event_type)
|
||||
{
|
||||
SpinlockLocker locker(process.address_space().get_lock());
|
||||
|
||||
OwnPtr<KString> executable;
|
||||
if (process.executable())
|
||||
executable = TRY(process.executable()->try_serialize_absolute_path());
|
||||
|
@ -354,13 +352,15 @@ ErrorOr<void> PerformanceEventBuffer::add_process(Process const& process, Proces
|
|||
});
|
||||
TRY(result);
|
||||
|
||||
return process.address_space().region_tree().with([&](auto& region_tree) -> ErrorOr<void> {
|
||||
return process.address_space().with([&](auto& space) {
|
||||
return space->region_tree().with([&](auto& region_tree) -> ErrorOr<void> {
|
||||
for (auto const& region : region_tree.regions()) {
|
||||
TRY(append_with_ip_and_bp(process.pid(), 0,
|
||||
0, 0, PERF_EVENT_MMAP, 0, region.range().base().get(), region.range().size(), region.name()));
|
||||
}
|
||||
return {};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ErrorOr<FlatPtr> PerformanceEventBuffer::register_string(NonnullOwnPtr<KString> string)
|
||||
|
|
|
@ -218,16 +218,25 @@ void Process::unprotect_data()
|
|||
|
||||
ErrorOr<NonnullLockRefPtr<Process>> Process::try_create(LockRefPtr<Thread>& first_thread, NonnullOwnPtr<KString> name, UserID uid, GroupID gid, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> current_directory, RefPtr<Custody> executable, TTY* tty, Process* fork_parent)
|
||||
{
|
||||
auto space = TRY(Memory::AddressSpace::try_create(fork_parent ? &fork_parent->address_space() : nullptr));
|
||||
OwnPtr<Memory::AddressSpace> new_address_space;
|
||||
if (fork_parent) {
|
||||
TRY(fork_parent->address_space().with([&](auto& parent_address_space) -> ErrorOr<void> {
|
||||
new_address_space = TRY(Memory::AddressSpace::try_create(parent_address_space.ptr()));
|
||||
return {};
|
||||
}));
|
||||
} else {
|
||||
new_address_space = TRY(Memory::AddressSpace::try_create(nullptr));
|
||||
}
|
||||
auto unveil_tree = UnveilNode { TRY(KString::try_create("/"sv)), UnveilMetadata(TRY(KString::try_create("/"sv))) };
|
||||
auto credentials = TRY(Credentials::create(uid, gid, uid, gid, uid, gid, {}));
|
||||
auto process = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) Process(move(name), move(credentials), ppid, is_kernel_process, move(current_directory), move(executable), tty, move(unveil_tree))));
|
||||
TRY(process->attach_resources(move(space), first_thread, fork_parent));
|
||||
TRY(process->attach_resources(new_address_space.release_nonnull(), first_thread, fork_parent));
|
||||
return process;
|
||||
}
|
||||
|
||||
Process::Process(NonnullOwnPtr<KString> name, NonnullRefPtr<Credentials> credentials, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> current_directory, RefPtr<Custody> executable, TTY* tty, UnveilNode unveil_tree)
|
||||
: m_name(move(name))
|
||||
, m_space(LockRank::None)
|
||||
, m_protected_data_lock(LockRank::None)
|
||||
, m_is_kernel_process(is_kernel_process)
|
||||
, m_executable(LockRank::None, move(executable))
|
||||
|
@ -248,7 +257,9 @@ Process::Process(NonnullOwnPtr<KString> name, NonnullRefPtr<Credentials> credent
|
|||
|
||||
ErrorOr<void> Process::attach_resources(NonnullOwnPtr<Memory::AddressSpace>&& preallocated_space, LockRefPtr<Thread>& first_thread, Process* fork_parent)
|
||||
{
|
||||
m_space = move(preallocated_space);
|
||||
m_space.with([&](auto& space) {
|
||||
space = move(preallocated_space);
|
||||
});
|
||||
|
||||
auto create_first_thread = [&] {
|
||||
if (fork_parent) {
|
||||
|
@ -401,7 +412,7 @@ void Process::crash(int signal, FlatPtr ip, bool out_of_memory)
|
|||
protected_data.termination_signal = signal;
|
||||
});
|
||||
set_should_generate_coredump(!out_of_memory);
|
||||
address_space().dump_regions();
|
||||
address_space().with([](auto& space) { space->dump_regions(); });
|
||||
VERIFY(is_user_process());
|
||||
die();
|
||||
// We can not return from here, as there is nowhere
|
||||
|
@ -662,7 +673,7 @@ void Process::finalize()
|
|||
|
||||
unblock_waiters(Thread::WaitBlocker::UnblockFlags::Terminated);
|
||||
|
||||
m_space->remove_all_regions({});
|
||||
m_space.with([](auto& space) { space->remove_all_regions({}); });
|
||||
|
||||
VERIFY(ref_count() > 0);
|
||||
// WaitBlockerSet::finalize will be in charge of dropping the last
|
||||
|
|
|
@ -558,8 +558,8 @@ public:
|
|||
PerformanceEventBuffer* perf_events() { return m_perf_event_buffer; }
|
||||
PerformanceEventBuffer const* perf_events() const { return m_perf_event_buffer; }
|
||||
|
||||
Memory::AddressSpace& address_space() { return *m_space; }
|
||||
Memory::AddressSpace const& address_space() const { return *m_space; }
|
||||
SpinlockProtected<OwnPtr<Memory::AddressSpace>>& address_space() { return m_space; }
|
||||
SpinlockProtected<OwnPtr<Memory::AddressSpace>> const& address_space() const { return m_space; }
|
||||
|
||||
VirtualAddress signal_trampoline() const
|
||||
{
|
||||
|
@ -656,7 +656,7 @@ private:
|
|||
|
||||
NonnullOwnPtr<KString> m_name;
|
||||
|
||||
OwnPtr<Memory::AddressSpace> m_space;
|
||||
SpinlockProtected<OwnPtr<Memory::AddressSpace>> m_space;
|
||||
|
||||
LockRefPtr<ProcessGroup> m_pg;
|
||||
|
||||
|
|
|
@ -267,7 +267,8 @@ ErrorOr<void> Process::procfs_get_fds_stats(KBufferBuilder& builder) const
|
|||
ErrorOr<void> Process::procfs_get_virtual_memory_stats(KBufferBuilder& builder) const
|
||||
{
|
||||
auto array = TRY(JsonArraySerializer<>::try_create(builder));
|
||||
TRY(address_space().region_tree().with([&](auto& region_tree) -> ErrorOr<void> {
|
||||
TRY(address_space().with([&](auto& space) {
|
||||
return space->region_tree().with([&](auto& region_tree) -> ErrorOr<void> {
|
||||
for (auto const& region : region_tree.regions()) {
|
||||
auto current_process_credentials = Process::current().credentials();
|
||||
if (!region.is_user() && !current_process_credentials->is_superuser())
|
||||
|
@ -306,6 +307,7 @@ ErrorOr<void> Process::procfs_get_virtual_memory_stats(KBufferBuilder& builder)
|
|||
TRY(region_object.finish());
|
||||
}
|
||||
return {};
|
||||
});
|
||||
}));
|
||||
TRY(array.finish());
|
||||
return {};
|
||||
|
|
|
@ -204,7 +204,7 @@ NEVER_INLINE void syscall_handler(TrapFrame* trap)
|
|||
PANIC("Syscall from process with IOPL != 0");
|
||||
}
|
||||
|
||||
Memory::MemoryManager::validate_syscall_preconditions(process.address_space(), regs);
|
||||
Memory::MemoryManager::validate_syscall_preconditions(process, regs);
|
||||
|
||||
FlatPtr function;
|
||||
FlatPtr arg1;
|
||||
|
|
|
@ -17,8 +17,10 @@ ErrorOr<FlatPtr> Process::sys$map_time_page()
|
|||
|
||||
auto& vmobject = TimeManagement::the().time_page_vmobject();
|
||||
|
||||
auto* region = TRY(address_space().allocate_region_with_vmobject(Memory::RandomizeVirtualAddress::Yes, {}, PAGE_SIZE, PAGE_SIZE, vmobject, 0, "Kernel time page"sv, PROT_READ, true));
|
||||
return address_space().with([&](auto& space) -> ErrorOr<FlatPtr> {
|
||||
auto* region = TRY(space->allocate_region_with_vmobject(Memory::RandomizeVirtualAddress::Yes, {}, PAGE_SIZE, PAGE_SIZE, vmobject, 0, "Kernel time page"sv, PROT_READ, true));
|
||||
return region->vaddr().get();
|
||||
});
|
||||
}
|
||||
|
||||
ErrorOr<FlatPtr> Process::sys$clock_gettime(clockid_t clock_id, Userspace<timespec*> user_ts)
|
||||
|
|
|
@ -551,7 +551,7 @@ ErrorOr<void> Process::do_exec(NonnullLockRefPtr<OpenFileDescription> main_progr
|
|||
// This ensures that the process always has a valid page directory.
|
||||
Memory::MemoryManager::enter_address_space(*load_result.space);
|
||||
|
||||
m_space = load_result.space.release_nonnull();
|
||||
m_space.with([&](auto& space) { space = load_result.space.release_nonnull(); });
|
||||
|
||||
m_executable.with([&](auto& executable) { executable = main_program_description->custody(); });
|
||||
m_arguments = move(arguments);
|
||||
|
@ -661,7 +661,7 @@ ErrorOr<void> Process::do_exec(NonnullLockRefPtr<OpenFileDescription> main_progr
|
|||
regs.rip = load_result.entry_eip;
|
||||
regs.rsp = new_userspace_sp;
|
||||
#endif
|
||||
regs.cr3 = address_space().page_directory().cr3();
|
||||
regs.cr3 = address_space().with([](auto& space) { return space->page_directory().cr3(); });
|
||||
|
||||
{
|
||||
TemporaryChange profiling_disabler(m_profiling, was_profiling);
|
||||
|
|
|
@ -65,7 +65,6 @@ ErrorOr<FlatPtr> Process::sys$fork(RegisterState& regs)
|
|||
});
|
||||
|
||||
dbgln_if(FORK_DEBUG, "fork: child={}", child);
|
||||
child->address_space().set_enforces_syscall_regions(address_space().enforces_syscall_regions());
|
||||
|
||||
// A child created via fork(2) inherits a copy of its parent's signal mask
|
||||
child_first_thread->update_signal_mask(Thread::current()->signal_mask());
|
||||
|
@ -123,13 +122,15 @@ ErrorOr<FlatPtr> Process::sys$fork(RegisterState& regs)
|
|||
# error Unknown architecture
|
||||
#endif
|
||||
|
||||
{
|
||||
TRY(address_space().region_tree().with([&](auto& parent_region_tree) -> ErrorOr<void> {
|
||||
return child->address_space().region_tree().with([&](auto& child_region_tree) -> ErrorOr<void> {
|
||||
TRY(address_space().with([&](auto& parent_space) {
|
||||
return child->address_space().with([&](auto& child_space) {
|
||||
child_space->set_enforces_syscall_regions(parent_space->enforces_syscall_regions());
|
||||
return parent_space->region_tree().with([&](auto& parent_region_tree) -> ErrorOr<void> {
|
||||
return child_space->region_tree().with([&](auto& child_region_tree) -> ErrorOr<void> {
|
||||
for (auto& region : parent_region_tree.regions()) {
|
||||
dbgln_if(FORK_DEBUG, "fork: cloning Region '{}' @ {}", region.name(), region.vaddr());
|
||||
auto region_clone = TRY(region.try_clone());
|
||||
TRY(region_clone->map(child->address_space().page_directory(), Memory::ShouldFlushTLB::No));
|
||||
TRY(region_clone->map(child_space->page_directory(), Memory::ShouldFlushTLB::No));
|
||||
TRY(child_region_tree.place_specifically(*region_clone, region.range()));
|
||||
auto* child_region = region_clone.leak_ptr();
|
||||
|
||||
|
@ -138,8 +139,9 @@ ErrorOr<FlatPtr> Process::sys$fork(RegisterState& regs)
|
|||
}
|
||||
return {};
|
||||
});
|
||||
});
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
thread_finalizer_guard.disarm();
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ static Singleton<SpinlockProtected<HashMap<GlobalFutexKey, NonnullLockRefPtr<Fut
|
|||
void Process::clear_futex_queues_on_exec()
|
||||
{
|
||||
s_global_futex_queues->with([this](auto& queues) {
|
||||
auto const* address_space = &this->address_space();
|
||||
auto const* address_space = this->address_space().with([](auto& space) { return space.ptr(); });
|
||||
queues.remove_all_matching([address_space](auto& futex_key, auto& futex_queue) {
|
||||
if ((futex_key.raw.offset & futex_key_private_flag) == 0)
|
||||
return false;
|
||||
|
@ -45,13 +45,14 @@ ErrorOr<GlobalFutexKey> Process::get_futex_key(FlatPtr user_address, bool shared
|
|||
if (!shared) { // If this is thread-shared, we can skip searching the matching region
|
||||
return GlobalFutexKey {
|
||||
.private_ = {
|
||||
.address_space = &address_space(),
|
||||
.address_space = this->address_space().with([](auto& space) { return space.ptr(); }),
|
||||
.user_address = user_address | futex_key_private_flag,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
auto* matching_region = address_space().find_region_containing(range);
|
||||
return address_space().with([&](auto& space) -> ErrorOr<GlobalFutexKey> {
|
||||
auto* matching_region = space->find_region_containing(range);
|
||||
if (!matching_region)
|
||||
return EFAULT;
|
||||
|
||||
|
@ -60,7 +61,7 @@ ErrorOr<GlobalFutexKey> Process::get_futex_key(FlatPtr user_address, bool shared
|
|||
if (!matching_region->is_shared()) {
|
||||
return GlobalFutexKey {
|
||||
.private_ = {
|
||||
.address_space = &address_space(),
|
||||
.address_space = space.ptr(),
|
||||
.user_address = user_address | futex_key_private_flag,
|
||||
}
|
||||
};
|
||||
|
@ -84,6 +85,7 @@ ErrorOr<GlobalFutexKey> Process::get_futex_key(FlatPtr user_address, bool shared
|
|||
.vmobject = &vmobject,
|
||||
.offset = matching_region->offset_in_vmobject_from_vaddr(range.base()) }
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
ErrorOr<FlatPtr> Process::sys$futex(Userspace<Syscall::SC_futex_params const*> user_params)
|
||||
|
|
|
@ -14,7 +14,8 @@ ErrorOr<FlatPtr> Process::sys$get_stack_bounds(Userspace<FlatPtr*> user_stack_ba
|
|||
VERIFY_NO_PROCESS_BIG_LOCK(this);
|
||||
auto& regs = Thread::current()->get_register_dump_from_stack();
|
||||
FlatPtr stack_pointer = regs.userspace_sp();
|
||||
auto* stack_region = address_space().find_region_containing(Memory::VirtualRange { VirtualAddress(stack_pointer), 1 });
|
||||
return address_space().with([&](auto& space) -> ErrorOr<FlatPtr> {
|
||||
auto* stack_region = space->find_region_containing(Memory::VirtualRange { VirtualAddress(stack_pointer), 1 });
|
||||
|
||||
// The syscall handler should have killed us if we had an invalid stack pointer.
|
||||
VERIFY(stack_region);
|
||||
|
@ -24,6 +25,7 @@ ErrorOr<FlatPtr> Process::sys$get_stack_bounds(Userspace<FlatPtr*> user_stack_ba
|
|||
TRY(copy_to_user(user_stack_base, &stack_base));
|
||||
TRY(copy_to_user(user_stack_size, &stack_size));
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -192,32 +192,23 @@ ErrorOr<FlatPtr> Process::sys$mmap(Userspace<Syscall::SC_mmap_params const*> use
|
|||
|
||||
Memory::Region* region = nullptr;
|
||||
|
||||
// If MAP_FIXED is specified, existing mappings that intersect the requested range are removed.
|
||||
if (map_fixed)
|
||||
TRY(address_space().unmap_mmap_range(VirtualAddress(addr), size));
|
||||
|
||||
Memory::VirtualRange requested_range { VirtualAddress { addr }, rounded_size };
|
||||
if (addr && !(map_fixed || map_fixed_noreplace)) {
|
||||
// If there's an address but MAP_FIXED wasn't specified, the address is just a hint.
|
||||
requested_range = { {}, rounded_size };
|
||||
}
|
||||
LockRefPtr<OpenFileDescription> description;
|
||||
LockRefPtr<Memory::AnonymousVMObject> vmobject;
|
||||
|
||||
if (map_anonymous) {
|
||||
auto strategy = map_noreserve ? AllocationStrategy::None : AllocationStrategy::Reserve;
|
||||
LockRefPtr<Memory::AnonymousVMObject> vmobject;
|
||||
|
||||
if (flags & MAP_PURGEABLE) {
|
||||
vmobject = TRY(Memory::AnonymousVMObject::try_create_purgeable_with_size(rounded_size, strategy));
|
||||
} else {
|
||||
vmobject = TRY(Memory::AnonymousVMObject::try_create_with_size(rounded_size, strategy));
|
||||
}
|
||||
|
||||
region = TRY(address_space().allocate_region_with_vmobject(map_randomized ? Memory::RandomizeVirtualAddress::Yes : Memory::RandomizeVirtualAddress::No, requested_range.base(), requested_range.size(), alignment, vmobject.release_nonnull(), 0, {}, prot, map_shared));
|
||||
} else {
|
||||
if (offset < 0)
|
||||
return EINVAL;
|
||||
if (static_cast<size_t>(offset) & ~PAGE_MASK)
|
||||
return EINVAL;
|
||||
auto description = TRY(open_file_description(fd));
|
||||
description = TRY(open_file_description(fd));
|
||||
if (description->is_directory())
|
||||
return ENODEV;
|
||||
// Require read access even when read protection is not requested.
|
||||
|
@ -229,8 +220,23 @@ ErrorOr<FlatPtr> Process::sys$mmap(Userspace<Syscall::SC_mmap_params const*> use
|
|||
}
|
||||
if (description->inode())
|
||||
TRY(validate_inode_mmap_prot(prot, *description->inode(), map_shared));
|
||||
}
|
||||
|
||||
region = TRY(description->mmap(*this, requested_range, static_cast<u64>(offset), prot, map_shared));
|
||||
return address_space().with([&](auto& space) -> ErrorOr<FlatPtr> {
|
||||
// If MAP_FIXED is specified, existing mappings that intersect the requested range are removed.
|
||||
if (map_fixed)
|
||||
TRY(space->unmap_mmap_range(VirtualAddress(addr), size));
|
||||
|
||||
Memory::VirtualRange requested_range { VirtualAddress { addr }, rounded_size };
|
||||
if (addr && !(map_fixed || map_fixed_noreplace)) {
|
||||
// If there's an address but MAP_FIXED wasn't specified, the address is just a hint.
|
||||
requested_range = { {}, rounded_size };
|
||||
}
|
||||
|
||||
if (map_anonymous) {
|
||||
region = TRY(space->allocate_region_with_vmobject(map_randomized ? Memory::RandomizeVirtualAddress::Yes : Memory::RandomizeVirtualAddress::No, requested_range.base(), requested_range.size(), alignment, vmobject.release_nonnull(), 0, {}, prot, map_shared));
|
||||
} else {
|
||||
region = TRY(description->mmap(*this, *space, requested_range, static_cast<u64>(offset), prot, map_shared));
|
||||
}
|
||||
|
||||
if (!region)
|
||||
|
@ -247,6 +253,7 @@ ErrorOr<FlatPtr> Process::sys$mmap(Userspace<Syscall::SC_mmap_params const*> use
|
|||
PerformanceManager::add_mmap_perf_event(*this, *region);
|
||||
|
||||
return region->vaddr().get();
|
||||
});
|
||||
}
|
||||
|
||||
ErrorOr<FlatPtr> Process::sys$mprotect(Userspace<void*> addr, size_t size, int prot)
|
||||
|
@ -265,7 +272,8 @@ ErrorOr<FlatPtr> Process::sys$mprotect(Userspace<void*> addr, size_t size, int p
|
|||
if (!is_user_range(range_to_mprotect))
|
||||
return EFAULT;
|
||||
|
||||
if (auto* whole_region = address_space().find_region_from_range(range_to_mprotect)) {
|
||||
return address_space().with([&](auto& space) -> ErrorOr<FlatPtr> {
|
||||
if (auto* whole_region = space->find_region_from_range(range_to_mprotect)) {
|
||||
if (!whole_region->is_mmap())
|
||||
return EPERM;
|
||||
TRY(validate_mmap_prot(prot, whole_region->is_stack(), whole_region->vmobject().is_anonymous(), whole_region));
|
||||
|
@ -282,7 +290,7 @@ ErrorOr<FlatPtr> Process::sys$mprotect(Userspace<void*> addr, size_t size, int p
|
|||
}
|
||||
|
||||
// Check if we can carve out the desired range from an existing region
|
||||
if (auto* old_region = address_space().find_region_containing(range_to_mprotect)) {
|
||||
if (auto* old_region = space->find_region_containing(range_to_mprotect)) {
|
||||
if (!old_region->is_mmap())
|
||||
return EPERM;
|
||||
TRY(validate_mmap_prot(prot, old_region->is_stack(), old_region->vmobject().is_anonymous(), old_region));
|
||||
|
@ -293,28 +301,28 @@ ErrorOr<FlatPtr> Process::sys$mprotect(Userspace<void*> addr, size_t size, int p
|
|||
|
||||
// Remove the old region from our regions tree, since were going to add another region
|
||||
// with the exact same start address.
|
||||
auto region = address_space().take_region(*old_region);
|
||||
auto region = space->take_region(*old_region);
|
||||
region->unmap();
|
||||
|
||||
// This vector is the region(s) adjacent to our range.
|
||||
// We need to allocate a new region for the range we wanted to change permission bits on.
|
||||
auto adjacent_regions = TRY(address_space().try_split_region_around_range(*region, range_to_mprotect));
|
||||
auto adjacent_regions = TRY(space->try_split_region_around_range(*region, range_to_mprotect));
|
||||
|
||||
size_t new_range_offset_in_vmobject = region->offset_in_vmobject() + (range_to_mprotect.base().get() - region->range().base().get());
|
||||
auto* new_region = TRY(address_space().try_allocate_split_region(*region, range_to_mprotect, new_range_offset_in_vmobject));
|
||||
auto* new_region = TRY(space->try_allocate_split_region(*region, range_to_mprotect, new_range_offset_in_vmobject));
|
||||
new_region->set_readable(prot & PROT_READ);
|
||||
new_region->set_writable(prot & PROT_WRITE);
|
||||
new_region->set_executable(prot & PROT_EXEC);
|
||||
|
||||
// Map the new regions using our page directory (they were just allocated and don't have one).
|
||||
for (auto* adjacent_region : adjacent_regions) {
|
||||
TRY(adjacent_region->map(address_space().page_directory()));
|
||||
TRY(adjacent_region->map(space->page_directory()));
|
||||
}
|
||||
TRY(new_region->map(address_space().page_directory()));
|
||||
TRY(new_region->map(space->page_directory()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (auto const& regions = TRY(address_space().find_regions_intersecting(range_to_mprotect)); regions.size()) {
|
||||
if (auto const& regions = TRY(space->find_regions_intersecting(range_to_mprotect)); regions.size()) {
|
||||
size_t full_size_found = 0;
|
||||
// Check that all intersecting regions are compatible.
|
||||
for (auto const* region : regions) {
|
||||
|
@ -347,19 +355,19 @@ ErrorOr<FlatPtr> Process::sys$mprotect(Userspace<void*> addr, size_t size, int p
|
|||
}
|
||||
// Remove the old region from our regions tree, since were going to add another region
|
||||
// with the exact same start address.
|
||||
auto region = address_space().take_region(*old_region);
|
||||
auto region = space->take_region(*old_region);
|
||||
region->unmap();
|
||||
|
||||
// This vector is the region(s) adjacent to our range.
|
||||
// We need to allocate a new region for the range we wanted to change permission bits on.
|
||||
auto adjacent_regions = TRY(address_space().try_split_region_around_range(*old_region, intersection_to_mprotect));
|
||||
auto adjacent_regions = TRY(space->try_split_region_around_range(*old_region, intersection_to_mprotect));
|
||||
|
||||
// Since the range is not contained in a single region, it can only partially cover its starting and ending region,
|
||||
// therefore carving out a chunk from the region will always produce a single extra region, and not two.
|
||||
VERIFY(adjacent_regions.size() == 1);
|
||||
|
||||
size_t new_range_offset_in_vmobject = old_region->offset_in_vmobject() + (intersection_to_mprotect.base().get() - old_region->range().base().get());
|
||||
auto* new_region = TRY(address_space().try_allocate_split_region(*region, intersection_to_mprotect, new_range_offset_in_vmobject));
|
||||
auto* new_region = TRY(space->try_allocate_split_region(*region, intersection_to_mprotect, new_range_offset_in_vmobject));
|
||||
|
||||
new_region->set_readable(prot & PROT_READ);
|
||||
new_region->set_writable(prot & PROT_WRITE);
|
||||
|
@ -367,15 +375,16 @@ ErrorOr<FlatPtr> Process::sys$mprotect(Userspace<void*> addr, size_t size, int p
|
|||
|
||||
// Map the new region using our page directory (they were just allocated and don't have one) if any.
|
||||
if (adjacent_regions.size())
|
||||
TRY(adjacent_regions[0]->map(address_space().page_directory()));
|
||||
TRY(adjacent_regions[0]->map(space->page_directory()));
|
||||
|
||||
TRY(new_region->map(address_space().page_directory()));
|
||||
TRY(new_region->map(space->page_directory()));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return EINVAL;
|
||||
});
|
||||
}
|
||||
|
||||
ErrorOr<FlatPtr> Process::sys$madvise(Userspace<void*> address, size_t size, int advice)
|
||||
|
@ -391,7 +400,8 @@ ErrorOr<FlatPtr> Process::sys$madvise(Userspace<void*> address, size_t size, int
|
|||
if (!is_user_range(range_to_madvise))
|
||||
return EFAULT;
|
||||
|
||||
auto* region = address_space().find_region_from_range(range_to_madvise);
|
||||
return address_space().with([&](auto& space) -> ErrorOr<FlatPtr> {
|
||||
auto* region = space->find_region_from_range(range_to_madvise);
|
||||
if (!region)
|
||||
return EINVAL;
|
||||
if (!region->is_mmap())
|
||||
|
@ -407,6 +417,7 @@ ErrorOr<FlatPtr> Process::sys$madvise(Userspace<void*> address, size_t size, int
|
|||
return was_purged ? 1 : 0;
|
||||
}
|
||||
return EINVAL;
|
||||
});
|
||||
}
|
||||
|
||||
ErrorOr<FlatPtr> Process::sys$set_mmap_name(Userspace<Syscall::SC_set_mmap_name_params const*> user_params)
|
||||
|
@ -421,7 +432,8 @@ ErrorOr<FlatPtr> Process::sys$set_mmap_name(Userspace<Syscall::SC_set_mmap_name_
|
|||
auto name = TRY(try_copy_kstring_from_user(params.name));
|
||||
auto range = TRY(Memory::expand_range_to_page_boundaries((FlatPtr)params.addr, params.size));
|
||||
|
||||
auto* region = address_space().find_region_from_range(range);
|
||||
return address_space().with([&](auto& space) -> ErrorOr<FlatPtr> {
|
||||
auto* region = space->find_region_from_range(range);
|
||||
if (!region)
|
||||
return EINVAL;
|
||||
if (!region->is_mmap())
|
||||
|
@ -431,13 +443,16 @@ ErrorOr<FlatPtr> Process::sys$set_mmap_name(Userspace<Syscall::SC_set_mmap_name_
|
|||
PerformanceManager::add_mmap_perf_event(*this, *region);
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
ErrorOr<FlatPtr> Process::sys$munmap(Userspace<void*> addr, size_t size)
|
||||
{
|
||||
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
|
||||
TRY(require_promise(Pledge::stdio));
|
||||
TRY(address_space().unmap_mmap_range(addr.vaddr(), size));
|
||||
TRY(address_space().with([&](auto& space) {
|
||||
return space->unmap_mmap_range(addr.vaddr(), size);
|
||||
}));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -449,7 +464,8 @@ ErrorOr<FlatPtr> Process::sys$mremap(Userspace<Syscall::SC_mremap_params const*>
|
|||
|
||||
auto old_range = TRY(Memory::expand_range_to_page_boundaries((FlatPtr)params.old_address, params.old_size));
|
||||
|
||||
auto* old_region = address_space().find_region_from_range(old_range);
|
||||
return address_space().with([&](auto& space) -> ErrorOr<FlatPtr> {
|
||||
auto* old_region = space->find_region_from_range(old_range);
|
||||
if (!old_region)
|
||||
return EINVAL;
|
||||
|
||||
|
@ -466,15 +482,16 @@ ErrorOr<FlatPtr> Process::sys$mremap(Userspace<Syscall::SC_mremap_params const*>
|
|||
auto old_name = old_region->take_name();
|
||||
|
||||
old_region->unmap();
|
||||
address_space().deallocate_region(*old_region);
|
||||
space->deallocate_region(*old_region);
|
||||
|
||||
auto* new_region = TRY(address_space().allocate_region_with_vmobject(range, move(new_vmobject), old_offset, old_name->view(), old_prot, false));
|
||||
auto* new_region = TRY(space->allocate_region_with_vmobject(range, move(new_vmobject), old_offset, old_name->view(), old_prot, false));
|
||||
new_region->set_mmap(true);
|
||||
return new_region->vaddr().get();
|
||||
}
|
||||
|
||||
dbgln("sys$mremap: Unimplemented remap request (flags={})", params.flags);
|
||||
return ENOTIMPL;
|
||||
});
|
||||
}
|
||||
|
||||
ErrorOr<FlatPtr> Process::sys$allocate_tls(Userspace<char const*> initial_data, size_t size)
|
||||
|
@ -504,7 +521,8 @@ ErrorOr<FlatPtr> Process::sys$allocate_tls(Userspace<char const*> initial_data,
|
|||
if (multiple_threads)
|
||||
return EINVAL;
|
||||
|
||||
auto* region = TRY(address_space().allocate_region(Memory::RandomizeVirtualAddress::Yes, {}, size, PAGE_SIZE, "Master TLS"sv, PROT_READ | PROT_WRITE));
|
||||
return address_space().with([&](auto& space) -> ErrorOr<FlatPtr> {
|
||||
auto* region = TRY(space->allocate_region(Memory::RandomizeVirtualAddress::Yes, {}, size, PAGE_SIZE, "Master TLS"sv, PROT_READ | PROT_WRITE));
|
||||
|
||||
m_master_tls_region = TRY(region->try_make_weak_ptr());
|
||||
m_master_tls_size = size;
|
||||
|
@ -529,23 +547,26 @@ ErrorOr<FlatPtr> Process::sys$allocate_tls(Userspace<char const*> initial_data,
|
|||
#endif
|
||||
|
||||
return m_master_tls_region.unsafe_ptr()->vaddr().get();
|
||||
});
|
||||
}
|
||||
|
||||
ErrorOr<FlatPtr> Process::sys$msyscall(Userspace<void*> address)
|
||||
{
|
||||
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
|
||||
if (address_space().enforces_syscall_regions())
|
||||
|
||||
return address_space().with([&](auto& space) -> ErrorOr<FlatPtr> {
|
||||
if (space->enforces_syscall_regions())
|
||||
return EPERM;
|
||||
|
||||
if (!address) {
|
||||
address_space().set_enforces_syscall_regions(true);
|
||||
space->set_enforces_syscall_regions(true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!Memory::is_user_address(address.vaddr()))
|
||||
return EFAULT;
|
||||
|
||||
auto* region = address_space().find_region_containing(Memory::VirtualRange { address.vaddr(), 1 });
|
||||
auto* region = space->find_region_containing(Memory::VirtualRange { address.vaddr(), 1 });
|
||||
if (!region)
|
||||
return EINVAL;
|
||||
|
||||
|
@ -554,6 +575,7 @@ ErrorOr<FlatPtr> Process::sys$msyscall(Userspace<void*> address)
|
|||
|
||||
region->set_syscall_region(true);
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
ErrorOr<FlatPtr> Process::sys$msync(Userspace<void*> address, size_t size, int flags)
|
||||
|
@ -572,7 +594,8 @@ ErrorOr<FlatPtr> Process::sys$msync(Userspace<void*> address, size_t size, int f
|
|||
// Note: This is not specified
|
||||
auto rounded_size = TRY(Memory::page_round_up(size));
|
||||
|
||||
auto regions = TRY(address_space().find_regions_intersecting(Memory::VirtualRange { address.vaddr(), rounded_size }));
|
||||
return address_space().with([&](auto& space) -> ErrorOr<FlatPtr> {
|
||||
auto regions = TRY(space->find_regions_intersecting(Memory::VirtualRange { address.vaddr(), rounded_size }));
|
||||
// All regions from address upto address+size shall be mapped
|
||||
if (regions.is_empty())
|
||||
return ENOMEM;
|
||||
|
@ -603,6 +626,7 @@ ErrorOr<FlatPtr> Process::sys$msync(Userspace<void*> address, size_t size, int f
|
|||
// FIXME: Handle MS_INVALIDATE
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -197,7 +197,9 @@ ErrorOr<void> Process::peek_user_data(Span<u8> destination, Userspace<u8 const*>
|
|||
ErrorOr<void> Process::poke_user_data(Userspace<FlatPtr*> address, FlatPtr data)
|
||||
{
|
||||
Memory::VirtualRange range = { address.vaddr(), sizeof(FlatPtr) };
|
||||
auto* region = address_space().find_region_containing(range);
|
||||
|
||||
return address_space().with([&](auto& space) -> ErrorOr<void> {
|
||||
auto* region = space->find_region_containing(range);
|
||||
if (!region)
|
||||
return EFAULT;
|
||||
ScopedAddressSpaceSwitcher switcher(*this);
|
||||
|
@ -222,6 +224,7 @@ ErrorOr<void> Process::poke_user_data(Userspace<FlatPtr*> address, FlatPtr data)
|
|||
});
|
||||
|
||||
return copy_to_user(address, &data);
|
||||
});
|
||||
}
|
||||
|
||||
ErrorOr<FlatPtr> Thread::peek_debug_register(u32 register_index)
|
||||
|
|
|
@ -134,7 +134,8 @@ ErrorOr<void> Process::remap_range_as_stack(FlatPtr address, size_t size)
|
|||
if (!is_user_range(range_to_remap))
|
||||
return EFAULT;
|
||||
|
||||
if (auto* whole_region = address_space().find_region_from_range(range_to_remap)) {
|
||||
return address_space().with([&](auto& space) -> ErrorOr<void> {
|
||||
if (auto* whole_region = space->find_region_from_range(range_to_remap)) {
|
||||
if (!whole_region->is_mmap())
|
||||
return EPERM;
|
||||
if (!whole_region->vmobject().is_anonymous() || whole_region->is_shared())
|
||||
|
@ -150,7 +151,7 @@ ErrorOr<void> Process::remap_range_as_stack(FlatPtr address, size_t size)
|
|||
return {};
|
||||
}
|
||||
|
||||
if (auto* old_region = address_space().find_region_containing(range_to_remap)) {
|
||||
if (auto* old_region = space->find_region_containing(range_to_remap)) {
|
||||
if (!old_region->is_mmap())
|
||||
return EPERM;
|
||||
if (!old_region->vmobject().is_anonymous() || old_region->is_shared())
|
||||
|
@ -158,15 +159,15 @@ ErrorOr<void> Process::remap_range_as_stack(FlatPtr address, size_t size)
|
|||
|
||||
// Remove the old region from our regions tree, since were going to add another region
|
||||
// with the exact same start address.
|
||||
auto region = address_space().take_region(*old_region);
|
||||
auto region = space->take_region(*old_region);
|
||||
region->unmap();
|
||||
|
||||
// This vector is the region(s) adjacent to our range.
|
||||
// We need to allocate a new region for the range we wanted to change permission bits on.
|
||||
auto adjacent_regions = TRY(address_space().try_split_region_around_range(*region, range_to_remap));
|
||||
auto adjacent_regions = TRY(space->try_split_region_around_range(*region, range_to_remap));
|
||||
|
||||
size_t new_range_offset_in_vmobject = region->offset_in_vmobject() + (range_to_remap.base().get() - region->range().base().get());
|
||||
auto* new_region = TRY(address_space().try_allocate_split_region(*region, range_to_remap, new_range_offset_in_vmobject));
|
||||
auto* new_region = TRY(space->try_allocate_split_region(*region, range_to_remap, new_range_offset_in_vmobject));
|
||||
new_region->unsafe_clear_access();
|
||||
new_region->set_readable(true);
|
||||
new_region->set_writable(true);
|
||||
|
@ -176,14 +177,14 @@ ErrorOr<void> Process::remap_range_as_stack(FlatPtr address, size_t size)
|
|||
|
||||
// Map the new regions using our page directory (they were just allocated and don't have one).
|
||||
for (auto* adjacent_region : adjacent_regions) {
|
||||
TRY(adjacent_region->map(address_space().page_directory()));
|
||||
TRY(adjacent_region->map(space->page_directory()));
|
||||
}
|
||||
TRY(new_region->map(address_space().page_directory()));
|
||||
TRY(new_region->map(space->page_directory()));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (auto const& regions = TRY(address_space().find_regions_intersecting(range_to_remap)); regions.size()) {
|
||||
if (auto const& regions = TRY(space->find_regions_intersecting(range_to_remap)); regions.size()) {
|
||||
size_t full_size_found = 0;
|
||||
// Check that all intersecting regions are compatible.
|
||||
for (auto const* region : regions) {
|
||||
|
@ -214,19 +215,19 @@ ErrorOr<void> Process::remap_range_as_stack(FlatPtr address, size_t size)
|
|||
}
|
||||
// Remove the old region from our regions tree, since were going to add another region
|
||||
// with the exact same start address.
|
||||
auto region = address_space().take_region(*old_region);
|
||||
auto region = space->take_region(*old_region);
|
||||
region->unmap();
|
||||
|
||||
// This vector is the region(s) adjacent to our range.
|
||||
// We need to allocate a new region for the range we wanted to change permission bits on.
|
||||
auto adjacent_regions = TRY(address_space().try_split_region_around_range(*old_region, intersection_to_remap));
|
||||
auto adjacent_regions = TRY(space->try_split_region_around_range(*old_region, intersection_to_remap));
|
||||
|
||||
// Since the range is not contained in a single region, it can only partially cover its starting and ending region,
|
||||
// therefore carving out a chunk from the region will always produce a single extra region, and not two.
|
||||
VERIFY(adjacent_regions.size() == 1);
|
||||
|
||||
size_t new_range_offset_in_vmobject = old_region->offset_in_vmobject() + (intersection_to_remap.base().get() - old_region->range().base().get());
|
||||
auto* new_region = TRY(address_space().try_allocate_split_region(*region, intersection_to_remap, new_range_offset_in_vmobject));
|
||||
auto* new_region = TRY(space->try_allocate_split_region(*region, intersection_to_remap, new_range_offset_in_vmobject));
|
||||
|
||||
new_region->unsafe_clear_access();
|
||||
new_region->set_readable(true);
|
||||
|
@ -236,15 +237,16 @@ ErrorOr<void> Process::remap_range_as_stack(FlatPtr address, size_t size)
|
|||
new_region->clear_to_zero();
|
||||
|
||||
// Map the new region using our page directory (they were just allocated and don't have one) if any.
|
||||
TRY(adjacent_regions[0]->map(address_space().page_directory()));
|
||||
TRY(adjacent_regions[0]->map(space->page_directory()));
|
||||
|
||||
TRY(new_region->map(address_space().page_directory()));
|
||||
TRY(new_region->map(space->page_directory()));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return EINVAL;
|
||||
});
|
||||
}
|
||||
|
||||
ErrorOr<FlatPtr> Process::sys$sigaltstack(Userspace<stack_t const*> user_ss, Userspace<stack_t*> user_old_ss)
|
||||
|
|
|
@ -27,8 +27,11 @@ ErrorOr<FlatPtr> Process::sys$create_thread(void* (*entry)(void*), Userspace<Sys
|
|||
if (user_sp.has_overflow())
|
||||
return EOVERFLOW;
|
||||
|
||||
if (!MM.validate_user_stack(this->address_space(), VirtualAddress(user_sp.value() - 4)))
|
||||
TRY(address_space().with([&](auto& space) -> ErrorOr<void> {
|
||||
if (!MM.validate_user_stack(*space, VirtualAddress(user_sp.value() - 4)))
|
||||
return EFAULT;
|
||||
return {};
|
||||
}));
|
||||
|
||||
// FIXME: return EAGAIN if Thread::all_threads().size() is greater than PTHREAD_THREADS_MAX
|
||||
|
||||
|
@ -60,7 +63,7 @@ ErrorOr<FlatPtr> Process::sys$create_thread(void* (*entry)(void*), Userspace<Sys
|
|||
regs.rdx = params.rdx;
|
||||
regs.rcx = params.rcx;
|
||||
#endif
|
||||
regs.cr3 = address_space().page_directory().cr3();
|
||||
regs.cr3 = address_space().with([](auto& space) { return space->page_directory().cr3(); });
|
||||
|
||||
TRY(thread->make_thread_specific_region({}));
|
||||
|
||||
|
@ -92,7 +95,9 @@ void Process::sys$exit_thread(Userspace<void*> exit_value, Userspace<void*> stac
|
|||
PerformanceManager::add_thread_exit_event(*current_thread);
|
||||
|
||||
if (stack_location) {
|
||||
auto unmap_result = address_space().unmap_mmap_range(stack_location.vaddr(), stack_size);
|
||||
auto unmap_result = address_space().with([&](auto& space) {
|
||||
return space->unmap_mmap_range(stack_location.vaddr(), stack_size);
|
||||
});
|
||||
if (unmap_result.is_error())
|
||||
dbgln("Failed to unmap thread stack, terminating thread anyway. Error code: {}", unmap_result.error());
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ Thread::Thread(NonnullLockRefPtr<Process> process, NonnullOwnPtr<Memory::Region>
|
|||
# error Unknown architecture
|
||||
#endif
|
||||
|
||||
m_regs.cr3 = m_process->address_space().page_directory().cr3();
|
||||
m_regs.cr3 = m_process->address_space().with([](auto& space) { return space->page_directory().cr3(); });
|
||||
|
||||
m_kernel_stack_base = m_kernel_stack_region->vaddr().get();
|
||||
m_kernel_stack_top = m_kernel_stack_region->vaddr().offset(default_kernel_stack_size).get() & ~(FlatPtr)0x7u;
|
||||
|
@ -471,8 +471,10 @@ void Thread::exit(void* exit_value)
|
|||
u32 unlock_count;
|
||||
[[maybe_unused]] auto rc = unlock_process_if_locked(unlock_count);
|
||||
if (m_thread_specific_range.has_value()) {
|
||||
auto* region = process().address_space().find_region_from_range(m_thread_specific_range.value());
|
||||
process().address_space().deallocate_region(*region);
|
||||
process().address_space().with([&](auto& space) {
|
||||
auto* region = space->find_region_from_range(m_thread_specific_range.value());
|
||||
space->deallocate_region(*region);
|
||||
});
|
||||
}
|
||||
#ifdef ENABLE_KERNEL_COVERAGE_COLLECTION
|
||||
KCOVDevice::free_thread();
|
||||
|
@ -1352,7 +1354,8 @@ static ErrorOr<bool> symbolicate(RecognizedSymbol const& symbol, Process& proces
|
|||
if (!Memory::is_user_address(VirtualAddress(symbol.address))) {
|
||||
TRY(builder.try_append("0xdeadc0de\n"sv));
|
||||
} else {
|
||||
if (auto* region = process.address_space().find_region_containing({ VirtualAddress(symbol.address), sizeof(FlatPtr) })) {
|
||||
TRY(process.address_space().with([&](auto& space) -> ErrorOr<void> {
|
||||
if (auto* region = space->find_region_containing({ VirtualAddress(symbol.address), sizeof(FlatPtr) })) {
|
||||
size_t offset = symbol.address - region->vaddr().get();
|
||||
if (auto region_name = region->name(); !region_name.is_null() && !region_name.is_empty())
|
||||
TRY(builder.try_appendff("{:p} {} + {:#x}\n", (void*)symbol.address, region_name, offset));
|
||||
|
@ -1361,6 +1364,8 @@ static ErrorOr<bool> symbolicate(RecognizedSymbol const& symbol, Process& proces
|
|||
} else {
|
||||
TRY(builder.try_appendff("{:p}\n", symbol.address));
|
||||
}
|
||||
return {};
|
||||
}));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1412,7 +1417,8 @@ ErrorOr<void> Thread::make_thread_specific_region(Badge<Process>)
|
|||
if (!process().m_master_tls_region)
|
||||
return {};
|
||||
|
||||
auto* region = TRY(process().address_space().allocate_region(Memory::RandomizeVirtualAddress::Yes, {}, thread_specific_region_size(), PAGE_SIZE, "Thread-specific"sv, PROT_READ | PROT_WRITE));
|
||||
return process().address_space().with([&](auto& space) -> ErrorOr<void> {
|
||||
auto* region = TRY(space->allocate_region(Memory::RandomizeVirtualAddress::Yes, {}, thread_specific_region_size(), PAGE_SIZE, "Thread-specific"sv, PROT_READ | PROT_WRITE));
|
||||
|
||||
m_thread_specific_range = region->range();
|
||||
|
||||
|
@ -1426,6 +1432,7 @@ ErrorOr<void> Thread::make_thread_specific_region(Badge<Process>)
|
|||
memcpy(thread_local_storage, process().m_master_tls_region.unsafe_ptr()->vaddr().as_ptr(), process().m_master_tls_size);
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
LockRefPtr<Thread> Thread::from_tid(ThreadID tid)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue