mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 20:47:45 +00:00
UserspaceEmulator: Enable splitting regions at arbitrary points
This is not yet useful in and of itself, but enables the feature in the next commit.
This commit is contained in:
parent
7cc8f20a30
commit
45443f24ec
7 changed files with 66 additions and 2 deletions
|
@ -223,6 +223,19 @@ void MmapRegion::write64(u32 offset, ValueWithShadow<u64> value)
|
||||||
*reinterpret_cast<u64*>(m_shadow_data + offset) = value.shadow();
|
*reinterpret_cast<u64*>(m_shadow_data + offset) = value.shadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NonnullOwnPtr<MmapRegion> MmapRegion::split_at(VirtualAddress offset)
|
||||||
|
{
|
||||||
|
VERIFY(!m_malloc);
|
||||||
|
VERIFY(!m_malloc_metadata);
|
||||||
|
Range new_range = range();
|
||||||
|
Range other_range = new_range.split_at(offset);
|
||||||
|
auto other_region = adopt_own(*new MmapRegion(other_range.base().get(), other_range.size(), prot(), data() + new_range.size(), shadow_data() + new_range.size()));
|
||||||
|
other_region->m_file_backed = m_file_backed;
|
||||||
|
other_region->m_name = m_name;
|
||||||
|
set_range(new_range);
|
||||||
|
return other_region;
|
||||||
|
}
|
||||||
|
|
||||||
void MmapRegion::set_prot(int prot)
|
void MmapRegion::set_prot(int prot)
|
||||||
{
|
{
|
||||||
set_readable(prot & PROT_READ);
|
set_readable(prot & PROT_READ);
|
||||||
|
|
|
@ -56,6 +56,12 @@ public:
|
||||||
bool is_malloc_block() const { return m_malloc; }
|
bool is_malloc_block() const { return m_malloc; }
|
||||||
void set_malloc(bool b) { m_malloc = b; }
|
void set_malloc(bool b) { m_malloc = b; }
|
||||||
|
|
||||||
|
NonnullOwnPtr<MmapRegion> split_at(VirtualAddress);
|
||||||
|
|
||||||
|
int prot() const
|
||||||
|
{
|
||||||
|
return (is_readable() ? PROT_READ : 0) | (is_writable() ? PROT_WRITE : 0) | (is_executable() ? PROT_EXEC : 0);
|
||||||
|
}
|
||||||
void set_prot(int prot);
|
void set_prot(int prot);
|
||||||
|
|
||||||
MallocRegionMetadata* malloc_metadata() { return m_malloc_metadata; }
|
MallocRegionMetadata* malloc_metadata() { return m_malloc_metadata; }
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
namespace UserspaceEmulator {
|
namespace UserspaceEmulator {
|
||||||
|
|
||||||
Vector<Range, 2> Range::carve(const Range& taken)
|
Vector<Range, 2> Range::carve(const Range& taken) const
|
||||||
{
|
{
|
||||||
VERIFY((taken.size() % PAGE_SIZE) == 0);
|
VERIFY((taken.size() % PAGE_SIZE) == 0);
|
||||||
Vector<Range, 2> parts;
|
Vector<Range, 2> parts;
|
||||||
|
|
|
@ -67,7 +67,18 @@ public:
|
||||||
return contains(other.base(), other.size());
|
return contains(other.base(), other.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<Range, 2> carve(const Range&);
|
Vector<Range, 2> carve(const Range&) const;
|
||||||
|
|
||||||
|
Range split_at(VirtualAddress address)
|
||||||
|
{
|
||||||
|
VERIFY(address.is_page_aligned());
|
||||||
|
VERIFY(m_base < address);
|
||||||
|
size_t new_size = (address - m_base).get();
|
||||||
|
VERIFY(new_size < m_size);
|
||||||
|
size_t other_size = m_size - new_size;
|
||||||
|
m_size = new_size;
|
||||||
|
return { address, other_size };
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VirtualAddress m_base;
|
VirtualAddress m_base;
|
||||||
|
|
|
@ -81,6 +81,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Region(u32 base, u32 size);
|
Region(u32 base, u32 size);
|
||||||
|
void set_range(Range r) { m_range = r; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Emulator& m_emulator;
|
Emulator& m_emulator;
|
||||||
|
|
|
@ -61,6 +61,38 @@ void SoftMMU::remove_region(Region& region)
|
||||||
m_regions.remove_first_matching([&](auto& entry) { return entry.ptr() == ®ion; });
|
m_regions.remove_first_matching([&](auto& entry) { return entry.ptr() == ®ion; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SoftMMU::ensure_split_at(X86::LogicalAddress address)
|
||||||
|
{
|
||||||
|
// FIXME: If this fails, call Emulator::dump_backtrace
|
||||||
|
VERIFY(address.selector() != 0x2b);
|
||||||
|
|
||||||
|
u32 offset = address.offset();
|
||||||
|
VERIFY((offset & (PAGE_SIZE - 1)) == 0);
|
||||||
|
size_t page_index = address.offset() / PAGE_SIZE;
|
||||||
|
|
||||||
|
if (!page_index)
|
||||||
|
return;
|
||||||
|
if (m_page_to_region_map[page_index - 1] != m_page_to_region_map[page_index])
|
||||||
|
return;
|
||||||
|
if (!m_page_to_region_map[page_index])
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If we get here, we know that the page exists and belongs to a region, that there is
|
||||||
|
// a previous page, and that it belongs to the same region.
|
||||||
|
VERIFY(is<MmapRegion>(m_page_to_region_map[page_index]));
|
||||||
|
MmapRegion* old_region = static_cast<MmapRegion*>(m_page_to_region_map[page_index]);
|
||||||
|
NonnullOwnPtr<MmapRegion> new_region = old_region->split_at(VirtualAddress(offset));
|
||||||
|
|
||||||
|
size_t first_page_in_region = new_region->base() / PAGE_SIZE;
|
||||||
|
size_t last_page_in_region = (new_region->base() + new_region->size() - 1) / PAGE_SIZE;
|
||||||
|
for (size_t page = first_page_in_region; page <= last_page_in_region; ++page) {
|
||||||
|
VERIFY(m_page_to_region_map[page] == old_region);
|
||||||
|
m_page_to_region_map[page] = new_region.ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_regions.append(move(new_region));
|
||||||
|
}
|
||||||
|
|
||||||
void SoftMMU::set_tls_region(NonnullOwnPtr<Region> region)
|
void SoftMMU::set_tls_region(NonnullOwnPtr<Region> region)
|
||||||
{
|
{
|
||||||
VERIFY(!m_tls_region);
|
VERIFY(!m_tls_region);
|
||||||
|
|
|
@ -63,6 +63,7 @@ public:
|
||||||
|
|
||||||
void add_region(NonnullOwnPtr<Region>);
|
void add_region(NonnullOwnPtr<Region>);
|
||||||
void remove_region(Region&);
|
void remove_region(Region&);
|
||||||
|
void ensure_split_at(X86::LogicalAddress);
|
||||||
|
|
||||||
void set_tls_region(NonnullOwnPtr<Region>);
|
void set_tls_region(NonnullOwnPtr<Region>);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue