📄 kern_physmem.cxx
字号:
/* * Copyright (C) 1998, 1999, Jonathan S. Shapiro. * * This file is part of the EROS Operating System. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <kerninc/kernel.hxx>#include <kerninc/util.h>#include <kerninc/PhysMem.hxx>#include <disk/DiskKey.hxx>#include <kerninc/BootInfo.h> #define dbg_init 0x1u#define dbg_avail 0x2u#define dbg_alloc 0x4u#define dbg_new 0x8u/* Following should be an OR of some of the above */#define dbg_flags ( 0u )#define DEBUG(x) if (dbg_##x & dbg_flags)/* Implementation of Memory Constraints */PmemConstraint PhysMem::pages = { (kpa_t) 0u, ~((kpa_t)0u), EROS_PAGE_SIZE };PmemConstraint PhysMem::any = { (kpa_t) 0u, ~((kpa_t)0u), sizeof(uint32_t) };extern "C" { extern int end;}kpa_t PhysMem::PhysicalPageBound = 0;static PmemInfo PhysicalMemoryInfo[MAX_MEMINFO];PmemInfo *PhysMem::pmemInfo = &PhysicalMemoryInfo[0];unsigned long PhysMem::nPmemInfo;voidPhysMem::Init(){ for (unsigned i = 0; i < BootInfoPtr->nMemInfo; i++) { MemInfo *pmi = &BootInfoPtr->memInfo[i]; bool readOnly = (pmi->type != MI_MEMORY); (void) PhysMem::AddRegion(pmi->base, pmi->bound, pmi->type, readOnly); if ( (pmi->type == MI_MEMORY || pmi->type == MI_RAMDISK || pmi->type == MI_PRELOAD) && PhysicalPageBound < pmi->bound) PhysicalPageBound = align_up(pmi->bound + EROS_PAGE_SIZE - 1, EROS_PAGE_SIZE); } DEBUG(init) PrintStatus(); /* Allocate regions to hold the kernel and the primary mapping table: */ PmemConstraint constraint; constraint.base = KERNPAGEDIR; constraint.bound = KERNPAGEDIR + EROS_PAGE_SIZE; constraint.align = EROS_PAGE_SIZE; Alloc(constraint.bound - constraint.base, &constraint); constraint.base = KERNPBASE; constraint.bound = align_up((uint32_t) &end, EROS_PAGE_SIZE); constraint.align = EROS_PAGE_SIZE; Alloc(constraint.bound - constraint.base, &constraint);}PmemInfo *PhysMem::AddRegion(kpa_t base, kpa_t bound, uint32_t type, bool readOnly){ PmemInfo *kmi = &pmemInfo[nPmemInfo]; if (type == MI_DEVICEMEM) { /* Do not do this check for the bootup cases, as some of those * actually do overlap. */ for (unsigned int i = 0; i < nPmemInfo; i++) { if (base >= pmemInfo[i].base && base < pmemInfo[i].bound) return 0; if (bound > pmemInfo[i].base && bound <= pmemInfo[i].bound) return 0; } } assert (nPmemInfo < MAX_MEMINFO); kmi->base = base; kmi->bound = bound; kmi->type = type; kmi->nPages = 0; kmi->basepa = 0; kmi->firstObHdr = 0; kmi->readOnly = readOnly; if (type == MI_MEMORY) { kmi->allocBase = base; kmi->allocBound = bound; } else { kmi->allocBase = 0; kmi->allocBound = 0; } nPmemInfo++; return kmi;}kpsize_tPhysMem::TotalPhysicalPages(){ return PhysicalPageBound / EROS_PAGE_SIZE;}kpsize_tPhysMem::MemAvailable(PmemConstraint *mc, unsigned unitSize, bool contiguous){ unsigned nUnits = 0; for (unsigned rgn = 0; rgn < BootInfoPtr->nMemInfo; rgn++) { PmemInfo *kmi = &pmemInfo[rgn]; if (kmi->type != MI_MEMORY) continue; uint32_t base = kmi->allocBase; uint32_t bound = kmi->allocBound; base = max(base, mc->base); bound = min(bound, mc->bound); if (base >= bound) continue; /* The region (partially) overlaps the requested region */ base = align_up(base, mc->align); unsigned unitsHere = (bound - base) / unitSize; if (contiguous) { if (nUnits < unitsHere) nUnits = unitsHere; } else nUnits += unitsHere; } DEBUG(avail) { printf("%d units of %d %% %d %s bytes available\n", nUnits, unitSize, mc->align, contiguous ? "contiguous" : "total"); } return nUnits;}/* Preferentially allocate out of higher memory, because legacy DMA * controllers tend to have restricted addressable bounds in physical * memory. */static PmemInfo *preferred_region(PmemInfo *rgn1, PmemInfo *rgn2){ if (rgn1 == 0) return rgn2; if (rgn2 && rgn1->base < rgn2->base) return rgn2; return rgn1;}PmemInfo *PhysMem::ChooseRegion(kpsize_t nBytes, PmemConstraint *mc){ PmemInfo *allocTarget = 0; for (unsigned rgn = 0; rgn < BootInfoPtr->nMemInfo; rgn++) { PmemInfo *kmi = &pmemInfo[rgn]; if (kmi->type != MI_MEMORY) continue; kpa_t base = kmi->allocBase; kpa_t bound = kmi->allocBound; base = max(base, mc->base); bound = min(bound, mc->bound); if (base >= bound) continue; /* The region (partially) overlaps the requested region. See if it * has enough suitably aligned space: */ kpa_t where = bound - nBytes; where = align_down(where, mc->align); if (where >= base) allocTarget = preferred_region(allocTarget, kmi); } return allocTarget;}/* Allocate nBytes from available physical memory with constraint mc. nBytes must be a multiple of mc->align. */kpa_tPhysMem::Alloc(kpsize_t nBytes, PmemConstraint *mc){ assert(((unsigned)nBytes & (mc->align - 1)) == 0); DEBUG(alloc) printf("PhysMem::Alloc: nBytes=0x%x, " "mc->base=0x%x, mc->bound=0x%x, mc->align=0x%x\n", (unsigned)nBytes, (unsigned)mc->base, (unsigned)mc->bound, mc->align); PmemInfo *allocTarget = ChooseRegion(nBytes, mc); if (allocTarget) { /* We are willing to waste space at either the beginning or the end if necessary for alignment. */ kpa_t allocTargetBaseAligned = align_up(allocTarget->allocBase, mc->align); kpa_t allocTargetBoundAligned = align_down(allocTarget->allocBound, mc->align); /* Apply the constraint. */ kpa_t base = max(allocTargetBaseAligned, mc->base); kpa_t bound = min(allocTargetBoundAligned, mc->bound); /* We will only grab from the end or from the beginning -- not * from the middle. In fact, we will only grab from the beginning * if we absolutely have to... */ kpa_t where /* The following value is used in the "grab from end" case. We assign it here to avoid a compiler warning. */ = allocTargetBoundAligned - nBytes; if (bound == allocTargetBoundAligned) { /* grab from end */ /* where = allocTargetBoundAligned - nBytes; */ allocTarget->allocBound = where; } else if (base == allocTargetBaseAligned) { /* grab from beginning */ where = allocTargetBaseAligned; allocTarget->allocBase = where + nBytes; } else { printf("0x%x 0x%x 0x%x 0x%x\n", (unsigned)allocTarget->allocBase, (unsigned)allocTarget->allocBound, (unsigned)mc->base, (unsigned)mc->bound ); fatal("Physical memory allocator will not split memory regions\n"); } assert(where >= base); assert(where + nBytes <= bound); DEBUG(alloc) printf("Alloc %u %% %u at 0x%08x. " "Rgn 0x%08x now [0x%08x,0x%08x)\n", (uint32_t) nBytes, mc->align, (uint32_t) where, allocTarget, (unsigned) allocTarget->allocBase, (unsigned) allocTarget->allocBound); return where; } return 0;}#ifdef OPTION_DDBvoidPhysMem::ddb_dump(){ extern void db_printf(const char *fmt, ...); for (unsigned rgn = 0; rgn <nPmemInfo; rgn++) { PmemInfo *kmi = &pmemInfo[rgn]; kpa_t base = kmi->allocBase; kpa_t bound = kmi->allocBound; printf("Rgn 0x%08x ty=%d: [0x%08x,0x%08x) %u bytes unallocated\n", kmi, kmi->type, (unsigned) kmi->base, (unsigned) kmi->bound, (unsigned) bound - base); if (kmi->firstObHdr) { printf(" allocBase 0x%08x%08x allocBound 0x%08x%08x\n", (unsigned) (kmi->allocBase >> 32), (unsigned) (kmi->allocBase), (unsigned) (kmi->allocBound >> 32), (unsigned) (kmi->allocBound)); printf(" nPages 0x%08x (%d) basepa 0x%08x firstObHdr 0x%08x\n", kmi->nPages, kmi->nPages, kmi->basepa, kmi->firstObHdr); } }}#endif#define NEW_STOP falseextern void *malloc(size_t sz);void *operator new[](size_t sz, void *place){ void *v = 0; if (place == 0) v = KPAtoP(void *, PhysMem::Alloc(sz, &PhysMem::any)); else if (place == (void *) 1) v = malloc(sz); DEBUG(new) dprintf(NEW_STOP, "placement vec new grabs " "0x%x (%d) at 0x%08x\n", sz, sz, v); return v;}void *operator new(size_t sz, void * place){ void *v = 0; if (place == 0) v = KPAtoP(void *, PhysMem::Alloc(sz, &PhysMem::any)); else if (place == (void *) 1) v = malloc(sz); DEBUG(new) dprintf(NEW_STOP, "placement new grabs " "0x%x (%d) at 0x%08x\n", sz, sz, v); return v;}void *operator new(size_t sz){ fatal("Inappropriate call to non-placement operator new\n"); return KPAtoP(void *, PhysMem::Alloc(sz, &PhysMem::any));}void *operator new [](size_t sz){ fatal("Inappropriate call to non-placement operator vector new\n"); return KPAtoP(void *, PhysMem::Alloc(sz, &PhysMem::any));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -