summaryrefslogtreecommitdiff
path: root/emulators/qemu-devel/files/patch-z-arm-bsd-user-001
blob: 4c3a0e06e5041bc79b342a224dd00bf67346d497 (plain) (blame)
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
--- a/bsd-user/elfload.c.orig
+++ b/bsd-user/elfload.c
@@ -190,6 +190,9 @@ static inline void init_thread(struct ta
     if (infop->entry & 1)
       regs->ARM_cpsr |= CPSR_T;
     regs->ARM_pc = infop->entry & 0xfffffffe;
+    if (bsd_type == target_freebsd) {
+      regs->ARM_lr = infop->entry & 0xfffffffe;
+    }
     regs->ARM_sp = infop->start_stack;
     /* FIXME - what to for failure of get_user()? */
     get_user_ual(regs->ARM_r2, stack + 8); /* envp */
--- a/bsd-user/main.c.orig
+++ b/bsd-user/main.c
@@ -389,6 +389,259 @@ void cpu_loop(CPUX86State *env)
 }
 #endif
 
+#ifdef TARGET_ARM
+// #define DEBUG_ARM
+
+void cpu_loop(CPUARMState *env)
+{
+    int trapnr;
+    unsigned int n, insn;
+    uint32_t addr;
+
+    for(;;) {
+#ifdef DEBUG_ARM
+	printf("CPU LOOPING\n");
+#endif
+        cpu_exec_start(env);
+#ifdef DEBUG_ARM
+	printf("EXECUTING...\n");
+#endif
+        trapnr = cpu_arm_exec(env);
+#ifdef DEBUG_ARM
+	printf("trapnr %d\n", trapnr);
+#endif
+        cpu_exec_end(env);
+        switch(trapnr) {
+        case EXCP_UDEF:
+            {
+#if 0
+                TaskState *ts = env->opaque;
+                uint32_t opcode;
+                int rc;
+
+                /* we handle the FPU emulation here, as Linux */
+                /* we get the opcode */
+                /* FIXME - what to do if get_user() fails? */
+                get_user_u32(opcode, env->regs[15]);
+
+                rc = EmulateAll(opcode, &ts->fpa, env);
+                if (rc == 0) { /* illegal instruction */
+                    info.si_signo = SIGILL;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_ILL_ILLOPN;
+                    info._sifields._sigfault._addr = env->regs[15];
+                    queue_signal(env, info.si_signo, &info);
+
+                } else if (rc < 0) { /* FP exception */
+                    int arm_fpe=0;
+
+                    /* translate softfloat flags to FPSR flags */
+                    if (-rc & float_flag_invalid)
+                      arm_fpe |= BIT_IOC;
+                    if (-rc & float_flag_divbyzero)
+                      arm_fpe |= BIT_DZC;
+                    if (-rc & float_flag_overflow)
+                      arm_fpe |= BIT_OFC;
+                    if (-rc & float_flag_underflow)
+                      arm_fpe |= BIT_UFC;
+                    if (-rc & float_flag_inexact)
+                      arm_fpe |= BIT_IXC;
+
+                    FPSR fpsr = ts->fpa.fpsr;
+                    //printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe);
+
+                    if (fpsr & (arm_fpe << 16)) { /* exception enabled? */
+                      info.si_signo = SIGFPE;
+                      info.si_errno = 0;
+
+                      /* ordered by priority, least first */
+                      if (arm_fpe & BIT_IXC) info.si_code = TARGET_FPE_FLTRES;
+                      if (arm_fpe & BIT_UFC) info.si_code = TARGET_FPE_FLTUND;
+                      if (arm_fpe & BIT_OFC) info.si_code = TARGET_FPE_FLTOVF;
+                      if (arm_fpe & BIT_DZC) info.si_code = TARGET_FPE_FLTDIV;
+                      if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV;
+
+                      info._sifields._sigfault._addr = env->regs[15];
+                      queue_signal(env, info.si_signo, &info);
+                    } else {
+                      env->regs[15] += 4;
+                    }
+
+                    /* accumulate unenabled exceptions */
+                    if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC))
+                      fpsr |= BIT_IXC;
+                    if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC))
+                      fpsr |= BIT_UFC;
+                    if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC))
+                      fpsr |= BIT_OFC;
+                    if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC))
+                      fpsr |= BIT_DZC;
+                    if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC))
+                      fpsr |= BIT_IOC;
+                    ts->fpa.fpsr=fpsr;
+                } else { /* everything OK */
+                    /* increment PC */
+                    env->regs[15] += 4;
+                }
+            }
+#endif
+            break;
+        case EXCP_SWI:
+        case EXCP_BKPT:
+            {
+                env->eabi = 1;
+                /* system call */
+                if (trapnr == EXCP_BKPT) {
+                    if (env->thumb) {
+                        /* FIXME - what to do if get_user() fails? */
+                        get_user_u16(insn, env->regs[15]);
+                        n = insn & 0xff;
+                        env->regs[15] += 2;
+                    } else {
+                        /* FIXME - what to do if get_user() fails? */
+                        get_user_u32(insn, env->regs[15]);
+                        n = (insn & 0xf) | ((insn >> 4) & 0xff0);
+                        env->regs[15] += 4;
+                    }
+                } else {
+                    if (env->thumb) {
+                        /* FIXME - what to do if get_user() fails? */
+                        get_user_u16(insn, env->regs[15] - 2);
+                        n = insn & 0xff;
+                    } else {
+                        /* FIXME - what to do if get_user() fails? */
+                        get_user_u32(insn, env->regs[15] - 4);
+                        n = insn & 0xffffff;
+                    }
+                }
+
+#ifdef DEBUG_ARM
+		printf("AVANT CALL %d\n", n);
+#endif
+                if (bsd_type == target_freebsd) {
+                    int ret;
+                    abi_ulong params = get_sp_from_cpustate(env);
+                    int32_t syscall_nr = n;
+                    int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+
+#if 0 // XXX FIXME
+                    if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
+                        get_user_s32(syscall_nr, params);
+                        params += sizeof(int32_t);
+                    } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
+                        get_user_s32(syscall_nr, params);
+                        params += sizeof(int64_t);
+                    }
+#endif
+                    arg1 = env->regs[0];
+                    arg2 = env->regs[1];
+                    arg3 = env->regs[2];
+                    arg4 = env->regs[3];
+                    get_user_s32(arg5, params);
+                    params += sizeof(int32_t);
+                    get_user_s32(arg6, params);
+                    params += sizeof(int32_t);
+                    get_user_s32(arg7, params);
+                    params += sizeof(int32_t);
+                    get_user_s32(arg8, params);
+                    ret = do_freebsd_syscall(env,
+                                                      syscall_nr,
+                                                      arg1,
+                                                      arg2,
+                                                      arg3,
+                                                      arg4,
+                                                      arg5,
+                                                      arg6,
+                                                      arg7,
+                                                      arg8);
+                    if ((unsigned int)ret >= (unsigned int)(-515)) {
+                        ret = -ret;
+                        cpsr_write(env, CPSR_C, CPSR_C);
+                        env->regs[0] = ret;
+                    } else {
+                        cpsr_write(env, 0, CPSR_C);
+                        env->regs[0] = ret; // XXX need to handle lseek()?
+                        // env->regs[1] = 0;
+                    }
+                } else {
+                    // XXX is this correct?
+                    env->regs[0] = do_openbsd_syscall(env,
+                        n,
+                        env->regs[0],
+                        env->regs[1],
+                        env->regs[2],
+                        env->regs[3],
+                        env->regs[4],
+                        env->regs[5]);
+                }
+#ifdef DEBUG_ARM
+		printf("APRES CALL\n");
+#endif
+            }
+        }
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        case EXCP_PREFETCH_ABORT:
+            addr = env->cp15.c6_insn;
+            goto do_segv;
+        case EXCP_DATA_ABORT:
+            addr = env->cp15.c6_data;
+        do_segv:
+            {
+#if 0
+#
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                info._sifields._sigfault._addr = addr;
+                queue_signal(env, info.si_signo, &info);
+#endif
+            }
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig (env, TARGET_SIGTRAP);
+                if (sig)
+                  {
+#if 0
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+#endif
+                  }
+            }
+            break;
+#if 0
+        case EXCP_KERNEL_TRAP:
+            if (do_kernel_trap(env))
+              goto error;
+            break;
+        case EXCP_STREX:
+            if (do_strex(env)) {
+                addr = env->cp15.c6_data;
+                goto do_segv;
+            }
+            break;
+        error:
+#endif
+        default:
+            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
+                    trapnr);
+            cpu_dump_state(env, stderr, fprintf, 0);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+
+#endif
+
 #ifdef TARGET_SPARC
 #define SPARC64_STACK_BIAS 2047
 
