From c76dc9a047c54293f148b3b35c5e538ed2871ed1 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 28 Oct 2018 10:26:07 +0100 Subject: [PATCH] Add /proc/mm and a /bin/mm utility that just dumps it. This shows some info about the MM. Right now it's just the zone count and the number of free physical pages. Lots more can be added. Also added "exit" to sh so we can nest shells and exit from them. I also noticed that we were leaking all the physical pages, so fixed that. --- AK/Vector.h | 15 ++++++++++++++ Kernel/MemoryManager.cpp | 42 +++++++++++++++++++++++++++++---------- Kernel/MemoryManager.h | 15 +++++++------- Kernel/ProcFileSystem.cpp | 13 ++++++++++++ Kernel/sync-sh | 1 + Userland/.gitignore | 1 + Userland/Makefile | 9 +++++++-- Userland/mm.cpp | 25 +++++++++++++++++++++++ Userland/ps.cpp | 4 ++-- Userland/sh.cpp | 11 ++++++++++ 10 files changed, 115 insertions(+), 21 deletions(-) create mode 100644 Userland/mm.cpp diff --git a/AK/Vector.h b/AK/Vector.h index 330d33cd0d2..10b7ee5dcdd 100644 --- a/AK/Vector.h +++ b/AK/Vector.h @@ -116,6 +116,21 @@ public: m_impl->remove(index); } + void append(Vector&& other) + { + Vector tmp = move(other); + ensureCapacity(size() + tmp.size()); + for (auto&& v : tmp) { + uncheckedAppend(move(v)); + } + } + + void uncheckedAppend(T&& value) + { + new (m_impl->slot(m_impl->m_size)) T(move(value)); + ++m_impl->m_size; + } + void append(T&& value) { ensureCapacity(size() + 1); diff --git a/Kernel/MemoryManager.cpp b/Kernel/MemoryManager.cpp index 0f32eb96795..c22e8b3e0e4 100644 --- a/Kernel/MemoryManager.cpp +++ b/Kernel/MemoryManager.cpp @@ -34,9 +34,7 @@ void MemoryManager::initializePaging() memset(m_pageTableOne, 0, 4096); memset(m_pageDirectory, 0, 4096); - kprintf("MM: Page directory @ %p\n", m_pageDirectory); - kprintf("MM: Page table zero @ %p\n", m_pageTableZero); - kprintf("MM: Page table one @ %p\n", m_pageTableOne); + kprintf("[MM] Page directory @ %p\n", m_pageDirectory); // Make null dereferences crash. protectMap(LinearAddress(0), 4 * KB); @@ -72,7 +70,7 @@ auto MemoryManager::ensurePTE(LinearAddress linearAddress) -> PageTableEntry PageDirectoryEntry pde = PageDirectoryEntry(&m_pageDirectory[pageDirectoryIndex]); if (!pde.isPresent()) { - kprintf("PDE %u !present, allocating\n", pageDirectoryIndex); + kprintf("[MM] PDE %u not present, allocating\n", pageDirectoryIndex); if (pageDirectoryIndex == 0) { pde.setPageTableBase((dword)m_pageTableZero); pde.setUserAllowed(true); @@ -85,7 +83,7 @@ auto MemoryManager::ensurePTE(LinearAddress linearAddress) -> PageTableEntry pde.setWritable(true); } else { auto* pageTable = allocatePageTable(); - kprintf("allocated page table %u (for laddr=%p) at %p\n", pageDirectoryIndex, linearAddress.get(), pageTable); + kprintf("[MM] Allocated page table #%u (for laddr=%p) at %p\n", pageDirectoryIndex, linearAddress.get(), pageTable); memset(pageTable, 0, 4096); pde.setPageTableBase((dword)pageTable); pde.setUserAllowed(true); @@ -134,7 +132,7 @@ void MemoryManager::initialize() PageFaultResponse MemoryManager::handlePageFault(const PageFault& fault) { ASSERT_INTERRUPTS_DISABLED(); - kprintf("MM: handlePageFault(%w) at laddr=%p\n", fault.code(), fault.address().get()); + kprintf("[MM] handlePageFault(%w) at laddr=%p\n", fault.code(), fault.address().get()); if (fault.isNotPresent()) { kprintf(" >> NP fault!\n"); } else if (fault.isProtectionViolation()) { @@ -143,11 +141,36 @@ PageFaultResponse MemoryManager::handlePageFault(const PageFault& fault) return PageFaultResponse::ShouldCrash; } +void MemoryManager::registerZone(Zone& zone) +{ + ASSERT_INTERRUPTS_DISABLED(); + m_zones.set(&zone); +} + +void MemoryManager::unregisterZone(Zone& zone) +{ + ASSERT_INTERRUPTS_DISABLED(); + m_zones.remove(&zone); + m_freePages.append(move(zone.m_pages)); +} + +Zone::Zone(Vector&& pages) + : m_pages(move(pages)) +{ + MM.registerZone(*this); +} + +Zone::~Zone() +{ + MM.unregisterZone(*this); +} + RetainPtr MemoryManager::createZone(size_t size) { + InterruptDisabler disabler; auto pages = allocatePhysicalPages(ceilDiv(size, PAGE_SIZE)); if (pages.isEmpty()) { - kprintf("MM: createZone: no physical pages for size %u", size); + kprintf("[MM] createZone: no physical pages for size %u", size); return nullptr; } return adopt(*new Zone(move(pages))); @@ -170,7 +193,7 @@ byte* MemoryManager::quickMapOnePage(PhysicalAddress physicalAddress) { ASSERT_INTERRUPTS_DISABLED(); auto pte = ensurePTE(LinearAddress(4 * MB)); - kprintf("quickmap %x @ %x {pte @ %p}\n", physicalAddress.get(), 4*MB, pte.ptr()); + kprintf("[MM] quickmap %x @ %x {pte @ %p}\n", physicalAddress.get(), 4*MB, pte.ptr()); pte.setPhysicalPageBase(physicalAddress.pageBase()); pte.setPresent(true); pte.setWritable(true); @@ -297,7 +320,7 @@ bool MemoryManager::mapRegionsForTask(Task& task) bool copyToZone(Zone& zone, const void* data, size_t size) { if (zone.size() < size) { - kprintf("copyToZone: can't fit %u bytes into zone with size %u\n", size, zone.size()); + kprintf("[MM] copyToZone: can't fit %u bytes into zone with size %u\n", size, zone.size()); return false; } @@ -314,4 +337,3 @@ bool copyToZone(Zone& zone, const void* data, size_t size) return true; } - diff --git a/Kernel/MemoryManager.h b/Kernel/MemoryManager.h index 0c886074334..4ed3ff66f7a 100644 --- a/Kernel/MemoryManager.h +++ b/Kernel/MemoryManager.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include "Task.h" class Task; @@ -17,7 +17,7 @@ enum class PageFaultResponse { struct Zone : public Retainable { public: - ~Zone() { } + ~Zone(); size_t size() const { return m_pages.size() * PAGE_SIZE; } const Vector& pages() const { return m_pages; } @@ -25,10 +25,7 @@ public: private: friend class MemoryManager; friend bool copyToZone(Zone&, const void* data, size_t); - explicit Zone(Vector&& pages) - : m_pages(move(pages)) - { - } + explicit Zone(Vector&&); Vector m_pages; }; @@ -38,6 +35,7 @@ bool copyToZone(Zone&, const void* data, size_t); #define MM MemoryManager::the() class MemoryManager { + friend ByteBuffer procfs$mm(); public: static MemoryManager& the() PURE; @@ -62,6 +60,9 @@ public: bool mapRegionsForTask(Task&); bool unmapRegionsForTask(Task&); + void registerZone(Zone&); + void unregisterZone(Zone&); + private: MemoryManager(); ~MemoryManager(); @@ -161,7 +162,7 @@ private: dword* m_pageTableZero; dword* m_pageTableOne; - HashMap> m_zones; + HashTable m_zones; Vector m_freePages; }; diff --git a/Kernel/ProcFileSystem.cpp b/Kernel/ProcFileSystem.cpp index 8457361cf4c..f7b7f3f5cbc 100644 --- a/Kernel/ProcFileSystem.cpp +++ b/Kernel/ProcFileSystem.cpp @@ -118,6 +118,18 @@ void ProcFileSystem::removeProcess(Task& task) m_pid2inode.remove(pid); } +ByteBuffer procfs$mm() +{ + InterruptDisabler disabler; + auto buffer = ByteBuffer::createUninitialized(1024); + char* ptr = (char*)buffer.pointer(); + ptr += ksprintf(ptr, "Zone count: %u\n", MM.m_zones.size()); + ptr += ksprintf(ptr, "Free physical pages: %u\n", MM.m_freePages.size()); + buffer.trim(ptr - (char*)buffer.pointer()); + return buffer; +} + + ByteBuffer procfs$mounts() { InterruptDisabler disabler; @@ -171,6 +183,7 @@ ByteBuffer procfs$summary() bool ProcFileSystem::initialize() { SyntheticFileSystem::initialize(); + addFile(createGeneratedFile("mm", procfs$mm)); addFile(createGeneratedFile("mounts", procfs$mounts)); addFile(createGeneratedFile("kmalloc", procfs$kmalloc)); addFile(createGeneratedFile("summary", procfs$summary)); diff --git a/Kernel/sync-sh b/Kernel/sync-sh index 8584eaa626a..4847c68a401 100755 --- a/Kernel/sync-sh +++ b/Kernel/sync-sh @@ -15,6 +15,7 @@ cp ../Userland/cat mnt/bin/cat cp ../Userland/uname mnt/bin/uname cp ../Userland/clear mnt/bin/clear cp ../Userland/tst mnt/bin/tst +cp ../Userland/mm mnt/bin/mm cp kernel.map mnt/ umount mnt sync diff --git a/Userland/.gitignore b/Userland/.gitignore index e365fd391b0..f6b0db76150 100644 --- a/Userland/.gitignore +++ b/Userland/.gitignore @@ -13,3 +13,4 @@ cat uname clear tst +mm diff --git a/Userland/Makefile b/Userland/Makefile index 72057879704..bc8e0ecaee3 100644 --- a/Userland/Makefile +++ b/Userland/Makefile @@ -12,7 +12,8 @@ OBJS = \ cat.o \ uname.o \ clear.o \ - tst.o + tst.o \ + mm.o APPS = \ id \ @@ -28,7 +29,8 @@ APPS = \ cat \ uname \ clear \ - tst + tst \ + mm ARCH_FLAGS = STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib @@ -90,6 +92,9 @@ clear: clear.o tst: tst.o $(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a +mm: mm.o + $(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a + .cpp.o: @echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< diff --git a/Userland/mm.cpp b/Userland/mm.cpp new file mode 100644 index 00000000000..ee035988677 --- /dev/null +++ b/Userland/mm.cpp @@ -0,0 +1,25 @@ +#include +#include + +int main(int c, char** v) +{ + int fd = open("/proc/mm"); + if (fd == -1) { + perror("failed to open /proc/mm"); + return 1; + } + for (;;) { + char buf[128]; + ssize_t nread = read(fd, buf, sizeof(buf)); + if (nread == 0) + break; + if (nread < 0) { + perror("failed to read"); + return 2; + } + for (ssize_t i = 0; i < nread; ++i) { + putchar(buf[i]); + } + } + return 0; +} diff --git a/Userland/ps.cpp b/Userland/ps.cpp index a1cc620c208..ec49c480d0e 100644 --- a/Userland/ps.cpp +++ b/Userland/ps.cpp @@ -5,7 +5,7 @@ int main(int c, char** v) { int fd = open("/proc/summary"); if (fd == -1) { - printf("failed to open /proc/summary :(\n"); + perror("failed to open /proc/summary"); return 1; } for (;;) { @@ -14,7 +14,7 @@ int main(int c, char** v) if (nread == 0) break; if (nread < 0) { - printf("failed to read :(\n"); + perror("failed to read"); return 2; } for (ssize_t i = 0; i < nread; ++i) { diff --git a/Userland/sh.cpp b/Userland/sh.cpp index b172f6fa9c9..3f503419a63 100644 --- a/Userland/sh.cpp +++ b/Userland/sh.cpp @@ -26,6 +26,13 @@ static int sh_pwd(int, const char**) return 0; } +static int sh_exit(int, const char**) +{ + printf("Good-bye!\n"); + exit(0); + return 0; +} + static int sh_cd(int argc, const char** argv) { if (argc == 1) { @@ -77,6 +84,10 @@ static bool handle_builtin(int argc, const char** argv, int& retval) retval = sh_pwd(argc, argv); return true; } + if (!strcmp(argv[0], "exit")) { + retval = sh_exit(argc, argv); + return true; + } return false; }