--- BasiliskII/src/Unix/video_vosf.h 2000/10/02 17:52:42 1.4 +++ BasiliskII/src/Unix/video_vosf.h 2001/01/11 16:39:08 1.11 @@ -130,13 +130,13 @@ static void do_fbcopy_raw(uint8 * dest, #define FB_FUNC_NAME do_fbcopy_16_nbo #include "video_blit.h" -// opposite byte order (untested) +// opposite byte order #define FB_BLIT_1(dst, src) \ - (dst = ((((src) >> 6) & 0xff) | (((src) & 0x60) << 9))) + (dst = ((((src) >> 7) & 0xff) | (((src) << 9) & 0xc000) | (((src) << 8) & 0x1f00))) #define FB_BLIT_2(dst, src) \ - (dst = ((((src) >> 6) & 0x00ff00ff) | (((src) & 0x00600060) << 9))) + (dst = ((((src) >> 7) & 0x00ff00ff) | (((src) << 9) & 0xc000c000) | (((src) << 8) & 0x1f001f00))) #define FB_DEPTH 16 #define FB_FUNC_NAME do_fbcopy_16_obo @@ -206,23 +206,23 @@ static fbcopy_func do_update_framebuffer // fb_copy_funcs[depth_id][native_byte_order][dga_mode] // NT : not tested // OK : has been successfully tested -// NBO : native byte order -// OBO : opposite byte order +// NBO : native byte order (X server vs. client) +// OBO : opposite byte order (X server vs. client) static fbcopy_func fbcopy_funcs[ID_DEPTH_COUNT][2][2] = { #ifdef WORDS_BIGENDIAN /* opposite byte order native byte order */ /* 1 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // NT /* 8 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // OK (NBO) -/* 15 bpp */ { WD(fbcopy_15_obo) , WD(fbcopy_raw) }, // NT -/* 16 bpp */ { WD(fbcopy_16_obo) , WD(fbcopy_16_nbo) }, // NT -/* 24 bpp */ { WD(fbcopy_24_obo) , WD(fbcopy_raw) } // NT +/* 15 bpp */ { WD(fbcopy_15_obo) , WD(fbcopy_raw) }, // OK (OBO) +/* 16 bpp */ { WD(fbcopy_16_obo) , WD(fbcopy_16_nbo) }, // OK (OBO) +/* 24 bpp */ { WD(fbcopy_24_obo) , WD(fbcopy_raw) } // OK (OBO) #else /* opposite byte order native byte order */ /* 1 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // NT /* 8 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // OK (NBO) /* 15 bpp */ { WD(fbcopy_raw) , WD(fbcopy_15_nbo) }, // OK (NBO) /* 16 bpp */ { WD(fbcopy_16_obo) , WD(fbcopy_16_nbo) }, // OK (NBO) -/* 24 bpp */ { WD(fbcopy_raw) , WD(fbcopy_24_nbo) } // NT +/* 24 bpp */ { WD(fbcopy_raw) , WD(fbcopy_24_nbo) } // OK (NBO) #endif }; @@ -240,38 +240,74 @@ static fbcopy_func fbcopy_funcs[ID_DEPTH * Screen fault handler */ -static inline void do_handle_screen_fault(uintptr addr) +const uintptr INVALID_PC = (uintptr)-1; + +static inline void do_handle_screen_fault(uintptr addr, uintptr pc = INVALID_PC) { - if ((addr < mainBuffer.memStart) || (addr >= mainBuffer.memEnd)) { - fprintf(stderr, "Segmentation fault at 0x%08X\n", addr); - abort(); + /* Someone attempted to write to the frame buffer. Make it writeable + * now so that the data could actually be written. It will be made + * read-only back in one of the screen update_*() functions. + */ + if ((addr >= mainBuffer.memStart) && (addr < mainBuffer.memEnd)) { + const int page = (addr - mainBuffer.memStart) >> mainBuffer.pageBits; + caddr_t page_ad = (caddr_t)(addr & ~(mainBuffer.pageSize - 1)); + LOCK_VOSF; + PFLAG_SET(page); + mprotect(page_ad, mainBuffer.pageSize, PROT_READ | PROT_WRITE); + UNLOCK_VOSF; + return; } - const int page = (addr - mainBuffer.memStart) >> mainBuffer.pageBits; - caddr_t page_ad = (caddr_t)(addr & ~(mainBuffer.pageSize - 1)); -#ifdef HAVE_PTHREADS - pthread_mutex_lock(&Screen_draw_lock); -#endif - PFLAG_SET(page); - mprotect(page_ad, mainBuffer.pageSize, PROT_READ | PROT_WRITE); -#ifdef HAVE_PTHREADS - pthread_mutex_unlock(&Screen_draw_lock); -#endif + /* Otherwise, we don't know how to handle the fault, let it crash */ + fprintf(stderr, "do_handle_screen_fault: unhandled address 0x%08X", addr); + if (pc != INVALID_PC) + fprintf(stderr, " [IP=0x%08X]", pc); + fprintf(stderr, "\n"); + + signal(SIGSEGV, SIG_DFL); } #if defined(HAVE_SIGINFO_T) + static void Screen_fault_handler(int, siginfo_t * sip, void *) { D(bug("Screen_fault_handler: ADDR=0x%08X\n", sip->si_addr)); do_handle_screen_fault((uintptr)sip->si_addr); } + #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE) + # if defined(__i386__) && defined(__linux__) static void Screen_fault_handler(int, struct sigcontext scs) { D(bug("Screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", scs.cr2, scs.eip)); - do_handle_screen_fault((uintptr)scs.cr2); + do_handle_screen_fault((uintptr)scs.cr2, (uintptr)scs.eip); +} + +# elif defined(__m68k__) && defined(__NetBSD__) + +# include +static void Screen_fault_handler(int, int code, struct sigcontext *scp) +{ + D(bug("Screen_fault_handler: ADDR=0x%08X\n", code)); + struct sigstate { + int ss_flags; + struct frame ss_frame; + }; + struct sigstate *state = (struct sigstate *)scp->sc_ap; + uintptr fault_addr; + switch (state->ss_frame.f_format) { + case 7: // 68040 access error + // "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown + fault_addr = state->ss_frame.f_fmt7.f_fa; + break; + default: + fault_addr = (uintptr)code; + break; + } + do_handle_screen_fault(fault_addr); } + # else # error "No suitable subterfuge for Video on SEGV signals" # endif @@ -290,7 +326,7 @@ static bool Screen_fault_handler_init() // Setup SIGSEGV handler to process writes to frame buffer sigemptyset(&vosf_sa.sa_mask); vosf_sa.sa_sigaction = Screen_fault_handler; - vosf_sa.sa_flags = 0; + vosf_sa.sa_flags = SA_SIGINFO; return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0); } #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE) @@ -299,7 +335,12 @@ static bool Screen_fault_handler_init() // Setup SIGSEGV handler to process writes to frame buffer sigemptyset(&vosf_sa.sa_mask); vosf_sa.sa_handler = (void (*)(int)) Screen_fault_handler; +#if !EMULATED_68K && defined(__NetBSD__) + sigaddset(&vosf_sa.sa_mask, SIGALRM); + vosf_sa.sa_flags = SA_ONSTACK; +#else vosf_sa.sa_flags = 0; +#endif return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0); } #endif @@ -313,21 +354,13 @@ static inline void update_display_window { int page = 0; for (;;) { - while (PFLAG_ISCLEAR_4(page)) - page += 4; - - while (PFLAG_ISCLEAR(page)) - page++; - - if (page >= mainBuffer.pageCount) + const int first_page = find_next_page_set(page); + if (first_page >= mainBuffer.pageCount) break; - - const int first_page = page; - while ((page < mainBuffer.pageCount) && PFLAG_ISSET(page)) { - PFLAG_CLEAR(page); - ++page; - } - + + page = find_next_page_clear(first_page); + PFLAG_CLEAR_RANGE(first_page, page); + // Make the dirty pages read-only again const int32 offset = first_page << mainBuffer.pageBits; const uint32 length = (page - first_page) << mainBuffer.pageBits; @@ -344,40 +377,78 @@ static inline void update_display_window // Check for first column from left and first column // from right that have changed - int x1 = VideoMonitor.x * bytes_per_pixel - 1; - for (j = y1; j <= y2; j++) { - uint8 * const p1 = &the_buffer[j * bytes_per_row]; - uint8 * const p2 = &the_buffer_copy[j * bytes_per_row]; - for (i = 0; i < x1; i++) { - if (p1[i] != p2[i]) { - x1 = i; - break; + int x1, x2, width; + if (depth == 1) { + + x1 = VideoMonitor.x - 1; + for (j = y1; j <= y2; j++) { + uint8 * const p1 = &the_buffer[j * bytes_per_row]; + uint8 * const p2 = &the_buffer_copy[j * bytes_per_row]; + for (i = 0; i < (x1>>3); i++) { + if (p1[i] != p2[i]) { + x1 = i << 3; + break; + } } } - } - x1 /= bytes_per_pixel; - - int x2 = x1 * bytes_per_pixel; - for (j = y2; j >= y1; j--) { - uint8 * const p1 = &the_buffer[j * bytes_per_row]; - uint8 * const p2 = &the_buffer_copy[j * bytes_per_row]; - for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) { - if (p1[i] != p2[i]) { - x2 = i; - break; + + x2 = x1; + for (j = y2; j >= y1; j--) { + uint8 * const p1 = &the_buffer[j * bytes_per_row]; + uint8 * const p2 = &the_buffer_copy[j * bytes_per_row]; + for (i = (VideoMonitor.x>>3) - 1; i > (x2>>3); i--) { + if (p1[i] != p2[i]) { + x2 = (i << 3) + 7; + break; + } } } - } - x2 /= bytes_per_pixel; + width = x2 - x1 + 1; + + // Update the_host_buffer and copy of the_buffer + i = y1 * bytes_per_row + (x1 >> 3); + for (j = y1; j <= y2; j++) { + do_update_framebuffer(the_host_buffer + i, the_buffer + i, width >> 3); + memcpy(the_buffer_copy + i, the_buffer + i, width >> 3); + i += bytes_per_row; + } + + } else { + + x1 = VideoMonitor.x * bytes_per_pixel - 1; + for (j = y1; j <= y2; j++) { + uint8 * const p1 = &the_buffer[j * bytes_per_row]; + uint8 * const p2 = &the_buffer_copy[j * bytes_per_row]; + for (i = 0; i < x1; i++) { + if (p1[i] != p2[i]) { + x1 = i; + break; + } + } + } + x1 /= bytes_per_pixel; - // Update the_host_buffer and copy of the_buffer - // There is at least one pixel to copy - const int width = x2 - x1 + 1; - i = y1 * bytes_per_row + x1 * bytes_per_pixel; - for (j = y1; j <= y2; j++) { - do_update_framebuffer(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width); - memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width); - i += bytes_per_row; + x2 = x1 * bytes_per_pixel; + for (j = y2; j >= y1; j--) { + uint8 * const p1 = &the_buffer[j * bytes_per_row]; + uint8 * const p2 = &the_buffer_copy[j * bytes_per_row]; + for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) { + if (p1[i] != p2[i]) { + x2 = i; + break; + } + } + } + x2 /= bytes_per_pixel; + width = x2 - x1 + 1; + + // Update the_host_buffer and copy of the_buffer + i = y1 * bytes_per_row + x1 * bytes_per_pixel; + for (j = y1; j <= y2; j++) { + do_update_framebuffer(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width); + memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width); + i += bytes_per_row; + } } if (have_shm) @@ -398,21 +469,13 @@ static inline void update_display_dga_vo { int page = 0; for (;;) { - while (PFLAG_ISCLEAR_4(page)) - page += 4; - - while (PFLAG_ISCLEAR(page)) - page++; - - if (page >= mainBuffer.pageCount) + const int first_page = find_next_page_set(page); + if (first_page >= mainBuffer.pageCount) break; - - const int first_page = page; - while ((page < mainBuffer.pageCount) && PFLAG_ISSET(page)) { - PFLAG_CLEAR(page); - ++page; - } - + + page = find_next_page_clear(first_page); + PFLAG_CLEAR_RANGE(first_page, page); + // Make the dirty pages read-only again const int32 offset = first_page << mainBuffer.pageBits; const uint32 length = (page - first_page) << mainBuffer.pageBits;