@@ -1133,6 +1386,14 @@ int main(int argc, char **argv)
         for(i = 0; i < 8; i++)
             env->regwptr[i] = regs->u_regs[i + 8];
     }
+#elif defined(TARGET_ARM)
+    {
+        int i;
+        cpsr_write(env, regs->uregs[16], 0xffffffff);
+        for (i = 0; i < 16; i++) {
+                env->regs[i] = regs->uregs[i];
+        }
+    }
 #else
 #error unsupported target CPU
 #endif
--- a/bsd-user/syscall.c.orig
+++ b/bsd-user/syscall.c
@@ -157,6 +161,12 @@ static abi_long do_freebsd_sysarch(void 
 }
 #endif
 
+#ifdef TARGET_ARM
+static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms)
+{
+    return -TARGET_EINVAL;
+}
+#endif
 #ifdef __FreeBSD__
 /*
  * XXX this uses the undocumented oidfmt interface to find the kind of
@@ -215,6 +225,7 @@ static int sysctl_oldcvt(void *holdp, si
     case CTLTYPE_QUAD:
 #else
     case CTLTYPE_U64:
+    case CTLTYPE_S64:
 #endif
         *(uint64_t *)holdp = tswap64(*(uint64_t *)holdp);
         break;
@@ -380,6 +391,9 @@ abi_long do_freebsd_syscall(void *cpu_en
                                     arg5,
                                     arg6));
         break;
+    case TARGET_FREEBSD_NR_munmap:
+        ret = get_errno(target_munmap(arg1, arg2));
+        break;
     case TARGET_FREEBSD_NR_mprotect:
         ret = get_errno(target_mprotect(arg1, arg2, arg3));
         break;
--- /dev/null
+++ b/default-configs/arm-bsd-user.mak
@@ -0,0 +1,3 @@
+# Default configuration for arm-bsd-user
+
+CONFIG_GDBSTUB_XML=y
--- /dev/null
+++ b/bsd-user/arm/syscall.h
@@ -0,0 +1,23 @@
+struct target_pt_regs {
+	abi_long uregs[15];
+};
+
+#define ARM_cpsr	uregs[16]
+#define ARM_pc		uregs[15]
+#define ARM_lr		uregs[14]
+#define ARM_sp		uregs[13]
+#define ARM_ip		uregs[12]
+#define ARM_fp		uregs[11]
+#define ARM_r10		uregs[10]
+#define ARM_r9		uregs[9]
+#define ARM_r8		uregs[8]
+#define ARM_r7		uregs[7]
+#define ARM_r6		uregs[6]
+#define ARM_r5		uregs[5]
+#define ARM_r4		uregs[4]
+#define ARM_r3		uregs[3]
+#define ARM_r2		uregs[2]
+#define ARM_r1		uregs[1]
+#define ARM_r0		uregs[0]
+
+#define ARM_SYSCALL_BASE	0 /* XXX: FreeBSD only */
--- /dev/null
+++ b/bsd-user/arm/target_signal.h
@@ -0,0 +1,19 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_ulong ss_sp;
+	abi_long ss_flags;
+	abi_ulong ss_size;
+} target_stack_t;
+
+static inline abi_ulong get_sp_from_cpustate(CPUARMState *state)
+{
+    return state->regs[13];
+}
+
+#endif /* TARGET_SIGNAL_H */