From: notaz Date: Sun, 15 Aug 2010 21:44:00 +0000 (+0300) Subject: pnd release 3. X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7000b522095b21ba16784d02997835d74ecc3375;p=ginge.git pnd release 3. Preliminary Wiz support, exec* handling, kill button, random fixes. --- diff --git a/common/host_fb.c b/common/host_fb.c index 94910ec..f577bb9 100644 --- a/common/host_fb.c +++ b/common/host_fb.c @@ -49,7 +49,12 @@ void host_video_finish(void) fbdev = NULL; } -void host_video_update_pal(unsigned int *pal) +void host_video_update_pal16(unsigned short *pal) +{ + memcpy(host_pal, pal, sizeof(host_pal)); +} + +void host_video_update_pal32(unsigned int *pal) { unsigned short *dstp = host_pal; int i; @@ -64,47 +69,47 @@ void host_video_change_bpp(int bpp) { } -void host_video_blit4(const unsigned char *src, int w, int h) +void host_video_blit4(const unsigned char *src, int w, int h, int stride) { unsigned short *dst = host_screen; unsigned short *hpal = host_pal; int i, u; - for (i = 0; i < 240; i++, dst += host_stride / 2 - 320) { - for (u = 320 / 2; u > 0; u--, src++) { - *dst++ = hpal[*src >> 4]; - *dst++ = hpal[*src & 0x0f]; + for (i = 0; i < 240; i++, dst += host_stride / 2, src += stride) { + for (u = 0; i < w / 2; u++) { + dst[u*2 + 0] = hpal[src[u] >> 4]; + dst[u*2 + 1] = hpal[src[u] & 0x0f]; } } host_video_flip(); } -void host_video_blit8(const unsigned char *src, int w, int h) +void host_video_blit8(const unsigned char *src, int w, int h, int stride) { unsigned short *dst = host_screen; unsigned short *hpal = host_pal; int i, u; - for (i = 0; i < 240; i++, dst += host_stride / 2 - 320) { - for (u = 320 / 4; u > 0; u--) { - *dst++ = hpal[*src++]; - *dst++ = hpal[*src++]; - *dst++ = hpal[*src++]; - *dst++ = hpal[*src++]; + for (i = 0; i < 240; i++, dst += host_stride / 2, src += stride) { + for (u = 0; u < w; u += 4) { + dst[u + 0] = hpal[src[u + 0]]; + dst[u + 1] = hpal[src[u + 1]]; + dst[u + 2] = hpal[src[u + 2]]; + dst[u + 3] = hpal[src[u + 3]]; } } host_video_flip(); } -void host_video_blit16(const unsigned short *src, int w, int h) +void host_video_blit16(const unsigned short *src, int w, int h, int stride) { unsigned short *dst = host_screen; int i; - for (i = 0; i < 240; i++, dst += host_stride / 2, src += 320) - memcpy(dst, src, 320*2); + for (i = 0; i < 240; i++, dst += host_stride / 2, src += stride / 2) + memcpy(dst, src, w*2); host_video_flip(); } @@ -143,9 +148,14 @@ void host_video_finish(void) vout_gp2x_finish(); } -void host_video_update_pal(unsigned int *pal) +void host_video_update_pal16(unsigned short *pal) +{ + vout_gp2x_set_palette16(pal, 256); +} + +void host_video_update_pal32(unsigned int *pal) { - vout_gp2x_set_palette(pal, 256); + vout_gp2x_set_palette32(pal, 256); } void host_video_change_bpp(int bpp) @@ -154,13 +164,13 @@ void host_video_change_bpp(int bpp) } #ifdef LOADER -void host_video_blit4(const unsigned char *src, int w, int h) +void host_video_blit4(const unsigned char *src, int w, int h, int stride) { memcpy(host_screen, src, 320*240/2); // FIXME host_video_flip(); } -void host_video_blit8(const unsigned char *src, int w, int h) +void host_video_blit8(const unsigned char *src, int w, int h, int stride) { extern void rotated_blit8(void *dst, const void *linesx4); @@ -168,7 +178,7 @@ void host_video_blit8(const unsigned char *src, int w, int h) host_video_flip(); } -void host_video_blit16(const unsigned short *src, int w, int h) +void host_video_blit16(const unsigned short *src, int w, int h, int stride) { extern void rotated_blit16(void *dst, const void *linesx4); diff --git a/common/host_fb.h b/common/host_fb.h index 1fcfdc3..9a1c1f8 100644 --- a/common/host_fb.h +++ b/common/host_fb.h @@ -2,8 +2,11 @@ int host_video_init(int *stride, int no_dblbuf); void host_video_finish(void); void *host_video_flip(void); void host_video_change_bpp(int bpp); -void host_video_update_pal(unsigned int *pal); -void host_video_blit4(const unsigned char *src, int w, int h); -void host_video_blit8(const unsigned char *src, int w, int h); -void host_video_blit16(const unsigned short *src, int w, int h); +// these are mutually exclusive +void host_video_update_pal16(unsigned short *pal); +void host_video_update_pal32(unsigned int *pal); + +void host_video_blit4(const unsigned char *src, int w, int h, int stride); +void host_video_blit8(const unsigned char *src, int w, int h, int stride); +void host_video_blit16(const unsigned short *src, int w, int h, int stride); diff --git a/common/wiz_video.c b/common/wiz_video.c index 121f89a..657e4af 100644 --- a/common/wiz_video.c +++ b/common/wiz_video.c @@ -141,7 +141,14 @@ static void vout_gp2x_set_mode(int bpp, int rot) memregl[0x4058>>2] = r; } -static void vout_gp2x_set_palette(unsigned int *pal, int len) +static void vout_gp2x_set_palette16(unsigned short *pal, int len) +{ + int i; + for (i = 0; i < len; i++) + memregl[0x4070>>2] = (i << 24) | pal[i]; +} + +static void vout_gp2x_set_palette32(unsigned int *pal, int len) { /* pollux palette is 16bpp only.. */ int i; diff --git a/dist/ginge.gpe b/dist/ginge.gpe index bb80392..5e06e1d 100755 --- a/dist/ginge.gpe +++ b/dist/ginge.gpe @@ -5,6 +5,11 @@ unset LD_PRELOAD /sbin/rmmod warm 2> /dev/null /sbin/insmod ./tools/warm_2.6.24.ko +# we might write something to /tmp, no need to write to flash +if ! grep -q '/tmp' /proc/mounts; then + mount -t tmpfs none /tmp +fi + # theoretically GP2X apps can make use of more RAM, because # Wiz has 2.6 kernel (larger memory requirements) and larger # reserved areas, so we mount some swap here just in case. @@ -14,6 +19,7 @@ swapon swapfile ./gp2xmenu --view-game swapoff swapfile +umount /tmp /sbin/rmmod warm 2> /dev/null cd /usr/gp2x/ diff --git a/dist/make_cmn.sh b/dist/make_cmn.sh index 486f949..4e9f3c3 100755 --- a/dist/make_cmn.sh +++ b/dist/make_cmn.sh @@ -11,7 +11,6 @@ rm -rf $1 mkdir $1 cp gp2xmenu/gp2xmenu $1/ cp -r gp2xmenu/gp2xmenu_data $1/ -cp prep/ginge_prep $1/ cp loader/ginge_dyn $1/ cp loader/ginge_sloader $1/ cp readme.txt $1/ diff --git a/loader/dl.c b/loader/dl.c index 468a2e0..b12c921 100644 --- a/loader/dl.c +++ b/loader/dl.c @@ -75,6 +75,7 @@ static void ginge_init(void) // remove self from preload, further commands (from system() and such) // will be handled by ginge_prep. unsetenv("LD_PRELOAD"); + unsetenv("LD_LIBRARY_PATH"); emu_init((void *)lowest_segment); } diff --git a/loader/emu.c b/loader/emu.c index 571c3b0..dd507ff 100644 --- a/loader/emu.c +++ b/loader/emu.c @@ -87,9 +87,10 @@ static struct { #define CTRL_TRANSPARENCYENB (1 << 11) static struct { + // mmsp2 u16 mlc_stl_cntl; union { - u32 mlc_stl_adr; + u32 mlc_stl_adr; // mlcaddress for pollux struct { u16 mlc_stl_adrl; u16 mlc_stl_adrh; @@ -101,12 +102,26 @@ static struct { u32 mlc_stl_pallt_d32[256]; }; + // pollux + u32 mlccontrol; + u16 mlcpalette[256]; + // state void *umem; u32 old_mlc_stl_adr; - u32 btn_state; // as seen through /dev/GPIO - u32 dirty_pal:1; + u32 btn_state; // as seen through /dev/GPIO: 0PVdVu YXBA RLSeSt 0Ri0Dn 0Le0Up + struct { + u32 width, height; + u32 stride; + u32 bpp; + u32 dirty_pal:2; + } v; } mmsp2; +#define pollux mmsp2 // so that code doesn't look that weird +enum { + DIRTY_PAL_MMSP2 = 1, + DIRTY_PAL_POLLUX = 2, +}; #if defined(LOG_IO) || defined(LOG_IO_UNK) @@ -267,14 +282,17 @@ bad_blit: } // FIXME: pass real dimensions to blitters -static void mlc_flip(void *src, int bpp) +static void mlc_flip(void *src, int bpp, int stride) { static int old_bpp; // only pass pal to host if it's dirty - if (bpp <= 8 && mmsp2.dirty_pal) { - host_video_update_pal(mmsp2.mlc_stl_pallt_d32); - mmsp2.dirty_pal = 0; + if (bpp <= 8 && mmsp2.v.dirty_pal) { + if (mmsp2.v.dirty_pal == DIRTY_PAL_MMSP2) + host_video_update_pal32(mmsp2.mlc_stl_pallt_d32); + else + host_video_update_pal16(mmsp2.mlcpalette); + mmsp2.v.dirty_pal = 0; } if (bpp != old_bpp) { @@ -284,15 +302,15 @@ static void mlc_flip(void *src, int bpp) switch (bpp) { case 4: - host_video_blit4(src, 320, 240); + host_video_blit4(src, 320, 240, stride); break; case 8: - host_video_blit8(src, 320, 240); + host_video_blit8(src, 320, 240, stride); break; case 16: - host_video_blit16(src, 320, 240); + host_video_blit16(src, 320, 240, stride); break; case 24: @@ -315,6 +333,7 @@ static void *fb_sync_thread(void *arg) { int invalid_fb_addr = 1; int manual_refresh = 0; + int frame_counter = 0; struct timespec ts; int ret, wait_ret; @@ -331,7 +350,6 @@ static void *fb_sync_thread(void *arg) while (1) { u8 *gp2x_fb, *gp2x_fb_end; - int mode, bpp; ret = pthread_mutex_lock(&fb_mutex); wait_ret = pthread_cond_timedwait(&fb_cond, &fb_mutex, &ts); @@ -340,16 +358,16 @@ static void *fb_sync_thread(void *arg) if (ret != 0) { err("fb_thread: mutex error: %d\n", ret); sleep(1); - continue; + goto check_keys; } if (wait_ret != 0 && wait_ret != ETIMEDOUT) { err("fb_thread: cond error: %d\n", wait_ret); sleep(1); - continue; + goto check_keys; } if (fb_sync_thread_paused) { ts_add_nsec(ts, 100000000); - continue; + goto check_keys; } if (wait_ret != ETIMEDOUT) { @@ -365,11 +383,8 @@ static void *fb_sync_thread(void *arg) manual_refresh = 0; } - mode = (mmsp2.mlc_stl_cntl >> 9) & 3; - bpp = mode ? mode * 8 : 4; - gp2x_fb = uppermem_lookup(mmsp2.mlc_stl_adr, &gp2x_fb_end); - if (gp2x_fb == NULL || gp2x_fb + 320*240 * bpp / 8 > gp2x_fb_end) { + if (gp2x_fb == NULL || gp2x_fb + 320*240 * mmsp2.v.bpp / 8 > gp2x_fb_end) { if (!invalid_fb_addr) { err("fb_thread: %08x is out of range\n", mmsp2.mlc_stl_adr); invalid_fb_addr = 1; @@ -377,7 +392,17 @@ static void *fb_sync_thread(void *arg) continue; } - mlc_flip(gp2x_fb, bpp); + invalid_fb_addr = 0; + mlc_flip(gp2x_fb, mmsp2.v.bpp, mmsp2.v.stride); + + frame_counter++; + if (frame_counter & 0x0f) + continue; + +check_keys: + // this is to check for kill key, in case main thread hung + // or something else went wrong. + pollux.btn_state = host_read_btns(); } } @@ -394,6 +419,50 @@ static void fb_thread_resume(void) fb_sync_thread_paused = 0; } +static u32 xread32_io_cmn(u32 a, u32 *handled) +{ + u32 d = 0; + + *handled = 1; + switch (a) { + // Wiz stuff + case 0x402c: // MLCVSTRIDE0 + case 0x4060: // MLCVSTRIDE1 + d = pollux.v.stride; + break; + case 0x4038: // MLCADDRESS0 + case 0x406c: // MLCADDRESS1 + d = pollux.mlc_stl_adr; + break; + // wiz_lib reads: + // ???? ???? YXBA DURiLe ???? VdVuMS LR?? ???? + // | GPIOC[31:16] | GPIOB[31:16] | + case 0xa058: // GPIOBPAD + d = pollux.btn_state & 0x0300; + d |= (pollux.btn_state >> 3) & 0x0080; + d |= (pollux.btn_state >> 5) & 0x0040; + d |= (pollux.btn_state >> 6) & 0x0c00; + d <<= 16; + d = ~d; + break; + case 0xa098: // GPIOCPAD + pollux.btn_state = host_read_btns(); + d = (pollux.btn_state >> 8) & 0x00f0; + d |= (pollux.btn_state >> 1) & 0x0008; + d |= (pollux.btn_state << 2) & 0x0004; + d |= (pollux.btn_state >> 5) & 0x0002; + d |= (pollux.btn_state >> 2) & 0x0001; + d <<= 16; + d = ~d; + break; + default: + *handled = 0; + break; + } + + return d; +} + static u32 xread8(u32 a) { iolog("r8 ", a, 0, 8); @@ -414,8 +483,8 @@ static u32 xread16(u32 a) d = 0x9407; break; // minilib reads as: - // 0000 P000 VuVd00 0000 YXBA RLSeSt 0R0D 0L0U - // | GPIOD |GPIOC[8:15]|GPIOM[0:7]| + // 0000 P000 VuVd00 0000 YXBA RLSeSt 0Ri0D 0Le0U + // | GPIOD |GPIOC[8:15]|GPIOM[0:7] | // /dev/GPIO: // ... 0PVdVu ... case 0x1184: // GPIOC @@ -457,13 +526,19 @@ static u32 xread16(u32 a) case 0x2958: d = mmsp2.mlc_stl_pallt_a; break; + default: - goto unh; + d = xread32_io_cmn(a_, &t); + if (!t) + goto unk; + if (!(a_ & 2)) + d >>= 16; + break; } goto out; } -unh: +unk: if (a == old_a) { d = fudge; fudge = ~fudge; @@ -484,6 +559,7 @@ static u32 xread32(u32 a) u32 a_ = a & 0xffff; struct timespec ts; u64 t64; + u32 t; switch (a_) { case 0x0a00: // TCOUNT, 1/7372800s @@ -493,7 +569,14 @@ static u32 xread32(u32 a) t64 *= 31665935; d = t64 >> 32; break; + + default: + d = xread32_io_cmn(a_, &t); + if (!t) + goto unh; + break; } + goto out; } if ((a & 0xfff00000) == 0x7f100000) { u32 *bl = &blitter.dstctrl; @@ -505,6 +588,8 @@ static u32 xread32(u32 a) goto out; } } + +unh: iolog_unh("r32", a, d, 32); out: @@ -524,31 +609,38 @@ static void xwrite16(u32 a, u32 d) if ((a & 0xfff00000) == 0x7f000000) { u32 a_ = a & 0xffff; switch (a_) { - case 0x28da: - mmsp2.mlc_stl_cntl = d | 0xaa; - break; - case 0x290e: - case 0x2910: - // odd addresses don't affect LCD. What about TV? - return; - case 0x2912: - mmsp2.mlc_stl_adrl = d; - return; - case 0x2914: - mmsp2.mlc_stl_adrh = d; - if (mmsp2.mlc_stl_adr != mmsp2.old_mlc_stl_adr) - // ask for refresh - pthread_cond_signal(&fb_cond); - mmsp2.old_mlc_stl_adr = mmsp2.mlc_stl_adr; - return; - case 0x2958: - mmsp2.mlc_stl_pallt_a = d & 0x1ff; - return; - case 0x295a: - mmsp2.mlc_stl_pallt_d[mmsp2.mlc_stl_pallt_a++] = d; - mmsp2.mlc_stl_pallt_a &= 0x1ff; - mmsp2.dirty_pal = 1; - return; + case 0x28da: { + int mode; + mmsp2.mlc_stl_cntl = d | 0xaa; + mode = (d >> 9) & 3; + mmsp2.v.bpp = mode ? mode * 8 : 4; + break; + } + case 0x290c: + mmsp2.v.stride = d; + return; + case 0x290e: + case 0x2910: + // odd addresses don't affect LCD. What about TV? + return; + case 0x2912: + mmsp2.mlc_stl_adrl = d; + return; + case 0x2914: + mmsp2.mlc_stl_adrh = d; + if (mmsp2.mlc_stl_adr != mmsp2.old_mlc_stl_adr) + // ask for refresh + pthread_cond_signal(&fb_cond); + mmsp2.old_mlc_stl_adr = mmsp2.mlc_stl_adr; + return; + case 0x2958: + mmsp2.mlc_stl_pallt_a = d & 0x1ff; + return; + case 0x295a: + mmsp2.mlc_stl_pallt_d[mmsp2.mlc_stl_pallt_a++] = d; + mmsp2.mlc_stl_pallt_a &= 0x1ff; + mmsp2.v.dirty_pal = DIRTY_PAL_MMSP2; + return; } } iolog_unh("w16", a, d, 16); @@ -558,6 +650,39 @@ static void xwrite32(u32 a, u32 d) { iolog("w32", a, d, 32); + if ((a & 0xfff00000) == 0x7f000000) { + u32 a_ = a & 0xffff; + switch (a_) { + // Wiz + case 0x4024: // MLCCONTROL0 + case 0x4058: // MLCCONTROL1 + pollux.mlccontrol = d; + if (!(d & 0x20)) + return; // layer not enabled + if ((d >> 16) == 0x443A) + pollux.v.bpp = 8; + else + pollux.v.bpp = 16; + return; + case 0x402c: // MLCVSTRIDE0 + case 0x4060: // MLCVSTRIDE1 + pollux.v.stride = d; + return; + case 0x4038: // MLCADDRESS0 + case 0x406c: // MLCADDRESS1 + pollux.mlc_stl_adr = d; + if (d != mmsp2.old_mlc_stl_adr) + // ask for refresh + pthread_cond_signal(&fb_cond); + mmsp2.old_mlc_stl_adr = d; + return; + case 0x403c: // MLCPALETTE0 + case 0x4070: // MLCPALETTE1 + pollux.mlcpalette[d >> 24] = d; + pollux.v.dirty_pal = DIRTY_PAL_POLLUX; + return; + } + } if ((a & 0xfff00000) == 0x7f100000) { u32 *bl = &blitter.dstctrl; u32 a_ = a & 0xfff; @@ -843,9 +968,14 @@ void emu_init(void *map_bottom) } pthread_detach(tid); - // mmsp2 defaults + // defaults mmsp2.mlc_stl_adr = 0x03101000; // fb2 is at 0x03381000 mmsp2.mlc_stl_cntl = 0x4ab; // 16bpp, region 1 active + mmsp2.v.width = 320; + mmsp2.v.height = 240; + mmsp2.v.stride = 320*2; + mmsp2.v.bpp = 16; + mmsp2.v.dirty_pal = 1; sigemptyset(&segv_action.sa_mask); sigaction(SIGSEGV, &segv_action, NULL); @@ -865,21 +995,16 @@ int emu_read_gpiodev(void *buf, int count) return count; } -struct dev_fd_t emu_interesting_fds[] = { - [IFD_SOUND] = { "/dev/dsp", -1 }, - { NULL, 0 }, -}; - static void *emu_mmap_dev(unsigned int length, int prot, int flags, unsigned int offset) { u8 *umem, *umem_end; // SoC regs - if ((offset & ~0xffff) == 0xc0000000) { + if ((offset & ~0x1ffff) == 0xc0000000) { return mmap((void *)0x7f000000, length, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED|MAP_NORESERVE, -1, 0); } - // blitter + // MMSP2 blitter if ((offset & ~0xffff) == 0xe0020000) { return mmap((void *)0x7f100000, length, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED|MAP_NORESERVE, -1, 0); @@ -916,6 +1041,21 @@ void *emu_do_mmap(unsigned int length, int prot, int flags, int fd, unsigned int return MAP_FAILED; } +static void emu_sound_open(int fd) +{ +#ifdef PND + int ret, frag; + + // set default buffer size to 16 * 1K + frag = (16<<16) | 10; // 16K + ret = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag); + if (ret != 0) { + err("snd ioctl SETFRAGMENT %08x: ", frag); + perror(NULL); + } +#endif +} + static int emu_sound_ioctl(int fd, int request, void *argp) { int *arg = argp; @@ -930,24 +1070,48 @@ static int emu_sound_ioctl(int fd, int request, void *argp) /* People set strange frag settings on GP2X, which even manage * to break audio on pandora (causes writes to fail). * Catch this and set to something that works. */ - if (request == SNDCTL_DSP_SPEED) { - int ret, bsize, frag; + switch(request) { + case SNDCTL_DSP_SETFRAGMENT: { + int ret, bsize, frag, frag_cnt; + if (arg == NULL) + break; - // ~4ms. gpSP wants small buffers or else it stutters - // because of it's audio thread sync stuff - bsize = *arg / 250 * 4; - for (frag = 0; bsize; bsize >>= 1, frag++) - ; + frag = *arg & 0xffff; + frag_cnt = *arg >> 16; + bsize = frag_cnt << frag; + if (frag < 10 || bsize < 4096*4 || bsize > 4096*4*2) { + /* + * ~4ms. gpSP wants small buffers or else it stutters + * because of it's audio thread sync stuff + * XXX: hardcoding, as low samplerates will result in small fragment size, + * which itself causes ALSA stall and hangs the program. + * Also some apps change samplerate without reopening /dev/dsp, + * which causes ALSA to reject SNDCTL_DSP_SETFRAGMENT. + */ + bsize = 44100 / 250 * 4; + + for (frag = 0; bsize; bsize >>= 1, frag++) + ; + + frag_cnt = 16; + } - frag |= 16 << 16; // fragment count - ret = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag); - if (ret != 0) { - err("snd ioctl SETFRAGMENT %08x: ", frag); - perror(NULL); + frag |= frag_cnt << 16; + ret = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag); + if (ret != 0) { + err("snd ioctl SETFRAGMENT %08x: ", frag); + perror(NULL); + } + // indicate success even if we fail (because of ALSA mostly), + // things like MikMod will bail out otherwise. + return 0; } + case SNDCTL_DSP_SYNC: + // Franxis tends to use sync/write loops, bad idea under ALSA + return 0; + default: + break; } - else if (request == SNDCTL_DSP_SETFRAGMENT) - return 0; return ioctl(fd, request, argp); } @@ -1022,6 +1186,11 @@ fail: return -1; } +struct dev_fd_t emu_interesting_fds[] = { + [IFD_SOUND] = { "/dev/dsp", -1, emu_sound_open }, + { NULL, 0, NULL }, +}; + static const struct { const char *from; const char *to; @@ -1052,13 +1221,21 @@ static const char *wrap_path(const char *path) return path; } +static void wrap_path_free(const char *w_path, const char *old_path) +{ + if (w_path != old_path) + free((void *)w_path); +} + void *emu_do_fopen(const char *path, const char *mode) { - const char *w_path = wrap_path(path); + const char *w_path; FILE *ret; + + w_path = wrap_path(path); ret = fopen(w_path, mode); - if (w_path != path) - free((void *)w_path); + wrap_path_free(w_path, path); + return ret; } @@ -1084,8 +1261,7 @@ int emu_do_system(const char *command) p2 = wrap_path(command); snprintf(p, sizeof(tmp_path) - (p - tmp_path), " --nomenu %s", p2); - if (p2 != command) - free((void *)p2); + wrap_path_free(p2, command); dbg("system: \"%s\"\n", tmp_path); @@ -1096,3 +1272,42 @@ int emu_do_system(const char *command) return ret; } +int emu_do_execve(const char *filename, char *const argv[], char *const envp[]) +{ + const char **new_argv; + char *prep_path; + int i, ret, argc; + + if (filename == NULL) + return -1; + + if (strstr(filename, "/gp2xmenu") != NULL) + exit(0); + + for (i = 0; argv[i] != NULL; i++) + ; + argc = i + 1; + + new_argv = calloc(argc + 2, sizeof(new_argv[0])); + if (new_argv == NULL) + return -1; + + prep_path = malloc(512); + if (prep_path == NULL) + return -1; + + make_local_path(prep_path, 512, "ginge_prep"); + new_argv[0] = prep_path; + new_argv[1] = "--nomenu"; + new_argv[2] = wrap_path(filename); + + if (argv[0] != NULL) + for (i = 1; argv[i] != NULL; i++) + new_argv[i + 2] = argv[i]; + + dbg("execve \"%s\" %s \"%s\"\n", new_argv[0], new_argv[1], new_argv[2]); + ret = execve(new_argv[0], (char **)new_argv, envp); + perror("execve"); + return ret; +} + diff --git a/loader/ginge_dyn.symver b/loader/ginge_dyn.symver index cb50f2b..20d2cd4 100644 --- a/loader/ginge_dyn.symver +++ b/loader/ginge_dyn.symver @@ -12,6 +12,9 @@ global: system; execl; execlp; + execle; + execv; + execvp; execve; chdir; diff --git a/loader/header.h b/loader/header.h index 752dd03..58ef4d9 100644 --- a/loader/header.h +++ b/loader/header.h @@ -17,6 +17,7 @@ void do_entry(unsigned long entry, void *stack_frame, int stack_frame_cnt, void struct dev_fd_t { const char *name; int fd; + void (*open_cb)(int fd); }; extern struct dev_fd_t emu_interesting_fds[]; enum { @@ -45,6 +46,7 @@ int emu_do_ioctl(int fd, int request, void *argp); int emu_read_gpiodev(void *buf, int count); void *emu_do_fopen(const char *path, const char *mode); int emu_do_system(const char *command); +int emu_do_execve(const char *filename, char *const argv[], char *const envp[]); int host_init(void); int host_read_btns(void); diff --git a/loader/host_pnd.c b/loader/host_pnd.c index 9064047..32fe95a 100644 --- a/loader/host_pnd.c +++ b/loader/host_pnd.c @@ -76,7 +76,7 @@ static const struct { { BTN_SELECT, GP2X_SELECT }, { KEY_COMMA, GP2X_VOL_DOWN }, { KEY_DOT, GP2X_VOL_UP }, - { KEY_Q, GP2X_PUSH }, + { KEY_1, GP2X_PUSH }, }; int host_read_btns(void) @@ -103,6 +103,15 @@ int host_read_btns(void) if (ev.type != EV_KEY) continue; + if (ev.code == KEY_Q && ev.value) { + // exit() might not be enough because loader and app data is out of sync, + // and other threads (which are really processes) might not exit properly. + system("killall ginge_sloader"); + usleep(300000); + system("killall -9 ginge_sloader"); + exit(1); + } + for (i = 0; i < sizeof(key_map) / sizeof(key_map[0]); i++) { if (key_map[i].key != ev.code) continue; diff --git a/loader/override.c b/loader/override.c index 75b8eeb..b61ed8b 100644 --- a/loader/override.c +++ b/loader/override.c @@ -33,6 +33,9 @@ static const struct dev_fd_t takeover_devs[] = { { "/dev/mmuhack", FAKEDEV_MMUHACK }, { "/dev/tty", -1 }, // XXX hmh.. { "/dev/tty0", FAKEDEV_TTY0 }, +#ifdef PND + { "/dev/input/event*", -1 }, // hide for now, may cause dupe events +#endif }; static int w_open(const char *pathname, int flags, mode_t mode) @@ -40,7 +43,17 @@ static int w_open(const char *pathname, int flags, mode_t mode) int i, ret; for (i = 0; i < ARRAY_SIZE(takeover_devs); i++) { - if (strcmp(pathname, takeover_devs[i].name) == 0) { + const char *p, *oname; + int len; + + oname = takeover_devs[i].name; + p = strchr(oname, '*'); + if (p != NULL) + len = p - oname; + else + len = strlen(oname) + 1; + + if (strncmp(pathname, oname, len) == 0) { ret = takeover_devs[i].fd; break; } @@ -51,8 +64,11 @@ static int w_open(const char *pathname, int flags, mode_t mode) if (ret >= 0) { for (i = 0; emu_interesting_fds[i].name != NULL; i++) { - if (strcmp(pathname, emu_interesting_fds[i].name) == 0) { - emu_interesting_fds[i].fd = ret; + struct dev_fd_t *eifd = &emu_interesting_fds[i]; + if (strcmp(pathname, eifd->name) == 0) { + eifd->fd = ret; + if (eifd->open_cb != NULL) + eifd->open_cb(ret); break; } } @@ -150,18 +166,37 @@ static UNUSED int w_system(const char *command) return ret; } -// 4 functions bellow are efforts to prevent gp2xmenu from being started.. +extern char **environ; + static UNUSED int w_execl(const char *path, const char *arg, ...) { // don't allow exec (for now) strace("execl(%s, %s, ...) = ?\n", path, arg); - exit(0); + exit(1); } static UNUSED int w_execlp(const char *file, const char *arg, ...) { strace("execlp(%s, %s, ...) = ?\n", file, arg); - exit(0); + exit(1); +} + +static UNUSED int w_execle(const char *path, const char *arg, ...) +{ + strace("execle(%s, %s, ...) = ?\n", path, arg); + exit(1); +} + +static UNUSED int w_execv(const char *path, char *const argv[]) +{ + strace("execv(%s, %p) = ?\n", path, argv); + return emu_do_execve(path, argv, environ); +} + +static UNUSED int w_execvp(const char *file, char *const argv[]) +{ + strace("execvp(%s, %p) = ?\n", file, argv); + return emu_do_execve(file, argv, environ); } // static note: this can't safely return because of the way it's patched in @@ -170,9 +205,7 @@ static UNUSED int w_execve(const char *filename, char *const argv[], char *const envp[]) { strace("execve(%s, %p, %p) = ?\n", filename, argv, envp); - if (filename != NULL && strstr(filename, "/gp2xmenu") != NULL) - exit(0); - return execve(filename, argv, envp); + return emu_do_execve(filename, argv, envp); } static int w_chdir(const char *path) @@ -197,6 +230,9 @@ static int w_chdir(const char *path) #undef system #undef execl #undef execlp +#undef execle +#undef execv +#undef execvp #undef execve #undef chdir @@ -223,6 +259,9 @@ MAKE_WRAP_SYM(tcsetattr); MAKE_WRAP_SYM(system); MAKE_WRAP_SYM_N(execl); MAKE_WRAP_SYM_N(execlp); +MAKE_WRAP_SYM_N(execle); +MAKE_WRAP_SYM_N(execv); +MAKE_WRAP_SYM_N(execvp); MAKE_WRAP_SYM(execve); MAKE_WRAP_SYM(chdir); typeof(mmap) mmap2 __attribute__((alias("w_mmap"))); diff --git a/loader/realfuncs.h b/loader/realfuncs.h index 38e3fce..43d2ddf 100644 --- a/loader/realfuncs.h +++ b/loader/realfuncs.h @@ -35,6 +35,9 @@ int real_chdir(const char *path); #define system real_system #define execl real_execl #define execlp real_execlp +#define execle real_execle +#define execv real_execv +#define execvp real_execvp #define execve real_execve #define chdir real_chdir diff --git a/loader/tools/static.c b/loader/tools/static.c index a244d5d..3475228 100644 --- a/loader/tools/static.c +++ b/loader/tools/static.c @@ -48,6 +48,7 @@ int main(int argc, char *argv[]) if (argc == 1000) fork(); chdir("wuhahaha!"); + usleep(1); // tcgetattr(-1, NULL); // tcsetattr(-1, 0, NULL); diff --git a/make_pnd.sh b/make_pnd.sh index 8a0fab0..84dc0a5 100755 --- a/make_pnd.sh +++ b/make_pnd.sh @@ -4,11 +4,14 @@ pnd_make=$HOME/dev/pnd/src/pandora-libraries/testdata/scripts/pnd_make.sh set -e -dist/make_cmn.sh out_pnd -mkdir -p out_pnd/tools -cp dist/ginge.sh out_pnd/ -cp dist/ginge_dyn_eabi.sh out_pnd/ginge_dyn.sh -cp tools/cramfsck_eabi out_pnd/tools/cramfsck -cp -r lib out_pnd/ - -$pnd_make -p ginge.pnd -d out_pnd -x dist/ginge.pxml -c -i dist/ginge60.png +out=out_pnd + +dist/make_cmn.sh ${out} +mkdir -p ${out}/tools +cp dist/ginge.sh ${out}/ +cp dist/ginge_dyn_eabi.sh ${out}/ginge_dyn.sh +cp prep/ginge_prep_pnd ${out}/ginge_prep +cp tools/cramfsck_eabi ${out}/tools/cramfsck +cp -r lib ${out}/ + +$pnd_make -p ginge.pnd -d ${out} -x dist/ginge.pxml -c -i dist/ginge60.png diff --git a/make_wiz.sh b/make_wiz.sh index bea9af7..09d35bc 100755 --- a/make_wiz.sh +++ b/make_wiz.sh @@ -9,6 +9,7 @@ mkdir -p ${out}/tools ${out}/lib cp dist/ginge.gpe ${out}/ cp dist/ginge32.png ${out}/ginge.png cp dist/ginge_dyn_oabi.sh ${out}/ginge_dyn.sh +cp prep/ginge_prep_wiz ${out}/ginge_prep cp lib/libSDL-1.2.so.0.7.0 ${out}/lib/libSDL-1.2.so.0 cp tools/cramfsck_oabi ${out}/tools/cramfsck cp tools/warm_2.6.24.ko ${out}/tools/ diff --git a/prep/Makefile b/prep/Makefile index bf9c95c..82ec39f 100644 --- a/prep/Makefile +++ b/prep/Makefile @@ -3,19 +3,21 @@ CFLAGS += -Wall -O2 LDFLAGS = -s -O2 ifdef WIZ CFLAGS += -DWIZ +TAG = _wiz endif ifdef PND CFLAGS += -DPND +TAG = _pnd endif vpath %.c = ../common/ -TARGET = ginge_prep +TARGET = ginge_prep$(TAG) OBJS += main.o host_fb.o cmn.o all: $(TARGET) -ginge_prep: $(OBJS) +$(TARGET): $(OBJS) $(CC) -o $@ $^ $(LDFLAGS) clean: diff --git a/readme.txt b/readme.txt index ab318bd..3eb1913 100644 --- a/readme.txt +++ b/readme.txt @@ -1,6 +1,6 @@ GINGE - Ginge Is Not GP2X Emulator -release 2 +release 3 (C) notaz, 2010 http://notaz.gp2x.de/ @@ -9,13 +9,14 @@ http://notaz.gp2x.de/ About ----- -Ginge is an application that can run many GP2X F100/F200 games on other ARM -Linux platforms, which currently includes Wiz. It is not a full hardware -emulator like MAME, PicoDrive or similar, it does not emulate the CPU. It can -be considered as compatibility layer similar to Wine on PC Linux, however it -does emulate small portion of MMSP2 system-on-chip. It operates by hooking -certain system calls and using realtime patching of code that accesses memory -mapped hardware directly. +Ginge is an application that can run many GP2X F100/F200, Wiz games and +programs on other ARM Linux platforms, which currently includes Pandora +and Wiz itself. It is not a full hardware emulator like MAME, PicoDrive or +similar, it does not emulate the CPU. It can be considered as compatibility +layer similar to Wine on PC Linux, however it does emulate small portion of +MMSP2 and Pollux system-on-chips. It operates by hooking certain system calls +and using realtime patching of code that accesses memory mapped hardware +directly. Usage @@ -26,6 +27,14 @@ can then be used to start GP2X software, which will either run if it's compatible, or just return back to the menu if it is not. In some cases it might hang though. +Keys are mapped to corresponding keys on both pandora and Wiz, except: + +Key Pandora Wiz +Stick Push 1 unmapped +Volume up/down '.', ',' Volume up/down + +On pandora pressing 'q' will exit the menu or try to kill current application. + Structure --------- @@ -46,6 +55,12 @@ it does is running ginge_prep on GP2X .gpe program, ginge_prep handles the rest. Changelog --------- +r3 +* improved exec handling, mostly for gpecomp. ++ added preliminary Wiz support, pcsx4all works. +* Wiz: since some stuff is written to /tmp, mount tmpfs there when starting + to avoid wearing down flash. + r2 * improved exit handling * Wiz: should now return to Wiz menu after gp2xmenu exit diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..25c6274 --- /dev/null +++ b/todo.txt @@ -0,0 +1,4 @@ +- extract text +- giana +- odanata - no sound +- touchscreen