#include <u.h>
#include <libc.h>
#include <ureg.h>
#include "linux.h"
#include "linuxsys.h"
typedef struct Ureg Ureg;
static void maincall(ulong, ulong, char**, ulong);
static int linuxnote(void*, char*);
void* mmap(char*);
void* mmapfd(int);
void *bss;
int debug;
void
usage(void)
{
fprint(2, "usage: %s [-d] linuxprog args...\n", argv0);
exits("usage");
}
void
main(int argc, char **argv)
{
long entry = 0;
void *file;
ARGBEGIN{
case 'd':
debug = 1;
break;
default:
usage();
}ARGEND
if(argc < 1)
usage();
if((file = mmap(argv[0])) == nil) {
fprint(2, "mmap failed: %r\n");
exits("mmap");
}
if(memcmp(file, "\x7fELF", 4) == 0)
entry = elfload(file);
else {
fprint(2, "cannot identify binary\n");
exits("binary type");
}
if(entry <= 0) {
fprint(2, "error loading binary\n");
exits("binary load");
}
DPRINT("entry=%lux\n", entry);
maincall(entry, argc, argv, 0);
abort(); // not reached
}
/*
* set up the argument stack
* for linux and do the jmp.
* this should not return, since
* what we're jumping to is supposed
* to call exit.
*
* we use jumpstack, provided by stack.s
*
* it expects
*
* | envp
* |
* |----
* |
* | argv
* |
* |----
* | argc
* |---- ← sp
*
*/
static void
maincall(ulong entry, ulong argc, char **argv, ulong depth)
{
ulong buf[1024/4], *p;
int i, n;
/* BUG do environment */
n = 8; // padding
n += (argc+1)*4; // argv
n += 4; // argc
/*
* here's a kludge: we need some room on the
* stack. rather than try to assemble "SP -= n",
* since that will confuse the compiler, we just
* call ourselves lots of times to bring the stack
* depth down to what we want, giving us enough
* room. we have no intention of returning.
*/
depth++;
if(depth * sizeof buf < n)
maincall(entry, argc, argv, depth);
/* install ``syscall'' handler */
atnotify(linuxnote, 1);
p = (ulong*) buf;
*p++ = argc;
for(i=0; i<argc; i++)
*p++ = (ulong) argv[i];
*p++ = 0;
*p++ = 0;
*p = 0;
jumpstack(entry, buf);
abort(); // not reached.
}
static int
linuxnote(void *v, char *msg)
{
ulong n;
uchar *x;
Syscall f;
Ureg *ureg;
ureg = v;
if(strstr(msg, "general protection") == nil)
return 0;
x = (uchar*) ureg->pc;
if(x[0] != 0xCD || x[1] != 0x80) /* INT $0x80 */
return 0;
n = ureg->ax;
DPRINT("SYSCALL %d\n", n);
if(n >= LMAXSYSCALL || (f=syscalltab[ureg->ax]) == 0) {
print("wants unimplemented function %lux (%s) pc=%lux\n", n,
n < LMAXSYSCALL ? syscallname[n] : "(?)", ureg->pc);
ureg->ax = -1;
} else {
(*f)(ureg);
DPRINT("returns %lud=0x%lux...\n", ureg->ax, ureg->ax);
}
ureg->pc += 2;
return 1;
}
/*
* mmap, if it were handled by the kernel
*
void*
_mmap(char *name)
{
void *v;
Dir *d;
char *buf;
vlong len;
if((d = dirstat(name)) == nil || d->length == 0){
free(d);
return nil;
}
len = d->length;
free(d);
buf = malloc(strlen(name)+10);
if(buf == nil)
return nil;
sprint(buf, "file!%s", name);
v = (void*)segattach(0, buf, nil, len);
print("v=%lx file=%s len=%ld\n", v, name, len);
free(buf);
if(v == (void*)-1)
return nil;
return v;
}
void*
_mmapfd(int fd)
{
void *v;
Dir d;
char buf[30];
if(dirfstat(fd, &d) < 0 || d.length == 0)
return nil;
snprint(buf, sizeof buf, "file!/fd/%d", fd);
v = (void*)segattach(0, buf, nil, 4096);
if(v == (void*)-1)
return nil;
return v;
}
*/
/*
* crummy mmap. should be handled by kernel.
*/
void*
mmap(char *name)
{
void *v;
int fd;
if((fd = open(name, OREAD)) < 0)
return nil;
v = mmapfd(fd);
close(fd);
return v;
}
void*
mmapfd(int fd)
{
void *v;
Dir *d;
vlong len;
if((d = dirfstat(fd)) == nil)
return nil;
len = d->length;
free(d);
if(len == 0)
return nil;
v = malloc(len);
if(v == nil)
return nil;
if(readn(fd, v, len) != len) {
free(v);
return nil;
}
return v;
}
|