Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/*
*
* 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.
*
*/
/* Assumptions these routines are based on:
os_validate: Not called with NULL for an addr.
os_invalidate: Never called.
os_map: Files are only mapped at the beginning of one of the areas passed
to os_validate.
os_protect: Only called on an entire region when giving permissions and only
called from some point in a segment to the end of the segment
when removing them.
Only called with all protections or no protections.
os_zero: Only ever zeroed from some point in a segment to the end of the
segment.
os_allocate_at: Calls to here are disjoint from those around it (the others
in os-common.c) since it calls os_validate and the others (in
os-common.c) use malloc, etc.
Note that os_validate does not actually allocate memory until it has to map
the particular section in.
*/
/* #define DEBUG */
#include <stdio.h>
#include <assert.h>
#include <signal.h>
#include <sys/file.h>
#include <unistd.h>
#include "os.h"
#include <sys/resource.h>
#include "interrupt.h"
#include <netdb.h>
os_vm_size_t os_vm_page_size = (-1);
#define ALLOC_SIZE 0x10000
os_vm_address_t base;
os_vm_size_t len;
os_vm_address_t valid;
os_vm_address_t protected;
void
os_init0(const char *argv[], const char *envp[])
{}
int i;
os_vm_page_size = sysconf(_SC_PAGE_SIZE);
for (i = 0; i < MAX_SEGMENTS; i++)
segments[i].len = 0;
os_vm_address_t os_validate(os_vm_address_t addr, os_vm_size_t len)
int fd, i;
caddr_t ret;
addr = os_trunc_to_page(addr);
len = os_round_up_size_to_page(len);
printf("os_validate: addr: 0x%X, len: 0x%X, end: 0x%X\n", addr, len,
addr + len);
#endif
assert(addr != NULL);
assert(len != 0);
for (i = 0; i < MAX_SEGMENTS; i++)
if (segments[i].len == 0)
break;
assert(i != MAX_SEGMENTS);
segments[i].base = addr;
segments[i].len = len;
segments[i].valid = addr;
segments[i].protected = addr + len;
return addr;
}
void
os_invalidate(os_vm_address_t addr, os_vm_size_t len)
{
}
os_vm_address_t
os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
{
addr = os_trunc_to_page(addr);
len = os_round_up_size_to_page(len);
if (mmap(addr, len, OS_VM_PROT_ALL, MAP_FILE | MAP_FIXED | MAP_PRIVATE, fd,
(off_t) offset) == (os_vm_address_t) - 1) {
perror("mmap");
return NULL;
}
for (i = 0; i < MAX_SEGMENTS; i++)
if (segments[i].len != 0 && segments[i].base == addr)
break;
assert(i != MAX_SEGMENTS);
assert(segments[i].valid == addr);
segments[i].valid = addr + len;
printf("os_map: addr: 0x%X, len: 0x%X, end: 0x%X\n", addr, len, addr + len);
}
void
os_flush_icache(os_vm_address_t address, os_vm_size_t length)
{
sanctify_for_execution(address, length);
}
void
os_protect(os_vm_address_t addr, os_vm_size_t len, os_vm_prot_t prot)
{
int i;
addr = os_trunc_to_page(addr);
len = os_round_up_size_to_page(len);
for (i = 0; i < MAX_SEGMENTS; i++)
if (segments[i].base <= addr
&& addr < segments[i].base + segments[i].len) break;
assert(i != MAX_SEGMENTS);
if (prot) {
assert(segments[i].base == addr && segments[i].len == len);
segments[i].protected = addr + len;
} else {
assert(segments[i].protected == addr + len);
segments[i].protected = addr;
if (addr < segments[i].valid)
if (mprotect(addr, segments[i].valid - addr, prot) == -1) {
perror("mprotect");
printf("segments[i].base: 0x%X\n", segments[i].base);
printf("segments[i].len: 0x%X\n", segments[i].len);
printf("segments[i].valid: 0x%X\n", segments[i].valid);
printf("addr: 0x%X, segments[i].valid-addr: 0x%X\n", addr,
segments[i].valid - addr);
printf("prot: 0x%X, len 0x%X\n", prot, len);
assert(FALSE);
}
printf("os_protect: addr: 0x%X, len: 0x%X, end: 0x%X, prot 0x%X\n",
addr, len, addr + len, prot);
boolean valid_addr(os_vm_address_t addr)
for (i = 0; i < MAX_SEGMENTS; i++)
if (segments[i].base <= addr
&& addr < segments[i].base + segments[i].len) return TRUE;
return FALSE;
}
void
segv_handler(int signal, int code, struct sigcontext *context)
{
int i;
os_vm_address_t addr, nvalid;
sigsetmask(BLOCKABLE);
addr = (os_vm_address_t) context->sc_sl.sl_ss.ss_cr21; /* verify this!!! */
for (i = 0; i < MAX_SEGMENTS; i++)
if (segments[i].len != 0 && segments[i].base <= addr &&
addr < segments[i].base + segments[i].len)
break;
if (i == MAX_SEGMENTS || addr < segments[i].valid)
interrupt_handle_now(signal, code, context);
else if (segments[i].protected <= addr) {
if (!interrupt_maybe_gc(signal, code, context))
interrupt_handle_now(signal, code, context);
} else {
nvalid =
((os_vm_address_t)
(((long) (addr + ALLOC_SIZE)) & ~((long) (ALLOC_SIZE - 1))));
if (nvalid > segments[i].protected)
nvalid = segments[i].protected;
printf("Mapping: addr: 0x%08x, old: 0x%08x, new: 0x%08x\n",
addr, segments[i].valid, nvalid);
if (mmap(segments[i].valid, nvalid - segments[i].valid,
OS_VM_PROT_ALL, MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, -1,
0) == (os_vm_address_t) - 1) {
perror("mmap");
printf("segments[i].base: 0x%X\n", segments[i].base);
printf("segments[i].len: 0x%X\n", segments[i].len);
printf("segments[i].valid: 0x%X\n", segments[i].valid);
printf("segments[i].protected: 0x%X\n", segments[i].protected);
printf("nvalid: 0x%X\n", nvalid);
printf("nvalid-segments[i].valid: 0x%X\n",
nvalid - segments[i].valid);
assert(FALSE);
}
segments[i].valid = nvalid;
}
}
void
sigbus_handler(int signal, int code, struct sigcontext *context)
{
#ifdef DEBUG
printf("Bus Error at 0x%X\n", context->sc_sl.sl_ss.ss_cr21);
if (!interrupt_maybe_gc(signal, code, context))
interrupt_handle_now(signal, code, context);
os_install_interrupt_handlers(void)
interrupt_install_low_level_handler(SIGSEGV, segv_handler);
interrupt_install_low_level_handler(SIGBUS, sigbus_handler);
os_zero(os_vm_address_t addr, os_vm_size_t length)
{
os_vm_address_t block_start;
os_vm_size_t block_size;
int i;
fprintf(stderr, "os_zero: addr: 0x%08x, len: 0x%08x, end: 0x%X\n", addr,
length, addr + length);
block_start = os_round_up_to_page(addr);
length -= block_start - addr;
block_size = os_trunc_size_to_page(length);
if (block_start > addr)
memset((char *) addr, 0, block_start - addr);
if (block_size < length)
assert(FALSE);
if (block_size != 0) {
/* Now deallocate and allocate the block so that it */
/* faults in zero-filled. */
for (i = 0; i < MAX_SEGMENTS; i++)
if (segments[i].base <= block_start &&
block_start < segments[i].base + segments[i].len)
break;
assert(i != MAX_SEGMENTS);
assert(block_start + block_size == segments[i].base + segments[i].len);
if (segments[i].valid > block_start) {
if (munmap(block_start, segments[i].valid - block_start) == -1) {
perror("munmap");
return;
}
segments[i].valid = block_start;
os_vm_address_t os_allocate(os_vm_size_t len)
return (os_vm_address_t) malloc(len);
os_vm_address_t os_allocate_at(os_vm_address_t addr, os_vm_size_t len)
return os_validate(addr, len);
os_deallocate(os_vm_address_t addr, os_vm_size_t len)
os_reallocate(os_vm_address_t addr, os_vm_size_t old_len, os_vm_size_t len)
addr = (os_vm_address_t) realloc(addr, len);
assert(addr != NULL);
return addr;
int
getrusage(int who, struct rusage *rusage)
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
static long ticks_per_sec = 0;
static long usec_per_tick = 0;
struct tms buf;
clock_t uticks, sticks;
memset(rusage, 0, sizeof(struct rusage));
if (ticks_per_sec == 0) {
ticks_per_sec = sysconf(_SC_CLK_TCK);
usec_per_tick = 1000000 / ticks_per_sec;
}
if (times(&buf) == -1)
return -1;
if (who == RUSAGE_SELF) {
uticks = buf.tms_utime;
sticks = buf.tms_stime;
} else if (who == RUSAGE_CHILDREN) {
uticks = buf.tms_utime;
sticks = buf.tms_stime;
} else {
errno = EINVAL;
return -1;
}
rusage->ru_utime.tv_sec = uticks / ticks_per_sec;
rusage->ru_utime.tv_usec = (uticks % ticks_per_sec) * usec_per_tick;
rusage->ru_stime.tv_sec = sticks / ticks_per_sec;
rusage->ru_stime.tv_usec = (sticks % ticks_per_sec) * usec_per_tick;
return 0;
struct rlimit rlp;
assert(getrlimit(RLIMIT_NOFILE, &rlp) == 0);
return rlp.rlim_cur;
char hostname[256];
struct hostent *hostent;
static unsigned long addr = NULL;
if (addr)
return addr;
if (gethostname(hostname, sizeof(hostname)) == -1) {
perror("gethostname");
return 0;
}
hostent = gethostbyname(hostname);
if (hostent == NULL) {
perror("gethostbyname");
return 0;
}
addr = ((unsigned char *) (hostent->h_addr))[0] << 24 |
((unsigned char *) (hostent->h_addr))[1] << 16 |
((unsigned char *) (hostent->h_addr))[2] << 8 |
((unsigned char *) (hostent->h_addr))[3];
int
getpagesize(void)
{
return os_vm_page_size;