]>
Commit | Line | Data |
---|---|---|
1c79356b A |
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 | } |