Commit a745ec6d91fc3ee06b4c281d30b472aeaa6302e0
1 parent
f0b86b14
Update ARM rt_frame layout.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4365 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
172 additions
and
14 deletions
linux-user/qemu.h
linux-user/signal.c
... | ... | @@ -1020,12 +1020,22 @@ struct target_sigcontext { |
1020 | 1020 | abi_ulong fault_address; |
1021 | 1021 | }; |
1022 | 1022 | |
1023 | -struct target_ucontext { | |
1023 | +struct target_ucontext_v1 { | |
1024 | + abi_ulong tuc_flags; | |
1025 | + abi_ulong tuc_link; | |
1026 | + target_stack_t tuc_stack; | |
1027 | + struct target_sigcontext tuc_mcontext; | |
1028 | + target_sigset_t tuc_sigmask; /* mask last for extensibility */ | |
1029 | +}; | |
1030 | + | |
1031 | +struct target_ucontext_v2 { | |
1024 | 1032 | abi_ulong tuc_flags; |
1025 | 1033 | abi_ulong tuc_link; |
1026 | 1034 | target_stack_t tuc_stack; |
1027 | 1035 | struct target_sigcontext tuc_mcontext; |
1028 | 1036 | target_sigset_t tuc_sigmask; /* mask last for extensibility */ |
1037 | + char __unused[128 - sizeof(sigset_t)]; | |
1038 | + abi_ulong tuc_regspace[128] __attribute__((__aligned__(8))); | |
1029 | 1039 | }; |
1030 | 1040 | |
1031 | 1041 | struct sigframe |
... | ... | @@ -1035,12 +1045,19 @@ struct sigframe |
1035 | 1045 | abi_ulong retcode; |
1036 | 1046 | }; |
1037 | 1047 | |
1038 | -struct rt_sigframe | |
1048 | +struct rt_sigframe_v1 | |
1039 | 1049 | { |
1040 | 1050 | abi_ulong pinfo; |
1041 | 1051 | abi_ulong puc; |
1042 | 1052 | struct target_siginfo info; |
1043 | - struct target_ucontext uc; | |
1053 | + struct target_ucontext_v1 uc; | |
1054 | + abi_ulong retcode; | |
1055 | +}; | |
1056 | + | |
1057 | +struct rt_sigframe_v2 | |
1058 | +{ | |
1059 | + struct target_siginfo info; | |
1060 | + struct target_ucontext_v2 uc; | |
1044 | 1061 | abi_ulong retcode; |
1045 | 1062 | }; |
1046 | 1063 | |
... | ... | @@ -1191,11 +1208,11 @@ end: |
1191 | 1208 | } |
1192 | 1209 | |
1193 | 1210 | /* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */ |
1194 | -static void setup_rt_frame(int usig, struct emulated_sigaction *ka, | |
1195 | - target_siginfo_t *info, | |
1196 | - target_sigset_t *set, CPUState *env) | |
1211 | +static void setup_rt_frame_v1(int usig, struct emulated_sigaction *ka, | |
1212 | + target_siginfo_t *info, | |
1213 | + target_sigset_t *set, CPUState *env) | |
1197 | 1214 | { |
1198 | - struct rt_sigframe *frame; | |
1215 | + struct rt_sigframe_v1 *frame; | |
1199 | 1216 | abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); |
1200 | 1217 | struct target_sigaltstack stack; |
1201 | 1218 | int i, err = 0; |
... | ... | @@ -1204,14 +1221,14 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, |
1204 | 1221 | if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) |
1205 | 1222 | return /* 1 */; |
1206 | 1223 | |
1207 | - info_addr = frame_addr + offsetof(struct rt_sigframe, info); | |
1224 | + info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info); | |
1208 | 1225 | __put_user_error(info_addr, &frame->pinfo, err); |
1209 | - uc_addr = frame_addr + offsetof(struct rt_sigframe, uc); | |
1226 | + uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc); | |
1210 | 1227 | __put_user_error(uc_addr, &frame->puc, err); |
1211 | 1228 | err |= copy_siginfo_to_user(&frame->info, info); |
1212 | 1229 | |
1213 | 1230 | /* Clear all the bits of the ucontext we don't use. */ |
1214 | - memset(&frame->uc, 0, offsetof(struct target_ucontext, tuc_mcontext)); | |
1231 | + memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext)); | |
1215 | 1232 | |
1216 | 1233 | memset(&stack, 0, sizeof(stack)); |
1217 | 1234 | __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); |
... | ... | @@ -1228,7 +1245,55 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, |
1228 | 1245 | |
1229 | 1246 | if (err == 0) |
1230 | 1247 | err = setup_return(env, ka, &frame->retcode, frame_addr, usig, |
1231 | - frame_addr + offsetof(struct rt_sigframe, retcode)); | |
1248 | + frame_addr + offsetof(struct rt_sigframe_v1, retcode)); | |
1249 | + | |
1250 | + if (err == 0) { | |
1251 | + env->regs[1] = info_addr; | |
1252 | + env->regs[2] = uc_addr; | |
1253 | + } | |
1254 | + | |
1255 | +end: | |
1256 | + unlock_user_struct(frame, frame_addr, 1); | |
1257 | + | |
1258 | + // return err; | |
1259 | +} | |
1260 | + | |
1261 | +static void setup_rt_frame_v2(int usig, struct emulated_sigaction *ka, | |
1262 | + target_siginfo_t *info, | |
1263 | + target_sigset_t *set, CPUState *env) | |
1264 | +{ | |
1265 | + struct rt_sigframe_v2 *frame; | |
1266 | + abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); | |
1267 | + struct target_sigaltstack stack; | |
1268 | + int i, err = 0; | |
1269 | + abi_ulong info_addr, uc_addr; | |
1270 | + | |
1271 | + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) | |
1272 | + return /* 1 */; | |
1273 | + | |
1274 | + info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info); | |
1275 | + uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc); | |
1276 | + err |= copy_siginfo_to_user(&frame->info, info); | |
1277 | + | |
1278 | + /* Clear all the bits of the ucontext we don't use. */ | |
1279 | + memset(&frame->uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext)); | |
1280 | + | |
1281 | + memset(&stack, 0, sizeof(stack)); | |
1282 | + __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); | |
1283 | + __put_user(target_sigaltstack_used.ss_size, &stack.ss_size); | |
1284 | + __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags); | |
1285 | + memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack)); | |
1286 | + | |
1287 | + err |= setup_sigcontext(&frame->uc.tuc_mcontext, /*&frame->fpstate,*/ | |
1288 | + env, set->sig[0]); | |
1289 | + for(i = 0; i < TARGET_NSIG_WORDS; i++) { | |
1290 | + if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i])) | |
1291 | + goto end; | |
1292 | + } | |
1293 | + | |
1294 | + if (err == 0) | |
1295 | + err = setup_return(env, ka, &frame->retcode, frame_addr, usig, | |
1296 | + frame_addr + offsetof(struct rt_sigframe_v2, retcode)); | |
1232 | 1297 | |
1233 | 1298 | if (err == 0) { |
1234 | 1299 | /* |
... | ... | @@ -1246,6 +1311,17 @@ end: |
1246 | 1311 | // return err; |
1247 | 1312 | } |
1248 | 1313 | |
1314 | +static void setup_rt_frame(int usig, struct emulated_sigaction *ka, | |
1315 | + target_siginfo_t *info, | |
1316 | + target_sigset_t *set, CPUState *env) | |
1317 | +{ | |
1318 | + if (get_osversion() >= 0x020612) { | |
1319 | + setup_rt_frame_v2(usig, ka, info, set, env); | |
1320 | + } else { | |
1321 | + setup_rt_frame_v1(usig, ka, info, set, env); | |
1322 | + } | |
1323 | +} | |
1324 | + | |
1249 | 1325 | static int |
1250 | 1326 | restore_sigcontext(CPUState *env, struct target_sigcontext *sc) |
1251 | 1327 | { |
... | ... | @@ -1325,10 +1401,51 @@ badframe: |
1325 | 1401 | return 0; |
1326 | 1402 | } |
1327 | 1403 | |
1328 | -long do_rt_sigreturn(CPUState *env) | |
1404 | +long do_rt_sigreturn_v1(CPUState *env) | |
1329 | 1405 | { |
1330 | 1406 | abi_ulong frame_addr; |
1331 | - struct rt_sigframe *frame; | |
1407 | + struct rt_sigframe_v1 *frame; | |
1408 | + sigset_t host_set; | |
1409 | + | |
1410 | + /* | |
1411 | + * Since we stacked the signal on a 64-bit boundary, | |
1412 | + * then 'sp' should be word aligned here. If it's | |
1413 | + * not, then the user is trying to mess with us. | |
1414 | + */ | |
1415 | + if (env->regs[13] & 7) | |
1416 | + goto badframe; | |
1417 | + | |
1418 | + frame_addr = env->regs[13]; | |
1419 | + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) | |
1420 | + goto badframe; | |
1421 | + | |
1422 | + target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask); | |
1423 | + sigprocmask(SIG_SETMASK, &host_set, NULL); | |
1424 | + | |
1425 | + if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) | |
1426 | + goto badframe; | |
1427 | + | |
1428 | + if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) | |
1429 | + goto badframe; | |
1430 | + | |
1431 | +#if 0 | |
1432 | + /* Send SIGTRAP if we're single-stepping */ | |
1433 | + if (ptrace_cancel_bpt(current)) | |
1434 | + send_sig(SIGTRAP, current, 1); | |
1435 | +#endif | |
1436 | + unlock_user_struct(frame, frame_addr, 0); | |
1437 | + return env->regs[0]; | |
1438 | + | |
1439 | +badframe: | |
1440 | + unlock_user_struct(frame, frame_addr, 0); | |
1441 | + force_sig(SIGSEGV /* , current */); | |
1442 | + return 0; | |
1443 | +} | |
1444 | + | |
1445 | +long do_rt_sigreturn_v2(CPUState *env) | |
1446 | +{ | |
1447 | + abi_ulong frame_addr; | |
1448 | + struct rt_sigframe_v2 *frame; | |
1332 | 1449 | sigset_t host_set; |
1333 | 1450 | |
1334 | 1451 | /* |
... | ... | @@ -1349,7 +1466,7 @@ long do_rt_sigreturn(CPUState *env) |
1349 | 1466 | if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) |
1350 | 1467 | goto badframe; |
1351 | 1468 | |
1352 | - if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) | |
1469 | + if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v2, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) | |
1353 | 1470 | goto badframe; |
1354 | 1471 | |
1355 | 1472 | #if 0 |
... | ... | @@ -1366,6 +1483,15 @@ badframe: |
1366 | 1483 | return 0; |
1367 | 1484 | } |
1368 | 1485 | |
1486 | +long do_rt_sigreturn(CPUState *env) | |
1487 | +{ | |
1488 | + if (get_osversion() >= 0x020612) { | |
1489 | + return do_rt_sigreturn_v2(env); | |
1490 | + } else { | |
1491 | + return do_rt_sigreturn_v1(env); | |
1492 | + } | |
1493 | +} | |
1494 | + | |
1369 | 1495 | #elif defined(TARGET_SPARC) |
1370 | 1496 | |
1371 | 1497 | #define __SUNOS_MAXWIN 31 | ... | ... |
linux-user/syscall.c
... | ... | @@ -3054,6 +3054,37 @@ static inline abi_long host_to_target_timespec(abi_ulong target_addr, |
3054 | 3054 | unlock_user_struct(target_ts, target_addr, 1); |
3055 | 3055 | } |
3056 | 3056 | |
3057 | +int get_osversion(void) | |
3058 | +{ | |
3059 | + static int osversion; | |
3060 | + struct new_utsname buf; | |
3061 | + const char *s; | |
3062 | + int i, n, tmp; | |
3063 | + if (osversion) | |
3064 | + return osversion; | |
3065 | + if (qemu_uname_release && *qemu_uname_release) { | |
3066 | + s = qemu_uname_release; | |
3067 | + } else { | |
3068 | + if (sys_uname(&buf)) | |
3069 | + return 0; | |
3070 | + s = buf.release; | |
3071 | + } | |
3072 | + tmp = 0; | |
3073 | + for (i = 0; i < 3; i++) { | |
3074 | + n = 0; | |
3075 | + while (*s >= '0' && *s <= '9') { | |
3076 | + n *= 10; | |
3077 | + n += *s - '0'; | |
3078 | + s++; | |
3079 | + } | |
3080 | + tmp = (tmp << 8) + n; | |
3081 | + if (*s == '.') | |
3082 | + s++; | |
3083 | + } | |
3084 | + osversion = tmp; | |
3085 | + return osversion; | |
3086 | +} | |
3087 | + | |
3057 | 3088 | /* do_syscall() should always have a single exit point at the end so |
3058 | 3089 | that actions, such as logging of syscall results, can be performed. |
3059 | 3090 | All errnos that do_syscall() returns must be -TARGET_<errcode>. */ | ... | ... |