]>
Commit | Line | Data |
---|---|---|
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 | // The sophisticated BAT manager | |
28 | ||
29 | unsigned int mappedSegments = 0; | |
30 | unsigned int availableBATs = 0xE; // BAT0 used, 1-3 available | |
31 | ||
32 | vm_offset_t | |
33 | PEResidentAddress( vm_offset_t address, vm_size_t length ) | |
34 | { | |
35 | if( mappedSegments & (1 << (15 & (address >> 28)))) | |
36 | return( address); | |
37 | else | |
38 | return( 0); | |
39 | } | |
40 | ||
41 | vm_offset_t | |
42 | PEMapSegment( vm_offset_t address, vm_size_t length ) | |
43 | { | |
44 | vm_offset_t retAddress; | |
45 | bat_t bat; | |
46 | int batNum; | |
47 | ||
48 | retAddress = PEResidentAddress( address, length ); | |
49 | if( retAddress) | |
50 | return( retAddress); | |
51 | ||
52 | if( length < (256 * 1024)) | |
53 | return( 0); | |
54 | if( availableBATs == 0) | |
55 | return( 0); | |
56 | ||
57 | for( batNum = 0; | |
58 | (0 == (availableBATs & (1 << batNum))); | |
59 | batNum++); | |
60 | ||
61 | bat.upper.word = address & 0xf0000000; | |
62 | bat.lower.word = bat.upper.word; | |
63 | ||
64 | bat.upper.bits.bl = 0x7ff; /* size = 256M */ | |
65 | bat.upper.bits.vs = 1; | |
66 | bat.upper.bits.vp = 0; /* user disabled */ | |
67 | ||
68 | bat.lower.bits.wimg = PTE_WIMG_IO; | |
69 | bat.lower.bits.pp = 2; /* read/write access */ | |
70 | ||
71 | // Update the shadow bats. | |
72 | shadow_BAT.DBATs[batNum].upper = bat.upper.word; | |
73 | shadow_BAT.DBATs[batNum].lower = bat.lower.word; | |
74 | ||
75 | sync();isync(); | |
76 | switch( batNum) { // !%$@!! mtdbat needs literal | |
77 | case 0: | |
78 | mtdbatu( 0, BAT_INVALID); /* invalidate old mapping */ | |
79 | mtdbatl( 0, bat.lower.word); | |
80 | mtdbatu( 0, bat.upper.word); | |
81 | break; | |
82 | case 1: | |
83 | mtdbatu( 1, BAT_INVALID); | |
84 | mtdbatl( 1, bat.lower.word); | |
85 | mtdbatu( 1, bat.upper.word); | |
86 | break; | |
87 | case 2: | |
88 | mtdbatu( 2, BAT_INVALID); | |
89 | mtdbatl( 2, bat.lower.word); | |
90 | mtdbatu( 2, bat.upper.word); | |
91 | break; | |
92 | case 3: | |
93 | mtdbatu( 3, BAT_INVALID); | |
94 | mtdbatl( 3, bat.lower.word); | |
95 | mtdbatu( 3, bat.upper.word); | |
96 | break; | |
97 | } | |
98 | sync();isync(); | |
99 | ||
100 | availableBATs &= ~(1 << batNum); | |
101 | mappedSegments |= (1 << (15 & (address >> 28))); | |
102 | ||
103 | return( address); | |
104 | } | |
105 | ||
106 | void initialize_bats(boot_args *args) | |
107 | { | |
108 | int i; | |
109 | ||
110 | /* Give ourselves the virtual map that we would like */ | |
111 | bat_t bat; | |
112 | ||
113 | /* Make sure that the BATs map what we expect. Note | |
114 | * that we assume BAT0 maps kernel text & data. | |
115 | * | |
116 | * Except, oops, none of the BATs have ever been set. | |
117 | * Developer worked only by fluke. | |
118 | */ | |
119 | ||
120 | bat.upper.word = 0; | |
121 | bat.upper.bits.bepi = 0x0; /* start at logical addr 0M */ | |
122 | /* | |
123 | * We should be smarter here about picking an | |
124 | * amount to map | |
125 | */ | |
126 | bat.upper.bits.bl = 0x7ff; /* size = 256M */ | |
127 | bat.upper.bits.vs = 1; | |
128 | bat.upper.bits.vp = 0; | |
129 | ||
130 | bat.lower.word = 0; | |
131 | bat.lower.bits.brpn = 0x0; /* start at physical addr 0 */ | |
132 | bat.lower.bits.wimg = PTE_WIMG_DEFAULT; | |
133 | bat.lower.bits.pp = 2; /* read/write access */ | |
134 | ||
135 | /* Mustn't cause any data traffic here, | |
136 | * we're modifying our data BAT register! | |
137 | */ | |
138 | ||
139 | sync(); | |
140 | mtdbatu(0, BAT_INVALID); /* invalidate old mapping */ | |
141 | isync(); | |
142 | mtdbatl(0, bat.lower.word); | |
143 | isync(); | |
144 | mtdbatu(0, bat.upper.word); /* update with new mapping */ | |
145 | isync(); | |
146 | mtibatl(0, bat.lower.word); | |
147 | isync(); | |
148 | mtibatu(0, bat.upper.word); /* update with new mapping */ | |
149 | isync(); | |
150 | ||
151 | sync();isync(); | |
152 | mtdbatu(1,BAT_INVALID); mtdbatl(1,BAT_INVALID); | |
153 | mtibatu(1,BAT_INVALID); mtibatl(1,BAT_INVALID); | |
154 | mtdbatu(2,BAT_INVALID); mtdbatl(2,BAT_INVALID); | |
155 | mtibatu(2,BAT_INVALID); mtibatl(2,BAT_INVALID); | |
156 | mtdbatu(3,BAT_INVALID); mtdbatl(3,BAT_INVALID); | |
157 | mtibatu(3,BAT_INVALID); mtibatl(3,BAT_INVALID); | |
158 | sync();isync(); | |
159 | ||
160 | PEMapSegment( 0xf0000000, 0x10000000); | |
161 | if( args->Video.v_baseAddr) | |
162 | PEMapSegment( args->Video.v_baseAddr, 0x10000000); | |
163 | ||
164 | /* Set up segment registers as VM through space 0 */ | |
165 | isync(); | |
166 | for (i=0; i<=15; i++) { | |
167 | mtsrin(KERNEL_SEG_REG0_VALUE | i, i * 0x10000000); | |
168 | } | |
169 | isync(); | |
170 | } | |
171 | ||
172 | /* | |
173 | * Adjust the size of the region mapped by a BAT | |
174 | * to to be just large enough to include the specified | |
175 | * offset, and return the offset of the new end of the region. | |
176 | * Note that both 'offsets' are really *lengths*, i.e. the | |
177 | * offset of the end of the mapped region from the beginning. | |
178 | * Either the instruction or data BATs (or both) can be specified. | |
179 | * If the new length is greater than the size mappable by a BAT, | |
180 | * then that value is just returned and no changes are made. | |
181 | */ | |
182 | vm_offset_t | |
183 | adjust_bat_limit( | |
184 | vm_offset_t new_minimum, | |
185 | int batn, | |
186 | boolean_t ibat, | |
187 | boolean_t dbat | |
188 | ) | |
189 | { | |
190 | vm_offset_t new_limit; | |
191 | ||
192 | if (new_minimum <= 256*1024*1024) { | |
193 | unsigned int bl = 0; | |
194 | ||
195 | new_limit = 128*1024; | |
196 | while (new_limit < new_minimum) { | |
197 | new_limit *= 2; | |
198 | bl = (bl << 1) | 1; | |
199 | } | |
200 | ||
201 | { | |
202 | batu_t batu; | |
203 | ||
204 | if (dbat) switch (batn) { | |
205 | ||
206 | case 0: | |
207 | mfdbatu(batu, 0 ); | |
208 | batu.bits.bl = bl; | |
209 | ||
210 | sync(); isync(); | |
211 | mtdbatu( 0, batu); | |
212 | sync(); isync(); | |
213 | ||
214 | break; | |
215 | ||
216 | case 1: | |
217 | mfdbatu(batu, 1 ); | |
218 | batu.bits.bl = bl; | |
219 | ||
220 | sync(); isync(); | |
221 | mtdbatu( 1, batu); | |
222 | sync(); isync(); | |
223 | ||
224 | break; | |
225 | ||
226 | case 2: | |
227 | mfdbatu(batu, 2 ); | |
228 | batu.bits.bl = bl; | |
229 | ||
230 | sync(); isync(); | |
231 | mtdbatu( 2, batu); | |
232 | sync(); isync(); | |
233 | ||
234 | break; | |
235 | ||
236 | case 3: | |
237 | mfdbatu(batu, 3 ); | |
238 | batu.bits.bl = bl; | |
239 | ||
240 | sync(); isync(); | |
241 | mtdbatu( 3, batu); | |
242 | sync(); isync(); | |
243 | ||
244 | break; | |
245 | } | |
246 | ||
247 | if (ibat) switch (batn) { | |
248 | ||
249 | case 0: | |
250 | mfibatu(batu, 0 ); | |
251 | batu.bits.bl = bl; | |
252 | ||
253 | sync(); isync(); | |
254 | mtibatu( 0, batu); | |
255 | sync(); isync(); | |
256 | ||
257 | break; | |
258 | ||
259 | case 1: | |
260 | mfibatu(batu, 1 ); | |
261 | batu.bits.bl = bl; | |
262 | ||
263 | sync(); isync(); | |
264 | mtibatu( 1, batu); | |
265 | sync(); isync(); | |
266 | ||
267 | break; | |
268 | ||
269 | case 2: | |
270 | mfibatu(batu, 2 ); | |
271 | batu.bits.bl = bl; | |
272 | ||
273 | sync(); isync(); | |
274 | mtibatu( 2, batu); | |
275 | sync(); isync(); | |
276 | ||
277 | break; | |
278 | ||
279 | case 3: | |
280 | mfibatu(batu, 3 ); | |
281 | batu.bits.bl = bl; | |
282 | ||
283 | sync(); isync(); | |
284 | mtibatu( 3, batu); | |
285 | sync(); isync(); | |
286 | ||
287 | break; | |
288 | } | |
289 | } | |
290 | } | |
291 | else | |
292 | new_limit = new_minimum; | |
293 | ||
294 | return (new_limit); | |
295 | } |