plan9fox/sys/src/9/port/rebootcmd.c
cinap_lenrek c2297ce5c1 kernel: use 64-bit virtual entry point for expanded header, document behaviour in a.out(6)
For 64-bit architectures, the a.out header has the HDR_MAGIC flag set
in the magic and is expanded by 8 bytes containing the 64-bit virtual
address of the programs entry point. While Exec.entry contains physical
address for kernel images.

Our sysexec() would always use Exec.entry, even for 64-bit a.out binaries,
which worked because PADDR(entry) == entry for userspace pointers.

This change fixes it, having the kernel use the 64-bit entry point
and document the behaviour in the manpage.
2021-05-29 14:18:35 +02:00

94 lines
1.5 KiB
C

#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include "a.out.h"
static void
readn(Chan *c, void *vp, long n)
{
char *p = vp;
long nn;
while(n > 0) {
nn = devtab[c->type]->read(c, p, n, c->offset);
if(nn == 0)
error(Eshort);
c->offset += nn;
p += nn;
n -= nn;
}
}
void
rebootcmd(int argc, char *argv[])
{
struct {
Exec;
uvlong hdr[1];
} ehdr;
Chan *c;
ulong magic, text, rtext, entry, data, size, align;
uchar *p;
if(argc == 0)
exit(0);
c = namec(argv[0], Aopen, OEXEC, 0);
if(waserror()){
cclose(c);
nexterror();
}
readn(c, &ehdr, sizeof(Exec));
magic = beswal(ehdr.magic);
entry = beswal(ehdr.entry);
text = beswal(ehdr.text);
data = beswal(ehdr.data);
if(!(magic == AOUT_MAGIC)){
switch(magic){
case I_MAGIC:
case S_MAGIC:
if((I_MAGIC == AOUT_MAGIC) || (S_MAGIC == AOUT_MAGIC))
break;
default:
error(Ebadexec);
}
}
if(magic & HDR_MAGIC)
readn(c, ehdr.hdr, sizeof(ehdr.hdr));
switch(magic){
case R_MAGIC:
align = 0x10000; /* 64k segment alignment for arm64 */
break;
default:
align = BY2PG;
break;
}
/* round text out to page boundary */
rtext = ROUND(entry+text, align)-entry;
size = rtext + data;
p = malloc(size);
if(p == nil)
error(Enomem);
if(waserror()){
free(p);
nexterror();
}
memset(p, 0, size);
readn(c, p, text);
readn(c, p + rtext, data);
ksetenv("bootfile", argv[0], 1);
reboot((void*)entry, p, size);
error(Egreg);
}