[COMMIT osv master] mmu: track linear mmap

6 views
Skip to first unread message

Commit Bot

unread,
Mar 30, 2022, 11:29:47 PM3/30/22
to osv...@googlegroups.com, Waldemar Kozaczuk
From: Waldemar Kozaczuk <jwkoz...@gmail.com>
Committer: Waldemar Kozaczuk <jwkoz...@gmail.com>
Branch: master

mmu: track linear mmap

Sometimes while debugging problems related to how kernel and devices are
memory-mapped it is helpful to see it in some form in gdb or by reading
a procfs file just like we can do with mmap-ed VMAs. In addition we
need to know where linear VMAs are located so that we can avoid
collisions with mmap() as described by the issue #1135.

To that end this patch adds new struct - linear_vma and collection
of those - linear_vma_set - to track how memory gets mapped using
linear_map(). It also modifies all places calling linear_map() to
pass new argument - name.

Please note that we can not re-use existing vma class, as it holds
much richer information and lots of it is not applicable to linear map
which is quite static and is simply a pre-populated mapping between
some area of virtual and physical memory.

Upcoming patches will add new 'osv linear_mmap' to loader.py
and implementation of new sysfs pseudo file.

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>

---
diff --git a/arch/aarch64/arch-setup.cc b/arch/aarch64/arch-setup.cc
--- a/arch/aarch64/arch-setup.cc
+++ b/arch/aarch64/arch-setup.cc
@@ -61,7 +61,7 @@ void arch_setup_pci()
pci::set_pci_cfg(pci_cfg, pci_cfg_len);
pci_cfg = pci::get_pci_cfg(&pci_cfg_len);
mmu::linear_map((void *)pci_cfg, (mmu::phys)pci_cfg, pci_cfg_len,
- mmu::page_size, mmu::mattr::dev);
+ "pci_cfg", mmu::page_size, mmu::mattr::dev);

/* linear_map [TTBR0 - PCI I/O and memory ranges] */
u64 ranges[2]; size_t ranges_len[2];
@@ -73,9 +73,9 @@ void arch_setup_pci()
ranges[0] = pci::get_pci_io(&ranges_len[0]);
ranges[1] = pci::get_pci_mem(&ranges_len[1]);
mmu::linear_map((void *)ranges[0], (mmu::phys)ranges[0], ranges_len[0],
- mmu::page_size, mmu::mattr::dev);
+ "pci_io", mmu::page_size, mmu::mattr::dev);
mmu::linear_map((void *)ranges[1], (mmu::phys)ranges[1], ranges_len[1],
- mmu::page_size, mmu::mattr::dev);
+ "pci_mem", mmu::page_size, mmu::mattr::dev);
}
#endif

@@ -94,25 +94,27 @@ void arch_setup_free_memory()
/* linear_map [TTBR1] */
for (auto&& area : mmu::identity_mapped_areas) {
auto base = reinterpret_cast<void*>(get_mem_area_base(area));
- mmu::linear_map(base + addr, addr, memory::phys_mem_size);
+ mmu::linear_map(base + addr, addr, memory::phys_mem_size,
+ area == mmu::mem_area::main ? "main" :
+ area == mmu::mem_area::page ? "page" : "mempool");
}

/* linear_map [TTBR0 - boot, DTB and ELF] */
mmu::linear_map((void *)mmu::mem_addr, (mmu::phys)mmu::mem_addr,
- addr - mmu::mem_addr);
+ addr - mmu::mem_addr, "kernel");

