2009-06-13 01:03:10 +00:00
|
|
|
#include "rsys/common.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This file is a quick hack to hoist code from config/os/linux to where it
|
|
|
|
* can be shared with the Mac OS X port.
|
|
|
|
*
|
|
|
|
* Eventually everything should be rejiggered to use the GNU build system.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if defined (LINUX) || defined (MACOSX)
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
|
|
|
#include "rsys/os.h"
|
|
|
|
#include "rsys/memsize.h"
|
|
|
|
#include "rsys/mman.h"
|
|
|
|
#include "rsys/system_error.h"
|
|
|
|
#include "rsys/memory_layout.h"
|
|
|
|
#include "rsys/assert.h"
|
|
|
|
#include "rsys/lowglobals.h"
|
|
|
|
|
|
|
|
#include "Gestalt.h"
|
|
|
|
#include "SegmentLdr.h"
|
|
|
|
|
|
|
|
#include "rsys/gestalt.h"
|
|
|
|
|
|
|
|
#include "rsys/lockunlock.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <signal.h>
|
|
|
|
|
|
|
|
#if defined (MACOSX)
|
|
|
|
// The code in here should work for Mac OS X as well as Linux, although
|
|
|
|
// in Mac OS X they use MAP_ANON instead of MAP_ANONYMOUS
|
|
|
|
#warning "Fix this, the code isn't Linux specific"
|
|
|
|
#define MAP_ANONYMOUS MAP_ANON
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void
|
|
|
|
my_fault_proc( int sig )
|
|
|
|
{
|
|
|
|
// FIXME: Change this to an internal Executor dialog
|
|
|
|
fprintf(stderr, "Unexpected Application Failure\n");
|
|
|
|
|
|
|
|
// If we are already in the browser, does this exit the program?
|
|
|
|
C_ExitToShell ();
|
|
|
|
}
|
|
|
|
|
|
|
|
static int except_list[] = { SIGSEGV, SIGBUS, 0 };
|
|
|
|
|
|
|
|
void
|
|
|
|
install_exception_handler (void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for ( i=0; except_list[i]; ++i )
|
|
|
|
{
|
|
|
|
signal(except_list[i], my_fault_proc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
uninstall_exception_handler (void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for ( i=0; except_list[i]; ++i )
|
|
|
|
{
|
|
|
|
signal(except_list[i], SIG_DFL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned long
|
|
|
|
physical_memory (void)
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
unsigned long mem;
|
|
|
|
|
|
|
|
mem = 0;
|
|
|
|
fp = fopen ("/proc/meminfo", "r");
|
|
|
|
if (fp)
|
|
|
|
{
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
while (fgets (buf, sizeof buf - 1, fp))
|
|
|
|
if (!strncmp (buf, "Mem:", 4) && sscanf (buf + 4, "%lu", &mem))
|
|
|
|
break;
|
|
|
|
|
|
|
|
fclose (fp);
|
|
|
|
}
|
|
|
|
|
|
|
|
replace_physgestalt_selector (gestaltPhysicalRAMSize, mem);
|
|
|
|
return mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
guess_good_memory_settings (void)
|
|
|
|
{
|
|
|
|
unsigned long new_appl_size;
|
|
|
|
|
|
|
|
new_appl_size = physical_memory () / 4;
|
|
|
|
|
|
|
|
#if defined (powerpc)
|
|
|
|
|
|
|
|
/* This hack prevents Photoshop 5.5 demo from complaining that we don't
|
|
|
|
have enough memory when we run on a 64 MB Linux machine. Our division
|
|
|
|
by four is a bit naive above, so there's really no harm, other than
|
|
|
|
ugliness, to this hack. */
|
|
|
|
|
|
|
|
{
|
|
|
|
enum { PHOTOSHOP_55_PREFERRED_SIZE = 16584 * 1024 };
|
|
|
|
|
|
|
|
if (new_appl_size < PHOTOSHOP_55_PREFERRED_SIZE &&
|
|
|
|
new_appl_size >= PHOTOSHOP_55_PREFERRED_SIZE * 8 / 10)
|
|
|
|
new_appl_size = PHOTOSHOP_55_PREFERRED_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (new_appl_size > ROMlib_applzone_size)
|
|
|
|
ROMlib_applzone_size = MIN (MAX_APPLZONE_SIZE, new_appl_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
boolean_t
|
|
|
|
os_init (void)
|
|
|
|
{
|
|
|
|
guess_good_memory_settings ();
|
|
|
|
#if defined (SDL)
|
|
|
|
install_exception_handler ();
|
|
|
|
#endif
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PUBLIC int
|
|
|
|
ROMlib_lockunlockrange (int fd, uint32 begin, uint32 count, lockunlock_t op)
|
|
|
|
{
|
|
|
|
int retval;
|
|
|
|
struct flock flock;
|
|
|
|
|
|
|
|
warning_trace_info ("fd = %d, begin = %d, count = %d, op = %d",
|
|
|
|
fd, begin, count, op);
|
|
|
|
retval = noErr;
|
|
|
|
switch (op)
|
|
|
|
{
|
|
|
|
case lock:
|
|
|
|
flock.l_type = F_WRLCK;
|
|
|
|
break;
|
|
|
|
case unlock:
|
|
|
|
flock.l_type = F_UNLCK;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
warning_unexpected ("op = %d", op);
|
|
|
|
retval = paramErr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retval == noErr)
|
|
|
|
{
|
|
|
|
boolean_t success;
|
|
|
|
|
|
|
|
flock.l_whence = SEEK_SET;
|
|
|
|
flock.l_start = begin;
|
|
|
|
flock.l_len = count;
|
|
|
|
|
|
|
|
success = fcntl (fd, F_SETLK, &flock) != -1;
|
|
|
|
if (success)
|
|
|
|
retval = noErr;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (errno)
|
|
|
|
{
|
|
|
|
case EAGAIN:
|
|
|
|
case EACCES:
|
|
|
|
retval = fLckdErr;
|
|
|
|
break;
|
|
|
|
#if 0
|
|
|
|
case ERROR_NOT_LOCKED:
|
|
|
|
retval = afpRangeNotLocked;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if 0
|
|
|
|
case ERROR_LOCK_FAILED:
|
|
|
|
retval = afpRangeOverlap;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
warning_unexpected ("errno = %d", errno);
|
|
|
|
retval = noErr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
PUBLIC int
|
|
|
|
ROMlib_launch_native_app (int n_filenames, char **filenames)
|
|
|
|
{
|
|
|
|
char **v;
|
|
|
|
|
|
|
|
v = alloca (sizeof *v * (n_filenames + 1));
|
|
|
|
memcpy (v, filenames, n_filenames * sizeof *v);
|
|
|
|
v[n_filenames] = 0;
|
|
|
|
if (fork () == 0)
|
|
|
|
execv (filenames[0], v);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !(defined (__GNUC__) && defined (__GNUC_MINOR__) && ((__GNUC__ == 2 && __GNUC_MINOR__ == 7 && defined (__i386__)) || defined (RELEASE_INTERNAL) || defined (powerpc) || defined (__alpha)))
|
|
|
|
#warning THIS IS NOT A PRODUCTION BUILD
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There is a very bad problem associated with the use of the db
|
|
|
|
* shared libraries under Linux. Specifically, the calling convention
|
|
|
|
* for functions which return structs that are larger than 32 bits
|
|
|
|
* somehow got changed when some of the Linux distributions switched
|
|
|
|
* from gcc to egcs. Both compilers put an extra pointer on the stack
|
|
|
|
* before calling the routine that returns the large struct, but gcc
|
|
|
|
* expects the caller to pop that extra pointer, where egcs expects
|
|
|
|
* the called to pop it. This means that if you compile the caller
|
|
|
|
* with gcc and call a shared library that was called with egcs, the
|
|
|
|
* stack pointer will be off by 4 bytes after the function returns and
|
|
|
|
* the stack is adjusted. That can be a catastrophe if further code
|
|
|
|
* expects the stack to be correct after adjustments. On the other
|
|
|
|
* hand, if we make the questionable call and then do nothing else,
|
|
|
|
* the "leave" instruction will restore the stack pointer by using the
|
|
|
|
* frame pointer and we'll never be bothered by the extra pop.
|
|
|
|
*
|
|
|
|
* So, as a workaround, we can wrap the routines, then check the
|
|
|
|
* assembly code that the compiler produces to make sure that it's
|
|
|
|
* tolerant of the error, then call the wrappers. That makes the
|
|
|
|
* wrapper routines look like voodoo code that was written by a
|
|
|
|
* superstitious programmer, but the code (or some other workaround)
|
|
|
|
* is absolutely necessary because we want to have one Executor
|
|
|
|
* executable that can run with both the shared libraries from Red Hat
|
|
|
|
* 5.2 as well as the new ones in SuSE 6.0 (and the new ones that will
|
|
|
|
* probably be in Red Hat 6.0).
|
|
|
|
*
|
|
|
|
* These wrappers absolutely have to be compiled with enough
|
|
|
|
* optimization so that the stack isn't adjusted before the leave
|
|
|
|
* instruction. If it is adjusted, then any interrupt that occurs
|
|
|
|
* between the adjustment and the transfering of the data from the
|
|
|
|
* temporary stack space to the address passed will cause corruption.
|
|
|
|
*
|
|
|
|
* If you do not understand the above, or if you disagree with it,
|
|
|
|
* please contact Cliff before changing the following code. Axing the
|
|
|
|
* code alone and then testing the result is not sufficient, unless
|
|
|
|
* you're sure that your test involves *both* db shared libaries.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
PUBLIC void
|
|
|
|
_dbm_fetch (datum *datump, DBM *db, datum datum)
|
|
|
|
{
|
|
|
|
*datump = dbm_fetch (db, datum);
|
|
|
|
}
|
|
|
|
|
|
|
|
PUBLIC void
|
|
|
|
_dbm_firstkey (datum *datump, DBM *db)
|
|
|
|
{
|
|
|
|
*datump = dbm_firstkey (db);
|
|
|
|
}
|
|
|
|
|
|
|
|
PUBLIC void
|
|
|
|
_dbm_nextkey (datum *datump, DBM *db)
|
|
|
|
{
|
|
|
|
*datump = dbm_nextkey (db);
|
|
|
|
}
|
|
|
|
|
|
|
|
PUBLIC boolean_t host_has_spfcommon (void)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
PUBLIC boolean_t
|
|
|
|
host_spfcommon (host_spf_reply_block *replyp, const char *prompt,
|
|
|
|
const char *incoming_filename, void *fp, void *filef, int numt,
|
|
|
|
void *tl, getorput_t getorput, sf_flavor_t flavor,
|
|
|
|
void *activeList, void *activateproc, void *yourdatap)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
mmap_lowglobals (void)
|
|
|
|
{
|
|
|
|
if (!force_big_offset)
|
|
|
|
{
|
|
|
|
caddr_t addr;
|
|
|
|
|
|
|
|
addr = mmap ((caddr_t) PAGE_ZERO_START,
|
|
|
|
PAGE_ZERO_SIZE,
|
|
|
|
PROT_READ | PROT_WRITE,
|
|
|
|
MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, -1, 0);
|
|
|
|
gui_assert (addr == (caddr_t) PAGE_ZERO_START);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-15 02:58:21 +00:00
|
|
|
#if !defined (MACOSX)
|
|
|
|
|
2009-06-13 01:03:10 +00:00
|
|
|
#if !defined (powerpc)
|
|
|
|
PRIVATE caddr_t
|
|
|
|
round_up_to_page_size (unsigned long addr)
|
|
|
|
{
|
|
|
|
caddr_t retval;
|
|
|
|
size_t page_size;
|
|
|
|
|
|
|
|
page_size = getpagesize ();
|
|
|
|
retval = (caddr_t) ((addr + page_size - 1) / page_size * page_size);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static jmp_buf segv_return;
|
|
|
|
|
|
|
|
static void
|
|
|
|
segv_handler (int signum_ignored __attribute__((unused)))
|
|
|
|
{
|
|
|
|
siglongjmp (segv_return, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
mmap_conflict (void *start, size_t length)
|
|
|
|
{
|
|
|
|
bool retval;
|
|
|
|
long page_size;
|
|
|
|
|
|
|
|
retval = false;
|
|
|
|
|
|
|
|
page_size = sysconf(_SC_PAGESIZE);
|
|
|
|
|
|
|
|
if ((long) start % page_size != 0)
|
|
|
|
{
|
|
|
|
retval = true;
|
|
|
|
warning_unexpected ("start = %p, page_size = %ld, "
|
|
|
|
"start %% page_size = %ld",
|
|
|
|
start, page_size, (long) start % page_size);
|
|
|
|
}
|
|
|
|
else if (length % page_size != 0)
|
|
|
|
{
|
|
|
|
retval = true;
|
|
|
|
warning_unexpected ("length = %ld, page_size = %ld, "
|
|
|
|
"length %% page_size = %ld",
|
|
|
|
(long) length, page_size, (long) length % page_size);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sig_t old_segv_handler;
|
|
|
|
volatile int n_pages;
|
|
|
|
volatile int n_failures;
|
|
|
|
volatile char *volatile addr;
|
|
|
|
char *stop;
|
|
|
|
|
|
|
|
n_pages = 0;
|
|
|
|
n_failures = 0;
|
|
|
|
stop = (char *) start + length;
|
|
|
|
|
|
|
|
old_segv_handler = signal (SIGSEGV, segv_handler);
|
|
|
|
for (addr = start; addr < stop; addr += page_size)
|
|
|
|
{
|
|
|
|
++n_pages;
|
|
|
|
if (sigsetjmp (segv_return, 1) != 0)
|
|
|
|
++n_failures;
|
|
|
|
else
|
|
|
|
*addr;
|
|
|
|
}
|
|
|
|
signal (SIGSEGV, old_segv_handler);
|
|
|
|
retval = n_failures < n_pages;
|
|
|
|
if (retval)
|
|
|
|
warning_unexpected ("%d pages were already mapped",
|
|
|
|
n_pages - n_failures);
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
2009-06-15 02:58:21 +00:00
|
|
|
#endif /* defined (MACOSX) */
|
2009-06-13 01:03:10 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This code used to try to get us memory that we could use directly (meaning
|
|
|
|
* it either included page 0 or was adjacent to page 0 and we could use some
|
|
|
|
* other trick to get page 0) without having to offset the emulated addresses.
|
|
|
|
*
|
|
|
|
* I doubt it works on many (any?) platforms anymore, and since speed of
|
|
|
|
* emulation isn't an issue, we really shouldn't care.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void *
|
|
|
|
mmap_permanent_memory (unsigned long amount_wanted)
|
|
|
|
{
|
|
|
|
#if defined(MACOSX)
|
|
|
|
return NULL;
|
|
|
|
#else
|
|
|
|
caddr_t addr_got;
|
|
|
|
caddr_t badness_start;
|
|
|
|
|
|
|
|
/* Only do this if our text segment is up nice and high out of the way. */
|
|
|
|
if (((unsigned long) mmap_permanent_memory & 0xFF000000L) == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
{
|
|
|
|
extern void *_start;
|
|
|
|
|
|
|
|
badness_start = (caddr_t) ((unsigned long) &_start
|
|
|
|
/ (1024 * 1024) * (1024 * 1024));
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !defined (powerpc)
|
|
|
|
{
|
|
|
|
caddr_t addr_wanted;
|
|
|
|
|
|
|
|
addr_wanted = round_up_to_page_size (PAGE_ZERO_START + PAGE_ZERO_SIZE);
|
|
|
|
|
|
|
|
if (addr_wanted + amount_wanted > badness_start)
|
|
|
|
{
|
|
|
|
warning_unexpected ("addr_wanted = %p, amount_wanted = 0x%lx, "
|
|
|
|
"badness_start = %p", addr_wanted, amount_wanted,
|
|
|
|
badness_start);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mmap_conflict (addr_wanted, amount_wanted))
|
|
|
|
addr_got = NULL;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
addr_got = mmap (addr_wanted, amount_wanted, PROT_READ | PROT_WRITE,
|
|
|
|
MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, -1, 0);
|
|
|
|
if (addr_got == (caddr_t) -1)
|
|
|
|
addr_got = NULL;
|
|
|
|
else if (addr_got != addr_wanted)
|
|
|
|
warning_unexpected ("addr_wanted = %p, addr_got = %p",
|
|
|
|
addr_wanted, addr_got);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
|
|
#warning THIS CODE IS PROBABLY WRONG
|
|
|
|
|
|
|
|
/*
|
|
|
|
* I haven't tested a powerpc build in a while, but I just noticed that
|
|
|
|
* we're trying to mmap from 0 and then we're returning addr_got. I think
|
|
|
|
* that when we return 0, the caller believes that we weren't able to
|
|
|
|
* mmap the low globals. As such, the code below PROBABLY DOESN'T DO
|
|
|
|
* ANYTHING DIFFERENT THAN SIMPLY RETURNING NULL.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (amount_wanted > badness_start)
|
|
|
|
{
|
|
|
|
warning_unexpected ("amount_wanted = 0x%x, badness_start = %p",
|
|
|
|
amount_wanted, badness_start);
|
|
|
|
addr_got = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
addr_got = mmap (0, amount_wanted, PROT_READ | PROT_WRITE,
|
|
|
|
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
|
|
|
if (addr_got == (caddr_t) -1)
|
|
|
|
addr_got = NULL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return addr_got;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* defined (LINUX) || defined (MACOSX) */
|