Waternoose, the XBOX 360 emulator
A very young XBOX 360 emulator that aims to boot games some day
Loading...
Searching...
No Matches
memory.cpp
1#include <memory/memory.h>
2#include <util.h>
3#include <stddef.h>
4#include <sys/mman.h>
5#include <stdio.h>
6#include <errno.h>
7#include <string.h>
8#include <stdlib.h>
9#include <fstream>
10#include <bitset>
11#include <loader/xex.h>
12#include <cpu/CPU.h>
13#include <tmmintrin.h>
14#include "memory.h"
15
16extern uint32_t mainThreadStackSize;
17
18std::vector<AllocInfo> allocInfo;
19
20uint8_t** readPages, **writePages;
21#define PAGE_SIZE (4*1024)
22#define MAX_ADDRESS_SPACE 0xFFFF0000
23std::bitset<MAX_ADDRESS_SPACE / PAGE_SIZE> usedPages;
24
25void Memory::Initialize()
26{
27 readPages = new uint8_t*[MAX_ADDRESS_SPACE / PAGE_SIZE];
28 writePages = new uint8_t*[MAX_ADDRESS_SPACE / PAGE_SIZE];
29 usedPages.reset();
30
31 for (size_t i = 0; i < 64*1024; i += 4096)
32 usedPages[i / 4096] = true;
33}
34
35void Memory::Dump()
36{
37 std::ofstream file("mem.dump");
38 for (uint32_t i = mainXexBase; i < mainXexBase+mainXexSize; i += 4)
39 {
40 uint32_t data = bswap32(Read32(i));
41 file.write((char*)&data, 4);
42 }
43 file.close();
44
45 file.open("stack.dump");
46 for (uint32_t i = 0x70000000; i < 0x70000000+mainThreadStackSize; i += 4)
47 {
48 uint32_t data = bswap32(Read32(i));
49 file.write((char*)&data, 4);
50 }
51 file.close();
52}
53
54void *Memory::AllocMemory(uint32_t baseAddress, uint32_t size)
55{
56 void* ret = mmap((void*)baseAddress, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
57
58 if (ret == MAP_FAILED)
59 {
60 printf("Failed to allocate memory: %s\n", strerror(errno));
61 exit(1);
62 }
63
64 size = (size + PAGE_SIZE) & ~PAGE_SIZE;
65
66 for (int i = 0; i < size; i += PAGE_SIZE)
67 {
68 readPages[(baseAddress + i) / PAGE_SIZE] = ((uint8_t*)ret+i);
69 writePages[(baseAddress + i) / PAGE_SIZE] = ((uint8_t*)ret+i);
70 }
71
72 return ret;
73}
74
75uint32_t Memory::VirtAllocMemoryRange(uint32_t beginAddr, uint32_t endAddr, uint32_t size)
76{
77 uint32_t requiredPages = size / PAGE_SIZE;
78
79 // Find the lowest free range that fits the size
80 uint32_t candidate = 0;
81 uint32_t freePages = 0;
82 for (uint32_t i = beginAddr; i < endAddr; i += PAGE_SIZE)
83 {
84 if (!candidate && !usedPages[i / PAGE_SIZE])
85 {
86 candidate = i / PAGE_SIZE;
87 freePages = 1;
88 }
89 else if (!usedPages[i / PAGE_SIZE])
90 {
91 freePages++;
92 if (freePages == requiredPages)
93 break;
94 }
95 else
96 {
97 candidate = 0;
98 }
99 }
100
101 if (candidate == 0)
102 {
103 printf("ERROR: Failed to allocate virtual memory in range [0x%08x -> 0x%08x]\n", beginAddr, endAddr);
104 exit(1);
105 }
106
107 // Mark the pages as used
108 for (int i = 0; i < requiredPages; i++)
109 usedPages.set(candidate+i, true);
110
111 AllocInfo info;
112 info.baseAddress = candidate*PAGE_SIZE;
113 info.regionSize = requiredPages*PAGE_SIZE;
114 allocInfo.push_back(info);
115
116 return candidate*PAGE_SIZE;
117}
118
119uint8_t *Memory::GetRawPtrForAddr(uint32_t addr)
120{
121 if (!readPages[addr / PAGE_SIZE])
122 {
123 printf("Read raw ptr from unmapped addr 0x%08x\n", addr);
124 exit(1);
125 }
126
127 return &readPages[addr / PAGE_SIZE][addr % PAGE_SIZE];
128}
129
130bool Memory::GetAllocInfo(uint32_t addr, AllocInfo& outInfo)
131{
132 for (auto& info : allocInfo)
133 {
134 if (info.baseAddress <= addr && info.baseAddress+info.regionSize > addr)
135 {
136 outInfo = info;
137 return true;
138 }
139 }
140
141 printf("Failed to get allocation info for region 0x%08x\n", addr);
142 return false;
143}
144
145uint8_t Memory::Read8(uint32_t addr, bool slow)
146{
147 if (!slow)
148 {
149 if (!readPages[addr / PAGE_SIZE])
150 {
151 return Read8(addr, true);
152 }
153
154 return readPages[addr / PAGE_SIZE][addr % PAGE_SIZE];
155 }
156 else
157 {
158 switch (addr)
159 {
160 case 0x15A:
161 return 0x06;
162 default:
163 printf("Read8 from unmapped addr 0x%08x\n", addr);
164 exit(1);
165 }
166 }
167}
168
169uint16_t Memory::Read16(uint32_t addr, bool slow)
170{
171 if (!slow)
172 {
173 if (!readPages[addr / PAGE_SIZE])
174 {
175 return Read16(addr, true);
176 }
177
178 return bswap16(*(uint16_t*)&readPages[addr / PAGE_SIZE][addr % PAGE_SIZE]);
179 }
180 else
181 {
182 switch (addr)
183 {
184 case 0x10158:
185 return bswap16(0x2); // Some kind of console type (maybe debug vs retail?). xbdm.xex relies on this while booting
186 case 0x1015A:
187 return 0; // More xbdm.xex nonsense
188 case 0x1015C:
189 return bswap16(0x4f80); // According to assert messages inside xbdm, this is the console's firmware revision
190 case 0x1015E:
191 return 0; // Setting this to 0x8000 will cause a bunch of extra stuff to happen inside xbdm
192 case 0x10164:
193 // If bit 9 is set, then xbdm will enforce in-order execution of I/O (EIEIO)
194 return 0;
195 case 0x8e03860a: // Some kind of weird page mapped by the OS
196 return 0;
197 default:
198 printf("Read16 from unmapped address 0x%08x\n", addr);
199 exit(1);
200 }
201 }
202}
203
204uint32_t Memory::Read32(uint32_t addr, bool slow)
205{
206 if (!slow)
207 {
208 if (!readPages[addr / PAGE_SIZE])
209 {
210 return Read32(addr, true);
211 }
212
213 return bswap32(*(uint32_t*)&readPages[addr / PAGE_SIZE][addr % PAGE_SIZE]);
214 }
215 else
216 {
217 static int system_ticks = 0;
218 switch (addr)
219 {
220 case 0x59:
221 return 0;
222 case 0xbd:
223 return bswap32(system_ticks++);
224 case 0x156:
225 return bswap32(0x20);
226 case 0x10156:
227 return bswap32(0x2000000); // Setting this to 0x2000000 causes some kind of memory address to be set to 1
228 default:
229 printf("Read32 from unmapped address 0x%08x\n", addr);
230 exit(1);
231 }
232 }
233}
234
235uint64_t Memory::Read64(uint32_t addr)
236{
237 if (!readPages[addr / PAGE_SIZE])
238 {
239 printf("Read64 from unmapped addr 0x%08x\n", addr);
240 exit(1);
241 }
242
243 return bswap64(*(uint64_t*)&readPages[addr / PAGE_SIZE][addr % PAGE_SIZE]);
244}
245
246unsigned __int128 swap(unsigned __int128 n)
247{
248 unsigned __int128 m;
249 const uint64_t* src = (const uint64_t*)(&n);
250 uint64_t* dest = (uint64_t*)(&m);
251 dest[1] = bswap64(src[0]);
252 dest[0] = bswap64(src[1]);
253 return m;
254}
255
256__uint128_t Memory::Read128(uint32_t addr)
257{
258 if (!readPages[addr / PAGE_SIZE])
259 {
260 printf("Read128 from unmapped addr 0x%08x\n", addr);
261 exit(1);
262 }
263
264 __uint128_t t = *(__uint128_t*)&readPages[addr / PAGE_SIZE][addr % PAGE_SIZE];
265 return swap(t);
266}
267
268void Memory::Write8(uint32_t addr, uint8_t data)
269{
270 if (!writePages[addr / PAGE_SIZE])
271 {
272 printf("Write8 to unmapped addr 0x%08x\n", addr);
273 exit(1);
274 }
275
276 writePages[addr / PAGE_SIZE][addr % PAGE_SIZE] = data;
277}
278
279void Memory::Write16(uint32_t addr, uint16_t data)
280{
281 if (!writePages[addr / PAGE_SIZE])
282 {
283 printf("Write16 to unmapped addr 0x%08x\n", addr);
284 exit(1);
285 }
286
287 *(uint16_t*)&writePages[addr / PAGE_SIZE][addr % PAGE_SIZE] = bswap16(data);
288}
289
290void Memory::Write32(uint32_t addr, uint32_t data)
291{
292 if (!writePages[addr / PAGE_SIZE])
293 {
294 printf("Write32 to unmapped addr 0x%08x\n", addr);
295 exit(1);
296 }
297
298 *(uint32_t*)&writePages[addr / PAGE_SIZE][addr % PAGE_SIZE] = bswap32(data);
299}
300
301void Memory::Write64(uint32_t addr, uint64_t data)
302{
303 if (!writePages[addr / PAGE_SIZE])
304 {
305 printf("Write64 to unmapped addr 0x%08x\n", addr);
306 exit(1);
307 }
308
309 *(uint64_t*)&writePages[addr / PAGE_SIZE][addr % PAGE_SIZE] = bswap64(data);
310}
311
312void Memory::Write128(uint32_t addr, __uint128_t data)
313{
314 if (!writePages[addr / PAGE_SIZE])
315 {
316 printf("Write64 to unmapped addr 0x%08x\n", addr);
317 exit(1);
318 }
319
320 data = swap(data);
321 *(__uint128_t*)&writePages[addr / PAGE_SIZE][addr % PAGE_SIZE] = data;
322}