1 /* $NetBSD: memory.cpp,v 1.9 2006/03/05 04:05:39 uwe Exp $ */
4 * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
35 MemoryManager::MemoryManager(Console
*&cons
, size_t pagesize
)
39 _page_size
= pagesize
;
41 int mask
= _page_size
;
42 for (_page_shift
= 0; !(mask
& 1); _page_shift
++)
45 _page_per_region
= WCE_REGION_SIZE
/ _page_size
;
52 MemoryManager::~MemoryManager(void)
55 VirtualFree(LPVOID(_memory
), 0, MEM_RELEASE
);
59 MemoryManager::loadBank(paddr_t paddr
, psize_t psize
)
61 struct MemoryManager::bank
*b
= &_bank
[_nbank
++];
64 DPRINTF((TEXT("[%d] 0x%08x size 0x%08x\n"), _nbank
- 1,
69 MemoryManager::reservePage(vsize_t size
, BOOL page_commit
)
71 // My virtual memory space
80 // reserve all virtual memory.
81 vsize
= roundRegion(size
);
82 npage
= roundPage(size
) / _page_size
;
84 size_t tabsz
= sizeof(struct AddressTranslationTable
) * npage
;
85 _addr_table
= static_cast <struct AddressTranslationTable
*>
87 if (_addr_table
== NULL
) {
88 DPRINTF((TEXT("can't allocate memory for translation table.\n")));
91 DPRINTF((TEXT("address translation table %d pages. (0x%x bytes)\n"),
95 vbase
= vaddr_t(VirtualAlloc(0, vsize
, MEM_RESERVE
,
98 vbase
= vaddr_t(VirtualAlloc(0, vsize
, MEM_COMMIT
,
99 PAGE_READWRITE
| PAGE_NOCACHE
));
102 DPRINTF((TEXT("can't allocate memory\n")));
107 // find physical address of allocated page.
108 AddressTranslationTable
*tab
= _addr_table
;
110 for (i
= 0; i
< npage
; i
++) {
115 // now map to physical page.
116 vaddr
= vaddr_t(VirtualAlloc(
117 LPVOID(vbase
+ _page_size
* i
),
118 _page_size
, MEM_COMMIT
,
119 PAGE_READWRITE
| PAGE_NOCACHE
));
121 vaddr
= vbase
+ _page_size
* i
;
123 paddr
= searchPage(vaddr
);
126 DPRINTF((TEXT("page#%d not found\n"), i
));
129 #ifdef MEMORY_MAP_DEBUG
130 DPRINTF((TEXT("page %d vaddr=0x%08x paddr=0x%08x\n"),
131 _naddr_table
, vaddr
, paddr
));
140 #ifdef MEMORY_MAP_DEBUG
141 // dump virtual <-> physical address table
143 for (i
= 0; i
< _naddr_table
;) {
144 for (int j
= 0; j
< 4; j
++, i
++, tab
++)
145 DPRINTF((TEXT("%08x=%08x "), tab
->vaddr
, tab
->paddr
));
146 DPRINTF((TEXT("\n")));
149 DPRINTF((TEXT("allocated %d page. mapped %d page.\n"), npage
,
156 MemoryManager::getPage(vaddr_t
&vaddr
, paddr_t
&paddr
)
158 /* get plain page from the top */
159 if (_addr_table_idx
>= _naddr_table
||
163 int idx
= --_naddr_table
;
165 AddressTranslationTable
*tab
= &_addr_table
[idx
];
173 MemoryManager::getTaggedPage(vaddr_t
&vaddr
, paddr_t
&paddr
)
175 /* get tagged page from the bottom */
176 if (_addr_table_idx
>= _naddr_table
||
177 _addr_table
== NULL
) {
178 DPRINTF((TEXT("page insufficient.\n")));
181 AddressTranslationTable
*tab
=
182 &_addr_table
[_addr_table_idx
++];
190 MemoryManager::getTaggedPage(vaddr_t
&v
, paddr_t
&p
,
191 struct PageTag
**pvec
, paddr_t
&pvec_paddr
)
193 if (!getTaggedPage(v
, p
))
196 *pvec
=(struct PageTag
*)v
;
197 memset(*pvec
, 0, sizeof(struct PageTag
));
198 v
+= sizeof(struct PageTag
);
200 p
+= sizeof(struct PageTag
);
206 MemoryManager::mapPhysicalPage(paddr_t paddr
, psize_t size
, uint32_t flags
)
208 paddr_t pstart
= truncPage(paddr
);
209 paddr_t pend
= roundPage(paddr
+ size
);
210 psize_t psize
= pend
- pstart
;
212 LPVOID p
= VirtualAlloc(0, psize
, MEM_RESERVE
, PAGE_NOACCESS
);
214 int ok
= VirtualCopy(p
, LPVOID(pstart
>> 8), psize
,
215 flags
| PAGE_NOCACHE
| PAGE_PHYSICAL
);
217 DPRINTF((TEXT("can't map physical address 0x%08x\n"), paddr
));
221 DPRINTF((TEXT("start=0x%08x end=0x%08x size=0x%08x return=0x%08x\n"),
222 pstart
, pend
, psize
, vaddr_t(p
) + vaddr_t(paddr
- pstart
)));
224 return vaddr_t(p
) + vaddr_t(paddr
- pstart
);
228 MemoryManager::unmapPhysicalPage(vaddr_t vaddr
)
230 int ok
= VirtualFree(LPVOID(truncPage(vaddr
)), 0, MEM_RELEASE
);
232 DPRINTF((TEXT("can't release memory\n")));
236 MemoryManager::readPhysical4(paddr_t paddr
)
238 vaddr_t v
= mapPhysicalPage(paddr
, 4, PAGE_READONLY
);
239 uint32_t val
= *(uint32_t *)v
;
240 unmapPhysicalPage(v
);
247 MemoryManager_LockPages::MemoryManager_LockPages
248 (BOOL(*lock_pages
)(LPVOID
, DWORD
, PDWORD
, int),
249 BOOL(*unlock_pages
)(LPVOID
, DWORD
),
250 Console
*&cons
, size_t pagesize
, int shift
)
251 : MemoryManager(cons
, pagesize
)
253 _lock_pages
= lock_pages
;
254 _unlock_pages
= unlock_pages
;
256 DPRINTF((TEXT("MemoryManager: LockPages\n")));
259 MemoryManager_LockPages::~MemoryManager_LockPages(void)
264 MemoryManager_LockPages::searchPage(vaddr_t vaddr
)
268 if (!_lock_pages(LPVOID(vaddr
), _page_size
, PDWORD(&paddr
), 1))
271 if (!_unlock_pages(LPVOID(vaddr
), _page_size
)) {
272 DPRINTF((TEXT("can't unlock pages\n")));
275 return(paddr
>>(_page_shift
- _shift
)) << _page_shift
;
281 MemoryManager_VirtualCopy::MemoryManager_VirtualCopy(Console
*&cons
,
283 : MemoryManager(cons
, pagesize
)
286 DPRINTF((TEXT("MemoryManager: VirtualCopy\n")));
289 MemoryManager_VirtualCopy::~MemoryManager_VirtualCopy(void)
294 MemoryManager_VirtualCopy::searchPage(vaddr_t vaddr
)
299 // search all D-RAM bank.
302 for (i
= 0; i
< _nbank
; i
++) {
303 paddr
= searchBank(i
);
307 if (_search_guess
!= 0 && paddr
== ~0) {
318 MemoryManager_VirtualCopy::searchBank(int banknum
)
321 paddr_t paddr
, pstart
, pend
, pfound
= ~0;
322 paddr_t bstart
, bend
;
325 bstart
= _bank
[banknum
].addr
;
326 bend
= _bank
[banknum
].addr
+ _bank
[banknum
].size
;
328 pstart
= _search_guess
? _search_guess
: bstart
;
331 if (pstart
< bstart
|| pstart
>= pend
)
334 // reserve physical reference region
335 ref
= VirtualAlloc(0, BLOCK_SIZE
, MEM_RESERVE
, PAGE_NOACCESS
);
337 DPRINTF((TEXT("can't allocate virtual memory.\n")));
341 for (paddr
= pstart
; paddr
< pend
; paddr
+= BLOCK_SIZE
) {
342 if (!VirtualCopy(ref
, LPVOID(paddr
>> 8), BLOCK_SIZE
,
343 PAGE_READONLY
| PAGE_NOCACHE
| PAGE_PHYSICAL
)) {
344 DPRINTF((TEXT("can't map physical addr 0x%08x(->0x%08x)\n"),
349 // search magic in this region.
350 ofs
= checkMagicRegion(vaddr_t(ref
), BLOCK_SIZE
, _page_size
);
352 // decommit reference region.
353 if (!VirtualFree(ref
, BLOCK_SIZE
, MEM_DECOMMIT
)) {
354 DPRINTF((TEXT("can't decommit addr 0x%08x(->0x%08x)\n"),
360 pfound
= paddr
+ ofs
;
361 _search_guess
= paddr
;
366 if (!VirtualFree(ref
, 0, MEM_RELEASE
))
367 DPRINTF((TEXT("can't release memory\n")));