Commit 88a8c98455cc28ef27f92fd0c6845cedf86d21fc
Committed by
Riku Voipio
1 parent
9ad197d9
Implement shm* syscalls and fix 64/32bit errors
No regressions were observed on either 64bit or 32bit IA hosts. Patch based on original patches by: Kirill A. Shutemov <kirill@shutemov.name> - Implement shm* syscalls - Fix and cleanup IPCOP_shm* ipc calls handling Depends on "export mmap_find_vma for shmat" patch. Various whitespace uglifications applied to minimize patch size. Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
Showing
1 changed file
with
250 additions
and
49 deletions
linux-user/syscall.c
@@ -1924,14 +1924,12 @@ static abi_long do_socketcall(int num, abi_ulong vptr) | @@ -1924,14 +1924,12 @@ static abi_long do_socketcall(int num, abi_ulong vptr) | ||
1924 | } | 1924 | } |
1925 | #endif | 1925 | #endif |
1926 | 1926 | ||
1927 | -#ifdef TARGET_NR_ipc | ||
1928 | #define N_SHM_REGIONS 32 | 1927 | #define N_SHM_REGIONS 32 |
1929 | 1928 | ||
1930 | static struct shm_region { | 1929 | static struct shm_region { |
1931 | abi_ulong start; | 1930 | abi_ulong start; |
1932 | abi_ulong size; | 1931 | abi_ulong size; |
1933 | } shm_regions[N_SHM_REGIONS]; | 1932 | } shm_regions[N_SHM_REGIONS]; |
1934 | -#endif | ||
1935 | 1933 | ||
1936 | struct target_ipc_perm | 1934 | struct target_ipc_perm |
1937 | { | 1935 | { |
@@ -2424,6 +2422,224 @@ end: | @@ -2424,6 +2422,224 @@ end: | ||
2424 | return ret; | 2422 | return ret; |
2425 | } | 2423 | } |
2426 | 2424 | ||
2425 | +struct target_shmid_ds | ||
2426 | +{ | ||
2427 | + struct target_ipc_perm shm_perm; | ||
2428 | + abi_ulong shm_segsz; | ||
2429 | + abi_ulong shm_atime; | ||
2430 | +#if TARGET_ABI_BITS == 32 | ||
2431 | + abi_ulong __unused1; | ||
2432 | +#endif | ||
2433 | + abi_ulong shm_dtime; | ||
2434 | +#if TARGET_ABI_BITS == 32 | ||
2435 | + abi_ulong __unused2; | ||
2436 | +#endif | ||
2437 | + abi_ulong shm_ctime; | ||
2438 | +#if TARGET_ABI_BITS == 32 | ||
2439 | + abi_ulong __unused3; | ||
2440 | +#endif | ||
2441 | + int shm_cpid; | ||
2442 | + int shm_lpid; | ||
2443 | + abi_ulong shm_nattch; | ||
2444 | + unsigned long int __unused4; | ||
2445 | + unsigned long int __unused5; | ||
2446 | +}; | ||
2447 | + | ||
2448 | +static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd, | ||
2449 | + abi_ulong target_addr) | ||
2450 | +{ | ||
2451 | + struct target_shmid_ds *target_sd; | ||
2452 | + | ||
2453 | + if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) | ||
2454 | + return -TARGET_EFAULT; | ||
2455 | + if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr)) | ||
2456 | + return -TARGET_EFAULT; | ||
2457 | + __get_user(host_sd->shm_segsz, &target_sd->shm_segsz); | ||
2458 | + __get_user(host_sd->shm_atime, &target_sd->shm_atime); | ||
2459 | + __get_user(host_sd->shm_dtime, &target_sd->shm_dtime); | ||
2460 | + __get_user(host_sd->shm_ctime, &target_sd->shm_ctime); | ||
2461 | + __get_user(host_sd->shm_cpid, &target_sd->shm_cpid); | ||
2462 | + __get_user(host_sd->shm_lpid, &target_sd->shm_lpid); | ||
2463 | + __get_user(host_sd->shm_nattch, &target_sd->shm_nattch); | ||
2464 | + unlock_user_struct(target_sd, target_addr, 0); | ||
2465 | + return 0; | ||
2466 | +} | ||
2467 | + | ||
2468 | +static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr, | ||
2469 | + struct shmid_ds *host_sd) | ||
2470 | +{ | ||
2471 | + struct target_shmid_ds *target_sd; | ||
2472 | + | ||
2473 | + if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) | ||
2474 | + return -TARGET_EFAULT; | ||
2475 | + if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm))) | ||
2476 | + return -TARGET_EFAULT; | ||
2477 | + __put_user(host_sd->shm_segsz, &target_sd->shm_segsz); | ||
2478 | + __put_user(host_sd->shm_atime, &target_sd->shm_atime); | ||
2479 | + __put_user(host_sd->shm_dtime, &target_sd->shm_dtime); | ||
2480 | + __put_user(host_sd->shm_ctime, &target_sd->shm_ctime); | ||
2481 | + __put_user(host_sd->shm_cpid, &target_sd->shm_cpid); | ||
2482 | + __put_user(host_sd->shm_lpid, &target_sd->shm_lpid); | ||
2483 | + __put_user(host_sd->shm_nattch, &target_sd->shm_nattch); | ||
2484 | + unlock_user_struct(target_sd, target_addr, 1); | ||
2485 | + return 0; | ||
2486 | +} | ||
2487 | + | ||
2488 | +struct target_shminfo { | ||
2489 | + abi_ulong shmmax; | ||
2490 | + abi_ulong shmmin; | ||
2491 | + abi_ulong shmmni; | ||
2492 | + abi_ulong shmseg; | ||
2493 | + abi_ulong shmall; | ||
2494 | +}; | ||
2495 | + | ||
2496 | +static inline abi_long host_to_target_shminfo(abi_ulong target_addr, | ||
2497 | + struct shminfo *host_shminfo) | ||
2498 | +{ | ||
2499 | + struct target_shminfo *target_shminfo; | ||
2500 | + if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0)) | ||
2501 | + return -TARGET_EFAULT; | ||
2502 | + __put_user(host_shminfo->shmmax, &target_shminfo->shmmax); | ||
2503 | + __put_user(host_shminfo->shmmin, &target_shminfo->shmmin); | ||
2504 | + __put_user(host_shminfo->shmmni, &target_shminfo->shmmni); | ||
2505 | + __put_user(host_shminfo->shmseg, &target_shminfo->shmseg); | ||
2506 | + __put_user(host_shminfo->shmall, &target_shminfo->shmall); | ||
2507 | + unlock_user_struct(target_shminfo, target_addr, 1); | ||
2508 | + return 0; | ||
2509 | +} | ||
2510 | + | ||
2511 | +struct target_shm_info { | ||
2512 | + int used_ids; | ||
2513 | + abi_ulong shm_tot; | ||
2514 | + abi_ulong shm_rss; | ||
2515 | + abi_ulong shm_swp; | ||
2516 | + abi_ulong swap_attempts; | ||
2517 | + abi_ulong swap_successes; | ||
2518 | +}; | ||
2519 | + | ||
2520 | +static inline abi_long host_to_target_shm_info(abi_ulong target_addr, | ||
2521 | + struct shm_info *host_shm_info) | ||
2522 | +{ | ||
2523 | + struct target_shm_info *target_shm_info; | ||
2524 | + if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0)) | ||
2525 | + return -TARGET_EFAULT; | ||
2526 | + __put_user(host_shm_info->used_ids, &target_shm_info->used_ids); | ||
2527 | + __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot); | ||
2528 | + __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss); | ||
2529 | + __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp); | ||
2530 | + __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts); | ||
2531 | + __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes); | ||
2532 | + unlock_user_struct(target_shm_info, target_addr, 1); | ||
2533 | + return 0; | ||
2534 | +} | ||
2535 | + | ||
2536 | +static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf) | ||
2537 | +{ | ||
2538 | + struct shmid_ds dsarg; | ||
2539 | + struct shminfo shminfo; | ||
2540 | + struct shm_info shm_info; | ||
2541 | + abi_long ret = -TARGET_EINVAL; | ||
2542 | + | ||
2543 | + cmd &= 0xff; | ||
2544 | + | ||
2545 | + switch(cmd) { | ||
2546 | + case IPC_STAT: | ||
2547 | + case IPC_SET: | ||
2548 | + case SHM_STAT: | ||
2549 | + if (target_to_host_shmid_ds(&dsarg, buf)) | ||
2550 | + return -TARGET_EFAULT; | ||
2551 | + ret = get_errno(shmctl(shmid, cmd, &dsarg)); | ||
2552 | + if (host_to_target_shmid_ds(buf, &dsarg)) | ||
2553 | + return -TARGET_EFAULT; | ||
2554 | + break; | ||
2555 | + case IPC_INFO: | ||
2556 | + ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo)); | ||
2557 | + if (host_to_target_shminfo(buf, &shminfo)) | ||
2558 | + return -TARGET_EFAULT; | ||
2559 | + break; | ||
2560 | + case SHM_INFO: | ||
2561 | + ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info)); | ||
2562 | + if (host_to_target_shm_info(buf, &shm_info)) | ||
2563 | + return -TARGET_EFAULT; | ||
2564 | + break; | ||
2565 | + case IPC_RMID: | ||
2566 | + case SHM_LOCK: | ||
2567 | + case SHM_UNLOCK: | ||
2568 | + ret = get_errno(shmctl(shmid, cmd, NULL)); | ||
2569 | + break; | ||
2570 | + } | ||
2571 | + | ||
2572 | + return ret; | ||
2573 | +} | ||
2574 | + | ||
2575 | +static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg) | ||
2576 | +{ | ||
2577 | + abi_long raddr; | ||
2578 | + void *host_raddr; | ||
2579 | + struct shmid_ds shm_info; | ||
2580 | + int i,ret; | ||
2581 | + | ||
2582 | + /* find out the length of the shared memory segment */ | ||
2583 | + ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info)); | ||
2584 | + if (is_error(ret)) { | ||
2585 | + /* can't get length, bail out */ | ||
2586 | + return ret; | ||
2587 | + } | ||
2588 | + | ||
2589 | + mmap_lock(); | ||
2590 | + | ||
2591 | + if (shmaddr) | ||
2592 | + host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg); | ||
2593 | + else { | ||
2594 | + abi_ulong mmap_start; | ||
2595 | + | ||
2596 | + mmap_start = mmap_find_vma(0, shm_info.shm_segsz); | ||
2597 | + | ||
2598 | + if (mmap_start == -1) { | ||
2599 | + errno = ENOMEM; | ||
2600 | + host_raddr = (void *)-1; | ||
2601 | + } else | ||
2602 | + host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP); | ||
2603 | + } | ||
2604 | + | ||
2605 | + if (host_raddr == (void *)-1) { | ||
2606 | + mmap_unlock(); | ||
2607 | + return get_errno((long)host_raddr); | ||
2608 | + } | ||
2609 | + raddr=h2g((unsigned long)host_raddr); | ||
2610 | + | ||
2611 | + page_set_flags(raddr, raddr + shm_info.shm_segsz, | ||
2612 | + PAGE_VALID | PAGE_READ | | ||
2613 | + ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE)); | ||
2614 | + | ||
2615 | + for (i = 0; i < N_SHM_REGIONS; i++) { | ||
2616 | + if (shm_regions[i].start == 0) { | ||
2617 | + shm_regions[i].start = raddr; | ||
2618 | + shm_regions[i].size = shm_info.shm_segsz; | ||
2619 | + break; | ||
2620 | + } | ||
2621 | + } | ||
2622 | + | ||
2623 | + mmap_unlock(); | ||
2624 | + return raddr; | ||
2625 | + | ||
2626 | +} | ||
2627 | + | ||
2628 | +static inline abi_long do_shmdt(abi_ulong shmaddr) | ||
2629 | +{ | ||
2630 | + int i; | ||
2631 | + | ||
2632 | + for (i = 0; i < N_SHM_REGIONS; ++i) { | ||
2633 | + if (shm_regions[i].start == shmaddr) { | ||
2634 | + shm_regions[i].start = 0; | ||
2635 | + page_set_flags(shmaddr, shm_regions[i].size, 0); | ||
2636 | + break; | ||
2637 | + } | ||
2638 | + } | ||
2639 | + | ||
2640 | + return get_errno(shmdt(g2h(shmaddr))); | ||
2641 | +} | ||
2642 | + | ||
2427 | #ifdef TARGET_NR_ipc | 2643 | #ifdef TARGET_NR_ipc |
2428 | /* ??? This only works with linear mappings. */ | 2644 | /* ??? This only works with linear mappings. */ |
2429 | /* do_ipc() must return target values and target errnos. */ | 2645 | /* do_ipc() must return target values and target errnos. */ |
@@ -2433,8 +2649,6 @@ static abi_long do_ipc(unsigned int call, int first, | @@ -2433,8 +2649,6 @@ static abi_long do_ipc(unsigned int call, int first, | ||
2433 | { | 2649 | { |
2434 | int version; | 2650 | int version; |
2435 | abi_long ret = 0; | 2651 | abi_long ret = 0; |
2436 | - struct shmid_ds shm_info; | ||
2437 | - int i; | ||
2438 | 2652 | ||
2439 | version = call >> 16; | 2653 | version = call >> 16; |
2440 | call &= 0xffff; | 2654 | call &= 0xffff; |
@@ -2489,48 +2703,24 @@ static abi_long do_ipc(unsigned int call, int first, | @@ -2489,48 +2703,24 @@ static abi_long do_ipc(unsigned int call, int first, | ||
2489 | break; | 2703 | break; |
2490 | 2704 | ||
2491 | case IPCOP_shmat: | 2705 | case IPCOP_shmat: |
2706 | + switch (version) { | ||
2707 | + default: | ||
2492 | { | 2708 | { |
2493 | abi_ulong raddr; | 2709 | abi_ulong raddr; |
2494 | - void *host_addr; | ||
2495 | - /* SHM_* flags are the same on all linux platforms */ | ||
2496 | - host_addr = shmat(first, (void *)g2h(ptr), second); | ||
2497 | - if (host_addr == (void *)-1) { | ||
2498 | - ret = get_errno((long)host_addr); | ||
2499 | - break; | ||
2500 | - } | ||
2501 | - raddr = h2g((unsigned long)host_addr); | ||
2502 | - /* find out the length of the shared memory segment */ | ||
2503 | - | ||
2504 | - ret = get_errno(shmctl(first, IPC_STAT, &shm_info)); | ||
2505 | - if (is_error(ret)) { | ||
2506 | - /* can't get length, bail out */ | ||
2507 | - shmdt(host_addr); | ||
2508 | - break; | ||
2509 | - } | ||
2510 | - page_set_flags(raddr, raddr + shm_info.shm_segsz, | ||
2511 | - PAGE_VALID | PAGE_READ | | ||
2512 | - ((second & SHM_RDONLY)? 0: PAGE_WRITE)); | ||
2513 | - for (i = 0; i < N_SHM_REGIONS; ++i) { | ||
2514 | - if (shm_regions[i].start == 0) { | ||
2515 | - shm_regions[i].start = raddr; | ||
2516 | - shm_regions[i].size = shm_info.shm_segsz; | ||
2517 | - break; | ||
2518 | - } | ||
2519 | - } | 2710 | + raddr = do_shmat(first, ptr, second); |
2711 | + if (is_error(raddr)) | ||
2712 | + return get_errno(raddr); | ||
2520 | if (put_user_ual(raddr, third)) | 2713 | if (put_user_ual(raddr, third)) |
2521 | return -TARGET_EFAULT; | 2714 | return -TARGET_EFAULT; |
2522 | - ret = 0; | 2715 | + break; |
2716 | + } | ||
2717 | + case 1: | ||
2718 | + ret = -TARGET_EINVAL; | ||
2719 | + break; | ||
2523 | } | 2720 | } |
2524 | break; | 2721 | break; |
2525 | case IPCOP_shmdt: | 2722 | case IPCOP_shmdt: |
2526 | - for (i = 0; i < N_SHM_REGIONS; ++i) { | ||
2527 | - if (shm_regions[i].start == ptr) { | ||
2528 | - shm_regions[i].start = 0; | ||
2529 | - page_set_flags(ptr, shm_regions[i].size, 0); | ||
2530 | - break; | ||
2531 | - } | ||
2532 | - } | ||
2533 | - ret = get_errno(shmdt((void *)g2h(ptr))); | 2723 | + ret = do_shmdt(ptr); |
2534 | break; | 2724 | break; |
2535 | 2725 | ||
2536 | case IPCOP_shmget: | 2726 | case IPCOP_shmget: |
@@ -2540,18 +2730,9 @@ static abi_long do_ipc(unsigned int call, int first, | @@ -2540,18 +2730,9 @@ static abi_long do_ipc(unsigned int call, int first, | ||
2540 | 2730 | ||
2541 | /* IPC_* and SHM_* command values are the same on all linux platforms */ | 2731 | /* IPC_* and SHM_* command values are the same on all linux platforms */ |
2542 | case IPCOP_shmctl: | 2732 | case IPCOP_shmctl: |
2543 | - switch(second) { | ||
2544 | - case IPC_RMID: | ||
2545 | - case SHM_LOCK: | ||
2546 | - case SHM_UNLOCK: | ||
2547 | - ret = get_errno(shmctl(first, second, NULL)); | ||
2548 | - break; | ||
2549 | - default: | ||
2550 | - goto unimplemented; | ||
2551 | - } | 2733 | + ret = do_shmctl(first, second, third); |
2552 | break; | 2734 | break; |
2553 | default: | 2735 | default: |
2554 | - unimplemented: | ||
2555 | gemu_log("Unsupported ipc call: %d (version %d)\n", call, version); | 2736 | gemu_log("Unsupported ipc call: %d (version %d)\n", call, version); |
2556 | ret = -TARGET_ENOSYS; | 2737 | ret = -TARGET_ENOSYS; |
2557 | break; | 2738 | break; |
@@ -5312,6 +5493,26 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, | @@ -5312,6 +5493,26 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, | ||
5312 | ret = do_msgsnd(arg1, arg2, arg3, arg4); | 5493 | ret = do_msgsnd(arg1, arg2, arg3, arg4); |
5313 | break; | 5494 | break; |
5314 | #endif | 5495 | #endif |
5496 | +#ifdef TARGET_NR_shmget | ||
5497 | + case TARGET_NR_shmget: | ||
5498 | + ret = get_errno(shmget(arg1, arg2, arg3)); | ||
5499 | + break; | ||
5500 | +#endif | ||
5501 | +#ifdef TARGET_NR_shmctl | ||
5502 | + case TARGET_NR_shmctl: | ||
5503 | + ret = do_shmctl(arg1, arg2, arg3); | ||
5504 | + break; | ||
5505 | +#endif | ||
5506 | +#ifdef TARGET_NR_shmat | ||
5507 | + case TARGET_NR_shmat: | ||
5508 | + ret = do_shmat(arg1, arg2, arg3); | ||
5509 | + break; | ||
5510 | +#endif | ||
5511 | +#ifdef TARGET_NR_shmdt | ||
5512 | + case TARGET_NR_shmdt: | ||
5513 | + ret = do_shmdt(arg1); | ||
5514 | + break; | ||
5515 | +#endif | ||
5315 | case TARGET_NR_fsync: | 5516 | case TARGET_NR_fsync: |
5316 | ret = get_errno(fsync(arg1)); | 5517 | ret = get_errno(fsync(arg1)); |
5317 | break; | 5518 | break; |