28 |
|
* Page-aligned memory allocation |
29 |
|
*/ |
30 |
|
|
31 |
< |
// Align on page boundaries |
32 |
< |
static uintptr align_on_page_boundary(uintptr size) |
31 |
> |
// Extend size to page boundary |
32 |
> |
static uint32 page_extend(uint32 size) |
33 |
|
{ |
34 |
|
const uint32 page_size = getpagesize(); |
35 |
|
const uint32 page_mask = page_size - 1; |
36 |
|
return (size + page_mask) & ~page_mask; |
37 |
|
} |
38 |
|
|
39 |
< |
// Allocate memory on page boundary |
40 |
< |
static void * allocate_framebuffer(uint32 size, uint8 * hint = 0) |
41 |
< |
{ |
42 |
< |
// Remind that the system can allocate at 0x00000000... |
43 |
< |
return mmap((caddr_t)hint, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zero_fd, 0); |
44 |
< |
} |
45 |
< |
|
46 |
< |
|
47 |
< |
/* |
48 |
< |
* Screen fault handler |
49 |
< |
*/ |
50 |
< |
|
51 |
< |
const uintptr INVALID_PC = (uintptr)-1; |
52 |
< |
|
53 |
< |
static inline void do_handle_screen_fault(uintptr addr, uintptr pc = INVALID_PC) |
39 |
> |
// Screen fault handler |
40 |
> |
static bool screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction) |
41 |
|
{ |
42 |
+ |
D(bug("screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", fault_address, fault_instruction)); |
43 |
+ |
const uintptr addr = (uintptr)fault_address; |
44 |
+ |
|
45 |
|
/* Someone attempted to write to the frame buffer. Make it writeable |
46 |
|
* now so that the data could actually be written. It will be made |
47 |
|
* read-only back in one of the screen update_*() functions. |
48 |
|
*/ |
49 |
|
if ((addr >= mainBuffer.memStart) && (addr < mainBuffer.memEnd)) { |
50 |
|
const int page = (addr - mainBuffer.memStart) >> mainBuffer.pageBits; |
51 |
< |
caddr_t page_ad = (caddr_t)(addr & ~(mainBuffer.pageSize - 1)); |
51 |
> |
caddr_t page_ad = (caddr_t)(addr & -mainBuffer.pageSize); |
52 |
|
LOCK_VOSF; |
53 |
|
PFLAG_SET(page); |
54 |
< |
mprotect(page_ad, mainBuffer.pageSize, PROT_READ | PROT_WRITE); |
54 |
> |
vm_protect((char *)page_ad, mainBuffer.pageSize, VM_PAGE_READ | VM_PAGE_WRITE); |
55 |
|
mainBuffer.dirty = true; |
56 |
|
UNLOCK_VOSF; |
57 |
< |
return; |
57 |
> |
return true; |
58 |
|
} |
59 |
|
|
60 |
|
/* Otherwise, we don't know how to handle the fault, let it crash */ |
61 |
|
fprintf(stderr, "do_handle_screen_fault: unhandled address 0x%08X", addr); |
62 |
< |
if (pc != INVALID_PC) |
63 |
< |
fprintf(stderr, " [IP=0x%08X]", pc); |
62 |
> |
if (fault_instruction != SIGSEGV_INVALID_PC) |
63 |
> |
fprintf(stderr, " [IP=0x%08X]", fault_instruction); |
64 |
|
fprintf(stderr, "\n"); |
65 |
< |
|
76 |
< |
signal(SIGSEGV, SIG_DFL); |
77 |
< |
} |
78 |
< |
|
79 |
< |
#if defined(HAVE_SIGINFO_T) |
80 |
< |
|
81 |
< |
static void Screen_fault_handler(int, siginfo_t * sip, void *) |
82 |
< |
{ |
83 |
< |
D(bug("Screen_fault_handler: ADDR=0x%08X\n", sip->si_addr)); |
84 |
< |
do_handle_screen_fault((uintptr)sip->si_addr); |
85 |
< |
} |
86 |
< |
|
87 |
< |
#elif defined(HAVE_SIGCONTEXT_SUBTERFUGE) |
88 |
< |
|
89 |
< |
# if defined(__i386__) && defined(__linux__) |
90 |
< |
static void Screen_fault_handler(int, struct sigcontext scs) |
91 |
< |
{ |
92 |
< |
D(bug("Screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", scs.cr2, scs.eip)); |
93 |
< |
do_handle_screen_fault((uintptr)scs.cr2, (uintptr)scs.eip); |
94 |
< |
} |
95 |
< |
|
96 |
< |
# elif defined(__m68k__) && defined(__NetBSD__) |
97 |
< |
|
98 |
< |
# include <m68k/frame.h> |
99 |
< |
static void Screen_fault_handler(int, int code, struct sigcontext *scp) |
100 |
< |
{ |
101 |
< |
D(bug("Screen_fault_handler: ADDR=0x%08X\n", code)); |
102 |
< |
struct sigstate { |
103 |
< |
int ss_flags; |
104 |
< |
struct frame ss_frame; |
105 |
< |
}; |
106 |
< |
struct sigstate *state = (struct sigstate *)scp->sc_ap; |
107 |
< |
uintptr fault_addr; |
108 |
< |
switch (state->ss_frame.f_format) { |
109 |
< |
case 7: // 68040 access error |
110 |
< |
// "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown |
111 |
< |
fault_addr = state->ss_frame.f_fmt7.f_fa; |
112 |
< |
break; |
113 |
< |
default: |
114 |
< |
fault_addr = (uintptr)code; |
115 |
< |
break; |
116 |
< |
} |
117 |
< |
do_handle_screen_fault(fault_addr); |
118 |
< |
} |
119 |
< |
|
120 |
< |
# elif defined(__powerpc__) && defined(__linux__) |
121 |
< |
|
122 |
< |
static void Screen_fault_handler(int, struct sigcontext_struct *scs) |
123 |
< |
{ |
124 |
< |
D(bug("Screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", scs->regs->dar, scs->regs->nip)); |
125 |
< |
do_handle_screen_fault((uintptr)scs->regs->dar, (uintptr)scs->regs->nip); |
126 |
< |
} |
127 |
< |
|
128 |
< |
# else |
129 |
< |
# error "No suitable subterfuge for Video on SEGV signals" |
130 |
< |
# endif |
131 |
< |
#else |
132 |
< |
# error "Can't do Video on SEGV signals" |
133 |
< |
#endif |
134 |
< |
|
135 |
< |
|
136 |
< |
/* |
137 |
< |
* Screen fault handler initialization |
138 |
< |
*/ |
139 |
< |
|
140 |
< |
#if defined(HAVE_SIGINFO_T) |
141 |
< |
static bool Screen_fault_handler_init() |
142 |
< |
{ |
143 |
< |
// Setup SIGSEGV handler to process writes to frame buffer |
144 |
< |
sigemptyset(&vosf_sa.sa_mask); |
145 |
< |
vosf_sa.sa_sigaction = Screen_fault_handler; |
146 |
< |
vosf_sa.sa_flags = SA_SIGINFO; |
147 |
< |
return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0); |
65 |
> |
return false; |
66 |
|
} |
149 |
– |
#elif defined(HAVE_SIGCONTEXT_SUBTERFUGE) |
150 |
– |
static bool Screen_fault_handler_init() |
151 |
– |
{ |
152 |
– |
// Setup SIGSEGV handler to process writes to frame buffer |
153 |
– |
sigemptyset(&vosf_sa.sa_mask); |
154 |
– |
vosf_sa.sa_handler = (void (*)(int)) Screen_fault_handler; |
155 |
– |
#if !EMULATED_68K && defined(__NetBSD__) |
156 |
– |
sigaddset(&vosf_sa.sa_mask, SIGALRM); |
157 |
– |
vosf_sa.sa_flags = SA_ONSTACK; |
158 |
– |
#else |
159 |
– |
vosf_sa.sa_flags = 0; |
160 |
– |
#endif |
161 |
– |
return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0); |
162 |
– |
} |
163 |
– |
#endif |
164 |
– |
|
67 |
|
|
68 |
|
/* |
69 |
|
* Update display for Windowed mode and VOSF |
120 |
|
// Make the dirty pages read-only again |
121 |
|
const int32 offset = first_page << mainBuffer.pageBits; |
122 |
|
const uint32 length = (page - first_page) << mainBuffer.pageBits; |
123 |
< |
mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ); |
123 |
> |
vm_protect((char *)mainBuffer.memStart + offset, length, VM_PAGE_READ); |
124 |
|
|
125 |
|
// There is at least one line to update |
126 |
|
const int y1 = mainBuffer.pageInfo[first_page].top; |
178 |
|
// Make the dirty pages read-only again |
179 |
|
const int32 offset = first_page << mainBuffer.pageBits; |
180 |
|
const uint32 length = (page - first_page) << mainBuffer.pageBits; |
181 |
< |
mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ); |
181 |
> |
vm_protect((char *)mainBuffer.memStart + offset, length, VM_PAGE_READ); |
182 |
|
|
183 |
|
// I am sure that y2 >= y1 and depth != 1 |
184 |
|
const int y1 = mainBuffer.pageInfo[first_page].top; |