ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/BeOS/SheepDriver/sheep_driver.c
Revision: 1.4
Committed: 2002-01-15T14:58:36Z (22 years, 10 months ago) by cebix
Content type: text/plain
Branch: MAIN
CVS Tags: nigel-build-19, nigel-build-12, nigel-build-13, nigel-build-16, nigel-build-17, nigel-build-15, snapshot-15012002, HEAD
Changes since 1.3: +2 -2 lines
Log Message:
- documentation updates
- 2001 -> 2002
- version 0.9 -> 1.0

File Contents

# Content
1 /*
2 * sheep_driver.c - Low memory and ROM access driver for SheepShaver and
3 * Basilisk II on PowerPC systems
4 *
5 * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer
6 * Basilisk II (C) 1997-2002 Christian Bauer
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 #ifdef __i386__
24 #error The sheep driver only runs on PowerPC machines.
25 #endif
26
27 #include <drivers/KernelExport.h>
28 #include <drivers/Drivers.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <fcntl.h>
34
35 #include "sheep_driver.h"
36
37 #define DEBUG 0
38
39 #if DEBUG==1
40 #define bug pprintf
41 #elif DEBUG==2
42 #define bug dprintf
43 #endif
44
45 #if DEBUG
46 #define D(x) (x)
47 #else
48 #define D(x) ;
49 #endif
50
51 #define PORT_NAME "sheep_driver installed"
52
53
54 /*
55 * For debugging
56 */
57
58 static int pprintf(const char* format, ...)
59 {
60 port_id PortNum;
61 int len, ret;
62 char Buffer[1024];
63 va_list ap;
64
65 if ((PortNum = find_port("PortLogger")) == B_NAME_NOT_FOUND)
66 return(PortNum);
67 for (len=0; len<1024; len++)
68 Buffer[len]='\0';
69 va_start(ap, format);
70 vsprintf(Buffer, format, ap);
71 ret = write_port(PortNum, 0, Buffer, strlen(Buffer));
72 return ret;
73 }
74
75
76 /*
77 * Page table functions
78 */
79
80 static uint32 *pte_address = 0;
81 static uint32 vsid;
82 static uint32 table_size;
83
84 static status_t map_page(uint32 ea, uint32 ra, uint32 **free_pte, uint32 bits)
85 {
86 int i;
87 int pte_class;
88 uint32 hash1, hash2, api, *pteg1, *pteg2;
89
90 D(bug("Trying to map EA %p -> RA %p\n", ea, ra));
91
92 // Find PTEG addresses for given EA
93 hash1 = (vsid & 0x7ffff) ^ ((ea >> 12) & 0xffff);
94 hash2 = ~hash1 & 0x7ffff;
95 api = (ea >> 22) & 0x3f;
96 pteg1 = (uint32 *)((uint32)pte_address + ((hash1 << 6) & (table_size - 1)));
97 pteg2 = (uint32 *)((uint32)pte_address + ((hash2 << 6) & (table_size - 1)));
98 D(bug("PTEG1 at %p, PTEG2 at %p\n", pteg1, pteg2));
99
100 // Search all 8 PTEs of each PTEG
101 *free_pte = NULL;
102 pte_class = 0;
103 for (i=0; i<8; i++) {
104 D(bug(" found %08lx %08lx\n", pteg1[i*2], pteg1[i*2+1]));
105 if (pteg1[i*2] == (0x80000000 | (vsid << 7) | (pte_class << 6) | api)) {
106 *free_pte = pteg1 + i*2;
107 D(bug(" existing PTE found (PTEG1)\n"));
108 break;
109 } else if (!pteg1[i*2]) {
110 *free_pte = pteg1 + i*2;
111 D(bug(" free PTE found (PTEG1)\n"));
112 break;
113 }
114 }
115 if (*free_pte == NULL) {
116 pte_class = 1;
117 for (i=0; i<8; i++) {
118 D(bug(" found %08lx %08lx\n", pteg2[i*2], pteg2[i*2+1]));
119 if (pteg2[i*2] == (0x80000000 | (vsid << 7) | (pte_class << 6) | api)) {
120 *free_pte = pteg2 + i*2;
121 D(bug(" existing PTE found (PTEG2)\n"));
122 break;
123 } else if (!pteg2[i*2]) {
124 *free_pte = pteg2 + i*2;
125 D(bug(" free PTE found (PTEG2)\n"));
126 break;
127 }
128 }
129 }
130
131 // Remap page
132 if (*free_pte == NULL) {
133 D(bug(" No free PTE found :-(\m"));
134 return B_DEVICE_FULL;
135 } else {
136 (*free_pte)[0] = 0x80000000 | (vsid << 7) | (pte_class << 6) | api;
137 (*free_pte)[1] = ra | bits;
138 D(bug(" written %08lx %08lx to PTE\n", (*free_pte)[0], (*free_pte)[1]));
139 return B_NO_ERROR;
140 }
141 }
142
143 static status_t remap_page(uint32 *free_pte, uint32 ra, uint32 bits)
144 {
145 D(bug("Remapping PTE %p -> RA %p\n", free_pte, ra));
146
147 // Remap page
148 if (free_pte == NULL) {
149 D(bug(" Invalid PTE :-(\n"));
150 return B_BAD_ADDRESS;
151 } else {
152 free_pte[1] = ra | bits;
153 D(bug(" written %08lx %08lx to PTE\n", free_pte[0], free_pte[1]));
154 return B_NO_ERROR;
155 }
156 }
157
158
159 /*
160 * Foward declarations for hook functions
161 */
162
163 static status_t sheep_open(const char *name, uint32 flags, void **cookie);
164 static status_t sheep_close(void *cookie);
165 static status_t sheep_free(void *cookie);
166 static status_t sheep_control(void *cookie, uint32 op, void *data, size_t len);
167 static status_t sheep_read(void *cookie, off_t pos, void *data, size_t *len);
168 static status_t sheep_write(void *cookie, off_t pos, const void *data, size_t *len);
169
170
171 /*
172 * Version of our driver
173 */
174
175 int32 api_version = B_CUR_DRIVER_API_VERSION;
176
177
178 /*
179 * Device_hooks structure - has function pointers to the
180 * various entry points for device operations
181 */
182
183 static device_hooks my_device_hooks = {
184 &sheep_open,
185 &sheep_close,
186 &sheep_free,
187 &sheep_control,
188 &sheep_read,
189 &sheep_write,
190 NULL,
191 NULL,
192 NULL,
193 NULL
194 };
195
196
197 /*
198 * List of device names to be returned by publish_devices()
199 */
200
201 static char *device_name_list[] = {
202 "sheep",
203 0
204 };
205
206
207 /*
208 * Init - do nothing
209 */
210
211 status_t init_hardware(void)
212 {
213 #if DEBUG==2
214 set_dprintf_enabled(true);
215 #endif
216 D(bug("init_hardware()\n"));
217 return B_NO_ERROR;
218 }
219
220 status_t init_driver(void)
221 {
222 D(bug("init_driver()\n"));
223 return B_NO_ERROR;
224 }
225
226 void uninit_driver(void)
227 {
228 D(bug("uninit_driver()\n"));
229 }
230
231
232 /*
233 * publish_devices - return list of device names implemented by this driver
234 */
235
236 const char **publish_devices(void)
237 {
238 return device_name_list;
239 }
240
241
242 /*
243 * find_device - return device hooks for a specific device name
244 */
245
246 device_hooks *find_device(const char *name)
247 {
248 if (!strcmp(name, device_name_list[0]))
249 return &my_device_hooks;
250
251 return NULL;
252 }
253
254
255 /*
256 * sheep_open - hook function for the open call.
257 */
258
259 static status_t sheep_open(const char *name, uint32 flags, void **cookie)
260 {
261 return B_NO_ERROR;
262 }
263
264
265 /*
266 * sheep_close - hook function for the close call.
267 */
268
269 static status_t sheep_close(void *cookie)
270 {
271 return B_NO_ERROR;
272 }
273
274
275 /*
276 * sheep_free - hook function to free the cookie returned
277 * by the open hook. Since the open hook did not return
278 * a cookie, this is a no-op.
279 */
280
281 static status_t sheep_free(void *cookie)
282 {
283 return B_NO_ERROR;
284 }
285
286
287 /*
288 * sheep_control - hook function for the ioctl call
289 */
290
291 static asm void inval_tlb(uint32 ea)
292 {
293 isync
294 tlbie r3
295 sync
296 blr
297 }
298
299 static asm void tlbsync(void)
300 {
301 machine 604
302 tlbsync
303 sync
304 blr
305 }
306
307 static status_t sheep_control(void *cookie, uint32 op, void *data, size_t len)
308 {
309 static void *block;
310 static void *block_aligned;
311 physical_entry pe[2];
312 system_info sysinfo;
313 area_id id;
314 area_info info;
315 cpu_status cpu_st;
316 status_t res;
317 uint32 ra0, ra1;
318 uint32 *free_pte_0, *free_pte_1;
319 int i;
320
321 D(bug("control(%d) data %p, len %08x\n", op, data, len));
322
323 switch (op) {
324 case SHEEP_UP:
325
326 // Already messed up? Then do nothing now
327 if (find_port(PORT_NAME) != B_NAME_NOT_FOUND)
328 return B_NO_ERROR;
329
330 // Get system info
331 get_system_info(&sysinfo);
332
333 // Prepare replacement memory
334 block = malloc(B_PAGE_SIZE * 3);
335 D(bug("3 pages malloc()ed at %p\n", block));
336 block_aligned = (void *)(((uint32)block + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE-1));
337 D(bug("Address aligned to %p\n", block_aligned));
338 res = lock_memory(block_aligned, B_PAGE_SIZE * 2, 0);
339 if (res < 0)
340 return res;
341
342 // Get memory mapping
343 D(bug("Memory locked\n"));
344 res = get_memory_map(block_aligned, B_PAGE_SIZE * 2, pe, 2);
345 D(bug("get_memory_map returned %d\n", res));
346 if (res != B_NO_ERROR)
347 return res;
348
349 // Find PTE table area
350 id = find_area("pte_table");
351 get_area_info(id, &info);
352 pte_address = (uint32 *)info.address;
353 D(bug("PTE table seems to be at %p\n", pte_address));
354 table_size = info.size;
355 D(bug("PTE table size: %dKB\n", table_size / 1024));
356
357 // Disable interrupts
358 cpu_st = disable_interrupts();
359
360 // Find vsid and real addresses of replacement memory
361 for (i=0; i<table_size/8; i++) {
362 if (((uint32)pe[0].address & 0xfffff000)==(pte_address[i*2+1]&0xfffff000)) {
363 D(bug("Found page 0 PtePos %04x V%x VSID %03x H%x API %02x RPN %03x R%1x C%1x WIMG%1x PP%1x \n",
364 i << 2,
365 ((pte_address[i*2]&0x80000000) >> 31),((pte_address[i*2]&0x7fffff80) >> 7),
366 ((pte_address[i*2]&0x00000040) >> 6),(pte_address[i*2] & 0x3f),
367 ((pte_address[i*2+1]&0xfffff000) >> 12),((pte_address[i*2+1]&0x00000100) >> 8),
368 ((pte_address[i*2+1]&0x00000080) >> 7),((pte_address[i*2+1]&0x00000078) >> 3),
369 (pte_address[i*2+1]&0x00000003)));
370 vsid = (pte_address[i*2]&0x7fffff80) >> 7;
371 ra0 = (uint32)pe[0].address & 0xfffff000;
372 }
373 if ((uint32)pe[0].size == B_PAGE_SIZE) {
374 if (((uint32)pe[1].address & 0xfffff000)==(pte_address[i*2+1]&0xfffff000)) {
375 D(bug("Found page 1f PtePos %04x V%x VSID %03x H%x API %02x RPN %03x R%1x C%1x WIMG%1x PP%1x \n",
376 i << 2,
377 ((pte_address[i*2]&0x80000000) >> 31), ((pte_address[i*2]&0x7fffff80) >> 7),
378 ((pte_address[i*2]&0x00000040) >> 6), (pte_address[i*2] & 0x3f),
379 ((pte_address[i*2+1]&0xfffff000) >> 12), ((pte_address[i*2+1]&0x00000100) >> 8),
380 ((pte_address[i*2+1]&0x00000080) >> 7), ((pte_address[i*2+1]&0x00000078) >> 3),
381 (pte_address[i*2+1]&0x00000003)));
382 ra1 = (uint32)pe[1].address & 0xfffff000;
383 }
384 } else {
385 if ((((uint32)pe[0].address + B_PAGE_SIZE) & 0xfffff000)==(pte_address[i*2+1]&0xfffff000)) {
386 D(bug("Found page 1d PtePos %04x V%x VSID %03x H%x API %02x RPN %03x R%1x C%1x WIMG%1x PP%1x \n",
387 i << 2,
388 ((pte_address[i*2]&0x80000000) >> 31), ((pte_address[i*2]&0x7fffff80) >> 7),
389 ((pte_address[i*2]&0x00000040) >> 6), (pte_address[i*2] & 0x3f),
390 ((pte_address[i*2+1]&0xfffff000) >> 12), ((pte_address[i*2+1]&0x00000100) >> 8),
391 ((pte_address[i*2+1]&0x00000080) >> 7), ((pte_address[i*2+1]&0x00000078) >> 3),
392 (pte_address[i*2+1]&0x00000003)));
393 ra1 = ((uint32)pe[0].address + B_PAGE_SIZE) & 0xfffff000;
394 }
395 }
396 }
397
398 // Map low memory for emulator
399 free_pte_0 = NULL;
400 free_pte_1 = NULL;
401 __sync();
402 __isync();
403 inval_tlb(0);
404 inval_tlb(B_PAGE_SIZE);
405 if (sysinfo.cpu_type != B_CPU_PPC_603 && sysinfo.cpu_type != B_CPU_PPC_603e)
406 tlbsync();
407 res = map_page(0, ra0, &free_pte_0, 0x12);
408 if (res == B_NO_ERROR)
409 res = map_page(B_PAGE_SIZE, ra1, &free_pte_1, 0x12);
410 inval_tlb(0);
411 inval_tlb(B_PAGE_SIZE);
412 if (sysinfo.cpu_type != B_CPU_PPC_603 && sysinfo.cpu_type != B_CPU_PPC_603e)
413 tlbsync();
414 __sync();
415 __isync();
416
417 // Restore interrupts
418 restore_interrupts(cpu_st);
419
420 // Create port so we know that messing was successful
421 set_port_owner(create_port(1, PORT_NAME), B_SYSTEM_TEAM);
422 return B_NO_ERROR;
423
424 case SHEEP_DOWN:
425 return B_NO_ERROR;
426
427 default:
428 return B_BAD_VALUE;
429 }
430 }
431
432
433 /*
434 * sheep_read - hook function for the read call
435 */
436
437 static status_t sheep_read(void *cookie, off_t pos, void *data, size_t *len)
438 {
439 void *rom_adr;
440 area_id area;
441 system_info info;
442
443 D(bug("read() pos %Lx, data %p, len %08x\n", pos, data, *len));
444
445 get_system_info(&info);
446 if (info.platform_type == B_BEBOX_PLATFORM) {
447 *len = 0;
448 return B_ERROR;
449 }
450 if (*len != 0x400000 && pos != 0) {
451 *len = 0;
452 return B_BAD_VALUE;
453 }
454 area = map_physical_memory("mac_rom", (void *)0xff000000, 0x00400000, B_ANY_KERNEL_ADDRESS, B_READ_AREA, &rom_adr);
455 D(bug("Mapped ROM to %p, area id %d\n", rom_adr, area));
456 if (area < 0) {
457 *len = 0;
458 return area;
459 }
460 D(bug("Copying ROM\n"));
461 memcpy(data, rom_adr, *len);
462 D(bug("Deleting area\n"));
463 delete_area(area);
464 return B_NO_ERROR;
465 }
466
467
468 /*
469 * sheep_write - hook function for the write call
470 */
471
472 static status_t sheep_write(void *cookie, off_t pos, const void *data, size_t *len)
473 {
474 D(bug("write() pos %Lx, data %p, len %08x\n", pos, data, *len));
475 return B_READ_ONLY_DEVICE;
476 }