common.cpp 17.1 KB
Newer Older
~skmp's avatar
~skmp committed
1
#include "types.h"
2

Libretro-Admin's avatar
Libretro-Admin committed
3
4
#include <errno.h>

5
6
7
8
9
10
11
#include <fcntl.h>
#include <semaphore.h>
#include <stdarg.h>
#include <signal.h>
#include <sys/param.h>
#include <sys/time.h>
#include <unistd.h>
12
#include "oslib/host_context.h"
13
#include "hw/sh4/dyna/blockmanager.h"
14
#include "hw/mem/vmem32.h"
15
16
17

#include "hw/sh4/dyna/ngen.h"

18
19
20
21
22
#ifdef _WIN32
#include "../imgread/common.h"

#include <windows.h>

Libretro-Admin's avatar
Libretro-Admin committed
23
#define UNW_FLAG_NHANDLER 0x00
Libretro-Admin's avatar
Libretro-Admin committed
24
#define UNW_FLAG_UHANDLER 0x02
Libretro-Admin's avatar
Libretro-Admin committed
25

26
bool VramLockedWrite(u8* address);
Libretro-Admin's avatar
Libretro-Admin committed
27
bool ngen_Rewrite(size_t &addr, size_t retadr, size_t acc);
28
29
bool BM_LockedWrite(u8* address);

30

Libretro-Admin's avatar
Libretro-Admin committed
31
static LONG ExceptionHandler(EXCEPTION_POINTERS *ep)
32
33
34
35
36
37
{
   u32 dwCode = ep->ExceptionRecord->ExceptionCode;

   if (dwCode != EXCEPTION_ACCESS_VIOLATION)
      return EXCEPTION_CONTINUE_SEARCH;

Libretro-Admin's avatar
Libretro-Admin committed
38
   EXCEPTION_RECORD* pExceptionRecord=ep->ExceptionRecord;
39
40
41
42
   u8* address=(u8*)pExceptionRecord->ExceptionInformation[1];

   //printf("[EXC] During access to : 0x%X\n", address);

Libretro-Admin's avatar
Libretro-Admin committed
43
   // code protection in RAM
44
45
	if (bm_RamWriteAccess(address))
		return EXCEPTION_CONTINUE_EXECUTION;
Libretro-Admin's avatar
Libretro-Admin committed
46
   // texture protection in VRAM
47
	else if (VramLockedWrite(address))
48
49
      return EXCEPTION_CONTINUE_EXECUTION;
#ifndef TARGET_NO_NVMEM
Libretro-Admin's avatar
Libretro-Admin committed
50
   /* FPCB jump table protection */
51
   if (BM_LockedWrite(address))
52
53
      return EXCEPTION_CONTINUE_EXECUTION;
#endif
Libretro-Admin's avatar
Libretro-Admin committed
54

55
#if FEAT_SHREC == DYNAREC_JIT && HOST_CPU == CPU_X86
Libretro-Admin's avatar
Libretro-Admin committed
56
   // fast mem access rewriting
Libretro-Admin's avatar
Libretro-Admin committed
57
   if ( ngen_Rewrite((size_t&)ep->ContextRecord->Eip,*(size_t*)ep->ContextRecord->Esp,ep->ContextRecord->Eax) )
58
59
60
61
62
63
64
65
66
   {
      //remove the call from call stack
      ep->ContextRecord->Esp+=4;
      //restore the addr from eax to ecx so its valid again
      ep->ContextRecord->Ecx=ep->ContextRecord->Eax;
      return EXCEPTION_CONTINUE_EXECUTION;
   }
#endif

Libretro-Admin's avatar
Libretro-Admin committed
67
   ERROR_LOG(COMMON, "[GPF]Unhandled access to : %p", address);
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
   return EXCEPTION_CONTINUE_SEARCH;
}

#ifdef _WIN64
#include "hw/sh4/dyna/ngen.h"

typedef union _UNWIND_CODE {
   struct {
      u8 CodeOffset;
      u8 UnwindOp : 4;
      u8 OpInfo : 4;
   };
   USHORT FrameOffset;
} UNWIND_CODE, *PUNWIND_CODE;