if (console::PL011_Console::active) {
/* linear_map [TTBR0 - UART] */
addr = (mmu::phys)console::aarch64_console.pl011.get_base_addr();
- mmu::linear_map((void *)addr, addr, 0x1000, mmu::page_size,
+ mmu::linear_map((void *)addr, addr, 0x1000, "pl011", mmu::page_size,
mmu::mattr::dev);
}

#if CONF_drivers_cadence
if (console::Cadence_Console::active) {
// linear_map [TTBR0 - UART]
addr = (mmu::phys)console::aarch64_console.cadence.get_base_addr();
- mmu::linear_map((void *)addr, addr, 0x1000, mmu::page_size,
+ mmu::linear_map((void *)addr, addr, 0x1000, "cadence", mmu::page_size,
mmu::mattr::dev);
}
#endif
@@ -124,9 +126,9 @@ void arch_setup_free_memory()
abort("arch-setup: failed to get GICv2 information from dtb.\n");
}
gic::gic = new gic::gic_driver(dist, cpu);
- mmu::linear_map((void *)dist, (mmu::phys)dist, dist_len, mmu::page_size,
+ mmu::linear_map((void *)dist, (mmu::phys)dist, dist_len, "gic_dist", mmu::page_size,
mmu::mattr::dev);
- mmu::linear_map((void *)cpu, (mmu::phys)cpu, cpu_len, mmu::page_size,
+ mmu::linear_map((void *)cpu, (mmu::phys)cpu, cpu_len, "gic_cpu", mmu::page_size,
mmu::mattr::dev);

#if CONF_drivers_pci
diff --git a/arch/x64/apic.cc b/arch/x64/apic.cc
--- a/arch/x64/apic.cc
+++ b/arch/x64/apic.cc
@@ -103,7 +103,7 @@ void apic_driver::read_base()
xapic::xapic()
: apic_driver()
{
- mmu::linear_map(static_cast<void*>(_base_virt), _apic_base, 4096);
+ mmu::linear_map(static_cast<void*>(_base_virt), _apic_base, 4096, "xapic");
xapic::enable();
}

diff --git a/arch/x64/arch-setup.cc b/arch/x64/arch-setup.cc
--- a/arch/x64/arch-setup.cc
+++ b/arch/x64/arch-setup.cc
@@ -164,7 +164,10 @@ void arch_setup_free_memory()
});
for (auto&& area : mmu::identity_mapped_areas) {
auto base = reinterpret_cast<void*>(get_mem_area_base(area));
- mmu::linear_map(base, 0, initial_map, initial_map);
+ mmu::linear_map(base, 0, initial_map,
+ area == mmu::mem_area::main ? "main" :
+ area == mmu::mem_area::page ? "page" : "mempool",
+ initial_map);
}
// Map the core, loaded by the boot loader
// In order to properly setup mapping between virtual
@@ -176,7 +179,7 @@ void arch_setup_free_memory()
// as expressed by the assignment below
elf_start = reinterpret_cast<void*>(elf_phys_start + OSV_KERNEL_VM_SHIFT);
elf_size = edata_phys - elf_phys_start;
- mmu::linear_map(elf_start, elf_phys_start, elf_size, OSV_KERNEL_BASE);
+ mmu::linear_map(elf_start, elf_phys_start, elf_size, "kernel", OSV_KERNEL_BASE);
// get rid of the command line, before low memory is unmapped
parse_cmdline(mb);
// now that we have some free memory, we can start mapping the rest
@@ -205,7 +208,9 @@ void arch_setup_free_memory()
}
for (auto&& area : mmu::identity_mapped_areas) {
auto base = reinterpret_cast<void*>(get_mem_area_base(area));
- mmu::linear_map(base + ent.addr, ent.addr, ent.size, ~0);
+ mmu::linear_map(base + ent.addr, ent.addr, ent.size,
+ area == mmu::mem_area::main ? "main" :
+ area == mmu::mem_area::page ? "page" : "mempool", ~0);
}
mmu::free_initial_memory_range(ent.addr, ent.size);
});
diff --git a/arch/x64/dmi.cc b/arch/x64/dmi.cc
--- a/arch/x64/dmi.cc
+++ b/arch/x64/dmi.cc
@@ -53,7 +53,7 @@ static void dmi_table(u32 base, u16 len, u16 num)
{
u8* const table_virt = mmu::phys_cast<u8>(base);

- mmu::linear_map(static_cast<void*>(table_virt), base, len);
+ mmu::linear_map(static_cast<void*>(table_virt), base, len, "smbios");

auto start = reinterpret_cast<const char*>(table_virt);

@@ -131,7 +131,7 @@ void dmi_probe()

u8* const dmi_virt = mmu::phys_cast<u8>(dmi_base);

- mmu::linear_map(static_cast<void*>(dmi_virt), dmi_base, 0x10000);
+ mmu::linear_map(static_cast<void*>(dmi_virt), dmi_base, 0x10000, "dmi");

auto start = reinterpret_cast<const char*>(dmi_virt);

diff --git a/arch/x64/ioapic.cc b/arch/x64/ioapic.cc
--- a/arch/x64/ioapic.cc
+++ b/arch/x64/ioapic.cc
@@ -43,7 +43,7 @@ void write(unsigned reg, u32 data)

void init()
{
- mmu::linear_map(const_cast<void*>(base), base_phys, 4096);
+ mmu::linear_map(const_cast<void*>(base), base_phys, 4096, "ioapic");
}

}
diff --git a/bsd/porting/mmu.cc b/bsd/porting/mmu.cc
--- a/bsd/porting/mmu.cc
+++ b/bsd/porting/mmu.cc
@@ -15,7 +15,7 @@

void *pmap_mapdev(uint64_t paddr, size_t size)
{
- return (void *)mmio_map(paddr, size);
+ return (void *)mmio_map(paddr, size, "xen_store");
}

