|
|
1.1 root 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: File: PseudoKernel.c
24:
25: Contains: BlueBox PseudoKernel calls
26:
27: Copyright: 1997 by Apple Computer, Inc., all rights reserved
28:
29: */
30:
31: #include <mach/mach_types.h>
32: #include <mach/kern_return.h>
33: #include <kern/host.h>
34: #include <kern/task.h>
35: #include <kern/thread.h>
36: #include <ppc/PseudoKernel.h>
37: #include <ppc/exception.h>
38: #include <vm/vm_kern.h>
39:
40: void bbSetRupt(ReturnHandler *rh, thread_act_t ct);
41: void DumpTheSave(struct savearea *save); /* (TEST/DEBUG) */
42:
43: /*
44: ** Function: NotifyInterruption
45: **
46: ** Inputs:
47: ** ppcInterrupHandler - interrupt handler to execute
48: ** interruptStatePtr - current interrupt state
49: **
50: ** Outputs:
51: **
52: ** Notes:
53: **
54: */
55: kern_return_t syscall_notify_interrupt (UInt32 ppcInterruptHandler) {
56:
57: UInt32 interruptState;
58: task_t task;
59: spl_t s;
60: thread_act_t act, fact;
61: thread_t thread;
62: bbRupt *bbr;
63: int i;
64:
65: task = current_task(); /* Figure out who our task is */
66:
67: task_lock(task); /* Lock our task */
68: mutex_lock(&task->act_list_lock); /* Lock the list so it can't change on us */
69:
70: fact = (thread_act_t)task->thr_acts.next; /* Get the first activation on task */
71: act = 0; /* Pretend we didn't find it yet */
72:
73: for(i = 0; i < task->thr_act_count; i++) { /* Scan the whole list */
74: if(fact->mact.bbDescAddr) { /* Is this the Blue thread? */
75: act = fact; /* Yeah... */
76: break; /* Bail the loop... */
77: }
78: fact = (thread_act_t)fact->thr_acts.next; /* Go to the next one */
79: }
80:
81: mutex_unlock(&task->act_list_lock);
82:
83: if(!act) { /* Couldn't find a bluebox */
84: task_unlock(task); /* Release task lock */
85: return KERN_FAILURE; /* No tickie, no shirtee... */
86: }
87:
88: act_lock_thread(act); /* Make sure this stays 'round */
89: task_unlock(task); /* Safe to release now */
90:
91: if(act->mact.bbPendRupt >= 16) { /* Have we hit the arbitrary maximum? */
92: act_unlock_thread(act); /* Unlock the activation */
93: return KERN_RESOURCE_SHORTAGE; /* Too many pending right now */
94: }
95:
96: if(!(bbr = (bbRupt *)kalloc(sizeof(bbRupt)))) { /* Get a return handler control block */
97: act_unlock_thread(act); /* Unlock the activation */
98: return KERN_RESOURCE_SHORTAGE; /* No storage... */
99: }
100:
101: act->mact.bbPendRupt++; /* Count this 'rupt */
102: bbr->rh.handler = bbSetRupt; /* Set interruption routine */
103: bbr->ruptRtn = ppcInterruptHandler; /* Set address to vector to */
104:
105: bbr->rh.next = act->handlers; /* Put our interrupt at the start of the list */
106: act->handlers = &bbr->rh;
107:
108: s = splsched(); /* No talking in class */
109: act_set_apc(act); /* Set an APC AST */
110: splx(s); /* Ok, you can talk now */
111:
112: act_unlock_thread(act); /* Unlock the activation */
113: return KERN_SUCCESS; /* We're done... */
114: }
115:
116: /*
117: * This guy is fired off asynchronously to actually do the 'rupt.
118: * We will find the user state savearea and modify it. If we can't,
119: * we just leave after releasing our work area
120: */
121:
122: void bbSetRupt(ReturnHandler *rh, thread_act_t act) {
123:
124: savearea *sv;
125: BDA_t *bda;
126: bbRupt *bbr;
127: UInt32 interruptState;
128:
129: bbr = (bbRupt *)rh; /* Make our area convenient */
130:
131: if(!(bda = (BDA_t *)act->mact.bbDescAddr)) { /* Is BlueBox still enabled? */
132: kfree((vm_offset_t)bbr, sizeof(bbRupt)); /* No, release the control block */
133: return;
134: }
135:
136: act->mact.bbPendRupt--; /* Uncount this 'rupt */
137:
138: if(!(sv = (savearea *)find_user_regs(act))) { /* Find the user state registers */
139: kfree((vm_offset_t)bbr, sizeof(bbRupt)); /* Couldn't find 'em, release the control block */
140: return;
141: }
142:
143: interruptState = (bda->InterruptControlWord & kInterruptStateMask) >> kInterruptStateShift;
144:
145: switch (interruptState) {
146:
147: case kInUninitialized:
148: break;
149:
150: case kInPseudoKernel:
151: case kOutsideBlue:
152: bda->InterruptControlWord = bda->InterruptControlWord |
153: ((bda->postIntMask >> kCR2ToBackupShift) & kBackupCR2Mask);
154: break;
155:
156: case kInSystemContext:
157: sv->save_cr |= bda->postIntMask;
158: break;
159:
160: case kInAlternateContext:
161: bda->InterruptControlWord = bda->InterruptControlWord |
162: ((bda->postIntMask >> kCR2ToBackupShift) & kBackupCR2Mask);
163: bda->InterruptControlWord = (bda->InterruptControlWord & ~kInterruptStateMask) |
164: (kInPseudoKernel << kInterruptStateShift);
165:
166: bda->ihs_pc = sv->save_srr0; /* Save the current PC */
167: sv->save_srr0 = bbr->ruptRtn; /* Set the new one */
168: bda->ihs_gpr2 = sv->save_r2; /* Save the original R2 */
169: break;
170:
171: case kInExceptionHandler:
172: bda->InterruptControlWord = bda->InterruptControlWord |
173: ((bda->postIntMask >> kCR2ToBackupShift) & kBackupCR2Mask);
174: break;
175:
176: default:
177: break;
178: }
179:
180: kfree((vm_offset_t)bbr, sizeof(bbRupt)); /* Release the control block */
181: return;
182:
183: }
184:
185: kern_return_t enable_bluebox(
186: host_t host,
187: void *TWI_TableStart, /* Start of TWI table */
188: char *Desc_TableStart /* Start of descriptor table */
189: ) {
190:
191: thread_t th;
192: vm_offset_t kerndescaddr, physdescaddr;
193: kern_return_t ret;
194: int i;
195:
196: th = current_thread(); /* Get our thread */
197:
198: if (host == HOST_NULL) return KERN_INVALID_HOST;
199:
200: if(!is_suser()) return KERN_FAILURE; /* We will only do this for the superuser */
201: if(th->top_act->mact.bbDescAddr) return KERN_FAILURE; /* Bail if already authorized... */
202: if((unsigned int) Desc_TableStart & (PAGE_SIZE - 1)) /* Is the descriptor page aligned? */
203: return KERN_FAILURE; /* No, kick 'em out... */
204:
205: ret = vm_map_wire(th->top_act->map, /* Kernel wire the descriptor in the user's map */
206: (vm_offset_t)Desc_TableStart,
207: (vm_offset_t)Desc_TableStart + PAGE_SIZE,
208: VM_PROT_READ | VM_PROT_WRITE,
209: FALSE);
210:
211: if(ret != KERN_SUCCESS) { /* Couldn't wire it, spit on 'em... */
212: return KERN_FAILURE;
213: }
214:
215: physdescaddr = /* Get the physical address of the page */
216: pmap_extract(th->top_act->map->pmap, (vm_offset_t) Desc_TableStart);
217:
218: ret = kmem_alloc_pageable(kernel_map, &kerndescaddr, PAGE_SIZE); /* Find a virtual address to use */
219: if(ret != KERN_SUCCESS) { /* Could we get an address? */
220: (void) vm_map_unwire(th->top_act->map, /* No, unwire the descriptor */
221: (vm_offset_t)Desc_TableStart,
222: (vm_offset_t)Desc_TableStart + PAGE_SIZE,
223: TRUE);
224: return KERN_FAILURE; /* Split... */
225: }
226:
227: (void) pmap_enter(kernel_pmap, /* Map this into the kernel */
228: kerndescaddr, physdescaddr, VM_PROT_READ|VM_PROT_WRITE,
229: TRUE);
230:
231: th->top_act->mact.bbDescAddr = (unsigned int)kerndescaddr; /* Set kernel address of the table */
232: th->top_act->mact.bbUserDA = (unsigned int)Desc_TableStart; /* Set user address of the table */
233: th->top_act->mact.bbTableStart = (unsigned int)TWI_TableStart; /* Set address of the trap table */
234: th->top_act->mact.bbPendRupt = 0; /* Clean pending 'rupt count */
235:
236: return KERN_SUCCESS;
237:
238: }
239:
240: kern_return_t disable_bluebox( host_t host ) {
241:
242: thread_act_t act;
243:
244: act = current_act(); /* Get our thread */
245:
246: if (host == HOST_NULL) return KERN_INVALID_HOST;
247:
248: if(!is_suser()) return KERN_FAILURE; /* We will only do this for the superuser */
249: if(!act->mact.bbDescAddr) return KERN_FAILURE; /* Bail if not authorized... */
250:
251: (void) vm_map_unwire(act->map, /* Unwire the descriptor in user's address space */
252: (vm_offset_t)act->mact.bbUserDA,
253: (vm_offset_t)act->mact.bbUserDA + PAGE_SIZE,
254: FALSE);
255:
256: kmem_free(kernel_map, (vm_offset_t)act->mact.bbDescAddr, PAGE_SIZE); /* Release the page */
257:
258: act->mact.bbDescAddr = 0; /* Clear kernel pointer to it */
259: act->mact.bbUserDA = 0; /* Clear user pointer to it */
260: act->mact.bbTableStart = 0; /* Clear start of table address */
261: act->mact.bbPendRupt = 0; /* Clean pending 'rupt count */
262: return KERN_SUCCESS;
263: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.