typedef struct _UNWIND_INFO {
   u8 Version : 3;
   u8 Flags : 5;
   u8 SizeOfProlog;
   u8 CountOfCodes;
   u8 FrameRegister : 4;
   u8 FrameOffset : 4;
   //ULONG ExceptionHandler;
   UNWIND_CODE UnwindCode[1];
   /*  UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
    *   union {
    *       OPTIONAL ULONG ExceptionHandler;
    *       OPTIONAL ULONG FunctionEntry;
    *   };
    *   OPTIONAL ULONG ExceptionData[]; */
} UNWIND_INFO, *PUNWIND_INFO;

static RUNTIME_FUNCTION Table[1];
static _UNWIND_INFO unwind_info[1];

   EXCEPTION_DISPOSITION
__gnat_SEH_error_handler(struct _EXCEPTION_RECORD* ExceptionRecord,
      void *EstablisherFrame,
      struct _CONTEXT* ContextRecord,
      void *DispatcherContext)
{
   EXCEPTION_POINTERS ep;
   ep.ContextRecord = ContextRecord;
   ep.ExceptionRecord = ExceptionRecord;

Libretro-Admin's avatar
Libretro-Admin committed
113
   return (EXCEPTION_DISPOSITION)ExceptionHandler(&ep);
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
}

PRUNTIME_FUNCTION
seh_callback(
      _In_ DWORD64 ControlPc,
      _In_opt_ PVOID Context
      ) {
   unwind_info[0].Version = 1;
   unwind_info[0].Flags = UNW_FLAG_UHANDLER;
   /* We don't use the unwinding info so fill the structure with 0 values.  */
   unwind_info[0].SizeOfProlog = 0;
   unwind_info[0].CountOfCodes = 0;
   unwind_info[0].FrameOffset = 0;
   unwind_info[0].FrameRegister = 0;
   /* Add the exception handler.  */

   //		unwind_info[0].ExceptionHandler =
   //	(DWORD)((u8 *)__gnat_SEH_error_handler - CodeCache);
   /* Set its scope to the entire program.  */
   Table[0].BeginAddress = 0;// (CodeCache - (u8*)__ImageBase);
134
135
   Table[0].EndAddress = /*(CodeCache - (u8*)__ImageBase) +*/ CODE_SIZE + TEMP_CODE_SIZE;
   Table[0].UnwindData = (ULONG)((u8 *)unwind_info - CodeCache);
Flyinghead's avatar
Flyinghead committed
136
   DEBUG_LOG(COMMON, "TABLE CALLBACK");
137
138
   return Table;
}
Libretro-Admin's avatar
Libretro-Admin committed
139
140
141

void setup_seh(void)
{
142
143
144
145
146
147
148
149
150
151
152
153
154
155
   /* Get the base of the module.  */
   /* Current version is always 1 and we are registering an
      exception handler.  */
   unwind_info[0].Version = 1;
   unwind_info[0].Flags = UNW_FLAG_NHANDLER;
   /* We don't use the unwinding info so fill the structure with 0 values.  */
   unwind_info[0].SizeOfProlog = 0;
   unwind_info[0].CountOfCodes = 1;
   unwind_info[0].FrameOffset = 0;
   unwind_info[0].FrameRegister = 0;
   /* Add the exception handler.  */

   unwind_info[0].UnwindCode[0].CodeOffset = 0;
   unwind_info[0].UnwindCode[0].UnwindOp = 2;// UWOP_ALLOC_SMALL;
156
   unwind_info[0].UnwindCode[0].OpInfo = 0x20 / 8;	// OpInfo * 8 + 8 bytes -> 0x28 bytes
157
158
159

   /* Set its scope to the entire program.  */
   Table[0].BeginAddress = 0;// (CodeCache - (u8*)__ImageBase);
160
161
   Table[0].EndAddress = /*(CodeCache - (u8*)__ImageBase) +*/ CODE_SIZE + TEMP_CODE_SIZE;
   Table[0].UnwindData = (ULONG)((u8 *)unwind_info - CodeCache);
162
163
164
165
166
167
   /* Register the unwind information.  */
   RtlAddFunctionTable(Table, 1, (DWORD64)CodeCache);
}
#endif
#endif

