From: Waldemar Kozaczuk <[email protected]>
Committer: Waldemar Kozaczuk <[email protected]>
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 <[email protected]>

---
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,

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/00000000000006c25a05db7b46b7%40google.com.

Reply via email to