ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/name_registry.cpp
Revision: 1.21
Committed: 2009-08-18T18:26:10Z (14 years, 9 months ago) by asvitkine
Branch: MAIN
Changes since 1.20: +1 -1 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 * name_registry.cpp - Name Registry handling
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 #include <string.h>
22
23 #include "sysdeps.h"
24 #include "name_registry.h"
25 #include "main.h"
26 #include "macos_util.h"
27 #include "user_strings.h"
28 #include "emul_op.h"
29 #include "thunks.h"
30
31 #define DEBUG 0
32 #include "debug.h"
33
34
35 // Function pointers
36 typedef int16 (*rcec_ptr)(const RegEntryID *, const char *, RegEntryID *);
37 static uint32 rcec_tvect = 0;
38 static inline int16 RegistryCStrEntryCreate(uintptr arg1, const char *arg2, uint32 arg3)
39 {
40 SheepString arg2str(arg2);
41 return (int16)CallMacOS3(rcec_ptr, rcec_tvect, (const RegEntryID *)arg1, arg2str.addr(), arg3);
42 }
43 typedef int16 (*rpc_ptr)(const RegEntryID *, const char *, const void *, uint32);
44 static uint32 rpc_tvect = 0;
45 static inline int16 RegistryPropertyCreate(uintptr arg1, const char *arg2, uintptr arg3, uint32 arg4)
46 {
47 SheepString arg2str(arg2);
48 return (int16)CallMacOS4(rpc_ptr, rpc_tvect, (const RegEntryID *)arg1, arg2str.addr(), (const void *)arg3, arg4);
49 }
50 static inline int16 RegistryPropertyCreateStr(uintptr arg1, const char *arg2, const char *arg3)
51 {
52 SheepString arg3str(arg3);
53 return RegistryPropertyCreate(arg1, arg2, arg3str.addr(), strlen(arg3) + 1);
54 }
55
56 // Video driver stub
57 static const uint8 video_driver[] = {
58 #include "VideoDriverStub.i"
59 };
60
61 // Ethernet driver stub
62 static const uint8 ethernet_driver[] = {
63 #ifdef USE_ETHER_FULL_DRIVER
64 #include "EthernetDriverFull.i"
65 #else
66 #include "EthernetDriverStub.i"
67 #endif
68 };
69
70 // Helper for RegEntryID
71 typedef SheepArray<sizeof(RegEntryID)> SheepRegEntryID;
72
73 // Helper for a <uint32, uint32> pair
74 struct SheepPair : public SheepArray<8> {
75 SheepPair(uint32 base, uint32 size) : SheepArray<8>()
76 { WriteMacInt32(addr(), base); WriteMacInt32(addr() + 4, size); }
77 };
78
79
80 /*
81 * Patch Name Registry during startup
82 */
83
84 void DoPatchNameRegistry(void)
85 {
86 SheepVar32 u32;
87 D(bug("Patching Name Registry..."));
88
89 // Create "device-tree"
90 SheepRegEntryID device_tree;
91 if (!RegistryCStrEntryCreate(0, "Devices:device-tree", device_tree.addr())) {
92 u32.set_value(BusClockSpeed);
93 RegistryPropertyCreate(device_tree.addr(), "clock-frequency", u32.addr(), 4);
94 RegistryPropertyCreateStr(device_tree.addr(), "model", "Power Macintosh");
95
96 // Create "AAPL,ROM"
97 SheepRegEntryID aapl_rom;
98 if (!RegistryCStrEntryCreate(device_tree.addr(), "AAPL,ROM", aapl_rom.addr())) {
99 RegistryPropertyCreateStr(aapl_rom.addr(), "device_type", "rom");
100 SheepPair reg(ROMBase, ROM_SIZE);
101 RegistryPropertyCreate(aapl_rom.addr(), "reg", reg.addr(), 8);
102 }
103
104 // Create "PowerPC,60x"
105 SheepRegEntryID power_pc;
106 char *str;
107 switch (PVR >> 16) {
108 case 1: // 601
109 str = "PowerPC,601";
110 break;
111 case 3: // 603
112 str = "PowerPC,603";
113 break;
114 case 4: // 604
115 str = "PowerPC,604";
116 break;
117 case 6: // 603e
118 str = "PowerPC,603e";
119 break;
120 case 7: // 603ev
121 str = "PowerPC,603ev";
122 break;
123 case 8: // 750
124 str = "PowerPC,750";
125 break;
126 case 9: // 604e
127 str = "PowerPC,604e";
128 break;
129 case 10: // 604ev5
130 str = "PowerPC,604ev";
131 break;
132 case 50: // 821
133 str = "PowerPC,821";
134 break;
135 case 80: // 860
136 str = "PowerPC,860";
137 break;
138 case 12: // 7400, 7410, 7450, 7455, 7457
139 case 0x800c:
140 case 0x8000:
141 case 0x8001:
142 case 0x8002:
143 str = "PowerPC,G4";
144 break;
145 default:
146 str = "PowerPC,???";
147 break;
148 }
149 if (!RegistryCStrEntryCreate(device_tree.addr(), str, power_pc.addr())) {
150 u32.set_value(CPUClockSpeed);
151 RegistryPropertyCreate(power_pc.addr(), "clock-frequency", u32.addr(), 4);
152 u32.set_value(BusClockSpeed);
153 RegistryPropertyCreate(power_pc.addr(), "bus-frequency", u32.addr(), 4);
154 u32.set_value(TimebaseSpeed);
155 RegistryPropertyCreate(power_pc.addr(), "timebase-frequency", u32.addr(), 4);
156 u32.set_value(PVR);
157 RegistryPropertyCreate(power_pc.addr(), "cpu-version", u32.addr(), 4);
158 RegistryPropertyCreateStr(power_pc.addr(), "device_type", "cpu");
159 switch (PVR >> 16) {
160 case 1: // 601
161 u32.set_value(64);
162 RegistryPropertyCreate(power_pc.addr(), "d-cache-block-size", u32.addr(), 4);
163 u32.set_value(128);
164 RegistryPropertyCreate(power_pc.addr(), "d-cache-sets", u32.addr(), 4);
165 u32.set_value(0x8000);
166 RegistryPropertyCreate(power_pc.addr(), "d-cache-size", u32.addr(), 4);
167 u32.set_value(64);
168 RegistryPropertyCreate(power_pc.addr(), "i-cache-block-size", u32.addr(), 4);
169 u32.set_value(128);
170 RegistryPropertyCreate(power_pc.addr(), "i-cache-sets", u32.addr(), 4);
171 u32.set_value(0x8000);
172 RegistryPropertyCreate(power_pc.addr(), "i-cache-size", u32.addr(), 4);
173 u32.set_value(128);
174 RegistryPropertyCreate(power_pc.addr(), "tlb-sets", u32.addr(), 4);
175 u32.set_value(256);
176 RegistryPropertyCreate(power_pc.addr(), "tlb-size", u32.addr(), 4);
177 break;
178 case 3: // 603
179 u32.set_value(32);
180 RegistryPropertyCreate(power_pc.addr(), "d-cache-block-size", u32.addr(), 4);
181 u32.set_value(64);
182 RegistryPropertyCreate(power_pc.addr(), "d-cache-sets", u32.addr(), 4);
183 u32.set_value(0x2000);
184 RegistryPropertyCreate(power_pc.addr(), "d-cache-size", u32.addr(), 4);
185 u32.set_value(32);
186 RegistryPropertyCreate(power_pc.addr(), "i-cache-block-size", u32.addr(), 4);
187 u32.set_value(64);
188 RegistryPropertyCreate(power_pc.addr(), "i-cache-sets", u32.addr(), 4);
189 u32.set_value(0x2000);
190 RegistryPropertyCreate(power_pc.addr(), "i-cache-size", u32.addr(), 4);
191 u32.set_value(32);
192 RegistryPropertyCreate(power_pc.addr(), "tlb-sets", u32.addr(), 4);
193 u32.set_value(64);
194 RegistryPropertyCreate(power_pc.addr(), "tlb-size", u32.addr(), 4);
195 break;
196 case 4: // 604
197 u32.set_value(32);
198 RegistryPropertyCreate(power_pc.addr(), "d-cache-block-size", u32.addr(), 4);
199 u32.set_value(128);
200 RegistryPropertyCreate(power_pc.addr(), "d-cache-sets", u32.addr(), 4);
201 u32.set_value(0x4000);
202 RegistryPropertyCreate(power_pc.addr(), "d-cache-size", u32.addr(), 4);
203 u32.set_value(32);
204 RegistryPropertyCreate(power_pc.addr(), "i-cache-block-size", u32.addr(), 4);
205 u32.set_value(128);
206 RegistryPropertyCreate(power_pc.addr(), "i-cache-sets", u32.addr(), 4);
207 u32.set_value(0x4000);
208 RegistryPropertyCreate(power_pc.addr(), "i-cache-size", u32.addr(), 4);
209 u32.set_value(64);
210 RegistryPropertyCreate(power_pc.addr(), "tlb-sets", u32.addr(), 4);
211 u32.set_value(128);
212 RegistryPropertyCreate(power_pc.addr(), "tlb-size", u32.addr(), 4);
213 break;
214 case 6: // 603e
215 case 7: // 603ev
216 u32.set_value(32);
217 RegistryPropertyCreate(power_pc.addr(), "d-cache-block-size", u32.addr(), 4);
218 u32.set_value(128);
219 RegistryPropertyCreate(power_pc.addr(), "d-cache-sets", u32.addr(), 4);
220 u32.set_value(0x4000);
221 RegistryPropertyCreate(power_pc.addr(), "d-cache-size", u32.addr(), 4);
222 u32.set_value(32);
223 RegistryPropertyCreate(power_pc.addr(), "i-cache-block-size", u32.addr(), 4);
224 u32.set_value(128);
225 RegistryPropertyCreate(power_pc.addr(), "i-cache-sets", u32.addr(), 4);
226 u32.set_value(0x4000);
227 RegistryPropertyCreate(power_pc.addr(), "i-cache-size", u32.addr(), 4);
228 u32.set_value(32);
229 RegistryPropertyCreate(power_pc.addr(), "tlb-sets", u32.addr(), 4);
230 u32.set_value(64);
231 RegistryPropertyCreate(power_pc.addr(), "tlb-size", u32.addr(), 4);
232 break;
233 case 8: // 750, 750FX
234 case 0x7000:
235 u32.set_value(32);
236 RegistryPropertyCreate(power_pc.addr(), "d-cache-block-size", u32.addr(), 4);
237 u32.set_value(256);
238 RegistryPropertyCreate(power_pc.addr(), "d-cache-sets", u32.addr(), 4);
239 u32.set_value(0x8000);
240 RegistryPropertyCreate(power_pc.addr(), "d-cache-size", u32.addr(), 4);
241 u32.set_value(32);
242 RegistryPropertyCreate(power_pc.addr(), "i-cache-block-size", u32.addr(), 4);
243 u32.set_value(256);
244 RegistryPropertyCreate(power_pc.addr(), "i-cache-sets", u32.addr(), 4);
245 u32.set_value(0x8000);
246 RegistryPropertyCreate(power_pc.addr(), "i-cache-size", u32.addr(), 4);
247 u32.set_value(64);
248 RegistryPropertyCreate(power_pc.addr(), "tlb-sets", u32.addr(), 4);
249 u32.set_value(128);
250 RegistryPropertyCreate(power_pc.addr(), "tlb-size", u32.addr(), 4);
251 break;
252 case 9: // 604e
253 case 10: // 604ev5
254 u32.set_value(32);
255 RegistryPropertyCreate(power_pc.addr(), "d-cache-block-size", u32.addr(), 4);
256 u32.set_value(256);
257 RegistryPropertyCreate(power_pc.addr(), "d-cache-sets", u32.addr(), 4);
258 u32.set_value(0x8000);
259 RegistryPropertyCreate(power_pc.addr(), "d-cache-size", u32.addr(), 4);
260 u32.set_value(32);
261 RegistryPropertyCreate(power_pc.addr(), "i-cache-block-size", u32.addr(), 4);
262 u32.set_value(256);
263 RegistryPropertyCreate(power_pc.addr(), "i-cache-sets", u32.addr(), 4);
264 u32.set_value(0x8000);
265 RegistryPropertyCreate(power_pc.addr(), "i-cache-size", u32.addr(), 4);
266 u32.set_value(64);
267 RegistryPropertyCreate(power_pc.addr(), "tlb-sets", u32.addr(), 4);
268 u32.set_value(128);
269 RegistryPropertyCreate(power_pc.addr(), "tlb-size", u32.addr(), 4);
270 break;
271 case 12: // 7400, 7410, 7450, 7455, 7457
272 case 0x800c:
273 case 0x8000:
274 case 0x8001:
275 case 0x8002:
276 u32.set_value(32);
277 RegistryPropertyCreate(power_pc.addr(), "d-cache-block-size", u32.addr(), 4);
278 u32.set_value(128);
279 RegistryPropertyCreate(power_pc.addr(), "d-cache-sets", u32.addr(), 4);
280 u32.set_value(0x8000);
281 RegistryPropertyCreate(power_pc.addr(), "d-cache-size", u32.addr(), 4);
282 u32.set_value(32);
283 RegistryPropertyCreate(power_pc.addr(), "i-cache-block-size", u32.addr(), 4);
284 u32.set_value(128);
285 RegistryPropertyCreate(power_pc.addr(), "i-cache-sets", u32.addr(), 4);
286 u32.set_value(0x8000);
287 RegistryPropertyCreate(power_pc.addr(), "i-cache-size", u32.addr(), 4);
288 u32.set_value(64);
289 RegistryPropertyCreate(power_pc.addr(), "tlb-sets", u32.addr(), 4);
290 u32.set_value(128);
291 RegistryPropertyCreate(power_pc.addr(), "tlb-size", u32.addr(), 4);
292 break;
293 case 0x39: // 970
294 u32.set_value(128);
295 RegistryPropertyCreate(power_pc.addr(), "d-cache-block-size", u32.addr(), 4);
296 u32.set_value(128);
297 RegistryPropertyCreate(power_pc.addr(), "d-cache-sets", u32.addr(), 4);
298 u32.set_value(0x8000);
299 RegistryPropertyCreate(power_pc.addr(), "d-cache-size", u32.addr(), 4);
300 u32.set_value(128);
301 RegistryPropertyCreate(power_pc.addr(), "i-cache-block-size", u32.addr(), 4);
302 u32.set_value(512);
303 RegistryPropertyCreate(power_pc.addr(), "i-cache-sets", u32.addr(), 4);
304 u32.set_value(0x10000);
305 RegistryPropertyCreate(power_pc.addr(), "i-cache-size", u32.addr(), 4);
306 u32.set_value(256);
307 RegistryPropertyCreate(power_pc.addr(), "tlb-sets", u32.addr(), 4);
308 u32.set_value(0x1000);
309 RegistryPropertyCreate(power_pc.addr(), "tlb-size", u32.addr(), 4);
310 break;
311 default:
312 break;
313 }
314 u32.set_value(32);
315 RegistryPropertyCreate(power_pc.addr(), "reservation-granularity", u32.addr(), 4);
316 SheepPair reg(0, 0);
317 RegistryPropertyCreate(power_pc.addr(), "reg", reg.addr(), 8);
318 }
319
320 // Create "memory"
321 SheepRegEntryID memory;
322 if (!RegistryCStrEntryCreate(device_tree.addr(), "memory", memory.addr())) {
323 SheepPair reg(RAMBase, RAMSize);
324 RegistryPropertyCreateStr(memory.addr(), "device_type", "memory");
325 RegistryPropertyCreate(memory.addr(), "reg", reg.addr(), 8);
326 }
327
328 // Create "video"
329 SheepRegEntryID video;
330 if (!RegistryCStrEntryCreate(device_tree.addr(), "video", video.addr())) {
331 RegistryPropertyCreateStr(video.addr(), "AAPL,connector", "monitor");
332 RegistryPropertyCreateStr(video.addr(), "device_type", "display");
333 SheepArray<sizeof(video_driver)> the_video_driver;
334 Host2Mac_memcpy(the_video_driver.addr(), video_driver, sizeof(video_driver));
335 RegistryPropertyCreate(video.addr(), "driver,AAPL,MacOS,PowerPC", the_video_driver.addr(), sizeof(video_driver));
336 RegistryPropertyCreateStr(video.addr(), "model", "SheepShaver Video");
337 }
338
339 // Create "ethernet"
340 SheepRegEntryID ethernet;
341 if (!RegistryCStrEntryCreate(device_tree.addr(), "ethernet", ethernet.addr())) {
342 RegistryPropertyCreateStr(ethernet.addr(), "AAPL,connector", "ethernet");
343 RegistryPropertyCreateStr(ethernet.addr(), "device_type", "network");
344 SheepArray<sizeof(ethernet_driver)> the_ethernet_driver;
345 Host2Mac_memcpy(the_ethernet_driver.addr(), ethernet_driver, sizeof(ethernet_driver));
346 RegistryPropertyCreate(ethernet.addr(), "driver,AAPL,MacOS,PowerPC", the_ethernet_driver.addr(), sizeof(ethernet_driver));
347 // local-mac-address
348 // max-frame-size 2048
349 }
350 }
351 D(bug("done.\n"));
352 }
353
354 void PatchNameRegistry(void)
355 {
356 // Find RegistryCStrEntryCreate() and RegistryPropertyCreate() TVECTs
357 rcec_tvect = FindLibSymbol("\017NameRegistryLib", "\027RegistryCStrEntryCreate");
358 D(bug("RegistryCStrEntryCreate TVECT at %08x\n", rcec_tvect));
359 rpc_tvect = FindLibSymbol("\017NameRegistryLib", "\026RegistryPropertyCreate");
360 D(bug("RegistryPropertyCreate TVECT at %08x\n", rpc_tvect));
361 if (rcec_tvect == 0 || rpc_tvect == 0) {
362 ErrorAlert(GetString(STR_NO_NAME_REGISTRY_ERR));
363 QuitEmulator();
364 }
365
366 // Main routine must be executed in PPC mode
367 ExecuteNative(NATIVE_PATCH_NAME_REGISTRY);
368 }