168
#if !defined(TARGET_NO_EXCEPTIONS)
Libretro-Admin's avatar
Libretro-Admin committed
169
bool ngen_Rewrite(size_t& addr,size_t retadr,size_t acc);
170
171
172
u32* ngen_readm_fail_v2(u32* ptr,u32* regs,u32 saddr);
bool VramLockedWrite(u8* address);
bool BM_LockedWrite(u8* address);
173
174
175

void context_from_segfault(host_context_t* hctx, void* segfault_ctx);
void context_to_segfault(host_context_t* hctx, void* segfault_ctx);
176

177
#ifdef __MACH__
Libretro-Admin's avatar
Libretro-Admin committed
178
static void sigill_handler(int sn, siginfo_t * si, void *segfault_ctx)
Libretro-Admin's avatar
Libretro-Admin committed
179
{
180
   host_context_t ctx;
Libretro-Admin's avatar
Libretro-Admin committed
181
182
183

   context_from_segfault(&ctx, segfault_ctx);

Libretro-Admin's avatar
Libretro-Admin committed
184
   size_t pc     = (size_t)ctx.pc;
185
#if FEAT_SHREC == DYNAREC_JIT
186
   bool dyna_cde = (pc > (size_t)CodeCache) && (pc < (size_t)(CodeCache + CODE_SIZE + TEMP_CODE_SIZE));
187
188
189
#else
	bool dyna_cde = false;
#endif
Libretro-Admin's avatar
Libretro-Admin committed
190

191
	ERROR_LOG(COMMON, "SIGILL @ %p ... %p -> was not in vram, %d",
Flyinghead's avatar
Flyinghead committed
192
         pc, si->si_addr, dyna_cde);
Libretro-Admin's avatar
Libretro-Admin committed
193

194
	ERROR_LOG(COMMON, "Entering infiniloop");
Libretro-Admin's avatar
Libretro-Admin committed
195
   for (;;);
196
}
197
#endif
198

Greg V's avatar
Greg V committed
199
#if defined(__MACH__) || defined(__linux__) || defined(__HAIKU__) || \
m4xw's avatar
m4xw committed
200
   defined(__FreeBSD__) || defined(__DragonFly__) || defined(HAVE_LIBNX)
201
202
//#define LOG_SIGHANDLER

m4xw's avatar
m4xw committed
203
204
205
206
#ifdef HAVE_LIBNX
extern "C" char __start__;
#endif // HAVE_LIBNX