uint64_t virt_to_phys(void *virt)
diff --git a/core/mmio.cc b/core/mmio.cc
--- a/core/mmio.cc
+++ b/core/mmio.cc
@@ -51,10 +51,10 @@ u64 mmio_getq(mmioaddr_t addr)
return (*reinterpret_cast<volatile u64*>(addr));
}

-mmioaddr_t mmio_map(u64 paddr, size_t size_bytes)
+mmioaddr_t mmio_map(u64 paddr, size_t size_bytes, const char* name)
{
char* map_to = mmu::phys_mem + paddr;
- linear_map(map_to, paddr, size_bytes);
+ linear_map(map_to, paddr, size_bytes, name);
return map_to;
}

diff --git a/core/mmu.cc b/core/mmu.cc
--- a/core/mmu.cc
+++ b/core/mmu.cc
@@ -28,6 +28,7 @@
#include <osv/rcu.hh>
#include <osv/rwlock.h>
#include <numeric>
+#include <set>

// FIXME: Without this pragma, we get a lot of warnings that I don't know
// how to explain or fix. For now, let's just ignore them :-(
@@ -46,6 +47,16 @@ extern const char text_start[], text_end[];

namespace mmu {

+struct linear_vma_compare {
+ bool operator()(const linear_vma* a, const linear_vma* b) {
+ return a->_virt_addr < b->_virt_addr;
+ }
+};
+
+__attribute__((init_priority((int)init_prio::linear_vma_set)))
+std::set<linear_vma*, linear_vma_compare> linear_vma_set;
+rwlock_t linear_vma_set_mutex;
+
namespace bi = boost::intrusive;

class vma_compare {
@@ -1857,14 +1868,29 @@ int shm_file::close()
return 0;
}

-void linear_map(void* _virt, phys addr, size_t size,
+linear_vma::linear_vma(void* virt, phys phys, size_t size, mattr mem_attr, const char* name) {
+ _virt_addr = virt;
+ _phys_addr = phys;
+ _size = size;
+ _mem_attr = mem_attr;
+ _name = name;
+}
+
+linear_vma::~linear_vma() {
+}
+
+void linear_map(void* _virt, phys addr, size_t size, const char* name,
size_t slop, mattr mem_attr)
{
uintptr_t virt = reinterpret_cast<uintptr_t>(_virt);
slop = std::min(slop, page_size_level(nr_page_sizes - 1));
assert((virt & (slop - 1)) == (addr & (slop - 1)));
linear_page_mapper phys_map(addr, size, mem_attr);
map_range(virt, virt, size, phys_map, slop);
+ auto _vma = new linear_vma(_virt, addr, size, mem_attr, name);
+ WITH_LOCK(linear_vma_set_mutex.for_write()) {
+ linear_vma_set.insert(_vma);
+ }
}

void free_initial_memory_range(uintptr_t addr, size_t size)
diff --git a/drivers/acpi.cc b/drivers/acpi.cc
--- a/drivers/acpi.cc
+++ b/drivers/acpi.cc
@@ -175,7 +175,7 @@ void *AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Where, ACPI_SIZE Length)
uint64_t _where = align_down(Where, mmu::huge_page_size);
size_t map_size = align_up(Length + Where - _where, mmu::huge_page_size);

- mmu::linear_map(mmu::phys_to_virt(_where), _where, map_size);
+ mmu::linear_map(mmu::phys_to_virt(_where), _where, map_size, "acpi");
return mmu::phys_to_virt(Where);
}

diff --git a/drivers/hpet.cc b/drivers/hpet.cc
--- a/drivers/hpet.cc
+++ b/drivers/hpet.cc
@@ -174,7 +174,7 @@ void __attribute__((constructor(init_prio::hpet))) hpet_init()

// Check what type of main counter - 32-bit or 64-bit - is available and
// construct relevant hpet clock instance
- mmioaddr_t hpet_mmio_address = mmio_map(hpet_address.Address, 4096);
+ mmioaddr_t hpet_mmio_address = mmio_map(hpet_address.Address, 4096, "hpet");

