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

# User Rev Content
1 cebix 1.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     }