xref: /netbsd-src/sys/arch/hpc/stand/hpcboot/memory.cpp (revision ce099b40997c43048fb78bd578195f81d2456523)
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