Libretro-Admin's avatar
Libretro-Admin committed
207
static void signal_handler(int sn, siginfo_t * si, void *segfault_ctx)
208
{
209
   host_context_t ctx;
Libretro-Admin's avatar
Libretro-Admin committed
210
211
212

   context_from_segfault(&ctx, segfault_ctx);

213
#if FEAT_SHREC == DYNAREC_JIT
m4xw's avatar
m4xw committed
214
	bool dyna_cde = ((uintptr_t)CC_RX2RW(ctx.pc) > (uintptr_t)CodeCache) && ((uintptr_t)CC_RX2RW(ctx.pc) < (uintptr_t)(CodeCache + CODE_SIZE + TEMP_CODE_SIZE));
215
216
217
#else
	bool dyna_cde = false;
#endif
Libretro-Admin's avatar
Libretro-Admin committed
218

219
	DEBUG_LOG(COMMON, "mprot hit @ ptr %p @@ pc: %zx, %d", si->si_addr, ctx.pc, dyna_cde);
Libretro-Admin's avatar
Libretro-Admin committed
220

221
222
223
224
#if !defined(NO_MMU) && defined(HOST_64BIT_CPU)
#if HOST_CPU == CPU_ARM64
	u32 op = *(u32*)ctx.pc;
	bool write = (op & 0x00400000) == 0;
225
	u32 exception_pc = ctx.x2;
226
#elif HOST_CPU == CPU_X64
227
	bool write = false;	// TODO?
228
229
230
	u32 exception_pc = 0;
#endif
	if (vmem32_handle_signal(si->si_addr, write, exception_pc))
231
232
		return;
#endif
233
234
235
	if (bm_RamWriteAccess(si->si_addr))
		return;
	if (VramLockedWrite((u8*)si->si_addr))
Libretro-Admin's avatar
Libretro-Admin committed
236
      return;
237
#if !defined(TARGET_NO_NVMEM) && FEAT_SHREC != DYNAREC_NONE
238
239
240
   if (BM_LockedWrite((u8*)si->si_addr))
      return;
#endif
Libretro-Admin's avatar
Libretro-Admin committed
241
242
#if FEAT_SHREC == DYNAREC_JIT
#if HOST_CPU==CPU_ARM
Libretro-Admin's avatar
Libretro-Admin committed
243
   if (dyna_cde)
Libretro-Admin's avatar
Libretro-Admin committed
244
   {
Libretro-Admin's avatar
Libretro-Admin committed
245
      ctx.pc = (u32)ngen_readm_fail_v2((u32*)ctx.pc, ctx.r, (size_t)si->si_addr);
Libretro-Admin's avatar
Libretro-Admin committed
246
247
248
249

      context_to_segfault(&ctx, segfault_ctx);
   }
#elif HOST_CPU==CPU_X86
Libretro-Admin's avatar
Libretro-Admin committed
250
   if (ngen_Rewrite((size_t&)ctx.pc, *(size_t*)ctx.esp, ctx.eax))
Libretro-Admin's avatar
Libretro-Admin committed
251
252
253
254
255
256
257
258
259
   {
      //remove the call from call stack
      ctx.esp += 4;
      //restore the addr from eax to ecx so it's valid again
      ctx.ecx = ctx.eax;

      context_to_segfault(&ctx, segfault_ctx);
   }
#elif HOST_CPU == CPU_X64
260
261
262
263
	else if (dyna_cde && ngen_Rewrite((unat&)ctx.pc, 0, 0))
	{
		context_to_segfault(&ctx, segfault_ctx);
	}
Flyinghead's avatar
Flyinghead committed
264
#elif HOST_CPU == CPU_ARM64
265
266
267
268
	else if (dyna_cde && ngen_Rewrite(ctx.pc, 0, 0))
	{
		context_to_segfault(&ctx, segfault_ctx);
	}
Libretro-Admin's avatar
Libretro-Admin committed
269
#else
Flyinghead's avatar
Flyinghead committed
270
#error JIT: Not supported arch
Libretro-Admin's avatar
Libretro-Admin committed
271
272
273
274
#endif
#endif
   else
   {
275
   	ERROR_LOG(COMMON, "SIGSEGV @ %zx ... %p -> was not in vram (dyna code %d)", ctx.pc, si->si_addr, dyna_cde);
m4xw's avatar
m4xw committed
276
277
278
279
280
281
282
283
#ifdef HAVE_LIBNX
    MemoryInfo meminfo;
    u32 pageinfo;
    svcQueryMemory(&meminfo, &pageinfo, (u64)&__start__);
   	ERROR_LOG(COMMON, ".text base: %p", meminfo.addr);
#endif // HAVE_LIBNX
   	die("segfault");
   	signal(SIGSEGV, SIG_DFL);
Libretro-Admin's avatar
Libretro-Admin committed
284
   }
285
}
286
#endif
287

288
#endif
Libretro-Admin's avatar
Libretro-Admin committed
289

Libretro-Admin's avatar
Libretro-Admin committed
290
#ifndef _WIN32
Libretro-Admin's avatar
Libretro-Admin committed
291
292
293
294
295
296
#if !defined(TARGET_NO_EXCEPTIONS)
static struct sigaction old_sigsegv;
static struct sigaction old_sigill;
#endif

