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,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;