240 |
|
* Screen fault handler |
241 |
|
*/ |
242 |
|
|
243 |
< |
static inline void do_handle_screen_fault(uintptr addr) |
243 |
> |
const uintptr INVALID_PC = (uintptr)-1; |
244 |
> |
|
245 |
> |
static inline void do_handle_screen_fault(uintptr addr, uintptr pc = INVALID_PC) |
246 |
|
{ |
247 |
< |
if ((addr < mainBuffer.memStart) || (addr >= mainBuffer.memEnd)) { |
248 |
< |
fprintf(stderr, "Segmentation fault at 0x%08X\n", addr); |
249 |
< |
abort(); |
247 |
> |
/* Someone attempted to write to the frame buffer. Make it writeable |
248 |
> |
* now so that the data could actually be written. It will be made |
249 |
> |
* read-only back in one of the screen update_*() functions. |
250 |
> |
*/ |
251 |
> |
if ((addr >= mainBuffer.memStart) && (addr < mainBuffer.memEnd)) { |
252 |
> |
const int page = (addr - mainBuffer.memStart) >> mainBuffer.pageBits; |
253 |
> |
caddr_t page_ad = (caddr_t)(addr & ~(mainBuffer.pageSize - 1)); |
254 |
> |
LOCK_VOSF; |
255 |
> |
PFLAG_SET(page); |
256 |
> |
mprotect(page_ad, mainBuffer.pageSize, PROT_READ | PROT_WRITE); |
257 |
> |
UNLOCK_VOSF; |
258 |
> |
return; |
259 |
|
} |
260 |
|
|
261 |
< |
const int page = (addr - mainBuffer.memStart) >> mainBuffer.pageBits; |
262 |
< |
caddr_t page_ad = (caddr_t)(addr & ~(mainBuffer.pageSize - 1)); |
263 |
< |
LOCK_VOSF; |
264 |
< |
PFLAG_SET(page); |
265 |
< |
mprotect(page_ad, mainBuffer.pageSize, PROT_READ | PROT_WRITE); |
266 |
< |
UNLOCK_VOSF; |
261 |
> |
/* Otherwise, we don't know how to handle the fault, let it crash */ |
262 |
> |
fprintf(stderr, "do_handle_screen_fault: unhandled address 0x%08X", addr); |
263 |
> |
if (pc != INVALID_PC) |
264 |
> |
fprintf(stderr, " [IP=0x%08X]", pc); |
265 |
> |
fprintf(stderr, "\n"); |
266 |
> |
|
267 |
> |
signal(SIGSEGV, SIG_DFL); |
268 |
|
} |
269 |
|
|
270 |
|
#if defined(HAVE_SIGINFO_T) |
281 |
|
static void Screen_fault_handler(int, struct sigcontext scs) |
282 |
|
{ |
283 |
|
D(bug("Screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", scs.cr2, scs.eip)); |
284 |
< |
do_handle_screen_fault((uintptr)scs.cr2); |
284 |
> |
do_handle_screen_fault((uintptr)scs.cr2, (uintptr)scs.eip); |
285 |
|
} |
286 |
|
|
287 |
|
# elif defined(__m68k__) && defined(__NetBSD__) |
354 |
|
{ |
355 |
|
int page = 0; |
356 |
|
for (;;) { |
357 |
< |
while (PFLAG_ISCLEAR_4(page)) |
358 |
< |
page += 4; |
347 |
< |
|
348 |
< |
while (PFLAG_ISCLEAR(page)) |
349 |
< |
page++; |
350 |
< |
|
351 |
< |
if (page >= mainBuffer.pageCount) |
357 |
> |
const int first_page = find_next_page_set(page); |
358 |
> |
if (first_page >= mainBuffer.pageCount) |
359 |
|
break; |
360 |
< |
|
361 |
< |
const int first_page = page; |
362 |
< |
while ((page < mainBuffer.pageCount) && PFLAG_ISSET(page)) { |
356 |
< |
PFLAG_CLEAR(page); |
357 |
< |
++page; |
358 |
< |
} |
360 |
> |
|
361 |
> |
page = find_next_page_clear(first_page); |
362 |
> |
PFLAG_CLEAR_RANGE(first_page, page); |
363 |
|
|
364 |
|
// Make the dirty pages read-only again |
365 |
|
const int32 offset = first_page << mainBuffer.pageBits; |
469 |
|
{ |
470 |
|
int page = 0; |
471 |
|
for (;;) { |
472 |
< |
while (PFLAG_ISCLEAR_4(page)) |
473 |
< |
page += 4; |
470 |
< |
|
471 |
< |
while (PFLAG_ISCLEAR(page)) |
472 |
< |
page++; |
473 |
< |
|
474 |
< |
if (page >= mainBuffer.pageCount) |
472 |
> |
const int first_page = find_next_page_set(page); |
473 |
> |
if (first_page >= mainBuffer.pageCount) |
474 |
|
break; |
475 |
< |
|
476 |
< |
const int first_page = page; |
477 |
< |
while ((page < mainBuffer.pageCount) && PFLAG_ISSET(page)) { |
478 |
< |
PFLAG_CLEAR(page); |
480 |
< |
++page; |
481 |
< |
} |
482 |
< |
|
475 |
> |
|
476 |
> |
page = find_next_page_clear(first_page); |
477 |
> |
PFLAG_CLEAR_RANGE(first_page, page); |
478 |
> |
|
479 |
|
// Make the dirty pages read-only again |
480 |
|
const int32 offset = first_page << mainBuffer.pageBits; |
481 |
|
const uint32 length = (page - first_page) << mainBuffer.pageBits; |