macemu/SheepShaver/src/Unix/ppc_asm.S
asvitkine b3b5db5456 [Michael Schmitt]
Attached is a patch to SheepShaver to fix memory allocation problems when OS X 10.5 is the host. It also relaxes the 512 MB RAM limit on OS X hosts.


Problem
-------
Some users have been unable to run SheepShaver on OS X 10.5 (Leopard) hosts. The symptom is error "ERROR: Cannot map RAM: File already exists".

SheepShaver allocates RAM at fixed addresses. If it is running in "Real" addressing mode, and can't allocate at address 0, then it was hard-coded to allocate the RAM area at 0x20000000. The ROM area as allocated at 0x40800000.

The normal configuration is for SheepShaver to run under SDL, which is a Cocoa wrapper. By the time SheepShaver does its memory allocations, the Cocoa application has already started. The result is the SheepShaver memory address space already contains libraries, fonts, Input Managers, and IOKit areas.

On Leopard hosts these areas can land on the same addresses SheepShaver needs, so SheepShaver's memory allocation fails.


Solution
--------
The approach is to change SheepShaver (on Unix & OS X hosts) to allocate the RAM area anywhere it can find the space, rather than at a fixed address.

This could result in the RAM allocated higher than the ROM area, which causes a crash. To prevent this from occurring, the RAM and ROM areas are allocated contiguously.

Previously the ROM starting address was a constant ROM_BASE, which was used throughout the source files. The ROM start address is now a variable ROMBase. ROMBase is allocated and set by main_*.cpp just like RAMBase.

A side-effect of this change is that it lifts the 512 MB RAM limit for OS X hosts. The limit was because the fixed RAM and ROM addresses were such that the RAM could only be 512 MB before it overlapped the ROM area.


Impact
------
The change to make ROMBase a variable is throughout all hosts & addressing modes.

The RAM and ROM areas will only shift when run on Unix & OS X hosts, otherwise the same fixed allocation address is used as before.

This change is limited to "Real" addressing mode. Unlike Basilisk II, SheepShaver *pre-calculates* the offset for "Direct" addressing mode; the offset is compiled into the program. If the RAM address were allowed to shift, it could result in the RAM area wrapping around address 0.


Changes to main_unix.cpp
------------------------
1. Real addressing mode no longer defines a RAM_BASE constant.

2. The base address of the Mac ROM (ROMBase) is defined and exported by this program.

3. Memory management helper vm_mac_acquire is renamed to vm_mac_acquire_fixed. Added a new memory management helper vm_mac_acquire, which allocates memory at any address.

4. Changed and rearranged the allocation of RAM and ROM areas.

Before it worked like this:

  - Allocate ROM area
  - If can, attempt to allocate RAM at address zero
  - If RAM not allocated at 0, allocate at fixed address

We still want to try allocating the RAM at zero, and if using DIRECT addressing we're still going to use the fixed addresses. So we don't know where the ROM should be until after we do the RAM. The new logic is:

  - If can, attempt to allocate RAM at address zero
  - If RAM not allocated at 0
      if REAL addressing
         allocate RAM and ROM together. The ROM address is aligned to a 1 MB boundary
      else (direct addressing)
         allocate RAM at fixed address
  - If ROM hasn't been allocated yet, allocate at fixed address

5. Calculate ROMBase and ROMBaseHost based on where the ROM was loaded.

6. There is a crash if the RAM is allocated too high. To try and catch this, check if it was allocated higher than the kernel data address.

7. Change subsequent code from using constant ROM_BASE to variable ROMBase.


Changes to Other Programs
-------------------------
emul_op.cpp, main.cpp, name_registery.cpp, rom_patches.cpp, rsrc_patches.cpp, emul_ppc.cpp, sheepshaver_glue.cpp, ppc-translate-cpp:
Change from constant ROM_BASE to variable ROMBase.

ppc_asm.S: It was setting register to a hard-coded literal address: 0x40b0d000. Changed to set it to ROMBase + 0x30d000.

ppc_asm.tmpl: It defined a macro ASM_LO16 but it assumed that the macro would always be used with operands that included a register specification. This is not true. Moved the register specification from the macro to the macro invocations.