static int exception_handler_install_platform(void)
297
{
m4xw's avatar
m4xw committed
298
299
300
#if defined(HAVE_LIBNX)
   return 0;
#elif !defined(TARGET_NO_EXCEPTIONS)
Libretro-Admin's avatar
Libretro-Admin committed
301
302
303
304
305
306
307
   struct sigaction new_sa;
   new_sa.sa_flags = SA_SIGINFO;
   sigemptyset(&new_sa.sa_mask);
   new_sa.sa_sigaction = signal_handler;

   if (sigaction(SIGSEGV, &new_sa, &old_sigsegv) != 0)
      return 0;
Libretro-Admin's avatar
Libretro-Admin committed
308

Libretro-Admin's avatar
Libretro-Admin committed
309
310
311
312
#ifdef __MACH__
   /* this is broken on OSX/iOS/Mach in general */
   sigaction(SIGBUS, &new_sa, &old_sigsegv);
   new_sa.sa_sigaction = sigill_handler;
313
#endif
Libretro-Admin's avatar
Libretro-Admin committed
314
315
316

   if (sigaction(SIGILL, &new_sa, &old_sigill))
         return 0;
317
#endif
Libretro-Admin's avatar
Libretro-Admin committed
318
319

   return 1;
320
}
Libretro-Admin's avatar
Libretro-Admin committed
321
#endif
322

Libretro-Admin's avatar
Libretro-Admin committed
323
static void print_mem_addr(void)
324
{
325
   char line [ 512 ];
Libretro-Admin's avatar
Libretro-Admin committed
326
   FILE *ifp, *ofp;
327

Libretro-Admin's avatar
Libretro-Admin committed
328
   ifp = fopen("/proc/self/maps", "r");
329

330
331
   if (ifp == NULL)
   {
Libretro-Admin's avatar
Libretro-Admin committed
332
333
334
      fprintf(stderr, "Can't open input file /proc/self/maps!\n");
      exit(1);
   }
335

336
   ofp = stderr;
337

338
   while (fgets(line, sizeof line, ifp) != NULL)
Libretro-Admin's avatar
Libretro-Admin committed
339
      fprintf(ofp, "%s", line);
340

Libretro-Admin's avatar
Libretro-Admin committed
341
342
343
   fclose(ifp);
   if (ofp != stderr)
      fclose(ofp);
344
345
}

Libretro-Admin's avatar
Libretro-Admin committed
346

Libretro-Admin's avatar
Libretro-Admin committed
347
static void enable_runfast(void)
348
{
Libretro-Admin's avatar
Libretro-Admin committed
349
350
351
352
353
354
355
356
357
358
359
360
361
#if HOST_CPU==CPU_ARM && !defined(ARMCC)
   static const unsigned int x = 0x04086060;
   static const unsigned int y = 0x03000000;
   int r;
   asm volatile (
         "fmrx	%0, fpscr			\n\t"	//r0 = FPSCR
         "and	%0, %0, %1			\n\t"	//r0 = r0 & 0x04086060
         "orr	%0, %0, %2			\n\t"	//r0 = r0 | 0x03000000
         "fmxr	fpscr, %0			\n\t"	//FPSCR = r0
         : "=r"(r)
         : "r"(x), "r"(y)
         );

362
   DEBUG_LOG(BOOT, "ARM VFP-Run Fast (NFP) enabled !");
Libretro-Admin's avatar
Libretro-Admin committed
363
#endif
364
365
}

Libretro-Admin's avatar
Libretro-Admin committed
366
367
368
#if !defined(TARGET_NO_THREADS)

//Thread class
Flyinghead's avatar
Flyinghead committed
369
cThread::cThread(ThreadEntryFP* function,void* prm) : hThread(NULL)
Libretro-Admin's avatar
Libretro-Admin committed
370
371
372
373
374
375
376
{
	Entry=function;
	param=prm;
}

void cThread::Start()
{
Flyinghead's avatar
Flyinghead committed
377
	verify(hThread == NULL);
378
   hThread = sthread_create((void (*)(void *))Entry, param);
Libretro-Admin's avatar
Libretro-Admin committed
379
380
381
382
}

