1*ce099b40Smartin /* $NetBSD: memory.cpp,v 1.10 2008/04/28 20:23:20 martin Exp $ */
29173eae7Such
39173eae7Such /*-
47758e172Such * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
59173eae7Such * All rights reserved.
69173eae7Such *
79173eae7Such * This code is derived from software contributed to The NetBSD Foundation
89173eae7Such * by UCHIYAMA Yasushi.
99173eae7Such *
109173eae7Such * Redistribution and use in source and binary forms, with or without
119173eae7Such * modification, are permitted provided that the following conditions
129173eae7Such * are met:
139173eae7Such * 1. Redistributions of source code must retain the above copyright
149173eae7Such * notice, this list of conditions and the following disclaimer.
159173eae7Such * 2. Redistributions in binary form must reproduce the above copyright
169173eae7Such * notice, this list of conditions and the following disclaimer in the
179173eae7Such * documentation and/or other materials provided with the distribution.
189173eae7Such *
199173eae7Such * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
209173eae7Such * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
219173eae7Such * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
229173eae7Such * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
239173eae7Such * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
249173eae7Such * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
259173eae7Such * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
269173eae7Such * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
279173eae7Such * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
289173eae7Such * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
299173eae7Such * POSSIBILITY OF SUCH DAMAGE.
309173eae7Such */
319173eae7Such
329173eae7Such #include <memory.h>
339173eae7Such #include <console.h>
349173eae7Such
MemoryManager(Console * & cons,size_t pagesize)359173eae7Such MemoryManager::MemoryManager(Console *&cons, size_t pagesize)
369173eae7Such : _cons(cons)
379173eae7Such {
389173eae7Such _debug = FALSE;
399173eae7Such _page_size = pagesize;
409173eae7Such
419173eae7Such int mask = _page_size;
429173eae7Such for (_page_shift = 0; !(mask & 1); _page_shift++)
439173eae7Such mask >>= 1;
449173eae7Such
459173eae7Such _page_per_region = WCE_REGION_SIZE / _page_size;
469173eae7Such _nbank = 0;
479173eae7Such _addr_table_idx = 0;
489173eae7Such _addr_table = 0;
499173eae7Such _memory = 0;
509173eae7Such }
519173eae7Such
~MemoryManager(void)529173eae7Such MemoryManager::~MemoryManager(void)
539173eae7Such {
549173eae7Such if (_memory)
559173eae7Such VirtualFree(LPVOID(_memory), 0, MEM_RELEASE);
569173eae7Such }
579173eae7Such
589173eae7Such void
loadBank(paddr_t paddr,psize_t psize)599173eae7Such MemoryManager::loadBank(paddr_t paddr, psize_t psize)
609173eae7Such {
619173eae7Such struct MemoryManager::bank *b = &_bank[_nbank++];
629173eae7Such b->addr = paddr;
639173eae7Such b->size = psize;
647758e172Such DPRINTF((TEXT("[%d] 0x%08x size 0x%08x\n"), _nbank - 1,
659173eae7Such b->addr, b->size));
669173eae7Such }
679173eae7Such
689173eae7Such BOOL
reservePage(vsize_t size,BOOL page_commit)699173eae7Such MemoryManager::reservePage(vsize_t size, BOOL page_commit)
709173eae7Such {
719173eae7Such // My virtual memory space
729173eae7Such vaddr_t vbase;
739173eae7Such vsize_t vsize;
749173eae7Such
759173eae7Such int i, npage;
769173eae7Such
779173eae7Such if (size == 0)
789173eae7Such return FALSE;
799173eae7Such
809173eae7Such // reserve all virtual memory.
819173eae7Such vsize = roundRegion(size);
829173eae7Such npage = roundPage(size) / _page_size;
839173eae7Such
849173eae7Such size_t tabsz = sizeof(struct AddressTranslationTable) * npage;
859173eae7Such _addr_table = static_cast <struct AddressTranslationTable *>
869173eae7Such (malloc(tabsz));
879173eae7Such if (_addr_table == NULL) {
889173eae7Such DPRINTF((TEXT("can't allocate memory for translation table.\n")));
899173eae7Such return FALSE;
909173eae7Such }
91ef2734fbSuwe DPRINTF((TEXT("address translation table %d pages. (0x%x bytes)\n"),
92ef2734fbSuwe npage, tabsz));
939173eae7Such
949173eae7Such if (page_commit)
959173eae7Such vbase = vaddr_t(VirtualAlloc(0, vsize, MEM_RESERVE,
969173eae7Such PAGE_NOACCESS));
979173eae7Such else
989173eae7Such vbase = vaddr_t(VirtualAlloc(0, vsize, MEM_COMMIT,
999173eae7Such PAGE_READWRITE | PAGE_NOCACHE));
1009173eae7Such
1019173eae7Such if (vbase == 0) {
1029173eae7Such DPRINTF((TEXT("can't allocate memory\n")));
1039173eae7Such return FALSE;
1049173eae7Such }
1059173eae7Such _memory = vbase;
1069173eae7Such
1079173eae7Such // find physical address of allocated page.
1089173eae7Such AddressTranslationTable *tab = _addr_table;
1099173eae7Such _naddr_table = 0;
1109173eae7Such for (i = 0; i < npage; i++) {
1119173eae7Such vaddr_t vaddr;
1129173eae7Such paddr_t paddr = ~0;
1139173eae7Such
1149173eae7Such if (page_commit)
1159173eae7Such // now map to physical page.
1169173eae7Such vaddr = vaddr_t(VirtualAlloc(
1179173eae7Such LPVOID(vbase + _page_size * i),
1189173eae7Such _page_size, MEM_COMMIT,
1199173eae7Such PAGE_READWRITE | PAGE_NOCACHE));
1209173eae7Such else
1219173eae7Such vaddr = vbase + _page_size * i;
1229173eae7Such
1239173eae7Such paddr = searchPage(vaddr);
1249173eae7Such
1259173eae7Such if (paddr == ~0) {
1269173eae7Such DPRINTF((TEXT("page#%d not found\n"), i));
1279173eae7Such break;
1289173eae7Such } else {
1299173eae7Such #ifdef MEMORY_MAP_DEBUG
1309173eae7Such DPRINTF((TEXT("page %d vaddr=0x%08x paddr=0x%08x\n"),
1319173eae7Such _naddr_table, vaddr, paddr));
1329173eae7Such #endif
1339173eae7Such tab->vaddr = vaddr;
1349173eae7Such tab->paddr = paddr;
1359173eae7Such ++tab;
1369173eae7Such ++_naddr_table;
1379173eae7Such }
1389173eae7Such }
1399173eae7Such
1409173eae7Such #ifdef MEMORY_MAP_DEBUG
1419173eae7Such // dump virtual <-> physical address table
1429173eae7Such tab = _addr_table;
1439173eae7Such for (i = 0; i < _naddr_table;) {
1449173eae7Such for (int j = 0; j < 4; j++, i++, tab++)
1459173eae7Such DPRINTF((TEXT("%08x=%08x "), tab->vaddr, tab->paddr));
1469173eae7Such DPRINTF((TEXT("\n")));
1479173eae7Such }
1489173eae7Such #endif
1499173eae7Such DPRINTF((TEXT("allocated %d page. mapped %d page.\n"), npage,
1509173eae7Such _naddr_table));
1519173eae7Such
1529173eae7Such return TRUE;
1539173eae7Such }
1549173eae7Such
1559173eae7Such BOOL
getPage(vaddr_t & vaddr,paddr_t & paddr)1569173eae7Such MemoryManager::getPage(vaddr_t &vaddr, paddr_t &paddr)
1579173eae7Such {
1589173eae7Such /* get plain page from the top */
159422ad476Senami if (_addr_table_idx >= _naddr_table ||
160422ad476Senami _addr_table == NULL)
1619173eae7Such return FALSE;
1629173eae7Such
163422ad476Senami int idx = --_naddr_table;
164422ad476Senami
1659173eae7Such AddressTranslationTable *tab = &_addr_table[idx];
1669173eae7Such vaddr = tab->vaddr;
1679173eae7Such paddr = tab->paddr;
1689173eae7Such
1699173eae7Such return TRUE;
1709173eae7Such }
1719173eae7Such
1729173eae7Such BOOL
getTaggedPage(vaddr_t & vaddr,paddr_t & paddr)1739173eae7Such MemoryManager::getTaggedPage(vaddr_t &vaddr, paddr_t &paddr)
1749173eae7Such {
1759173eae7Such /* get tagged page from the bottom */
1769173eae7Such if (_addr_table_idx >= _naddr_table ||
1779173eae7Such _addr_table == NULL) {
1789173eae7Such DPRINTF((TEXT("page insufficient.\n")));
1799173eae7Such return FALSE;
1809173eae7Such }
1819173eae7Such AddressTranslationTable *tab =
1829173eae7Such &_addr_table[_addr_table_idx++];
1839173eae7Such vaddr = tab->vaddr;
1849173eae7Such paddr = tab->paddr;
1859173eae7Such
1869173eae7Such return TRUE;
1879173eae7Such }
1889173eae7Such
1899173eae7Such BOOL
getTaggedPage(vaddr_t & v,paddr_t & p,struct PageTag ** pvec,paddr_t & pvec_paddr)1909173eae7Such MemoryManager::getTaggedPage(vaddr_t &v, paddr_t &p,
1919173eae7Such struct PageTag **pvec, paddr_t &pvec_paddr)
1929173eae7Such {
1939173eae7Such if (!getTaggedPage(v, p))
1949173eae7Such return FALSE;
1959173eae7Such
1969173eae7Such *pvec =(struct PageTag *)v;
1979173eae7Such memset(*pvec, 0, sizeof(struct PageTag));
1989173eae7Such v += sizeof(struct PageTag);
1999173eae7Such pvec_paddr = p;
2009173eae7Such p += sizeof(struct PageTag);
2019173eae7Such
2029173eae7Such return TRUE;
2039173eae7Such }
2049173eae7Such
2059173eae7Such vaddr_t
mapPhysicalPage(paddr_t paddr,psize_t size,uint32_t flags)20624c8a902Suwe MemoryManager::mapPhysicalPage(paddr_t paddr, psize_t size, uint32_t flags)
2079173eae7Such {
2089173eae7Such paddr_t pstart = truncPage(paddr);
2099173eae7Such paddr_t pend = roundPage(paddr + size);
2109173eae7Such psize_t psize = pend - pstart;
2119173eae7Such
2129173eae7Such LPVOID p = VirtualAlloc(0, psize, MEM_RESERVE, PAGE_NOACCESS);
2139173eae7Such
2149173eae7Such int ok = VirtualCopy(p, LPVOID(pstart >> 8), psize,
2159173eae7Such flags | PAGE_NOCACHE | PAGE_PHYSICAL);
2169173eae7Such if (!ok) {
2179173eae7Such DPRINTF((TEXT("can't map physical address 0x%08x\n"), paddr));
2189173eae7Such return ~0;
2199173eae7Such }
2209173eae7Such #if 0
2219173eae7Such DPRINTF((TEXT("start=0x%08x end=0x%08x size=0x%08x return=0x%08x\n"),
2229173eae7Such pstart, pend, psize, vaddr_t(p) + vaddr_t(paddr - pstart)));
2239173eae7Such #endif
2249173eae7Such return vaddr_t(p) + vaddr_t(paddr - pstart);
2259173eae7Such }
2269173eae7Such
2279173eae7Such void
unmapPhysicalPage(vaddr_t vaddr)2289173eae7Such MemoryManager::unmapPhysicalPage(vaddr_t vaddr)
2299173eae7Such {
2309173eae7Such int ok = VirtualFree(LPVOID(truncPage(vaddr)), 0, MEM_RELEASE);
2319173eae7Such if (!ok)
2329173eae7Such DPRINTF((TEXT("can't release memory\n")));
2339173eae7Such }
2349173eae7Such
23524c8a902Suwe uint32_t
readPhysical4(paddr_t paddr)2369173eae7Such MemoryManager::readPhysical4(paddr_t paddr)
2379173eae7Such {
2389173eae7Such vaddr_t v = mapPhysicalPage(paddr, 4, PAGE_READONLY);
23924c8a902Suwe uint32_t val = *(uint32_t *)v;
2409173eae7Such unmapPhysicalPage(v);
2419173eae7Such return val;
2429173eae7Such }
2439173eae7Such
2449173eae7Such //
2459173eae7Such // Use LockPages()
2469173eae7Such //
MemoryManager_LockPages(BOOL (* lock_pages)(LPVOID,DWORD,PDWORD,int),BOOL (* unlock_pages)(LPVOID,DWORD),Console * & cons,size_t pagesize,int shift)2479173eae7Such MemoryManager_LockPages::MemoryManager_LockPages
2489173eae7Such (BOOL(*lock_pages)(LPVOID, DWORD, PDWORD, int),
2499173eae7Such BOOL(*unlock_pages)(LPVOID, DWORD),
2509173eae7Such Console *&cons, size_t pagesize, int shift)
2519173eae7Such : MemoryManager(cons, pagesize)
2529173eae7Such {
2539173eae7Such _lock_pages = lock_pages;
2549173eae7Such _unlock_pages = unlock_pages;
2559173eae7Such _shift = shift;
2567758e172Such DPRINTF((TEXT("MemoryManager: LockPages\n")));
2579173eae7Such }
2589173eae7Such
~MemoryManager_LockPages(void)2599173eae7Such MemoryManager_LockPages::~MemoryManager_LockPages(void)
2609173eae7Such {
2619173eae7Such }
2629173eae7Such
2639173eae7Such paddr_t
searchPage(vaddr_t vaddr)2649173eae7Such MemoryManager_LockPages::searchPage(vaddr_t vaddr)
2659173eae7Such {
2669173eae7Such paddr_t paddr = ~0;
2679173eae7Such
2689173eae7Such if (!_lock_pages(LPVOID(vaddr), _page_size, PDWORD(&paddr), 1))
2699173eae7Such return paddr;
2709173eae7Such
2719173eae7Such if (!_unlock_pages(LPVOID(vaddr), _page_size)) {
2729173eae7Such DPRINTF((TEXT("can't unlock pages\n")));
2739173eae7Such }
2749173eae7Such
2759173eae7Such return(paddr >>(_page_shift - _shift)) << _page_shift;
2769173eae7Such }
2779173eae7Such
2789173eae7Such //
2799173eae7Such // Use VirtualCopy()
2809173eae7Such //
MemoryManager_VirtualCopy(Console * & cons,size_t pagesize)2819173eae7Such MemoryManager_VirtualCopy::MemoryManager_VirtualCopy(Console *&cons,
2829173eae7Such size_t pagesize)
2839173eae7Such : MemoryManager(cons, pagesize)
2849173eae7Such {
285e78f561eSuch _search_guess = 0;
2867758e172Such DPRINTF((TEXT("MemoryManager: VirtualCopy\n")));
2879173eae7Such }
2889173eae7Such
~MemoryManager_VirtualCopy(void)2899173eae7Such MemoryManager_VirtualCopy::~MemoryManager_VirtualCopy(void)
2909173eae7Such {
2919173eae7Such }
2929173eae7Such
2939173eae7Such paddr_t
searchPage(vaddr_t vaddr)2949173eae7Such MemoryManager_VirtualCopy::searchPage(vaddr_t vaddr)
2959173eae7Such {
2969173eae7Such paddr_t paddr = ~0;
2979173eae7Such int i;
2989173eae7Such
2999173eae7Such // search all D-RAM bank.
3009173eae7Such setMagic(vaddr);
301e78f561eSuch retry:
3029173eae7Such for (i = 0; i < _nbank; i++) {
3039173eae7Such paddr = searchBank(i);
3049173eae7Such if (paddr != ~0)
3059173eae7Such break;
3069173eae7Such }
307e78f561eSuch if (_search_guess != 0 && paddr == ~0) {
308e78f561eSuch _search_guess = 0;
309e78f561eSuch goto retry;
310e78f561eSuch }
311e78f561eSuch
3129173eae7Such clearMagic();
3139173eae7Such
3149173eae7Such return paddr;
3159173eae7Such }
3169173eae7Such
3179173eae7Such paddr_t
searchBank(int banknum)3189173eae7Such MemoryManager_VirtualCopy::searchBank(int banknum)
3199173eae7Such {
3209173eae7Such LPVOID ref;
3219173eae7Such paddr_t paddr, pstart, pend, pfound = ~0;
322e78f561eSuch paddr_t bstart, bend;
3239173eae7Such vaddr_t ofs;
3249173eae7Such
325e78f561eSuch bstart = _bank[banknum].addr;
326e78f561eSuch bend = _bank[banknum].addr + _bank[banknum].size;
327e78f561eSuch
328e78f561eSuch pstart = _search_guess ? _search_guess : bstart;
329e78f561eSuch pend = bend;
330e78f561eSuch
331e78f561eSuch if (pstart < bstart || pstart >= pend)
332e78f561eSuch return pfound;
3339173eae7Such
3349173eae7Such // reserve physical reference region
3359173eae7Such ref = VirtualAlloc(0, BLOCK_SIZE, MEM_RESERVE, PAGE_NOACCESS);
3369173eae7Such if (ref == 0) {
3379173eae7Such DPRINTF((TEXT("can't allocate virtual memory.\n")));
3389173eae7Such return pfound;
3399173eae7Such }
3409173eae7Such
3419173eae7Such for (paddr = pstart; paddr < pend; paddr += BLOCK_SIZE) {
3429173eae7Such if (!VirtualCopy(ref, LPVOID(paddr >> 8), BLOCK_SIZE,
343fae3e8e7Such PAGE_READONLY | PAGE_NOCACHE | PAGE_PHYSICAL)) {
3449173eae7Such DPRINTF((TEXT("can't map physical addr 0x%08x(->0x%08x)\n"),
3459173eae7Such ref, paddr));
3469173eae7Such goto release;
3479173eae7Such }
3489173eae7Such
3499173eae7Such // search magic in this region.
3509173eae7Such ofs = checkMagicRegion(vaddr_t(ref), BLOCK_SIZE, _page_size);
3519173eae7Such
3529173eae7Such // decommit reference region.
3539173eae7Such if (!VirtualFree(ref, BLOCK_SIZE, MEM_DECOMMIT)) {
3549173eae7Such DPRINTF((TEXT("can't decommit addr 0x%08x(->0x%08x)\n"),
3559173eae7Such ref, paddr));
3569173eae7Such goto release;
3579173eae7Such }
3589173eae7Such
3599173eae7Such if (ofs != ~0) {
3609173eae7Such pfound = paddr + ofs;
361e78f561eSuch _search_guess = paddr;
3629173eae7Such break;
3639173eae7Such }
3649173eae7Such }
3659173eae7Such release:
3669173eae7Such if (!VirtualFree(ref, 0, MEM_RELEASE))
3679173eae7Such DPRINTF((TEXT("can't release memory\n")));
3689173eae7Such
3699173eae7Such return pfound;
3709173eae7Such }
371