auto cap = mmio_getl(hpet_mmio_address + HPET_CAP);
if (cap & HPET_CAP_COUNT_SIZE) {
diff --git a/drivers/mmio-isa-serial.cc b/drivers/mmio-isa-serial.cc
--- a/drivers/mmio-isa-serial.cc
+++ b/drivers/mmio-isa-serial.cc
@@ -31,7 +31,7 @@ void mmio_isa_serial_console::early_init(u64 mmio_phys_address)
void mmio_isa_serial_console::memory_map()
{
if (_phys_mmio_address) {
- _addr_mmio = mmio_map(_phys_mmio_address, mmu::page_size);
+ _addr_mmio = mmio_map(_phys_mmio_address, mmu::page_size, "isa_serial_console");
}
}

diff --git a/drivers/pci-function.cc b/drivers/pci-function.cc
--- a/drivers/pci-function.cc
+++ b/drivers/pci-function.cc
@@ -84,7 +84,7 @@ namespace pci {
void bar::map()
{
if (_is_mmio) {
- _addr_mmio = mmio_map(get_addr64(), get_size());
+ _addr_mmio = mmio_map(get_addr64(), get_size(), "pci_bar");
}
}

diff --git a/drivers/pl031.cc b/drivers/pl031.cc
--- a/drivers/pl031.cc
+++ b/drivers/pl031.cc
@@ -21,7 +21,7 @@
pl031::pl031(u64 address)
{
_address = address;
- mmu::linear_map((void *)_address, _address, mmu::page_size, mmu::page_size,
+ mmu::linear_map((void *)_address, _address, mmu::page_size, "pl031", mmu::page_size,
mmu::mattr::dev);
}

diff --git a/drivers/virtio-mmio.cc b/drivers/virtio-mmio.cc
--- a/drivers/virtio-mmio.cc
+++ b/drivers/virtio-mmio.cc
@@ -112,7 +112,7 @@ void mmio_device::register_interrupt(interrupt_factory irq_factory)

bool mmio_device::parse_config()
{
- _addr_mmio = mmio_map(_dev_info._address, _dev_info._size);
+ _addr_mmio = mmio_map(_dev_info._address, _dev_info._size, "virtio_mmio_cfg");

u32 magic = mmio_getl(_addr_mmio + VIRTIO_MMIO_MAGIC_VALUE);
if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) {
diff --git a/drivers/xenconsole.cc b/drivers/xenconsole.cc
--- a/drivers/xenconsole.cc
+++ b/drivers/xenconsole.cc
@@ -83,7 +83,7 @@ void XEN_Console::dev_start()
INTR_TYPE_MISC, &_irq) != 0)
throw std::runtime_error("fail to bind evtchn");

- _interface = (xencons_interface*)mmio_map(_pfn << PAGE_SHIFT, PAGE_SIZE);
+ _interface = (xencons_interface*)mmio_map(_pfn << PAGE_SHIFT, PAGE_SIZE, "xen_console");
}

void XEN_Console::flush()
diff --git a/include/osv/mmio.hh b/include/osv/mmio.hh
--- a/include/osv/mmio.hh
+++ b/include/osv/mmio.hh
@@ -25,7 +25,7 @@ u32 mmio_getl(mmioaddr_t addr);
u64 mmio_getq(mmioaddr_t addr);

// Map mmio regions
-mmioaddr_t mmio_map(u64 paddr, size_t size_bytes);
+mmioaddr_t mmio_map(u64 paddr, size_t size_bytes, const char* name);
void mmio_unmap(mmioaddr_t addr, size_t size_bytes);

#endif // MMIO_HH
diff --git a/include/osv/mmu.hh b/include/osv/mmu.hh
--- a/include/osv/mmu.hh
+++ b/include/osv/mmu.hh
@@ -43,6 +43,20 @@ constexpr inline unsigned pt_index(void *virt, unsigned level)

struct page_allocator;

+struct linear_vma {
+ void* _virt_addr;
+ phys _phys_addr;
+ size_t _size;
+ mattr _mem_attr;
+ std::string _name;
+
+ linear_vma(void* virt, phys phys, size_t size, mattr mem_attr, const char* name);
+ ~linear_vma();
+
+ uintptr_t v_start() const { return reinterpret_cast<uintptr_t>(_virt_addr); }
+ uintptr_t v_end() const { return reinterpret_cast<uintptr_t>(_virt_addr + _size); }
+};
+
class vma {
public:
vma(addr_range range, unsigned perm, unsigned flags, bool map_dirty, page_allocator *page_ops = nullptr);
@@ -298,7 +312,7 @@ bool is_page_aligned(void* addr)
// an architecture-specific meaning.
// Currently mem_attr is ignored on x86_64. For aarch64 specifics see
// definitions in arch/aarch64/arch-mmu.hh
-void linear_map(void* virt, phys addr, size_t size,
+void linear_map(void* virt, phys addr, size_t size, const char* name,
size_t slop = mmu::page_size,
mattr mem_attr = mmu::mattr_default);

diff --git a/include/osv/prio.hh b/include/osv/prio.hh
--- a/include/osv/prio.hh
+++ b/include/osv/prio.hh
@@ -16,6 +16,7 @@ enum {
cpus,
fpranges,
pt_root,
+ linear_vma_set,
mempool,
routecache,
pagecache,
Reply all
Reply to author
Forward
0 new messages