1 /* mm.c - memory management
3 Copyright (C) 2010-2011 Hector Martin "marcan" <hector@marcansoft.com>
5 This code is licensed to you under the terms of the GNU GPL, version 2;
6 see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
16 #define MSR_IR (1UL<<5)
17 #define MSR_DR (1UL<<4)
28 // highmem size is aligned to 16MB blocks
29 #define HIGHMEM_PBITS 24
30 #define HIGHMEM_PALIGN (1<<HIGHMEM_PBITS)
32 // highmem pointer is aligned to 64kB
33 #define HIGHMEM_ALIGN 65536
39 static u64 highmem_ptr
;
46 struct mmio_region mmios
[NUM_MMIO
];
48 int mm_addmmio(u64 start
, u32 size
)
56 if ((start
& 0xfff) || (end
& 0xfff)) {
57 printf("WARNING: MMIO region is not aligned (0x%016lx 0x%x)", start
, size
);
59 start
= (start
+0xfff)&~0xfff;
65 for (i
=0; i
<NUM_MMIO
; i
++) {
66 if (mmios
[i
].start
== 0) {
67 mmios
[i
].start
= start
;
72 printf("WARNING: Maximum number of MMIO regions exceeded\n");
76 int mm_delmmio(u64 start
)
80 for (i
=0; i
<NUM_MMIO
; i
++) {
81 if (mmios
[i
].start
== start
) {
87 printf("WARNING: Tried to delete nonexistent MMIO region 0x%016lx\n", start
);
93 memset(mmios
, 0, sizeof(mmios
));
97 int mm_ismmio(u64 addr
)
100 for (i
=0; i
<NUM_MMIO
; i
++) {
101 if (mmios
[i
].start
<= addr
&& mmios
[i
].end
> addr
)
107 int mm_loadseg(u64 addr
)
111 u64 esid
= addr
>> 28;
118 if (seg_idx
>= NUM_SLB
)
124 rs
= (esid
<<12) | 0x400;
125 rb
= (esid
<<28) | (1<<27) | index
;
127 asm("slbmte %0,%1 ; isync" :: "r"(rs
), "r"(rb
));
128 printf("SLB[%d] = %016lx %016lx (caused by %016lx)\n", index
, rs
, rb
, addr
);
132 int mm_loadhtab(u64 addr
)
138 //printf("Load HTAB for %016lx\n", addr);
143 if (mm_ismmio(addr
)) {
149 u64 inserted_index
, evicted_v
, evicted_r
;
151 hpte_v
= (addr
>>23)<<7;
153 hpte_r
= addr
|(wimg
<<3);
155 u64 htab_hash_mask
= ((256*1024)>>7)-1;
157 u64 hash
= (addr
>> 28) ^ ((addr
& 0x0fffffffUL
) >> 12);
158 u64 hpte_group
= ((hash
& htab_hash_mask
) * 8);
160 result
= lv1_insert_htab_entry(0, hpte_group
,
164 &evicted_v
, &evicted_r
);
166 printf("Failed to insert HTAB entry:\n");
167 printf("hpte_group=0x%lx hpte_v=0x%016lx hpte_r=0x%016lx\n", hpte_group
, hpte_v
, hpte_r
);
168 printf("result=%ld inserted_index=%lx evicted_v=%lx evicted_r=%lx\n", result
, inserted_index
, evicted_v
, evicted_r
);
179 printf("Initializing memory management...\n");
181 memset(mmios
, 0, sizeof(mmios
));
183 result
= lv1_construct_virtual_address_space(18, 0, 0, &vas_id
, &act_htab_size
);
185 fatal("Could not construct VAS\n");
186 printf("New VAS ID: %ld\n", vas_id
);
188 result
= lv1_select_virtual_address_space(vas_id
);
190 fatal("Could not switch VAS\n");
198 asm("mfmsr %0" : "=r"(msr
));
199 msr
|= MSR_IR
| MSR_DR
;
200 asm("isync ; mtmsrd %0,0 ; isync" :: "r"(msr
));
202 printf("MMU initialized, now running in virtual mode\n");
206 result
= lv1_get_logical_ppe_id(&ppe_id
);
208 fatal("could not get PPE ID");
210 result
= lv1_get_logical_partition_id(&lpar_id
);
212 fatal("could not get LPAR ID");
214 u64 rm_size
, rgntotal
, v2
;
216 result
= lv1_read_repository_node(lpar_id
, FIELD_FIRST("bi",0),
217 FIELD("pu",0), ppe_id
, FIELD("rm_size",0),
220 fatal("could not get bootmem size");
222 result
= lv1_read_repository_node(lpar_id
, FIELD_FIRST("bi",0),
223 FIELD("rgntotal",0), 0, 0, &rgntotal
, &v2
);
225 fatal("could not get total region size");
227 printf("Region size = %ld bytes (%ldMB)\n", rgntotal
, rgntotal
>>20);
228 printf("Bootmem = %ld bytes (%ldMB)\n", rm_size
, rm_size
>>20);
230 mm_bootmem_size
= rm_size
;
232 u64 exp_size
= rgntotal
- rm_size
;
233 exp_size
&= ~(HIGHMEM_PALIGN
-1);
237 result
= lv1_allocate_memory(exp_size
, HIGHMEM_PBITS
, 0, 0, &addr
, &muid
);
239 mm_highmem_addr
= addr
;
240 mm_highmem_size
= exp_size
;
243 printf("Allocation of %ld bytes failed (%d), trying again...\n", exp_size
, result
);
244 exp_size
-= HIGHMEM_PALIGN
;
249 fatal("could not allocate highmem");
251 highmem_ptr
= mm_highmem_addr
;
253 printf("Highmem = %ld bytes (%ldMB) at 0x%lx\n", mm_highmem_size
, mm_highmem_size
>>20, mm_highmem_addr
);
256 void mm_shutdown_highmem(void)
260 printf("Freeing highmem...\n");
261 result
= lv1_release_memory(mm_highmem_addr
);
264 fatal("could not free highmem");
266 printf("Highmem is gone\n");
269 void mm_shutdown(void)
272 printf("Shutting down memory management...\n");
275 asm("mfmsr %0" : "=r"(msr
));
276 msr
&= ~(MSR_IR
| MSR_DR
);
277 asm("mtmsrd %0,0 ; isync" :: "r"(msr
));
279 printf("Now running in real mode\n");
281 result
= lv1_select_virtual_address_space(0);
283 fatal("Could not switch to VAS 0\n");
285 result
= lv1_destruct_virtual_address_space(vas_id
);
287 fatal("Could not destroy VAS\n");
289 printf("Destroyed VAS %ld\n", vas_id
);
295 void mm_highmem_reserve(size_t size
)
297 if (size
> mm_highmem_freesize())
298 fatal("mm_highmem_reserve: too large");
300 highmem_ptr
+= size
+ HIGHMEM_ALIGN
- 1;
301 highmem_ptr
&= ~(HIGHMEM_ALIGN
-1);
304 void *mm_highmem_freestart(void)
306 return (void*)highmem_ptr
;
309 size_t mm_highmem_freesize(void)
311 return mm_highmem_addr
+ mm_highmem_size
- highmem_ptr
;
314 u64
mm_addr_to_kernel(void *addr
)
318 if (a
> mm_bootmem_size
)
319 if (a
>= mm_highmem_addr
&& a
< (mm_highmem_addr
+mm_highmem_size
))
320 return a
- mm_highmem_addr
+ mm_bootmem_size
;
322 fatal("mm_addr_to_kernel: out of bounds");
327 void sync_before_exec(void *addr
, int len
)
329 u64 p
= ((u64
)addr
) & ~0x1f;
330 u64 end
= ((u64
)addr
) + len
;
333 asm("dcbst 0,%0 ; sync ; icbi 0,%0" :: "r"(p
));