forked from libretro/RetroArch
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmain.c
168 lines (125 loc) · 4.14 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/* Copyright 2011 Dimok
This code is licensed to you under the terms of the GNU GPL, version 2;
see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt */
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#include "string.h"
#include <gccore.h>
#include "elf_abi.h"
#define SYSTEM_ARGV ((struct __argv *) 0x93200000)
#define EXECUTABLE_MEM_ADDR 0x91800000
#define ARENA1_HI_LIMIT 0x81800000
typedef struct _dolheade
{
uint32_t text_pos[7];
uint32_t data_pos[11];
uint32_t text_start[7];
uint32_t data_start[11];
uint32_t text_size[7];
uint32_t data_size[11];
uint32_t bss_start;
uint32_t bss_size;
uint32_t entry_point;
} dolheader;
typedef void (*entrypoint)(void);
static void sync_before_exec(const void *p, uint32_t len)
{
uint32_t a = (uint32_t)p & ~0x1f;
uint32_t b = ((uint32_t)p + len + 0x1f) & ~0x1f;
for ( ; a < b; a += 32)
asm("dcbst 0,%0 ; sync ; icbi 0,%0" : : "b"(a));
asm("sync ; isync");
}
/* ======================================================================
* Determine if a valid ELF image exists at the given memory location.
* First looks at the ELF header magic field, the makes sure that it is
* executable and makes sure that it is for a PowerPC.
* ====================================================================== */
static int32_t valid_elf_image (void *addr)
{
Elf32_Ehdr *ehdr = (Elf32_Ehdr*)addr;
if (!IS_ELF (*ehdr))
return 0;
if (ehdr->e_type != ET_EXEC)
return -1;
if (ehdr->e_machine != EM_PPC)
return -1;
return 1;
}
/* ======================================================================
* A very simple elf loader, assumes the image is valid, returns the
* entry point address.
* ====================================================================== */
static uint32_t load_elf_image (void *elfstart)
{
int i;
Elf32_Phdr *phdrs = NULL;
Elf32_Ehdr *ehdr = (Elf32_Ehdr*) elfstart;
if(ehdr->e_phoff == 0 || ehdr->e_phnum == 0)
return 0;
if(ehdr->e_phentsize != sizeof(Elf32_Phdr))
return 0;
phdrs = (Elf32_Phdr*)(elfstart + ehdr->e_phoff);
for (i = 0; i < ehdr->e_phnum; i++)
{
uint8_t *image;
if(phdrs[i].p_type != PT_LOAD)
continue;
phdrs[i].p_paddr &= 0x3FFFFFFF;
phdrs[i].p_paddr |= 0x80000000;
if(phdrs[i].p_filesz > phdrs[i].p_memsz)
return 0;
if(!phdrs[i].p_filesz)
continue;
image = (uint8_t*)(elfstart + phdrs[i].p_offset);
memcpy ((void *) phdrs[i].p_paddr, (const void *) image, phdrs[i].p_filesz);
sync_before_exec ((void *) phdrs[i].p_paddr, phdrs[i].p_memsz);
}
return ((ehdr->e_entry & 0x3FFFFFFF) | 0x80000000);
}
static uint32_t load_dol_image(const void *dolstart)
{
uint32_t i;
dolheader *dolfile = NULL;
if(!dolstart)
return 0;
dolfile = (dolheader *) dolstart;
for (i = 0; i < 7; i++)
{
if ((!dolfile->text_size[i]) || (dolfile->text_start[i] < 0x100))
continue;
memcpy((void *) dolfile->text_start[i], dolstart + dolfile->text_pos[i], dolfile->text_size[i]);
sync_before_exec((void *) dolfile->text_start[i], dolfile->text_size[i]);
}
for (i = 0; i < 11; i++)
{
if ((!dolfile->data_size[i]) || (dolfile->data_start[i] < 0x100))
continue;
memcpy((void *) dolfile->data_start[i], dolstart + dolfile->data_pos[i], dolfile->data_size[i]);
sync_before_exec((void *) dolfile->data_start[i], dolfile->data_size[i]);
}
return dolfile->entry_point;
}
/* if we name this main, GCC inserts the __eabi symbol,
* even when we specify -mno-eabi. */
void app_booter_main(void)
{
entrypoint exeEntryPoint;
uint32_t exeEntryPointAddress = 0;
void *exeBuffer = (void*)EXECUTABLE_MEM_ADDR;
if (valid_elf_image(exeBuffer) == 1)
exeEntryPointAddress = load_elf_image(exeBuffer);
else
exeEntryPointAddress = load_dol_image(exeBuffer);
exeEntryPoint = (entrypoint) exeEntryPointAddress;
if (!exeEntryPoint)
return;
if (SYSTEM_ARGV->argvMagic == ARGV_MAGIC)
{
void *new_argv = (void*)(exeEntryPointAddress + 8);
memcpy(new_argv, SYSTEM_ARGV, sizeof(struct __argv));
sync_before_exec(new_argv, sizeof(struct __argv));
}
exeEntryPoint();
}