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