]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/bat_init.c
xnu-123.5.tar.gz
[apple/xnu.git] / osfmk / ppc / bat_init.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 #include <mach/std_types.h>
23 #include <ppc/proc_reg.h>
24 #include <ppc/boot.h>
25 #include <ppc/mem.h>
26
27 #ifdef XXX_LOADER
28 unsigned int kernel_seg_regs[] = {
29 KERNEL_SEG_REG0_VALUE,
30 KERNEL_SEG_REG1_VALUE,
31 SEG_REG_INVALID, /* 2 */
32 SEG_REG_INVALID, /* 3 */
33 SEG_REG_INVALID, /* 4 */
34 KERNEL_SEG_REG5_VALUE, /* 5 - I/O segment */
35 SEG_REG_INVALID, /* 6 */
36 SEG_REG_INVALID, /* 7 */
37 KERNEL_SEG_REG8_VALUE, /* 8-F are possible IO space */
38 KERNEL_SEG_REG9_VALUE,
39 KERNEL_SEG_REG10_VALUE,
40 KERNEL_SEG_REG11_VALUE,
41 KERNEL_SEG_REG12_VALUE,
42 KERNEL_SEG_REG13_VALUE,
43 KERNEL_SEG_REG14_VALUE, /* 14 - A/V video */
44 KERNEL_SEG_REG15_VALUE /* 15 - NuBus etc */
45 };
46 #else
47 extern unsigned int kernel_seg_regs[];
48 #endif
49
50 // The sophisticated BAT manager
51
52 unsigned int mappedSegments = 0;
53 unsigned int availableBATs = 0xE; // BAT0 used, 1-3 available
54
55 vm_offset_t
56 PEResidentAddress( vm_offset_t address, vm_size_t length )
57 {
58 if( mappedSegments & (1 << (15 & (address >> 28))))
59 return( address);
60 else
61 return( 0);
62 }
63
64 vm_offset_t
65 PEMapSegment( vm_offset_t address, vm_size_t length )
66 {
67 vm_offset_t retAddress;
68 bat_t bat;
69 int batNum;
70
71 retAddress = PEResidentAddress( address, length );
72 if( retAddress)
73 return( retAddress);
74
75 if( length < (256 * 1024))
76 return( 0);
77 if( availableBATs == 0)
78 return( 0);
79
80 for( batNum = 0;
81 (0 == (availableBATs & (1 << batNum)));
82 batNum++);
83
84 bat.upper.word = address & 0xf0000000;
85 bat.lower.word = bat.upper.word;
86
87 bat.upper.bits.bl = 0x7ff; /* size = 256M */
88 bat.upper.bits.vs = 1;
89 bat.upper.bits.vp = 0; /* user disabled */
90
91 bat.lower.bits.wimg = PTE_WIMG_IO;
92 bat.lower.bits.pp = 2; /* read/write access */
93
94 // Update the shadow bats.
95 shadow_BAT.DBATs[batNum].upper = bat.upper.word;
96 shadow_BAT.DBATs[batNum].lower = bat.lower.word;
97
98 sync();isync();
99 switch( batNum) { // !%$@!! mtdbat needs literal
100 case 0:
101 mtdbatu( 0, BAT_INVALID); /* invalidate old mapping */
102 mtdbatl( 0, bat.lower.word);
103 mtdbatu( 0, bat.upper.word);
104 break;
105 case 1:
106 mtdbatu( 1, BAT_INVALID);
107 mtdbatl( 1, bat.lower.word);
108 mtdbatu( 1, bat.upper.word);
109 break;
110 case 2:
111 mtdbatu( 2, BAT_INVALID);
112 mtdbatl( 2, bat.lower.word);
113 mtdbatu( 2, bat.upper.word);
114 break;
115 case 3:
116 mtdbatu( 3, BAT_INVALID);
117 mtdbatl( 3, bat.lower.word);
118 mtdbatu( 3, bat.upper.word);
119 break;
120 }
121 sync();isync();
122
123 availableBATs &= ~(1 << batNum);
124 mappedSegments |= (1 << (15 & (address >> 28)));
125
126 return( address);
127 }
128
129 void initialize_bats(boot_args *args)
130 {
131 int i;
132
133 /* Give ourselves the virtual map that we would like */
134 bat_t bat;
135
136 /* Make sure that the BATs map what we expect. Note
137 * that we assume BAT0 maps kernel text & data.
138 *
139 * Except, oops, none of the BATs have ever been set.
140 * Developer worked only by fluke.
141 */
142
143 bat.upper.word = 0;
144 bat.upper.bits.bepi = 0x0; /* start at logical addr 0M */
145 /*
146 * We should be smarter here about picking an
147 * amount to map
148 */
149 bat.upper.bits.bl = 0x7ff; /* size = 256M */
150 bat.upper.bits.vs = 1;
151 bat.upper.bits.vp = 0;
152
153 bat.lower.word = 0;
154 bat.lower.bits.brpn = 0x0; /* start at physical addr 0 */
155 bat.lower.bits.wimg = PTE_WIMG_DEFAULT;
156 bat.lower.bits.pp = 2; /* read/write access */
157
158 /* Mustn't cause any data traffic here,
159 * we're modifying our data BAT register!
160 */
161
162 sync();
163 mtdbatu(0, BAT_INVALID); /* invalidate old mapping */
164 isync();
165 mtdbatl(0, bat.lower.word);
166 isync();
167 mtdbatu(0, bat.upper.word); /* update with new mapping */
168 isync();
169 mtibatl(0, bat.lower.word);
170 isync();
171 mtibatu(0, bat.upper.word); /* update with new mapping */
172 isync();
173
174 sync();isync();
175 mtdbatu(1,BAT_INVALID); mtdbatl(1,BAT_INVALID);
176 mtibatu(1,BAT_INVALID); mtibatl(1,BAT_INVALID);
177 mtdbatu(2,BAT_INVALID); mtdbatl(2,BAT_INVALID);
178 mtibatu(2,BAT_INVALID); mtibatl(2,BAT_INVALID);
179 mtdbatu(3,BAT_INVALID); mtdbatl(3,BAT_INVALID);
180 mtibatu(3,BAT_INVALID); mtibatl(3,BAT_INVALID);
181 sync();isync();
182
183 PEMapSegment( 0xf0000000, 0x10000000);
184 if( args->Video.v_baseAddr)
185 PEMapSegment( args->Video.v_baseAddr, 0x10000000);
186
187 /* Set up segment registers as VM through space 0 */
188 isync();
189 for (i=0; i<=15; i++) {
190 mtsrin(KERNEL_SEG_REG0_VALUE | i, i * 0x10000000);
191 }
192 isync();
193 }
194
195 /*
196 * Adjust the size of the region mapped by a BAT
197 * to to be just large enough to include the specified
198 * offset, and return the offset of the new end of the region.
199 * Note that both 'offsets' are really *lengths*, i.e. the
200 * offset of the end of the mapped region from the beginning.
201 * Either the instruction or data BATs (or both) can be specified.
202 * If the new length is greater than the size mappable by a BAT,
203 * then that value is just returned and no changes are made.
204 */
205 vm_offset_t
206 adjust_bat_limit(
207 vm_offset_t new_minimum,
208 int batn,
209 boolean_t ibat,
210 boolean_t dbat
211 )
212 {
213 vm_offset_t new_limit;
214
215 if (new_minimum <= 256*1024*1024) {
216 unsigned int bl = 0;
217
218 new_limit = 128*1024;
219 while (new_limit < new_minimum) {
220 new_limit *= 2;
221 bl = (bl << 1) | 1;
222 }
223
224 {
225 batu_t batu;
226
227 if (dbat) switch (batn) {
228
229 case 0:
230 mfdbatu(batu, 0 );
231 batu.bits.bl = bl;
232
233 sync(); isync();
234 mtdbatu( 0, batu);
235 sync(); isync();
236
237 break;
238
239 case 1:
240 mfdbatu(batu, 1 );
241 batu.bits.bl = bl;
242
243 sync(); isync();
244 mtdbatu( 1, batu);
245 sync(); isync();
246
247 break;
248
249 case 2:
250 mfdbatu(batu, 2 );
251 batu.bits.bl = bl;
252
253 sync(); isync();
254 mtdbatu( 2, batu);
255 sync(); isync();
256
257 break;
258
259 case 3:
260 mfdbatu(batu, 3 );
261 batu.bits.bl = bl;
262
263 sync(); isync();
264 mtdbatu( 3, batu);
265 sync(); isync();
266
267 break;
268 }
269
270 if (ibat) switch (batn) {
271
272 case 0:
273 mfibatu(batu, 0 );
274 batu.bits.bl = bl;
275
276 sync(); isync();
277 mtibatu( 0, batu);
278 sync(); isync();
279
280 break;
281
282 case 1:
283 mfibatu(batu, 1 );
284 batu.bits.bl = bl;
285
286 sync(); isync();
287 mtibatu( 1, batu);
288 sync(); isync();
289
290 break;
291
292 case 2:
293 mfibatu(batu, 2 );
294 batu.bits.bl = bl;
295
296 sync(); isync();
297 mtibatu( 2, batu);
298 sync(); isync();
299
300 break;
301
302 case 3:
303 mfibatu(batu, 3 );
304 batu.bits.bl = bl;
305
306 sync(); isync();
307 mtibatu( 3, batu);
308 sync(); isync();
309
310 break;
311 }
312 }
313 }
314 else
315 new_limit = new_minimum;
316
317 return (new_limit);
318 }