ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/BeOS/SheepDriver/sheep_driver.c
Revision: 1.1
Committed: 2000-11-13T16:59:41Z (23 years, 8 months ago) by cebix
Content type: text/plain
Branch: MAIN
Log Message:
added sources for "sheep" driver and "sheep_net" network add-on

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