Subversion Repository

Parent Directory Parent Directory | Revision Log Revision Log


Revision 87 - (show annotations)
Sun Oct 4 14:32:10 2009 UTC (3 years, 8 months ago) by cjg
File size: 430619 byte(s)
mol: added
1 diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
2 index e1ea4fe..df01158 100644
3 --- a/arch/powerpc/kernel/ppc_ksyms.c
4 +++ b/arch/powerpc/kernel/ppc_ksyms.c
5 @@ -173,6 +173,7 @@ EXPORT_SYMBOL(cacheable_memcpy);
6 #ifdef CONFIG_PPC32
7 EXPORT_SYMBOL(next_mmu_context);
8 EXPORT_SYMBOL(set_context);
9 +EXPORT_SYMBOL_GPL(handle_mm_fault); /* For MOL */
10 #endif
11
12 #ifdef CONFIG_PPC_STD_MMU_32
13 diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
14 index b526596..21ae499 100644
15 --- a/drivers/macintosh/Kconfig
16 +++ b/drivers/macintosh/Kconfig
17 @@ -253,4 +253,10 @@ config PMAC_RACKMETER
18 This driver provides some support to control the front panel
19 blue LEDs "vu-meter" of the XServer macs.
20
21 +config MACONLINUX
22 + tristate "Mac on Linux kernel module"
23 + depends on PPC32 && PPC_PMAC && MODULES && NET
24 + help
25 + call helpdesk
26 +
27 endif # MACINTOSH_DRIVERS
28 diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
29 index e3132ef..6548c56 100644
30 --- a/drivers/macintosh/Makefile
31 +++ b/drivers/macintosh/Makefile
32 @@ -4,6 +4,8 @@
33
34 # Each configuration option enables a list of files.
35
36 +obj-$(CONFIG_MACONLINUX) += mol/
37 +
38 obj-$(CONFIG_PPC_PMAC) += macio_asic.o macio_sysfs.o
39
40 obj-$(CONFIG_PMAC_MEDIABAY) += mediabay.o
41 diff --git a/drivers/macintosh/mol/Makefile b/drivers/macintosh/mol/Makefile
42 new file mode 100644
43 index 0000000..e649e89
44 --- /dev/null
45 +++ b/drivers/macintosh/mol/Makefile
46 @@ -0,0 +1,60 @@
47 +
48 +MOL_OBJS = \
49 + _fault.o \
50 + _dev.o \
51 + _misc.o \
52 + _mmu.o \
53 + _hostirq.o \
54 + init.o \
55 + hash.o \
56 + emu.o \
57 + mmu.o \
58 + mmu_fb.o \
59 + mmu_io.o \
60 + mmu_tracker.o \
61 + skiplist.o \
62 + mtable.o \
63 + fault.o \
64 + context.o \
65 + ptaccess.o \
66 + misc.o \
67 + _traps.o \
68 + actions.o
69 +
70 +
71 +mol-objs := $(MOL_OBJS)
72 +obj-m := mol.o sheep.o
73 +
74 +MOL_SRC_INCLUDE_DIR := $(srctree)/$(src)/include
75 +MOL_OBJ_INCLUDE_DIR := $(obj)/include
76 +MOL_ASMFLAGS := $(ASMFLAGS) $(INCLUDES) -D__ASSEMBLY__ -D__KERNEL__
77 +EXTRA_CFLAGS := -I$(MOL_SRC_INCLUDE_DIR) -I$(MOL_OBJ_INCLUDE_DIR)
78 +
79 +$(obj)/asm_offsets.c: $(srctree)/$(src)/asm_offsets.c $(MOL_OBJ_INCLUDE_DIR)/asm_offsets.h
80 + rm -f $@
81 + cat $(srctree)/$(src)/asm_offsets.c $(MOL_OBJ_INCLUDE_DIR)/asm_offsets.h > $@
82 +
83 +$(obj)/_traps.o: $(MOL_OBJ_INCLUDE_DIR)/asm_offsets.h $(srctree)/$(src)/asm-files/*.S
84 +
85 +$(obj)/_%.o: $(src)/asm-files/%.S
86 + echo " AS [x] $@"
87 + rm -f $@ $@.s
88 + $(CPP) $(LINUXINCLUDE) -I$(MOL_SRC_INCLUDE_DIR) -I$(MOL_OBJ_INCLUDE_DIR) $(MOL_ASMFLAGS) $< | m4 > $@.m4
89 + cat $@.m4 > $@.s
90 + $(AS) $@.s $(AS_FLAGS) -o $@
91 + rm -f $@.s $@.m4
92 +
93 +$(addprefix $(obj)/,$(MOL_OBJS)): $(obj)/%.o: $(MOL_OBJ_INCLUDE_DIR)/kconfig.h
94 +$(MOL_OBJ_INCLUDE_DIR)/kconfig.h:
95 + mkdir -vp $(MOL_OBJ_INCLUDE_DIR)
96 + rm -fv $@
97 + echo "/* nothing */" > $@
98 +
99 +$(MOL_OBJ_INCLUDE_DIR)/asm_offsets.h: $(MOL_SRC_INCLUDE_DIR)/archinclude.h $(MOL_SRC_INCLUDE_DIR)/kernel_vars.h $(MOL_SRC_INCLUDE_DIR)/mac_registers.h $(MOL_OBJ_INCLUDE_DIR)/kconfig.h
100 +$(MOL_OBJ_INCLUDE_DIR)/asm_offsets.h: $(srctree)/$(src)/asm_offsets.c $(MOL_SRC_INCLUDE_DIR)/asm_offsets.inc
101 + rm -fv $(obj)/tmp-offsets.c $@ ; cat $^ > $(obj)/tmp-offsets.c
102 + $(CC) -D__KERNEL__ $(CFLAGS) $(LINUXINCLUDE) -I$(MOL_SRC_INCLUDE_DIR) -I$(MOL_OBJ_INCLUDE_DIR) -Wall -S $(obj)/tmp-offsets.c
103 + echo "/* WARNING! Automatically generated from 'shared/asm_offsets.c' - DO NOT EDIT! */" > $@
104 + grep '^#' tmp-offsets.s >> $@
105 + rm -fv $(obj)/tmp-offsets.*
106 +
107 diff --git a/drivers/macintosh/mol/_dev.c b/drivers/macintosh/mol/_dev.c
108 new file mode 100644
109 index 0000000..524624c
110 --- /dev/null
111 +++ b/drivers/macintosh/mol/_dev.c
112 @@ -0,0 +1,376 @@
113 +/*
114 + * Creation Date: <2003/08/20 17:31:44 samuel>
115 + * Time-stamp: <2004/02/14 14:43:13 samuel>
116 + *
117 + * <dev.c>
118 + *
119 + * misc device
120 + *
121 + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
122 + *
123 + * This program is free software; you can redistribute it and/or
124 + * modify it under the terms of the GNU General Public License
125 + * version 2
126 + *
127 + */
128 +
129 +#include "archinclude.h"
130 +#include <linux/module.h>
131 +#include <linux/miscdevice.h>
132 +#include <linux/spinlock.h>
133 +#include <linux/init.h>
134 +#include <linux/interrupt.h>
135 +#include <linux/irq.h>
136 +#include <linux/bitops.h>
137 +#include <asm/prom.h>
138 +#include <asm/machdep.h>
139 +#include <asm/atomic.h>
140 +#include "kernel_vars.h"
141 +#include "mol-ioctl.h"
142 +#include "version.h"
143 +#include "mmu.h"
144 +#include "misc.h"
145 +#include "mtable.h"
146 +#include "atomic.h"
147 +
148 +MODULE_AUTHOR("Samuel Rydh <samuel@ibrium.se>");
149 +MODULE_DESCRIPTION("Mac-on-Linux kernel module");
150 +MODULE_LICENSE("GPL");
151 +
152 +static DECLARE_MUTEX( initmutex );
153 +static int opencnt;
154 +
155 +
156 +/************************************************************************/
157 +/* misc */
158 +/************************************************************************/
159 +
160 +#ifdef CONFIG_SMP
161 +#define HAS_SMP 1
162 +
163 +static void
164 +dummy_ipi( void *dummy )
165 +{
166 + /* we don't need to _do_ anything, the exception itself is sufficient */
167 +}
168 +static inline void
169 +send_ipi( void )
170 +{
171 + smp_call_function( dummy_ipi, NULL, 1, 0 );
172 +}
173 +#else /* CONFIG_SMP */
174 +
175 +#define HAS_SMP 0
176 +#define send_ipi() do {} while(0)
177 +
178 +#endif /* CONFIG_SMP */
179 +
180 +
181 +static int
182 +find_physical_rom( int *base, int *size )
183 +{
184 +#ifndef CONFIG_AMIGAONE
185 + struct device_node *dn;
186 + int len, *p;
187 + int by_type = 0;
188 +
189 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
190 + if( !(dn=find_devices("boot-rom")) && !(dn=find_type_devices("rom")) )
191 + return 0;
192 +#else
193 + if (! (dn = of_find_node_by_name(NULL, "boot-rom"))) {
194 + by_type = 1;
195 + if (! (dn = of_find_node_by_type(NULL, "rom")))
196 + return 0;
197 + }
198 +#endif /* < Linux 2.6.21 */
199 + do {
200 + if( !(p=of_get_property(dn, "reg", &len)) || len != sizeof(int[2]) ) {
201 + of_node_put(dn);
202 + return 0;
203 + }
204 + if( (unsigned int)(0xfff00100 - p[0]) < (unsigned int)p[1] ) {
205 + *base = p[0];
206 + *size = p[1];
207 + of_node_put(dn);
208 + return 1;
209 + }
210 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
211 + dn = dn->next;
212 +#else
213 + dn = by_type ? of_find_node_by_type(dn, "rom") :
214 + of_find_node_by_name(dn, "boot-rom");
215 +#endif /* < Linux 2.6.21 */
216 + } while( dn );
217 +#endif /* CONFIG_AMIGA_ONE */
218 + return 0;
219 +}
220 +
221 +static int
222 +get_info( mol_kmod_info_t *user_retinfo, int size )
223 +{
224 + mol_kmod_info_t info;
225 +
226 + memset( &info, 0, sizeof(info) );
227 + asm volatile("mfpvr %0" : "=r" (info.pvr) : );
228 + info.version = MOL_VERSION;
229 + find_physical_rom( &info.rombase, &info.romsize );
230 + info.tb_freq = HZ * tb_ticks_per_jiffy;
231 + info.smp_kernel = HAS_SMP;
232 +
233 + if( (uint)size > sizeof(info) )
234 + size = sizeof(info);
235 +
236 + if( copy_to_user(user_retinfo, &info, size) )
237 + return -EFAULT;
238 + return 0;
239 +}
240 +
241 +
242 +void
243 +prevent_mod_unload( void )
244 +{
245 +#ifndef LINUX_26
246 + MOD_INC_USE_COUNT;
247 +#else
248 + __module_get( THIS_MODULE );
249 +#endif
250 +}
251 +
252 +int
253 +get_irqs( kernel_vars_t *kv, irq_bitfield_t *irq_info_p )
254 +{
255 + irq_bitfield_t irq_mask;
256 + int i;
257 +
258 + /* copy the interrupt mask from userspace */
259 + if (copy_from_user(&irq_mask, irq_info_p, sizeof(irq_mask)))
260 + return -EFAULT;
261 +
262 + /* see which of the mapped interrupts need to be enabled */
263 + for (i = 0; i < NR_HOST_IRQS; i++) {
264 + if (check_bit_mol(i, (char *) kv->mregs.mapped_irqs.irqs)
265 + && check_bit_mol(i, (char *) irq_mask.irqs)
266 + && check_bit_mol(i, (char *) kv->mregs.active_irqs.irqs)) {
267 + if (test_and_clear_bit(i, kv->mregs.active_irqs.irqs))
268 + atomic_dec_mol((mol_atomic_t *) &(kv->mregs.hostirq_active_cnt));
269 + enable_irq(i);
270 + }
271 + }
272 +
273 + /* if one of the enabled interrupts was pending, it should have fired
274 + * now, updating active_irqs */
275 + if (copy_to_user(irq_info_p, &(kv->mregs.active_irqs), sizeof(kv->mregs.active_irqs)))
276 + return -EFAULT;
277 +
278 + return 0;
279 +}
280 +
281 +/************************************************************************/
282 +/* ioctl */
283 +/************************************************************************/
284 +
285 +static int
286 +debugger_op( kernel_vars_t *kv, dbg_op_params_t *upb )
287 +{
288 + dbg_op_params_t pb;
289 + int ret;
290 +
291 + if( copy_from_user(&pb, upb, sizeof(pb)) )
292 + return -EFAULT;
293 +
294 + switch( pb.operation ) {
295 + case DBG_OP_GET_PHYS_PAGE:
296 + ret = dbg_get_linux_page( pb.ea, &pb.ret.page );
297 + break;
298 + default:
299 + ret = do_debugger_op( kv, &pb );
300 + break;
301 + }
302 +
303 + if( copy_to_user(upb, &pb, sizeof(pb)) )
304 + return -EFAULT;
305 + return ret;
306 +}
307 +
308 +static int
309 +arch_handle_ioctl( kernel_vars_t *kv, int cmd, int p1, int p2, int p3 )
310 +{
311 + char *rompage;
312 + int ret = -EFAULT;
313 +
314 + switch( cmd ) {
315 + case MOL_IOCTL_GET_IRQS:
316 + return get_irqs( kv, (irq_bitfield_t *) p1 );
317 +
318 + case MOL_IOCTL_GET_DIRTY_FBLINES: /* short *retbuf, int size -- npairs */
319 + if( compat_verify_area(VERIFY_WRITE, (short*)p1, p2) )
320 + break;
321 + ret = get_dirty_fb_lines( kv, (short*)p1, p2 );
322 + break;
323 +
324 + case MOL_IOCTL_DEBUGGER_OP:
325 + ret = debugger_op( kv, (dbg_op_params_t*)p1 );
326 + break;
327 +
328 + case MOL_IOCTL_GRAB_IRQ:
329 + ret = grab_host_irq(kv, p1);
330 + break;
331 +
332 + case MOL_IOCTL_RELEASE_IRQ:
333 + ret = release_host_irq(kv, p1);
334 + break;
335 +
336 + case MOL_IOCTL_COPY_LAST_ROMPAGE: /* p1 = dest */
337 + ret = -ENODEV;
338 + if( (rompage=ioremap(0xfffff000, 0x1000)) ) {
339 + ret = copy_to_user( (char*)p1, rompage, 0x1000 );
340 + iounmap( rompage );
341 + }
342 + break;
343 +
344 + case MOL_IOCTL_SET_RAM: /* void ( char *lvbase, size_t size ) */
345 + if( compat_verify_area(VERIFY_WRITE, (char*)p1, p2) )
346 + break;
347 + ret = 0;
348 + kv->mmu.userspace_ram_base = p1;
349 + kv->mmu.ram_size = p2;
350 + mtable_tune_alloc_limit( kv, p2/(1024 * 1024) );
351 + break;
352 +
353 + case MOL_IOCTL_GET_MREGS_PHYS:
354 + ret = virt_to_phys( &kv->mregs );
355 + break;
356 +
357 + default:
358 + ret = handle_ioctl( kv, cmd, p1, p2, p3 );
359 + break;
360 + }
361 + return ret;
362 +}
363 +
364 +
365 +/************************************************************************/
366 +/* device interface */
367 +/************************************************************************/
368 +
369 +static int
370 +mol_open( struct inode *inode, struct file *file )
371 +{
372 + int ret=0;
373 +
374 + if( !(file->f_mode & FMODE_READ) )
375 + return -EPERM;
376 +
377 + down( &initmutex );
378 + if( !opencnt++ ) {
379 + if( common_init() ) {
380 + ret = -ENOMEM;
381 + opencnt = 0;
382 + }
383 + }
384 + up( &initmutex );
385 +
386 + file->private_data = NULL;
387 + return ret;
388 +}
389 +
390 +static int
391 +mol_release( struct inode *inode, struct file *file )
392 +{
393 + kernel_vars_t *kv = (kernel_vars_t*)file->private_data;
394 +
395 + down( &initmutex );
396 + if( kv )
397 + destroy_session( kv->session_index );
398 +
399 + if( !--opencnt )
400 + common_cleanup();
401 + up( &initmutex );
402 + return 0;
403 +}
404 +
405 +static int
406 +mol_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg )
407 +{
408 + mol_ioctl_pb_t pb;
409 + kernel_vars_t *kv;
410 + int ret;
411 + uint session;
412 +
413 + /* fast path */
414 + if( cmd == MOL_IOCTL_SMP_SEND_IPI ) {
415 + send_ipi();
416 + return 0;
417 + }
418 +
419 + if( copy_from_user(&pb, (void*)arg, sizeof(pb)) )
420 + return -EFAULT;
421 +
422 + switch( cmd ) {
423 + case MOL_IOCTL_GET_INFO:
424 + return get_info( (mol_kmod_info_t*)pb.arg1, pb.arg2 );
425 +
426 + case MOL_IOCTL_CREATE_SESSION:
427 + if( !(file->f_mode & FMODE_WRITE) || !capable(CAP_SYS_ADMIN) )
428 + return -EPERM;
429 + ret = -EINVAL;
430 + down( &initmutex );
431 + if( (uint)pb.arg1 < MAX_NUM_SESSIONS && !file->private_data ) {
432 + if( !(ret=initialize_session(pb.arg1)) ) {
433 + kv = g_sesstab->kvars[pb.arg1];
434 + init_MUTEX( &kv->ioctl_sem );
435 + file->private_data = kv;
436 + }
437 + }
438 + up( &initmutex );
439 + return ret;
440 +
441 + case MOL_IOCTL_DBG_COPY_KVARS:
442 + session = pb.arg1;
443 + ret = -EINVAL;
444 + down( &initmutex );
445 + if( session < MAX_NUM_SESSIONS && (kv=g_sesstab->kvars[session]) )
446 + ret = copy_to_user( (char*)pb.arg2, kv, sizeof(*kv) );
447 + up( &initmutex );
448 + return ret;
449 + }
450 +
451 + if( !(kv=(kernel_vars_t*)file->private_data) )
452 + return -EINVAL;
453 +
454 + down( &kv->ioctl_sem );
455 + ret = arch_handle_ioctl( kv, cmd, pb.arg1, pb.arg2, pb.arg3 );
456 + up( &kv->ioctl_sem );
457 +
458 + return ret;
459 +}
460 +
461 +static struct file_operations mol_device_fops = {
462 + .owner = THIS_MODULE,
463 + .open = mol_open,
464 + .release = mol_release,
465 + .ioctl = mol_ioctl,
466 +// .poll = mol_poll,
467 +// .mmap: = mol_mmap,
468 +};
469 +
470 +static struct miscdevice mol_device = {
471 + MISC_DYNAMIC_MINOR, "mol", &mol_device_fops
472 +};
473 +
474 +static int __init
475 +dev_register( void )
476 +{
477 + printk("MOL %s kernel module loaded\n", MOL_RELEASE );
478 + return misc_register( &mol_device );
479 +}
480 +
481 +static void __exit
482 +dev_unregister( void )
483 +{
484 + misc_deregister( &mol_device );
485 +}
486 +
487 +module_init( dev_register );
488 +module_exit( dev_unregister );
489 diff --git a/drivers/macintosh/mol/_dev.c.rej b/drivers/macintosh/mol/_dev.c.rej
490 new file mode 100644
491 index 0000000..b19f723
492 --- /dev/null
493 +++ b/drivers/macintosh/mol/_dev.c.rej
494 @@ -0,0 +1,379 @@
495 +***************
496 +*** 0 ****
497 +--- 1,376 ----
498 ++ /*
499 ++ * Creation Date: <2003/08/20 17:31:44 samuel>
500 ++ * Time-stamp: <2004/02/14 14:43:13 samuel>
501 ++ *
502 ++ * <dev.c>
503 ++ *
504 ++ * misc device
505 ++ *
506 ++ * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
507 ++ *
508 ++ * This program is free software; you can redistribute it and/or
509 ++ * modify it under the terms of the GNU General Public License
510 ++ * version 2
511 ++ *
512 ++ */
513 ++
514 ++ #include "archinclude.h"
515 ++ #include <linux/module.h>
516 ++ #include <linux/miscdevice.h>
517 ++ #include <linux/spinlock.h>
518 ++ #include <linux/init.h>
519 ++ #include <linux/interrupt.h>
520 ++ #include <linux/irq.h>
521 ++ #include <linux/bitops.h>
522 ++ #include <asm/prom.h>
523 ++ #include <asm/machdep.h>
524 ++ #include <asm/atomic.h>
525 ++ #include "kernel_vars.h"
526 ++ #include "mol-ioctl.h"
527 ++ #include "version.h"
528 ++ #include "mmu.h"
529 ++ #include "misc.h"
530 ++ #include "mtable.h"
531 ++ #include "atomic.h"
532 ++
533 ++ MODULE_AUTHOR("Samuel Rydh <samuel@ibrium.se>");
534 ++ MODULE_DESCRIPTION("Mac-on-Linux kernel module");
535 ++ MODULE_LICENSE("GPL");
536 ++
537 ++ static DECLARE_MUTEX( initmutex );
538 ++ static int opencnt;
539 ++
540 ++
541 ++ /************************************************************************/
542 ++ /* misc */
543 ++ /************************************************************************/
544 ++
545 ++ #ifdef CONFIG_SMP
546 ++ #define HAS_SMP 1
547 ++
548 ++ static void
549 ++ dummy_ipi( void *dummy )
550 ++ {
551 ++ /* we don't need to _do_ anything, the exception itself is sufficient */
552 ++ }
553 ++ static inline void
554 ++ send_ipi( void )
555 ++ {
556 ++ smp_call_function( dummy_ipi, NULL, 1, 0 );
557 ++ }
558 ++ #else /* CONFIG_SMP */
559 ++
560 ++ #define HAS_SMP 0
561 ++ #define send_ipi() do {} while(0)
562 ++
563 ++ #endif /* CONFIG_SMP */
564 ++
565 ++
566 ++ static int
567 ++ find_physical_rom( int *base, int *size )
568 ++ {
569 ++ #ifndef CONFIG_AMIGAONE
570 ++ struct device_node *dn;
571 ++ int len, *p;
572 ++ int by_type = 0;
573 ++
574 ++ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
575 ++ if( !(dn=find_devices("boot-rom")) && !(dn=find_type_devices("rom")) )
576 ++ return 0;
577 ++ #else
578 ++ if (! (dn = of_find_node_by_name(NULL, "boot-rom"))) {
579 ++ by_type = 1;
580 ++ if (! (dn = of_find_node_by_type(NULL, "rom")))
581 ++ return 0;
582 ++ }
583 ++ #endif /* < Linux 2.6.21 */
584 ++ do {
585 ++ if( !(p=(int*)get_property(dn, "reg", &len)) || len != sizeof(int[2]) ) {
586 ++ of_node_put(dn);
587 ++ return 0;
588 ++ }
589 ++ if( (unsigned int)(0xfff00100 - p[0]) < (unsigned int)p[1] ) {
590 ++ *base = p[0];
591 ++ *size = p[1];
592 ++ of_node_put(dn);
593 ++ return 1;
594 ++ }
595 ++ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
596 ++ dn = dn->next;
597 ++ #else
598 ++ dn = by_type ? of_find_node_by_type(dn, "rom") :
599 ++ of_find_node_by_name(dn, "boot-rom");
600 ++ #endif /* < Linux 2.6.21 */
601 ++ } while( dn );
602 ++ #endif /* CONFIG_AMIGA_ONE */
603 ++ return 0;
604 ++ }
605 ++
606 ++ static int
607 ++ get_info( mol_kmod_info_t *user_retinfo, int size )
608 ++ {
609 ++ mol_kmod_info_t info;
610 ++
611 ++ memset( &info, 0, sizeof(info) );
612 ++ asm volatile("mfpvr %0" : "=r" (info.pvr) : );
613 ++ info.version = MOL_VERSION;
614 ++ find_physical_rom( &info.rombase, &info.romsize );
615 ++ info.tb_freq = HZ * tb_ticks_per_jiffy;
616 ++ info.smp_kernel = HAS_SMP;
617 ++
618 ++ if( (uint)size > sizeof(info) )
619 ++ size = sizeof(info);
620 ++
621 ++ if( copy_to_user(user_retinfo, &info, size) )
622 ++ return -EFAULT;
623 ++ return 0;
624 ++ }
625 ++
626 ++
627 ++ void
628 ++ prevent_mod_unload( void )
629 ++ {
630 ++ #ifndef LINUX_26
631 ++ MOD_INC_USE_COUNT;
632 ++ #else
633 ++ __module_get( THIS_MODULE );
634 ++ #endif
635 ++ }
636 ++
637 ++ int
638 ++ get_irqs( kernel_vars_t *kv, irq_bitfield_t *irq_info_p )
639 ++ {
640 ++ irq_bitfield_t irq_mask;
641 ++ int i;
642 ++
643 ++ /* copy the interrupt mask from userspace */
644 ++ if (copy_from_user(&irq_mask, irq_info_p, sizeof(irq_mask)))
645 ++ return -EFAULT;
646 ++
647 ++ /* see which of the mapped interrupts need to be enabled */
648 ++ for (i = 0; i < NR_HOST_IRQS; i++) {
649 ++ if (check_bit_mol(i, (char *) kv->mregs.mapped_irqs.irqs)
650 ++ && check_bit_mol(i, (char *) irq_mask.irqs)
651 ++ && check_bit_mol(i, (char *) kv->mregs.active_irqs.irqs)) {
652 ++ if (test_and_clear_bit(i, kv->mregs.active_irqs.irqs))
653 ++ atomic_dec_mol((mol_atomic_t *) &(kv->mregs.hostirq_active_cnt));
654 ++ enable_irq(i);
655 ++ }
656 ++ }
657 ++
658 ++ /* if one of the enabled interrupts was pending, it should have fired
659 ++ * now, updating active_irqs */
660 ++ if (copy_to_user(irq_info_p, &(kv->mregs.active_irqs), sizeof(kv->mregs.active_irqs)))
661 ++ return -EFAULT;
662 ++
663 ++ return 0;
664 ++ }
665 ++
666 ++ /************************************************************************/
667 ++ /* ioctl */
668 ++ /************************************************************************/
669 ++
670 ++ static int
671 ++ debugger_op( kernel_vars_t *kv, dbg_op_params_t *upb )
672 ++ {
673 ++ dbg_op_params_t pb;
674 ++ int ret;
675 ++
676 ++ if( copy_from_user(&pb, upb, sizeof(pb)) )
677 ++ return -EFAULT;
678 ++
679 ++ switch( pb.operation ) {
680 ++ case DBG_OP_GET_PHYS_PAGE:
681 ++ ret = dbg_get_linux_page( pb.ea, &pb.ret.page );
682 ++ break;
683 ++ default:
684 ++ ret = do_debugger_op( kv, &pb );
685 ++ break;
686 ++ }
687 ++
688 ++ if( copy_to_user(upb, &pb, sizeof(pb)) )
689 ++ return -EFAULT;
690 ++ return ret;
691 ++ }
692 ++
693 ++ static int
694 ++ arch_handle_ioctl( kernel_vars_t *kv, int cmd, int p1, int p2, int p3 )
695 ++ {
696 ++ char *rompage;
697 ++ int ret = -EFAULT;
698 ++
699 ++ switch( cmd ) {
700 ++ case MOL_IOCTL_GET_IRQS:
701 ++ return get_irqs( kv, (irq_bitfield_t *) p1 );
702 ++
703 ++ case MOL_IOCTL_GET_DIRTY_FBLINES: /* short *retbuf, int size -- npairs */
704 ++ if( compat_verify_area(VERIFY_WRITE, (short*)p1, p2) )
705 ++ break;
706 ++ ret = get_dirty_fb_lines( kv, (short*)p1, p2 );
707 ++ break;
708 ++
709 ++ case MOL_IOCTL_DEBUGGER_OP:
710 ++ ret = debugger_op( kv, (dbg_op_params_t*)p1 );
711 ++ break;
712 ++
713 ++ case MOL_IOCTL_GRAB_IRQ:
714 ++ ret = grab_host_irq(kv, p1);
715 ++ break;
716 ++
717 ++ case MOL_IOCTL_RELEASE_IRQ:
718 ++ ret = release_host_irq(kv, p1);
719 ++ break;
720 ++
721 ++ case MOL_IOCTL_COPY_LAST_ROMPAGE: /* p1 = dest */
722 ++ ret = -ENODEV;
723 ++ if( (rompage=ioremap(0xfffff000, 0x1000)) ) {
724 ++ ret = copy_to_user( (char*)p1, rompage, 0x1000 );
725 ++ iounmap( rompage );
726 ++ }
727 ++ break;
728 ++
729 ++ case MOL_IOCTL_SET_RAM: /* void ( char *lvbase, size_t size ) */
730 ++ if( compat_verify_area(VERIFY_WRITE, (char*)p1, p2) )
731 ++ break;
732 ++ ret = 0;
733 ++ kv->mmu.userspace_ram_base = p1;
734 ++ kv->mmu.ram_size = p2;
735 ++ mtable_tune_alloc_limit( kv, p2/(1024 * 1024) );
736 ++ break;
737 ++
738 ++ case MOL_IOCTL_GET_MREGS_PHYS:
739 ++ ret = virt_to_phys( &kv->mregs );
740 ++ break;
741 ++
742 ++ default:
743 ++ ret = handle_ioctl( kv, cmd, p1, p2, p3 );
744 ++ break;
745 ++ }
746 ++ return ret;
747 ++ }
748 ++
749 ++
750 ++ /************************************************************************/
751 ++ /* device interface */
752 ++ /************************************************************************/
753 ++
754 ++ static int
755 ++ mol_open( struct inode *inode, struct file *file )
756 ++ {
757 ++ int ret=0;
758 ++
759 ++ if( !(file->f_mode & FMODE_READ) )
760 ++ return -EPERM;
761 ++
762 ++ down( &initmutex );
763 ++ if( !opencnt++ ) {
764 ++ if( common_init() ) {
765 ++ ret = -ENOMEM;
766 ++ opencnt = 0;
767 ++ }
768 ++ }
769 ++ up( &initmutex );
770 ++
771 ++ file->private_data = NULL;
772 ++ return ret;
773 ++ }
774 ++
775 ++ static int
776 ++ mol_release( struct inode *inode, struct file *file )
777 ++ {
778 ++ kernel_vars_t *kv = (kernel_vars_t*)file->private_data;
779 ++
780 ++ down( &initmutex );
781 ++ if( kv )
782 ++ destroy_session( kv->session_index );
783 ++
784 ++ if( !--opencnt )
785 ++ common_cleanup();
786 ++ up( &initmutex );
787 ++ return 0;
788 ++ }
789 ++
790 ++ static int
791 ++ mol_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg )
792 ++ {
793 ++ mol_ioctl_pb_t pb;
794 ++ kernel_vars_t *kv;
795 ++ int ret;
796 ++ uint session;
797 ++
798 ++ /* fast path */
799 ++ if( cmd == MOL_IOCTL_SMP_SEND_IPI ) {
800 ++ send_ipi();
801 ++ return 0;
802 ++ }
803 ++
804 ++ if( copy_from_user(&pb, (void*)arg, sizeof(pb)) )
805 ++ return -EFAULT;
806 ++
807 ++ switch( cmd ) {
808 ++ case MOL_IOCTL_GET_INFO:
809 ++ return get_info( (mol_kmod_info_t*)pb.arg1, pb.arg2 );
810 ++
811 ++ case MOL_IOCTL_CREATE_SESSION:
812 ++ if( !(file->f_mode & FMODE_WRITE) || !capable(CAP_SYS_ADMIN) )
813 ++ return -EPERM;
814 ++ ret = -EINVAL;
815 ++ down( &initmutex );
816 ++ if( (uint)pb.arg1 < MAX_NUM_SESSIONS && !file->private_data ) {
817 ++ if( !(ret=initialize_session(pb.arg1)) ) {
818 ++ kv = g_sesstab->kvars[pb.arg1];
819 ++ init_MUTEX( &kv->ioctl_sem );
820 ++ file->private_data = kv;
821 ++ }
822 ++ }
823 ++ up( &initmutex );
824 ++ return ret;
825 ++
826 ++ case MOL_IOCTL_DBG_COPY_KVARS:
827 ++ session = pb.arg1;
828 ++ ret = -EINVAL;
829 ++ down( &initmutex );
830 ++ if( session < MAX_NUM_SESSIONS && (kv=g_sesstab->kvars[session]) )
831 ++ ret = copy_to_user( (char*)pb.arg2, kv, sizeof(*kv) );
832 ++ up( &initmutex );
833 ++ return ret;
834 ++ }
835 ++
836 ++ if( !(kv=(kernel_vars_t*)file->private_data) )
837 ++ return -EINVAL;
838 ++
839 ++ down( &kv->ioctl_sem );
840 ++ ret = arch_handle_ioctl( kv, cmd, pb.arg1, pb.arg2, pb.arg3 );
841 ++ up( &kv->ioctl_sem );
842 ++
843 ++ return ret;
844 ++ }
845 ++
846 ++ static struct file_operations mol_device_fops = {
847 ++ .owner = THIS_MODULE,
848 ++ .open = mol_open,
849 ++ .release = mol_release,
850 ++ .ioctl = mol_ioctl,
851 ++ // .poll = mol_poll,
852 ++ // .mmap: = mol_mmap,
853 ++ };
854 ++
855 ++ static struct miscdevice mol_device = {
856 ++ MISC_DYNAMIC_MINOR, "mol", &mol_device_fops
857 ++ };
858 ++
859 ++ static int __init
860 ++ dev_register( void )
861 ++ {
862 ++ printk("MOL %s kernel module loaded\n", MOL_RELEASE );
863 ++ return misc_register( &mol_device );
864 ++ }
865 ++
866 ++ static void __exit
867 ++ dev_unregister( void )
868 ++ {
869 ++ misc_deregister( &mol_device );
870 ++ }
871 ++
872 ++ module_init( dev_register );
873 ++ module_exit( dev_unregister );
874 diff --git a/drivers/macintosh/mol/_fault.c b/drivers/macintosh/mol/_fault.c
875 new file mode 100644
876 index 0000000..10d2978
877 --- /dev/null
878 +++ b/drivers/macintosh/mol/_fault.c
879 @@ -0,0 +1,159 @@
880 +/*
881 + * Creation Date: <2002/06/08 21:01:54 samuel>
882 + * Time-stamp: <2004/02/19 11:54:33 samuel>
883 + *
884 + * <fault.c>
885 + *
886 + * Linux part
887 + *
888 + * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se)
889 + *
890 + * This program is free software; you can redistribute it and/or
891 + * modify it under the terms of the GNU General Public License
892 + * as published by the Free Software Foundation
893 + *
894 + */
895 +
896 +#include "archinclude.h"
897 +#include "alloc.h"
898 +#include "kernel_vars.h"
899 +#include "mmu.h"
900 +#include "mmu_contexts.h"
901 +#include "asmfuncs.h"
902 +#include "emu.h"
903 +#include "misc.h"
904 +#include "rvec.h"
905 +#include "performance.h"
906 +#include "mol-ioctl.h"
907 +#include "mtable.h"
908 +
909 +#ifdef CONFIG_HIGHPTE
910 +#error "MOL is currently incompatible with CONFIG_HIGHPTE"
911 +#endif
912 +
913 +static inline ulong
914 +fix_pte( ulong *p, ulong set, ulong flags )
915 +{
916 + unsigned long ret, tmp;
917 +
918 + __asm__ __volatile__("\n"
919 + "1: lwarx %0,0,%3 \n"
920 + " andc. %1,%5,%0 \n"
921 + " addi %1,0,0 \n"
922 + " bne- 2f \n"
923 + " or %1,%0,%4 \n"
924 + " stwcx. %1,0,%3 \n"
925 + " bne- 1b \n"
926 + "2: \n"
927 + : "=&r" (tmp), "=&r" (ret), "=m" (*p)
928 + : "r" (p), "r" (set), "r" (flags), "m" (*p)
929 + : "cc" );
930 + return ret;
931 +}
932 +
933 +/*
934 + * Get physical page corresponding to linux virtual address. Invokes linux page
935 + * fault handler if the page is missing. This function never fails since we
936 + * know there is a valid mapping...
937 + */
938 +#define PAGE_BITS_WRITE (_PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HASHPTE )
939 +#define PAGE_BITS_READ (_PAGE_ACCESSED | _PAGE_HASHPTE )
940 +
941 +ulong
942 +get_phys_page( kernel_vars_t *kv, ulong va, int request_rw )
943 +{
944 + char *lvptr = (char*)va;
945 + ulong lpte, uptr, *ptr;
946 + ulong flags;
947 + struct mm_struct *mm;
948 + struct vm_area_struct *vma;
949 +
950 + /* pte bits that must be set */
951 + flags = request_rw ? (_PAGE_USER | _PAGE_RW | _PAGE_PRESENT)
952 + : (_PAGE_USER | _PAGE_PRESENT);
953 +
954 + uptr = ((ulong*)current->thread.pgdir)[va>>22]; /* top 10 bits */
955 + ptr = (ulong*)(uptr & ~0xfff);
956 + if( !ptr )
957 + goto no_page;
958 +#ifdef LINUX_26
959 + ptr = phys_to_virt( (int)ptr );
960 +#endif
961 + ptr = ptr + ((va>>12) & 0x3ff); /* next 10 bits */
962 +
963 + /* this allows us to keep track of this page until we have
964 + * added a full mtable entry for it. The reservation is lost if
965 + * a TLB invalidation occurs.
966 + */
967 + make_lvptr_reservation( kv, lvptr );
968 +
969 + /* we atomically set _PAGE_HASHPTE after checking PAGE_PRESENT and PAGE_RW.
970 + * We are then guaranteed to be notified about a TLB invalidation through the
971 + * flush_hash_page hook.
972 + */
973 + lpte = fix_pte( ptr, (request_rw? PAGE_BITS_WRITE : PAGE_BITS_READ), flags );
974 +
975 + /* permissions violation */
976 + if( !lpte )
977 + goto no_page;
978 +
979 + return lpte & ~0xfff;
980 +
981 +no_page:
982 + BUMP( page_missing );
983 +
984 + /* no mac page found... */
985 + mm = current->mm;
986 + down_read( &mm->mmap_sem );
987 +
988 + if( !(vma=find_vma(mm,va)) || vma->vm_start > va )
989 + goto bad_area;
990 + if( !(vma->vm_flags & (request_rw ? VM_WRITE : (VM_READ | VM_EXEC))) )
991 + goto bad_area;
992 +
993 + handle_mm_fault( mm, vma, va, request_rw );
994 +
995 + up_read( &mm->mmap_sem );
996 + return get_phys_page(kv, va, request_rw);
997 +
998 +bad_area:
999 + up_read( &mm->mmap_sem );
1000 + printk("get_phys_page: BAD AREA, lvptr = %08lx\n", va );
1001 + force_sig(SIGSEGV, current);
1002 + return 0;
1003 +}
1004 +
1005 +
1006 +/************************************************************************/
1007 +/* Debugger functions */
1008 +/************************************************************************/
1009 +
1010 +int
1011 +dbg_get_linux_page( ulong va, dbg_page_info_t *r )
1012 +{
1013 + ulong val, uptr, *ptr;
1014 +
1015 + uptr = ((ulong*)current->thread.pgdir)[va>>22]; /* top 10 bits */
1016 + ptr = (ulong*)(uptr & ~0xfff);
1017 + if( !ptr )
1018 + return 1;
1019 +#ifdef LINUX_26
1020 + ptr = phys_to_virt( (int)ptr );
1021 +#endif
1022 + val = ptr[ (va>>12)&0x3ff ]; /* next 10 bits */
1023 +
1024 + r->phys = val & ~0xfff;
1025 + r->mflags =
1026 + DBG_TRANSL_PAGE_FLAG( val, _PAGE_PRESENT )
1027 + | DBG_TRANSL_PAGE_FLAG( val, _PAGE_USER )
1028 + | DBG_TRANSL_PAGE_FLAG( val, _PAGE_GUARDED )
1029 + | DBG_TRANSL_PAGE_FLAG( val, _PAGE_COHERENT )
1030 + | DBG_TRANSL_PAGE_FLAG( val, _PAGE_NO_CACHE )
1031 + | DBG_TRANSL_PAGE_FLAG( val, _PAGE_WRITETHRU )
1032 + | DBG_TRANSL_PAGE_FLAG( val, _PAGE_DIRTY )
1033 + | DBG_TRANSL_PAGE_FLAG( val, _PAGE_ACCESSED )
1034 + | DBG_TRANSL_PAGE_FLAG( val, _PAGE_RW )
1035 + | DBG_TRANSL_PAGE_FLAG( val, _PAGE_HASHPTE )
1036 + | DBG_TRANSL_PAGE_FLAG( val, _PAGE_EXEC );
1037 + return 0;
1038 +}
1039 diff --git a/drivers/macintosh/mol/_fault.c.rej b/drivers/macintosh/mol/_fault.c.rej
1040 new file mode 100644
1041 index 0000000..9c75956
1042 --- /dev/null
1043 +++ b/drivers/macintosh/mol/_fault.c.rej
1044 @@ -0,0 +1,162 @@
1045 +***************
1046 +*** 0 ****
1047 +--- 1,159 ----
1048 ++ /*
1049 ++ * Creation Date: <2002/06/08 21:01:54 samuel>
1050 ++ * Time-stamp: <2004/02/19 11:54:33 samuel>
1051 ++ *
1052 ++ * <fault.c>
1053 ++ *
1054 ++ * Linux part
1055 ++ *
1056 ++ * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se)
1057 ++ *
1058 ++ * This program is free software; you can redistribute it and/or
1059 ++ * modify it under the terms of the GNU General Public License
1060 ++ * as published by the Free Software Foundation
1061 ++ *
1062 ++ */
1063 ++
1064 ++ #include "archinclude.h"
1065 ++ #include "alloc.h"
1066 ++ #include "kernel_vars.h"
1067 ++ #include "mmu.h"
1068 ++ #include "mmu_contexts.h"
1069 ++ #include "asmfuncs.h"
1070 ++ #include "emu.h"
1071 ++ #include "misc.h"
1072 ++ #include "rvec.h"
1073 ++ #include "performance.h"
1074 ++ #include "mol-ioctl.h"
1075 ++ #include "mtable.h"
1076 ++
1077 ++ #ifdef CONFIG_HIGHPTE
1078 ++ #error "MOL is currently incompatible with CONFIG_HIGHPTE"
1079 ++ #endif
1080 ++
1081 ++ static inline ulong
1082 ++ fix_pte( ulong *p, ulong set, ulong flags )
1083 ++ {
1084 ++ unsigned long ret, tmp;
1085 ++
1086 ++ __asm__ __volatile__("\n"
1087 ++ "1: lwarx %0,0,%3 \n"
1088 ++ " andc. %1,%5,%0 \n"
1089 ++ " addi %1,0,0 \n"
1090 ++ " bne- 2f \n"
1091 ++ " or %1,%0,%4 \n"
1092 ++ " stwcx. %1,0,%3 \n"
1093 ++ " bne- 1b \n"
1094 ++ "2: \n"
1095 ++ : "=&r" (tmp), "=&r" (ret), "=m" (*p)
1096 ++ : "r" (p), "r" (set), "r" (flags), "m" (*p)
1097 ++ : "cc" );
1098 ++ return ret;
1099 ++ }
1100 ++
1101 ++ /*
1102 ++ * Get physical page corresponding to linux virtual address. Invokes linux page
1103 ++ * fault handler if the page is missing. This function never fails since we
1104 ++ * know there is a valid mapping...
1105 ++ */
1106 ++ #define PAGE_BITS_WRITE (_PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HASHPTE )
1107 ++ #define PAGE_BITS_READ (_PAGE_ACCESSED | _PAGE_HASHPTE )
1108 ++
1109 ++ ulong
1110 ++ get_phys_page( kernel_vars_t *kv, ulong va, int request_rw )
1111 ++ {
1112 ++ char *lvptr = (char*)va;
1113 ++ ulong lpte, uptr, *ptr;
1114 ++ ulong flags;
1115 ++ struct mm_struct *mm;
1116 ++ struct vm_area_struct *vma;
1117 ++
1118 ++ /* pte bits that must be set */
1119 ++ flags = request_rw ? (_PAGE_USER | _PAGE_RW | _PAGE_PRESENT)
1120 ++ : (_PAGE_USER | _PAGE_PRESENT);
1121 ++
1122 ++ uptr = ((ulong*)current->thread.pgdir)[va>>22]; /* top 10 bits */
1123 ++ ptr = (ulong*)(uptr & ~0xfff);
1124 ++ if( !ptr )
1125 ++ goto no_page;
1126 ++ #ifdef LINUX_26
1127 ++ ptr = phys_to_virt( (int)ptr );
1128 ++ #endif
1129 ++ ptr = ptr + ((va>>12) & 0x3ff); /* next 10 bits */
1130 ++
1131 ++ /* this allows us to keep track of this page until we have
1132 ++ * added a full mtable entry for it. The reservation is lost if
1133 ++ * a TLB invalidation occurs.
1134 ++ */
1135 ++ make_lvptr_reservation( kv, lvptr );
1136 ++
1137 ++ /* we atomically set _PAGE_HASHPTE after checking PAGE_PRESENT and PAGE_RW.
1138 ++ * We are then guaranteed to be notified about a TLB invalidation through the
1139 ++ * flush_hash_page hook.
1140 ++ */
1141 ++ lpte = fix_pte( ptr, (request_rw? PAGE_BITS_WRITE : PAGE_BITS_READ), flags );
1142 ++
1143 ++ /* permissions violation */
1144 ++ if( !lpte )
1145 ++ goto no_page;
1146 ++
1147 ++ return lpte & ~0xfff;
1148 ++
1149 ++ no_page:
1150 ++ BUMP( page_missing );
1151 ++
1152 ++ /* no mac page found... */
1153 ++ mm = current->mm;
1154 ++ down_read( &mm->mmap_sem );
1155 ++
1156 ++ if( !(vma=find_vma(mm,va)) || vma->vm_start > va )
1157 ++ goto bad_area;
1158 ++ if( !(vma->vm_flags & (request_rw ? VM_WRITE : (VM_READ | VM_EXEC))) )
1159 ++ goto bad_area;
1160 ++
1161 ++ handle_mm_fault( mm, vma, va, request_rw );
1162 ++
1163 ++ up_read( &mm->mmap_sem );
1164 ++ return get_phys_page(kv, va, request_rw);
1165 ++
1166 ++ bad_area:
1167 ++ up_read( &mm->mmap_sem );
1168 ++ printk("get_phys_page: BAD AREA, lvptr = %08lx\n", va );
1169 ++ force_sig(SIGSEGV, current);
1170 ++ return 0;
1171 ++ }
1172 ++
1173 ++
1174 ++ /************************************************************************/
1175 ++ /* Debugger functions */
1176 ++ /************************************************************************/
1177 ++
1178 ++ int
1179 ++ dbg_get_linux_page( ulong va, dbg_page_info_t *r )
1180 ++ {
1181 ++ ulong val, uptr, *ptr;
1182 ++
1183 ++ uptr = ((ulong*)current->thread.pgdir)[va>>22]; /* top 10 bits */
1184 ++ ptr = (ulong*)(uptr & ~0xfff);
1185 ++ if( !ptr )
1186 ++ return 1;
1187 ++ #ifdef LINUX_26
1188 ++ ptr = phys_to_virt( (int)ptr );
1189 ++ #endif
1190 ++ val = ptr[ (va>>12)&0x3ff ]; /* next 10 bits */
1191 ++
1192 ++ r->phys = val & ~0xfff;
1193 ++ r->mflags =
1194 ++ DBG_TRANSL_PAGE_FLAG( val, _PAGE_PRESENT )
1195 ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_USER )
1196 ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_GUARDED )
1197 ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_COHERENT )
1198 ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_NO_CACHE )
1199 ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_WRITETHRU )
1200 ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_DIRTY )
1201 ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_ACCESSED )
1202 ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_RW )
1203 ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_HASHPTE )
1204 ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_EXEC );
1205 ++ return 0;
1206 ++ }
1207 diff --git a/drivers/macintosh/mol/_hostirq.c b/drivers/macintosh/mol/_hostirq.c
1208 new file mode 100644
1209 index 0000000..b0681c1
1210 --- /dev/null
1211 +++ b/drivers/macintosh/mol/_hostirq.c
1212 @@ -0,0 +1,116 @@
1213 +/*
1214 + * <hostirq.c>
1215 + *
1216 + * host IRQ handling (for pciproxied devices)
1217 + *
1218 + * Copyright (C) 2005 Mattias Nissler <mattias.nissler@gmx.de>
1219 + *
1220 + * This program is free software; you can redistribute it and/or
1221 + * modify it under the terms of the GNU General Public License
1222 + * version 2
1223 + *
1224 + */
1225 +#include <linux/version.h>
1226 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
1227 +#include <linux/threads.h>
1228 +#include <linux/spinlock.h>
1229 +#endif
1230 +#include <linux/interrupt.h>
1231 +#include <linux/irq.h>
1232 +#include <linux/sched.h>
1233 +#include <linux/bitops.h>
1234 +#include <asm/atomic.h>
1235 +
1236 +#include "archinclude.h"
1237 +#include "kernel_vars.h"
1238 +#include "misc.h"
1239 +#include "atomic.h"
1240 +
1241 +irqreturn_t
1242 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
1243 +hostirq_handler(int irq, void *pkv)
1244 +#else
1245 +hostirq_handler(int irq, void *pkv, struct pt_regs *regs)
1246 +#endif
1247 +{
1248 + siginfo_t si;
1249 + kernel_vars_t *kv = (kernel_vars_t *) pkv;
1250 +
1251 + /* disable the irq */
1252 + disable_irq_nosync(irq);
1253 + /* have the interrupt handled */
1254 + if (!test_and_set_bit(irq, kv->mregs.active_irqs.irqs))
1255 + atomic_inc_mol((mol_atomic_t *) &(kv->mregs.hostirq_active_cnt));
1256 + kv->mregs.hostirq_update = 1;
1257 + kv->mregs.interrupt = 1;
1258 + /* signal the main thread (it might be DOZEing) */
1259 + if (kv->main_thread != NULL) {
1260 + memset(&si, 0, sizeof(si));
1261 + si.si_signo = SIGHUP;
1262 + si.si_code = irq;
1263 + send_sig_info(SIGHUP, &si, kv->main_thread);
1264 + }
1265 +
1266 + return IRQ_HANDLED;
1267 +}
1268 +
1269 +static char *molirqdescstring = "MOL irq mapping";
1270 +
1271 +int
1272 +grab_host_irq(kernel_vars_t *kv, int irq)
1273 +{
1274 + int ret;
1275 +
1276 + /* sanity check */
1277 + if (irq < 0 || irq >= NR_HOST_IRQS
1278 + || check_bit_mol(irq, (char *) kv->mregs.mapped_irqs.irqs))
1279 + return 0;
1280 +
1281 + /* request the irq */
1282 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)
1283 + ret = request_irq(irq, hostirq_handler, IRQF_DISABLED | IRQF_SHARED, molirqdescstring, kv);
1284 +#else
1285 + ret = request_irq(irq, hostirq_handler, SA_INTERRUPT | SA_SHIRQ, molirqdescstring, kv);
1286 +#endif
1287 + if (!ret) {
1288 +// printk(KERN_INFO "mapped irq line %d\n", irq);
1289 + set_bit_mol(irq, (char *) kv->mregs.mapped_irqs.irqs);
1290 + }
1291 +
1292 + return ret;
1293 +}
1294 +
1295 +int
1296 +release_host_irq(kernel_vars_t *kv, int irq)
1297 +{
1298 + /* sanity check */
1299 + if (irq < 0 || irq >= NR_HOST_IRQS
1300 + || !check_bit_mol(irq, (char *) kv->mregs.mapped_irqs.irqs))
1301 + return 0;
1302 +
1303 + clear_bit_mol(irq, (char *) kv->mregs.mapped_irqs.irqs);
1304 + disable_irq(irq);
1305 + free_irq(irq, kv);
1306 +
1307 + return 1;
1308 +}
1309 +
1310 +void
1311 +init_host_irqs(kernel_vars_t *kv)
1312 +{
1313 + memset(&(kv->mregs.mapped_irqs), 0, sizeof(kv->mregs.mapped_irqs));
1314 + kv->main_thread = current;
1315 + kv->mregs.hostirq_update = 0;
1316 +}
1317 +
1318 +void
1319 +cleanup_host_irqs(kernel_vars_t *kv)
1320 +{
1321 + int n;
1322 +
1323 + for (n = 0; n < NR_HOST_IRQS; n++) {
1324 + if (check_bit_mol(n, (char *) kv->mregs.mapped_irqs.irqs))
1325 + release_host_irq(kv, n);
1326 + }
1327 +}
1328 +
1329 diff --git a/drivers/macintosh/mol/_hostirq.c.rej b/drivers/macintosh/mol/_hostirq.c.rej
1330 new file mode 100644
1331 index 0000000..368eff6
1332 --- /dev/null
1333 +++ b/drivers/macintosh/mol/_hostirq.c.rej
1334 @@ -0,0 +1,119 @@
1335 +***************
1336 +*** 0 ****
1337 +--- 1,116 ----
1338 ++ /*
1339 ++ * <hostirq.c>
1340 ++ *
1341 ++ * host IRQ handling (for pciproxied devices)
1342 ++ *
1343 ++ * Copyright (C) 2005 Mattias Nissler <mattias.nissler@gmx.de>
1344 ++ *
1345 ++ * This program is free software; you can redistribute it and/or
1346 ++ * modify it under the terms of the GNU General Public License
1347 ++ * version 2
1348 ++ *
1349 ++ */
1350 ++ #include <linux/version.h>
1351 ++ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
1352 ++ #include <linux/threads.h>
1353 ++ #include <linux/spinlock.h>
1354 ++ #endif
1355 ++ #include <linux/interrupt.h>
1356 ++ #include <linux/irq.h>
1357 ++ #include <linux/sched.h>
1358 ++ #include <linux/bitops.h>
1359 ++ #include <asm/atomic.h>
1360 ++
1361 ++ #include "archinclude.h"
1362 ++ #include "kernel_vars.h"
1363 ++ #include "misc.h"
1364 ++ #include "atomic.h"
1365 ++
1366 ++ irqreturn_t
1367 ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
1368 ++ hostirq_handler(int irq, void *pkv)
1369 ++ #else
1370 ++ hostirq_handler(int irq, void *pkv, struct pt_regs *regs)
1371 ++ #endif
1372 ++ {
1373 ++ siginfo_t si;
1374 ++ kernel_vars_t *kv = (kernel_vars_t *) pkv;
1375 ++
1376 ++ /* disable the irq */
1377 ++ disable_irq_nosync(irq);
1378 ++ /* have the interrupt handled */
1379 ++ if (!test_and_set_bit(irq, kv->mregs.active_irqs.irqs))
1380 ++ atomic_inc_mol((mol_atomic_t *) &(kv->mregs.hostirq_active_cnt));
1381 ++ kv->mregs.hostirq_update = 1;
1382 ++ kv->mregs.interrupt = 1;
1383 ++ /* signal the main thread (it might be DOZEing) */
1384 ++ if (kv->main_thread != NULL) {
1385 ++ memset(&si, 0, sizeof(si));
1386 ++ si.si_signo = SIGHUP;
1387 ++ si.si_code = irq;
1388 ++ send_sig_info(SIGHUP, &si, kv->main_thread);
1389 ++ }
1390 ++
1391 ++ return IRQ_HANDLED;
1392 ++ }
1393 ++
1394 ++ static char *molirqdescstring = "MOL irq mapping";
1395 ++
1396 ++ int
1397 ++ grab_host_irq(kernel_vars_t *kv, int irq)
1398 ++ {
1399 ++ int ret;
1400 ++
1401 ++ /* sanity check */
1402 ++ if (irq < 0 || irq >= NR_HOST_IRQS
1403 ++ || check_bit_mol(irq, (char *) kv->mregs.mapped_irqs.irqs))
1404 ++ return 0;
1405 ++
1406 ++ /* request the irq */
1407 ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)
1408 ++ ret = request_irq(irq, hostirq_handler, IRQF_DISABLED | IRQF_SHARED, molirqdescstring, kv);
1409 ++ #else
1410 ++ ret = request_irq(irq, hostirq_handler, SA_INTERRUPT | SA_SHIRQ, molirqdescstring, kv);
1411 ++ #endif
1412 ++ if (!ret) {
1413 ++ // printk(KERN_INFO "mapped irq line %d\n", irq);
1414 ++ set_bit_mol(irq, (char *) kv->mregs.mapped_irqs.irqs);
1415 ++ }
1416 ++
1417 ++ return ret;
1418 ++ }
1419 ++
1420 ++ int
1421 ++ release_host_irq(kernel_vars_t *kv, int irq)
1422 ++ {
1423 ++ /* sanity check */
1424 ++ if (irq < 0 || irq >= NR_HOST_IRQS
1425 ++ || !check_bit_mol(irq, (char *) kv->mregs.mapped_irqs.irqs))
1426 ++ return 0;
1427 ++
1428 ++ clear_bit_mol(irq, (char *) kv->mregs.mapped_irqs.irqs);
1429 ++ disable_irq(irq);
1430 ++ free_irq(irq, kv);
1431 ++
1432 ++ return 1;
1433 ++ }
1434 ++
1435 ++ void
1436 ++ init_host_irqs(kernel_vars_t *kv)
1437 ++ {
1438 ++ memset(&(kv->mregs.mapped_irqs), 0, sizeof(kv->mregs.mapped_irqs));
1439 ++ kv->main_thread = current;
1440 ++ kv->mregs.hostirq_update = 0;
1441 ++ }
1442 ++
1443 ++ void
1444 ++ cleanup_host_irqs(kernel_vars_t *kv)
1445 ++ {
1446 ++ int n;
1447 ++
1448 ++ for (n = 0; n < NR_HOST_IRQS; n++) {
1449 ++ if (check_bit_mol(n, (char *) kv->mregs.mapped_irqs.irqs))
1450 ++ release_host_irq(kv, n);
1451 ++ }
1452 ++ }
1453 ++
1454 diff --git a/drivers/macintosh/mol/_kuname.c b/drivers/macintosh/mol/_kuname.c
1455 new file mode 100644
1456 index 0000000..e72b418
1457 --- /dev/null
1458 +++ b/drivers/macintosh/mol/_kuname.c
1459 @@ -0,0 +1,48 @@
1460 +/*
1461 + * Creation Date: <2001/08/15 01:11:01 samuel>
1462 + * Time-stamp: <2003/10/24 10:22:00 samuel>
1463 + *
1464 + * <kuname.c>
1465 + *
1466 + * Extract from the kernel source
1467 + *
1468 + * Copyright (C) 2001, 2002, 2003 Samuel Rydh (samuel@ibrium.se)
1469 + *
1470 + * This program is free software; you can redistribute it and/or
1471 + * modify it under the terms of the GNU General Public License
1472 + * as published by the Free Software Foundation
1473 + *
1474 + */
1475 +
1476 +#include <linux/version.h>
1477 +
1478 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
1479 +#include <linux/utsrelease.h>
1480 +#endif
1481 +
1482 +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18)
1483 +#include <linux/config.h>
1484 +#else
1485 +#include <linux/autoconf.h>
1486 +#endif
1487 +
1488 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
1489 +
1490 +#ifdef CONFIG_SMP
1491 +#define SMP_STRING "-smp"
1492 +#else
1493 +#define SMP_STRING ""
1494 +#endif
1495 +
1496 +#ifndef CONFIG_ALTIVEC
1497 +#define ALTIVEC_STRING "-noav"
1498 +#else
1499 +#define ALTIVEC_STRING ""
1500 +#endif
1501 +
1502 +#else
1503 +#define SMP_STRING ""
1504 +#define ALTIVEC_STRING ""
1505 +#endif
1506 +
1507 +char *cross_compiling_magic = "-MAGIC-" UTS_RELEASE SMP_STRING ALTIVEC_STRING ;
1508 diff --git a/drivers/macintosh/mol/_misc.c b/drivers/macintosh/mol/_misc.c
1509 new file mode 100644
1510 index 0000000..096cf40
1511 --- /dev/null
1512 +++ b/drivers/macintosh/mol/_misc.c
1513 @@ -0,0 +1,147 @@
1514 +/*
1515 + * Creation Date: <97/05/26 02:10:43 samuel>
1516 + * Time-stamp: <2004/03/13 14:14:20 samuel>
1517 + *
1518 + * <misc.c>
1519 + *
1520 + * Kernel interface
1521 + *
1522 + * Copyright (C) 1997-2004 Samuel Rydh (samuel@ibrium.se)
1523 + *
1524 + * This program is free software; you can redistribute it and/or
1525 + * modify it under the terms of the GNU General Public License
1526 + * as published by the Free Software Foundation
1527 + *
1528 + */
1529 +
1530 +#include "archinclude.h"
1531 +#include <linux/vmalloc.h>
1532 +#include <linux/sched.h>
1533 +#include <asm/uaccess.h>
1534 +#include <asm/prom.h>
1535 +#include "kernel_vars.h"
1536 +#include "misc.h"
1537 +#include "performance.h"
1538 +#include "map.h"
1539 +
1540 +#define MMU kv->mmu
1541 +
1542 +kernel_vars_t *
1543 +alloc_kvar_pages( void )
1544 +{
1545 + kernel_vars_t *kv;
1546 + int i, order;
1547 + char *ptr;
1548 +
1549 + for( i=1, order=0; i<NUM_KVARS_PAGES; i=i<<1, order++ )
1550 + ;
1551 + if( !(kv=(kernel_vars_t*)__get_free_pages(GFP_KERNEL, order)) )
1552 + return NULL;
1553 +
1554 + /* To be able to export the kernel variables to user space, we
1555 + * must set the PG_reserved bit. This is due to a check
1556 + * in remap_pte_range() in kernel/memory.c (is this bug or a feature?).
1557 + */
1558 + for( ptr=(char*)kv, i=0; i<NUM_KVARS_PAGES; i++, ptr+=0x1000 )
1559 + SetPageReserved( virt_to_page(ptr) );
1560 +
1561 + return kv;
1562 +}
1563 +
1564 +void
1565 +free_kvar_pages( kernel_vars_t *kv )
1566 +{
1567 + char *ptr = (char*)kv;
1568 + int i, order;
1569 +
1570 + for( i=0; i<NUM_KVARS_PAGES; i++, ptr+=0x1000 )
1571 + ClearPageReserved( virt_to_page(ptr) );
1572 +
1573 + for( i=1, order=0; i<NUM_KVARS_PAGES; i=i<<1, order++ )
1574 + ;
1575 + free_pages( (ulong)kv, order );
1576 +}
1577 +
1578 +
1579 +/************************************************************************/
1580 +/* hash access */
1581 +/************************************************************************/
1582 +
1583 +ulong *
1584 +map_emulated_hash( kernel_vars_t *kv, ulong mbase, ulong size )
1585 +{
1586 + return (ulong*)(MMU.userspace_ram_base + mbase);
1587 +}
1588 +
1589 +void
1590 +unmap_emulated_hash( kernel_vars_t *kv )
1591 +{
1592 + /* nothing */
1593 +}
1594 +
1595 +/************************************************************************/
1596 +/* kernel lowmem asm <-> kernel C-code switching */
1597 +/************************************************************************/
1598 +
1599 +typedef int (*kernelfunc_t)( kernel_vars_t *, ulong, ulong, ulong );
1600 +typedef void (*trampoline_t)( struct pt_regs *regs );
1601 +static trampoline_t old_trampoline;
1602 +
1603 +static void
1604 +mol_trampoline_vector( struct pt_regs *r )
1605 +{
1606 + kernel_vars_t *kv = (kernel_vars_t*)r->gpr[8];
1607 +
1608 +#ifndef LINUX_26
1609 + /* the 0x2f00 trap does not enable MSR_EE */
1610 + local_irq_enable();
1611 +#endif
1612 + TICK_CNTR_PUSH( kv );
1613 + r->gpr[3] = (*(kernelfunc_t)r->gpr[3])( kv, r->gpr[4], r->gpr[5], r->gpr[6] );
1614 + TICK_CNTR_POP( kv, in_kernel );
1615 +}
1616 +
1617 +static trampoline_t
1618 +set_trampoline( trampoline_t tramp )
1619 +{
1620 + trampoline_t old;
1621 +#ifdef LINUX_26
1622 + extern trampoline_t mol_trampoline;
1623 + old = mol_trampoline;
1624 + mol_trampoline = tramp;
1625 +#else
1626 + /* we steal the unused 0x2f00 exception vector... */
1627 + u32 *p = (u32*)(KERNELBASE + 0x2f00);
1628 + static trampoline_t *tptr = NULL;
1629 + int i;
1630 +
1631 + /* look for bl xxxx ; .long vector; .long exception_return */
1632 + for( i=0; !tptr && i<0x100/4; i++ ) {
1633 + if( (p[i] & ~0xffff) != 0x48000000 )
1634 + continue;
1635 + if( (p[i+1] & ~0x7fffff) != KERNELBASE || (p[i+2] & ~0x0fffff) != KERNELBASE )
1636 + continue;
1637 + tptr = (trampoline_t*)&p[i+1];
1638 + }
1639 + if( !tptr ) {
1640 + printk("MOL trampoline not found!\n");
1641 + return NULL;
1642 + }
1643 + old = *tptr;
1644 + *tptr = tramp;
1645 +#endif
1646 + return old;
1647 +}
1648 +
1649 +int
1650 +arch_common_init( void )
1651 +{
1652 + old_trampoline = set_trampoline( mol_trampoline_vector );
1653 + return !old_trampoline;
1654 +}
1655 +
1656 +void
1657 +arch_common_cleanup( void )
1658 +{
1659 + set_trampoline( old_trampoline );
1660 +}
1661 diff --git a/drivers/macintosh/mol/_mmu.c b/drivers/macintosh/mol/_mmu.c
1662 new file mode 100644
1663 index 0000000..8626e6e
1664 --- /dev/null
1665 +++ b/drivers/macintosh/mol/_mmu.c
1666 @@ -0,0 +1,41 @@
1667 +/*
1668 + * Creation Date: <2002/07/13 13:58:00 samuel>
1669 + * Time-stamp: <2004/02/14 12:47:09 samuel>
1670 + *
1671 + * <mmu.c>
1672 + *
1673 + *
1674 + *
1675 + * Copyright (C) 2002, 2003 Samuel Rydh (samuel@ibrium.se)
1676 + *
1677 + * This program is free software; you can redistribute it and/or
1678 + * modify it under the terms of the GNU General Public License
1679 + * as published by the Free Software Foundation
1680 + *
1681 + */
1682 +
1683 +#include "archinclude.h"
1684 +#include "alloc.h"
1685 +#include "kernel_vars.h"
1686 +#include "mmu.h"
1687 +#include "asmfuncs.h"
1688 +
1689 +#define MMU (kv->mmu)
1690 +
1691 +#ifdef CONFIG_SMP
1692 +void (*xx_tlbie_lowmem)( void );
1693 +void (*xx_store_pte_lowmem)( void );
1694 +#else
1695 +void (*xx_store_pte_lowmem)( ulong *slot, int pte0, int pte1 );
1696 +#endif
1697 +
1698 +int
1699 +arch_mmu_init( kernel_vars_t *kv )
1700 +{
1701 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
1702 + MMU.emulator_context = current->mm->context.id;
1703 +#else
1704 + MMU.emulator_context = current->mm->context;
1705 +#endif
1706 + return 0;
1707 +}
1708 diff --git a/drivers/macintosh/mol/actions.c b/drivers/macintosh/mol/actions.c
1709 new file mode 100644
1710 index 0000000..9f10043
1711 --- /dev/null
1712 +++ b/drivers/macintosh/mol/actions.c
1713 @@ -0,0 +1,548 @@
1714 +/*
1715 + * Creation Date: <2001/04/07 17:33:52 samuel>
1716 + * Time-stamp: <2004/03/13 14:17:40 samuel>
1717 + *
1718 + * <actions.c>
1719 + *
1720 + * Handle assambly actions (relocations, exception vector
1721 + * hooking, lowmem relocations and other stuff)
1722 + *
1723 + * Copyright (C) 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se)
1724 + *
1725 + * This program is free software; you can redistribute it and/or
1726 + * modify it under the terms of the GNU General Public License
1727 + * as published by the Free Software Foundation
1728 + *
1729 + */
1730 +
1731 +#include "archinclude.h"
1732 +#include "alloc.h"
1733 +#include "kernel_vars.h"
1734 +#include "misc.h"
1735 +#include "asmfuncs.h"
1736 +#include "actions.h"
1737 +#include "map.h"
1738 +
1739 +
1740 +/* globals */
1741 +int reloc_virt_offs;
1742 +
1743 +static char *code_base;
1744 +static uint code_size;
1745 +
1746 +/* some opcodes */
1747 +#define OPCODE_ADDIS( dreg, sreg, hi_val ) ((15<<26) | ((dreg)<<21) | ((sreg)<<16) | (hi_val))
1748 +#define OPCODE_LIS( dreg, hi_val ) OPCODE_ADDIS( dreg, 0, hi_val )
1749 +#define OPCODE_ORI( dreg, sreg, val ) ((24<<26) | ((dreg)<<16) | ((sreg)<<21) | (val))
1750 +#define OPCODE_MTSPRG2( sreg ) (0x7c1243a6 + ((sreg)<<21))
1751 +
1752 +
1753 +/************************************************************************/
1754 +/* lowmem allocations (allocates within the first 32 MB of RAM) */
1755 +/************************************************************************/
1756 +
1757 +/* The low-level assembly code need to be located in memory which is
1758 + * physically continuous. The kernel exception vector are patched
1759 + * through pseudo symbols (action symbols).
1760 + */
1761 +
1762 +#define MAX_NUM_CLEANUP_HANDLERS 32
1763 +
1764 +typedef struct {
1765 + char *lowmem_addr;
1766 + int alloc_size;
1767 + int alloc_method;
1768 +
1769 + ulong *inst_addr; /* these fields are used */
1770 + ulong opcode; /* be the hook code */
1771 +} cleanup_entry_t;
1772 +
1773 +static int num_cleanup_entries;
1774 +static cleanup_entry_t cleanup_table[ MAX_NUM_CLEANUP_HANDLERS ];
1775 +static ulong lowmem_phys_cursor;
1776 +
1777 +/* Memory mapping of exception vectors */
1778 +static ulong lowmem_phys_base;
1779 +static char *lowmem_virt_base;
1780 +static void *lowmem_mapping;
1781 +
1782 +
1783 +static inline ulong *
1784 +lowmem_phys_to_virt( ulong paddr ) {
1785 + return (ulong*)(lowmem_virt_base + (paddr - lowmem_phys_base));
1786 +}
1787 +
1788 +static inline ulong
1789 +lowmem_tophys( void *vaddr ) {
1790 + return lowmem_phys_base + ((ulong)vaddr - (ulong)lowmem_virt_base);
1791 +}
1792 +
1793 +
1794 +static void
1795 +lowmem_initialize( void )
1796 +{
1797 + if( num_cleanup_entries ) {
1798 + printk("Internal error in lowmem_initialize\n");
1799 + return;
1800 + }
1801 + lowmem_phys_cursor = 0x100;
1802 +
1803 + /* In Darwin, the mapping will fail if we put lowmem_phys_base to zero */
1804 + lowmem_phys_base = 0x100;
1805 + lowmem_mapping = map_phys_range( lowmem_phys_base, 0x4000, &lowmem_virt_base );
1806 +}
1807 +
1808 +static char *
1809 +lowmem_alloc( int size, cleanup_entry_t **ret_ce )
1810 +{
1811 + ulong *pstart;
1812 + cleanup_entry_t ce;
1813 + int found=0;
1814 +
1815 + memset( &ce, 0, sizeof(ce) );
1816 + if( ret_ce )
1817 + *ret_ce = NULL;
1818 +
1819 + if( num_cleanup_entries >= MAX_NUM_CLEANUP_HANDLERS ) {
1820 + printk("MOL: Need more cleanup slots!\n");
1821 + return NULL;
1822 + }
1823 +
1824 + /* Find big enough empty piece of memory */
1825 + if( size < 0x10 )
1826 + size = 0x10;
1827 +
1828 + pstart = lowmem_phys_to_virt(lowmem_phys_cursor);
1829 + pstart = (ulong*)(((ulong)pstart + 0xf) & ~0xf);
1830 + for( ; lowmem_phys_cursor < 0x3000; lowmem_phys_cursor+=4 ) {
1831 + ulong *p = lowmem_phys_to_virt(lowmem_phys_cursor);
1832 + if( ((int)p - (int)pstart) >= size ) {
1833 + found = 1;
1834 + break;
1835 + }
1836 + if( *p ) {
1837 + pstart = (ulong*)(((ulong)p + sizeof(ulong) + 0xf) & ~0xf);
1838 + continue;
1839 + }
1840 + }
1841 + if( !found ) {
1842 + printk("MOL: Did not find an empty piece of lowmem memory!\n");
1843 + return NULL;
1844 + }
1845 + /* printk("lowmem alloc: %08lX\n", pstart ); */
1846 +
1847 + ce.lowmem_addr = (char*)pstart;
1848 + ce.alloc_method = 0;
1849 + ce.alloc_size = size;
1850 + /* printk("lowmem-alloc SPACE %X bytes at %08lX\n", size, (ulong)pstart ); */
1851 +
1852 + cleanup_table[num_cleanup_entries] = ce;
1853 + if( ret_ce )
1854 + *ret_ce = &cleanup_table[num_cleanup_entries];
1855 + num_cleanup_entries++;
1856 +
1857 + return ce.lowmem_addr;
1858 +}
1859 +
1860 +static void
1861 +lowmem_free_all( void )
1862 +{
1863 + cleanup_entry_t *ce = &cleanup_table[0];
1864 + int i;
1865 +
1866 + for(i=0; i<num_cleanup_entries; i++, ce++ )
1867 + memset( ce->lowmem_addr, 0, ce->alloc_size );
1868 +
1869 + num_cleanup_entries = 0;
1870 +
1871 + if( lowmem_mapping ) {
1872 + unmap_phys_range( lowmem_mapping );
1873 + lowmem_mapping = NULL;
1874 + }
1875 +}
1876 +
1877 +
1878 +/************************************************************************/
1879 +/* helper functions */
1880 +/************************************************************************/
1881 +
1882 +static action_pb_t *
1883 +find_action( int action, int index )
1884 +{
1885 + extern int r__actions_offs_section[], r__actions_offs_section_end[];
1886 + extern char *r__actions_section[];
1887 + const int n = ((int)r__actions_offs_section_end - (int)r__actions_offs_section)/sizeof(int);
1888 + int i, *op = r__actions_offs_section;
1889 +
1890 + for( i=0; i<n; i++ ) {
1891 + action_pb_t *p = (action_pb_t*)((char*)r__actions_section + op[i]);
1892 +
1893 + if( p->action != action || index-- )
1894 + continue;
1895 + return p;
1896 + }
1897 + return NULL;
1898 +}
1899 +
1900 +static int
1901 +relocate_inst( ulong *opc_ptr, ulong from, ulong to )
1902 +{
1903 + ulong opcode = *opc_ptr;
1904 + int offs=-1;
1905 +
1906 + /* XXX: UNTESTED if target instruction is a branch */
1907 +
1908 + /* Since we use this on the _first_ instruction of the
1909 + * exception vector, it can't touch LR/CR. Thus, we
1910 + * only look for unconditional, relative branches.
1911 + */
1912 +
1913 + /* relativ branch b */
1914 + if( (opcode & 0xfc000003) == (18<<26) ){
1915 + offs = (opcode & 0x03fffffc);
1916 + /* sign extend */
1917 + if( offs & 0x03000000 )
1918 + offs |= ~0x03ffffff;
1919 + }
1920 + /* unconditional, relativ bc branch (b 0100 001z1zz ...) */
1921 + if( (opcode & 0xfe800003) == 0x42800000 ){
1922 + offs = (opcode & 0xfffc);
1923 + if( offs & 0x8000 )
1924 + offs |= ~0xffff;
1925 + }
1926 + /* construct the absolute branch */
1927 + if( offs != -1 ) {
1928 + int dest = from + offs;
1929 + if( dest < 0 || dest > 33554431 ) {
1930 + printk("relocation of branch at %08lX to %08lX failed\n", from, to);
1931 + return 1;
1932 + }
1933 + /* absolute branch */
1934 + *opc_ptr = ((18<<26) + 2) | dest;
1935 + }
1936 + return 0;
1937 +}
1938 +
1939 +
1940 +/************************************************************************/
1941 +/* actions */
1942 +/************************************************************************/
1943 +
1944 +typedef int (*action_func_t)( int action, ulong *target, const int *pb );
1945 +
1946 +static int
1947 +action_li_phys( int action, ulong *target, const int *pb )
1948 +{
1949 + int r = pb[0] & 0x1f;
1950 + ulong addr = pb[1] + tophys_mol( code_base );
1951 +
1952 + /* target[0] = addis r,0,addr@h ; target[1] = ori r,r,addr@l */
1953 + target[0] = (15 << 26) | (r << 21) | (addr >> 16);
1954 + target[1] = (24 << 26) | (r << 21) | (r << 16) | (addr & 0xffff);
1955 +
1956 + /* printk("ACTION_LI_PHYS %d %08lX\n", dreg, addr ); */
1957 + return 0;
1958 +}
1959 +
1960 +static int
1961 +action_lwz_physaddr_r( int action, ulong *target, const int *pb )
1962 +{
1963 + ulong addr = pb[1] + tophys_mol( code_base );
1964 + int dr = (pb[0] >> 5) & 0x1f;
1965 + int r = pb[0] & 0x1f;
1966 + short low = (addr & 0xffff);
1967 +
1968 + /* target[0] = addis dr,r,addr@h ; target[1] = lwz dr,addr@l(dr) */
1969 + target[0] = (15 << 26) | (dr << 21) | (r << 16) | ((addr - low) >> 16);
1970 + target[1] = (32 << 26) | (dr << 21) | (dr << 16) | ((int)low & 0xffff);
1971 +
1972 + /* printk("ACTION_LI_PHYS %d %08lX\n", dreg, addr ); */
1973 + return 0;
1974 +}
1975 +
1976 +static int
1977 +action_specvar( int action, ulong *target, const int *pb )
1978 +{
1979 + int r = pb[0] & 0x1f;
1980 + ulong addr;
1981 +
1982 + switch( pb[1] ) {
1983 + case SPECVAR_SESSION_TABLE:
1984 + addr = tophys_mol(g_sesstab);
1985 + break;
1986 + default:
1987 + return 1;
1988 + }
1989 +
1990 + if( action == ACTION_LIS_SPECVAR_H ) {
1991 + /* target[0] = addis r,0,addr@h */
1992 + target[0] = OPCODE_LIS( r, (addr >> 16) & 0xffff );
1993 + return 0;
1994 + }
1995 + if( action == ACTION_ORI_SPECVAR_L ) {
1996 + /* target[0] = ori rD,rS,addr@l */
1997 + int rD = (pb[0] >> 5) & 0x1f;
1998 + target[0] = OPCODE_ORI( rD, r, (addr & 0xffff));
1999 + return 0;
2000 + }
2001 + return 1;
2002 +}
2003 +
2004 +
2005 +/* Note: this only works under linux */
2006 +static int
2007 +action_tophysvirt( int action, ulong *target, const int *pb )
2008 +{
2009 + ulong addr = tophys_mol(0);
2010 + int dr = (pb[0] >> 5) & 0x1f;
2011 + int sr = pb[0] & 0x1f;
2012 +
2013 + if( action == ACTION_TOVIRT )
2014 + addr = -addr;
2015 +
2016 + /* target[0] = addis dr,sr,(tophys(0))@hi */
2017 + target[0] = OPCODE_ADDIS( dr, sr, (addr >> 16) & 0xffff );
2018 + return 0;
2019 +}
2020 +
2021 +/* pb[] = { vector, size, vret_offs, ...hook_code... } */
2022 +static int
2023 +action_reloc_hook( int action, ulong *hookcode, const int *pb )
2024 +{
2025 + ulong addr, inst, vector=pb[0], size=pb[1], vret_offs=pb[2];
2026 + cleanup_entry_t *clean;
2027 + ulong *vector_virt, *target;
2028 + action_pb_t *apb;
2029 + char *lowmem;
2030 + int i;
2031 +
2032 + /* Virtual address of exception vector */
2033 + vector_virt = lowmem_phys_to_virt(vector);
2034 +
2035 + /* address of the vector hook code */
2036 + addr = tophys_mol( (char*)hookcode );
2037 +
2038 + /* allocate lowmem and add cleanup handler */
2039 + if( !(lowmem=lowmem_alloc(size, &clean)) )
2040 + return 1;
2041 +
2042 + /* printk("ACTION_RELOC_HOOK: %lx, %lx, %lx, %lx %p\n", vector, size, vret_action, vret_offs, lowmem); */
2043 +
2044 + memcpy( lowmem, &pb[3], size );
2045 +
2046 + /* perform the vret_action */
2047 + for( i=0; (apb=find_action(ACTION_VRET, i)); i++ ) {
2048 + if( apb->params[0] != vector )
2049 + continue;
2050 +
2051 + /* insert the absolut branch */
2052 + target = (ulong*)(code_base + apb->offs);
2053 + *target = ((18<<26) + 2) | lowmem_tophys(lowmem + vret_offs);
2054 + flush_icache_mol( (ulong)target, (ulong)target + 4 );
2055 + /* printk("'ba xxx' added (opcode %08lX at %p)\n", *target, target ); */
2056 + }
2057 +
2058 + /* fix the hook address in the glue code */
2059 + target = (ulong*)lowmem;
2060 + target[1] = (target[1] & ~0xffff) | (addr >> 16); /* target[0] = addis r3,0,0 */
2061 + target[3] = (target[3] & ~0xffff) | (addr & 0xffff); /* target[1] = ori r3,r3,0 */
2062 +
2063 + /* relocate instruction to be overwritten with a branch */
2064 + inst = *vector_virt;
2065 + clean->opcode = inst;
2066 + if( relocate_inst( &inst, vector, lowmem_tophys(lowmem+vret_offs) ))
2067 + return 1;
2068 + *(ulong*)(lowmem + vret_offs) = inst;
2069 + flush_icache_mol( (ulong)lowmem, (ulong)lowmem + size );
2070 +
2071 + /* insert branch, 'ba lowmem_ph' */
2072 + *(volatile ulong*)vector_virt = 0x48000002 + lowmem_tophys(lowmem);
2073 + flush_icache_mol( (ulong)vector_virt, (ulong)vector_virt+4 );
2074 +
2075 + /* we are in business! */
2076 + clean->inst_addr = vector_virt;
2077 + return 0;
2078 +}
2079 +
2080 +
2081 +/* pb = { size, where_to_store_lowmem_addr, ...code... } */
2082 +static int
2083 +action_reloc_low( int action, ulong *dummy, const int *pb )
2084 +{
2085 + int size = pb[0];
2086 + char **func_ptr = (char**)pb[1];
2087 + char *lowmem;
2088 +
2089 + if( !(lowmem=lowmem_alloc(size, NULL)) )
2090 + return 1;
2091 + memcpy( lowmem, (char*)&pb[2], size );
2092 +
2093 + flush_icache_mol( (ulong)lowmem, (ulong)lowmem+size );
2094 + *func_ptr = lowmem;
2095 + return 0;
2096 +}
2097 +
2098 +/* pb = { symind, size, fret_offset, codeglue... } */
2099 +static int
2100 +action_hook_function( int action, ulong *hookcode, const int *pb )
2101 +{
2102 + ulong addr, fhook=pb[0], size=pb[1], fret_offs=pb[2];
2103 + ulong *target, inst;
2104 + char *lowmem, *func_addr=NULL;
2105 + cleanup_entry_t *clean;
2106 +
2107 + switch( fhook ) {
2108 +#ifdef __linux__
2109 + case FHOOK_FLUSH_HASH_PAGE:
2110 + func_addr = (char*)compat_flush_hash_pages;
2111 + break;
2112 +#endif
2113 + default:
2114 + printk("Bad fhook index %ld\n", fhook );
2115 + return 1;
2116 + }
2117 +
2118 + /* this does not have to be in lowmem, but it is simpler with a unified approach */
2119 + if( !(lowmem=lowmem_alloc(size, &clean)) )
2120 + return 1;
2121 +
2122 + /* printk("ACTION_HOOK_FUNCTION: %lx, %lx, %lx %p\n", fhook, size, fret_offs, lowmem); */
2123 +
2124 + memcpy( lowmem, &pb[3], size );
2125 +
2126 + /* fix the hook address in the glue code */
2127 + target = (ulong*)lowmem;
2128 + addr = (ulong)hookcode;
2129 + target[1] = (target[1] & ~0xffff) | (addr >> 16); /* target[1] = addis rX,0,0 */
2130 + target[2] = (target[2] & ~0xffff) | (addr & 0xffff); /* target[2] = ori rX,rX,0 */
2131 +
2132 + /* relocate overwritten instruction and add relative return branch */
2133 + inst = *(ulong*)func_addr;
2134 + clean->opcode = inst;
2135 + if( relocate_inst(&inst, (ulong)func_addr, (ulong)lowmem + fret_offs) )
2136 + return 1;
2137 + target = (ulong*)(lowmem + fret_offs);
2138 + target[0] = inst;
2139 + target[1] = (18<<26) | (((ulong)func_addr - (ulong)&target[1] + sizeof(long)) & 0x03fffffc);
2140 + flush_icache_mol( (ulong)lowmem, (ulong)lowmem + size );
2141 + _sync();
2142 +
2143 + /* insert relative branch, 'b lowmem' */
2144 + *(volatile ulong*)func_addr = (18<<26) | ((lowmem - func_addr) & 0x03fffffc);
2145 + flush_icache_mol( (ulong)func_addr, (ulong)func_addr+4 );
2146 +
2147 + _sync();
2148 +
2149 + /* we are in business! */
2150 + clean->inst_addr = (ulong*)func_addr;
2151 + return 0;
2152 +}
2153 +
2154 +static int
2155 +action_fix_sprg2( int action, ulong *target, const int *pb )
2156 +{
2157 +#ifdef __darwin__
2158 + int sprg2;
2159 + int r = pb[0] & 0x1f;
2160 + asm volatile("mfspr %0,274" : "=r" (sprg2) );
2161 + target[0] = OPCODE_LIS( r, (sprg2 >> 16) & 0xffff );
2162 + target[1] = OPCODE_ORI( r, r, (sprg2 & 0xffff) );
2163 + target[2] = OPCODE_MTSPRG2( r );
2164 +#endif
2165 + return 0;
2166 +}
2167 +
2168 +static int
2169 +action_noaction( int action, ulong *hookcode, const int *pb )
2170 +{
2171 + return 0;
2172 +}
2173 +
2174 +static action_func_t actiontable[MAX_NUM_ACTIONS] = {
2175 + [ACTION_LI_PHYS] = action_li_phys,
2176 + [ACTION_LWZ_PHYSADDR_R] = action_lwz_physaddr_r,
2177 + [ACTION_TOPHYS] = action_tophysvirt,
2178 + [ACTION_TOVIRT] = action_tophysvirt,
2179 + [ACTION_RELOC_HOOK] = action_reloc_hook,
2180 + [ACTION_RELOCATE_LOW] = action_reloc_low,
2181 + [ACTION_HOOK_FUNCTION] = action_hook_function,
2182 + [ACTION_VRET] = action_noaction,
2183 + [ACTION_FIX_SPRG2] = action_fix_sprg2,
2184 +
2185 + [ACTION_LIS_SPECVAR_H] = action_specvar,
2186 + [ACTION_ORI_SPECVAR_L] = action_specvar,
2187 +};
2188 +
2189 +
2190 +/************************************************************************/
2191 +/* write/remove hooks */
2192 +/************************************************************************/
2193 +
2194 +static int
2195 +relocate_code( void )
2196 +{
2197 + extern char r__reloctable_start[], r__reloctable_end[];
2198 +
2199 + code_size = r__reloctable_end - r__reloctable_start;
2200 +
2201 + if( !(code_base=kmalloc_cont_mol(code_size)) )
2202 + return 1;
2203 +
2204 + memcpy( code_base, r__reloctable_start, code_size );
2205 + reloc_virt_offs = (int)code_base - (int)r__reloctable_start;
2206 + return 0;
2207 +}
2208 +
2209 +int
2210 +perform_actions( void )
2211 +{
2212 + action_pb_t *pb;
2213 + int action, i;
2214 +
2215 + if( relocate_code() )
2216 + return 1;
2217 + lowmem_initialize();
2218 +
2219 + for( action=0; action < MAX_NUM_ACTIONS; action++ ) {
2220 + for( i=0; (pb=find_action(action,i)); i++ ) {
2221 + ulong *target = (ulong*)(code_base + pb->offs);
2222 +
2223 + if( pb->offs > code_size ) {
2224 + printk("OFFSET ERROR!\n");
2225 + goto error;
2226 + }
2227 +
2228 + if( !actiontable[action] )
2229 + goto error;
2230 + if( (*actiontable[action])(action, target, pb->params) )
2231 + goto error;
2232 + }
2233 +
2234 + /* we need to flush the icache before the hook actions are performed */
2235 + if( action == FLUSH_CACHE_ACTION )
2236 + flush_icache_mol( (ulong)code_base, (ulong)code_base + code_size );
2237 + }
2238 + /* to be on the safe side, flush the cache once more */
2239 + flush_icache_mol( (ulong)code_base, (ulong)code_base + code_size );
2240 + return 0;
2241 + error:
2242 + printk("MOL: action %d error\n", action );
2243 + cleanup_actions();
2244 + return 1;
2245 +}
2246 +
2247 +void
2248 +cleanup_actions( void )
2249 +{
2250 + cleanup_entry_t *ce = &cleanup_table[0];
2251 + int i;
2252 +
2253 + for( i=0; i<num_cleanup_entries; i++, ce++ ) {
2254 + if( ce->inst_addr ) {
2255 + *(volatile ulong*)ce->inst_addr = cleanup_table[i].opcode;
2256 + flush_icache_mol( (ulong)ce->inst_addr, (ulong)ce->inst_addr + 4 );
2257 + }
2258 + }
2259 + lowmem_free_all();
2260 + kfree_cont_mol( code_base );
2261 +}
2262 diff --git a/drivers/macintosh/mol/asm-files/603.S b/drivers/macintosh/mol/asm-files/603.S
2263 new file mode 100644
2264 index 0000000..30649d2
2265 --- /dev/null
2266 +++ b/drivers/macintosh/mol/asm-files/603.S
2267 @@ -0,0 +1,218 @@
2268 +/*
2269 + * Creation Date: <2001/06/15 20:10:49 samuel>
2270 + * Time-stamp: <2001/06/16 15:35:22 samuel>
2271 + *
2272 + * <603.S>
2273 + *
2274 + * 603 MMU support
2275 + *
2276 + * Copyright (C) 2001 Samuel Rydh (samuel@ibrium.se)
2277 + *
2278 + * This program is free software; you can redistribute it and/or
2279 + * modify it under the terms of the GNU General Public License
2280 + * as published by the Free Software Foundation
2281 + *
2282 + */
2283 +
2284 +#define P603_USE_G_BIT
2285 +#define P603_USE_R_BIT
2286 +#define P603_USE_C_BIT
2287 +
2288 +/* NOTE: The 603 vectors are called with ctr saved in r0.
2289 + * Secondary interrupts are not detected automatically.
2290 + */
2291 +
2292 +/************************************************************************/
2293 +/* Instruction TLB Miss (603 specific vector) */
2294 +/************************************************************************/
2295 +
2296 +VECTOR_603( 0x1000, "Instruction TLB Miss - 603" )
2297 +// mfctr r0 // Need to save this - CTR can't be touched!
2298 + mfspr r2,HASH1 // Get PTE pointer
2299 + mfspr r3,ICMP // Partial item compare value
2300 +00: li r1,8 // 8 items / bucket
2301 + mtctr r1
2302 + subi r2,r2,8 // Preset pointer
2303 +10: lwzu r1,8(r2) // Get next PTE
2304 + cmp 0,r1,r3 // Found entry yet?
2305 + bdnzf 2,10b // Jump back if not, until CTR==0
2306 + bne 30f // Try secondary hash if CTR==0
2307 + lwz r1,4(r2) // Get second word of entry
2308 +#ifdef P603_USE_G_BIT
2309 + andi. r3,r1,8 // check G-bit
2310 + bne DoISI_603_G // if guarded, take an ISI
2311 +#endif
2312 + mtctr r0 // Restore CTR
2313 + mfspr r3,SRR1 // Need to restore CR0
2314 + mtcrf 0x80,r3
2315 + mfspr r0,IMISS // Set to update TLB
2316 + mtspr RPA,r1
2317 +#ifdef P603_USE_R_BIT
2318 + ori r1,r1,0x100 // Set reference bit
2319 + srwi r1,r1,8 // Get byte 7 of pte
2320 + tlbli r0 // Load the ITLB
2321 + stb r1,6(r2) // update page table
2322 +#else
2323 + tlbli r0 // Load the ITLB
2324 +#endif
2325 + rfi // All done
2326 +
2327 + // Secondary hash
2328 +30: andi. r1,r3,0x40 // Already doing secondary hash?
2329 + bne DoISI_603 // Yes - item not in hash table
2330 + mfspr r2,HASH2 // Get hash table pointer
2331 + ori r3,r3,0x40 // Set secondary hash
2332 + b 00b // Try lookup again
2333 +
2334 +
2335 +/************************************************************************/
2336 +/* Data Store TLB Miss (603 specific vector) */
2337 +/************************************************************************/
2338 +
2339 +VECTOR_603( 0x1200, "Data Store TLB Miss - 603" )
2340 +// mfctr r0 // Need to save this - CTR can't be touched!
2341 + mfspr r2,HASH1 // Get PTE pointer
2342 + mfspr r3,DCMP // Partial item compare value
2343 +00: li r1,8 // 8 items / bucket
2344 + mtctr r1
2345 + subi r2,r2,8 // Preset pointer
2346 +10: lwzu r1,8(r2) // Get next PTE
2347 + cmp 0,r1,r3 // Found entry yet?
2348 + bdnzf 2,10b // Jump back if not, until CTR==0
2349 + bne 30f // Try secondary hash if CTR==0
2350 + lwz r1,4(r2) // Get second word of entry
2351 +#ifdef P603_USE_C_BIT
2352 + andi. r3,r1,0x80 // Check the C-bit
2353 + beq CheckProt_603
2354 +16:
2355 +#endif
2356 +20: mtctr r0 // Restore CTR
2357 + mfspr r3,SRR1 // Need to restore CR0
2358 + mtcrf 0x80,r3
2359 + mfspr r0,DMISS // Set to update TLB
2360 + mtspr RPA,r1
2361 + tlbld r0
2362 + rfi // All done
2363 +
2364 + // Secondary hash
2365 +30: andi. r1,r3,0x40 // Already doing secondary hash?
2366 + bne DoDSI_603 // Yes - item not in hash table
2367 + mfspr r2,HASH2 // Get hash table pointer
2368 + ori r3,r3,0x40 // Set secondary hash
2369 + b 00b // Try lookup again
2370 +
2371 +#ifdef P603_USE_C_BIT
2372 + // Entry found and PTE[c] == 0. Check protection before setting PTE[c]
2373 + // r0 = saved ctr, r1 = second word of PTE, r2 = pointer to pteg, r3 = trash
2374 +CheckProt_603:
2375 + rlwinm. r3,r1,30,0,1 // test PP
2376 + bge- 50f // if (PP == 00 or PP == 01) goto 50
2377 + andi. r3,r1,1 // test PP[0]
2378 + beq+ 60f // return if PP[0] == 0
2379 + b DoDSI_603_P // else DSI_P, (PP==11, read-only)
2380 +
2381 +50: mfspr r3,SRR1 // get old msr
2382 + andis. r3,r3,0x0008 // test the KEY bit (SRR1-bit 12)
2383 + beq 60f // if KEY==0, goto 60
2384 + b DoDSI_603_P // else DSI_P
2385 +
2386 +60: ori r1,r1,0x180 // set reference and change bit
2387 + sth r1,6(r2) // update page table
2388 + b 16b // and back we go
2389 +#endif
2390 +
2391 +
2392 +/************************************************************************/
2393 +/* Data Load TLB Miss (603 specific vector) */
2394 +/************************************************************************/
2395 +
2396 +VECTOR_603( 0x1100, "Data Load TLB Miss - 603" )
2397 +// mfctr r0 // Need to save this - CTR can't be touched!
2398 + mfspr r2,HASH1 // Get PTE pointer
2399 + mfspr r3,DCMP // Partial item compare value
2400 +00: li r1,8 // 8 items / bucket
2401 + mtctr r1
2402 + subi r2,r2,8 // Preset pointer
2403 +10: lwzu r1,8(r2) // Get next PTE
2404 + cmp 0,r1,r3 // Found entry yet?
2405 + bdnzf 2,10b // Jump back if not, until CTR==0
2406 + bne 30f // Try secondary hash if CTR==0
2407 + lwz r1,4(r2) // Get second word of entry
2408 +20: mtctr r0 // Restore CTR
2409 + mfspr r3,SRR1 // Need to restore CR0
2410 + mtcrf 0x80,r3
2411 + mfspr r0,DMISS // Set to update TLB
2412 + mtspr RPA,r1
2413 +#ifdef P603_USE_R_BIT
2414 + ori r1,r1,0x100 // set reference bit
2415 + srwi r1,r1,8
2416 + tlbld r0
2417 + stb r1,6(r2)
2418 +#else
2419 + tlbld r0
2420 +#endif
2421 + rfi // All done
2422 +
2423 +// Secondary hash
2424 +30: andi. r1,r3,0x40 // Already doing secondary hash?
2425 + bne DoDSI_603 // Yes - item not in hash table
2426 + mfspr r2,HASH2 // Get hash table pointer
2427 + ori r3,r3,0x40 // Set secondary hash
2428 + b 00b // Try lookup again
2429 +
2430 +
2431 +/************************************************************************/
2432 +/* Synthesize an ISI Exception */
2433 +/************************************************************************/
2434 +
2435 +DoISI_603:
2436 + mfspr r3,SRR1
2437 + andi. r2,r3,0xFFFF // Clear upper bits of SRR1
2438 + addis r2,r2,0x4000 // Set bit 1 -> PTE not found (in HTAB)
2439 + mtctr r0 // Restore CTR
2440 +40: mtspr SRR1,r2
2441 + mfmsr r0 // Restore "normal" registers
2442 + xoris r0,r0,MSR_TGPR>>16
2443 + mtcrf 0x80,r3 // Restore CR0
2444 + sync // Some chip revs have problems here...
2445 + mtmsr r0
2446 + SOFT_VECTOR_ENTRY_603( 0x400 ) // Jump to the ISI vector
2447 +
2448 +
2449 +#ifdef P603_USE_G_BIT
2450 +DoISI_603_G:
2451 + mfspr r3,SRR1
2452 + andi. r2,r3,0xFFFF // Clear upper bits of SRR1
2453 +// addis r2,r2,0x0800 // Page protection violation
2454 + addis r2,r2,0x1000 // Guarded memory access
2455 + b 40b
2456 +#endif
2457 +
2458 +
2459 +/************************************************************************/
2460 +/* Synthesize a DSI exception */
2461 +/************************************************************************/
2462 +
2463 +DoDSI_603:
2464 + mfspr r3,SRR1
2465 + rlwinm r1,r3,9,6,6 // Get load/store bit
2466 + addis r1,r1,0x4000 // Set bit 1 -> PTE not found
2467 +
2468 +10: mtspr DSISR,r1
2469 + mtctr r0 // Restore CTR
2470 + andi. r2,r3,0xFFFF // Clear upper bits of SRR1
2471 + mtspr SRR1,r2
2472 + mfspr r1,DMISS // Get failing address
2473 + mtspr DAR,r1 // Set fault address
2474 + mfmsr r0 // Restore "normal" registers
2475 + xoris r0,r0,MSR_TGPR>>16
2476 + mtcrf 0x80,r3 // Restore CR0
2477 + sync // Some chip revs have problems here...
2478 + mtmsr r0
2479 + SOFT_VECTOR_ENTRY_603( 0x300 ) // Jump to the DSI vector
2480 +
2481 +DoDSI_603_P:
2482 + mfspr r3,SRR1
2483 + rlwinm r1,r3,9,6,6 // get load/store bit
2484 + addis r1,r1,0x800 // Set bit 4 (prot. violation)
2485 + b 10b
2486 diff --git a/drivers/macintosh/mol/asm-files/dec.S b/drivers/macintosh/mol/asm-files/dec.S
2487 new file mode 100644
2488 index 0000000..5c93634
2489 --- /dev/null
2490 +++ b/drivers/macintosh/mol/asm-files/dec.S
2491 @@ -0,0 +1,228 @@
2492 +/*
2493 + * Creation Date: <2001/06/21 17:10:35 samuel>
2494 + * Time-stamp: <2004/03/07 13:16:58 samuel>
2495 + *
2496 + * <dec.S>
2497 + *
2498 + * DEC / TimeBase stuff
2499 + *
2500 + * Copyright (C) 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se)
2501 + *
2502 + * This program is free software; you can redistribute it and/or
2503 + * modify it under the terms of the GNU General Public License
2504 + * as published by the Free Software Foundation
2505 + *
2506 + */
2507 +
2508 +/************************************************************************/
2509 +/* TBWU / TBWL */
2510 +/************************************************************************/
2511 +
2512 +#if 0
2513 +spr_tbwu:
2514 + blr // read (won't come here)
2515 + mr r3,r0
2516 + mftb r4
2517 + b update_tb
2518 +
2519 +spr_tbwl:
2520 + blr // read (won't come here)
2521 + mftbu r3
2522 + mr r4,r0
2523 + // ...fall through...
2524 +
2525 +// r3 = tbu, r4 = tbl, r0,r2,r5 free.
2526 +update_tb:
2527 + lwz r5,K_LOADED_DEC(r1)
2528 + mfdec r2
2529 + sub r5,r5,r2 // r5 = elapsed ticks
2530 +
2531 + li r2,0 // Set timebase
2532 + mttbl r4
2533 + mttbu r3
2534 + mttbl r4
2535 +
2536 + mfxer r2
2537 + subfc r4,r5,r4
2538 + addme r3,r3
2539 + stw r4,xTBL(r1)
2540 + stw r3,xTBU(r1)
2541 + mtxer r2
2542 + b emulation_done
2543 +#endif
2544 +
2545 +
2546 +/************************************************************************/
2547 +/* Load/restore DEC and TB */
2548 +/************************************************************************/
2549 +
2550 + //////////////////////////////////////////////////////////////
2551 + // recalc_int_stamp
2552 + //
2553 + // May modify: r0,r2-r5
2554 + //
2555 +
2556 +recalc_int_stamp:
2557 + crclr FBIT_RecalcDecInt
2558 +
2559 + lwz r5,xTIMER_STAMP(r1)
2560 + bf FBIT_DecSeenZero, 1f // FBIT_DecSeenZero must be set when DEC is loaded
2561 + bt FBIT_DecINT, 1f // interrupt might already be flagged...
2562 + mftb r3
2563 + lwz r4,xDEC_STAMP(r1) // Has the xDEC overflown already?
2564 + sub. r0,r4,r3
2565 + blt 2f // branch if xDEC < 0
2566 + sub. r0,r4,r5
2567 + blt 2f // branch if xDEC < xTIMER
2568 +1: mr r4,r5
2569 +2: stw r4,K_INT_STAMP(r1) // dec = xTIMER
2570 + blr
2571 +
2572 +
2573 + //////////////////////////////////////////////////////////////
2574 + // set_mol_dec
2575 + //
2576 + // May modify: r0,r2-r5
2577 + //
2578 + // Old 2.4 kernels assume that linux-DEC never ticks faster
2579 + // than the DEC interval measured from TB. Unfortunately,
2580 + // it is virtually impossible to keep DEC/TB in sync.
2581 + //
2582 + // Experimentally, the "worst case" senario is a linux DEC tick
2583 + // beeing delayed 0.04 ms (to be compare with the 20 ms period).
2584 + //
2585 + // Sequences similar to
2586 + //
2587 + // 1: mftb r2; mfdec r3; mftb r4; cmp r2,r4; bne 1b
2588 + //
2589 + // do *not* work - DEC and TB probably ticks on different edges.
2590 +
2591 +set_mol_dec:
2592 + lwz r5,K_INT_STAMP(r1) // DEC = K_INT_STAMP - tbl
2593 + mfdec r3 // Make sure linux interrupts *never*
2594 + mftb r2 // occur too fast
2595 +
2596 + sub r4,r5,r2
2597 + cmpw r4,r3
2598 + bgtlr
2599 + add r5,r3,r2 // K_DEC_STAMP = DEC + tbl
2600 + mtdec r4
2601 +
2602 + stw r5,K_DEC_STAMP(r1)
2603 + crset FBIT_MolDecLoaded
2604 + blr
2605 +
2606 + ///////////////////////////////////////////////////////////////
2607 + // set_kernel_dec
2608 + //
2609 + // May modify: r0,r2, cr
2610 + //
2611 +
2612 +set_kernel_dec:
2613 + lwz r0,K_DEC_STAMP(r1)
2614 + crclr FBIT_MolDecLoaded
2615 + mftb r2 // Keep linux-DEC coherent
2616 + sub r2,r0,r2 // DEC = stamp - tbl
2617 + mtdec r2
2618 + blr
2619 +
2620 +
2621 +
2622 +/************************************************************************/
2623 +/* DEC read/write */
2624 +/************************************************************************/
2625 +
2626 +_dec_read:
2627 + lwz r4,xDEC_STAMP(r1)
2628 + mftb r3
2629 + sub r0,r4,r3
2630 +
2631 + BUMP("dec_read")
2632 + GET_TICK_CNT(entry,"dec_read")
2633 + b simple_mfspr
2634 +
2635 +spr_dec:
2636 + b _dec_read
2637 +
2638 + // dec write. r0 = spr_value
2639 + BUMP("mtdec")
2640 + rlwinm. r5,r0,0,0,0 // seen zero?
2641 + mftb r4
2642 + cror FBIT_DecSeenZero,FBIT_DecSeenZero,eq
2643 + add r5,r4,r0
2644 + stw r5,xDEC_STAMP(r1) // set new dec value
2645 + bf FBIT_DecSeenZero, emulation_done
2646 + bl recalc_int_stamp // M: r0,r2-r5
2647 + btl FBIT_MolDecLoaded, set_kernel_dec // M: r0,r2
2648 + bl set_mol_dec // M: r0,r2-r5
2649 + b emulation_done
2650 +
2651 +
2652 +/************************************************************************/
2653 +/* Decrementer Exception */
2654 +/************************************************************************/
2655 +
2656 + // __dec_VECTOR (non-MOL dec exception)
2657 + //
2658 + // r3=cr, sprg1=saved_r1, sprg0=saved_r3
2659 + //
2660 + // An exception with DEC>=0 can occur if a mac-DEC overflows occurs
2661 + // just prior to a context switch. These exceptions should be
2662 + // dropped silently.
2663 +
2664 +__dec_VECTOR:
2665 + mfdec r1
2666 + cmpwi r1,0
2667 + blt+ 1f
2668 + mtcr r3 // Restore and exit
2669 + ABORT_TRAP( 0x900 )
2670 +1:
2671 + mtcr r3 // Restore and continue trap
2672 + CONTINUE_TRAP( 0x900 )
2673 +
2674 +VECTOR_( 0x900, "Decrementer", secint_bad, __dec_VECTOR )
2675 + EXCEPTION_PREAMBLE // r0-r5, CR, LR, r6/r7 = msr/nip
2676 + TRACE(0x900, "Decrementer")
2677 + mfdec r4
2678 + cmpwi r4,0
2679 + bge exception_return
2680 + bf FBIT_MolDecLoaded, take_linux_dec_exception
2681 +
2682 + mftb r3
2683 + lis r2,0x1000 // r2 = DEC rearm constant
2684 +
2685 + bf FBIT_DecSeenZero, 1f // check for xDEC overflow
2686 + lwz r4,xDEC_STAMP(r1)
2687 + sub. r0,r4,r3 // lt set if xDEC has overflown
2688 + cror FBIT_DecINT, FBIT_DecINT, lt // dec_int |= lt
2689 + crandc FBIT_DecSeenZero, FBIT_DecSeenZero, lt // szero &= ~lt
2690 +1:
2691 + lwz r5,xTIMER_STAMP(r1) // r5 = xTIMER_STAMP
2692 + sub. r0,r5,r3 // lt set if xTIMER has overflown
2693 + mtdec r2 // rearm DEC
2694 + blt- 2f // xTIMER has higher priority...
2695 +
2696 + // mac-dec interrupt
2697 + BUMP("DEC-overflow")
2698 + bl set_kernel_dec
2699 + bl recalc_int_stamp
2700 + bl set_mol_dec
2701 + GET_TICK_CNT(entry,"dec-overflow")
2702 + bf- FBIT_DecINT,exception_return // could occur if xTIMER has changed on us
2703 + lwz r4,xMSR(r1)
2704 + rlwinm. r0,r4,0,MSR_EE
2705 + beq- exception_return // no... simply return
2706 + BUMP("DEC-exception")
2707 + b mac_dec_trap
2708 +
2709 + // timer interrupt
2710 +2: BUMP("Timer-interrupt")
2711 + crset FBIT_RecalcDecInt // dec must be recalced
2712 + GET_TICK_CNT(entry,"timer-overflow")
2713 + MAC_EXIT_SAVE( RVEC_TIMER )
2714 +
2715 +
2716 +take_linux_dec_exception:
2717 + BUMP("Linux-DEC")
2718 + bl save_middle_regs
2719 + TAKE_EXCEPTION( 0x900 )
2720 diff --git a/drivers/macintosh/mol/asm-files/emuaccel.S b/drivers/macintosh/mol/asm-files/emuaccel.S
2721 new file mode 100644
2722 index 0000000..000e69d
2723 --- /dev/null
2724 +++ b/drivers/macintosh/mol/asm-files/emuaccel.S
2725 @@ -0,0 +1,188 @@
2726 +/*
2727 + * Creation Date: <2003/01/24 13:54:52 samuel>
2728 + * Time-stamp: <2003/08/14 03:12:00 samuel>
2729 + *
2730 + * <emuaccel.S>
2731 + *
2732 + * Emulation acceleration
2733 + *
2734 + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
2735 + *
2736 + * This program is free software; you can redistribute it and/or
2737 + * modify it under the terms of the GNU General Public License
2738 + * as published by the Free Software Foundation
2739 + *
2740 + */
2741 +
2742 +#include "emuaccel_sh.h"
2743 +
2744 + // emuaccel registers:
2745 + //
2746 + // r2 = emuaccel_slot
2747 + // r6,r7 = nip(return address)/mregs
2748 + //
2749 +
2750 + balign_8
2751 +emuaccel_mtmsr_rNN:
2752 +mFORLOOP([i],0,31,[
2753 + LOAD_EMUGPR_IM r0,i
2754 + b emulate_mtmsr_accel
2755 +])
2756 +emuaccel_mtsrr0_rNN:
2757 +mFORLOOP([i],0,31,[
2758 + .if (i <= 7)
2759 + LOAD_EMUGPR_IM r0,i
2760 + b emulate_mtsrr0_accel
2761 + .else
2762 + stw rPREFIX[]i,xSRR0(r1)
2763 + b emulation_done_noinc
2764 + .endif
2765 +])
2766 +emuaccel_mtsrr1_rNN:
2767 +mFORLOOP([i],0,31,[
2768 + .if (i <= 7)
2769 + LOAD_EMUGPR_IM r0,i
2770 + b emulate_mtsrr1_accel
2771 + .else
2772 + stw rPREFIX[]i,xSRR1(r1)
2773 + b emulation_done_noinc
2774 + .endif
2775 +])
2776 +emuaccel_mtsprg0_rNN:
2777 +mFORLOOP([i],0,31,[
2778 + .if (i <= 7)
2779 + LOAD_EMUGPR_IM r0,i
2780 + b emulate_mtsprg0_accel
2781 + .else
2782 + stw rPREFIX[]i,xSPRG0(r1)
2783 + b emulation_done_noinc
2784 + .endif
2785 +])
2786 +emuaccel_mtsprg1_rNN:
2787 +mFORLOOP([i],0,31,[
2788 + .if (i <= 7)
2789 + LOAD_EMUGPR_IM r0,i
2790 + b emulate_mtsprg1_accel
2791 + .else
2792 + stw rPREFIX[]i,xSPRG1(r1)
2793 + b emulation_done_noinc
2794 + .endif
2795 +])
2796 +emuaccel_mtsprg2_rNN:
2797 +mFORLOOP([i],0,31,[
2798 + .if (i <= 7)
2799 + LOAD_EMUGPR_IM r0,i
2800 + b emulate_mtsprg2_accel
2801 + .else
2802 + stw rPREFIX[]i,xSPRG2(r1)
2803 + b emulation_done_noinc
2804 + .endif
2805 +])
2806 +emuaccel_mtsprg3_rNN:
2807 +mFORLOOP([i],0,31,[
2808 + .if (i <= 7)
2809 + LOAD_EMUGPR_IM r0,i
2810 + b emulate_mtsprg3_accel
2811 + .else
2812 + stw rPREFIX[]i,xSPRG3(r1)
2813 + b emulation_done_noinc
2814 + .endif
2815 +])
2816 +emuaccel_mthid0_rNN:
2817 +mFORLOOP([i],0,31,[
2818 + .if (i <= 7)
2819 + LOAD_EMUGPR_IM r0,i
2820 + b emulate_mthid0_accel
2821 + .else
2822 + stw rPREFIX[]i,xHID0(r1)
2823 + b emulation_done_noinc
2824 + .endif
2825 +])
2826 +
2827 +emuaccel_nop:
2828 + b emulation_done_noinc
2829 +
2830 +emuaccel_rfi:
2831 + addi r6,r6,-4 // point nip to the rfi instruction
2832 + b emulate_rfi
2833 +
2834 +emuaccel_update_dec:
2835 + lwz r4,xDEC_STAMP(r1)
2836 + mftb r3
2837 + sub r0,r4,r3
2838 + stw r0,xDEC(r1)
2839 + b emulation_done_noinc
2840 +
2841 + balign_8
2842 +emuaccel_mtsr:
2843 + lwz r4,12(r2) // emuaccel paramamter (opcode)
2844 + addi r6,r6,-4 // back NIP
2845 + rlwinm r5,r4,14,24,28 // reg_num << 3
2846 + b emulate_mtsr
2847 +
2848 +
2849 +/************************************************************************/
2850 +/* implementation */
2851 +/************************************************************************/
2852 +
2853 +emulate_mtsrr0_accel:
2854 + stw r0,xSRR0(r1)
2855 + b emulation_done_noinc
2856 +emulate_mtsrr1_accel:
2857 + stw r0,xSRR1(r1)
2858 + b emulation_done_noinc
2859 +emulate_mtsprg0_accel:
2860 + stw r0,xSPRG0(r1)
2861 + b emulation_done_noinc
2862 +emulate_mtsprg1_accel:
2863 + stw r0,xSPRG1(r1)
2864 + b emulation_done_noinc
2865 +emulate_mtsprg2_accel:
2866 + stw r0,xSPRG2(r1)
2867 + b emulation_done_noinc
2868 +emulate_mtsprg3_accel:
2869 + stw r0,xSPRG3(r1)
2870 + b emulation_done_noinc
2871 +emulate_mthid0_accel:
2872 + stw r0,xHID0(r1)
2873 + b emulation_done_noinc
2874 +
2875 + balign_32
2876 +emulate_mtmsr_accel:
2877 + lwz r3,xMSR(r1) // r3 = old MSR
2878 + bl msr_altered
2879 +
2880 + GET_TICK_CNT(entry, "mtmsr-accel")
2881 + BUMP("emulate_mtmsr-accel")
2882 +
2883 + beq+ cr1,emulation_done_noinc // no doze... we are done
2884 + MAC_EXIT_SAVE( RVEC_MSR_POW ) // doze
2885 +
2886 +
2887 +
2888 +/************************************************************************/
2889 +/* setup */
2890 +/************************************************************************/
2891 +
2892 +#define EMUACCEL_REL(s) s - emuaccel_table
2893 +
2894 +#ifdef __linux__
2895 + .text 70 /* this table does not need to be relocated */
2896 +#endif
2897 + // format: emuaccel_inst, offset, table_index_mask
2898 +GLOBAL_SYMBOL(emuaccel_table):
2899 + .long EMUACCEL_MTMSR, EMUACCEL_REL( emuaccel_mtmsr_rNN ), 0x1f
2900 + .long EMUACCEL_MTSRR0, EMUACCEL_REL( emuaccel_mtsrr0_rNN ), 0x1f
2901 + .long EMUACCEL_MTSRR1, EMUACCEL_REL( emuaccel_mtsrr1_rNN ), 0x1f
2902 + .long EMUACCEL_MTSPRG0, EMUACCEL_REL( emuaccel_mtsprg0_rNN ), 0x1f
2903 + .long EMUACCEL_MTSPRG1, EMUACCEL_REL( emuaccel_mtsprg1_rNN ), 0x1f
2904 + .long EMUACCEL_MTSPRG2, EMUACCEL_REL( emuaccel_mtsprg2_rNN ), 0x1f
2905 + .long EMUACCEL_MTSPRG3, EMUACCEL_REL( emuaccel_mtsprg3_rNN ), 0x1f
2906 + .long EMUACCEL_MTHID0, EMUACCEL_REL( emuaccel_mthid0_rNN ), 0x1f
2907 + .long EMUACCEL_RFI, EMUACCEL_REL( emuaccel_rfi ), 0
2908 + .long EMUACCEL_UPDATE_DEC, EMUACCEL_REL( emuaccel_update_dec ), 0
2909 + .long EMUACCEL_MTSR, EMUACCEL_REL( emuaccel_mtsr ), 0
2910 + .long EMUACCEL_NOP, EMUACCEL_REL( emuaccel_nop ), 0
2911 + .long 0, 0, 0 /* end marker */
2912 +
2913 + .text
2914 diff --git a/drivers/macintosh/mol/asm-files/emulation.S b/drivers/macintosh/mol/asm-files/emulation.S
2915 new file mode 100644
2916 index 0000000..9b11621
2917 --- /dev/null
2918 +++ b/drivers/macintosh/mol/asm-files/emulation.S
2919 @@ -0,0 +1,714 @@
2920 +/*
2921 + * Creation Date: <97/07/26 18:23:02 samuel>
2922 + * Time-stamp: <2004/02/22 13:12:14 samuel>
2923 + *
2924 + * <emulation.S>
2925 + *
2926 + * Low-level emulation of some privileged instructions
2927 + *
2928 + * Copyright (C) 1997-2004 Samuel Rydh (samuel@ibrium.se)
2929 + *
2930 + * This program is free software; you can redistribute it and/or
2931 + * modify it under the terms of the GNU General Public License
2932 + * as published by the Free Software Foundation
2933 + *
2934 + */
2935 +
2936 +MACRO_0(INC_NIP, [
2937 + addi r6,r6,4
2938 +])
2939 +
2940 +
2941 +/************************************************************************/
2942 +/* program exception vector */
2943 +/************************************************************************/
2944 +
2945 + //////////////////////////////////////////////////////////////
2946 + // exception preamble
2947 + // r1 stack (mregs)
2948 + // r6,r7 nip / srr1
2949 + // cr4-7 flag_bits
2950 + //
2951 + // Saved r0-r5 (NOT SAVED: ctr, xer)
2952 +
2953 +VECTOR_( 0x700, "Program", secint_bad, mac_entry )
2954 + EXCEPTION_PREAMBLE // 46 cycles on a G3
2955 + TRACE(0x700, "Program")
2956 +
2957 + mtcrf 0x10,r7 // put srr1 bits (12-15) into cr3
2958 + bt 14,mac_program_trap
2959 + GET_INSTR_OPCODE // r6=nip, r2-r3, r4=opcode (cr not touched)
2960 + bt+ 13,emulate_priv_instr
2961 + bt+ 12,emulate_illegal_instr
2962 + mtcrf 0x20,r7 // put srr1 bits (8-11) into cr2
2963 + bt+ 11,mac_program_trap // bit 11 = fpu_exception
2964 +
2965 + // we should not come here
2966 + MAC_EXIT_SAVE( RVEC_UNUSUAL_PROGRAM_EXCEP )
2967 +
2968 +unhandled_priv_inst:
2969 + MAC_EXIT_SAVE( RVEC_PRIV_INST ) // r4 = opcode
2970 +
2971 +emulate_illegal_instr:
2972 + rlwinm r2,r4,32-1,22,31
2973 + lwz r3,xMSR(r1)
2974 + rlwinm r5,r4,14,24,28 // r5 = reg_num << 3 (instr. bits 6-10)
2975 + rlwimi r2,r4,16,16,21 // r2 = opcode
2976 +
2977 + rlwinm r0,r2,0,~0x80 // clear mtspr/mfspr bit
2978 + cmpwi r0,OPCODE(31,339) // mfspr/mtspr
2979 + bne 1f
2980 +
2981 + rlwinm r7,r7,0,14,10 // clear srr1 bit 11-13
2982 + cmpwi cr1,r2,OPCODE(31,339) // mfspr
2983 + oris r7,r7,0x4 // set bit 13 (privileged instr)
2984 +
2985 + beq- cr1,emulate_mfspr // r3=xMSR, r4=opcode, r5=reg_num
2986 + b emulate_mtspr // must be mtspr
2987 +1:
2988 +#ifdef EMULATE_603
2989 + bl emulate_603_instr
2990 +#endif
2991 + MAC_EXIT_SAVE( RVEC_ILLEGAL_INST ) // r4 = opcode
2992 +
2993 +
2994 +/************************************************************************/
2995 +/* mac exceptions */
2996 +/************************************************************************/
2997 +
2998 + /////////////////////////////////////////////////////////////
2999 + // mac_trap
3000 + //
3001 + // r2 exception vector
3002 + // r6 nip
3003 + // r7 reason bits (0-15)
3004 + //
3005 + // r0,r2-r5 may be modified
3006 +
3007 +mac_irq_trap:
3008 + li r2,0x500
3009 + li r7,0 // no reason bits
3010 + b mac_trap
3011 +
3012 +mac_dec_trap:
3013 + li r2,0x900
3014 + crclr FBIT_DecINT
3015 + li r7,0 // no reason bits
3016 + b mac_trap
3017 +
3018 + balign_32
3019 +mac_program_trap: // the reason bits already in r7 are used
3020 + __BUMP("mac_trap")
3021 + li r2,0x700
3022 +mac_trap:
3023 + lwz r3,xMSR(r1)
3024 + stw r6,xSRR0(r1) // mac-srr0 = nip
3025 + mr r4,r3 // copy xMSR to SRR1
3026 + mr r6,r2 // new nip
3027 + rlwinm r5,r3,25+1,31,31 // put MSR_IP (bit 25) in r5[31]
3028 + rlwimi r4,r7,0,0,15 // copy reason bits from r7 to SRR1
3029 + rlwimi r4,r3,0,6,6 // copy MSR_VEC bit of xMSR to SRR1
3030 + stw r4,xSRR1(r1) // srr1 = (msr & (0xffff|MSR_VEC)) | (srr1 & ~(0xffff|MSR_VEC))
3031 + rlwinm r4,r3,0,25,25 // copy MSR_IP to xMSR
3032 + neg r5,r5 // r5 = 0xffffffff * MSR_IP
3033 + rlwimi r4,r3,0,19,19 // copy MSR_ME to xMSR
3034 + rlwimi r6,r5,0,0,11 // insert exception prefix
3035 + stw r4,xMSR(r1)
3036 + GET_TICK_CNT(entry,"mac-expception")
3037 + b msr_exception_return
3038 +
3039 +rvec_trace_trap:
3040 + MAC_EXIT_SAVE( RVEC_TRACE_TRAP )
3041 +
3042 +
3043 +/************************************************************************/
3044 +/* decode privileged instruction */
3045 +/************************************************************************/
3046 +
3047 + /////////////////////////////////////////////////////////////
3048 + // emulate_priv_instr
3049 + // r4 opcode
3050 + // r6,r7 nip/srr1
3051 + //
3052 + // r0,r2-r5,lr free
3053 +
3054 + balign_32
3055 +emulate_priv_instr:
3056 + rlwinm r2,r4,32-1,22,31
3057 + lwz r3,xMSR(r1)
3058 + rlwinm r5,r4,14,24,28 // r5 = reg_num << 3 (instr. bits 6-10)
3059 + rlwimi r2,r4,16,16,21 // r2 = opcode
3060 +
3061 + GET_TICK_CNT(entry,"get_inst")
3062 + BUMP("decode_priv_inst")
3063 +
3064 + cmpwi cr1,r2,OPCODE(31,339) // mfspr (both user and supervisor mode)
3065 + beq- cr1,emulate_mfspr // r3=xMSR, r4=opcode, r5=reg_num
3066 +
3067 + cmpwi cr2,r2,OPCODE(31,467) // mtspr (both user and supervisor mode)
3068 + beq- cr2,emulate_mtspr
3069 +
3070 + andi. r3,r3,MSR_PR // only emulate in supervisor mode
3071 + bne- mac_program_trap
3072 +
3073 + cmpwi cr3,r2,OPCODE(31,83) // mfmsr
3074 + beq- cr3,emulate_mfmsr
3075 +
3076 + cmpwi cr0,r2,OPCODE(31,146) // mtmsr
3077 + beq- cr0,emulate_mtmsr
3078 +
3079 + cmpwi cr1,r2,OPCODE(19,50) // rfi
3080 + beq- cr1,emulate_rfi
3081 +
3082 + cmpwi cr2,r2,OPCODE(31,595) // mfsr
3083 + beq- cr2,emulate_mfsr
3084 +
3085 + cmpwi cr3,r2,OPCODE(31,659) // mfsrin
3086 + beq- cr3,emulate_mfsrin
3087 +
3088 + cmpwi cr0,r2,OPCODE(31,210) // mtsr
3089 + beq- cr0,emulate_mtsr
3090 +
3091 + cmpwi cr1,r2,OPCODE(31,242) // mtsrin
3092 + beq- cr1,emulate_mtsrin
3093 +
3094 + cmpwi cr2,r2,OPCODE(31,306) // tlbie
3095 + beq- cr2,emulate_tlbie
3096 +
3097 + cmpwi cr3,r2,OPCODE(31,566) // tlbsync
3098 + beq- cr3,emulate_tlbsync
3099 +
3100 + cmpwi cr0,r2,OPCODE(31,467) // dcbi
3101 + beq- cr0,emulate_dcbi
3102 +#ifdef EMULATE_603
3103 + cmpwi cr1,r2,OPCODE(31,978) // tlbld
3104 + beq- cr1,emulate_tlbld
3105 +
3106 + cmpwi cr2,r2,OPCODE(31,1010) // tlbli
3107 + beq- cr2,emulate_tlbli
3108 +#endif
3109 + // Program-trap, illegal instruction
3110 + b unhandled_priv_inst // r4 = opcode
3111 +
3112 +
3113 +#ifdef EMULATE_603
3114 +emulate_603_instr:
3115 + rlwinm r2,r4,32-1,22,31
3116 + rlwimi r2,r4,16,16,21 // r2 = opcode
3117 +
3118 + cmpwi cr0,r2,OPCODE(31,978) // tlbld
3119 + beq cr0,2f
3120 + cmpwi cr1,r2,OPCODE(31,1010) // tlbli
3121 + beq cr1,2f
3122 + cmpwi cr2,r2,OPCODE(31,339) // mfspr
3123 + beq cr2,1f
3124 + cmpwi cr3,r2,OPCODE(31,467) // mtspr
3125 + bnelr cr3
3126 +1: rlwinm r3,r4,32-16,27,31
3127 + rlwimi r3,r4,32-6,22,26 // r3 = spr#
3128 + cmpwi r3,976 // first 603 SPR
3129 + bltlr
3130 + cmpwi r3,982 // last 603 SPR
3131 + bgtlr
3132 +2:
3133 + rlwinm r7,r7,0,14,10 // clear bit 11-13
3134 + oris r7,r7,0x4 // set bit 13
3135 + b emulate_priv_instr
3136 +
3137 +#endif /* EMULATE_603 */
3138 +
3139 +
3140 +/************************************************************************/
3141 +/* mac register access */
3142 +/************************************************************************/
3143 +
3144 +MACRO(LOAD_EMUGPR_IM, [dreg,ereg], [
3145 +.if _ereg <= 7
3146 + lwz _dreg,xGPR0+_ereg[]*4(r1)
3147 +.else
3148 + mr _dreg,rPREFIX[]_ereg
3149 +.endif
3150 +])
3151 +
3152 +MACRO(STORE_EMUGPR_IM, [sreg,ereg], [
3153 +.if _ereg <= 7
3154 + stw _sreg,xGPR0+_ereg[]*4(r1)
3155 +.else
3156 + mr rPREFIX[]_ereg, _sreg
3157 +.endif
3158 +])
3159 +
3160 + balign_32
3161 +store_gpr_table:
3162 +mFORLOOP([i],0,31,[
3163 + STORE_EMUGPR_IM r0,i
3164 + blr
3165 +])
3166 +
3167 +load_gpr_table:
3168 +mFORLOOP([i],0,31,[
3169 + LOAD_EMUGPR_IM r0,i
3170 + blr
3171 +])
3172 +
3173 +MACRO(EMU_LOAD_GPR, [reg, scr], [
3174 + LI_PHYS( _scr, load_gpr_table )
3175 + add rPREFIX[]_scr,_reg,rPREFIX[]_scr
3176 + mtlr rPREFIX[]_scr
3177 + blrl
3178 +])
3179 +
3180 +MACRO(EMU_STORE_GPR, [reg, scr], [
3181 + LI_PHYS( _scr, store_gpr_table )
3182 + add rPREFIX[]_scr,_reg,rPREFIX[]_scr
3183 + mtlr rPREFIX[]_scr
3184 + blrl
3185 +])
3186 +
3187 +
3188 +
3189 +/************************************************************************/
3190 +/* instruction emulation */
3191 +/************************************************************************/
3192 +
3193 + //////////////////////////////////////////////////////////
3194 + // emulate_xxxxx
3195 + // r3 xMSR
3196 + // r4 opcode
3197 + // r5 regnum<<3 (from opcode bits 6-10)
3198 + //
3199 + // May modify: r0,r2-r5 (lr)
3200 +
3201 +/********************************************************************/
3202 +emulate_mfmsr:
3203 + lwz r0,xMSR(r1)
3204 + EMU_STORE_GPR r5, /**/ R2
3205 + GET_TICK_CNT( entry, "mfmsr" )
3206 + b emulation_done
3207 +
3208 +/********************************************************************/
3209 +emulate_mfspr: // r3 = xMSR
3210 + BUMP("emulate_mfspr")
3211 + rlwimi r4,r4,32-10,21,25 // flip spr
3212 + rlwinm r0,r3,32-14,31,31 // r0(bit31) = MSR_PR
3213 + addi r3,r1,K_SPR_HOOKS
3214 + rlwinm r2,r4,32-4,20,29 // r2 = spr# << 2
3215 + addi r4,r1,xSPR_BASE
3216 + lwzx r3,r2,r3 // hook in r3
3217 + and. r0,r0,r3 // privileged SPR?
3218 + bne- mac_program_trap
3219 + lwzx r0,r2,r4 // value in r0
3220 + mtlr r3
3221 + blr // call hook
3222 +
3223 +/********************************************************************/
3224 +emulate_mtspr: // r3 = xMSR
3225 + BUMP("emulate_mtspr")
3226 + rlwimi r4,r4,32-10,21,25 // flip spr
3227 + EMU_LOAD_GPR r5, /**/ R2 // value in r0
3228 + rlwinm r2,r4,32-4,20,29 // r2 = spr# << 2
3229 + addi r4,r1,K_SPR_HOOKS
3230 + rlwinm r3,r3,32-14,31,31 // r3(bit31) = MSR_PR
3231 + lwzx r4,r2,r4 // hook in r4
3232 + addi r5,r2,xSPR_BASE // r5+r1 points to SPR reg
3233 + addi r4,r4,4 // branch to hook +4
3234 + and. r3,r3,r4 // privileged SPR?
3235 + bne- mac_program_trap // privileged exception
3236 + mtlr r4 // lsb is discarded...
3237 + blr // call hook
3238 +
3239 +
3240 +/********************************************************************/
3241 + balign_32
3242 +emulate_mtmsr:
3243 + lwz r3,xMSR(r1) // r3 = old MSR
3244 + LI_PHYS( R2, load_gpr_table )
3245 + add r2,r5,r2
3246 + mtlr r2
3247 + blrl // r0 = new MSR
3248 +
3249 + INC_NIP
3250 + bl msr_altered
3251 +
3252 + GET_TICK_CNT(entry, "mtmsr")
3253 + BUMP("emulate_mtmsr")
3254 +
3255 + beq+ cr1,emulation_done_noinc
3256 + MAC_EXIT_SAVE( RVEC_MSR_POW ) // POW 1 => doze
3257 +
3258 +
3259 +/********************************************************************/
3260 +emulate_rfi:
3261 + BUMP("rfi")
3262 + lis r4,(MSR_VEC)>>16
3263 + lwz r0,xSRR1(r1)
3264 + ori r4,r4,0xffff
3265 +#ifdef EMULATE_603
3266 + oris r4,r4,(MSR_TGPR)>>16
3267 +#endif
3268 + lwz r3,xMSR(r1) // r3 = old MSR
3269 + and r0,r0,r4
3270 + andc r5,r3,r4
3271 + lwz r6,xSRR0(r1) // new nip = SRR0
3272 + or r0,r0,r5
3273 +
3274 + bl msr_altered // r0,r2-r5, r7 [srr1] updated
3275 +
3276 + GET_TICK_CNT(entry,"rfi")
3277 +
3278 + lwz r3,K_BREAK_FLAGS(r1) // break at rfi support
3279 + andi. r3,r3,BREAK_RFI
3280 + beq+ exception_return
3281 + li r4,BREAK_RFI // r4 = flag causing the break
3282 + MAC_EXIT_SAVE( RVEC_BREAK )
3283 +
3284 +
3285 +/********************************************************************/
3286 +#ifdef EMULATE_603
3287 +emulate_tlbli:
3288 + LOADI r3,EXTERN(do_tlbli)
3289 + b 1f
3290 +emulate_tlbld:
3291 + LOADI r3,EXTERN(do_tlbld)
3292 + b 1f
3293 +emulate_tlbie:
3294 + LOADI r3,EXTERN(do_tlbie)
3295 +1: INC_NIP
3296 + rlwinm r5,r4,32-8,24,28 // r5 = #B << 3
3297 + EMU_LOAD_GPR r5, /**/ R2 // value ret. in r0
3298 + mr r4,r0 // r4 = ea
3299 + b call_kernel_save
3300 +#else
3301 +emulate_tlbie:
3302 + b emulation_done
3303 +#endif /* EMULATE_603 */
3304 +
3305 +/********************************************************************/
3306 +emulate_tlbsync:
3307 + b emulation_done
3308 +
3309 +/********************************************************************/
3310 +emulate_dcbi:
3311 + b unhandled_priv_inst // r4 = opcode
3312 +
3313 +/********************************************************************/
3314 +emulate_mfsrin:
3315 + rlwinm r2,r4,32-8,24,28 // r2 = #B << 3
3316 + EMU_LOAD_GPR r2, /**/ R3 // r0 = reg B
3317 + rlwinm r3,r0,6,26,29 // r3 = #sr << 2
3318 + b 1f
3319 +emulate_mfsr:
3320 + rlwinm r3,r4,32-14,26,29 // r3 = #sr << 2
3321 +1: addi r2,r1,xSEGR_BASE
3322 + lwzx r0,r3,r2
3323 + EMU_STORE_GPR r5, /**/ R2
3324 + GET_TICK_CNT(entry, "mfsr")
3325 + BUMP("mfsr_")
3326 + b emulation_done
3327 +
3328 +
3329 +
3330 +/************************************************************************/
3331 +/* SPR - emulation */
3332 +/************************************************************************/
3333 +
3334 + ////////////////////////////////////////////////////////////
3335 + // read (offset 0)
3336 + // r0 spr_value
3337 + // r2 spr << 2
3338 + // r5 dreg << 3
3339 + //
3340 + // write (offset 4)
3341 + // r0 gpr_value
3342 + // r2 spr << 2
3343 + // r5 spr offset (relative r1)
3344 + //
3345 + // Safe to modify: r2-r5, lr
3346 + // NOT SAVED: ctr, xer
3347 +
3348 +/********************************************************************/
3349 +simple_mfspr:
3350 + EMU_STORE_GPR r5, /**/ R3
3351 + GET_TICK_CNT(entry,"simple_mfspr")
3352 + b emulation_done
3353 +
3354 +GLOBAL_SYMBOL(r__spr_read_write):
3355 +spr_read_write:
3356 + b simple_mfspr
3357 + stwx r0,r5,r1 // value in r0
3358 + GET_TICK_CNT(entry,"simple_mtspr")
3359 + b emulation_done
3360 +
3361 +
3362 +/********************************************************************/
3363 +GLOBAL_SYMBOL(r__spr_read_only):
3364 +spr_read_only:
3365 + b simple_mfspr // allow read
3366 + b emulation_done // ignore write
3367 +
3368 +/********************************************************************/
3369 +GLOBAL_SYMBOL(r__spr_illegal):
3370 +spr_illegal:
3371 + nop // spr read entry
3372 + rlwinm r7,r7,0,15,10 // clear srr1 bit 11-14
3373 + oris r7,r7,0x8 // set bit 12 (privileged instr)
3374 + b mac_program_trap
3375 +
3376 +
3377 +/********************************************************************/
3378 +unhandled_spr_read:
3379 + srwi r4,r2,2
3380 + srwi r5,r5,3
3381 + // r4 = spr#
3382 + // r5 = dest gpr
3383 + MAC_EXIT_SAVE( RVEC_SPR_READ )
3384 +
3385 +unhandled_spr:
3386 + b unhandled_spr_read // read hook (offs 0)
3387 +unhandled_spr_write: // write hook (offs 4)
3388 + srwi r4,r2,2
3389 + mr r5,r0
3390 + // r4 = spr#
3391 + // r5 = register-value
3392 + MAC_EXIT_SAVE( RVEC_SPR_WRITE )
3393 +
3394 +/********************************************************************/
3395 +spr_bat:
3396 + b simple_mfspr // read has no side-effects
3397 + INC_NIP
3398 + LOADI r3,EXTERN(do_mtbat)
3399 + bl save_middle_regs // Must do this before touching r6-r12
3400 + srwi r4,r2,2 // r4 = spr#
3401 + mr r5,r0 // r5 = value
3402 + li r6,0 // not forced
3403 + b call_kernel
3404 +
3405 +/********************************************************************/
3406 +spr_sdr1:
3407 + b simple_mfspr // read has no side-effects
3408 + INC_NIP
3409 + LOADI r3,EXTERN(do_mtsdr1)
3410 + mr r4,r0 // r4 = value
3411 + b call_kernel_save
3412 +
3413 +
3414 +
3415 +
3416 +/************************************************************************/
3417 +/* handle MSR changes */
3418 +/************************************************************************/
3419 +
3420 + ////////////////////////////////////////////////////////////
3421 + // msr_exception_return (exception taken)
3422 + //
3423 + // r6, r7: nip / srr1
3424 + //
3425 + // modifies: r0,r2-r5 (r7 updated)
3426 +
3427 + balign_16
3428 +msr_exception_return:
3429 + addi r3,r1,K_UNMAPPED_SR_BASE // set unmapped context
3430 + li r7,(MSR_ME | MSR_SE | MSR_IR | MSR_DR | MSR_PR)
3431 + stw r3,K_CUR_SR_BASE(r1)
3432 + li r5,(fb_DbgTrace | fb_Trace)
3433 + ori r7,r7,MSR_EE
3434 +
3435 + bt+ FBIT_DbgTrace, 1f
3436 + li r5,0
3437 + rlwinm r7,r7,0,~MSR_SE
3438 +1:
3439 + stw r3,K_SR_DATA(r1)
3440 + li r4,fb_LoadSegreg
3441 +
3442 + stw r3,K_SR_INST(r1)
3443 + mtcrf TRACE_CR_FIELD,r5 // set singlestep bits [cr6]
3444 + mtcrf MMU_CR_FIELD,r4
3445 +
3446 + stw r7,K_MSR(r1)
3447 + b exception_return
3448 +
3449 +
3450 + ////////////////////////////////////////////////////////////
3451 + // msr_altered
3452 + //
3453 + // r6, r7: nip / srr1
3454 + //
3455 + // r0 = new msr
3456 + // r3 = old msr
3457 + //
3458 + // Sets cr1.ne if we MSR_POW is set
3459 + //
3460 + // M: r2-r5 (r7 updated).
3461 + // r0 may _NOT_ be modified
3462 +
3463 +#define MSR_CLEARBITS (MSR_FP | MSR_FE0 | MSR_FE1 | MSR_BE | MSR_SE)
3464 +#define MSR_COPYBITS (MSR_BE | MSR_SE)
3465 +
3466 + balign_32
3467 +msr_altered:
3468 +#ifdef EMULATE_603
3469 + bf+ FBIT_603_AltGPR,7f // 603 alternate GPR support
3470 + rlwinm. r5,r0,0,MSR_TGPR
3471 + bne+ 7f
3472 + lwz r2,xGPRSAVE0_603(r1) // MSR_TGPR cleared...
3473 + lwz r4,xGPRSAVE1_603(r1)
3474 + lwz r5,xGPRSAVE2_603(r1)
3475 + stw r2,xGPR0(r1)
3476 + lwz r2,xGPRSAVE3_603(r1)
3477 + stw r4,xGPR1(r1)
3478 + stw r5,xGPR2(r1)
3479 + stw r2,xGPR3(r1)
3480 + crclr FBIT_603_AltGPR
3481 +7:
3482 +#endif
3483 + li r7,(MSR_ME | MSR_SE | MSR_IR | MSR_DR | MSR_PR)
3484 + stw r0,xMSR(r1)
3485 + xor r3,r3,r0 // r3 == MSR bit toggle
3486 + bt- FBIT_IRQPending,test_for_irq // M: r2
3487 +irq_test_ret:
3488 + rlwinm r4,r0,0,MSR_POW // MSR_POW
3489 + ori r7,r7,MSR_EE
3490 + andi. r3,r3,(MSR_DR|MSR_IR|MSR_PR) // MMU change (cr unused)?
3491 + bt- FBIT_DecINT,test_for_dec // M: r2
3492 +dec_test_ret:
3493 + cmpwi cr1,r4,0 // MSR_POW set?
3494 + li r2,(fb_DbgTrace | fb_Trace)
3495 + cmpwi cr2,r3,0
3496 + bt- FBIT_DbgTrace,1f
3497 + rlwinm r2,r0,(21+32-FBIT_Trace),fb_Trace // MSR_SE[21] -> FBIT_Trace
3498 + rlwimi r7,r0,0,(MSR_SE|MSR_BE) // no debugger; copy MSR_SE and MSR_BE
3499 +1:
3500 + stw r7,K_MSR(r1)
3501 + mtcrf TRACE_CR_FIELD,r2 // set singlestep bits [cr6]
3502 +
3503 + bne cr2,1f // bnelr is slower...
3504 + blr
3505 +1:
3506 + /* MMU change */
3507 + BUMP("MMU-change")
3508 +
3509 + andi. r3,r0,(MSR_IR | MSR_DR) // IR DR part of index
3510 + addi r5,r1,K_MSR_SR_TABLE
3511 + addi r4,r3,MSR_DR // splitmode (MSR_DR != MSR_IR) testing
3512 + rlwimi r3,r0,32-8,25,25 // [PR IR DR] index to K_MSR_SR_TABLE
3513 + lwzux r3,r5,r3 // set sr bases from K_MSR_SR_TABLE
3514 + andi. r4,r4,MSR_IR // non-zero if in splitmode
3515 + lwz r2,4(r5)
3516 + li r4,(fb_InSplitmode | fb_LoadSegreg | fb_PrepareSplitmode)
3517 + lwz r5,8(r5)
3518 + stw r3,K_CUR_SR_BASE(r1) // new sr base in r3 (used below)
3519 + stw r2,K_SR_DATA(r1)
3520 + bne- 1f
3521 + li r4,fb_LoadSegreg // cur_sr_base changed
3522 +1: stw r5,K_SR_INST(r1)
3523 + mtcrf MMU_CR_FIELD,r4
3524 + blr
3525 +
3526 +test_for_irq:
3527 + BUMP("test-for-irq")
3528 + and r2,r3,r0 // check whether we are turning external interrupts on
3529 + andi. r2,r2,MSR_EE // we need to recheck IRQs in userspace then
3530 + beq+ 1f
3531 + lwz r4,xHOSTIRQ_ACTIVE_CNT(r1)
3532 + cmpwi r4,0 // only return if some host irq is up
3533 + beq+ 1f
3534 + MAC_EXIT_SAVE(RVEC_CHECK_IRQS)
3535 +
3536 +1: andi. r2,r0,MSR_EE
3537 + beq irq_test_ret
3538 + b mac_irq_trap
3539 +
3540 +test_for_dec:
3541 + BUMP("test-for-dec")
3542 + andi. r2,r0,MSR_EE
3543 + beq dec_test_ret
3544 + b mac_dec_trap
3545 +
3546 +force_msr_altered:
3547 + BUMP("force-msr-altered")
3548 + lwz r0,xMSR(r1) // r0 = new MSR
3549 + xori r3,r0,(MSR_DR|MSR_IR) // r3 = faked old MSR
3550 + b msr_altered // might throw an exception...
3551 +
3552 + // msr_altered( kv )
3553 +GLOBAL_SYMBOL(r__msr_altered):
3554 + lwz r5,xFLAG_BITS(r3)
3555 + ori r5,r5,fb_MsrModified
3556 + stw r5,xFLAG_BITS(r3)
3557 + blr
3558 +
3559 +
3560 +/************************************************************************/
3561 +/* initialize special purpose register table */
3562 +/************************************************************************/
3563 +
3564 +MACRO(SPR_HOOK, [spr, hook], [ LI_PHYS( R8, _hook ) ; stw r8,(((_spr)*4)+K_SPR_HOOKS)(r3) ])
3565 +
3566 +// The LSB of a SPR hook specifies that the SPR is privileged (these bits are
3567 +// set from C-code).
3568 +
3569 + // r3 = kvars
3570 +GLOBAL_SYMBOL(r__initialize_spr_table):
3571 + LI_PHYS( R7, unhandled_spr )
3572 + addi r8,r3,K_SPR_HOOKS-4
3573 + li r9,1024
3574 + mtctr r9
3575 +1: stwu r7,4(r8)
3576 + bdnz 1b
3577 +
3578 + // XXX for now...
3579 + SPR_HOOK TBWU, spr_read_write
3580 + SPR_HOOK TBWL, spr_read_write
3581 +
3582 + // SPRs that have side effects
3583 + SPR_HOOK SDR1, spr_sdr1
3584 + SPR_HOOK DEC, spr_dec
3585 +
3586 + // BATs
3587 + mFORLOOP([nn],0,15,[
3588 + SPR_HOOK eval(nn+IBAT0U), spr_bat
3589 + ])
3590 + blr
3591 +
3592 +
3593 +/************************************************************************/
3594 +/* initialize msr segment register table */
3595 +/************************************************************************/
3596 +
3597 + /////////////////////////////////////////////////////////////
3598 + // initialize_sr_offs_table
3599 + //
3600 + // Copy sr_offs_table to K_MSR_SR_TABLE
3601 + // r1 is added to each element
3602 +
3603 +initialize_msr_sr_table:
3604 + mflr r8 // Get address of table
3605 + bl sr_offs_table
3606 + mflr r3
3607 + mtlr r8
3608 +
3609 + li r5,4*8 // #words in table
3610 + mtctr r5
3611 + addi r3,r3,-4
3612 + addi r4,r1,K_MSR_SR_TABLE-4
3613 +1:
3614 + lwzu r6,4(r3)
3615 + add r6,r6,r1 // And add r1
3616 + stwu r6,4(r4)
3617 + bdnz 1b
3618 + blr
3619 +
3620 + // Used to construct msr_sr_table (mbase is added)
3621 +sr_offs_table:
3622 + blrl
3623 + /* K_CUR_SR_BASE, K_SR_DATA_BASE, K_SR_INST_BASE, dummy */
3624 +
3625 + .long K_UNMAPPED_SR_BASE, K_UNMAPPED_SR_BASE, K_UNMAPPED_SR_BASE, 0
3626 + .long K_SPLIT_SR_BASE, K_SV_SR_BASE, K_UNMAPPED_SR_BASE, 0 /* DR */
3627 + .long K_SPLIT_SR_BASE, K_UNMAPPED_SR_BASE, K_SV_SR_BASE, 0 /* IR */
3628 + .long K_SV_SR_BASE, K_SV_SR_BASE, K_SV_SR_BASE, 0 /* DR|IR */
3629 +
3630 + .long K_UNMAPPED_SR_BASE, K_UNMAPPED_SR_BASE, K_UNMAPPED_SR_BASE, 0 /* PR */
3631 + .long K_SPLIT_SR_BASE, K_USER_SR_BASE, K_UNMAPPED_SR_BASE, 0 /* PR|DR */
3632 + .long K_SPLIT_SR_BASE, K_UNMAPPED_SR_BASE, K_USER_SR_BASE, 0 /* PR|IR */
3633 + .long K_USER_SR_BASE, K_USER_SR_BASE, K_USER_SR_BASE, 0 /* PR|DR|IR */
3634 diff --git a/drivers/macintosh/mol/asm-files/entry.S b/drivers/macintosh/mol/asm-files/entry.S
3635 new file mode 100644
3636 index 0000000..d24453f
3637 --- /dev/null
3638 +++ b/drivers/macintosh/mol/asm-files/entry.S
3639 @@ -0,0 +1,433 @@
3640 +/*
3641 + * Creation Date: <2001/01/30 00:22:35 samuel>
3642 + * Time-stamp: <2004/03/07 13:33:39 samuel>
3643 + *
3644 + * <entry.S>
3645 + *
3646 + * Emulator/mac switching
3647 + *
3648 + * Copyright (C) 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se)
3649 + *
3650 + * This program is free software; you can redistribute it and/or
3651 + * modify it under the terms of the GNU General Public License
3652 + * as published by the Free Software Foundation
3653 + *
3654 + */
3655 +
3656 +/* Short note about DEC. Due to the kernel implementation of the DEC
3657 + * exception handler (and get_time_of_day) in the 2.3/2.4 kernel, we
3658 + * must try to maintain coherency between DEC and TB. In any case,
3659 + * we must NEVER let DEC tick faster than TB, or get_time_of_day will
3660 + * occasionally return bogus values (the result is usually
3661 + * misbehaving X).
3662 + */
3663 +
3664 +/************************************************************************/
3665 +/* Mac Entry */
3666 +/************************************************************************/
3667 +
3668 + //////////////////////////////////////////////////////////
3669 + // mac_entry_initialize
3670 + //
3671 + // Run once in order to store certain things (segment
3672 + // registers and NIP)
3673 + //
3674 + // sprg1 userspace stack
3675 + // r6 emulator return point after 'call_kernel'
3676 + //
3677 + // Safe to modify: r0-r12, lr, ctr
3678 +
3679 +mac_entry_initialize:
3680 + __ZERO_TICK_CNT(entry)
3681 +
3682 + // Save emulator return point (skip over illegal inst)
3683 + mfsrr0 r5
3684 + addi r5,r5,4
3685 + stw r5,K_EMULATOR_NIP(r1) // This sets the return point once and for all
3686 + stw r2,K_EMULATOR_TOC(r1) // r2==TOC (not on linux though)
3687 + stw r6,K_EMULATOR_KCALL_NIP(r1) // Return point after 'call_kernel'
3688 + mfsrr1 r6
3689 + mfsprg_a1 r3
3690 + stw r6,K_EMULATOR_MSR(r1) // we want to return through mac_exit
3691 + stw r3,K_EMULATOR_STACK(r1)
3692 +
3693 + lwz r3,xFLAG_BITS(r1) // Best to initialize the flag bits
3694 + mtcr r3
3695 +
3696 + // msr to be used in mac-mode
3697 + LOADI r3,(MSR_ME | MSR_IR | MSR_DR | MSR_PR | MSR_EE)
3698 + stw r3,K_MSR(r1)
3699 +
3700 + PERF_MONITOR_SETUP /**/ r4
3701 +
3702 + addi r3,r1,K_EMULATOR_SR // Save segment registers
3703 + SAVE_SEGMENT_REGS r3, /**/ r4,r5
3704 + SAVE_IBATS K_IBAT0U_SAVE, /**/ r3 // And save linux BAT registers
3705 + SAVE_DBATS K_DBAT0U_SAVE, /**/ r3
3706 +
3707 + bl initialize_msr_sr_table
3708 +
3709 + addi r3,r1,K_EMULATOR_SR
3710 + LOAD_SEGMENT_REGS r3, /**/ r4,r5
3711 +
3712 + li r3,RVEC_EXIT
3713 + b exit_
3714 +
3715 +
3716 + ////////////////////////////////////////////////////////////////////
3717 + // mac_entry [ENTRYPOINT]
3718 + //
3719 + // sprg1 userspace stack
3720 + // r4 MOL_ENTRY_R4_MAGIC
3721 + // r5 magic
3722 + // r6 call_kernel return point (if initializing)
3723 + // r7 session number | initialize flag
3724 + //
3725 + // srr1 emulator msr
3726 + // r13-r31 mac gprs
3727 + // fr14-fr31 mac fp registers
3728 + // fr0-fr12 mac fp registers (see xFPU_STATE)
3729 +
3730 +1: li r4,1
3731 + stw r4,ST_MAGIC(r1)
3732 +2: mtcr r3 // restore registers
3733 + CONTINUE_TRAP( 0x700 ) // not MOL, take the trap
3734 +
3735 + balign_32
3736 +mac_entry:
3737 + lis_svh R1,SPECVAR_SESSION_TABLE
3738 + cmpwi r4,MOL_ENTRY_R4_MAGIC // MOL switch magic.
3739 + ori_svl R1,R1,SPECVAR_SESSION_TABLE
3740 + bne- 2b
3741 + lwz r4,ST_MAGIC(r1) // check that the magic match
3742 + cmplwi r5,1 // and is greater than 1
3743 + cmpw cr1,r5,r4
3744 + ble- 2b
3745 + addi r5,r1,ST_KVARS_PH // get kvars for this session
3746 + rlwinm r4,r7,2,((MAX_NUM_SESSIONS-1)*4)
3747 + bne- cr1,1b // r1 must point to session table
3748 + lwzx r1,r4,r5 // set r1 to kvars
3749 + cmpwi cr1,r1,0
3750 + cmplwi r7,MAX_NUM_SESSIONS
3751 + beq- cr1,2b // kvars == NULL
3752 + bge- mac_entry_initialize // initialize flag set
3753 +
3754 + // =====================================================================
3755 + // entrypoint
3756 + // =====================================================================
3757 +
3758 + __ZERO_TICK_CNT(entry)
3759 + TRACE(0x1111, "mac_entry")
3760 +
3761 + // Save emulator registers (r1,msr) and restore flag bits
3762 + mfsprg_a1 r3
3763 + lwz r4,xFLAG_BITS(r1)
3764 + stw r3,K_EMULATOR_STACK(r1)
3765 + mfsrr1 r6
3766 + mtcr r4
3767 + stw r6,K_EMULATOR_MSR(r1) // The MSR_FP/MSR_VEC bits are of interest...
3768 +
3769 + // Setup mac-environment
3770 +
3771 + btl FBIT_RecalcDecInt, recalc_int_stamp // M: r0,r2-r5
3772 + bl set_mac_context // M: r0,r2-r12,XER
3773 + bl set_mol_dec // M: r0,r2-r5
3774 +
3775 + crset FBIT_LoadSegreg // Load segment registers below
3776 +
3777 + RESTORE_MIDDLE_REGS // Loads r6,r7 (nip/msr) r8-r12, ctr, xer,
3778 +
3779 + rlwinm r7,r7,0,~MSR_VEC // We always clear MSR_VEC (MSR_FP should be off already)
3780 + stw r7,K_MSR(r1) // (enabling MSR_VEC is relatively cheap)
3781 + btl- FBIT_MsrModified,msr_altered_entry
3782 +
3783 + GET_TICK_CNT(entry, "mac_entry")
3784 +
3785 + bt- FBIT_DecINT,test_for_dec_int // check for DEC interrupts
3786 + b exception_return
3787 +
3788 +test_for_dec_int:
3789 + lwz r3,xMSR(r1)
3790 + rlwinm. r3,r3,0,MSR_EE // MSR_EE is set?
3791 + bne mac_dec_trap // if so take a DEC interrupt
3792 + b exception_return
3793 +
3794 +msr_altered_entry:
3795 + crclr FBIT_MsrModified
3796 + b force_msr_altered
3797 +
3798 +
3799 + /////////////////////////////////////////////////////////////
3800 + // All paths back to mac-mode goes through one of these
3801 + // functions.
3802 + //
3803 + // emulation_done
3804 + // emulation_done_noinc
3805 + // exception_return
3806 +
3807 + balign_32
3808 +emulation_done:
3809 + addi r6,r6,4 // increase NIP
3810 +emulation_done_noinc:
3811 + bt- FBIT_Trace, rvec_trace_trap
3812 + GET_TICK_CNT(entry,"emulation_done")
3813 +exception_return:
3814 + btl- FBIT_LoadSegreg,reload_sr // M: r3-r5, r6=nip
3815 + mtsrr1 r7 // setup SRR1
3816 + lwz r0,xCR(r1)
3817 + lwz r3,xLINK(r1)
3818 + mtsrr0 r6
3819 + lwz r4,xGPR4(r1)
3820 + lwz r5,xGPR5(r1)
3821 + mfcr r2 // Save flag bits
3822 + lwz r6,xGPR6(r1)
3823 + lwz r7,xGPR7(r1)
3824 + mtlr r3
3825 + stw r2,xFLAG_BITS(r1)
3826 + lwz r2,xGPR2(r1)
3827 + lwz r3,xGPR3(r1)
3828 + mtcr r0
3829 + lwz r0,xGPR0(r1)
3830 + __GET_TICK_CNT(entry,"asm-all") // performance measurements
3831 + __BUMP("asm-all")
3832 + lwz r1,xGPR1(r1)
3833 + rfi
3834 +
3835 +
3836 +/************************************************************************/
3837 +/* Exit Mac-Mode Paths */
3838 +/************************************************************************/
3839 +
3840 + // THESE ARE _ALL_ THE POSSIBLE EXIT PATHS. KEEP IT THAT WAY
3841 + // OR HAVE A *VERY GOOD* REASON TO INTRODUCE A NEW ONE.
3842 +
3843 + /////////////////////////////////////////////////////////
3844 + // giveup_fpu
3845 + //
3846 + // Save fpscr and fpr13 and clear the MSR_FP bit.
3847 + // Restore the emulator fpscr value.
3848 + //
3849 + // IMPORTANT: Call this function only if FBIT_FPUInUse is set
3850 + //
3851 + // modifies: r7,r8 (turns on MSR_FP if FP is set in K_MSR)
3852 +
3853 +giveup_fpu:
3854 + li r8,MSR_FP | MSR_FE0 | MSR_FE1
3855 + lwz r7,K_MSR(r1)
3856 + andc r8,r7,r8 // Clear MSR_FEx bits
3857 + stw r8,K_MSR(r1)
3858 +
3859 + mfmsr r7 // Temporary enable FPU in order to
3860 + ori r8,r7,MSR_FP // save fpscr and fpr13
3861 + mtmsr r8
3862 + isync
3863 + stfd fr13,xFPR13(r1)
3864 + mffs fr13
3865 + stfd fr13,xFPSCR-4(r1)
3866 + li r7,FPU_STATE_DIRTY
3867 + lfd fr13,xEMULATOR_FPSCR-4(r1) // We must restore FPSCR before since the emulator might
3868 + mtfsf 0xff,fr13 // use the FPU at any time, for instance in a signal handler.
3869 + stw r7,xFPU_STATE(r1) // Go to FPU_STATE_DIRTY
3870 +
3871 + crclr FBIT_FPUInUse // FPU no longer in use
3872 + blr
3873 +
3874 +
3875 + ////////////////////////////////////////////////////////
3876 + // PREPARE_ERET
3877 + //
3878 + // M: r0,r2, r9-r11
3879 +
3880 +MACRO(PREP_ERET,[nip_variable], [
3881 + btl FBIT_MolDecLoaded, set_kernel_dec // M: r0,r2,r9-r11
3882 +
3883 + lwz r10,_nip_variable[](r1)
3884 + mfcr r9
3885 + lwz r11,K_EMULATOR_MSR(r1)
3886 + mtsrr0 r10
3887 + lwz r2,K_EMULATOR_TOC(r1)
3888 + stw r9,xFLAG_BITS(r1)
3889 + mtsrr1 r11
3890 +])
3891 +
3892 + ////////////////////////////////////////////////////////
3893 + // mac_exit (return to emulator)
3894 + // r3 RVEC return code
3895 + //
3896 + // On stack: nip, ctr, lr, xer, r0-r12
3897 + // In registers: r13-r31
3898 +
3899 +mac_exit:
3900 + TRACE(0x2220, "mac_exit")
3901 + bl set_emulator_context // M: r0,r2,r7-r11,XER
3902 +exit_:
3903 + PREP_ERET K_EMULATOR_NIP // M: r0-r2,r9-r11
3904 + GET_TICK_CNT(entry, "mac_exit")
3905 + lwz r1,K_EMULATOR_STACK(r1)
3906 + rfi
3907 +
3908 +
3909 + ////////////////////////////////////////////////////////
3910 + // take_exception (take a linux exception)
3911 + //
3912 + // On stack: nip, ctr, lr, xer, r0-r12
3913 + // In registers: r13-r31
3914 +
3915 +take_exception:
3916 + TRACE(0x2221, "take_exception")
3917 +
3918 + mflr r12
3919 + bl set_emulator_context // M: r0,r2,r7-r11,XER
3920 +
3921 + PREP_ERET K_EMULATOR_NIP // M: r0,r2,r9-r11
3922 + GET_TICK_CNT(entry, "take_exception")
3923 + lwz r1,K_EMULATOR_STACK(r1)
3924 + mtlr r12
3925 + li r3,RVEC_NOP
3926 + blr
3927 +
3928 +
3929 + //////////////////////////////////////////////////////////////
3930 + // call_kernel (call mol kernel routine)
3931 + // r3 kernel routine
3932 + // r4..r6 args
3933 + //
3934 + // On stack: nip, ctr, lr, xer, r0-r12
3935 + // In registers: r13-r31
3936 +
3937 +#ifdef __linux__
3938 +call_kernel_save:
3939 + bl save_middle_regs // saves r8-r11, nip, ctr, xer
3940 +call_kernel:
3941 + bl set_emulator_context // M: r0,r2,r7-r11,XER
3942 +
3943 + TRACE(0x2222, "call_kernel")
3944 +
3945 + lwz r8,K_KERNEL_VARS(r1) // r8 = kvars (lvptr)
3946 + PREP_ERET K_EMULATOR_KCALL_NIP // M: r0,r2,r9-r11
3947 + GET_TICK_CNT(entry, "call_kernel_save")
3948 + lwz r1,K_EMULATOR_STACK(r1)
3949 + ba 0x2f00 // MOL trampoline
3950 +#endif
3951 +
3952 +/************************************************************************/
3953 +/* Set Mac/Emulator Context */
3954 +/************************************************************************/
3955 +
3956 + //////////////////////////////////////////////////////////////
3957 + // set_mac_context [r0,r2-r12, ctr, --->XER<---]
3958 + //
3959 + // - clear BATs (except DBAT0)
3960 + // - setup sprgs
3961 + // - reload_sr loads segment registers later on
3962 + //
3963 + // Currently unmodified r8-r12, ctr
3964 +
3965 +set_mac_context:
3966 + // Save and setup SPRG2 (magic) and SPRG3 (mol stack)
3967 + mfsprg_a2 r6
3968 + mfsprg_a3 r7
3969 + stw r6,K_EMULATOR_SPRG2(r1)
3970 + stw r7,K_EMULATOR_SPRG3(r1)
3971 + li r2,MOL_SPRG2_MAGIC
3972 + mtsprg_a3 r1
3973 + mtsprg_a2 r2
3974 +
3975 + li r4,0
3976 + mtspr IBAT0U,r4
3977 + mtspr IBAT1U,r4
3978 + mtspr IBAT2U,r4
3979 + mtspr IBAT3U,r4
3980 + // DBAT0 set from reload_sr
3981 + mtspr DBAT1U,r4
3982 + mtspr DBAT2U,r4
3983 + mtspr DBAT3U,r4
3984 +#ifdef __darwin__
3985 + lwz r4,K_MOL_SDR1(r1)
3986 + mtsdr1 r4
3987 +#endif
3988 + blr
3989 +
3990 +
3991 + ///////////////////////////////////////////////////////////////
3992 + // set_emulator_context [r0,r2,r7-r11,cr, --->XER<---]
3993 + //
3994 + // - load segr 0-15 with emulator context
3995 + // - restore BATs
3996 + // - restore DEC register
3997 +
3998 +set_emulator_context:
3999 + lwz r0,K_EMULATOR_SPRG2(r1)
4000 + lwz r2,K_EMULATOR_SPRG3(r1)
4001 + mtsprg_a2 r0
4002 + mtsprg_a3 r2
4003 +
4004 + // Restore segment registers
4005 + addi r8,r1,K_EMULATOR_SR
4006 + LOAD_SEGMENT_REGS r8, /**/ r2,r10
4007 +
4008 + // BATS, r11 = linux DEC
4009 +
4010 + lwz r7,K_IBAT0U_SAVE(r1)
4011 + mtspr IBAT0U,r7
4012 + lwz r2,K_IBAT1U_SAVE(r1)
4013 + mtspr IBAT1U,r2
4014 + lwz r7,K_IBAT2U_SAVE(r1)
4015 + mtspr IBAT2U,r7
4016 + lwz r2,K_IBAT3U_SAVE(r1)
4017 + mtspr IBAT3U,r2
4018 +
4019 + lwz r7,K_DBAT0U_SAVE(r1)
4020 + mtspr DBAT0U,r7
4021 + lwz r7,K_DBAT0L_SAVE(r1) // must also restore lower bat...
4022 + mtspr DBAT0L,r7
4023 + lwz r2,K_DBAT1U_SAVE(r1)
4024 + mtspr DBAT1U,r2
4025 + lwz r7,K_DBAT2U_SAVE(r1)
4026 + mtspr DBAT2U,r7
4027 + lwz r2,K_DBAT3U_SAVE(r1)
4028 + mtspr DBAT3U,r2
4029 +#ifdef __darwin__
4030 + lwz r2,K_OS_SDR1(r1)
4031 + mtsdr1 r2
4032 + fix_sprg2 /**/ R2 // must not modify sprg2 (i.e. sprg_a0) under OSX 10.3
4033 +#endif
4034 + blr
4035 +
4036 +
4037 +/************************************************************************/
4038 +/* Reload Segment Registers */
4039 +/************************************************************************/
4040 +
4041 + //////////////////////////////////////////////////////////////
4042 + // reload_sr
4043 + //
4044 + // r6 = mac-nip
4045 + //
4046 + // - loads segr 0-15 with mac context [modifies r3-r5]
4047 + // - reloads DBAT0 (used for splitmode)
4048 + //
4049 + // Modifies: r3-r5
4050 +
4051 +reload_sr:
4052 + bt FBIT_InSplitmode,prepare_splitmode // M: r0,r3-r5, r6=mac-nip
4053 +
4054 + lwz r3,K_TRANSL_DBAT0L(r1)
4055 + lwz r4,K_TRANSL_DBAT0U(r1)
4056 + li r5,0
4057 + mtspr DBAT0L,r3
4058 + mtcrf MMU_CR_FIELD,r5 // clear FBIT_LoadSegreg (and splitmode stuff)
4059 + mtspr DBAT0U,r4
4060 +1:
4061 + lwz r4,K_CUR_SR_BASE(r1)
4062 + LOAD_SEGMENT_REGS r4, /**/ r3,r5
4063 + blr
4064 +
4065 +ret_from_prep_splitmode:
4066 + lwz r3,K_SPLIT_DBAT0L(r1)
4067 + lwz r4,K_SPLIT_DBAT0U(r1)
4068 + li r5,fb_InSplitmode
4069 + mtspr DBAT0L,r3
4070 + mtcrf MMU_CR_FIELD,r5 // clear FBIT_LoadSegreg and FBIT_PrepareSplitmode
4071 + mtspr DBAT0U,r4
4072 + b 1b
4073 diff --git a/drivers/macintosh/mol/asm-files/iopage.S b/drivers/macintosh/mol/asm-files/iopage.S
4074 new file mode 100644
4075 index 0000000..7fbb5f9
4076 --- /dev/null
4077 +++ b/drivers/macintosh/mol/asm-files/iopage.S
4078 @@ -0,0 +1,89 @@
4079 +/*
4080 + * Creation Date: <97/07/26 18:23:02 samuel>
4081 + * Time-stamp: <2002/07/06 12:12:10 samuel>
4082 + *
4083 + * <iopage.S>
4084 + *
4085 + * IO low-level support
4086 + *
4087 + * Copyright (C) 2002 Samuel Rydh (samuel@ibrium.se)
4088 + *
4089 + * This program is free software; you can redistribute it and/or
4090 + * modify it under the terms of the GNU General Public License
4091 + * as published by the Free Software Foundation
4092 + *
4093 + */
4094 +
4095 + // NOTE: This function is also called from the splitmode secondary interrupt
4096 + // handler (splitmode segment registers are resetup at return).
4097 +
4098 +
4099 + ///////////////////////////////////////////////////////////////////
4100 + // check_io_page
4101 + //
4102 + // xINST_OPCODE is always valid at this point
4103 + //
4104 + // Examine if the page (which DAR points to) is an I/O page.
4105 + // Safe to modify: r0,r2-r12
4106 +
4107 +check_io_page:
4108 + // Is this is an IO-page? IMPORTANT: we must *never* insert mappings
4109 + // that are unreadable by supervisor (will cause a freeze right here).
4110 +
4111 + mfdsisr r10 // r10 = DSISR
4112 + rlwinm. r3,r10,0,1,1 // BIT 1 set if no PTE (or BAT mapping)
4113 + bnelr
4114 + mfdar r8
4115 +
4116 + mfmsr r7
4117 + ori r3,r7,MSR_DR // set MSR_DR
4118 + mtmsr r3
4119 + isync
4120 +
4121 + rlwinm r5,r8,0,0,19 // mask page index
4122 +
4123 + // XXX: TO BE FIXED. These instruction will _never_ cause an exceptions on a
4124 + // single processor system. However, on a SMP machine we *could* receive a
4125 + // tlbie invalidate broadcast. Thus we must implement a secondary
4126 + // interrupt handler to cover that case.
4127 +
4128 + lwz r2,IOP_MAGIC(r5)
4129 + lwz r3,IOP_MAGIC2(r5) // These should _never_ cause any exceptions
4130 + lwz r9,IOP_ME_PHYS(r5) // r9 = physical addr of iopage
4131 +
4132 + mtmsr r7 // restore MSR
4133 + isync
4134 +
4135 + lis r6,HI(IO_PAGE_MAGIC_1) // check MAGIC 1
4136 + ori r6,r6,LO(IO_PAGE_MAGIC_1)
4137 + cmplw r6,r2
4138 + bnelr
4139 +
4140 + lis r7,HI(IO_PAGE_MAGIC_2) // check MAGIC 2
4141 + ori r7,r7,LO(IO_PAGE_MAGIC_2)
4142 + cmplw r7,r3
4143 + bnelr
4144 +
4145 + // Obtain translation info from the iopage:
4146 + //
4147 + // r4 = mphys_ioaddr = iop->mphys | (dar & 0xfff);
4148 + // r5 = usr_data = iop->usr_data[ (dar & 0xfff) >> 3 ];
4149 + //
4150 + lwz r4,IOP_MPHYS(r9)
4151 + rlwimi r4,r8,0,20,31 // insert page offset
4152 +
4153 + rlwinm r7,r8,32-1,21,29 // grain = double word
4154 + addi r7,r7,IOP_USR_DATA // usr_data[ (dar&0xfff) ]
4155 + lwzx r5,r9,r7 // r5 = usr_data
4156 +
4157 + rlwinm. r2,r10,0,6,6 // was it a write? (r10=DSISR)
4158 + bne handle_write
4159 +
4160 + // r4 = mphys_ioaddr
4161 + // r5 = usr_data
4162 + MAC_EXIT( RVEC_IO_READ )
4163 +
4164 +handle_write:
4165 + // r4 = mphys_ioaddr
4166 + // r5 = usr_data
4167 + MAC_EXIT( RVEC_IO_WRITE )
4168 diff --git a/drivers/macintosh/mol/asm-files/linux.S b/drivers/macintosh/mol/asm-files/linux.S
4169 new file mode 100644
4170 index 0000000..0128e4c
4171 --- /dev/null
4172 +++ b/drivers/macintosh/mol/asm-files/linux.S
4173 @@ -0,0 +1,129 @@
4174 +/*
4175 + * Creation Date: <2001/02/24 14:08:28 samuel>
4176 + * Time-stamp: <2003/09/03 12:34:20 samuel>
4177 + *
4178 + * <platform.S>
4179 + *
4180 + * Linux Kernel Hooks
4181 + *
4182 + * Copyright (C) 2001, 2002, 2003 Samuel Rydh (samuel@ibrium.se)
4183 + *
4184 + * This program is free software; you can redistribute it and/or
4185 + * modify it under the terms of the GNU General Public License
4186 + * as published by the Free Software Foundation
4187 + *
4188 + */
4189 +
4190 + ////////////////////////////////////////////////////////
4191 + // flush_hash_page_hook
4192 + //
4193 + // Kernel hook
4194 + //
4195 + // r3: context
4196 + // r4: virtual address
4197 + // r5: 2.4.6 pointer to linux PTE (2.4.6 or later)
4198 + // 2.6 pmdval
4199 + // r6: 2.6 count
4200 + // r10: return address
4201 + //
4202 + // [must not modify: r3-r5,r10 - otherwise normal C-function]
4203 + // MMU is ON
4204 +
4205 +.set STACK_SPACE, 32
4206 +.set STACK_LR, STACK_SPACE+4
4207 +.set STACK_V0, 8
4208 +.set STACK_V1, 12
4209 +.set STACK_V2, 16
4210 +.set STACK_V3, 20
4211 +.set STACK_V4, 24
4212 +.set STACK_V5, 28
4213 +
4214 +FHOOK( FHOOK_FLUSH_HASH_PAGE )
4215 +GLOBAL_SYMBOL( r__flush_hash_page_hook ):
4216 + stwu r1,-STACK_SPACE(r1) // Push stackframe
4217 + mflr r0
4218 + stw r0,STACK_LR(r1)
4219 +
4220 + LOADI r7,EXTERN(do_flush)
4221 + mtctr r7
4222 +
4223 + stw r10,STACK_V1(r1) // Save registers
4224 + stw r3,STACK_V2(r1)
4225 + stw r4,STACK_V3(r1)
4226 + stw r5,STACK_V4(r1)
4227 +#ifdef LINUX_26
4228 + stw r6,STACK_V5(r1)
4229 +#else
4230 + li r6,1
4231 +#endif
4232 + bctrl
4233 +
4234 + lwz r10,STACK_V1(r1) // Restore registers
4235 + lwz r3,STACK_V2(r1)
4236 + lwz r4,STACK_V3(r1)
4237 + lwz r5,STACK_V4(r1)
4238 +#ifdef LINUX_26
4239 + lwz r6,STACK_V5(r1)
4240 +#endif
4241 +
4242 + lwz r0,STACK_LR(r1) // Pop stackframe
4243 + addi r1,r1,STACK_SPACE
4244 + mtlr r0
4245 + blr
4246 +
4247 +
4248 +/************************************************************************/
4249 +/* lowmem reallocations */
4250 +/************************************************************************/
4251 +
4252 +#ifdef CONFIG_SMP
4253 +
4254 + /* r3=ea, r4=pte_slot, r5=pte1, r6=pte2, r7=lock, r8=lockval, M: r0 */
4255 +RELOC_LOW(xx_store_pte_lowmem)
4256 +1: lwarx r0,0,r7
4257 + cmpwi r0,0
4258 + bne- 1b
4259 + stwcx. r8,0,r7 // take hash lock
4260 + bne- 1b
4261 + // isync // sync below is sufficient
4262 + stw r0,0(r4) // clear old PTE[V] (if we evict something)
4263 + sync // probably not needed - no other CPU uses this PTE
4264 + stw r6,4(r4) // store PTE2
4265 + eieio
4266 + stw r5,0(r4) // store PTE1
4267 + tlbie r3 // flush old pte
4268 + eieio // order tlbie before tlbsync
4269 + tlbsync // ensure tlbie finish on all processors
4270 + sync // ensure tlbsync completed
4271 + stw r0,0(r7) // release hash lock
4272 + blr
4273 +RELOC_LOW_END(xx_store_pte_lowmem)
4274 +
4275 +
4276 + /* r3=ea, r7=lock, r8=lockval, M: r0 */
4277 +RELOC_LOW(xx_tlbie_lowmem)
4278 +1: lwarx r0,0,r7
4279 + cmpwi r0,0
4280 + bne- 1b
4281 + stwcx. r8,0,r7 // take hash lock
4282 + bne- 1b
4283 + //isync // needed if we get rid of the sync
4284 + sync // make sure any PTE zero-outs have finished
4285 + tlbie r3 // flush old pte
4286 + eieio // order tlbie before tlbsync
4287 + tlbsync // ensure tlbie finish on all processors
4288 + sync // ensure tlbsync completed
4289 + stw r0,0(r7) // release hash lock
4290 + blr
4291 +RELOC_LOW_END(xx_tlbie_lowmem)
4292 +
4293 +#else
4294 +
4295 + /* r3=pte_slot, r4=pte0, r5=pte1 */
4296 +RELOC_LOW(xx_store_pte_lowmem)
4297 + stw r4,0(r3) // interrupts are off and we won't take a page fault
4298 + stw r5,4(r3) // so this is safe...
4299 + blr
4300 +RELOC_LOW_END(xx_store_pte_lowmem)
4301 +
4302 +#endif
4303 diff --git a/drivers/macintosh/mol/asm-files/ptintercept.S b/drivers/macintosh/mol/asm-files/ptintercept.S
4304 new file mode 100644
4305 index 0000000..5c55025
4306 --- /dev/null
4307 +++ b/drivers/macintosh/mol/asm-files/ptintercept.S
4308 @@ -0,0 +1,303 @@
4309 +/*
4310 + * Creation Date: <2001/03/17 18:00:05 samuel>
4311 + * Time-stamp: <2003/05/26 00:08:48 samuel>
4312 + *
4313 + * <ptintercept.S>
4314 + *
4315 + * Handles writes to the (mac) hash table
4316 + *
4317 + * Copyright (C) 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se)
4318 + *
4319 + * This program is free software; you can redistribute it and/or
4320 + * modify it under the terms of the GNU General Public License
4321 + * as published by the Free Software Foundation
4322 + *
4323 + */
4324 +
4325 +//////////////////////////////////////////////////////////////////////
4326 +// Implementing the tlbie instruction properly is tricky.
4327 +// The tlbie is supposed to invalidate an equivalence
4328 +// class of PTEs and this does not map well to the huge TLB
4329 +// MOL uses (the linux PTE hash, a lot bigger than the 2x64
4330 +// table found in most CPUs).
4331 +//
4332 +// The solution is intercepting PTE writes and maintain
4333 +// coherence without relying on the tlbie instruction (which
4334 +// can safely be replaced by a nop).
4335 +//
4336 +// Splitmode: The instruction sr might be active. DBAT0 does
4337 +// _not_ have the supervisor valid bit set so we have to load
4338 +// the data segment register.
4339 +//////////////////////////////////////////////////////////////////////
4340 +
4341 +MACRO(SET_MSR_DR, [scr], [
4342 + li _scr,MSR_DR
4343 + mtmsr _scr
4344 + isync
4345 +])
4346 +MACRO(CLEAR_MSR_DR, [scr], [
4347 + li _scr,0
4348 + mtmsr _scr
4349 + isync
4350 +])
4351 +
4352 + // r3 = exception vector
4353 +secint_pt_store:
4354 + bf+ FBIT_InSplitmode,1f
4355 + mfdar r2
4356 + lwz r4,K_TMP_SCRATCH0(r1) // in splitmode (might be
4357 + mtsrin r4,r2 // the instrucion sr)
4358 +1:
4359 + lwz r6,xNIP(r1) // restore NIP & MSR
4360 + lwz r7,K_MSR(r1)
4361 + cmpwi r3,0x300
4362 + beq 1f
4363 + cmpwi r3,0x600 // Alignment
4364 + beq 2f
4365 + DEBUGGER_SAVE( 0x6909 )
4366 +1: bl save_middle_regs
4367 + b dsi_cont
4368 +2: bl save_middle_regs
4369 + b alignment_cont
4370 +
4371 + ////////////////////////////////////////////////////////////////////////
4372 + // check_pthash_hit
4373 + //
4374 + // m: r0,r2-r5, cr
4375 +
4376 +check_pthash_hit:
4377 + mfdsisr r3
4378 + rlwinm. r4,r3,0,4,4 // Is this a protection violation?
4379 + beqlr
4380 + rlwinm. r4,r3,0,6,6 // and a write?
4381 + beqlr-
4382 +
4383 + mfdar r2 // Is this a pthash hit?
4384 + lwz r3,K_TLBHASH_BASE_EA(r1) // First check EA...
4385 + lwz r4,K_HASH_MASK(r1)
4386 + sub r5,r2,r3
4387 + cmplw r5,r4
4388 + bgtlr+
4389 +
4390 + lwz r5,K_SR_DATA(r1) // Correct context for EA?
4391 + rlwinm r3,r2,4+2,26,29 // #sr << 2
4392 + lwz r4,K_TLBHASH_SR(r1)
4393 + lwzx r3,r3,r5
4394 + cmpw r3,r4
4395 + bnelr-
4396 +
4397 + /////////////////////////////////////////////////
4398 + // Handle page table write, r2=dar, r4=segreg
4399 + /////////////////////////////////////////////////
4400 +
4401 + bf+ FBIT_InSplitmode,1f
4402 + mfsrin r3,r2 // save old segment register
4403 + stw r3,K_TMP_SCRATCH0(r1) // in splitmode (might be
4404 + mtsrin r4,r2 // the instrucion sr)
4405 +1:
4406 + lwz r3,xINST_OPCODE(r1)
4407 + LI_PHYS( R4,secint_pt_store ) // r4 = secondary exception handler
4408 + stw r6,xNIP(r1)
4409 +
4410 + // r2 = dar, r3 = opcode
4411 + rlwinm r0,r3,6,0x3e // primary opcode & ~1
4412 + rlwinm r5,r3,6+5+3,(0x1f<<3) // r5 = rS << 3
4413 + cmpwi r0,30 // 31 & ~1
4414 + beq- do_opcode_31
4415 + mtcrf 0x40,r3 // cr[5] = update bit
4416 + cmpwi r0,36 // 36, stw/stwu
4417 + beq do_stw
4418 + cmpwi r0,38 // 38, stb/stbu
4419 + beq do_stb
4420 + cmpwi r0,44 // 44, stb/stbu
4421 + beq do_sth
4422 + cmpwi r0,52 // 52, stfs/stsu
4423 + beq do_stfs
4424 + cmpwi r0,54 // 54, stfd/stfdu
4425 + beq do_stfd
4426 + cmpwi r0,46 // 47, stmw
4427 + beq do_stmw
4428 + b do_st_bad // ???
4429 +
4430 +do_opcode_31:
4431 + rlwinm r0,r3,32-1,22,31 // secondary opcode
4432 + rlwinm. r6,r3,0,(32<<1) // update form?
4433 + rlwinm r0,r0,0,~32 // clear update bit
4434 + crnot 5,eq
4435 +
4436 + cmpwi r0,151 // stwx/stwxu
4437 + beq+ do_stw
4438 + cmpwi r0,215 // stbx / stbxu
4439 + beq- do_stb
4440 + cmpwi r0,150 // stwcx.
4441 + beq- do_stwcx
4442 + cmpwi r0,407 // sthx / sthxu
4443 + beq- do_sth
4444 + cmpwi r0,727 // stfdx / stfdxu
4445 + beq- do_stfd
4446 + cmpwi r0,663 // stfsx / stfsxu
4447 + beq- do_stfs
4448 + crclr 5
4449 + rlwinm r0,r3,32-1,22,31 // unmasked secondary opcode
4450 + cmpwi r0,470 // dcbi
4451 + beq- do_dcbi
4452 + cmpwi r0,1014 // dcbz
4453 + beq- do_dcbz
4454 + cmpwi r0,983 // stfiwx [optional]
4455 + beq- do_stfiw
4456 + cmpwi r0,725 // stswi
4457 + beq- do_stswi
4458 + cmpwi r0,661
4459 + beq- do_stswx
4460 + b do_st_bad // float, cache or altivec
4461 +
4462 +do_st_bad:
4463 +do_stfd:
4464 +do_stfs:
4465 +do_stfiw:
4466 +do_stswi:
4467 +do_stswx:
4468 + lwz r6,xNIP(r1)
4469 + DEBUGGER_SAVE(0x1882) // unimplemented store instruction
4470 +
4471 + // r2=dar, r3=opcode, r4=secint_handler, r5=rS_offs
4472 +do_dcbi:
4473 +do_dcbz:
4474 + mtlr r4
4475 + SET_MSR_DR /**/ r6
4476 + rlwinm r6,r2,0,~0x7
4477 + lwz r4,0(r6)
4478 + lwz r5,4(r6)
4479 + dcbz 0,r2
4480 + CLEAR_MSR_DR /**/ r0
4481 + b st_continue_2
4482 +do_stwcx:
4483 + EMU_LOAD_GPR r5, /**/ R6 // r0 = value
4484 + mtlr r4
4485 + SET_MSR_DR /**/ r6
4486 + rlwinm r6,r2,0,~0x7
4487 + lwz r4,0(r6)
4488 + lwz r5,4(r6)
4489 + stwcx. r0,0,r2
4490 + CLEAR_MSR_DR /**/ r0
4491 + lwz r6,xCR(r1)
4492 + mfcr r0
4493 + rlwimi r6,r0,0,0,3
4494 + stw r6,xCR(r1)
4495 + b st_continue_2
4496 +do_sth:
4497 + EMU_LOAD_GPR r5, /**/ R6 // r0 = value
4498 + mtlr r4
4499 + SET_MSR_DR /**/ r6
4500 + rlwinm r6,r2,0,~0x7
4501 + lwz r4,0(r6)
4502 + lwz r5,4(r6)
4503 + sth r0,0(r2)
4504 + b st_continue
4505 +do_stb:
4506 + EMU_LOAD_GPR r5, /**/ R6 // r0 = value
4507 + mtlr r4
4508 + SET_MSR_DR /**/ r6
4509 + rlwinm r6,r2,0,~0x7
4510 + lwz r4,0(r6)
4511 + lwz r5,4(r6)
4512 + stb r0,0(r2)
4513 + b st_continue
4514 +do_stw:
4515 + EMU_LOAD_GPR r5, /**/ R6 // r0 = value
4516 + mtlr r4
4517 + SET_MSR_DR /**/ r6
4518 + rlwinm r6,r2,0,~0x7
4519 + lwz r4,0(r6)
4520 + lwz r5,4(r6)
4521 + stw r0,0(r2)
4522 + b st_continue
4523 +
4524 + // r4=PTE0, r5=PTE1, r3=opcode, r2=dar, scratch: r0
4525 +st_continue:
4526 + CLEAR_MSR_DR /**/ r0
4527 + bf+ 5,st_continue_2 // update form?
4528 + rlwinm r3,r3,6+5+5+3,(31<<3)
4529 + mr r0,r2
4530 + EMU_STORE_GPR r3, /**/ R6 // r0 = value
4531 +st_continue_2:
4532 + // check if the old PTE has been used (r2=dar,r4/r5=PTE)
4533 + lwz r3,K_TLBHASH_BASE_EA(r1) // Calculate tlb offset
4534 + sub r0,r2,r3 // r0 = pte_nr * 8
4535 + lwz r6,K_PTHASH_INUSE_PH(r1)
4536 + rlwinm r3,r0,32-6,6,29 // r3 = word offset
4537 + cmpwi r6,0
4538 + beq- 1f
4539 + lwzx r3,r3,r6
4540 + rlwinm r6,r2,32-3,27,31 // pte_nr & 0x1f
4541 + li r0,1
4542 + slw r6,r0,r6 // r6 = bit
4543 + and. r6,r6,r3
4544 + GET_TICK_CNT(entry,"ptintercept-1")
4545 + bne- pt_intercept
4546 +1:
4547 + BUMP("pt_intercept_not_taken")
4548 + // return from exception [r2=dar]
4549 + lwz r6,xNIP(r1) // restore r6
4550 + bf+ FBIT_InSplitmode,emulation_done
4551 + lwz r3,K_TMP_SCRATCH0(r1) // in splitmode (might be
4552 + mtsrin r3,r2 // the instrucion sr)
4553 + b emulation_done
4554 +
4555 + // transfer to C-function [r2=dar, r3/r4=pte]
4556 +pt_intercept:
4557 + BUMP("pt_intercept_taken")
4558 + lwz r6,xNIP(r1) // restore r6
4559 + lwz r3,K_TLBHASH_BASE_EA(r1) // calculate tlb offset
4560 + addi r6,r6,4 // inc NIP
4561 + bl save_middle_regs
4562 + sub r6,r2,r3
4563 + rlwinm r6,r6,0,0,28 // argument pteoffs (dword aligned)
4564 +
4565 + // r4=PTE0, r5=PTE1
4566 + LOADI r3,EXTERN(do_intercept_tlbie)
4567 + b call_kernel
4568 +
4569 + // stmw uses another emulator entry point because it might overwrite a bunch of PTEs
4570 +do_stmw:
4571 + mtlr r4
4572 +
4573 + // save some debugging info
4574 +// stw r2,xDBG_TRACE_SPACE(r1)
4575 +
4576 + SET_MSR_DR /**/ r6
4577 +
4578 + // now do the stmw. we do that manually since we have to access emulator regs.
4579 + mr r4,r2 // r4: memory pointer
4580 + srwi r6,r5,3 // r6: rS
4581 +1: cmpwi r5,32 << 3 // loop condition
4582 + bge 2f
4583 + EMU_LOAD_GPR r5, /**/ R3 // r0 = value
4584 + stw r0,0(r4) // store the value
4585 + addi r5,r5,1 << 3 // update register counter
4586 + addi r4,r4,4 // and memory pointer
4587 + b 1b
4588 +
4589 +2: CLEAR_MSR_DR /**/ r0
4590 +
4591 + // load up r4 and r5 for do_intercept_tlbie_block (see below)
4592 + subfic r5,r6,32 // number of registers (=words) stored
4593 + slwi r5,r5,2 // number of bytes stored
4594 + add r4,r2,r5 // last byte stored
4595 + addi r4,r4,7 // alignment to
4596 + rlwinm r5,r4,0,~0x7 // PTE size
4597 + rlwinm r4,r2,0,~0x7 // pte block pointer
4598 + sub r5,r5,r4 // substract block pointer -> length (in bytes)
4599 + lwz r3,K_TLBHASH_BASE_EA(r1) // calculate tlb offset
4600 + sub r4,r4,r3 // tlb offset
4601 + b st_block_continue
4602 +
4603 + // transfer to C-function [r2=dar, r4=pte block offset, r5=pte block length]
4604 +st_block_continue:
4605 + BUMP("pt_intercept_taken")
4606 + lwz r6,xNIP(r1)
4607 + addi r6,r6,4 // inc NIP
4608 + bl save_middle_regs
4609 +
4610 + LOADI r3,EXTERN(do_intercept_tlbie_block)
4611 + b call_kernel
4612 diff --git a/drivers/macintosh/mol/asm-files/splitmode.S b/drivers/macintosh/mol/asm-files/splitmode.S
4613 new file mode 100644
4614 index 0000000..69090d2
4615 --- /dev/null
4616 +++ b/drivers/macintosh/mol/asm-files/splitmode.S
4617 @@ -0,0 +1,428 @@
4618 +/*
4619 + * Creation Date: <2000/07/11 03:38:32 samuel>
4620 + * Time-stamp: <2003/08/20 16:37:04 samuel>
4621 + *
4622 + * <splitmode.S>
4623 + *
4624 + * Handles splitmode (MSR_IR != MSR_DR)
4625 + *
4626 + * Copyright (C) 2000, 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se)
4627 + *
4628 + * This program is free software; you can redistribute it and/or
4629 + * modify it under the terms of the GNU General Public License
4630 + * as published by the Free Software Foundation
4631 + *
4632 + */
4633 +
4634 +MACRO(SM_SET_MSR_DR, [scr], [
4635 + li _scr,MSR_DR
4636 + mtmsr _scr
4637 + isync
4638 +])
4639 +MACRO(SM_CLEAR_MSR_DR, [scr], [
4640 + li _scr,0
4641 + mtmsr _scr
4642 + isync
4643 +])
4644 +MACRO(SPLITMODE_SMP_LOCK, [scr1,scr2], [
4645 +#ifdef CONFIG_SMP
4646 + LI_PHYS( _scr1,splitmode_lock )
4647 +7: lwarx _scr2,0,_scr1
4648 + cmpwi _scr2,0
4649 + li _scr2,1
4650 + bne- 7b
4651 + stwcx. _scr2,0,_scr1
4652 + bne- 7b
4653 + isync
4654 +#endif
4655 +])
4656 +MACRO(SPLITMODE_SMP_UNLOCK, [scr1,scr2], [
4657 +#ifdef CONFIG_SMP
4658 + LI_PHYS( _scr1,splitmode_lock )
4659 + li _scr2,0
4660 + stw _scr2,0(_scr1)
4661 +#endif
4662 +])
4663 +
4664 + /////////////////////////////////////////////////////////////
4665 + // prepare_splitmode
4666 + //
4667 + // r6,r7: nip/srr1
4668 + //
4669 + // M: r0,r3-r5
4670 + //
4671 + // Fill in splitmode segment register table. The segment register
4672 + // containing xNIP is set up for instruction access (if xNIP does
4673 + // not hold nip, an extra ISI exception will occur). The instruction
4674 + // segment is protected from data access through the use of a DBAT
4675 + // register.
4676 + //
4677 + // It MUST be safe to call this function even if we are *not* in
4678 + // splitmode.
4679 +
4680 +prepare_splitmode:
4681 + bf FBIT_PrepareSplitmode, ret_from_prep_splitmode
4682 +
4683 + ZERO_TICK_CNT(splitmode_prep)
4684 +
4685 + // fill split mode table with data segment registers
4686 + lwz r3,K_SR_DATA(r1) // physical addr
4687 + addi r4,r1,K_SPLIT_SR_BASE-4
4688 + li r5,16
4689 + mfctr r0 // save ctr in r0
4690 + mtctr r5
4691 + addi r3,r3,-4
4692 +1: lwzu r5,4(r3)
4693 + oris r5,r5,0x1000 // no-execute segment bit
4694 + stwu r5,4(r4)
4695 + bdnz 1b
4696 + mtctr r0 // restore ctr
4697 +
4698 + // insert instruction mode segment
4699 + rlwinm r3,r6,0,0,3
4700 + stw r3,K_SPLIT_NIP_SEGMENT(r1)
4701 + rlwinm r3,r6,4+2,26,29 // r3 = offset, ((sr & 0xf000000) >> 28 ) * 4
4702 + lwz r5,K_SR_INST(r1)
4703 + lwzx r5,r3,r5 // segment register for instructions
4704 + addi r4,r1,K_SPLIT_SR_BASE
4705 + stwx r5,r3,r4
4706 +
4707 + // and protect it with DBAT0.
4708 + //
4709 + // The supervisor valid bit must be cleared
4710 + // - we don't want to block get_opcode.
4711 +
4712 + rlwinm r3,r6,0,0,3 // segment base
4713 + ori r3,r3,0x1ffd // user valid bit | 256MB mask
4714 + stw r3,K_SPLIT_DBAT0U(r1)
4715 + li r4,0
4716 + stw r4,K_SPLIT_DBAT0L(r1) // pp=0, wimg=0
4717 + GET_TICK_CNT(splitmode_prep, "splitmode_prep")
4718 + b ret_from_prep_splitmode
4719 +
4720 +
4721 + ///////////////////////////////////////////////////////////////////
4722 + // split_sr_no_execute
4723 + //
4724 + // r6,r7: nip/srr1
4725 + //
4726 + // An instruction is to be fetched from one of the no-execute
4727 + // segments. This function reinitializes the segment registers.
4728 + //
4729 + // M: r0, r3-r5
4730 +
4731 +split_sr_no_execute:
4732 + rlwinm. r0,r7,0,3,3 // Guarded access or no-execute?
4733 + beqlr
4734 +
4735 + rlwinm r3,r6,0,0,3 // segment
4736 + lwz r4,K_SPLIT_NIP_SEGMENT(r1)
4737 + cmpw r3,r4
4738 + beqlr // guarded PTE/mac-guarded segment
4739 +
4740 + crset FBIT_PrepareSplitmode
4741 + crset FBIT_LoadSegreg
4742 + b exception_return
4743 +
4744 +
4745 +
4746 + //////////////////////////////////////////////////////////////////
4747 + // splitmode_dsi
4748 + //
4749 + // r6/r7: nip/srr1
4750 + //
4751 + // An DSI exception occured (DBAT protection violation).
4752 + // That is, a load/store instruction targeted the segment
4753 + // instructions was fetched from.
4754 + //
4755 + // Safe to modify: r0,r2-r5, (lr)
4756 +
4757 +splitmode_dsi:
4758 + mfdsisr r3 // DBAT/page protection violation?
4759 + rlwinm. r0,r3,0,4,4
4760 + beqlr- // If not, it does not concern us
4761 +
4762 + mfdar r2 // Normal page protected exception?
4763 + lwz r4,K_SPLIT_NIP_SEGMENT(r1) // the instruction segment?
4764 + rlwinm r5,r2,0,0,3 // data segment
4765 + cmpw r4,r5
4766 + bnelr // exit - not in the instruction segment
4767 +
4768 + // splitmode write, r2=dar
4769 + mfsrin r0,r2 // r0 = old segment register
4770 + stw r6,xNIP(r1) // need one additional reg
4771 + rlwinm r4,r2,4+2,26,29 // sr_offset = sr_num * 4
4772 + lwz r5,K_SR_DATA(r1)
4773 + lwzx r4,r4,r5
4774 + stw r0,K_TMP_SCRATCH0(r1) // save old segment register
4775 + oris r4,r4,0x4000 // set supervisor key bit (Ks)
4776 + mtsrin r4,r2
4777 +
4778 + rlwinm. r3,r3,0,6,6 // cr[eq] set if this a read
4779 + lwz r3,xINST_OPCODE(r1)
4780 + LI_PHYS( R4, secint_splitm ) // r4 = secint handler
4781 +
4782 + // handle simple stores r2=seg#, r3=opcode, r4=secint
4783 + beq splitm_load
4784 +
4785 + rlwinm r5,r3,6+5+3,(0x1f<<3) // r5 = rS << 3
4786 + EMU_LOAD_GPR r5, /**/ R6 // r0 = value
4787 + mtlr r4 // secint handler
4788 + SM_SET_MSR_DR /**/ r5
4789 +
4790 + rlwinm r6,r3,6,0x3e // primary opcode & ~1
4791 + mtcrf 0x40,r3 // cr[5] = update bit (if opcode != 31)
4792 + cmpwi r6,30 // 31 & ~1
4793 + beq- splitm_store_op31
4794 + cmpwi r6,36 // 36, stw/stwu
4795 + beq splitm_stw
4796 + cmpwi r6,38 // 38, stb/stbu
4797 + beq splitm_stb
4798 + cmpwi r6,44 // 44, stb/stbu
4799 + beq splitm_sth
4800 + b splitm_fallback
4801 +splitm_store_op31:
4802 + rlwinm. r6,r3,0,(32<<1) // update form?
4803 + rlwinm r6,r3,32-1,22,31 // secondary opcode
4804 + rlwinm r6,r6,0,~32 // clear update bit
4805 + crnot 5,eq
4806 + cmpwi r6,151 // stwx/stwxu
4807 + beq+ splitm_stw
4808 + cmpwi r6,215 // stbx / stbxu
4809 + beq- splitm_stb
4810 + cmpwi r6,407 // sthx / sthxu
4811 + beq- splitm_sth
4812 + rlwinm r6,r3,32-1,22,31 // secondary opcode
4813 + cmpwi r6,150 // stwcx.
4814 + beq- splitm_stwcx
4815 + cmpwi r6,1014 // 1014, dcbz
4816 + beq- splitm_dcbz
4817 + cmpwi r6,662 // 662, stwbrx
4818 + beq- splitm_stwbrx
4819 + b splitm_fallback
4820 +
4821 +splitm_load:
4822 + mtlr r4 // secint handler
4823 + SM_SET_MSR_DR /**/ r5
4824 + rlwinm r6,r3,6,0x3e // primary opcode & ~1
4825 + mtcrf 0x40,r3 // cr[5] = update bit (if opcode != 31)
4826 + cmpwi r6,30 // 31 & ~1
4827 + beq- splitm_load_op31
4828 + cmpwi r6,32 // 32, lwz/lwzu
4829 + beq+ splitm_lwz
4830 + cmpwi r6,34 // 34, lbz/lbzu
4831 + beq- splitm_lbz
4832 + cmpwi r6,40 // 40, lhz/lhzu
4833 + beq- splitm_lhz
4834 + b splitm_fallback
4835 +splitm_load_op31:
4836 + rlwinm. r6,r3,0,(32<<1) // update form?
4837 + rlwinm r6,r3,32-1,22,31 // secondary opcode
4838 + rlwinm r6,r6,0,~32 // clear update bit
4839 + crnot 5,eq
4840 + cmpwi r6,23 // 23, lwzx/lwzux
4841 + beq+ splitm_lwz
4842 + cmpwi r6,87 // 87, lbzx/lbzux
4843 + beq- splitm_lbz
4844 + cmpwi r6,279 // 279, lhzx/lhzux
4845 + beq- splitm_lhz
4846 + rlwinm r6,r3,32-1,22,31 // secondary opcode
4847 + crclr 5
4848 + cmpwi r6,20 // 20, lwarx
4849 + beq- splitm_lwarx
4850 + cmpwi r6,86 // 86, dcbf
4851 + beq- splitm_dcbf
4852 + cmpwi r6,982 // 982, icbi
4853 + beq- splitm_icbi
4854 + cmpwi r6,534 // 534, lwbrx
4855 + beq- splitm_lwbrx
4856 + b splitm_fallback
4857 +
4858 +
4859 + // r0=value, r2=ea, r3=opcode
4860 +splitm_stwcx:
4861 + stwcx. r0,0,r2
4862 + SM_CLEAR_MSR_DR /**/ r0
4863 + lwz r6,xCR(r1)
4864 + mfcr r0
4865 + rlwimi r6,r0,0,0,3
4866 + stw r6,xCR(r1)
4867 + b splitm_done2
4868 +splitm_sth:
4869 + sth r0,0(r2)
4870 + b splitm_store_continue
4871 +splitm_stb:
4872 + stb r0,0(r2)
4873 + b splitm_store_continue
4874 +splitm_stw:
4875 + stw r0,0(r2)
4876 + b splitm_store_continue
4877 +splitm_lwz:
4878 + lwz r0,0(r2)
4879 + b splitm_load_continue
4880 +splitm_lhz:
4881 + lhz r0,0(r2)
4882 + b splitm_load_continue
4883 +splitm_lbz:
4884 + lbz r0,0(r2)
4885 + b splitm_load_continue
4886 +splitm_lwarx:
4887 + lwarx r0,0,r2
4888 + b splitm_load_continue
4889 +splitm_lwbrx:
4890 + lwbrx r0,0,r2
4891 + b splitm_load_continue
4892 +splitm_dcbz:
4893 + dcbz 0,r2
4894 + b splitm_done
4895 +splitm_icbi:
4896 + icbi 0,r2
4897 + b splitm_done
4898 +splitm_dcbf:
4899 + dcbf 0,r2
4900 + b splitm_done
4901 +splitm_stwbrx:
4902 + stwbrx r0,0,r2
4903 + b splitm_done
4904 +
4905 +splitm_load_continue:
4906 + SM_CLEAR_MSR_DR /**/ r4
4907 + BUMP("splitm_load")
4908 + rlwinm r4,r3,6+5+3,(0x1f<<3) // r5 = rS << 3
4909 + EMU_STORE_GPR r4, /**/ R6 // r0 = value
4910 + bf+ 5,splitm_done2 // update form?
4911 + b 1f
4912 +
4913 +splitm_store_continue:
4914 + SM_CLEAR_MSR_DR /**/ r0
4915 + BUMP("splitm_store")
4916 + bf+ 5,splitm_done2 // update form?
4917 +1: rlwinm r3,r3,6+5+5+3,(31<<3)
4918 + mr r0,r2
4919 + EMU_STORE_GPR r3, /**/ R6 // r0 = value
4920 + b splitm_done2
4921 +splitm_done:
4922 + SM_CLEAR_MSR_DR /**/ r0
4923 +splitm_done2:
4924 + lwz r3,K_TMP_SCRATCH0(r1)
4925 + lwz r6,xNIP(r1) // restore NIP
4926 + mtsrin r3,r2
4927 + b emulation_done
4928 +
4929 +
4930 + // fallback, store and execute the instruction, r3=opcode
4931 +splitm_fallback:
4932 + SM_CLEAR_MSR_DR /**/ r0
4933 +#if 0
4934 + stw r3,xDEBUG1(r1)
4935 + stw r6,xDEBUG0(r1)
4936 + lwz r6,xNIP(r1)
4937 + DEBUGGER_SAVE(0x1111)
4938 +#endif
4939 + SPLITMODE_SMP_LOCK /**/ r0,r2
4940 +
4941 + BUMP("splitm_fallback")
4942 + bl secint_splitm_fallback // set secondary exception handler
4943 +
4944 + LI_PHYS( R2,split_store_patch ) // r2 = addr of split_store_patch
4945 + stw r3,0(r2) // store instruction
4946 + dcbst 0,r2
4947 + sync
4948 + icbi 0,r2
4949 + sync // 74xx needs this
4950 +
4951 + mtsrr0 r2 // The simplest thing is to do an RFI
4952 + LOADI r3,(MSR_EE | MSR_PR | MSR_IR | MSR_SE | MSR_BE)
4953 + andc r4,r7,r3 // Clear msr bits (r7=srr1)
4954 + xGPR_LOAD R6
4955 + xGPR_LOAD R7
4956 + mtsrr1 r4
4957 + xGPR_LOAD_RANGE R2,R5,r1 // Restore registers (except r1)
4958 + xGPR_LOAD R0
4959 + xGPR_LOAD R1
4960 + rfi
4961 +
4962 +split_store_patch:
4963 + nop
4964 +
4965 + mtsprg_a0 r1 // restore MSR
4966 + li r1,MSR_ME
4967 + mtmsr r1
4968 + isync
4969 + mfsprg_a3 r1 // and stack pointer
4970 +
4971 + xGPR_SAVE_RANGE R2,R7,r1
4972 + SPLITMODE_SMP_UNLOCK /**/ r3,r4
4973 +
4974 + mfsprg_a0 r2 // r1 - to be saved
4975 + lwz r6,xNIP(r1) // restore r6,r7 and segment register
4976 + lwz r7,K_MSR(r1)
4977 + stw r0,xGPR0(r1)
4978 + stw r2,xGPR1(r1)
4979 + lwz r2,K_TMP_SCRATCH0(r1)
4980 + mtsrin r2,r6
4981 +
4982 + GET_TICK_CNT( entry, "splitmode_dsi" )
4983 + b emulation_done
4984 +
4985 +
4986 + //////////////////////////////////////////////////////////////////////
4987 + // secint_splitm / secint_splitm_fallback
4988 + // r1: stack (sprg1 = old r1)
4989 + // r3: vector index (sprg0 = old r3)
4990 + // srr0/srr1: kernel nip/msr
4991 + //
4992 + // xGPR(0-5) are valid (unless this is a trace exception)
4993 +
4994 +secint_splitm_fallback:
4995 + blrl
4996 + SPLITMODE_SMP_UNLOCK /**/ R2,R4
4997 +
4998 +secint_splitm:
4999 + lwz r6,xNIP(r1) // Restore nip/msr
5000 + lwz r7,K_MSR(r1)
5001 +
5002 + cmpwi r3,0x300 // ** DSI **
5003 + bne- 1f
5004 + mfsrin r2,r6 // r6 = NIP
5005 + rlwinm r2,r2,0,2,0 // Clear Ks [bit1] (supervisor key bit)
5006 + mtsrin r2,r6
5007 + bl save_middle_regs // Note: If dsi_cont ever returns immediately,
5008 + bl check_io_page // we will need to fix the segment registers before
5009 + b dsi_cont // the last dsi_cont branch.
5010 +
5011 +1: lwz r2,K_TMP_SCRATCH0(r1) // We might return immediately...
5012 + mtsrin r2,r6
5013 +
5014 + cmpwi r3,0x600 // ** Alignment **
5015 + bne 2f
5016 + bl save_middle_regs
5017 + b alignment_cont
5018 +
5019 +2: cmpwi r3,0x800 // ** FPU Unavailable **
5020 + beq fpu_cont
5021 + cmpwi r3,0xf20 // ** AltiVec Unavailable **
5022 + beq altivec_cont
5023 +
5024 + DEBUGGER_SAVE( 0x5918 ) // ERROR...
5025 +
5026 +
5027 + ////////////////////////////////////////////////////////////////////////
5028 + // invalidate_splitmode( kernel_vars_t *kv )
5029 + //
5030 + // This function must be called whenever the segment registers are
5031 + // modified. A flag is set which will force a refresh of the slitmode
5032 + // segment registers (at mac context switch in). We could rewrite this
5033 + // in C but it might be better to keep things centralized.
5034 +
5035 +GLOBAL_SYMBOL(r__invalidate_splitmode_sr):
5036 + // this will have no effect if fb_InSplitmode is not set
5037 + lwz r4,xFLAG_BITS(r3)
5038 + ori r4,r4,fb_PrepareSplitmode | fb_LoadSegreg
5039 + stw r4,xFLAG_BITS(r3)
5040 + blr
5041 +
5042 +#ifdef CONFIG_SMP
5043 +splitmode_lock:
5044 + .long 0
5045 +#endif
5046 diff --git a/drivers/macintosh/mol/asm-files/traps.S b/drivers/macintosh/mol/asm-files/traps.S
5047 new file mode 100644
5048 index 0000000..996adb0
5049 --- /dev/null
5050 +++ b/drivers/macintosh/mol/asm-files/traps.S
5051 @@ -0,0 +1,501 @@
5052 +/*
5053 + * Creation Date: <2001/01/27 16:25:14 samuel>
5054 + * Time-stamp: <2004/03/07 21:58:48 samuel>
5055 + *
5056 + * <traps.S>
5057 + *
5058 + * Exception Vectors
5059 + *
5060 + * Copyright (C) 2000, 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se)
5061 + *
5062 + * This program is free software; you can redistribute it and/or
5063 + * modify it under the terms of the GNU General Public License
5064 + * as published by the Free Software Foundation
5065 + *
5066 + */
5067 +
5068 +#define DBG_TRACE 0 // enable TRACE macro?
5069 +
5070 +#include "archinclude.h"
5071 +#include "processor.h" /* avoid <asm/processor.h> (bogus SPRN_TBWU/L) */
5072 +#include "asm_offsets.h"
5073 +#include "asmdefs.h"
5074 +#include "molasm.h"
5075 +#include "asmdbg.h"
5076 +#include "actions.h"
5077 +#include "vector.h"
5078 +#include "rvec.h"
5079 +#include "constants.h"
5080 +#include "mac_registers.h"
5081 +#include "mmu.h"
5082 +#include "osi.h"
5083 +#include "kernel_vars.h"
5084 +
5085 +
5086 +/************************************************************************/
5087 +/* Exception Vector Definitions */
5088 +/************************************************************************/
5089 +
5090 + ACTIONS_SECTION
5091 +GLOBAL_SYMBOL(r__actions_section):
5092 + ACTIONS_OFFS_SECTION
5093 +GLOBAL_SYMBOL(r__actions_offs_section):
5094 +
5095 + .text
5096 +GLOBAL_SYMBOL(r__reloctable_start):
5097 +
5098 +MACRO_0(EXCEPTION_PREAMBLE, [
5099 + // SPRG1 = r1, SPRG0 = r3, r3=CR, r1=MOL_STACK
5100 + __ZERO_TICK_CNT(entry)
5101 + stw r4,xGPR4(r1) // store instruction are store serializing
5102 + lwz r4,xFLAG_BITS(r1)
5103 + stw r5,xGPR5(r1) // and mix very badly with execution serializing
5104 + stw r6,xGPR6(r1) // instructions (like mfspr)
5105 + mfsrr0 r6
5106 + stw r7,xGPR7(r1)
5107 + mfsrr1 r7
5108 + stw r0,xGPR0(r1)
5109 + mtcr r4
5110 + stw r2,xGPR2(r1)
5111 + mflr r2
5112 + stw r3,xCR(r1)
5113 + mfsprg_a1 r5 // SPRG1 = r1
5114 + stw r2,xLINK(r1)
5115 + mfsprg_a0 r3 // SPRG0 = r3
5116 + stw r5,xGPR1(r1)
5117 + stw r3,xGPR3(r1)
5118 +
5119 + // saved: r0-r7, cr, lr
5120 + // r1 = stack, cr5-7=flag_bits, r6/r7 = nip/msr
5121 +])
5122 +
5123 + balign_32
5124 +save_middle_regs: // save r8-r12 and nip (r13-r31 should always be in regs)
5125 + stw r6,xNIP(r1)
5126 + mfxer r7
5127 + mfctr r6
5128 + stw r8,xGPR8(r1)
5129 + stw r9,xGPR9(r1)
5130 + stw r10,xGPR10(r1)
5131 + stw r11,xGPR11(r1)
5132 + stw r12,xGPR12(r1)
5133 + stw r6,xCTR(r1)
5134 + stw r7,xXER(r1)
5135 + bt- FBIT_FPUInUse,giveup_fpu // modifies r7/r8
5136 + blr
5137 +
5138 +MACRO_0(RESTORE_MIDDLE_REGS, [ // reverse save_middle_regs, restores registers
5139 + lwz r11,xCTR(r1) // r8-r12, ctr, xer, r6/r7 = nip/msr
5140 + lwz r12,xXER(r1)
5141 + lwz r8,xGPR8(r1)
5142 + lwz r9,xGPR9(r1)
5143 + mtctr r11
5144 + lwz r10,xGPR10(r1)
5145 + lwz r11,xGPR11(r1)
5146 + mtxer r12
5147 + lwz r12,xGPR12(r1)
5148 + lwz r6,xNIP(r1)
5149 + lwz r7,K_MSR(r1)
5150 +])
5151 +
5152 +#define EXCEPTION_SAVE_ALL \
5153 + EXCEPTION_PREAMBLE ;\
5154 + bl save_middle_regs ;
5155 +
5156 +#define VECTOR_KERNEL( v, dummy_name, secint ) \
5157 + VECTOR( v, dummy_name, secint ) ;\
5158 + EXCEPTION_SAVE_ALL ;\
5159 + TAKE_EXCEPTION( v ) ;
5160 +
5161 +#define VECTOR_RESERVED( v, dummy_name, secint ) \
5162 + VECTOR( v, dummy_name, secint ) ;\
5163 + DEBUGGER_SAVE( v ) ;
5164 +
5165 +#define MAC_EXIT( rvec_code ) \
5166 + li r3,rvec_code ;\
5167 + b mac_exit ;
5168 +
5169 +#define MAC_EXIT_SAVE( rvec_code ) \
5170 + bl save_middle_regs ;\
5171 + li r3,rvec_code ;\
5172 + b mac_exit ;
5173 +
5174 +#define MAC_TRAP( trap_num ) \
5175 + li r2,trap_num ;\
5176 + b mac_trap ;
5177 +
5178 +#define DEBUGGER(n) li r4,n ; MAC_EXIT( RVEC_DEBUGGER );
5179 +#define DEBUGGER_SAVE(n) li r4,n ; MAC_EXIT_SAVE( RVEC_DEBUGGER );
5180 +
5181 +
5182 +/************************************************************************/
5183 +/* Misc macros */
5184 +/************************************************************************/
5185 +
5186 + //////////////////////////////////////////////////////////////
5187 + // _get_instr_opcode
5188 + // r6 nip
5189 + // ret: r4 opcode
5190 + //
5191 + // Modifies: r2,r3.
5192 + // Side-effects: Might return from the exception
5193 +
5194 +MACRO(GET_INSTR_OPCODE, [dummy], [
5195 + mfmsr r3 // r3 = exception MSR
5196 + ori r2,r3,MSR_DR
5197 + bl 8f
5198 +
5199 + // secondary interrupt entry (we _know_ this must be a DSI)
5200 +#ifdef CONFIG_SMP
5201 + LOADI r5,EXTERN(compat_hash_table_lock)
5202 + li r4,1
5203 + tophys r5,r5
5204 +7: lwarx r0,0,r5 // lock
5205 + cmpwi r0,0
5206 + bne- 7b
5207 + stwcx. r4,0,r5
5208 + bne- 7b
5209 + isync
5210 + tlbie r6
5211 + eieio
5212 + tlbsync
5213 + sync
5214 + stw r0,0(r5) // release lock
5215 +#else
5216 + tlbie r6 // flush PTE from ITLB
5217 +#endif
5218 + b exception_return
5219 +8:
5220 + mtmsr r2
5221 + isync
5222 +
5223 + lwz r4,0(r6) // get opcode
5224 +
5225 + mtmsr r3 // restore exception MSR
5226 + isync
5227 +])
5228 +
5229 +/************************************************************************/
5230 +/* Reserved / Kernel Vectors */
5231 +/************************************************************************/
5232 +
5233 +VECTOR_KERNEL( 0x100, "System Reset", secint_bad )
5234 +VECTOR_KERNEL( 0x500, "External Interrupt", secint_bad )
5235 +VECTOR_KERNEL( 0x1400, "System Management Interrupt", secint_bad )
5236 +VECTOR_KERNEL( 0x1700, "Thermal Management Interrupt", secint_bad )
5237 +
5238 +VECTOR_RESERVED( 0x200, "Machine Check", secint_bad )
5239 +VECTOR_RESERVED( 0xa00, "Reserved", secint_bad )
5240 +VECTOR_RESERVED( 0xb00, "Reserved", secint_bad )
5241 +VECTOR_RESERVED( 0xe00, "FPU Assist", secint_bad )
5242 +
5243 +PERFMON_VECTOR_RELOCATION( PERFMON_VECTOR )
5244 +VECTOR_RESERVED( PERFMON_VECTOR, "Performance Monitor Interrupt", secint_bad )
5245 +
5246 +//VECTOR_RESERVED( 0x1000, "InstructionTLBMiss-603", secint_bad )
5247 +//VECTOR_RESERVED( 0x1100, "DataLoadTLBMiss-603", secint_bad )
5248 +//VECTOR_RESERVED( 0x1200, "DataLoadTLBMiss-603", secint_bad )
5249 +
5250 +/************************************************************************/
5251 +/* DSI Exceptions */
5252 +/************************************************************************/
5253 +
5254 +VECTOR( 0x300, "DSI", secint_lr_call )
5255 + EXCEPTION_PREAMBLE
5256 + TRACE(0x300, "DSI")
5257 +
5258 + GET_INSTR_OPCODE // m: r2-r3, ret: r4=opcode, r6=nip
5259 + stw r4,xINST_OPCODE(r1)
5260 + bl check_pthash_hit // m: r0,r2-r5
5261 + btl- FBIT_InSplitmode,splitmode_dsi
5262 + bl save_middle_regs
5263 + bl check_io_page
5264 +
5265 +dsi_cont:
5266 + LOADI r3,EXTERN(dsi_exception)
5267 + mfdar r4 // We might need to do this earlier
5268 + mfdsisr r5 // when the splitmode code is activated...
5269 + b call_kernel
5270 +
5271 +
5272 +/************************************************************************/
5273 +/* ISI Exceptions */
5274 +/************************************************************************/
5275 +
5276 +VECTOR( 0x400, "ISI", secint_bad )
5277 + EXCEPTION_PREAMBLE
5278 + TRACE(0x400, "ISI")
5279 +
5280 + // emuaccel engine
5281 + rlwinm. r0,r7,0,4,4 // protection violation
5282 + beq- 1f
5283 + lwz r3,K_EMUACCEL_MPHYS(r1)
5284 + rlwinm r4,r6,0,~0x0fff // nip page
5285 + rlwinm r2,r6,0,0x0ff8 // nip offset (dword align)
5286 + lwz r5,K_EMUACCEL_PAGE_PHYS(r1)
5287 + cmpw r3,r4
5288 + bne- 1f
5289 + lwzux r0,r2,r5 // r0 = handler
5290 + mtlr r0
5291 + lwz r6,4(r2) // address of next instruction
5292 + blr // parameters: r2 == emuaccel_slot
5293 +1:
5294 + btl- FBIT_InSplitmode, split_sr_no_execute
5295 + bl save_middle_regs
5296 +
5297 + LOADI r3,EXTERN(isi_exception)
5298 + mfsrr0 r4
5299 + mfsrr1 r5
5300 + b call_kernel
5301 +
5302 +
5303 +/************************************************************************/
5304 +/* Alignement Exception */
5305 +/************************************************************************/
5306 +
5307 +VECTOR( 0x600, "Alignment", secint_lr_call )
5308 + EXCEPTION_SAVE_ALL
5309 + TRACE(0x400, "Alignment")
5310 +
5311 +alignment_cont:
5312 + mfdar r4
5313 + mfdsisr r5
5314 + MAC_EXIT( RVEC_ALIGNMENT_TRAP )
5315 +
5316 +
5317 +/************************************************************************/
5318 +/* FPU Unavailable Exception */
5319 +/************************************************************************/
5320 +
5321 + // xFPU_STATE has only meaning when FBIT_FPUInUse is not set
5322 + //
5323 + // FPU_STATE_DIRTY - fr13 & fpscr are not loaded (everything else is).
5324 + // FPU_STATE_HALF_SAVED - fr14-fr31 are loaded.
5325 + // FPU_STATE_SAVED - fr14-fr31 are loaded (but also saved in mregs).
5326 + //
5327 + // FPU_STATE_DIRTY in the *emulator* means that all floating point
5328 + // registers *EXCEPT* fr13 and fpscr are valid.
5329 + //
5330 + // Implementation note: When we do not own the fpu, the MSR_FEx bits
5331 + // must be cleared. Otherwise we might experience bogus FPU exceptions.
5332 + //
5333 + // MOL will never throw FPU exceptions went the FP bit is off. This
5334 + // is a small violation of the standard but the alternative would be
5335 + // always loading FPSCR (which requires FPU ownership...)
5336 + //
5337 +
5338 +VECTOR( 0x800, "FPU Unavailable", secint_lr_call )
5339 + EXCEPTION_PREAMBLE
5340 + TRACE(0x800, "FPU Unavailable")
5341 +fpu_cont:
5342 +
5343 + lwz r2,xMSR(r1) // r2 = xMSR (used below too)
5344 + andi. r4,r2,MSR_FP
5345 + beq- mac_fpu_unavailable // mac trap?
5346 + bt FBIT_FPUInUse,2f // FPU ready for use?
5347 +
5348 + lwz r3,K_EMULATOR_MSR(r1) // FPU owned by our userland process?
5349 + andi. r4,r3,MSR_FP
5350 + bne+ 1f
5351 + MAC_EXIT_SAVE( RVEC_ENABLE_FPU ) // No... grab FPU in userspace
5352 +
5353 +mac_fpu_unavailable:
5354 + BUMP( "mac-fpu-trap" )
5355 + MAC_TRAP( 0x800 )
5356 +
5357 + // userland process owns FPU
5358 +1: BUMP( "enable-fpu" )
5359 + ENABLE_MSR_FP /**/ r4 // enable kernel FPU
5360 + // flag the fpu dirty
5361 + lwz r3,xFPU_STATE(r1)
5362 + lfd fr13,xFPSCR-4(r1) // fp13 and fpscr are *ALWAYS* saved
5363 + crset FBIT_FPUInUse // we own the FPU now
5364 + cmpwi r3,FPU_STATE_HALF_SAVED
5365 + mtfsf 0xff,fr13
5366 + lfd fr13,xFPR13(r1)
5367 + bne 2f
5368 + xLOAD_LOW_FPU r1 // load fr0-fr12
5369 +2:
5370 + li r3,MSR_FP| MSR_FE0 | MSR_FE1 // FPU bits
5371 + lwz r7,K_MSR(r1) // enable MSR_FP
5372 + and r2,r2,r3 // r2 = (xMSR & MSR_FEx)
5373 + andc r7,r7,r3 // K_MSR &= ~MSR_FEx
5374 + or r7,r7,r2 // K_MSR |= (xMSR & MSR_FEx)
5375 + stw r7,K_MSR(r1)
5376 + GET_TICK_CNT(entry,"enable_fpu")
5377 + b exception_return
5378 +
5379 +
5380 +/************************************************************************/
5381 +/* Decrementer Exception */
5382 +/************************************************************************/
5383 +
5384 +// The 0x900 decrementer vector is in dec.S
5385 +
5386 +/************************************************************************/
5387 +/* System Call Exception */
5388 +/************************************************************************/
5389 +
5390 +VECTOR( 0xc00, "System Call", secint_bad )
5391 + EXCEPTION_PREAMBLE
5392 + TRACE( 0xc00, "System Call")
5393 +
5394 + lwz r3,xGPR3(r1)
5395 + LOADI r5,OSI_SC_MAGIC_R3
5396 + lwz r4,xGPR4(r1)
5397 + LOADI r2,OSI_SC_MAGIC_R4
5398 + cmpw cr1,r3,r5
5399 + cmpw cr0,r4,r2
5400 + crand eq,eq,cr1_eq
5401 + beq+ 2f
5402 +
5403 + MAC_TRAP(0xc00) // r7 reason bits used (zero)
5404 +2:
5405 + MAC_EXIT_SAVE( RVEC_OSI_SYSCALL )
5406 +
5407 +
5408 +/************************************************************************/
5409 +/* Trace Exception */
5410 +/************************************************************************/
5411 +
5412 +VECTOR( 0xd00, "Trace", secint_bad )
5413 +trace_vector:
5414 + EXCEPTION_PREAMBLE
5415 + TRACE(0xd00, "Trace")
5416 +
5417 + MAC_EXIT_SAVE( RVEC_TRACE_TRAP );
5418 +
5419 +
5420 +/************************************************************************/
5421 +/* AltiVec Exception */
5422 +/************************************************************************/
5423 +
5424 +VECTOR( 0xf20, "AltiVec", secint_lr_call )
5425 + EXCEPTION_PREAMBLE
5426 + TRACE(0xf20, "AltiVec")
5427 +altivec_cont:
5428 +
5429 + lwz r4,xNO_ALTIVEC(r1) // AltiVec support disabled?
5430 + cmpwi r4,0
5431 + bne- mac_altivec_unavailable
5432 +
5433 + lwz r2,xMSR(r1)
5434 + rlwinm. r4,r2,0,6,6 // bit 6 = MSR_VEC
5435 + beq- mac_altivec_unavailable
5436 +
5437 + lwz r3,K_EMULATOR_MSR(r1)
5438 + rlwinm. r4,r3,0,6,6 // bit 6 = MSR_VEC
5439 + bne+ enable_altivec
5440 + MAC_EXIT_SAVE( RVEC_ENABLE_ALTIVEC )
5441 +
5442 +mac_altivec_unavailable:
5443 + MAC_EXIT_SAVE( RVEC_ALTIVEC_UNAVAIL_TRAP )
5444 +
5445 +enable_altivec:
5446 + // We don't need to load any registers since the emulator
5447 + // won't touch the altivec unit (at least for now).
5448 +
5449 + lwz r7,K_MSR(r1)
5450 + oris r7,r7,HI(MSR_VEC)
5451 + stw r7,K_MSR(r1)
5452 + b exception_return
5453 +
5454 +
5455 +VECTOR( 0x1600, "AltiVec Assist", secint_bad )
5456 + EXCEPTION_SAVE_ALL
5457 + TRACE(0x1600, "AltiVec Assist")
5458 +
5459 + mr r4,r7
5460 + MAC_EXIT( RVEC_ALTIVEC_ASSIST ) // r4 = srr1
5461 +
5462 +
5463 +/************************************************************************/
5464 +/* Instruction Breakpoint */
5465 +/************************************************************************/
5466 +
5467 +VECTOR( 0x1300, "Instruction Breakpoint", secint_bad )
5468 + EXCEPTION_SAVE_ALL
5469 + TRACE(0x1300, "IABR")
5470 +
5471 + DEBUGGER(0x1300)
5472 +
5473 +
5474 +/************************************************************************/
5475 +/* RunMode-601 (trace) */
5476 +/************************************************************************/
5477 +
5478 +VECTOR( 0x2000, "RunMode-601", secint_bad )
5479 + b trace_vector
5480 +
5481 +
5482 +/************************************************************************/
5483 +/* Secondary Interrupt Handlers */
5484 +/************************************************************************/
5485 +
5486 + //////////////////////////////////////////////////////////////////////
5487 + // secint_xxx
5488 + //
5489 + // r1: stack (sprg1 = old r1)
5490 + // r3: vector addr (sprg0 = old r3)
5491 + // srr0/srr1: kernel nip/msr
5492 + //
5493 + // secint_lr_call:
5494 + // lr secondary interrupt handler
5495 +
5496 +secint_bad:
5497 + TRACE(0xbad, "secint_bad")
5498 + mr r4,r3
5499 + MAC_EXIT( RVEC_INTERNAL_ERROR )
5500 +
5501 +secint_lr_call:
5502 + blrl
5503 + li r4,0x6666
5504 + MAC_EXIT( RVEC_INTERNAL_ERROR )
5505 +
5506 +
5507 +/**************************************************************
5508 +* Includes
5509 +**************************************************************/
5510 +
5511 +// We need to be sure this code is contiguous, the simplest/safest
5512 +// method is using only a single file. This will also effectively
5513 +// reduce the size of the relocation table.
5514 +
5515 +#ifdef __darwin__
5516 +#include "darwin.S"
5517 +#endif
5518 +#include "entry.S"
5519 +#include "dec.S"
5520 +#include "emulation.S"
5521 +#include "emuaccel.S"
5522 +#include "iopage.S"
5523 +#include "splitmode.S"
5524 +#include "ptintercept.S"
5525 +#include "vsid.S"
5526 +#ifdef __MPC107__
5527 +#include "./mpc107/mpc107.S"
5528 +#else
5529 +#ifdef __linux__
5530 +#include "linux.S"
5531 +#include "603.S"
5532 +#endif
5533 +#endif
5534 +
5535 +#ifdef __linux__
5536 + .text 50
5537 +#endif
5538 +GLOBAL_SYMBOL(r__reloctable_end):
5539 +
5540 + ACTIONS_OFFS_SECTION
5541 +GLOBAL_SYMBOL(r__actions_offs_section_end):
5542 +
5543 +// The BUMP("counter") macro adds entries to text subsection 90.
5544 +// This adds labels before the counter entries.
5545 +
5546 +#ifdef __linux__
5547 + .text 89
5548 +GLOBAL_SYMBOL(__start_bumptable):
5549 + .text 91
5550 +GLOBAL_SYMBOL(__end_bumptable):
5551 + .text
5552 +#endif
5553 diff --git a/drivers/macintosh/mol/asm-files/vsid.S b/drivers/macintosh/mol/asm-files/vsid.S
5554 new file mode 100644
5555 index 0000000..97ecc2e
5556 --- /dev/null
5557 +++ b/drivers/macintosh/mol/asm-files/vsid.S
5558 @@ -0,0 +1,123 @@
5559 +/*
5560 + * Creation Date: <2003/03/06 22:03:59 samuel>
5561 + * Time-stamp: <2004/02/21 16:30:45 samuel>
5562 + *
5563 + * <vsid.S>
5564 + *
5565 + * VSID lookup (skiplist search)
5566 + *
5567 + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
5568 + *
5569 + * This program is free software; you can redistribute it and/or
5570 + * modify it under the terms of the GNU General Public License
5571 + * as published by the Free Software Foundation
5572 + *
5573 + */
5574 +
5575 +#include "mtable.h"
5576 +
5577 +#if (SKIPLIST_LEVELSIZE == 4)
5578 +#define SLEVEL_SHIFT 2
5579 +#endif
5580 +#if (SKIPLIST_LEVELSIZE == 8)
5581 +#define SLEVEL_SHIFT 3
5582 +#endif
5583 +
5584 +emulate_mtsrin:
5585 + rlwinm r2,r4,32-8,24,28 // r2 = #B << 8
5586 + EMU_LOAD_GPR r2, /**/ R3 // r0 = reg B
5587 + rlwinm r4,r0,0,0,3 // #sr top 4 bits of r4
5588 + b 1f
5589 +emulate_mtsr:
5590 + rlwinm r4,r4,12,0,3 // #sr in top 4 bits of r4
5591 +1: EMU_LOAD_GPR r5, /**/ R2 // r0 = new segr value
5592 +
5593 + stw r8,xGPR8(r1) // save r8
5594 + rlwinm r8,r4,6,26,29 // r8 = #sr << 2
5595 + stw r9,xGPR9(r1) // save r9
5596 + add r8,r8,r1 // r8 = r1 + sr_offset
5597 + stw r6,xNIP(r1) // save r6 (need more registers)
5598 + rlwinm r9,r0,0,0,3 // r9 = [T Ks Kp N]
5599 + stw r0,xSEGR_BASE(r8) // store new value
5600 + rlwinm r0,r0,0,8,31 // mask VSID
5601 +
5602 + /******* vsid lookup (skiplist search) *******/
5603 +
5604 + lwz r2,K_VSID_SL_SLEVEL(r1) // n = search level (0..15)
5605 + rlwinm r2,r2,SLEVEL_SHIFT,0,29 // n *= 4 (or n *= 8 on darwin)
5606 +
5607 + addi r3,r1,K_VSID_SL_ROOT_ELEM // p = root element
5608 +1: add r5,r2,r3 //
5609 +2: lwz r3,SKIPLIST_NEXT(r5) // r3 = p->next[n]
5610 +#ifdef __linux__
5611 + tophys R3,R3
5612 +#endif
5613 + lwz r4,SKIPLIST_KEY(r3) // r0 = p->next[n].key
5614 + cmpw cr1,r4,r0
5615 + bge- cr1,3f
5616 + b 1b
5617 +3:
5618 + addi r2,r2,-SKIPLIST_LEVELSIZE // r2 -= 4|8
5619 + beq- cr1,vsid_found // jump if key matches
5620 + cmpwi r2,0
5621 + addi r5,r5,-SKIPLIST_LEVELSIZE // r5 -= 4|8
5622 + bge+ 2b
5623 +
5624 + /******* vsid missing *******/
5625 + BUMP("vsid_missing")
5626 + // r8 used
5627 + lwz r2,K_ILLEGAL_SR(r1) // vsid unallocated...
5628 + li r4,0 // no entry...
5629 + stw r2,K_SV_SR_BASE(r8)
5630 + stw r2,K_USER_SR_BASE(r8)
5631 + stw r2,K_SPLIT_SR_BASE(r8) // this way we can forget the splitmode case
5632 + stw r4,K_VSID_ENT_BASE(r8)
5633 + sub r5,r8,r1 // r5 = VSID offset
5634 + lwz r0,K_CUR_SR_BASE(r1) // r0 = cur_sr_table
5635 + b 6f
5636 +
5637 + /******* vsid found *******/
5638 +vsid_found:
5639 +
5640 + BUMP("vsid_found")
5641 + // match, r3 points to the skiplist element
5642 + addi r4,r3,-SIZEOF_VSID_ENT // sizeof(vsid_ent_t)
5643 + lwz r2,VSID_USER_OFFS(r4) // vsid_user
5644 + lwz r3,VSID_SV_OFFS(r4) // vsid_sv
5645 +#ifdef __linux__
5646 + tovirt R4,R4 // r4 = vsid_element
5647 +#else
5648 + lwz r4,VSID_MYSELF_VIRT(r4)
5649 +#endif
5650 + rlwinm r6,r9,2,31,31 // r6 = Ks ? 1:0
5651 + stw r4,K_VSID_ENT_BASE(r8) // store vsid entry (possibly NULL)
5652 + rlwinm r4,r9,3,31,31 // r4 = Kp ? 1:0
5653 + rlwimi r2,r9,0,3,3 // copy the N-bit (no-execute)
5654 + rlwimi r3,r9,0,3,3 // copy the N-bit (no-execute)
5655 + cror FBIT_LoadSegreg, FBIT_LoadSegreg, FBIT_InSplitmode
5656 + addi r6,r6,-1 // r6 = Ks-mask
5657 + addi r4,r4,-1 // r4 = Kp-mask
5658 + andc r0,r2,r6 // Kp == 1 case
5659 + and r6,r3,r6 // Kp == 0 case
5660 + crmove FBIT_PrepareSplitmode, FBIT_InSplitmode
5661 + andc r9,r2,r4 // Ks == 1 case
5662 + or r6,r6,r0
5663 + lwz r0,K_CUR_SR_BASE(r1) // r0 = cur_sr_table
5664 + and r4,r3,r4 // Ks == 0 case
5665 + stw r6,K_SV_SR_BASE(r8) // sv_sr set
5666 + or r4,r4,r9
5667 + sub r5,r8,r1 // r5 = VSID offset
5668 + stw r4,K_USER_SR_BASE(r8) // user_sr set
5669 +6:
5670 + // r0,r5 used
5671 + rlwinm r2,r5,32-6,0,3 // r2 = sr# in bits 0-3
5672 + lwzx r3,r5,r0 // r3 = sr to be loaded into sr#
5673 + mtsrin r3,r2 // update segment register
5674 +
5675 + lwz r6,xNIP(r1) // restore r6
5676 + lwz r8,xGPR8(r1) // restore r8
5677 + lwz r9,xGPR9(r1) // restore r9
5678 + GET_TICK_CNT(entry, "mtsr")
5679 + BUMP("mtsr_")
5680 + b emulation_done
5681 +
5682 diff --git a/drivers/macintosh/mol/asm_offsets.c b/drivers/macintosh/mol/asm_offsets.c
5683 new file mode 100644
5684 index 0000000..bab89f1
5685 --- /dev/null
5686 +++ b/drivers/macintosh/mol/asm_offsets.c
5687 @@ -0,0 +1,161 @@
5688 +/*
5689 + * This program is used to generate definitions needed by
5690 + * some assembly functions.
5691 + *
5692 + * We use the technique used in the OSF Mach kernel code:
5693 + * generate asm statements containing #defines,
5694 + * compile this file to assembler, and then extract the
5695 + * #defines from the assembly-language output.
5696 + */
5697 +
5698 +#ifdef __KERNEL__
5699 +#include "archinclude.h"
5700 +#include "kernel_vars.h"
5701 +#include "mmu.h"
5702 +#else
5703 +#include "mol_config.h"
5704 +#include <stddef.h>
5705 +#include "mac_registers.h"
5706 +#endif
5707 +
5708 +#include "processor.h"
5709 +
5710 +#define DEFINE(sym, val) \
5711 + asm volatile("\n#define\t" #sym "\t%0" : : "i" (val))
5712 +
5713 +#define K_DEF(sym, val ) \
5714 + DEFINE(sym, offsetof(kernel_vars_t, val ))
5715 +
5716 +#define ST_DEF(sym, val ) \
5717 + DEFINE(sym, offsetof(session_table_t, val ))
5718 +
5719 +#define M_DEF(sym, val ) \
5720 + DEFINE(sym, XOFFS + offsetof(mac_regs_t, val ))
5721 +
5722 +#define IO_DEF(sym, val) \
5723 + DEFINE(sym, offsetof(struct io_page, val ))
5724 +
5725 +int main( void )
5726 +{
5727 +#ifdef __KERNEL__
5728 + #define XOFFS offsetof(kernel_vars_t, mregs)
5729 +#else
5730 + #define XOFFS 0
5731 +#endif
5732 + /* --- mac_regs offsets --- */
5733 +
5734 + M_DEF( xVEC_BASE, vec[0] );
5735 + M_DEF( xVEC0, vec[0] );
5736 + M_DEF( xVEC1, vec[1] );
5737 + M_DEF( xVEC2, vec[2] );
5738 + M_DEF( xVSCR, vscr );
5739 + M_DEF( xVRSAVE, spr[S_VRSAVE] );
5740 +
5741 + M_DEF( xGPR_BASE, gpr[0] );
5742 + M_DEF( xGPR0, gpr[0] );
5743 + M_DEF( xGPR1, gpr[1] );
5744 + M_DEF( xGPR2, gpr[2] );
5745 + M_DEF( xGPR3, gpr[3] );
5746 + M_DEF( xGPR4, gpr[4] );
5747 + M_DEF( xGPR5, gpr[5] );
5748 + M_DEF( xGPR6, gpr[6] );
5749 + M_DEF( xGPR7, gpr[7] );
5750 + M_DEF( xGPR8, gpr[8] );
5751 + M_DEF( xGPR9, gpr[9] );
5752 + M_DEF( xGPR10, gpr[10] );
5753 + M_DEF( xGPR11, gpr[11] );
5754 + M_DEF( xGPR12, gpr[12] );
5755 + M_DEF( xGPR13, gpr[13] );
5756 + M_DEF( xGPR14, gpr[14] );
5757 + M_DEF( xGPR15, gpr[15] );
5758 + M_DEF( xGPR16, gpr[16] );
5759 + M_DEF( xGPR17, gpr[17] );
5760 + M_DEF( xGPR18, gpr[18] );
5761 + M_DEF( xGPR19, gpr[19] );
5762 + M_DEF( xGPR20, gpr[20] );
5763 + M_DEF( xGPR21, gpr[21] );
5764 + M_DEF( xGPR22, gpr[22] );
5765 + M_DEF( xGPR23, gpr[23] );
5766 + M_DEF( xGPR24, gpr[24] );
5767 + M_DEF( xGPR25, gpr[25] );
5768 + M_DEF( xGPR26, gpr[26] );
5769 + M_DEF( xGPR27, gpr[27] );
5770 + M_DEF( xGPR28, gpr[28] );
5771 + M_DEF( xGPR29, gpr[29] );
5772 + M_DEF( xGPR30, gpr[30] );
5773 + M_DEF( xGPR31, gpr[31] );
5774 +
5775 + M_DEF( xNIP, nip);
5776 + M_DEF( xCR, cr);
5777 + M_DEF( xFPR_BASE, fpr[0]);
5778 + M_DEF( xFPR13, fpr[13]);
5779 + M_DEF( xFPSCR, fpscr );
5780 + M_DEF( xEMULATOR_FPSCR, emulator_fpscr );
5781 + M_DEF( xFPU_STATE, fpu_state );
5782 +
5783 + M_DEF( xLINK, link);
5784 + M_DEF( xXER, xer);
5785 + M_DEF( xCTR, ctr);
5786 + M_DEF( xFLAG_BITS, flag_bits );
5787 + M_DEF( xDEC, spr[S_DEC]);
5788 + M_DEF( xDEC_STAMP, dec_stamp);
5789 + M_DEF( xTIMER_STAMP, timer_stamp);
5790 + M_DEF( xMSR, msr);
5791 + M_DEF( xSPR_BASE, spr[0]);
5792 +
5793 + M_DEF( xHID0, spr[S_HID0]);
5794 +
5795 + M_DEF( xSRR0, spr[S_SRR0]);
5796 + M_DEF( xSRR1, spr[S_SRR1]);
5797 +
5798 + M_DEF( xSPRG0, spr[S_SPRG0]);
5799 + M_DEF( xSPRG1, spr[S_SPRG1]);
5800 + M_DEF( xSPRG2, spr[S_SPRG2]);
5801 + M_DEF( xSPRG3, spr[S_SPRG3]);
5802 +
5803 + M_DEF( xSEGR_BASE, segr[0]);
5804 + M_DEF( xIBAT_BASE, spr[S_IBAT0U] );
5805 + M_DEF( xSDR1, spr[S_SDR1] );
5806 +
5807 + M_DEF( xINST_OPCODE, inst_opcode );
5808 + M_DEF( xALTIVEC_USED, altivec_used );
5809 + M_DEF( xNO_ALTIVEC, no_altivec );
5810 +
5811 + M_DEF( xINTERRUPT, interrupt );
5812 + M_DEF( xIN_VIRTUAL_MODE, in_virtual_mode );
5813 +
5814 + M_DEF( xRVEC_PARAM0, rvec_param[0] );
5815 + M_DEF( xRVEC_PARAM1, rvec_param[1] );
5816 + M_DEF( xRVEC_PARAM2, rvec_param[2] );
5817 +
5818 +#ifdef EMULATE_603
5819 + M_DEF( xGPRSAVE0_603, gprsave_603[0] );
5820 + M_DEF( xGPRSAVE1_603, gprsave_603[1] );
5821 + M_DEF( xGPRSAVE2_603, gprsave_603[2] );
5822 + M_DEF( xGPRSAVE3_603, gprsave_603[3] );
5823 +#endif
5824 +
5825 + M_DEF( xDEBUG0, debug[0] );
5826 + M_DEF( xDEBUG1, debug[1] );
5827 + M_DEF( xDEBUG2, debug[2] );
5828 + M_DEF( xDEBUG3, debug[3] );
5829 + M_DEF( xDEBUG4, debug[4] );
5830 + M_DEF( xDEBUG5, debug[5] );
5831 + M_DEF( xDEBUG6, debug[6] );
5832 + M_DEF( xDEBUG7, debug[7] );
5833 + M_DEF( xDEBUG8, debug[8] );
5834 + M_DEF( xDEBUG9, debug[9] );
5835 +
5836 + M_DEF( xDEBUG_SCR1, debug_scr1 );
5837 + M_DEF( xDEBUG_SCR2, debug_scr2 );
5838 + M_DEF( xDEBUG_TRACE, debug_trace );
5839 + M_DEF( xDBG_TRACE_SPACE, dbg_trace_space[0] );
5840 + M_DEF( xDBG_LAST_RVEC, dbg_last_rvec );
5841 +
5842 + M_DEF( xKERNEL_DBG_STOP, kernel_dbg_stop );
5843 +
5844 + M_DEF( xHOSTIRQ_ACTIVE_CNT, hostirq_active_cnt );
5845 +
5846 + return 0;
5847 +}
5848 +
5849 diff --git a/drivers/macintosh/mol/context.c b/drivers/macintosh/mol/context.c
5850 new file mode 100644
5851 index 0000000..9f97a6a
5852 --- /dev/null
5853 +++ b/drivers/macintosh/mol/context.c
5854 @@ -0,0 +1,99 @@
5855 +/*
5856 + * Creation Date: <1998-11-20 16:18:20 samuel>
5857 + * Time-stamp: <2004/02/28 19:16:44 samuel>
5858 + *
5859 + * <context.c>
5860 + *
5861 + * MMU context allocation
5862 + *
5863 + * Copyright (C) 1998-2004 Samuel Rydh (samuel@ibrium.se)
5864 + *
5865 + * This program is free software; you can redistribute it and/or
5866 + * modify it under the terms of the GNU General Public License
5867 + * as published by the Free Software Foundation
5868 + *
5869 + */
5870 +
5871 +#include "archinclude.h"
5872 +#include "alloc.h"
5873 +#include "mmu.h"
5874 +#include "mmu_contexts.h"
5875 +#include "misc.h"
5876 +#include "asmfuncs.h"
5877 +#include "emu.h"
5878 +#include "mtable.h"
5879 +#include "performance.h"
5880 +#include "context.h"
5881 +#include "hash.h"
5882 +
5883 +#define MMU (kv->mmu)
5884 +
5885 +
5886 +static int
5887 +flush_all_PTEs( kernel_vars_t *kv )
5888 +{
5889 + int i, count=0, npte=(ptehash.pte_mask + 8)/8;
5890 + ulong *pte, ea, v;
5891 +
5892 + for( pte=ptehash.base, i=0; i<npte; i++, pte+=2 ) {
5893 + v = *pte;
5894 + if( !(v & BIT(0)) ) /* test V-bit */
5895 + continue;
5896 + v = (v & ~BIT(0)) >> 7;
5897 + v = (v - ((v & 0xf) * MUNGE_ESID_ADD)) * MUNGE_MUL_INVERSE;
5898 + v = (v>>4) & CTX_MASK;
5899 +
5900 + if( v >= MMU.first_mol_context && v <= MMU.last_mol_context ) {
5901 + *pte = 0;
5902 + count++;
5903 + }
5904 + }
5905 +
5906 + /* perform a tlbia */
5907 + for( ea=0; ea <= (0x3f << 12); ea += 0x1000 )
5908 + __tlbie( ea );
5909 +
5910 + if( count )
5911 + printk("%d stale PTEs flushed (something is wrong)\n", count );
5912 + return count;
5913 +}
5914 +
5915 +int
5916 +init_contexts( kernel_vars_t *kv )
5917 +{
5918 + MMU.first_mol_context = FIRST_MOL_CONTEXT( kv->session_index );
5919 + MMU.last_mol_context = LAST_MOL_CONTEXT( kv->session_index );
5920 + MMU.next_mol_context = MMU.first_mol_context;
5921 +
5922 + MMU.illegal_sr = alloc_context(kv) | VSID_Kp | VSID_N;
5923 +
5924 + flush_all_PTEs( kv );
5925 + return 0;
5926 +}
5927 +
5928 +void
5929 +cleanup_contexts( kernel_vars_t *kv )
5930 +{
5931 + flush_all_PTEs( kv );
5932 +}
5933 +
5934 +void
5935 +handle_context_wrap( kernel_vars_t *kv, int n )
5936 +{
5937 + if( MMU.next_mol_context + n > MMU.last_mol_context ) {
5938 + printk("MOL context wrap\n");
5939 +
5940 + clear_all_vsids( kv );
5941 + init_contexts( kv );
5942 + }
5943 +}
5944 +
5945 +int
5946 +alloc_context( kernel_vars_t *kv )
5947 +{
5948 + int mol_context = MMU.next_mol_context++;
5949 + int vsid = MUNGE_CONTEXT(mol_context >> 4);
5950 +
5951 + vsid += MUNGE_ESID_ADD * (mol_context & 0xf);
5952 + return (vsid & VSID_MASK);
5953 +}
5954 diff --git a/drivers/macintosh/mol/emu.c b/drivers/macintosh/mol/emu.c
5955 new file mode 100644
5956 index 0000000..2a25db7
5957 --- /dev/null
5958 +++ b/drivers/macintosh/mol/emu.c
5959 @@ -0,0 +1,228 @@
5960 +/*
5961 + * Creation Date: <1998-11-21 16:07:47 samuel>
5962 + * Time-stamp: <2004/03/13 14:08:18 samuel>
5963 + *
5964 + * <emu.c>
5965 + *
5966 + * Emulation of some assembly instructions
5967 + *
5968 + * Copyright (C) 1998-2004 Samuel Rydh (samuel@ibrium.se)
5969 + *
5970 + * This program is free software; you can redistribute it and/or
5971 + * modify it under the terms of the GNU General Public License
5972 + * as published by the Free Software Foundation
5973 + *
5974 + */
5975 +
5976 +#include "archinclude.h"
5977 +#include "alloc.h"
5978 +#include "mmu.h"
5979 +#include "kernel_vars.h"
5980 +#include "emu.h"
5981 +#include "asmfuncs.h"
5982 +#include "rvec.h"
5983 +#include "processor.h"
5984 +#include "mtable.h"
5985 +#include "performance.h"
5986 +#include "emuaccel_sh.h"
5987 +#include "misc.h"
5988 +#include "map.h"
5989 +
5990 +#define BAT_PERFORMANCE_HACK
5991 +// #define DEBUG
5992 +
5993 +/* If BAT_PERFORMANCE_HACK is defined, PTEs corresponding to a mac bat
5994 + * mapping will not necessary be flushed when the bat registers are
5995 + * touched. This gives a huge performance gain in MacOS 9.1 (which
5996 + * clears the bat registers in the idle loop). Of course, this break
5997 + * compatibility (although most operating systems initializes the
5998 + * BATs once and for all).
5999 + */
6000 +
6001 +#ifdef BAT_PERFORMANCE_HACK
6002 + #define BAT_HACK(kv) (!MREGS.use_bat_hack || kv->mmu.bat_hack_count++ < 0x100)
6003 +#else
6004 + #define BAT_HACK(kv) 1
6005 +#endif
6006 +
6007 +#define MREGS (kv->mregs)
6008 +#define MMU (kv->mmu)
6009 +
6010 +
6011 +int
6012 +do_mtsdr1( kernel_vars_t *kv, ulong value )
6013 +{
6014 + ulong mbase, mask;
6015 + int s;
6016 +
6017 + MREGS.spr[S_SDR1] = value;
6018 +
6019 + /* the mask must be a valid one; we hade better make sure we are
6020 + * not tricked by a bogus sdr1 value
6021 + */
6022 + for( mask=BIT(23); mask && !(mask & value) ; mask=mask>>1 )
6023 + ;
6024 + mask = mask? ((mask | (mask-1)) << 16) | 0xffff : 0xffff;
6025 + mbase = value & ~mask;
6026 +
6027 + if( mbase + mask >= MMU.ram_size ) {
6028 + /* S_SDR1 out of range, fallback to a safe setting */
6029 + printk("WARNING, S_SDR1, %08lX is out of range\n", value);
6030 + mbase = 0;
6031 + mask = 0xffff;
6032 + }
6033 +
6034 + MMU.hash_mbase = mbase;
6035 + MMU.hash_mask = mask;
6036 + MMU.pthash_sr = -1; /* clear old tlbhash matching */
6037 +
6038 + if( MMU.hash_base )
6039 + unmap_emulated_hash( kv );
6040 + MMU.hash_base = map_emulated_hash( kv, MMU.hash_mbase, mask+1 );
6041 +
6042 + /* try to allocate the PTE bitfield table (16K/128 MB ram). The worst
6043 + * case is 512K which will fail since the kmalloc limit is 128K.
6044 + * If the allocation fails, we simply don't use the bitfield table.
6045 + */
6046 + s = (mask+1)/8/8;
6047 + if( MMU.pthash_inuse_bits )
6048 + kfree_cont_mol( MMU.pthash_inuse_bits );
6049 + if( !(MMU.pthash_inuse_bits=kmalloc_cont_mol(s)) )
6050 + MMU.pthash_inuse_bits_ph = 0;
6051 + else {
6052 + memset( MMU.pthash_inuse_bits, 0, s );
6053 + MMU.pthash_inuse_bits_ph = tophys_mol( MMU.pthash_inuse_bits );
6054 + }
6055 +
6056 + /* make sure the unmapped ram range is flushed... */
6057 + flush_lv_range( kv, MMU.userspace_ram_base + mbase, mask+1 );
6058 +
6059 + /* ...as well as any MMU mappings */
6060 + clear_pte_hash_table( kv );
6061 +
6062 + BUMP(do_mtsdr1);
6063 + return RVEC_NOP;
6064 +}
6065 +
6066 +/* This function is _very_ slow, since it must destroy a lot of PTEs.
6067 + * Fortunately, BAT-maps are normally static.
6068 + */
6069 +int
6070 +do_mtbat( kernel_vars_t *kv, int sprnum, ulong value, int force )
6071 +{
6072 + mac_bat_t *d;
6073 + int batnum;
6074 + mBAT *p;
6075 +
6076 + BUMP(do_mtbat);
6077 +
6078 + if( !force && MREGS.spr[sprnum] == value )
6079 + return RVEC_NOP;
6080 +
6081 + /* printk("do_mtbat %d %08lX\n", sprnum, value); */
6082 +
6083 + MREGS.spr[sprnum] = value;
6084 +
6085 + /* upper bat register have an even number */
6086 + batnum = (sprnum - S_IBAT0U) >>1;
6087 + d = &MMU.bats[batnum];
6088 +
6089 + /* First we must make sure that all PTEs corresponding to
6090 + * the old BAT-mapping are purged from the hash table.
6091 + */
6092 + if( BAT_HACK(kv) && d->valid )
6093 + flush_ea_range(kv, d->base & ~0xf0000000, d->size );
6094 +
6095 + p = (mBAT*)&MREGS.spr[sprnum & ~1];
6096 + d->valid = p->batu.vs | p->batu.vp;
6097 + d->vs = p->batu.vs;
6098 + d->vp = p->batu.vp;
6099 + d->wimg = (p->batl.w<<3) | (p->batl.i<<2) | (p->batl.m<<1) | p->batl.g;
6100 + d->ks = d->ku = 1; /* IBAT/DBATs, behaves as if key==1 */
6101 + d->pp = p->batl.pp;
6102 + d->size = (p->batu.bl+1)<<17;
6103 + d->base = (p->batu.bepi & ~p->batu.bl)<<17;
6104 + d->mbase = (p->batl.brpn & ~p->batu.bl)<<17;
6105 +
6106 + /* Next, we must make sure that no PTEs refer to the new
6107 + * BAT-mapped area.
6108 + */
6109 +
6110 + if( BAT_HACK(kv) && d->valid )
6111 + flush_ea_range( kv, d->base & ~0xf0000000, d->size );
6112 +
6113 + return RVEC_NOP;
6114 +}
6115 +
6116 +
6117 +/************************************************************************/
6118 +/* Emulation acceleration */
6119 +/************************************************************************/
6120 +
6121 +static ulong
6122 +lookup_emuaccel_handler( int emuaccel )
6123 +{
6124 + extern ulong emuaccel_table[];
6125 + ulong handler, *p = emuaccel_table;
6126 +
6127 + for( ; p[0]; p+=3 ) {
6128 + if( (emuaccel & EMUACCEL_INST_MASK) != p[0] )
6129 + continue;
6130 + emuaccel &= p[2]; /* offset mask */
6131 + handler = p[1] + (ulong)emuaccel_table + emuaccel * 8;
6132 + return tophys_mol( (ulong*)reloc_ptr(handler) );
6133 + }
6134 + return 0;
6135 +}
6136 +
6137 +int
6138 +alloc_emuaccel_slot( kernel_vars_t *kv, int emuaccel, int param, int inst_addr )
6139 +{
6140 + ulong *p = (ulong*)((char*)kv->emuaccel_page + kv->emuaccel_size);
6141 + ulong handler = lookup_emuaccel_handler( emuaccel );
6142 + int size, ret;
6143 +
6144 + size = (emuaccel & EMUACCEL_HAS_PARAM)? 16 : 8;
6145 + if( !handler || !p || kv->emuaccel_size + size > 0x1000 )
6146 + return 0;
6147 +
6148 + ret = kv->emuaccel_mphys + kv->emuaccel_size;
6149 + p[0] = handler;
6150 + p[1] = inst_addr + 4;
6151 +
6152 + if( emuaccel & EMUACCEL_HAS_PARAM ) {
6153 + /* p[2] is already EMUACCEL_NOP */
6154 + p[3] = param;
6155 + }
6156 +
6157 + kv->emuaccel_size += size;
6158 + return ret;
6159 +}
6160 +
6161 +int
6162 +mapin_emuaccel_page( kernel_vars_t *kv, int mphys )
6163 +{
6164 + int i, handler;
6165 + ulong *p;
6166 +
6167 + if( kv->emuaccel_page || (mphys & 0xfff) )
6168 + return 0;
6169 +
6170 + if( !(kv->emuaccel_page=alloc_page_mol()) )
6171 + return 0;
6172 +
6173 + kv->emuaccel_page_phys = tophys_mol( (char*)kv->emuaccel_page );
6174 + kv->emuaccel_mphys = mphys;
6175 + p = (ulong*)kv->emuaccel_page;
6176 +
6177 + handler = lookup_emuaccel_handler( EMUACCEL_NOP );
6178 + for( i=0; i<0x1000/sizeof(int); i+=2 ) {
6179 + p[i] = handler;
6180 + p[i+1] = 0;
6181 + }
6182 +
6183 + /* flush translations - an old translation is overridden */
6184 + clear_pte_hash_table( kv );
6185 + /* printk("emuaccel_mapin: %08x\n", mphys ); */
6186 + return mphys;
6187 +}
6188 diff --git a/drivers/macintosh/mol/fault.c b/drivers/macintosh/mol/fault.c
6189 new file mode 100644
6190 index 0000000..3b667ef
6191 --- /dev/null
6192 +++ b/drivers/macintosh/mol/fault.c
6193 @@ -0,0 +1,601 @@
6194 +/*
6195 + * Creation Date: <2002/06/08 20:53:20 samuel>
6196 + * Time-stamp: <2004/02/22 13:07:50 samuel>
6197 + *
6198 + * <fault.c>
6199 + *
6200 + * Page fault handler
6201 + *
6202 + * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se)
6203 + *
6204 + * This program is free software; you can redistribute it and/or
6205 + * modify it under the terms of the GNU General Public License
6206 + * as published by the Free Software Foundation
6207 + *
6208 + */
6209 +
6210 +#include "archinclude.h"
6211 +#include "alloc.h"
6212 +
6213 +#include "kernel_vars.h"
6214 +#include "mmu.h"
6215 +#include "mmu_contexts.h"
6216 +#include "asmfuncs.h"
6217 +#include "emu.h"
6218 +#include "misc.h"
6219 +#include "constants.h"
6220 +#include "rvec.h"
6221 +#include "mtable.h"
6222 +#include "performance.h"
6223 +#include "processor.h"
6224 +#include "hash.h"
6225 +
6226 +/* exception bits (srr1/dsisr and a couple of mol defined bits) */
6227 +#define EBIT_PAGE_FAULT BIT(1) /* I/D, PTE missing */
6228 +#define EBIT_NO_EXEC BIT(3) /* I, no-execute or guarded */
6229 +#define EBIT_PROT_VIOL BIT(4) /* I/D, protection violation */
6230 +#define EBIT_IS_WRITE BIT(6) /* D */
6231 +#define EBIT_IS_DSI 1 /* D, virtual bit */
6232 +#define EBIT_USE_MMU 2 /* I/D, virtual bit */
6233 +
6234 +#define use_mmu(ebits) ((ebits) & EBIT_USE_MMU)
6235 +#define is_write(ebits) ((ebits) & EBIT_IS_WRITE)
6236 +#define is_dsi(ebits) ((ebits) & EBIT_IS_DSI)
6237 +#define is_prot_viol(ebits) ((ebits) & EBIT_PROT_VIOL)
6238 +#define is_page_fault(ebits) ((ebits) & EBIT_PAGE_FAULT)
6239 +
6240 +typedef struct {
6241 + /* filled in by exception handler */
6242 + ulong ea;
6243 + ulong *sr_base;
6244 + struct vsid_ent **vsid_eptr; /* pointer to MMU.vsid or MMU.unmapped_vsid */
6245 +
6246 + /* filled in by lookup_mphys */
6247 + mPTE_t *mpte; /* lvptr to mac-pte (if != NULL) */
6248 + ulong mphys_page; /* ea of mphys page */
6249 + int pte1; /* RPN | 000 | R | C | WIMG | 00 | PP */
6250 + int key; /* pp key bit */
6251 +} fault_param_t;
6252 +
6253 +static const char priv_viol_table[16] = { /* [is_write | key | PP] */
6254 + 0,0,0,0,1,0,0,0, /* read (1 == violation) */
6255 + 0,0,0,1,1,1,0,1 /* write */
6256 +};
6257 +
6258 +#define NO_MMU_PTE1 (PTE1_R | PTE1_C /*| PTE1_M*/ | 0x2 /*pp*/ )
6259 +
6260 +#define MREGS (kv->mregs)
6261 +#define MMU (kv->mmu)
6262 +
6263 +#ifdef CONFIG_SMP
6264 +#define SMP_PTE1_M PTE1_M
6265 +#else
6266 +#define SMP_PTE1_M 0
6267 +#endif
6268 +
6269 +
6270 +/************************************************************************/
6271 +/* Debugging */
6272 +/************************************************************************/
6273 +
6274 +static inline void
6275 +DEBUG_print_inserted_pte( ulong *slot, ulong pte0, ulong pte1, ulong ea )
6276 +{
6277 +#if 0
6278 + mPTE_t pte;
6279 + ulong *p = (ulong)&pte;
6280 + p[0] = pte0;
6281 + p[1] = pte1;
6282 +
6283 + printk("[%p] ", slot );
6284 + printk("RPN %08X API %08X EA %08lX ", pte.rpn << 12, pte.api<<12, ea );
6285 + printk("%c%c %c%c; PP %d\n",
6286 + pte.h ? 'H' : 'h',
6287 + pte.v ? 'V' : 'v',
6288 + pte.r ? 'R' : 'r',
6289 + pte.c ? 'C' : 'c', pte.pp );
6290 +#endif
6291 +}
6292 +
6293 +
6294 +/************************************************************************/
6295 +/* MMU virtualization and page fault handling */
6296 +/************************************************************************/
6297 +
6298 +#ifdef EMULATE_603
6299 +static inline int
6300 +lookup_603_pte( kernel_vars_t *kv, ulong vsid, ulong ea, int is_dsi, mPTE_t **ret_pte )
6301 +{
6302 + int ind = (ea >> 12) & 0x1f; /* 32x2 PTEs */
6303 + ulong mask, phash, cmp, pteg, cmp_ea, *eap;
6304 + mPTE_t *p;
6305 +
6306 + // printk("lookup_603_pte %08lX\n", ea);
6307 +
6308 + if( is_dsi ) {
6309 + p = &MMU.ptes_d_603[ind];
6310 + eap = &MMU.ptes_d_ea_603[ind];
6311 + } else {
6312 + p = &MMU.ptes_i_603[ind];
6313 + eap = &MMU.ptes_i_ea_603[ind];
6314 + }
6315 + cmp_ea = ea & 0x0ffff000;
6316 + for( ; ind < 64 ; ind += 32, p += 32, eap += 32 ) {
6317 + if( *eap == cmp_ea && p->vsid == vsid ) {
6318 + *ret_pte = p;
6319 + return 0;
6320 + }
6321 + }
6322 + mask = MMU.hash_mask >> 6;
6323 +
6324 + /* calculate primary and secondary PTEG */
6325 + phash = (cmp_ea >> 12) ^ (vsid & 0x7ffff);
6326 + pteg = ((phash & mask) << 6);
6327 + MREGS.spr[S_HASH1] = MMU.hash_mbase + pteg;
6328 + MREGS.spr[S_HASH2] = MMU.hash_mbase + (pteg ^ (mask << 6));
6329 +
6330 + /* construct compare word */
6331 + cmp = BIT(0) | (vsid <<7) | (cmp_ea >> 22);
6332 + if( is_dsi ) {
6333 + MREGS.spr[S_DCMP] = cmp;
6334 + MREGS.spr[S_DMISS] = ea;
6335 + } else {
6336 + MREGS.spr[S_ICMP] = cmp;
6337 + MREGS.spr[S_IMISS] = ea;
6338 + }
6339 + return 1;
6340 +}
6341 +#endif
6342 +
6343 +static inline mPTE_t *
6344 +lookup_mac_pte( kernel_vars_t *kv, ulong vsid, ulong ea )
6345 +{
6346 + ulong phash, cmp, pteg, *p;
6347 + ulong mask;
6348 + int i;
6349 +
6350 + /* make sure the hash is mapped... */
6351 + if( !MMU.hash_base )
6352 + return NULL;
6353 +
6354 + /* we are only interested in the page index */
6355 + ea &= 0x0ffff000;
6356 + mask = MMU.hash_mask>>6;
6357 +
6358 + /* calculate primary hash function */
6359 + phash = (ea >> 12) ^ (vsid & 0x7ffff);
6360 + pteg = ((phash & mask) << 6);
6361 +
6362 + /* construct compare word */
6363 + cmp = BIT(0) | (vsid <<7) | ((ea&0x0fffffff)>>22);
6364 +
6365 + /* look in primary PTEG */
6366 + p = (ulong*)((ulong)MMU.hash_base + pteg);
6367 + for( i=0; i<8; i++, p+=2 )
6368 + if( cmp == *p )
6369 + return (mPTE_t*)p;
6370 +
6371 + /* look in secondary PTEG */
6372 + p = (ulong*)( (ulong)MMU.hash_base + (pteg ^ (mask << 6)) );
6373 + cmp |= BIT(25);
6374 +
6375 + for( i=0; i<8; i++,p+=2 )
6376 + if( cmp == *p )
6377 + return (mPTE_t*)p;
6378 + return NULL;
6379 +}
6380 +
6381 +static int
6382 +lookup_mphys( kernel_vars_t *kv, fault_param_t *pb, const int ebits )
6383 +{
6384 + ulong ea = (pb->ea & ~0xfff);
6385 + mSEGREG segr;
6386 + mac_bat_t *bp;
6387 + int sv_mode, i, sbits;
6388 + mPTE_t *mpte;
6389 +
6390 + pb->mpte = NULL;
6391 +
6392 + if( !use_mmu(ebits) ) {
6393 + pb->mphys_page = ea;
6394 + pb->pte1 = NO_MMU_PTE1;
6395 + pb->key = 0;
6396 + return 0;
6397 + }
6398 +
6399 + segr = *(mSEGREG*)&MREGS.segr[ea>>28];
6400 + sv_mode = !(MREGS.msr & MSR_PR);
6401 +
6402 + /* I/O segment? */
6403 + if( segr.t ) {
6404 + /* Memory forced (601/604)? Note that the 601 uses I/O segments
6405 + * even if translation is off(!). We don't implement this though.
6406 + */
6407 + ulong sr = MREGS.segr[ea>>28];
6408 + BUMP( memory_forced_segment );
6409 +
6410 + if( ((sr >> 20) & 0x1ff) != 0x7f )
6411 + return RVEC_MMU_IO_SEG_ACCESS;
6412 + pb->mphys_page = (ea & 0x0ffff000) | ((sr & 0xf)<<28);
6413 + pb->pte1 = NO_MMU_PTE1;
6414 + pb->key = 0;
6415 + return 0;
6416 + }
6417 +
6418 + /* BAT translation? 0-3 = IBATs, 4-7 = DBATs. Separated I/D BATS, hace 3/8/99 */
6419 + bp = is_dsi(ebits) ? &MMU.bats[4] : &MMU.bats[0];
6420 + for( i=0; i<4; i++, bp++ ) {
6421 + if( !bp->valid )
6422 + continue;
6423 + if( (sv_mode && !bp->vs) || (!sv_mode && !bp->vp) )
6424 + continue;
6425 + if( ea < bp->base || ea > bp->base+bp->size-1 )
6426 + continue;
6427 +
6428 + pb->mphys_page = ea - bp->base + bp->mbase;
6429 + pb->pte1 = bp->pp | (bp->wimg << 3) | PTE1_R | PTE1_C;
6430 + pb->key = sv_mode ? bp->ks : bp->ku;
6431 + return 0;
6432 + }
6433 +
6434 +#ifdef EMULATE_603
6435 + if( (MREGS.spr[S_PVR] >> 16) == 3 ) {
6436 + if( lookup_603_pte(kv, segr.vsid, ea, is_dsi(ebits), &mpte) )
6437 + return is_dsi(ebits) ? (is_write(ebits) ? RVEC_DMISS_STORE_TRAP :
6438 + RVEC_DMISS_LOAD_TRAP) : RVEC_IMISS_TRAP;
6439 +
6440 + pb->mpte = NULL; /* imporant */
6441 + pb->mphys_page = (mpte->rpn << 12);
6442 + pb->pte1 = ((ulong*)mpte)[1] & (PTE1_PP | PTE1_WIMG | PTE1_R | PTE1_C);
6443 + pb->key = sv_mode ? segr.ks : segr.kp;
6444 + return 0;
6445 + }
6446 +#endif
6447 + /* mac page table lookup */
6448 + if( (mpte=lookup_mac_pte(kv, segr.vsid, ea)) ) {
6449 + pb->mpte = mpte;
6450 + pb->mphys_page = (mpte->rpn << 12);
6451 + pb->pte1 = ((ulong*)mpte)[1] & (PTE1_PP | PTE1_WIMG | PTE1_R | PTE1_C);
6452 + pb->key = sv_mode ? segr.ks : segr.kp;
6453 + return 0;
6454 + }
6455 + /* mac page fault */
6456 + sbits = EBIT_PAGE_FAULT | (ebits & EBIT_IS_WRITE); /* r/w bit + page_fault */
6457 + RVEC_RETURN_2( &MREGS, is_dsi(ebits) ? RVEC_DSI_TRAP : RVEC_ISI_TRAP, pb->ea, sbits );
6458 +}
6459 +
6460 +
6461 +/* PTE0 must be fully initialized on entry (with V=1 and H=0).
6462 + * The pte_present flag should be set from srr1/dsisr bit and indicates
6463 + * that a valid PTE might already be present in the hash table.
6464 + */
6465 +static inline ulong *
6466 +find_pte_slot( ulong ea, ulong *pte0, int pte_present, int *pte_replaced )
6467 +{
6468 + static int grab_add=0;
6469 + ulong phash, pteg, *p, cmp = *pte0;
6470 + ulong *primary, *secondary;
6471 + int i;
6472 +
6473 + /* we are only interested in the page index */
6474 + ea &= 0x0ffff000;
6475 +
6476 + /* primary hash function */
6477 + phash = (ea >> 12) ^ (PTE0_VSID(cmp) & 0x7ffff);
6478 +
6479 + pteg = (phash << 6) & ptehash.pteg_mask;
6480 + primary = (ulong*)((ulong)ptehash.base + pteg);
6481 +
6482 + pteg = pteg ^ ptehash.pteg_mask;
6483 + secondary = (ulong*)((ulong)ptehash.base + pteg);
6484 +
6485 + if( pte_present ) {
6486 + *pte_replaced = 1;
6487 +
6488 + /* look in primary PTEG */
6489 + p = primary;
6490 + for( i=0; i<8; i++, p+=2 )
6491 + if( cmp == *p )
6492 + return p;
6493 +
6494 + /* look in secondary PTEG */
6495 + p = secondary;
6496 + cmp |= BIT(25);
6497 + for( i=0; i<8; i++, p+=2 )
6498 + if( cmp == *p ) {
6499 + *pte0 |= PTE0_H;
6500 + return p;
6501 + }
6502 + /* we will actually come here if the previous PTE
6503 + * was only available in the on-chip cache.
6504 + */
6505 + }
6506 + *pte_replaced = 0;
6507 +
6508 + /* free slot in primary PTEG? */
6509 + for( p=primary, i=0; i<8; i++, p+=2 )
6510 + if( !(*p & BIT(0)) )
6511 + return p;
6512 +
6513 + /* free slot in secondary PTEG? */
6514 + for( p=secondary, i=0; i<8; i++, p+=2 )
6515 + if( !(*p & BIT(0)) ) {
6516 + *pte0 |= PTE0_H;
6517 + return p;
6518 + }
6519 +
6520 + /* steal a primary PTEG slot */
6521 + grab_add = (grab_add+1) & 0x7;
6522 +
6523 + /* printk("Grabbing slot %d, EA %08X\n",grab_add, ea ); */
6524 + return (ulong*)((ulong)primary + grab_add * sizeof(ulong[2]));
6525 +}
6526 +
6527 +static inline int
6528 +insert_pte( kernel_vars_t *kv, fault_param_t *pb, const int ebits )
6529 +{
6530 + ulong ea=pb->ea, mphys=pb->mphys_page;
6531 + ulong sr=pb->sr_base[ea>>28];
6532 + int status, pte_replaced;
6533 + pte_lvrange_t *lvrange;
6534 + ulong pte0, pte1, *slot;
6535 + ulong lvptr;
6536 +
6537 +#ifdef CONFIG_AMIGAONE
6538 + pte1 = PTE1_R | (pb->pte1 & (PTE1_R | PTE1_C | PTE1_WIMG))
6539 + | (is_write(ebits) ? 2:3);
6540 +#else
6541 + pte1 = PTE1_M | PTE1_R | (pb->pte1 & (PTE1_R | PTE1_C | PTE1_WIMG))
6542 + | (is_write(ebits) ? 2:3);
6543 +#endif
6544 +
6545 + /* PP and WIMG bits must set before the call to mphys_to_pte */
6546 + status = mphys_to_pte( kv, mphys, &pte1, is_write(ebits), &lvrange );
6547 +
6548 + if( !status || (is_write(ebits) && (status & MAPPING_RO)) ) {
6549 + ulong addr = (mphys | (ea & 0xfff));
6550 + if( is_dsi(ebits) ) {
6551 + int rvec = is_write(ebits) ? RVEC_IO_WRITE : RVEC_IO_READ;
6552 + BUMP( io_read_write );
6553 + RVEC_RETURN_2( &MREGS, rvec, addr, NULL );
6554 + } else {
6555 + RVEC_RETURN_1( &MREGS, RVEC_BAD_NIP, addr );
6556 + }
6557 + }
6558 +
6559 + /* tlbhash table hit? */
6560 + if( (ulong)(pb->mphys_page - MMU.hash_mbase) < (ulong)MMU.hash_mask ) {
6561 + /* printk("hash_table_hit at %08lX\n", pb->ea ); */
6562 + MMU.pthash_sr = sr;
6563 + MMU.pthash_ea_base = ea & ~MMU.hash_mask;
6564 +
6565 + /* user read (always), superuser r/w */
6566 + pte1 &= ~PTE1_PP;
6567 + pte1 |= is_write(ebits) ? 1:3;
6568 + /* write accesses of the page table are handled in ptintercept.S */
6569 + }
6570 +
6571 + pte0 = PTE0_V | (sr << 7) | ((ea>>22) & PTE0_API);
6572 + slot = find_pte_slot( ea, &pte0, !is_page_fault(ebits), &pte_replaced );
6573 +
6574 + lvptr = (status & MAPPING_PHYSICAL) ? 0 : (pte1 & PTE1_RPN);
6575 +
6576 + /* the RC bits should correspond to the is_write flag; this prevents the
6577 + * CPU from stamping RC bits unnecessary (besides, the kernel seems to
6578 + * assume no RC-stamps will ever occur so RC-stamping is unsafe).
6579 + */
6580 + if( is_write(ebits) )
6581 + pte1 |= PTE1_C;
6582 + pte1 |= SMP_PTE1_M;
6583 +
6584 + /* if a page-out occurs between prepare_pte_insert() and the pte_inserted()
6585 + * call, then the PTE slot is zeroed out.
6586 + */
6587 + if( !(status & MAPPING_PHYSICAL) ) {
6588 +#if 0
6589 + if( is_write(ebits) )
6590 + lvpage_dirty( kv, lvptr );
6591 +#endif
6592 + pte1 &= ~PTE1_RPN;
6593 +
6594 + /* zero pages should work just fine now... */
6595 + pte1 |= get_phys_page( kv, lvptr, is_write(ebits) );
6596 + /* pte1 |= get_phys_page( kv, lvptr, !(status & MAPPING_RO) ); */
6597 + }
6598 +
6599 + if( status & MAPPING_FB_ACCEL )
6600 + video_pte_inserted( kv, lvptr, slot, pte0, pte1, ea );
6601 +
6602 + BUMP( page_fault_ctr );
6603 + DEBUG_print_inserted_pte( slot, pte0, pte1, ea );
6604 +
6605 + __store_PTE( ea, slot, pte0, pte1 );
6606 +
6607 + pte_inserted( kv, ea, (char*)lvptr, lvrange, slot, pb->vsid_eptr[ea>>28], sr );
6608 +
6609 + /* debugger support */
6610 + if( (kv->break_flags & BREAK_EA_PAGE) && (ea & ~0xfff) == MREGS.mdbg_ea_break )
6611 + RVEC_RETURN_1( &MREGS, RVEC_BREAK, BREAK_EA_PAGE );
6612 +
6613 + return RVEC_NOP;
6614 +}
6615 +
6616 +static int
6617 +page_fault( kernel_vars_t *kv, fault_param_t *pb, const int ebits )
6618 +{
6619 + int topind = pb->ea >> 28;
6620 + int ind, ret;
6621 +
6622 + BUMP( access_exception_ctr );
6623 +
6624 + if( (ret=lookup_mphys(kv, pb, ebits)) ) {
6625 + BUMP(mac_page_fault);
6626 + return ret;
6627 + }
6628 +
6629 + /* printk("MPHYS_PAGE: %08lX, pp %d, key %d, wimg %d, mpte %p\n",
6630 + pb->mphys_page, (pb->pte1 & 3), pb->key, ((pb->pte1 >> 3) & 0xf), pb->mpte ); */
6631 +
6632 + /* check privileges */
6633 + ind = (is_write(ebits) ? 8:0) | (pb->pte1 & PTE1_PP) | (pb->key?4:0);
6634 + if( priv_viol_table[ind] ) {
6635 + /* r/w bit + priv. violation */
6636 + int sbits = EBIT_PROT_VIOL | (ebits & EBIT_IS_WRITE);
6637 + BUMP(mac_priv_violation);
6638 + RVEC_RETURN_2( &MREGS, is_dsi(ebits) ? RVEC_DSI_TRAP : RVEC_ISI_TRAP, pb->ea, sbits );
6639 + }
6640 +
6641 + /* stamp R/C bits (mpte is NULL if this is not a page translation). */
6642 + if( pb->mpte ) {
6643 + pb->mpte->r = 1;
6644 + if( is_write(ebits) )
6645 + pb->mpte->c = 1;
6646 +
6647 + /* stamp pthash_inuse_bit */
6648 + if( MMU.pthash_inuse_bits ) {
6649 + int nr = ((int)pb->mpte - (int)MMU.hash_base) >> 3;
6650 + set_bit_mol( nr, MMU.pthash_inuse_bits );
6651 + }
6652 + }
6653 +
6654 + /* perform memory allocations if necessary; we are not allowed to
6655 + * do this later (the mtable insertion must be atomic)
6656 + */
6657 + if( mtable_memory_check(kv) )
6658 + return RVEC_NOP; /* out of memory */
6659 +
6660 + /* the vsid entry might have been released */
6661 + if( !pb->vsid_eptr[topind] )
6662 + return RVEC_NOP;
6663 +
6664 + return insert_pte( kv, pb, ebits );
6665 +}
6666 +
6667 +
6668 +/************************************************************************/
6669 +/* VSID allocation (the normal VSID lookup occurs in vsid.S) */
6670 +/************************************************************************/
6671 +
6672 +static void
6673 +fix_sr( kernel_vars_t *kv, int sr, int mapped )
6674 +{
6675 + int macvsid = mapped ? (MREGS.segr[sr] & VSID_MASK) : VSID_MASK + 1 + sr;
6676 + ulong user_sr, sv_sr;
6677 + vsid_ent_t *r = vsid_get_user_sv( kv, macvsid, &user_sr, &sv_sr );
6678 +
6679 + BUMP(fix_sr);
6680 + if( !r )
6681 + return;
6682 +
6683 + if( mapped ) {
6684 + int value = MREGS.segr[sr];
6685 + int nbit = value & VSID_N;
6686 + MMU.vsid[sr] = r;
6687 + MMU.user_sr[sr] = ((value & VSID_Kp) ? user_sr : sv_sr) | nbit;
6688 + MMU.sv_sr[sr] = ((value & VSID_Ks) ? user_sr : sv_sr) | nbit;
6689 + } else {
6690 + MMU.unmapped_vsid[sr] = r;
6691 + MMU.unmapped_sr[sr] = user_sr;
6692 + }
6693 + invalidate_splitmode_sr( kv );
6694 +}
6695 +
6696 +
6697 +/************************************************************************/
6698 +/* Exception entrypoints (called from assembly) */
6699 +/************************************************************************/
6700 +
6701 +extern int dsi_exception( kernel_vars_t *kv, ulong dar, ulong dsisr );
6702 +extern int isi_exception( kernel_vars_t *kv, ulong nip, ulong srr1 );
6703 +
6704 +int
6705 +dsi_exception( kernel_vars_t *kv, ulong dar, ulong dsisr )
6706 +{
6707 + int ebits, topind = dar >> 28;
6708 + fault_param_t pb;
6709 +
6710 + /* printk("DSI: EA %08lX, DSISR %08lX\n", dar, dsisr ); */
6711 + if( dsisr & 0x84500000 ) /* 0,5,9,11 */
6712 + RVEC_RETURN_2( &MREGS, RVEC_UNUSUAL_DSISR_BITS, dar, dsisr );
6713 +
6714 + pb.ea = dar;
6715 + ebits = EBIT_IS_DSI | (dsisr & (EBIT_PAGE_FAULT | EBIT_PROT_VIOL | EBIT_IS_WRITE))
6716 + | ((MREGS.msr & MSR_DR) ? EBIT_USE_MMU : 0);
6717 +
6718 + pb.vsid_eptr = (MREGS.msr & MSR_DR) ? MMU.vsid : MMU.unmapped_vsid;
6719 + pb.sr_base = (ulong*)((ulong)MMU.sr_data - kv->kvars_tophys_offs);
6720 +
6721 + /* segment register switch-in required? */
6722 + if( !pb.vsid_eptr[topind] ) {
6723 + fix_sr( kv, topind, use_mmu(ebits) );
6724 + return RVEC_NOP;
6725 + }
6726 + BUMP(dsi);
6727 + return page_fault( kv, &pb, ebits );
6728 +}
6729 +
6730 +int
6731 +isi_exception( kernel_vars_t *kv, ulong nip, ulong srr1 )
6732 +{
6733 + fault_param_t pb;
6734 + /* printk("ISI: NIP %08lX, SRR1 %08lX\n", nip, srr1 ); */
6735 +
6736 + pb.vsid_eptr = (MREGS.msr & MSR_IR) ? MMU.vsid : MMU.unmapped_vsid;
6737 +
6738 + if( srr1 & EBIT_PAGE_FAULT ) {
6739 + int ebits = EBIT_PAGE_FAULT | ((MREGS.msr & MSR_IR) ? EBIT_USE_MMU : 0);
6740 + pb.ea = nip;
6741 + pb.sr_base = (ulong*)((ulong)MMU.sr_inst - kv->kvars_tophys_offs);
6742 + BUMP(isi_page_fault);
6743 + return page_fault( kv, &pb, ebits );
6744 + }
6745 + if( srr1 & EBIT_NO_EXEC ) {
6746 + int sr = nip >> 28;
6747 + if( !pb.vsid_eptr[sr] ) {
6748 + fix_sr( kv, sr, (MREGS.msr & MSR_IR) );
6749 + return RVEC_NOP;
6750 + }
6751 + /* printk("Guarded memory access at %08lX\n", nip ); */
6752 + RVEC_RETURN_2( &MREGS, RVEC_ISI_TRAP, nip, EBIT_NO_EXEC );
6753 + }
6754 +
6755 + BUMP(isi_prot_violation);
6756 + /* must be privileges violation */
6757 + RVEC_RETURN_2( &MREGS, RVEC_ISI_TRAP, nip, EBIT_PROT_VIOL );
6758 +}
6759 +
6760 +
6761 +/************************************************************************/
6762 +/* debugger functions */
6763 +/************************************************************************/
6764 +
6765 +int
6766 +dbg_translate_ea( kernel_vars_t *kv, int context, ulong va, int *ret_mphys, int data_access )
6767 +{
6768 + int ebits = data_access ? EBIT_IS_DSI : 0;
6769 + fault_param_t pb;
6770 +
6771 + memset( &pb, 0, sizeof(pb) );
6772 + pb.ea = va;
6773 +
6774 + switch( context ) {
6775 + case kContextUnmapped:
6776 + pb.sr_base = MMU.unmapped_sr;
6777 + break;
6778 + case kContextMapped_S:
6779 + pb.sr_base = MMU.sv_sr;
6780 + ebits |= EBIT_USE_MMU;
6781 + break;
6782 + case kContextMapped_U:
6783 + pb.sr_base = MMU.user_sr;
6784 + ebits |= EBIT_USE_MMU;
6785 + break;
6786 + default:
6787 + return 1;
6788 + }
6789 +
6790 + if( lookup_mphys(kv, &pb, ebits) )
6791 + return 1;
6792 + *ret_mphys = pb.mphys_page | (va & 0xfff);
6793 + return 0;
6794 +}
6795 diff --git a/drivers/macintosh/mol/hash.c b/drivers/macintosh/mol/hash.c
6796 new file mode 100644
6797 index 0000000..2d27384
6798 --- /dev/null
6799 +++ b/drivers/macintosh/mol/hash.c
6800 @@ -0,0 +1,126 @@
6801 +/*
6802 + * Creation Date: <2004/02/14 11:42:19 samuel>
6803 + * Time-stamp: <2004/03/13 14:25:00 samuel>
6804 + *
6805 + * <hash.c>
6806 + *
6807 + * CPU PTE hash handling
6808 + *
6809 + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
6810 + *
6811 + * This program is free software; you can redistribute it and/or
6812 + * modify it under the terms of the GNU General Public License
6813 + * as published by the Free Software Foundation
6814 + *
6815 + */
6816 +
6817 +#include "archinclude.h"
6818 +#include "alloc.h"
6819 +#include "kernel_vars.h"
6820 +#include "mmu.h"
6821 +#include "mmu_contexts.h"
6822 +#include "asmfuncs.h"
6823 +#include "emu.h"
6824 +#include "misc.h"
6825 +#include "mtable.h"
6826 +#include "performance.h"
6827 +#include "context.h"
6828 +#include "hash.h"
6829 +#include "map.h"
6830 +
6831 +/* GLOBALS */
6832 +hash_info_t ptehash;
6833 +
6834 +static struct {
6835 + int hash_mapped;
6836 + int sdr1_loaded;
6837 + char *allocation;
6838 +} hs;
6839 +
6840 +
6841 +static int
6842 +create_pte_hash( void )
6843 +{
6844 + ulong size = 1024*128; /* 128K is the kmalloc limit */
6845 + ulong sdr1, mask, base, physbase;
6846 + char *p;
6847 +
6848 + if( !(p=kmalloc_cont_mol(size)) )
6849 + return 1;
6850 + memset( p, 0, size );
6851 + base = (ulong)p;
6852 + physbase = tophys_mol( (char*)base );
6853 +
6854 + if( (physbase & (size-1)) ) {
6855 + int offs;
6856 + printk("Badly aligned SDR1 allocation - 64K wasted\n");
6857 + size /= 2;
6858 + offs = ((physbase + size) & ~(size-1)) - physbase;
6859 + physbase += offs;
6860 + base += offs;
6861 + }
6862 + mask = (size-1) >> 6;
6863 + sdr1 = mask >> 10;
6864 + sdr1 |= physbase;
6865 +
6866 + hs.allocation = p;
6867 + ptehash.sdr1 = sdr1;
6868 + ptehash.base = (ulong*)base;
6869 +
6870 + printk("SDR1 = %08lX\n", sdr1 );
6871 + return 0;
6872 +}
6873 +
6874 +int
6875 +init_hash( void )
6876 +{
6877 + ulong sdr1;
6878 +
6879 + memset( &ptehash, 0, sizeof(ptehash) );
6880 +
6881 + if( IS_LINUX ) {
6882 + sdr1 = _get_sdr1();
6883 +
6884 + /* linux does not use SDR1 on the 603[e] */
6885 + if( !sdr1 ) {
6886 + create_pte_hash();
6887 + sdr1 = ptehash.sdr1;
6888 + _set_sdr1( sdr1 );
6889 + hs.sdr1_loaded = 1;
6890 + }
6891 + } else {
6892 + /* sharing the hash under darwin is too complicated */
6893 + create_pte_hash();
6894 + sdr1 = ptehash.sdr1;
6895 + }
6896 +
6897 + if( !sdr1 )
6898 + return 1;
6899 +
6900 + ptehash.sdr1 = sdr1;
6901 + ptehash.pteg_mask = (((sdr1 & 0x1ff) << 10) | 0x3ff) << 6;
6902 + ptehash.pte_mask = ptehash.pteg_mask | 0x38;
6903 + ptehash.physbase = sdr1 & ~0xffff;
6904 +
6905 + if( !ptehash.base ) {
6906 + hs.hash_mapped = 1;
6907 + ptehash.base = map_hw_hash( ptehash.physbase, ptehash.pte_mask + 8 );
6908 + }
6909 +
6910 + return !ptehash.base;
6911 +}
6912 +
6913 +void
6914 +cleanup_hash( void )
6915 +{
6916 + if( hs.hash_mapped )
6917 + unmap_hw_hash( ptehash.base );
6918 +
6919 + if( hs.sdr1_loaded )
6920 + _set_sdr1( 0 );
6921 + if( hs.allocation )
6922 + kfree_cont_mol( hs.allocation );
6923 +
6924 + memset( &ptehash, 0, sizeof(ptehash) );
6925 + memset( &hs, 0, sizeof(hs) );
6926 +}
6927 diff --git a/drivers/macintosh/mol/include/actions.h b/drivers/macintosh/mol/include/actions.h
6928 new file mode 100644
6929 index 0000000..49ce65b
6930 --- /dev/null
6931 +++ b/drivers/macintosh/mol/include/actions.h
6932 @@ -0,0 +1,177 @@
6933