ppc: Set up SLBs for ppc64
[openbios/afaerber.git] / arch / ppc / ofmem.c
blob436cfe36ba83b63034d9f29493b4dbe50ebf5670
1 /*
2 * Creation Date: <1999/11/07 19:02:11 samuel>
3 * Time-stamp: <2004/01/07 19:42:36 samuel>
5 * <ofmem.c>
7 * OF Memory manager
9 * Copyright (C) 1999-2004 Samuel Rydh (samuel@ibrium.se)
10 * Copyright (C) 2004 Stefan Reinauer
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation
18 /* TODO: Clean up MOLisms in a decent way */
20 #include "config.h"
21 #include "libopenbios/bindings.h"
22 #include "libc/string.h"
23 #include "libopenbios/ofmem.h"
24 #include "kernel.h"
25 #ifdef I_WANT_MOLISMS
26 #include "mol/prom.h"
27 #include "mol/mol.h"
28 #endif
29 #include "mmutypes.h"
30 #include "asm/processor.h"
31 #ifdef I_WANT_MOLISMS
32 #include "osi_calls.h"
33 #endif
35 #define BIT(n) (1U<<(31-(n)))
37 /* called from assembly */
38 extern void dsi_exception( void );
39 extern void isi_exception( void );
40 extern void setup_mmu( unsigned long code_base, unsigned long code_size, unsigned long ramsize );
42 /****************************************************************
43 * Memory usage (before of_quiesce is called)
45 * Physical
47 * 0x00000000 Exception vectors
48 * 0x00004000 Free space
49 * 0x01e00000 Open Firmware (us)
50 * 0x01f00000 OF allocations
51 * 0x01ff0000 PTE Hash
52 * 0x02000000- Free space
54 * Allocations grow downwards from 0x01e00000
56 ****************************************************************/
58 #define HASH_SIZE (2 << 15)
59 #define SEGR_BASE 0x400 /* segment number range to use */
61 #define FREE_BASE_1 0x00004000
62 #define OF_CODE_START 0x01e00000
63 /* #define OF_MALLOC_BASE 0x01f00000 */
64 extern char _end[];
65 #define OF_MALLOC_BASE _end
67 #define HASH_BASE (0x02000000 - HASH_SIZE)
68 #define FREE_BASE_2 0x02000000
70 #define RAMSIZE 0x02000000 /* XXXXXXXXXXXXXXXXXXX FIXME XXXXXXXXXXXXXXX */
72 static ofmem_t s_ofmem;
74 #define IO_BASE 0x80000000
75 #define OFMEM (&s_ofmem)
77 static inline unsigned long
78 get_hash_base( void )
80 return HASH_BASE;
83 static inline unsigned long
84 get_hash_size( void )
86 return HASH_SIZE;
89 static ucell get_heap_top( void )
91 return HASH_BASE;
94 static inline size_t ALIGN_SIZE(size_t x, size_t a)
96 return (x + a - 1) & ~(a-1);
99 ofmem_t* ofmem_arch_get_private(void)
101 return OFMEM;
104 void* ofmem_arch_get_malloc_base(void)
106 return OF_MALLOC_BASE;
109 ucell ofmem_arch_get_heap_top(void)
111 return get_heap_top();
114 ucell ofmem_arch_get_virt_top(void)
116 return IO_BASE;
119 void ofmem_arch_unmap_pages(ucell virt, ucell size)
121 /* kill page mappings in provided range */
124 void ofmem_arch_early_map_pages(ucell phys, ucell virt, ucell size, ucell mode)
126 /* none yet */
129 /************************************************************************/
130 /* OF private allocations */
131 /************************************************************************/
133 void *
134 malloc( int size )
136 return ofmem_malloc(size);
139 void
140 free( void *ptr )
142 return ofmem_free(ptr);
145 void *
146 realloc( void *ptr, size_t size )
148 return ofmem_realloc(ptr, size);
152 /************************************************************************/
153 /* misc */
154 /************************************************************************/
156 ucell ofmem_arch_default_translation_mode( ucell phys )
158 /* XXX: Guard bit not set as it should! */
159 if( phys < IO_BASE || phys >= 0xffc00000 )
160 return 0x02; /*0xa*/ /* wim GxPp */
161 return 0x6a; /* WIm GxPp, I/O */
165 /************************************************************************/
166 /* page fault handler */
167 /************************************************************************/
169 static ucell
170 ea_to_phys( ucell ea, ucell *mode )
172 ucell phys;
174 /* hardcode our translation needs */
175 if( ea >= OF_CODE_START && ea < FREE_BASE_2 ) {
176 *mode = ofmem_arch_default_translation_mode( ea );
177 return ea;
180 phys = ofmem_translate(ea, mode);
181 if( phys == (ucell)-1 ) {
182 #ifdef I_WANT_MOLISMS
183 if( ea != 0x80816c00 )
184 printk("ea_to_phys: no translation for %08lx, using 1-1\n", ea );
185 #endif
186 phys = ea;
187 *mode = ofmem_arch_default_translation_mode( phys );
189 #ifdef I_WANT_MOLISMS
190 forth_segv_handler( (char*)ea );
191 OSI_Debugger(1);
192 #endif
193 /* print_virt_range(); */
194 /* print_phys_range(); */
195 /* print_trans(); */
197 return phys;
200 static void
201 hash_page( ucell ea, ucell phys, ucell mode )
203 static int next_grab_slot=0;
204 unsigned long *upte, cmp, hash1;
205 int i, vsid, found;
206 mPTE_t *pp;
208 vsid = (ea>>28) + SEGR_BASE;
209 cmp = BIT(0) | (vsid << 7) | ((ea & 0x0fffffff) >> 22);
211 hash1 = vsid;
212 hash1 ^= (ea >> 12) & 0xffff;
213 hash1 &= (get_hash_size() - 1) >> 6;
215 pp = (mPTE_t*)(get_hash_base() + (hash1 << 6));
216 upte = (unsigned long*)pp;
218 /* replace old translation */
219 for( found=0, i=0; !found && i<8; i++ )
220 if( cmp == upte[i*2] )
221 found=1;
223 /* otherwise use a free slot */
224 for( i=0; !found && i<8; i++ )
225 if( !pp[i].v )
226 found=1;
228 /* out of slots, just evict one */
229 if( !found ) {
230 i = next_grab_slot + 1;
231 next_grab_slot = (next_grab_slot + 1) % 8;
233 i--;
234 upte[i*2] = cmp;
235 upte[i*2+1] = (phys & ~0xfff) | mode;
237 asm volatile( "tlbie %0" :: "r"(ea) );
240 void
241 dsi_exception( void )
243 unsigned long dar, dsisr;
244 ucell mode;
245 ucell phys;
247 asm volatile("mfdar %0" : "=r" (dar) : );
248 asm volatile("mfdsisr %0" : "=r" (dsisr) : );
250 //printk("dsi-exception @ %08lx <%08lx>\n", dar, dsisr );
252 phys = ea_to_phys(dar, &mode);
253 hash_page( dar, phys, mode );
256 void
257 isi_exception( void )
259 unsigned long nip, srr1;
260 ucell mode;
261 ucell phys;
263 asm volatile("mfsrr0 %0" : "=r" (nip) : );
264 asm volatile("mfsrr1 %0" : "=r" (srr1) : );
266 //printk("isi-exception @ %08lx <%08lx>\n", nip, srr1 );
268 phys = ea_to_phys(nip, &mode);
269 hash_page( nip, phys, mode );
273 /************************************************************************/
274 /* init / cleanup */
275 /************************************************************************/
277 void
278 setup_mmu( unsigned long code_base, unsigned long code_size, unsigned long ramsize )
280 unsigned long sdr1 = HASH_BASE | ((HASH_SIZE-1) >> 16);
281 unsigned long sr_base = (0x20 << 24) | SEGR_BASE;
282 unsigned long msr;
283 int i;
285 asm volatile("mtsdr1 %0" :: "r" (sdr1) );
286 for( i=0; i<16; i++ ) {
287 int j = i << 28;
288 asm volatile("mtsrin %0,%1" :: "r" (sr_base + i), "r" (j) );
290 asm volatile("mfmsr %0" : "=r" (msr) : );
291 msr |= MSR_IR | MSR_DR;
292 asm volatile("mtmsr %0" :: "r" (msr) );
295 void
296 ofmem_init( void )
298 ofmem_t *ofmem = OFMEM;
299 /* In case we can't rely on memory being zero initialized */
300 memset(ofmem, 0, sizeof(ofmem));
302 ofmem->ramsize = RAMSIZE;
304 ofmem_claim_phys( 0, FREE_BASE_1, 0 );
305 ofmem_claim_virt( 0, FREE_BASE_1, 0 );
306 ofmem_claim_phys( OF_CODE_START, FREE_BASE_2 - OF_CODE_START, 0 );
307 ofmem_claim_virt( OF_CODE_START, FREE_BASE_2 - OF_CODE_START, 0 );