/[pcsx2_0.9.7]/trunk/common/src/Utilities/Linux/LnxHostSys.cpp
ViewVC logotype

Contents of /trunk/common/src/Utilities/Linux/LnxHostSys.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (show annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 2 months ago) by william
File size: 7289 byte(s)
re-commit (had local access denied errors when committing)
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16
17 #include "../PrecompiledHeader.h"
18 #include "PageFaultSource.h"
19
20 #include <wx/thread.h>
21
22 #include <sys/mman.h>
23 #include <signal.h>
24 #include <errno.h>
25
26 extern void SignalExit(int sig);
27
28 static const uptr m_pagemask = getpagesize()-1;
29
30 // Linux implementation of SIGSEGV handler. Bind it using sigaction().
31 static void SysPageFaultSignalFilter( int signal, siginfo_t *siginfo, void * )
32 {
33 // [TODO] : Add a thread ID filter to the Linux Signal handler here.
34 // Rationale: On windows, the __try/__except model allows per-thread specific behavior
35 // for page fault handling. On linux, there is a single signal handler for the whole
36 // process, but the handler is executed by the thread that caused the exception.
37
38
39 // Stdio Usage note: SIGSEGV handling is a synchronous in-thread signal. It is done
40 // from the context of the current thread and stackframe. So long as the thread is not
41 // the main/ui thread, use of the px assertion system should be safe. Use of stdio should
42 // be safe even on the main thread.
43 // (in other words, stdio limitations only really apply to process-level asynchronous
44 // signals)
45
46 // Note: Use of stdio functions isn't safe here. Avoid console logs,
47 // assertions, file logs, or just about anything else useful.
48
49 Source_PageFault->Dispatch( PageFaultInfo( (uptr)siginfo->si_addr & ~m_pagemask ) );
50
51 // resumes execution right where we left off (re-executes instruction that
52 // caused the SIGSEGV).
53 if (Source_PageFault->WasHandled()) return;
54
55 if (!wxThread::IsMain())
56 {
57 pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr));
58 }
59
60 // Bad mojo! Completely invalid address.
61 // Instigate a trap if we're in a debugger, and if not then do a SIGKILL.
62
63 wxTrap();
64 if (!IsDebugBuild) raise( SIGKILL );
65 }
66
67 void _platform_InstallSignalHandler()
68 {
69 Console.WriteLn("Installing POSIX SIGSEGV handler...");
70 struct sigaction sa;
71
72 sigemptyset(&sa.sa_mask);
73 sa.sa_flags = SA_SIGINFO;
74 sa.sa_sigaction = SysPageFaultSignalFilter;
75 sigaction(SIGSEGV, &sa, NULL);
76 }
77
78 static __ri void PageSizeAssertionTest( size_t size )
79 {
80 pxAssertMsg( (__pagesize == getpagesize()), pxsFmt(
81 "Internal system error: Operating system pagesize does not match compiled pagesize.\n\t"
82 L"\tOS Page Size: 0x%x (%d), Compiled Page Size: 0x%x (%u)",
83 getpagesize(), getpagesize(), __pagesize, __pagesize )
84 );
85
86 pxAssertDev( (size & (__pagesize-1)) == 0, pxsFmt(
87 L"Memory block size must be a multiple of the target platform's page size.\n"
88 L"\tPage Size: 0x%x (%u), Block Size: 0x%x (%u)",
89 __pagesize, __pagesize, size, size )
90 );
91 }
92
93 // returns FALSE if the mprotect call fails with an ENOMEM.
94 // Raises assertions on other types of POSIX errors (since those typically reflect invalid object
95 // or memory states).
96 static bool _memprotect( void* baseaddr, size_t size, const PageProtectionMode& mode )
97 {
98 PageSizeAssertionTest(size);
99
100 uint lnxmode = 0;
101
102 if (mode.CanWrite()) lnxmode |= PROT_WRITE;
103 if (mode.CanRead()) lnxmode |= PROT_READ;
104 if (mode.CanExecute()) lnxmode |= PROT_EXEC | PROT_READ;
105
106 const int result = mprotect( baseaddr, size, lnxmode );
107
108 if (result == 0) return true;
109
110 switch(errno)
111 {
112 case EINVAL:
113 pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)",
114 baseaddr, (uptr)baseaddr+size, mode.ToString().c_str())
115 );
116 break;
117
118 case EACCES:
119 pxFailDev(pxsFmt(L"mprotect returned EACCES @ 0x%08X -> 0x%08X (mode=%s)",
120 baseaddr, (uptr)baseaddr+size, mode.ToString().c_str())
121 );
122 break;
123
124 case ENOMEM:
125 // caller handles assertion or exception, or whatever.
126 break;
127 }
128 return false;
129 }
130
131 void* HostSys::MmapReservePtr(void* base, size_t size)
132 {
133 PageSizeAssertionTest(size);
134
135 // On linux a reserve-without-commit is performed by using mmap on a read-only
136 // or anonymous source, with PROT_NONE (no-access) permission. Since the mapping
137 // is completely inaccessible, the OS will simply reserve it and will not put it
138 // against the commit table.
139 return mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
140 }
141
142 bool HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode)
143 {
144 // In linux, reserved memory is automatically committed when its permissions are
145 // changed to something other than PROT_NONE. If the user is committing memory
146 // as PROT_NONE, then just ignore this call (memory will be committed automatically
147 // later when the user changes permissions to something useful via calls to MemProtect).
148
149 if (mode.IsNone()) return false;
150
151 if (_memprotect( base, size, mode )) return true;
152
153 if (!pxDoOutOfMemory) return false;
154 pxDoOutOfMemory(size);
155 return _memprotect( base, size, mode );
156 }
157
158 void HostSys::MmapResetPtr(void* base, size_t size)
159 {
160 // On linux the only way to reset the memory is to unmap and remap it as PROT_NONE.
161 // That forces linux to unload all committed pages and start from scratch.
162
163 // FIXME: Ideally this code would have some threading lock on it to prevent any other
164 // malloc/free code in the current process from interfering with the operation, but I
165 // can't think of any good way to do that. (generally it shouldn't be a problem in
166 // PCSX2 anyway, since MmapReset is only called when the ps2vm is suspended; so that
167 // pretty well stops all PCSX2 threads anyway).
168
169 Munmap(base, size);
170 void* result = MmapReservePtr(base, size);
171
172 pxAssertRel ((uptr)result == (uptr)base, pxsFmt(
173 "Virtual memory decommit failed: memory at 0x%08X -> 0x%08X could not be remapped. "
174 "This is likely caused by multi-thread memory contention.", base, (uptr)base+size
175 ));
176 }
177
178 void* HostSys::MmapReserve(uptr base, size_t size)
179 {
180 return MmapReservePtr((void*)base, size);
181 }
182
183 bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode)
184 {
185 return MmapCommitPtr( (void*)base, size, mode );
186 }
187
188 void HostSys::MmapReset(uptr base, size_t size)
189 {
190 MmapResetPtr((void*)base, size);
191 }
192
193 void* HostSys::Mmap(uptr base, size_t size)
194 {
195 PageSizeAssertionTest(size);
196
197 // MAP_ANONYMOUS - means we have no associated file handle (or device).
198
199 return mmap((void*)base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
200 }
201
202 void HostSys::Munmap(uptr base, size_t size)
203 {
204 if (!base) return;
205 munmap((void*)base, size);
206 }
207
208 void HostSys::MemProtect( void* baseaddr, size_t size, const PageProtectionMode& mode )
209 {
210 if (!_memprotect(baseaddr, size, mode))
211 {
212 throw Exception::OutOfMemory( L"MemProtect" )
213 .SetDiagMsg(pxsFmt( L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)",
214 baseaddr, (uptr)baseaddr+size, mode.ToString().c_str()
215 )
216 );
217 }
218 }

  ViewVC Help
Powered by ViewVC 1.1.22