]>
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 | /* | |
23 | * This file is used to maintain the exception save areas | |
24 | * | |
25 | */ | |
26 | ||
27 | #include <cpus.h> | |
28 | #include <debug.h> | |
29 | #include <mach_kgdb.h> | |
30 | #include <mach_vm_debug.h> | |
31 | ||
32 | #include <kern/thread.h> | |
33 | #include <mach/vm_attributes.h> | |
34 | #include <mach/vm_param.h> | |
35 | #include <vm/vm_kern.h> | |
36 | #include <vm/vm_map.h> | |
37 | #include <vm/vm_page.h> | |
38 | #include <mach/ppc/thread_status.h> | |
39 | #include <kern/spl.h> | |
40 | #include <kern/simple_lock.h> | |
41 | ||
42 | #include <kern/misc_protos.h> | |
43 | #include <ppc/misc_protos.h> | |
44 | #include <ppc/proc_reg.h> | |
45 | #include <ppc/mem.h> | |
46 | #include <ppc/pmap.h> | |
47 | #include <ppc/pmap_internals.h> | |
48 | #include <ppc/Firmware.h> | |
49 | #include <ppc/mappings.h> | |
50 | #include <ppc/exception.h> | |
51 | #include <ppc/savearea.h> | |
52 | #include <ddb/db_output.h> | |
53 | ||
54 | ||
55 | extern struct Saveanchor saveanchor; /* Aliged savearea anchor */ | |
56 | unsigned int debsave0 = 0; /* Debug flag */ | |
57 | unsigned int backchain = 0; /* Debug flag */ | |
58 | ||
59 | /* | |
60 | * These routines keep track of exception save areas and keeps the count within specific limits. If there are | |
61 | * too few, more are allocated, too many, and they are released. This savearea is where the PCBs are | |
62 | * stored. They never span a page boundary and are referenced by both virtual and real addresses. | |
63 | * Within the interrupt vectors, the real address is used because at that level, no exceptions | |
64 | * can be tolerated. Save areas can be dynamic or permanent. Permanant saveareas are allocated | |
65 | * at boot time and must be in place before any type of exception occurs. These are never released, | |
66 | * and the number is based upon some arbitrary (yet to be determined) amount times the number of | |
67 | * processors. This represents the minimum number required to process a total system failure without | |
68 | * destroying valuable and ever-so-handy system debugging information. | |
69 | * | |
70 | * | |
71 | */ | |
72 | ||
73 | /* | |
74 | * This routine allocates a save area. It checks if enough are available. | |
75 | * If not, it allocates upward to the target free count. | |
76 | * Then, it allocates one and returns it. | |
77 | */ | |
78 | ||
79 | ||
80 | ||
81 | struct savearea *save_alloc(void) { /* Reserve a save area */ | |
82 | ||
83 | kern_return_t retr; | |
84 | savectl *sctl; /* Previous and current save pages */ | |
85 | vm_offset_t vaddr, paddr; | |
86 | struct savearea *newbaby; | |
87 | ||
88 | if(saveanchor.savecount <= (saveanchor.saveneed - saveanchor.saveneghyst)) { /* Start allocating if we drop too far */ | |
89 | while(saveanchor.savecount < saveanchor.saveneed) { /* Keep adding until the adjustment is done */ | |
90 | ||
91 | ||
92 | retr = kmem_alloc_wired(kernel_map, &vaddr, PAGE_SIZE); /* Find a virtual address to use */ | |
93 | ||
94 | if(retr != KERN_SUCCESS) { /* Did we get some memory? */ | |
95 | panic("Whoops... Not a bit of wired memory left for saveareas\n"); | |
96 | } | |
97 | ||
98 | paddr = pmap_extract(kernel_pmap, vaddr); /* Get the physical */ | |
99 | ||
100 | bzero((void *)vaddr, PAGE_SIZE); /* Clear it all to zeros */ | |
101 | sctl = (savectl *)(vaddr+PAGE_SIZE-sizeof(savectl)); /* Point to the control area of the new page */ | |
102 | sctl->sac_alloc = sac_empty; /* Mark all entries free */ | |
103 | sctl->sac_vrswap = (unsigned int)vaddr ^ (unsigned int)paddr; /* Form mask to convert V to R and vice versa */ | |
104 | ||
105 | sctl->sac_flags |= 0x0000EE00; /* (TEST/DEBUG) */ | |
106 | ||
107 | if(!save_queue(paddr)) { /* Add the new ones to the free savearea list */ | |
108 | panic("Arrgghhhh, time out trying to lock the savearea anchor during upward adjustment\n"); | |
109 | } | |
110 | } | |
111 | } | |
112 | if (saveanchor.savecount > saveanchor.savemaxcount) | |
113 | saveanchor.savemaxcount = saveanchor.savecount; | |
114 | ||
115 | newbaby = save_get(); /* Get a savearea and return it */ | |
116 | if(!((unsigned int)newbaby & 0xFFFFF000)) { /* Whoa... None left??? No, way, no can do... */ | |
117 | panic("No saveareas?!?!?! No way! Can't happen! Nuh-uh... I'm dead, done for, kaput...\n"); | |
118 | } | |
119 | ||
120 | return newbaby; /* Bye-bye baby... */ | |
121 | ||
122 | } | |
123 | ||
124 | ||
125 | /* | |
126 | * This routine releases a save area to the free queue. If after that, we have more than our maximum target, | |
127 | * we start releasing what we can until we hit the normal target. | |
128 | */ | |
129 | ||
130 | ||
131 | ||
132 | void save_release(struct savearea *save) { /* Release a save area */ | |
133 | ||
134 | savectl *csave; /* The just released savearea block */ | |
135 | ||
136 | save_ret(save); /* Return a savearea to the free list */ | |
137 | ||
138 | if(saveanchor.savecount > (saveanchor.saveneed + saveanchor.saveposhyst)) { /* Start releasing if we have to many */ | |
139 | csave = (savectl *)42; /* Start with some nonzero garbage */ | |
140 | while((unsigned int)csave && (saveanchor.savecount > saveanchor.saveneed)) { /* Keep removing until the adjustment is done */ | |
141 | ||
142 | csave = save_dequeue(); /* Find and dequeue one that is all empty */ | |
143 | ||
144 | if((unsigned int)csave & 1) { /* Did we timeout trying to get the lock? */ | |
145 | panic("Arrgghhhh, time out trying to lock the savearea anchor during downward adjustment\n"); | |
146 | return; | |
147 | } | |
148 | ||
149 | if((unsigned int)csave) kmem_free(kernel_map, (vm_offset_t) csave, PAGE_SIZE); /* Release the page if we found one */ | |
150 | } | |
151 | } | |
152 | return; | |
153 | ||
154 | } | |
155 | ||
156 | ||
157 | save_fake_zone_info(int *count, vm_size_t *cur_size, vm_size_t *max_size, vm_size_t *elem_size, | |
158 | vm_size_t *alloc_size, int *collectable, int *exhaustable) | |
159 | { | |
160 | *count = saveanchor.saveinuse; | |
161 | *cur_size = saveanchor.savecount * (PAGE_SIZE / 2); | |
162 | *max_size = saveanchor.savemaxcount * (PAGE_SIZE / 2); | |
163 | *elem_size = PAGE_SIZE / 2; | |
164 | *alloc_size = PAGE_SIZE; | |
165 | *collectable = 1; | |
166 | *exhaustable = 0; | |
167 | } | |
168 | ||
169 | ||
170 | ||
171 | /* | |
172 | * This routine prints the free savearea block chain for debugging. | |
173 | */ | |
174 | ||
175 | ||
176 | ||
177 | void save_free_dump(void) { /* Dump the free chain */ | |
178 | ||
179 | unsigned int *dsv, omsr; | |
180 | savectl *dsc; | |
181 | ||
182 | dsv = save_deb(&omsr); /* Get the virtual of the first and disable interrupts */ | |
183 | ||
184 | while(dsv) { /* Do 'em all */ | |
185 | dsc=(savectl *)((unsigned int)dsv+4096-sizeof(savectl)); /* Point to the control area */ | |
186 | // printf("%08X %08X: nxt=%08X; alloc=%08X; flags=%08X\n", dsv, /* Print it all out */ | |
187 | // ((unsigned int)dsv)^(dsc->sac_vrswap), dsc->sac_next, dsc->sac_alloc, dsc->sac_flags); | |
188 | dsv=(unsigned int *)(((unsigned int) dsc->sac_next)^(dsc->sac_vrswap)); /* On to the next, virtually */ | |
189 | ||
190 | } | |
191 | __asm__ volatile ("mtmsr %0" : : "r" (omsr)); /* Restore the interruption mask */ | |
192 | return; | |
193 | } | |
194 | ||
195 | /* | |
196 | * This routine prints the free savearea block chain for debugging. | |
197 | */ | |
198 | ||
199 | ||
200 | ||
201 | void DumpTheSave(struct savearea *save) { /* Dump the free chain */ | |
202 | ||
203 | unsigned int *r; | |
204 | ||
205 | printf("savearea at %08X\n", save); | |
206 | printf(" srrs: %08X %08X\n", save->save_srr0, save->save_srr1); | |
207 | printf(" cr, xer, lr: %08X %08X %08X\n", save->save_cr, save->save_xer, save->save_lr); | |
208 | printf("ctr, dar, dsisr: %08X %08X %08X\n", save->save_ctr, save->save_dar, save->save_dsisr); | |
209 | printf(" space, copyin: %08X %08X\n", save->save_space, save->save_sr_copyin); | |
210 | r=&save->save_r0; | |
211 | printf(" regs: %08X %08X %08X %08X %08X %08X %08X %08X\n", r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]); | |
212 | printf(" %08X %08X %08X %08X %08X %08X %08X %08X\n", r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]); | |
213 | printf(" %08X %08X %08X %08X %08X %08X %08X %08X\n", r[16], r[17], r[18], r[19], r[20], r[21], r[22], r[23]); | |
214 | printf(" %08X %08X %08X %08X %08X %08X %08X %08X\n", r[24], r[25], r[29], r[27], r[28], r[29], r[30], r[31]); | |
215 | r=(unsigned int *)&save->save_fp0; | |
216 | printf(" floats: %08X%08X %08X%08X %08X%08X %08X%08X\n", r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]); | |
217 | printf(" %08X%08X %08X%08X %08X%08X %08X%08X\n", r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]); | |
218 | printf(" %08X%08X %08X%08X %08X%08X %08X%08X\n", r[16], r[17], r[18], r[19], r[20], r[21], r[22], r[23]); | |
219 | printf(" %08X%08X %08X%08X %08X%08X %08X%08X\n", r[24], r[25], r[29], r[27], r[28], r[29], r[30], r[31]); | |
220 | printf(" %08X%08X %08X%08X %08X%08X %08X%08X\n", r[32], r[33], r[34], r[35], r[36], r[37], r[38], r[39]); | |
221 | printf(" %08X%08X %08X%08X %08X%08X %08X%08X\n", r[40], r[41], r[42], r[43], r[44], r[45], r[46], r[47]); | |
222 | printf(" %08X%08X %08X%08X %08X%08X %08X%08X\n", r[48], r[49], r[50], r[51], r[52], r[53], r[54], r[55]); | |
223 | printf(" %08X%08X %08X%08X %08X%08X %08X%08X\n", r[56], r[57], r[58], r[59], r[60], r[61], r[62], r[63]); | |
224 | r=&save->save_sr0; | |
225 | printf(" srs: %08X %08X %08X %08X %08X %08X %08X %08X\n", r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]); | |
226 | printf(" %08X %08X %08X %08X %08X %08X %08X %08X\n", r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]); | |
227 | printf("prev, phys, act: %08X %08X %08X\n", save->save_prev, save->save_phys, save->save_act); | |
228 | printf(" flags: %08X\n", save->save_flags); | |
229 | return; | |
230 | } | |
231 | ||
232 | ||
233 | ||
234 | ||
235 | /* | |
236 | * Dumps out savearea and stack backchains | |
237 | */ | |
238 | ||
239 | void DumpBackChain(struct savearea *save) { /* Prints out back chains */ | |
240 | ||
241 | unsigned int *r; | |
242 | savearea *sv; | |
243 | ||
244 | if(!backchain) return; | |
245 | printf("Proceeding back from savearea at %08X:\n", save); | |
246 | sv=save; | |
247 | while(sv) { | |
248 | printf(" curr=%08X; prev=%08X; stack=%08X\n", sv, sv->save_prev, sv->save_r1); | |
249 | sv=sv->save_prev; | |
250 | } | |
251 | return; | |
252 | } | |
253 | ||
254 | ||
255 | ||
256 |