main_beos.cpp, main_windows.cpp: Since the subprograms are all expecting a variable ROMBase, all the main_*.cpp pgrams have to define and export it. The ROM_BASE constant is moved here for consistency. The mains for beos and windows just allocate the ROM at the same fixed address as before, set ROMBaseHost and ROMBase to that address, and then use ROMBase for the subsequent code.

cpu_emulation.h: removed ROM_BASE constant. This value is moved to the main_*.cpp modules, to be consistent with RAM_BASE.

user_strings_unix.cpp, user_strings_unix.h: Added new error messages related to errors that occur when the RAM and ROM are allocated anywhere.
2009-08-18 18:26:11 +00:00

933 lines
18 KiB
ArmAsm

/*
* asm_linux.S - Assembly routines
*
* SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <ppc_asm.tmpl>
#include <xlowmem.h>
#define SAVE_FP_EXEC_68K 1
/*
* void *get_sp(void) - Get stack pointer
*/
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(get_sp)
C_SYMBOL_NAME(get_sp):
mr r3,r1
blr
/*
* void *get_r2(void) - Get r2
*/
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(get_r2)
C_SYMBOL_NAME(get_r2):
mr r3,r2
blr
/*
* void set_r2(void *val {r3}) - Set r2
*/
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(set_r2)
C_SYMBOL_NAME(set_r2):
mr r2,r3
blr
/*
* void *get_r13(void) - Get r13 (small data pointer under Linux)
*/
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(get_r13)
C_SYMBOL_NAME(get_r13):
mr r3,r13
blr
/*
* void set_r13(void *val {r3}) - Set r13 (small data pointer under Linux)
*/
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(set_r13)
C_SYMBOL_NAME(set_r13):
mr r13,r3
blr
/*
* void flush_icache_range(void *start {r3}, void *end {r3}) - Flush D and I cache
*/
CACHE_LINE_SIZE = 32
LG_CACHE_LINE_SIZE = 5
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(flush_icache_range)
C_SYMBOL_NAME(flush_icache_range):
li r5,CACHE_LINE_SIZE-1
andc r3,r3,r5
subf r4,r3,r4
add r4,r4,r5
srwi. r4,r4,LG_CACHE_LINE_SIZE
beqlr
mtctr r4
mr r6,r3
1: dcbst 0,r3
addi r3,r3,CACHE_LINE_SIZE
bdnz 1b
sync /* wait for dcbst's to get to ram */
mtctr r4
2: icbi 0,r6
addi r6,r6,CACHE_LINE_SIZE
bdnz 2b
sync
isync
blr
/*
* long atomic_add(long *var{r3}, long add{r4}) - Atomic add operation
* long atomic_and(long *var{r3}, long and{r4}) - Atomic and operation
* long atomic_or(long *var{r3}, long or{r4}) - Atomic or operation
* int test_and_set(int *var{r3}, int val{r4}) - Atomic test-and-set
*/
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(atomic_add)
C_SYMBOL_NAME(atomic_add):
0: dcbf 0,r3
sync
ori r0,r0,1
ori r0,r0,1
ori r0,r0,1
ori r0,r0,1
ori r0,r0,1
ori r0,r0,1
isync
lwarx r5,0,r3
add r0,r4,r5
stwcx. r0,0,r3
bne- 0b
mr r3,r5
isync
blr
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(atomic_and)
C_SYMBOL_NAME(atomic_and):
0: dcbf 0,r3
sync
ori r0,r0,1
ori r0,r0,1
ori r0,r0,1
ori r0,r0,1
ori r0,r0,1
ori r0,r0,1
isync
lwarx r5,0,r3
and r0,r4,r5
stwcx. r0,0,r3
bne- 0b
mr r3,r5
isync
blr
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(atomic_or)
C_SYMBOL_NAME(atomic_or):
0: dcbf 0,r3
sync
ori r0,r0,1
ori r0,r0,1
ori r0,r0,1
ori r0,r0,1
ori r0,r0,1
ori r0,r0,1
isync
lwarx r5,0,r3
or r0,r4,r5
stwcx. r0,0,r3
bne- 0b
mr r3,r5
isync
blr
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(test_and_set)
C_SYMBOL_NAME(test_and_set):
0: dcbf 0,r3
sync
ori r0,r0,1
ori r0,r0,1
ori r0,r0,1
ori r0,r0,1
ori r0,r0,1
ori r0,r0,1
isync
lwarx r5,0,r3
cmpi 0,r5,0x0000
bne 1f
stwcx. r4,0,r3
bne- 0b
1: isync
mr r3,r5
blr
/*
* void quit_emulator(void) - Jump to XLM_EMUL_RETURN_PROC
*/
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(quit_emulator)
C_SYMBOL_NAME(quit_emulator):
lwz r0,XLM_EMUL_RETURN_PROC(0)
mtlr r0
blr
/*
* void jump_to_rom(uint32 entry {r3}, uint32 emulator_data {r4}) - Jump to Mac ROM
*/
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(jump_to_rom)
C_SYMBOL_NAME(jump_to_rom):
// Create stack frame
mflr r0
stw r0,4(r1)
stwu r1,-(20+19*4+18*8)(r1) // maintain 16 byte alignment
// Save PowerPC registers
stmw r13,20(r1)
stfd f14,20+19*4+0*8(r1)
stfd f15,20+19*4+1*8(r1)
stfd f16,20+19*4+2*8(r1)
stfd f17,20+19*4+3*8(r1)
stfd f18,20+19*4+4*8(r1)
stfd f19,20+19*4+5*8(r1)
stfd f20,20+19*4+6*8(r1)
stfd f21,20+19*4+7*8(r1)
stfd f22,20+19*4+8*8(r1)
stfd f23,20+19*4+9*8(r1)
stfd f24,20+19*4+10*8(r1)
stfd f25,20+19*4+11*8(r1)
stfd f26,20+19*4+12*8(r1)
stfd f27,20+19*4+13*8(r1)
stfd f28,20+19*4+14*8(r1)
stfd f29,20+19*4+15*8(r1)
stfd f30,20+19*4+16*8(r1)
stfd f31,20+19*4+17*8(r1)
// Move entry address to ctr
mtctr r3
// Skip over EMUL_RETURN routine and get its address
bl 1f
/*
* EMUL_RETURN: Returned from emulator
*/
// Restore PowerPC registers
lwz r1,XLM_EMUL_RETURN_STACK(0)
RESTORE_SYSTEM_R2
lmw r13,20(r1)
lfd f14,20+19*4+0*8(r1)
lfd f15,20+19*4+1*8(r1)
lfd f16,20+19*4+2*8(r1)
lfd f17,20+19*4+3*8(r1)
lfd f18,20+19*4+4*8(r1)
lfd f19,20+19*4+5*8(r1)
lfd f20,20+19*4+6*8(r1)
lfd f21,20+19*4+7*8(r1)
lfd f22,20+19*4+8*8(r1)
lfd f23,20+19*4+9*8(r1)
lfd f24,20+19*4+10*8(r1)
lfd f25,20+19*4+11*8(r1)
lfd f26,20+19*4+12*8(r1)
lfd f27,20+19*4+13*8(r1)
lfd f28,20+19*4+14*8(r1)
lfd f29,20+19*4+15*8(r1)
lfd f30,20+19*4+16*8(r1)
lfd f31,20+19*4+17*8(r1)
// Exiting from 68k emulator
li r0,1
stw r0,XLM_IRQ_NEST(0)
li r0,MODE_NATIVE
stw r0,XLM_RUN_MODE(0)
// Return to caller of jump_to_rom()
lwz r0,20+19*4+18*8+4(r1)
mtlr r0
addi r1,r1,20+19*4+18*8
blr
// Save address of EMUL_RETURN routine for 68k emulator patch
1: mflr r0
stw r0,XLM_EMUL_RETURN_PROC(0)
// Skip over EXEC_RETURN routine and get its address
bl 2f
/*
* EXEC_RETURN: Returned from 68k routine executed with Execute68k()
*/
// Save r25 (contains current 68k interrupt level)
stw r25,XLM_68K_R25(0)
// Reentering EMUL_OP mode
li r0,MODE_EMUL_OP
stw r0,XLM_RUN_MODE(0)
// Save 68k registers
lwz r4,48(r1) // Pointer to M68kRegisters
stw r8,0*4(r4) // d[0]...d[7]
stw r9,1*4(r4)
stw r10,2*4(r4)
stw r11,3*4(r4)
stw r12,4*4(r4)
stw r13,5*4(r4)
stw r14,6*4(r4)
stw r15,7*4(r4)
stw r16,8*4(r4) // a[0]..a[6]
stw r17,9*4(r4)
stw r18,10*4(r4)
stw r19,11*4(r4)
stw r20,12*4(r4)
stw r21,13*4(r4)
stw r22,14*4(r4)
// Restore PowerPC registers
lmw r13,56(r1)
#if SAVE_FP_EXEC_68K
lfd f14,56+19*4+0*8(r1)
lfd f15,56+19*4+1*8(r1)
lfd f16,56+19*4+2*8(r1)
lfd f17,56+19*4+3*8(r1)
lfd f18,56+19*4+4*8(r1)
lfd f19,56+19*4+5*8(r1)
lfd f20,56+19*4+6*8(r1)
lfd f21,56+19*4+7*8(r1)
lfd f22,56+19*4+8*8(r1)
lfd f23,56+19*4+9*8(r1)
lfd f24,56+19*4+10*8(r1)
lfd f25,56+19*4+11*8(r1)
lfd f26,56+19*4+12*8(r1)
lfd f27,56+19*4+13*8(r1)
lfd f28,56+19*4+14*8(r1)
lfd f29,56+19*4+15*8(r1)
lfd f30,56+19*4+16*8(r1)
lfd f31,56+19*4+17*8(r1)
#endif
// Return to caller
lwz r0,52(r1)
mtcrf 0xff,r0
lwz r0,56+19*4+18*8+4(r1)
mtlr r0
addi r1,r1,56+19*4+18*8
RESTORE_SYSTEM_R2
RESTORE_SYSTEM_R13
blr
// Save address of EXEC_RETURN routine for 68k emulator patch
2: mflr r0
stw r0,XLM_EXEC_RETURN_PROC(0)
// Skip over EMUL_BREAK/EMUL_OP routine and get its address
bl 3f
/*
* EMUL_BREAK/EMUL_OP: Execute native routine, selector in r5 (my own private mode switch)
*
* 68k registers are stored in a M68kRegisters struct on the stack
* which the native routine may read and modify
*/
// Save r25 (contains current 68k interrupt level)
stw r25,XLM_68K_R25(0)
// Entering EMUL_OP mode within 68k emulator
li r0,MODE_EMUL_OP
stw r0,XLM_RUN_MODE(0)
// Create PowerPC stack frame, reserve space for M68kRegisters
mr r3,r1
subi r1,r1,64 // Fake "caller" frame
rlwinm r1,r1,0,0,27 // Align stack
mfcr r0
rlwinm r0,r0,0,11,8
stw r0,4(r1)
mfxer r0
stw r0,16(r1)
stw r2,12(r1)
stwu r1,-(56+16*4+15*8)(r1)
// Save 68k registers (M68kRegisters)
stw r8,56+0*4(r1) // d[0]..d[7]
stw r9,56+1*4(r1)
stw r10,56+2*4(r1)
stw r11,56+3*4(r1)
stw r12,56+4*4(r1)
stw r13,56+5*4(r1)
stw r14,56+6*4(r1)
stw r15,56+7*4(r1)
stw r16,56+8*4(r1) // a[0]..a[7]
stw r17,56+9*4(r1)
stw r18,56+10*4(r1)
stw r19,56+11*4(r1)
stw r20,56+12*4(r1)
stw r21,56+13*4(r1)
stw r22,56+14*4(r1)
stw r3,56+15*4(r1)
stfd f0,56+16*4+0*8(r1)
stfd f1,56+16*4+1*8(r1)
stfd f2,56+16*4+2*8(r1)
stfd f3,56+16*4+3*8(r1)
stfd f4,56+16*4+4*8(r1)
stfd f5,56+16*4+5*8(r1)
stfd f6,56+16*4+6*8(r1)
stfd f7,56+16*4+7*8(r1)
mffs f0
stfd f8,56+16*4+8*8(r1)
stfd f9,56+16*4+9*8(r1)
stfd f10,56+16*4+10*8(r1)
stfd f11,56+16*4+11*8(r1)
stfd f12,56+16*4+12*8(r1)
stfd f13,56+16*4+13*8(r1)
stfd f0,56+16*4+14*8(r1)
// Execute native routine
RESTORE_SYSTEM_R2
RESTORE_SYSTEM_R13
addi r3,r1,56
mr r4,r24
bl C_SYMBOL_NAME(EmulOp)
// Restore 68k registers (M68kRegisters)
lwz r8,56+0*4(r1) // d[0]..d[7]
lwz r9,56+1*4(r1)
lwz r10,56+2*4(r1)
lwz r11,56+3*4(r1)
lwz r12,56+4*4(r1)
lwz r13,56+5*4(r1)
lwz r14,56+6*4(r1)
lwz r15,56+7*4(r1)
lwz r16,56+8*4(r1) // a[0]..a[7]
lwz r17,56+9*4(r1)
lwz r18,56+10*4(r1)
lwz r19,56+11*4(r1)
lwz r20,56+12*4(r1)
lwz r21,56+13*4(r1)
lwz r22,56+14*4(r1)
lwz r3,56+15*4(r1)
lfd f13,56+16*4+14*8(r1)
lfd f0,56+16*4+0*8(r1)
lfd f1,56+16*4+1*8(r1)
lfd f2,56+16*4+2*8(r1)
lfd f3,56+16*4+3*8(r1)
lfd f4,56+16*4+4*8(r1)
lfd f5,56+16*4+5*8(r1)
lfd f6,56+16*4+6*8(r1)
lfd f7,56+16*4+7*8(r1)
mtfsf 0xff,f13
lfd f8,56+16*4+8*8(r1)
lfd f9,56+16*4+9*8(r1)
lfd f10,56+16*4+10*8(r1)
lfd f11,56+16*4+11*8(r1)
lfd f12,56+16*4+12*8(r1)
lfd f13,56+16*4+13*8(r1)
// Delete PowerPC stack frame
lwz r2,56+16*4+15*8+12(r1)
lwz r0,56+16*4+15*8+16(r1)
mtxer r0
lwz r0,56+16*4+15*8+4(r1)
mtcrf 0xff,r0
mr r1,r3
// Reentering 68k emulator
li r0,MODE_68K
stw r0,XLM_RUN_MODE(0)
// Set r0 to 0 for 68k emulator
li r0,0
// Execute next 68k opcode
rlwimi r29,r27,3,13,28
lhau r27,2(r24)
mtlr r29
blr
// Save address of EMUL_BREAK/EMUL_OP routine for 68k emulator patch
3: mflr r0
stw r0,XLM_EMUL_OP_PROC(0)
// Save stack pointer for EMUL_RETURN
stw r1,XLM_EMUL_RETURN_STACK(0)
// Preset registers for ROM boot routine
lis r3,ASM_HA16(C_SYMBOL_NAME(ROMBase)) // Pointer to ROM boot structure:
lwz r3,ASM_LO16(C_SYMBOL_NAME(ROMBase))(r3) // r3 = ROMBase + 0x30d000
addis r3,r3,ASM_HA16(0x30d000)
addi r3,r3,ASM_LO16(0x30d000)
// 68k emulator is now active
li r0,MODE_68K
stw r0,XLM_RUN_MODE(0)
// Jump to ROM
bctr
/*
* void execute_68k(uint32 pc {r3}, M68kRegisters *r {r4}) - Execute 68k routine
*/
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(execute_68k)
C_SYMBOL_NAME(execute_68k):
// Create MacOS stack frame
mflr r0
stw r0,4(r1)
stwu r1,-(56+19*4+18*8)(r1)
mfcr r0
stw r4,48(r1) // save pointer to M68kRegisters for EXEC_RETURN
stw r0,52(r1) // save CR
// Save PowerPC registers
stmw r13,56(r1)
#if SAVE_FP_EXEC_68K
stfd f14,56+19*4+0*8(r1)
stfd f15,56+19*4+1*8(r1)
stfd f16,56+19*4+2*8(r1)
stfd f17,56+19*4+3*8(r1)
stfd f18,56+19*4+4*8(r1)
stfd f19,56+19*4+5*8(r1)
stfd f20,56+19*4+6*8(r1)
stfd f21,56+19*4+7*8(r1)
stfd f22,56+19*4+8*8(r1)
stfd f23,56+19*4+9*8(r1)
stfd f24,56+19*4+10*8(r1)
stfd f25,56+19*4+11*8(r1)
stfd f26,56+19*4+12*8(r1)
stfd f27,56+19*4+13*8(r1)
stfd f28,56+19*4+14*8(r1)
stfd f29,56+19*4+15*8(r1)
stfd f30,56+19*4+16*8(r1)
stfd f31,56+19*4+17*8(r1)
#endif
// Set up registers for 68k emulator
lwz r31,XLM_KERNEL_DATA(0) // Pointer to Kernel Data
addi r31,r31,0x1000
li r0,0
mtcrf 0xff,r0
creqv 11,11,11 // Supervisor mode
lwz r8,0*4(r4) // d[0]..d[7]
lwz r9,1*4(r4)
lwz r10,2*4(r4)
lwz r11,3*4(r4)
lwz r12,4*4(r4)
lwz r13,5*4(r4)
lwz r14,6*4(r4)
lwz r15,7*4(r4)
lwz r16,8*4(r4) // a[0]..a[6]
lwz r17,9*4(r4)
lwz r18,10*4(r4)
lwz r19,11*4(r4)
lwz r20,12*4(r4)
lwz r21,13*4(r4)
lwz r22,14*4(r4)
li r23,0
mr r24,r3
lwz r25,XLM_68K_R25(0) // MSB of SR
li r26,0
li r28,0 // VBR
lwz r29,0x74(r31) // Pointer to opcode table
lwz r30,0x78(r31) // Address of emulator
// Push return address (points to EXEC_RETURN opcode) on stack
li r0,XLM_EXEC_RETURN_OPCODE
stwu r0,-4(r1)
// Reentering 68k emulator
li r0,MODE_68K
stw r0,XLM_RUN_MODE(0)
// Set r0 to 0 for 68k emulator
li r0,0
// Execute 68k opcode
lha r27,0(r24)
rlwimi r29,r27,3,13,28
lhau r27,2(r24)
mtlr r29
blr
/*
* uint32 call_macos1(uint32 tvect{r3}, uint32 arg1{r4}) ... - Call MacOS routines
*/
ASM_MACRO_START prolog
mflr r0
stw r0,4(r1)
stwu r1,-64(r1)
ASM_MACRO_END
ASM_MACRO_START epilog
lwz r0,64+4(r1)
mtlr r0
addi r1,r1,64
RESTORE_SYSTEM_R2
RESTORE_SYSTEM_R13
blr
ASM_MACRO_END
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(call_macos)
C_SYMBOL_NAME(call_macos):
prolog
lwz r0,0(r3) // Get routine address
lwz r2,4(r3) // Load TOC pointer
mtctr r0
bctrl
epilog
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(call_macos1)
C_SYMBOL_NAME(call_macos1):
prolog
lwz r0,0(r3) // Get routine address
lwz r2,4(r3) // Load TOC pointer
mtctr r0
mr r3,r4
bctrl
epilog
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(call_macos2)
C_SYMBOL_NAME(call_macos2):
prolog
lwz r0,0(r3) // Get routine address
lwz r2,4(r3) // Load TOC pointer
mtctr r0
mr r3,r4
mr r4,r5
bctrl
epilog
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(call_macos3)
C_SYMBOL_NAME(call_macos3):
prolog
lwz r0,0(r3) // Get routine address
lwz r2,4(r3) // Load TOC pointer
mtctr r0
mr r3,r4
mr r4,r5
mr r5,r6
bctrl
epilog
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(call_macos4)
C_SYMBOL_NAME(call_macos4):
prolog
lwz r0,0(r3) // Get routine address
lwz r2,4(r3) // Load TOC pointer
mtctr r0
mr r3,r4
mr r4,r5
mr r5,r6
mr r6,r7
bctrl
epilog
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(call_macos5)
C_SYMBOL_NAME(call_macos5):
prolog
lwz r0,0(r3) // Get routine address
lwz r2,4(r3) // Load TOC pointer
mtctr r0
mr r3,r4
mr r4,r5
mr r5,r6
mr r6,r7
mr r7,r8
bctrl
epilog
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(call_macos6)
C_SYMBOL_NAME(call_macos6):
prolog
lwz r0,0(r3) // Get routine address
lwz r2,4(r3) // Load TOC pointer
mtctr r0
mr r3,r4
mr r4,r5
mr r5,r6
mr r6,r7
mr r7,r8
mr r8,r9
bctrl
epilog
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(call_macos7)
C_SYMBOL_NAME(call_macos7):
prolog
lwz r0,0(r3) // Get routine address
lwz r2,4(r3) // Load TOC pointer
mtctr r0
mr r3,r4
mr r4,r5
mr r5,r6
mr r6,r7
mr r7,r8
mr r8,r9
mr r9,r10
bctrl
epilog
/*
* Native resource manager patches
*/
ASM_MACRO_START do_get_resource ASM_MACRO_ARG0_DEF
// Create stack frame
mflr r0
stw r0,8(r1)
stwu r1,-(56+12)(r1)
// Save type/ID
stw r3,56(r1)
stw r4,56+4(r1)
// Call old routine
lwz r0,ASM_MACRO_ARG0(0)
lwz r2,XLM_RES_LIB_TOC(0)
mtctr r0
bctrl
stw r3,56+8(r1) // Save handle
// Call CheckLoad
RESTORE_SYSTEM_R2
RESTORE_SYSTEM_R13
lwz r3,56(r1)
lha r4,56+6(r1)
lwz r5,56+8(r1)
bl C_SYMBOL_NAME(check_load_invoc)
lwz r3,56+8(r1) // Restore handle
// Return to caller
lwz r0,56+12+8(r1)
mtlr r0
addi r1,r1,56+12
blr
ASM_MACRO_END
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(get_resource)
C_SYMBOL_NAME(get_resource):
do_get_resource XLM_GET_RESOURCE
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(get_1_resource)
C_SYMBOL_NAME(get_1_resource):
do_get_resource XLM_GET_1_RESOURCE
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(get_ind_resource)
C_SYMBOL_NAME(get_ind_resource):
do_get_resource XLM_GET_IND_RESOURCE
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(get_1_ind_resource)
C_SYMBOL_NAME(get_1_ind_resource):
do_get_resource XLM_GET_1_IND_RESOURCE
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(r_get_resource)
C_SYMBOL_NAME(r_get_resource):
do_get_resource XLM_R_GET_RESOURCE
ASM_MACRO_START do_get_named_resource ASM_MACRO_ARG0_DEF
// Create stack frame
mflr r0
stw r0,8(r1)
stwu r1,-(56+12)(r1)
// Save type/ID
stw r3,56(r1)
stw r4,56+4(r1)
// Call old routine
lwz r0,ASM_MACRO_ARG0(0)
lwz r2,XLM_RES_LIB_TOC(0)
mtctr r0
bctrl
stw r3,56+8(r1) // Save handle
// Call CheckLoad
RESTORE_SYSTEM_R2
RESTORE_SYSTEM_R13
lwz r3,56(r1)
lwz r4,56+4(r1)
lwz r5,56+8(r1)
bl C_SYMBOL_NAME(named_check_load_invoc)
lwz r3,56+8(r1) // Restore handle
// Return to caller
lwz r0,56+12+8(r1)
mtlr r0
addi r1,r1,56+12
blr
ASM_MACRO_END
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(get_named_resource)
C_SYMBOL_NAME(get_named_resource):
do_get_named_resource XLM_GET_NAMED_RESOURCE
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(get_1_named_resource)
C_SYMBOL_NAME(get_1_named_resource):
do_get_named_resource XLM_GET_1_NAMED_RESOURCE
/*
* void ppc_interrupt(uint32 entry{r3}, uint32 kernel_data{r4}) - Execute PPC interrupt
*/
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(ppc_interrupt)
C_SYMBOL_NAME(ppc_interrupt):
mflr r0
stw r0,4(r1)
stwu r1,-64(r1)
// Get address of return routine
bl 1f
// Return routine
lwz r0,64+4(r1)
mtlr r0
addi r1,r1,64
blr
// Prepare registers for nanokernel interrupt routine
1: mtctr r1
mr r1,r4
stw r6,0x018(r1)
mfctr r6
stw r6,0x004(r1)
lwz r6,0x65c(r1)
stw r7,0x13c(r6)
stw r8,0x144(r6)
stw r9,0x14c(r6)
stw r10,0x154(r6)
stw r11,0x15c(r6)
stw r12,0x164(r6)
stw r13,0x16c(r6)
mflr r10
mfcr r13
lwz r7,0x660(r1)
mflr r12
rlwimi. r7,r7,8,0,0
li r11,0
ori r11,r11,0xf072 // MSR (SRR1)
mtcrf 0x70,r11
li r8,0
// Enter nanokernel
mtlr r3
blr
/*
* Define signal handlers with alternate stack initialization magic
*/
#define SIG_STACK_SIZE 0x10000
ASM_MACRO_START do_define_signal_handler \
ASM_MACRO_ARG0_DEF /* name */ \
ASM_MACRO_ARG1_DEF /* stack */ \
ASM_MACRO_ARG2_DEF /* stack id */ \
ASM_MACRO_ARG3_DEF /* signal handler */
// Alternate stack lower base for this signal handler
.lcomm ASM_MACRO_ARG1,SIG_STACK_SIZE,ASM_ALIGN_2(4)
ASM_TYPE(ASM_MACRO_ARG1,@object)
// Represents the current nest level for this signal handler
// Note that in SheepShaver, SIGUSR2 signals are blocked while
// handling other signals so, it's unlikely we ever get a nest
// level greater than 1
.lcomm ASM_MACRO_ARG2,4,ASM_ALIGN_2(2)
ASM_TYPE(ASM_MACRO_ARG2,@object)
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(ASM_MACRO_ARG0)
C_SYMBOL_NAME(ASM_MACRO_ARG0):
// Preserve args in scratch registers
mflr r14
mr r15,r3
mr r16,r4
mr r17,r5
mr r18,r1
// Atomically increase stack_id
lis r19,ASM_HA16(ASM_MACRO_ARG2)
la r19,ASM_LO16(ASM_MACRO_ARG2)(r19)
li r4,1
mr r3,r19
bl C_SYMBOL_NAME(atomic_add)
cmpwi r3,0
bne- 1f
// ID was 0, we can use the local stack
lis r9,ASM_HA16(ASM_MACRO_ARG1)
lis r3,(SIG_STACK_SIZE>>16)
la r9,ASM_LO16(ASM_MACRO_ARG1)(r9)
addi r3,r3,((SIG_STACK_SIZE&0xffff)-64)
add r1,r9,r3
1: // Invoke signal handler
stwu r1,-16(r1)
mr r3,r15
mr r4,r16
mr r5,r17
bl C_SYMBOL_NAME(ASM_MACRO_ARG3)
addi r1,r1,16
// Atomically decrease stack id
mr r3,r19
li r4,-1
bl C_SYMBOL_NAME(atomic_add)
// Restore kernel stack and return
mtlr r14
mr r1,r18
blr
ASM_MACRO_END
#define DEFINE_SIGNAL_HANDLER(NAME) \
do_define_signal_handler \
NAME##_handler_init ASM_MACRO_ARG_SEP \
NAME##_stack ASM_MACRO_ARG_SEP \
NAME##_stack_id ASM_MACRO_ARG_SEP \
NAME##_handler
DEFINE_SIGNAL_HANDLER(sigusr2)