Newer
Older
* $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/solaris-os.c,v 1.6 2002/11/13 13:10:22 toy Exp $
*
* OS-dependent routines. This file (along with os.h) exports an
* OS-independent interface to the operating system VM facilities.
* Suprisingly, this interface looks a lot like the Mach interface
* (but simpler in some places). For some operating systems, a subset
* of these functions will have to be emulated.
*
* This is an experimental Solaris version based on sunos-os.c but
* without the VM hack of unmapped pages for the GC trigger which
* caused trouble when system calls were passed unmapped pages.
*
*/
#define DEBUG
#include <stdio.h>
#include <signal.h>
#include <sys/file.h>
#include <unistd.h>
#include <errno.h>
#include <sys/param.h>
#include <dlfcn.h>
#define OS_PROTERR SEGV_ACCERR
#define OS_MAPERR SEGV_MAPERR
#define OS_HASERRNO(code) ((code)->si_errno != 0)
#define OS_ERRNO(code) ((code)->si_errno)
#include "os.h"
/* To get dynamic_0_space and friends */
#include "globals.h"
/* To get memory map */
#include "sparc-validate.h"
/* For type_ListPointer and NIL */
#include "internals.h"
/* block size must be larger than the system page size */
#define SPARSE_BLOCK_SIZE (1<<15)
#define SPARSE_SIZE_MASK (SPARSE_BLOCK_SIZE-1)
#define PROT_DEFAULT OS_VM_PROT_ALL
#define OFFSET_NONE ((os_vm_offset_t)(~0))
#define EMPTYFILE "/tmp/empty"
#define ZEROFILE "/dev/zero"
#define INITIAL_MAX_SEGS 32
#define GROW_MAX_SEGS 16
extern char *getenv();
/* ---------------------------------------------------------------- */
#define ADJ_OFFSET(off,adj) (((off)==OFFSET_NONE) ? OFFSET_NONE : ((off)+(adj)))
long os_vm_page_size=(-1);
static long os_real_page_size=(-1);
static os_vm_size_t real_page_size_difference=0;
{
char buf[500];
sprintf(buf,"os_init: %s",arg);
perror(buf);
exit(1);
}
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
{
zero_fd=open(ZEROFILE,O_RDONLY);
if(zero_fd<0)
os_init_bailout(ZEROFILE);
os_vm_page_size = os_real_page_size = sysconf(_SC_PAGESIZE);
if(os_vm_page_size>OS_VM_DEFAULT_PAGESIZE){
fprintf(stderr,"os_init: Pagesize too large (%d > %d)\n",
os_vm_page_size,OS_VM_DEFAULT_PAGESIZE);
exit(1);
}else{
/*
* we do this because there are apparently dependencies on
* the pagesize being OS_VM_DEFAULT_PAGESIZE somewhere...
* but since the OS doesn't know we're using this restriction,
* we have to grovel around a bit to enforce it, thus anything
* that uses real_page_size_difference.
*/
real_page_size_difference=OS_VM_DEFAULT_PAGESIZE-os_vm_page_size;
os_vm_page_size=OS_VM_DEFAULT_PAGESIZE;
}
}
/* ---------------------------------------------------------------- */
os_vm_address_t
os_validate(os_vm_address_t addr, os_vm_size_t len)
{
int flags = MAP_PRIVATE|MAP_NORESERVE;
if(addr) flags|=MAP_FIXED;
if((addr = (os_vm_address_t) mmap((void*)addr, len, OS_VM_PROT_ALL, flags, zero_fd, 0))
== (os_vm_address_t) -1)
perror("mmap");
return addr;
}
void
os_invalidate(os_vm_address_t addr, os_vm_size_t len)
{
perror("munmap");
}
os_vm_address_t
os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
{
if((addr = (os_vm_address_t) mmap((void*) addr, len, OS_VM_PROT_ALL, MAP_PRIVATE|MAP_FIXED, fd,
(off_t) offset)) == (os_vm_address_t) -1)
perror("mmap");
return addr;
}
void
os_flush_icache(os_vm_address_t address, os_vm_size_t length)
{
static int flushit = -1;
/*
* On some systems, iflush needs to be emulated in the kernel
* On those systems, it isn't necessary
* Call getenv() only once.
*/
if (flushit == -1)
flushit = getenv("CMUCL_NO_SPARC_IFLUSH") == 0;
if (flushit) {
static int traceit = -1;
if (traceit == -1)
traceit = getenv("CMUCL_TRACE_SPARC_IFLUSH") != 0;
if (traceit)
fprintf(stderr,";;;iflush %p - %x\n", address,length);
flush_icache(address,length);
}
}
void
os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
{
static boolean
in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen)
char* beg = (char*) sbeg;
char* end = (char*) sbeg + slen;
char* adr = (char*) a;
return (adr >= beg && adr < end);
}
boolean
valid_addr(os_vm_address_t addr)
{
/* Stolen from Linux-os.c */
os_vm_address_t newaddr;
newaddr = os_trunc_to_page(addr);
/* Just assume address is valid if it lies within one of the known
spaces. (Unlike sunos-os which keeps track of every valid page.) */
return ( in_range_p(addr, READ_ONLY_SPACE_START, READ_ONLY_SPACE_SIZE)
|| in_range_p(addr, STATIC_SPACE_START , STATIC_SPACE_SIZE )
|| in_range_p(addr, DYNAMIC_0_SPACE_START, dynamic_space_size )
|| in_range_p(addr, DYNAMIC_1_SPACE_START, dynamic_space_size )
|| in_range_p(addr, CONTROL_STACK_START , CONTROL_STACK_SIZE )
|| in_range_p(addr, BINDING_STACK_START , BINDING_STACK_SIZE ));
}
/* ---------------------------------------------------------------- */
/*
caddr_t addr = code->si_addr;
SAVE_CONTEXT();
if(!interrupt_maybe_gc(signal, code, context)) {
/* a *real* protection fault */
fprintf(stderr, "segv_handler: Real protection violation: 0x%08x\n",
addr);
interrupt_handle_now(signal,code,context);
}
{
interrupt_install_low_level_handler(SIGSEGV,segv_handler);
}
int *
solaris_register_address(struct ucontext *context, int reg)
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
{
if (reg == 0) {
static int zero;
zero = 0;
return &zero;
} else if (reg < 16) {
return &context->uc_mcontext.gregs[reg+3];
} else if (reg < 32) {
int *sp = (int*) context->uc_mcontext.gregs[REG_SP];
return &sp[reg-16];
} else
return 0;
}
/* function defintions for backward compatibilty and static linking */
/* For now we put in some porting functions */
#ifndef SOLARIS25
int
getdtablesize(void)
{
return sysconf(_SC_OPEN_MAX);
}
char *
getwd(char *path)
{
return getcwd(path, MAXPATHLEN);
}
int
getpagesize(void)
{
return sysconf(_SC_PAGESIZE);
}
#include <sys/procfs.h>
/* Old rusage definition */
struct rusage {
struct timeval ru_utime; /* user time used */
struct timeval ru_stime; /* system time used */
long ru_maxrss;
#define ru_first ru_ixrss
long ru_ixrss; /* XXX: 0 */
long ru_idrss; /* XXX: sum of rm_asrss */
long ru_isrss; /* XXX: 0 */
long ru_minflt; /* any page faults not requiring I/O */
long ru_majflt; /* any page faults requiring I/O */
long ru_nswap; /* swaps */
long ru_inblock; /* block input operations */
long ru_oublock; /* block output operations */
long ru_msgsnd; /* messages sent */
long ru_msgrcv; /* messages received */
long ru_nsignals; /* signals received */
long ru_nvcsw; /* voluntary context switches */
long ru_nivcsw; /* involuntary " */
#define ru_last ru_nivcsw
};
int
getrusage(int who, struct rusage *rp)
{
memset(rp, 0, sizeof(struct rusage));
return 0;
}
int
setreuid()
{
fprintf(stderr,"setreuid unimplemented\n");
errno = ENOSYS;
return -1;
}
int
setregid()
{
fprintf(stderr,"setregid unimplemented\n");
errno = ENOSYS;
return -1;
}
int
gethostid()
{
fprintf(stderr,"gethostid unimplemented\n");
errno = ENOSYS;
return -1;
}
int
killpg(int pgrp, int sig)
{
if (pgrp < 0) {
errno = ESRCH;
return -1;
}
return kill(-pgrp, sig);
}
#endif
int
sigblock(int mask)
{
sigset_t old, new;
sigemptyset(&new);
new.__sigbits[0] = mask;
sigprocmask(SIG_BLOCK, &new, &old);
return old.__sigbits[0];
}
#ifndef SOLARIS25
int
wait3(int *status, int options, struct rusage *rp)
{
if (rp)
memset(rp, 0, sizeof(struct rusage));
return waitpid(-1, status, options);
}
#endif
int
sigsetmask(int mask)
{
sigset_t old, new;
sigemptyset(&new);
new.__sigbits[0] = mask;
sigprocmask(SIG_SETMASK, &new, &old);
return old.__sigbits[0];
}
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
os_vm_address_t
round_up_sparse_size(os_vm_address_t addr)
{
return (addr + SPARSE_BLOCK_SIZE - 1) & ~SPARSE_SIZE_MASK;
}
/*
* An array of the start of the spaces which should have holes placed
* after them. Must not include the dynamic spaces because the size
* of the dynamic space can be controlled from the command line.
*/
static os_vm_address_t spaces[] =
{
READ_ONLY_SPACE_START, STATIC_SPACE_START,
BINDING_STACK_START, CONTROL_STACK_START
};
/*
* The corresponding array for the size of each space. Be sure that
* the spaces and holes don't overlap! The sizes MUST be on
* SPARSE_BLOCK_SIZE boundaries.
*/
static unsigned long space_size[] =
{
READ_ONLY_SPACE_SIZE, STATIC_SPACE_SIZE,
BINDING_STACK_SIZE, CONTROL_STACK_SIZE
};
/*
* The size of the hole to make. It should be strictly smaller than
* SPARSE_BLOCK_SIZE.
*/
#define HOLE_SIZE 0x2000
void make_holes(void)
{
int k;
os_vm_address_t hole;
/* Make holes of the appropriate size for desired spaces */
for (k = 0; k < sizeof(spaces)/sizeof(spaces[0]); ++k)
{
hole = spaces[k] + space_size[k];
if (os_validate(hole, HOLE_SIZE) == NULL) {
fprintf(stderr,
"ensure_space: Failed to validate hole of %ld bytes at 0x%08X\n",
HOLE_SIZE,
(unsigned long)hole);
exit(1);
}
/* Make it inaccessible */
os_protect(hole, HOLE_SIZE, 0);
}
/* Round up the dynamic_space_size to the nearest SPARSE_BLOCK_SIZE */
dynamic_space_size = round_up_sparse_size(dynamic_space_size);
/* Now make a hole for the dynamic spaces */
hole = dynamic_space_size + (os_vm_address_t) dynamic_0_space;
if (os_validate(hole, HOLE_SIZE) == NULL)
{
fprintf(stderr,
"ensure_space: Failed to validate hold of %ld bytes at 0x%08X\n",
HOLE_SIZE,
(unsigned long)hole);
exit(1);
}
os_protect(hole, HOLE_SIZE, 0);
hole = dynamic_space_size + (os_vm_address_t) dynamic_1_space;
if (os_validate(hole, HOLE_SIZE) == NULL)
{
fprintf(stderr,
"ensure_space: Failed to validate hole of %ld bytes at 0x%08X\n",
HOLE_SIZE,
(unsigned long)hole);
exit(1);
}
os_protect(hole, HOLE_SIZE, 0);
}
void *os_dlsym(const char *sym_name, lispobj lib_list)
{
static void *program_handle;
void *sym_addr = 0;
if (!program_handle)
program_handle = dlopen((void *)0, RTLD_LAZY | RTLD_GLOBAL);
if (lib_list != NIL) {
lispobj lib_list_head;
for (lib_list_head = lib_list;
lib_list_head != NIL;
lib_list_head = (CONS(lib_list_head))->cdr) {
struct cons *lib_cons = CONS(CONS(lib_list_head)->car);
struct sap *dlhandle = (struct sap *)PTR(lib_cons->car);
sym_addr = dlsym((void *)dlhandle->pointer, sym_name);
if (sym_addr)
return sym_addr;
}
}
sym_addr = dlsym(program_handle, sym_name);
return sym_addr;