CRUX PPC
A lightweight GNU/Linux distribution for PowerPC!
Subversion Repository
Parent Directory
|
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)
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 |