void cThread::WaitToEnd()
{
Flyinghead's avatar
Flyinghead committed
383
384
385
386
387
	if (hThread != NULL)
	{
		sthread_join(hThread);
		hThread = NULL;
	}
Libretro-Admin's avatar
Libretro-Admin committed
388
389
390
391
392
393
}

//End thread class
#endif

//cResetEvent Class
Flyinghead's avatar
Flyinghead committed
394
cResetEvent::cResetEvent()
Libretro-Admin's avatar
Libretro-Admin committed
395
396
397
398
399
{
#if !defined(TARGET_NO_THREADS)
   mutx = slock_new();
   cond = scond_new();
#endif
Flyinghead's avatar
Flyinghead committed
400
   state = false;
Libretro-Admin's avatar
Libretro-Admin committed
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
}

cResetEvent::~cResetEvent()
{
#if !defined(TARGET_NO_THREADS)
   slock_free(mutx);
   scond_free(cond);
#endif
}
void cResetEvent::Set()//Signal
{
#if !defined(TARGET_NO_THREADS)
	slock_lock(mutx );
#endif
	state=true;
#if !defined(TARGET_NO_THREADS)
   scond_signal(cond);
	slock_unlock(mutx );
#endif
}
void cResetEvent::Reset()//reset
{
#if !defined(TARGET_NO_THREADS)
	slock_lock(mutx );
#endif
	state=false;
#if !defined(TARGET_NO_THREADS)
	slock_unlock(mutx );
#endif
}
431
bool cResetEvent::Wait(u32 msec)//Wait for signal , then reset
Libretro-Admin's avatar
Libretro-Admin committed
432
{
433
434
435
#if !defined(TARGET_NO_THREADS)
	slock_lock(mutx);
	if (!state)
436
		scond_wait_timeout(cond, mutx, (int64_t)msec * 1000);
437
#endif
438
	bool ret = state;
439
440
441
442
443
	state = false;
#if !defined(TARGET_NO_THREADS)
   slock_unlock(mutx);
#endif
	return ret;
Libretro-Admin's avatar
Libretro-Admin committed
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
}
void cResetEvent::Wait()//Wait for signal , then reset
{
#if !defined(TARGET_NO_THREADS)
	slock_lock(mutx);
	if (!state)
      scond_wait(cond, mutx);
#endif
	state=false;
#if !defined(TARGET_NO_THREADS)
   slock_unlock(mutx);
#endif
}

//End AutoResetEvent
459
460
#ifndef TARGET_NO_EXCEPTIONS
void VArray2::LockRegion(u32 offset,u32 size_bytes)
Libretro-Admin's avatar
Libretro-Admin committed
461
{
462
   mem_region_lock(&data[offset], size_bytes);
Libretro-Admin's avatar
Libretro-Admin committed
463
464
}

465
void VArray2::UnLockRegion(u32 offset,u32 size_bytes)
Libretro-Admin's avatar
Libretro-Admin committed
466
{
467
   mem_region_unlock(&data[offset], size_bytes);
Libretro-Admin's avatar
Libretro-Admin committed
468
}
469
#endif
Libretro-Admin's avatar
Libretro-Admin committed
470

