Commit 88a8c98455cc28ef27f92fd0c6845cedf86d21fc

Authored by Riku Voipio
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;
... ...