/[pearpc]/src/io/prom/prommem.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /src/io/prom/prommem.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 7 months ago) by dpavlin
File size: 8608 byte(s)
import upstream CVS
1 /*
2 * PearPC
3 * prommem.cc
4 *
5 * Copyright (C) 2003 Sebastian Biallas (sb@biallas.net)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include <cstdlib>
22 #include <cstring>
23
24 #include "tools/snprintf.h"
25 #include "debug/tracers.h"
26 #include "cpu/mem.h"
27 #include "prom.h"
28 #include "promosi.h"
29 #include "prommem.h"
30
31 /*char *prom_ea_string(uint32 ea)
32 {
33 byte *r;
34 if (ppc_direct_effective_memory_handle(ea, r)) {
35 IO_PROM_ERR("nciht gut\n");
36 return NULL;
37 }
38 return (char*)r;
39 }*/
40
41 bool prom_get_string(String &result, uint32 ea)
42 {
43 uint32 pa;
44 result = "";
45 if (!ppc_prom_effective_to_physical(pa, ea)) {
46 IO_PROM_ERR("can't translate address in %s\n", __FUNCTION__);
47 return false;
48 }
49 while (1) {
50 byte mem[128];
51 if (!ppc_dma_read(mem, pa, sizeof mem)) {
52 IO_PROM_ERR("read memory in %s\n", __FUNCTION__);
53 return false;
54 }
55 byte *end;
56 if ((end = (byte *)memchr(mem, 0, sizeof mem))) {
57 if (end != mem) {
58 String s(mem, end-mem);
59 result += s;
60 }
61 return true;
62 } else {
63 String s(mem, sizeof mem);
64 result += s;
65 }
66 pa += sizeof mem;
67 }
68 }
69
70 static byte *gPhysMemoryUsed;
71 static int gPhysMemoryLastpage;
72
73 static int gPromMemStart, gPromMemEnd;
74
75 struct malloc_entry {
76 uint32 prev PACKED;
77 uint32 size PACKED;
78 };
79
80 #define MALLOC_BLOCK_FREE (1<<31)
81 #define MALLOC_BLOCK_GUARD (1)
82
83 static uint32 gPromMemFreeBlock;
84 static uint32 gPromMemLastBlock;
85
86 bool prom_claim_page(uint32 phys)
87 {
88 uint32 page = phys / 4096;
89 if (gPhysMemoryUsed[page / 8] & (1<<(page&0x7))) {
90 IO_PROM_WARN("%08x in use!\n", phys);
91 return false;
92 }
93 gPhysMemoryUsed[page / 8] |= (1<<(page&0x7));
94 return true;
95 }
96
97 bool prom_claim_pages(uint32 phys, uint32 size)
98 {
99 sint32 s=size;
100 while (s > 0) {
101 if (!prom_claim_page(phys)) return false;
102 phys += 4096;
103 s -= 4096;
104 }
105 return true;
106 }
107
108 extern uint32 gMemorySize; // GRRR
109
110 uint32 prom_get_free_page()
111 {
112 int s = gMemorySize/4096/8+1;
113 for (int i=gPhysMemoryLastpage; i<s; i++) {
114 if (gPhysMemoryUsed[i]!=0xff) {
115 int x=1;
116 for (int j=0; j<8; j++) {
117 if (!(gPhysMemoryUsed[i] & x)) {
118 uint32 pa = (i*8+j)*4096;
119 prom_claim_page(pa);
120 gPhysMemoryLastpage = i;
121 return pa;
122 }
123 x<<=1;
124 }
125 }
126 }
127 return 0;
128 }
129
130 uint32 prom_allocate_virt(uint32 size, uint32 align)
131 {
132 return 0;
133 }
134
135 uint32 prom_allocate_mem(uint32 size, uint32 align, uint32 virt)
136 {
137 uint32 ret;
138 if (virt == 0) {
139 ret = prom_mem_malloc(size+align-1);
140 if (ret % align) {
141 ret += align - (ret % align);
142 }
143 } else {
144 int pages = (size / 4096) + ((size % 4096)?1:0);
145 ret = virt;
146 for (int i=0; i<pages; i++) {
147 // test if phys==virtual mapping possible
148 if ((virt >= gMemorySize) ||
149 (gPhysMemoryUsed[virt/4096/8] & (1 << ((virt/4096) & 7)))) {
150 uint32 pa = prom_get_free_page();
151 if (!pa) return (uint32) -1;
152 ppc_prom_page_create(virt, pa);
153 } else {
154 prom_claim_page(virt);
155 ppc_prom_page_create(virt, virt);
156 }
157 virt+=4096;
158 }
159 }
160 return ret;
161 }
162
163 bool prom_free_mem(uint32 virt)
164 {
165 return false;
166 }
167
168 void prom_mem_set(uint32 pa, int c, int size)
169 {
170 if (!ppc_dma_set(pa, c, size)) {
171 IO_PROM_ERR("in mem_set\n");
172 }
173 }
174
175
176 static uint32 prom_mem_entry_get_size(uint32 pa)
177 {
178 uint32 r;
179 ppc_dma_read(&r, pa, 4);
180 return r;
181 }
182
183 static uint32 prom_mem_entry_get_prev(uint32 pa)
184 {
185 uint32 r;
186 ppc_dma_read(&r, pa+4, 4);
187 return r;
188 }
189
190 static void prom_mem_entry_set_size(uint32 pa, uint32 v)
191 {
192 ppc_dma_write(pa, &v, 4);
193 }
194
195 static void prom_mem_entry_set_prev(uint32 pa, uint32 v)
196 {
197 ppc_dma_write(pa+4, &v, 4);
198 }
199
200 uint32 prom_mem_malloc(uint32 size)
201 {
202 if (!size) {
203 IO_PROM_ERR("zero byte allocation!\n");
204 }
205 size = (size+7) & ~7;
206 size += sizeof(malloc_entry);
207
208 // ht_printf(" --> %d\n", size);
209
210 int i=0;
211 bool ok=false;
212 uint32 r = 0;
213 while (!ok) {
214 uint32 s = prom_mem_entry_get_size(gPromMemFreeBlock) & ~MALLOC_BLOCK_FREE;
215 // ht_printf("s: %08x\n", s);
216 if (s > size) {
217 // found block
218 uint32 blockp = gPromMemFreeBlock + s - size;
219 // ht_printf("blockp: %08x\n", blockp);
220
221 uint32 block = blockp;
222 uint32 next = gPromMemFreeBlock+s;
223
224 prom_mem_entry_set_size(gPromMemFreeBlock, (s - size) | MALLOC_BLOCK_FREE);
225 prom_mem_entry_set_prev(next, blockp);
226 prom_mem_entry_set_prev(blockp, gPromMemFreeBlock);
227 prom_mem_entry_set_size(blockp, size);
228
229 // ht_printf("malloced at %x\n", blockp+sizeof(malloc_entry));
230 return blockp+sizeof(malloc_entry);
231 }
232 if (s == size) {
233 // exact match
234 prom_mem_entry_set_size(gPromMemFreeBlock, s);
235 r = gPromMemFreeBlock + sizeof(malloc_entry);
236 ok = true;
237 }
238 do {
239 gPromMemFreeBlock = prom_mem_entry_get_prev(gPromMemFreeBlock);
240 if (prom_mem_entry_get_size(gPromMemFreeBlock) & MALLOC_BLOCK_GUARD) {
241 if (i) {
242 IO_PROM_ERR("out of memory!\n");
243 }
244 i++;
245 gPromMemFreeBlock = prom_mem_entry_get_prev(gPromMemLastBlock);
246 }
247 } while (!(prom_mem_entry_get_size(gPromMemFreeBlock) & MALLOC_BLOCK_FREE));
248 }
249 return r;
250 }
251
252 void prom_mem_free(uint32 p)
253 {
254 uint32 block = p - sizeof(malloc_entry);
255 if (prom_mem_entry_get_size(block) & MALLOC_BLOCK_FREE) {
256 IO_PROM_ERR("attempt to free unused block!\n");
257 }
258 if (prom_mem_entry_get_size(block) & MALLOC_BLOCK_GUARD) {
259 IO_PROM_ERR("attempt to free guard block!\n");
260 }
261 uint32 prev = prom_mem_entry_get_prev(block);
262 uint32 next = block + prom_mem_entry_get_size(block);
263 if ((prom_mem_entry_get_size(next) & MALLOC_BLOCK_FREE) && !(prom_mem_entry_get_size(next) & MALLOC_BLOCK_GUARD)) {
264 // merge with upper block
265 uint32 nnext = block + prom_mem_entry_get_size(block) + (prom_mem_entry_get_size(next) & ~MALLOC_BLOCK_FREE);
266 prom_mem_entry_set_prev(nnext, block);
267 prom_mem_entry_set_size(block, prom_mem_entry_get_size(next) & ~MALLOC_BLOCK_FREE);
268 }
269 if ((prom_mem_entry_get_size(prev) & MALLOC_BLOCK_FREE) && !(prom_mem_entry_get_size(prev) & MALLOC_BLOCK_GUARD)) {
270 // merge with lower block
271 prom_mem_entry_set_size(prev, prom_mem_entry_get_size(prev) + prom_mem_entry_get_size(block));
272 prom_mem_entry_set_prev(next, prom_mem_entry_get_prev(block));
273 gPromMemFreeBlock = prev;
274 } else {
275 prom_mem_entry_set_size(block, prom_mem_entry_get_size(block) | MALLOC_BLOCK_FREE);
276 gPromMemFreeBlock = block;
277 }
278 }
279
280 uint32 prom_mem_virt_to_phys(uint32 v)
281 {
282 return v+PROM_MEM_SIZE+gPromMemStart;
283 }
284
285 uint32 prom_mem_phys_to_virt(uint32 p)
286 {
287 return p-gPromMemStart+(0-PROM_MEM_SIZE);
288 }
289
290 bool prom_mem_init()
291 {
292 gPhysMemoryUsed = new byte[gMemorySize / 4096 / 8+1];
293 memset(gPhysMemoryUsed, 0, gMemorySize / 4096 / 8+1);
294 gPhysMemoryLastpage = 1;
295
296 /*
297 * The Prom-Memory (where the device-tree etc. resides) will be at the
298 * end of the physical and virtual memory
299 */
300
301 gPromMemStart = gMemorySize - PROM_MEM_SIZE;
302 gPromMemEnd = gMemorySize;
303 uint32 v = 0-PROM_MEM_SIZE;
304 // Allocate the physical pages
305 for (int i=gPromMemStart; i<gPromMemEnd; i+=4096) {
306 prom_claim_page(i);
307 ppc_prom_page_create(v, i);
308 v+=4096;
309 }
310
311 // ht_printf("gPromMemStart: %x\ngPromMemEnd: %x\n", gPromMemStart, gPromMemEnd);
312
313 uint32 start = gPromMemStart;
314 uint32 end = gPromMemEnd - sizeof(malloc_entry);
315 uint32 mem = gPromMemStart + sizeof(malloc_entry);
316
317 prom_mem_entry_set_size(start, sizeof(malloc_entry) | MALLOC_BLOCK_GUARD);
318 prom_mem_entry_set_size(mem, (PROM_MEM_SIZE-2*sizeof(malloc_entry)) | MALLOC_BLOCK_FREE);
319 prom_mem_entry_set_size(end, sizeof(malloc_entry) | MALLOC_BLOCK_GUARD);
320
321 prom_mem_entry_set_prev(start, gPromMemEnd-sizeof(malloc_entry));
322 prom_mem_entry_set_prev(end, gPromMemStart+sizeof(malloc_entry));
323 prom_mem_entry_set_prev(mem, gPromMemStart);
324
325 gPromMemLastBlock = end;
326 gPromMemFreeBlock = mem;
327
328 /*
329 * malloc works now
330 */
331
332 #define DW(w) (w)>>24, (w)>>16, (w)>>8, (w)>>0,
333 uint8 magic_opcode[] = {
334 DW(PROM_MAGIC_OPCODE)
335 DW(0x4e800020) // blr
336 };
337 gPromOSIEntry = prom_mem_malloc(sizeof magic_opcode);
338 ppc_dma_write(gPromOSIEntry, &magic_opcode, sizeof magic_opcode);
339 gPromOSIEntry = prom_mem_phys_to_virt(gPromOSIEntry);
340 return true;
341 }
342
343 bool prom_mem_done()
344 {
345 delete[] gPhysMemoryUsed;
346 gPhysMemoryUsed = NULL;
347 return true;
348 }

  ViewVC Help
Powered by ViewVC 1.1.26