File:  [Qemu by Fabrice Bellard] / qemu / darwin-user / commpage.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:55:05 2018 UTC (3 years, 3 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu0105, qemu0104, qemu0103, qemu0102, qemu0101, qemu0100, HEAD
qemu 0.10.0

    1:  /*
    2:  *  Commpage syscalls
    3:  *
    4:  *  Copyright (c) 2006 Pierre d'Herbemont
    5:  *
    6:  *  This program is free software; you can redistribute it and/or modify
    7:  *  it under the terms of the GNU General Public License as published by
    8:  *  the Free Software Foundation; either version 2 of the License, or
    9:  *  (at your option) any later version.
   10:  *
   11:  *  This program is distributed in the hope that it will be useful,
   12:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   13:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14:  *  GNU General Public License for more details.
   15:  *
   16:  *  You should have received a copy of the GNU General Public License
   17:  *  along with this program; if not, write to the Free Software
   18:  *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   19:  *  MA 02110-1301, USA.
   20:  */
   21: #include <fcntl.h>
   22: #include <stdio.h>
   23: #include <stdlib.h>
   24: #include <errno.h>
   25: 
   26: #include <mach/message.h>
   27: #include <mach/mach.h>
   28: #include <mach/mach_time.h>
   29: #include <sys/time.h>
   30: #include <sys/mman.h>
   31: #include <libkern/OSAtomic.h>
   32: 
   33: #include "qemu.h"
   34: 
   35: //#define DEBUG_COMMPAGE
   36: 
   37: #ifdef DEBUG_COMMPAGE
   38: # define DPRINTF(...) do { qemu_log(__VA_ARGS__); printf(__VA_ARGS__); } while(0)
   39: #else
   40: # define DPRINTF(...) do { qemu_log(__VA_ARGS__); } while(0)
   41: #endif
   42: 
   43: /********************************************************************
   44:  *   Commpage definitions
   45:  */
   46: #ifdef TARGET_I386
   47: /* Reserve space for the commpage see xnu/osfmk/i386/cpu_capabilities.h */
   48: # define COMMPAGE_START (-16 * 4096) /* base address is -20 * 4096 */
   49: # define COMMPAGE_SIZE  (0x1240) /* _COMM_PAGE_AREA_LENGTH is 19 * 4096 */
   50: #elif defined(TARGET_PPC)
   51: /* Reserve space for the commpage see xnu/osfmk/ppc/cpu_capabilities.h */
   52: # define COMMPAGE_START (-8*4096)
   53: # define COMMPAGE_SIZE  (2*4096) /* its _COMM_PAGE_AREA_USED but _COMM_PAGE_AREA_LENGTH is 7*4096 */
   54: #endif
   55: 
   56: void do_compare_and_swap32(void *cpu_env, int num);
   57: void do_compare_and_swap64(void *cpu_env, int num);
   58: void do_add_atomic_word32(void *cpu_env, int num);
   59: void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1);
   60: void do_nanotime(void *cpu_env, int num);
   61: 
   62: void unimpl_commpage(void *cpu_env, int num);
   63: 
   64: typedef void (*commpage_8args_function_t)(uint32_t arg1, uint32_t arg2, uint32_t arg3,
   65:                 uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
   66:                 uint32_t arg8);
   67: typedef void (*commpage_indirect_function_t)(void *cpu_env, int num, uint32_t arg1,
   68:                 uint32_t arg2, uint32_t arg3,  uint32_t arg4, uint32_t arg5,
   69:                 uint32_t arg6, uint32_t arg7, uint32_t arg8);
   70: 
   71: #define HAS_PTR  0x10
   72: #define NO_PTR   0x20
   73: #define CALL_DIRECT   0x1
   74: #define CALL_INDIRECT 0x2
   75: 
   76: #define COMMPAGE_ENTRY(name, nargs, offset, func, options) \
   77:     { #name, offset, nargs, options, (commpage_8args_function_t)func }
   78: 
   79: struct commpage_entry {
   80:     char * name;
   81:     int offset;
   82:     int nargs;
   83:     char options;
   84:     commpage_8args_function_t function;
   85: };
   86: 
   87: static inline int commpage_code_num(struct commpage_entry *entry)
   88: {
   89:     if((entry->options & HAS_PTR))
   90:         return entry->offset + 4;
   91:     else
   92:         return entry->offset;
   93: }
   94: 
   95: static inline int commpage_is_indirect(struct commpage_entry *entry)
   96: {
   97:     return !(entry->options & CALL_DIRECT);
   98: }
   99: 
  100: /********************************************************************
  101:  *   Commpage entry
  102:  */
  103: static struct commpage_entry commpage_entries[] =
  104: {
  105:     COMMPAGE_ENTRY(compare_and_swap32,    0, 0x080,  do_compare_and_swap32, CALL_INDIRECT | HAS_PTR),
  106:     COMMPAGE_ENTRY(compare_and_swap64,    0, 0x0c0,  do_compare_and_swap64, CALL_INDIRECT | HAS_PTR),
  107:     COMMPAGE_ENTRY(enqueue,               0, 0x100,  unimpl_commpage,       CALL_INDIRECT),
  108:     COMMPAGE_ENTRY(dequeue,               0, 0x140,  unimpl_commpage,       CALL_INDIRECT),
  109:     COMMPAGE_ENTRY(memory_barrier,        0, 0x180,  unimpl_commpage,       CALL_INDIRECT),
  110:     COMMPAGE_ENTRY(add_atomic_word32,     0, 0x1a0,  do_add_atomic_word32,  CALL_INDIRECT | HAS_PTR),
  111:     COMMPAGE_ENTRY(add_atomic_word64,     0, 0x1c0,  unimpl_commpage,       CALL_INDIRECT | HAS_PTR),
  112: 
  113:     COMMPAGE_ENTRY(mach_absolute_time,    0, 0x200,  unimpl_commpage,       CALL_INDIRECT),
  114:     COMMPAGE_ENTRY(spinlock_try,          1, 0x220,  unimpl_commpage,       CALL_INDIRECT),
  115:     COMMPAGE_ENTRY(spinlock_lock,         1, 0x260,  OSSpinLockLock,        CALL_DIRECT),
  116:     COMMPAGE_ENTRY(spinlock_unlock,       1, 0x2a0,  OSSpinLockUnlock,      CALL_DIRECT),
  117:     COMMPAGE_ENTRY(pthread_getspecific,   0, 0x2c0,  unimpl_commpage,       CALL_INDIRECT),
  118:     COMMPAGE_ENTRY(gettimeofday,          1, 0x2e0,  do_cgettimeofday,      CALL_INDIRECT),
  119:     COMMPAGE_ENTRY(sys_dcache_flush,      0, 0x4e0,  unimpl_commpage,       CALL_INDIRECT),
  120:     COMMPAGE_ENTRY(sys_icache_invalidate, 0, 0x520,  unimpl_commpage,       CALL_INDIRECT),
  121:     COMMPAGE_ENTRY(pthread_self,          0, 0x580,  unimpl_commpage,       CALL_INDIRECT),
  122: 
  123:     COMMPAGE_ENTRY(relinquish,            0, 0x5c0,  unimpl_commpage,       CALL_INDIRECT),
  124: 
  125: #ifdef TARGET_I386
  126:     COMMPAGE_ENTRY(bts,                   0, 0x5e0,  unimpl_commpage,       CALL_INDIRECT),
  127:     COMMPAGE_ENTRY(btc,                   0, 0x5f0,  unimpl_commpage,       CALL_INDIRECT),
  128: #endif
  129: 
  130:     COMMPAGE_ENTRY(bzero,                 2, 0x600,  bzero,                 CALL_DIRECT),
  131:     COMMPAGE_ENTRY(bcopy,                 3, 0x780,  bcopy,                 CALL_DIRECT),
  132:     COMMPAGE_ENTRY(memcpy,                3, 0x7a0,  memcpy,                CALL_DIRECT),
  133: 
  134: #ifdef TARGET_I386
  135:     COMMPAGE_ENTRY(old_nanotime,          0, 0xf80,  do_nanotime,           CALL_INDIRECT),
  136:     COMMPAGE_ENTRY(memset_pattern,        0, 0xf80,  unimpl_commpage,       CALL_INDIRECT),
  137:     COMMPAGE_ENTRY(long_copy,             0, 0x1200, unimpl_commpage,       CALL_INDIRECT),
  138: 
  139:     COMMPAGE_ENTRY(sysintegrity,          0, 0x1600, unimpl_commpage,       CALL_INDIRECT),
  140: 
  141:     COMMPAGE_ENTRY(nanotime,              0, 0x1700, do_nanotime,           CALL_INDIRECT),
  142: #elif TARGET_PPC
  143:     COMMPAGE_ENTRY(compare_and_swap32b,   0, 0xf80,  unimpl_commpage,       CALL_INDIRECT),
  144:     COMMPAGE_ENTRY(compare_and_swap64b,   0, 0xfc0,  unimpl_commpage,       CALL_INDIRECT),
  145:     COMMPAGE_ENTRY(memset_pattern,        0, 0x1000, unimpl_commpage,       CALL_INDIRECT),
  146:     COMMPAGE_ENTRY(bigcopy,               0, 0x1140, unimpl_commpage,       CALL_INDIRECT),
  147: #endif
  148: };
  149: 
  150: 
  151: /********************************************************************
  152:  *   Commpage backdoor
  153:  */
  154: static inline void print_commpage_entry(struct commpage_entry entry)
  155: {
  156:     printf("@0x%x %s\n", entry.offset, entry.name);
  157: }
  158: 
  159: static inline void install_commpage_backdoor_for_entry(struct commpage_entry entry)
  160: {
  161: #ifdef TARGET_I386
  162:     char * commpage = (char*)(COMMPAGE_START+entry.offset);
  163:     int c = 0;
  164:     if(entry.options & HAS_PTR)
  165:     {
  166:         commpage[c++] = (COMMPAGE_START+entry.offset+4) & 0xff;
  167:         commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 8) & 0xff;
  168:         commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 16) & 0xff;
  169:         commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 24) & 0xff;
  170:     }
  171:     commpage[c++] = 0xcd;
  172:     commpage[c++] = 0x79; /* int 0x79 */
  173:     commpage[c++] = 0xc3; /* ret */
  174: #else
  175:     qerror("can't install the commpage on this arch\n");
  176: #endif
  177: }
  178: 
  179: /********************************************************************
  180:  *   Commpage initialization
  181:  */
  182: void commpage_init(void)
  183: {
  184: #if (defined(__i386__) ^ defined(TARGET_I386)) || (defined(_ARCH_PPC) ^ defined(TARGET_PPC))
  185:     int i;
  186:     void * commpage = (void *)target_mmap( COMMPAGE_START, COMMPAGE_SIZE,
  187:                            PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_FIXED, -1, 0);
  188:     if((int)commpage != COMMPAGE_START)
  189:         qerror("can't allocate the commpage\n");
  190: 
  191:     bzero(commpage, COMMPAGE_SIZE);
  192: 
  193:     /* XXX: commpage data not handled */
  194: 
  195:     for(i = 0; i < ARRAY_SIZE(commpage_entries); i++)
  196:         install_commpage_backdoor_for_entry(commpage_entries[i]);
  197: #else
  198:     /* simply map our pages so they can be executed
  199:        XXX: we don't really want to do that since in the ppc on ppc situation we may
  200:        not able to run commpages host optimized instructions (like G5's on a G5),
  201:        hence this is sometimes a broken fix. */
  202:     page_set_flags(COMMPAGE_START, COMMPAGE_START+COMMPAGE_SIZE, PROT_EXEC | PROT_READ | PAGE_VALID);
  203: #endif
  204: }
  205: 
  206: /********************************************************************
  207:  *   Commpage implementation
  208:  */
  209: void do_compare_and_swap32(void *cpu_env, int num)
  210: {
  211: #ifdef TARGET_I386
  212:     uint32_t old = ((CPUX86State*)cpu_env)->regs[R_EAX];
  213:     uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_ECX];
  214:     DPRINTF("commpage: compare_and_swap32(%x,new,%p)\n", old, value);
  215: 
  216:     if(value && old == tswap32(*value))
  217:     {
  218:         uint32_t new = ((CPUX86State*)cpu_env)->regs[R_EDX];
  219:         *value = tswap32(new);
  220:         /* set zf flag */
  221:         ((CPUX86State*)cpu_env)->eflags |= 0x40;
  222:     }
  223:     else
  224:     {
  225:         ((CPUX86State*)cpu_env)->regs[R_EAX] = tswap32(*value);
  226:         /* unset zf flag */
  227:         ((CPUX86State*)cpu_env)->eflags &= ~0x40;
  228:     }
  229: #else
  230:     qerror("do_compare_and_swap32 unimplemented");
  231: #endif
  232: }
  233: 
  234: void do_compare_and_swap64(void *cpu_env, int num)
  235: {
  236: #ifdef TARGET_I386
  237:     /* OSAtomicCompareAndSwap64 is not available on non 64 bits ppc, here is a raw implementation */
  238:     uint64_t old, new, swapped_val;
  239:     uint64_t *value = (uint64_t*)((CPUX86State*)cpu_env)->regs[R_ESI];
  240:     old = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_EDX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EAX];
  241: 
  242:     DPRINTF("commpage: compare_and_swap64(%llx,new,%p)\n", old, value);
  243:     swapped_val = tswap64(*value);
  244: 
  245:     if(old == swapped_val)
  246:     {
  247:         new = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_ECX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EBX];
  248:         *value = tswap64(new);
  249:         /* set zf flag */
  250:         ((CPUX86State*)cpu_env)->eflags |= 0x40;
  251:     }
  252:     else
  253:     {
  254:         ((CPUX86State*)cpu_env)->regs[R_EAX] = (uint32_t)(swapped_val);
  255:         ((CPUX86State*)cpu_env)->regs[R_EDX] = (uint32_t)(swapped_val >> 32);
  256:         /* unset zf flag */
  257:         ((CPUX86State*)cpu_env)->eflags &= ~0x40;
  258:     }
  259: #else
  260:     qerror("do_compare_and_swap64 unimplemented");
  261: #endif
  262: }
  263: 
  264: void do_add_atomic_word32(void *cpu_env, int num)
  265: {
  266: #ifdef TARGET_I386
  267:     uint32_t amt = ((CPUX86State*)cpu_env)->regs[R_EAX];
  268:     uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_EDX];
  269:     uint32_t swapped_value = tswap32(*value);
  270: 
  271:     DPRINTF("commpage: add_atomic_word32(%x,%p)\n", amt, value);
  272: 
  273:     /* old value in EAX */
  274:     ((CPUX86State*)cpu_env)->regs[R_EAX] = swapped_value;
  275:     *value = tswap32(swapped_value + amt);
  276: #else
  277:     qerror("do_add_atomic_word32 unimplemented");
  278: #endif
  279: }
  280: 
  281: void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1)
  282: {
  283: #ifdef TARGET_I386
  284:     extern int __commpage_gettimeofday(struct timeval *);
  285:     DPRINTF("commpage: gettimeofday(0x%x)\n", arg1);
  286:     struct timeval *time = (struct timeval *)arg1;
  287:     int ret = __commpage_gettimeofday(time);
  288:     tswap32s((uint32_t*)&time->tv_sec);
  289:     tswap32s((uint32_t*)&time->tv_usec);
  290:     ((CPUX86State*)cpu_env)->regs[R_EAX] = ret; /* Success */
  291: #else
  292:     qerror("do_gettimeofday unimplemented");
  293: #endif
  294: }
  295: 
  296: void do_nanotime(void *cpu_env, int num)
  297: {
  298: #ifdef TARGET_I386
  299:     uint64_t t = mach_absolute_time();
  300:     ((CPUX86State*)cpu_env)->regs[R_EAX] = (int)(t & 0xffffffff);
  301:     ((CPUX86State*)cpu_env)->regs[R_EDX] = (int)((t >> 32) & 0xffffffff);
  302: #else
  303:     qerror("do_nanotime unimplemented");
  304: #endif
  305: }
  306: 
  307: void unimpl_commpage(void *cpu_env, int num)
  308: {
  309:     qerror("qemu: commpage function 0x%x not implemented\n", num);
  310: }
  311: 
  312: /********************************************************************
  313:  *   do_commpage - called by the main cpu loop
  314:  */
  315: void
  316: do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
  317:                 uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
  318:                 uint32_t arg8)
  319: {
  320:     int i, found = 0;
  321: 
  322:     arg1 = tswap32(arg1);
  323:     arg2 = tswap32(arg2);
  324:     arg3 = tswap32(arg3);
  325:     arg4 = tswap32(arg4);
  326:     arg5 = tswap32(arg5);
  327:     arg6 = tswap32(arg6);
  328:     arg7 = tswap32(arg7);
  329:     arg8 = tswap32(arg8);
  330: 
  331:     num = num-COMMPAGE_START-2;
  332: 
  333:     for(i = 0; i < ARRAY_SIZE(commpage_entries); i++) {
  334:         if( num == commpage_code_num(&commpage_entries[i]) )
  335:         {
  336:             DPRINTF("commpage: %s %s\n", commpage_entries[i].name, commpage_is_indirect(&commpage_entries[i]) ? "[indirect]" : "[direct]");
  337:             found = 1;
  338:             if(commpage_is_indirect(&commpage_entries[i]))
  339:             {
  340:                 commpage_indirect_function_t function = (commpage_indirect_function_t)commpage_entries[i].function;
  341:                 function(cpu_env, num, arg1, arg2, arg3,
  342:                     arg4, arg5, arg6, arg7, arg8);
  343:             }
  344:             else
  345:             {
  346:                 commpage_entries[i].function(arg1, arg2, arg3,
  347:                     arg4, arg5, arg6, arg7, arg8);
  348:             }
  349:             break;
  350:         }
  351:     }
  352: 
  353:     if(!found)
  354:     {
  355:         gemu_log("qemu: commpage function 0x%x not defined\n", num);
  356:         gdb_handlesig (cpu_env, SIGTRAP);
  357:         exit(-1);
  358:     }
  359: }

unix.superglobalmegacorp.com