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>. */ | ... | ... |