Libretro-Admin's avatar
Libretro-Admin committed
471
#if defined(_WIN64) && defined(_DEBUG)
Libretro-Admin's avatar
Libretro-Admin committed
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
static void ReserveBottomMemory(void)
{
    static bool s_initialized = false;
    if ( s_initialized )
        return;
    s_initialized = true;
 
    // Start by reserving large blocks of address space, and then
    // gradually reduce the size in order to capture all of the
    // fragments. Technically we should continue down to 64 KB but
    // stopping at 1 MB is sufficient to keep most allocators out.
 
    const size_t LOW_MEM_LINE = 0x100000000LL;
    size_t totalReservation = 0;
    size_t numVAllocs = 0;
    size_t numHeapAllocs = 0;
    size_t oneMB = 1024 * 1024;
    for (size_t size = 256 * oneMB; size >= oneMB; size /= 2)
    {
        for (;;)
        {
            void* p = VirtualAlloc(0, size, MEM_RESERVE, PAGE_NOACCESS);
            if (!p)
                break;
 
            if ((size_t)p >= LOW_MEM_LINE)
            {
                // We don't need this memory, so release it completely.
                VirtualFree(p, 0, MEM_RELEASE);
                break;
            }
 
            totalReservation += size;
            ++numVAllocs;
        }
    }
 
    // Now repeat the same process but making heap allocations, to use up
    // the already reserved heap blocks that are below the 4 GB line.
    HANDLE heap = GetProcessHeap();
    for (size_t blockSize = 64 * 1024; blockSize >= 16; blockSize /= 2)
    {
        for (;;)
        {
            void* p = HeapAlloc(heap, 0, blockSize);
            if (!p)
                break;
 
            if ((size_t)p >= LOW_MEM_LINE)
            {
                // We don't need this memory, so release it completely.
                HeapFree(heap, 0, p);
                break;
            }
 
            totalReservation += blockSize;
            ++numHeapAllocs;
        }
    }
 
    // Perversely enough the CRT doesn't use the process heap. Suck up
    // the memory the CRT heap has already reserved.
    for (size_t blockSize = 64 * 1024; blockSize >= 16; blockSize /= 2)
    {
        for (;;)
        {
            void* p = malloc(blockSize);
            if (!p)
                break;
 
            if ((size_t)p >= LOW_MEM_LINE)
            {
                // We don't need this memory, so release it completely.
                free(p);
                break;
            }
 
            totalReservation += blockSize;
            ++numHeapAllocs;
        }
    }
 
    // Print diagnostics showing how many allocations we had to make in
    // order to reserve all of low memory, typically less than 200.
    char buffer[1000];
    sprintf_s(buffer, "Reserved %1.3f MB (%d vallocs,"
                      "%d heap allocs) of low-memory.\n",
            totalReservation / (1024 * 1024.0),
            (int)numVAllocs, (int)numHeapAllocs);
    OutputDebugStringA(buffer);
}
Libretro-Admin's avatar
Libretro-Admin committed
563
#endif
Libretro-Admin's avatar
Libretro-Admin committed
564

Libretro-Admin's avatar
Libretro-Admin committed
565
void common_libretro_setup(void)
566
{
Libretro-Admin's avatar
Libretro-Admin committed
567
#if defined(_WIN64) && defined(_DEBUG)
Libretro-Admin's avatar
Libretro-Admin committed
568
   ReserveBottomMemory();
Libretro-Admin's avatar
Libretro-Admin committed
569
#endif
Libretro-Admin's avatar
Libretro-Admin committed
570

Libretro-Admin's avatar
Libretro-Admin committed
571
#if defined(__MACH__) || defined(__linux__)
Libretro-Admin's avatar
Libretro-Admin committed
572
   enable_runfast();
Libretro-Admin's avatar
Libretro-Admin committed
573
#endif
574
575
#ifdef _WIN32
#ifdef _WIN64
aliaspider's avatar
aliaspider committed
576
   AddVectoredExceptionHandler(1, ExceptionHandler);
577
#else
Libretro-Admin's avatar
Libretro-Admin committed
578
   SetUnhandledExceptionFilter(&ExceptionHandler);
579
#endif
580
#else
Libretro-Admin's avatar
Libretro-Admin committed
581
   exception_handler_install_platform();
Libretro-Admin's avatar
Libretro-Admin committed
582
   signal(SIGINT, exit);
583
#endif
Libretro-Admin's avatar
Libretro-Admin committed
584

Libretro-Admin's avatar
Libretro-Admin committed
585
#if defined(__MACH__) || defined(__linux__)
586
   DEBUG_LOG(BOOT, "Linux paging: %08lX %08X %08X\n",sysconf(_SC_PAGESIZE),PAGE_SIZE,PAGE_MASK);
587
   verify(PAGE_MASK==(sysconf(_SC_PAGESIZE)-1));
Libretro-Admin's avatar
Libretro-Admin committed
588
#endif
589
}
m4xw's avatar
m4xw committed
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670

