ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/include/cpu_emulation.h
Revision: 1.17
Committed: 2009-08-18T18:26:11Z (15 years, 2 months ago) by asvitkine
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.16: +2 -2 lines
Log Message:
[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.

File Contents

# Content
1 /*
2 * cpu_emulation.h - Definitions for CPU emulation and Mac memory access
3 *
4 * SheepShaver (C) 1997-2008 Christian Bauer and Marc Hellwig
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #ifndef CPU_EMULATION_H
22 #define CPU_EMULATION_H
23
24
25 /*
26 * Memory system
27 */
28
29 // Constants
30 const uint32 ROM_SIZE = 0x400000; // Size of ROM file
31 const uint32 ROM_AREA_SIZE = 0x500000; // Size of ROM area
32 const uintptr DR_EMULATOR_BASE = 0x68070000; // Address of DR emulator code
33 const uint32 DR_EMULATOR_SIZE = 0x10000; // Size of DR emulator code
34 const uintptr DR_CACHE_BASE = 0x69000000; // Address of DR cache
35 const uint32 DR_CACHE_SIZE = 0x80000; // Size of DR Cache
36
37 const uintptr KERNEL_DATA_BASE = 0x68ffe000; // Address of Kernel Data
38 const uintptr KERNEL_DATA2_BASE = 0x5fffe000; // Alternate address of Kernel Data
39 const uint32 KERNEL_AREA_SIZE = 0x2000; // Size of Kernel Data area
40
41 // MacOS 68k Emulator Data
42 struct EmulatorData {
43 uint32 v[0x400];
44 };
45
46 // MacOS Kernel Data
47 struct KernelData {
48 uint32 v[0x400];
49 EmulatorData ed;
50 };
51
52 // RAM and ROM pointers (allocated and set by main_*.cpp)
53 extern uint32 RAMBase; // Base address of Mac RAM
54 extern uint32 RAMSize; // Size address of Mac RAM
55 extern uint8 *RAMBaseHost; // Base address of Mac RAM (host address space)
56
57 extern uint32 ROMBase; // Base address of Mac ROM
58 extern uint8 *ROMBaseHost; // Base address of Mac ROM (host address space)
59
60 // Mac memory access functions
61 #if EMULATED_PPC
62 #include "cpu/vm.hpp"
63 static inline uint32 ReadMacInt8(uint32 addr) {return vm_read_memory_1(addr);}
64 static inline void WriteMacInt8(uint32 addr, uint32 v) {vm_write_memory_1(addr, v);}
65 static inline uint32 ReadMacInt16(uint32 addr) {return vm_read_memory_2(addr);}
66 static inline void WriteMacInt16(uint32 addr, uint32 v) {vm_write_memory_2(addr, v);}
67 static inline uint32 ReadMacInt32(uint32 addr) {return vm_read_memory_4(addr);}
68 static inline void WriteMacInt32(uint32 addr, uint32 v) {vm_write_memory_4(addr, v);}
69 static inline uint64 ReadMacInt64(uint32 addr) {return vm_read_memory_8(addr);}
70 static inline void WriteMacInt64(uint32 addr, uint64 v) {vm_write_memory_8(addr, v);}
71 static inline uint32 Host2MacAddr(uint8 *addr) {return vm_do_get_virtual_address(addr);}
72 static inline uint8 *Mac2HostAddr(uint32 addr) {return vm_do_get_real_address(addr);}
73 static inline void *Mac_memset(uint32 addr, int c, size_t n) {return vm_memset(addr, c, n);}
74 static inline void *Mac2Host_memcpy(void *dest, uint32 src, size_t n) {return vm_memcpy(dest, src, n);}
75 static inline void *Host2Mac_memcpy(uint32 dest, const void *src, size_t n) {return vm_memcpy(dest, src, n);}
76 static inline void *Mac2Mac_memcpy(uint32 dest, uint32 src, size_t n) {return vm_memcpy(dest, src, n);}
77 #else
78 static inline uint32 ReadMacInt8(uint32 addr) {return *(uint8 *)addr;}
79 static inline void WriteMacInt8(uint32 addr, uint32 b) {*(uint8 *)addr = b;}
80 static inline uint32 ReadMacInt16(uint32 addr) {return *(uint16 *)addr;}
81 static inline uint32 ReadMacInt32(uint32 addr) {return *(uint32 *)addr;}
82 static inline uint64 ReadMacInt64(uint32 addr) {return *(uint64 *)addr;}
83 static inline void WriteMacInt16(uint32 addr, uint32 w) {*(uint16 *)addr = w;}
84 static inline void WriteMacInt32(uint32 addr, uint32 l) {*(uint32 *)addr = l;}
85 static inline void WriteMacInt64(uint32 addr, uint64 ll) {*(uint64 *)addr = ll;}
86 static inline uint32 Host2MacAddr(uint8 *addr) {return (uint32)addr;}
87 static inline uint8 *Mac2HostAddr(uint32 addr) {return (uint8 *)addr;}
88 static inline void *Mac_memset(uint32 addr, int c, size_t n) {return memset(Mac2HostAddr(addr), c, n);}
89 static inline void *Mac2Host_memcpy(void *dest, uint32 src, size_t n) {return memcpy(dest, Mac2HostAddr(src), n);}
90 static inline void *Host2Mac_memcpy(uint32 dest, const void *src, size_t n) {return memcpy(Mac2HostAddr(dest), src, n);}
91 static inline void *Mac2Mac_memcpy(uint32 dest, uint32 src, size_t n) {return memcpy(Mac2HostAddr(dest), Mac2HostAddr(src), n);}
92 #endif
93
94
95 /*
96 * 680x0 and PPC emulation
97 */
98
99 // 68k procedure helper to write a big endian 16-bit word
100 #ifdef WORDS_BIGENDIAN
101 #define PW(W) W
102 #else
103 #define PW(X) ((((X) >> 8) & 0xff) | (((X) & 0xff) << 8))
104 #endif
105
106 // PowerPC procedure helper to write a big-endian 32-bit word
107 #ifdef WORDS_BIGENDIAN
108 #define PL(X) X
109 #else
110 #define PL(X) \
111 ((((X) & 0xff000000) >> 24) | (((X) & 0x00ff0000) >> 8) | \
112 (((X) & 0x0000ff00) << 8) | (((X) & 0x000000ff) << 24))
113 #endif
114
115 struct M68kRegisters;
116 extern void Execute68k(uint32, M68kRegisters *r); // Execute 68k subroutine from EMUL_OP routine, must be ended with RTS
117 extern void Execute68kTrap(uint16 trap, M68kRegisters *r); // Execute 68k A-Trap from EMUL_OP routine
118 #if EMULATED_PPC
119 extern void FlushCodeCache(uintptr start, uintptr end); // Invalidate emulator caches
120 #endif
121 extern void ExecuteNative(int selector); // Execute native code from EMUL_OP routine (real mode switch)
122
123 #endif