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