#if !defined(TARGET_NO_EXCEPTIONS) && defined(HAVE_LIBNX)
extern "C"
{

alignas(16) u8 __nx_exception_stack[0x1000];
u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
#include <malloc.h>
extern void context_switch_aarch64(void* context);

void __libnx_exception_handler(ThreadExceptionDump *ctx)
{   
   mcontext_t m_ctx;

   m_ctx.pc = ctx->pc.x;

   for(int i=0; i<29; i++)
   {
      // printf("X%d: %p\n", i, ctx->cpu_gprs[i].x);
      m_ctx.regs[i] = ctx->cpu_gprs[i].x;
   }

   /*
   printf("PC: %p\n", ctx->pc.x);
   printf("FP: %p\n", ctx->fp.x);
   printf("LR: %p\n", ctx->lr.x);
   printf("SP: %p\n", ctx->sp.x);
   */

   ucontext_t u_ctx;
   u_ctx.uc_mcontext = m_ctx;

   siginfo_t sig_info;

   sig_info.si_addr = (void*)ctx->far.x;

   signal_handler(0, &sig_info, (void*) &u_ctx);

   uint64_t handle[64] = { 0 };

   uint64_t *ptr = (uint64_t*)handle;
   ptr[0]  = m_ctx.regs[0]; /* x0 0  */
   ptr[1]  = m_ctx.regs[1]; /* x1 8 */
   ptr[2]  = m_ctx.regs[2]; /* x2 16 */
   ptr[3]  = m_ctx.regs[3]; /* x3 24 */
   ptr[4]  = m_ctx.regs[4]; /* x4 32 */
   ptr[5]  = m_ctx.regs[5]; /* x5 40 */
   ptr[6]  = m_ctx.regs[6]; /* x6 48 */
   ptr[7]  = m_ctx.regs[7]; /* x7 56 */
   /* Non-volatiles.  */
   ptr[8]  = m_ctx.regs[8]; /* x8 64 */
   ptr[9]  = m_ctx.regs[9]; /* x9 72 */
   ptr[10]  = m_ctx.regs[10]; /* x10 80 */
   ptr[11]  = m_ctx.regs[11]; /* x11 88 */
   ptr[12]  = m_ctx.regs[12]; /* x12 96 */
   ptr[13]  = m_ctx.regs[13]; /* x13 104 */
   ptr[14]  = m_ctx.regs[14]; /* x14 112 */
   ptr[15]  = m_ctx.regs[15]; /* x15 120 */
   ptr[16]  = m_ctx.regs[16]; /* x16 128 */
   ptr[17]  = m_ctx.regs[17]; /* x17 136 */
   ptr[18]  = m_ctx.regs[18]; /* x18 144 */
   ptr[19]  = m_ctx.regs[19]; /* x19 152 */
   ptr[20] = m_ctx.regs[20]; /* x20 160 */
   ptr[21] = m_ctx.regs[21]; /* x21 168 */
   ptr[22] = m_ctx.regs[22]; /* x22 176 */
   ptr[23] = m_ctx.regs[23]; /* x23 184 */
   ptr[24] = m_ctx.regs[24]; /* x24 192 */
   ptr[25] = m_ctx.regs[25]; /* x25 200 */
   ptr[26] = m_ctx.regs[26]; /* x26 208 */
   ptr[27] = m_ctx.regs[27]; /* x27 216 */
   ptr[28] = m_ctx.regs[28]; /* x28 224 */
   /* Special regs */
   ptr[29] = ctx->fp.x; /* frame pointer 232 */
   ptr[30] = ctx->lr.x; /* link register 240 */
   ptr[31] = ctx->sp.x; /* stack pointer 248 */
   ptr[32] = (uintptr_t)ctx->pc.x; /* PC 256 */

   context_switch_aarch64(ptr);
}
}

671
#endif