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, 6 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

# 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 cebix 1.4 * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer
6     * Basilisk II (C) 1997-2002 Christian Bauer
7 cebix 1.1 *
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 cebix 1.2 #ifdef __i386__
24     #error The sheep driver only runs on PowerPC machines.
25     #endif
26    
27 cebix 1.1 #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     }