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 | 1924 | } |
1925 | 1925 | #endif |
1926 | 1926 | |
1927 | -#ifdef TARGET_NR_ipc | |
1928 | 1927 | #define N_SHM_REGIONS 32 |
1929 | 1928 | |
1930 | 1929 | static struct shm_region { |
1931 | 1930 | abi_ulong start; |
1932 | 1931 | abi_ulong size; |
1933 | 1932 | } shm_regions[N_SHM_REGIONS]; |
1934 | -#endif | |
1935 | 1933 | |
1936 | 1934 | struct target_ipc_perm |
1937 | 1935 | { |
... | ... | @@ -2424,6 +2422,224 @@ end: |
2424 | 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 | 2643 | #ifdef TARGET_NR_ipc |
2428 | 2644 | /* ??? This only works with linear mappings. */ |
2429 | 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 | 2649 | { |
2434 | 2650 | int version; |
2435 | 2651 | abi_long ret = 0; |
2436 | - struct shmid_ds shm_info; | |
2437 | - int i; | |
2438 | 2652 | |
2439 | 2653 | version = call >> 16; |
2440 | 2654 | call &= 0xffff; |
... | ... | @@ -2489,48 +2703,24 @@ static abi_long do_ipc(unsigned int call, int first, |
2489 | 2703 | break; |
2490 | 2704 | |
2491 | 2705 | case IPCOP_shmat: |
2706 | + switch (version) { | |
2707 | + default: | |
2492 | 2708 | { |
2493 | 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 | 2713 | if (put_user_ual(raddr, third)) |
2521 | 2714 | return -TARGET_EFAULT; |
2522 | - ret = 0; | |
2715 | + break; | |
2716 | + } | |
2717 | + case 1: | |
2718 | + ret = -TARGET_EINVAL; | |
2719 | + break; | |
2523 | 2720 | } |
2524 | 2721 | break; |
2525 | 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 | 2724 | break; |
2535 | 2725 | |
2536 | 2726 | case IPCOP_shmget: |
... | ... | @@ -2540,18 +2730,9 @@ static abi_long do_ipc(unsigned int call, int first, |
2540 | 2730 | |
2541 | 2731 | /* IPC_* and SHM_* command values are the same on all linux platforms */ |
2542 | 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 | 2734 | break; |
2553 | 2735 | default: |
2554 | - unimplemented: | |
2555 | 2736 | gemu_log("Unsupported ipc call: %d (version %d)\n", call, version); |
2556 | 2737 | ret = -TARGET_ENOSYS; |
2557 | 2738 | break; |
... | ... | @@ -5312,6 +5493,26 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, |
5312 | 5493 | ret = do_msgsnd(arg1, arg2, arg3, arg4); |
5313 | 5494 | break; |
5314 | 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 | 5516 | case TARGET_NR_fsync: |
5316 | 5517 | ret = get_errno(fsync(arg1)); |
5317 | 5518 | break; | ... | ... |