2 ** Copyright 2001, Travis Geiselbrecht. All rights reserved.
3 ** Distributed under the terms of the NewOS License.
5 #include <boot/stage2.h>
6 #include <libc/string.h>
7 #include "stage2_priv.h"
11 static unsigned int primary_hash(unsigned int vsid
, unsigned int vaddr
);
12 static unsigned int secondary_hash(unsigned int primary_hash
);
15 #define BATU_BEPI_MASK 0xfffe0000
16 #define BATU_LEN_256M 0x1ffc
20 #define BATL_BRPN_MASK 0xfffe0000
21 #define BATL_WIMG_MASK 0x78
26 #define BATL_PP_MASK 0x3
27 #define BATL_PP_RO 0x1
28 #define BATL_PP_RW 0x2
33 unsigned int vsid
: 24;
34 unsigned int hash
: 1;
37 unsigned int ppn
: 20;
38 unsigned int unused
: 3;
41 unsigned int wimg
: 4;
42 unsigned int unused1
: 1;
48 static struct pteg
*ptable
= 0;
49 static int ptable_size
= 0;
50 static unsigned int ptable_hash_mask
= 0;
53 static unsigned long total_ram_size
= 0;
55 static void print_pte(struct pte
*e
);
58 static void find_phys_memory_map(kernel_args
*ka
)
66 int mem_regions_len
= 0;
68 // get the physical memory map of the system
69 handle
= of_finddevice("/memory");
70 memset(mem_regions
, 0, sizeof(mem_regions
));
71 mem_regions_len
= of_getprop(handle
, "reg", mem_regions
, sizeof(mem_regions
[0]) * 32);
72 mem_regions_len
/= sizeof(struct mem_region
);
74 // copy these regions over to the kernel args structure
75 ka
->num_phys_mem_ranges
= 0;
76 for(i
=0; i
<mem_regions_len
; i
++) {
77 if(mem_regions
[i
].len
> 0) {
78 total_ram_size
+= mem_regions
[i
].len
;
80 if(mem_regions
[i
].pa
== ka
->phys_mem_range
[ka
->num_phys_mem_ranges
-1].start
+ ka
->phys_mem_range
[ka
->num_phys_mem_ranges
-1].size
) {
81 // this range just extends the old one
82 ka
->phys_mem_range
[ka
->num_phys_mem_ranges
-1].size
+= mem_regions
[i
].len
;
86 ka
->phys_mem_range
[ka
->num_phys_mem_ranges
].start
= mem_regions
[i
].pa
;
87 ka
->phys_mem_range
[ka
->num_phys_mem_ranges
].size
= mem_regions
[i
].len
;
88 ka
->num_phys_mem_ranges
++;
89 if(ka
->num_phys_mem_ranges
== MAX_PHYS_MEM_ADDR_RANGE
) {
90 printf("too many physical memory maps, increase MAX_PHYS_MEM_ADDR_RANGE\n");
95 for(i
=0; i
<ka
->num_phys_mem_ranges
; i
++) {
96 printf("phys map %d: pa 0x%x, len %d\n", i
, ka
->phys_mem_range
[i
].start
, ka
->phys_mem_range
[i
].size
);
100 static void find_used_phys_memory_map(kernel_args
*ka
)
104 struct translation_map
{
110 int translation_map_len
= 0;
112 // get the current translation map of the system,
113 // to find how much memory was mapped to load the stage1 and bootdir
114 handle
= of_finddevice("/chosen");
115 of_getprop(handle
, "mmu", &handle
, sizeof(handle
));
116 handle
= of_instance_to_package(handle
);
117 memset(&memmap
, 0, sizeof(memmap
));
118 translation_map_len
= of_getprop(handle
, "translations", memmap
, sizeof(memmap
));
119 translation_map_len
/= sizeof(struct translation_map
);
120 for(i
=0; i
<translation_map_len
; i
++) {
121 printf("package loaded at pa 0x%x va 0x%x, len 0x%x\n", memmap
[i
].pa
, memmap
[i
].va
, memmap
[i
].len
);
122 if(memmap
[i
].va
== LOAD_ADDR
) {
123 // we found the translation that covers the loaded package. Save this.
124 ka
->phys_alloc_range
[0].start
= memmap
[i
].pa
;
125 ka
->phys_alloc_range
[0].size
= memmap
[i
].len
;
126 ka
->num_phys_alloc_ranges
= 1;
135 asm volatile("sync");
136 for(i
=0; i
< 0x40000; i
+= 0x1000) {
137 asm volatile("tlbie %0" :: "r" (i
));
138 asm volatile("eieio");
139 asm volatile("sync");
141 asm volatile("tlbsync");
142 asm volatile("sync");
147 void syncicache(void *address
, int len
)
152 off
= (unsigned int)address
& (CACHELINE
- 1);
156 p
= (char *)address
- off
;
158 asm volatile ("dcbst 0,%0" :: "r"(p
));
160 } while((l
-= CACHELINE
) > 0);
161 asm volatile ("sync");
162 p
= (char *)address
- off
;
164 asm volatile ("icbi 0,%0" :: "r"(p
));
166 } while((len
-= CACHELINE
) > 0);
167 asm volatile ("sync");
168 asm volatile ("isync");
171 int s2_mmu_init(kernel_args
*ka
)
173 unsigned int ibats
[8];
174 unsigned int dbats
[8];
184 // identity map the first 512Mb of RAM
185 ibats
[0] = BATU_LEN_256M
| BATU_VS
;
186 dbats
[0] = BATU_LEN_256M
| BATU_VS
;
187 ibats
[1] = BATL_MC
| BATL_PP_RW
;
188 dbats
[1] = BATL_MC
| BATL_PP_RW
;
189 ibats
[2] = 0x10000000 | BATU_LEN_256M
| BATU_VS
;
190 dbats
[2] = 0x10000000 | BATU_LEN_256M
| BATU_VS
;
191 ibats
[3] = 0x10000000 | BATL_MC
| BATL_PP_RW
;
192 dbats
[3] = 0x10000000 | BATL_MC
| BATL_PP_RW
;
194 /* map 0x90000000 down to a usable spot in memory */
195 ibats
[4] = 0x20000000 | BATU_LEN_256M
| BATU_VS
;
196 dbats
[4] = 0x20000000 | BATU_LEN_256M
| BATU_VS
;
197 ibats
[5] = 0x90000000 | BATL_CI
| BATL_PP_RW
;
198 dbats
[5] = 0x90000000 | BATL_CI
| BATL_PP_RW
;
206 s2_change_framebuffer_addr(0x26008000);
208 printf("msr = 0x%x\n", getmsr());
210 // figure out where physical memory is and what is being used
211 find_phys_memory_map(ka
);
212 find_used_phys_memory_map(ka
);
214 // allocate a page table
216 unsigned long top_ram
= 0;
218 // find the largest address of physical memory, but with a max of 512 MB,
219 // so it'll be within our 512 MB BAT window
220 for(i
=0; i
<ka
->num_phys_mem_ranges
; i
++) {
221 if(ka
->phys_mem_range
[i
].start
+ ka
->phys_mem_range
[i
].size
> top_ram
) {
222 if(ka
->phys_mem_range
[i
].start
+ ka
->phys_mem_range
[i
].size
> 512*1024*1024) {
223 if(ka
->phys_mem_range
[i
].start
< 512*1024*1024) {
224 top_ram
= 512*1024*1024;
228 top_ram
= ka
->phys_mem_range
[i
].start
+ ka
->phys_mem_range
[i
].size
;
231 printf("top of ram (but under 512MB) is 0x%x\n", top_ram
);
233 // figure the size of the new pagetable, as recommended by Motorola
234 if(total_ram_size
<= 8*1024*1024) {
235 ptable_size
= 64*1024;
236 } else if(total_ram_size
<= 16*1024*1024) {
237 ptable_size
= 128*1024;
238 } else if(total_ram_size
<= 32*1024*1024) {
239 ptable_size
= 256*1024;
240 } else if(total_ram_size
<= 64*1024*1024) {
241 ptable_size
= 512*1024;
242 } else if(total_ram_size
<= 128*1024*1024) {
243 ptable_size
= 1024*1024;
244 } else if(total_ram_size
<= 256*1024*1024) {
245 ptable_size
= 2*1024*1024;
246 } else if(total_ram_size
<= 512*1024*1024) {
247 ptable_size
= 4*1024*1024;
248 } else if(total_ram_size
<= 1024*1024*1024) {
249 ptable_size
= 8*1024*1024;
250 } else if(total_ram_size
<= 2*1024*1024*1024) {
251 ptable_size
= 16*1024*1024;
253 ptable_size
= 32*1024*1024;
256 // figure out where to put the page table
257 ptable_hash_mask
= (ptable_size
>> 6) - 1;
258 ptable
= (struct pteg
*)(top_ram
- ptable_size
);
259 printf("ptable at pa 0x%x, size 0x%x\n", ptable
, ptable_size
);
260 printf("mask = 0x%x\n", ptable_hash_mask
);
262 // save it's new location in the kernel args
263 ka
->arch_args
.page_table
.start
= (unsigned long)ptable
;
264 ka
->arch_args
.page_table
.size
= ptable_size
;
265 ka
->arch_args
.page_table_mask
= ptable_hash_mask
;
269 struct pteg
*old_ptable
;
272 printf("sdr1 = 0x%x\n", getsdr1());
274 old_ptable
= (struct pteg
*)((unsigned int)getsdr1() & 0xffff0000);
275 printf("old_ptable %p\n", old_ptable
);
276 for(i
=0; i
< (64*1024) >> 6 ; i
++) {
278 if(old_ptable
[i
].pte
[j
].v
&& old_ptable
[i
].pte
[j
].vsid
== 0)
279 print_pte(&old_ptable
[i
].pte
[j
]);
284 printf("memsetting pagetable and performing switch\n");
285 memset(ptable
, 0, ptable_size
);
287 // set up the segment registers
288 for(i
=0; i
<16; i
++) {
289 setsr(i
* 0x10000000, i
);
292 printf("done, setting sdr1\n");
293 setsdr1(((unsigned int)ptable
& 0xffff0000) | (ptable_hash_mask
>> 10));
295 printf("sdr1 = 0x%x\n", getsdr1());
298 mmu_map_page(0x96008000, 0x96008000);
299 mmu_map_page(0x96009000, 0x96009000);
300 mmu_map_page(0x9600a000, 0x9600a000);
301 mmu_map_page(0x0, 0x30000000);
303 printf("testing...\n");
305 printf("%d\n", *(int *)0x30000000);
306 printf("%d\n", *(int *)0x96008000);
313 static void print_pte(struct pte
*e
)
315 printf("entry %p: ", e
);
316 printf("v %d ", e
->v
);
318 printf("vsid 0x%x ", e
->vsid
);
319 printf("hash %d ", e
->hash
);
320 printf("api 0x%x ", e
->api
);
322 printf("ppn 0x%x ", e
->ppn
);
323 printf("r %d ", e
->r
);
324 printf("c %d ", e
->c
);
325 printf("wimg 0x%x ", e
->wimg
);
326 printf("pp 0x%x ", e
->pp
);
331 void mmu_map_page(unsigned long pa
, unsigned long va
)
338 // lookup the vsid based off the va
339 vsid
= getsr(va
) & 0xffffff;
341 // printf("mmu_map_page: vsid %d, pa 0x%x, va 0x%x\n", vsid, pa, va);
343 hash
= primary_hash(vsid
, va
);
344 // printf("hash = 0x%x\n", hash);
346 pteg
= &ptable
[hash
];
347 // printf("pteg @ 0x%x\n", pteg);
349 // search for the first free slot for this pte
351 // printf("trying pteg[%i]\n", i);
352 if(pteg
->pte
[i
].v
== 0) {
354 pteg
->pte
[i
].ppn
= pa
/ PAGE_SIZE
;
355 pteg
->pte
[i
].unused
= 0;
358 pteg
->pte
[i
].wimg
= 0x0;
359 pteg
->pte
[i
].unused1
= 0;
360 pteg
->pte
[i
].pp
= 0x2; // RW
361 asm volatile("eieio");
363 pteg
->pte
[i
].vsid
= vsid
;
364 pteg
->pte
[i
].hash
= 0; // primary
365 pteg
->pte
[i
].api
= (va
>> 22) & 0x3f;
368 // printf("set pteg to ");
369 // print_pte(&pteg->pte[i]);
370 // printf("set pteg to 0x%x 0x%x\n", *((int *)&pteg->pte[i]), *(((int *)&pteg->pte[i])+1));
376 static unsigned int primary_hash(unsigned int vsid
, unsigned int vaddr
)
378 unsigned int page_index
;
381 page_index
= (vaddr
>> 12) & 0xffff;
383 return (vsid
^ page_index
) & ptable_hash_mask
;
386 static unsigned int secondary_hash(unsigned int primary_hash
)
388 return ~primary_hash
;