first commit
This commit is contained in:
15
installboot/Makefile
Normal file
15
installboot/Makefile
Normal file
@@ -0,0 +1,15 @@
|
||||
PROG=installboot
|
||||
SRCS=$(wildcard *.c)
|
||||
OBJS=$(SRCS:.c=.o)
|
||||
|
||||
CFLAGS = -g -Wall -Werror
|
||||
CPPFLAGS = -I $(IDIR)
|
||||
|
||||
${PROG}: $(OBJS)
|
||||
$(CC) $(CFLAGS) -o $(BDIR)/$(PROG) $^
|
||||
cp filecopy.sh $(BDIR)
|
||||
|
||||
$(OBJS): ../dat.h
|
||||
|
||||
clean:
|
||||
rm -rf $(PROG) *.o
|
||||
65
installboot/elf32.h
Normal file
65
installboot/elf32.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#include <elf.h>
|
||||
|
||||
/* e_ident */
|
||||
#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
|
||||
(ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
|
||||
(ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
|
||||
(ehdr).e_ident[EI_MAG3] == ELFMAG3)
|
||||
|
||||
typedef Elf32_Ehdr Ehdr;
|
||||
typedef Elf32_Phdr Ephdr;
|
||||
typedef Elf32_Shdr Eshdr;
|
||||
typedef Elf32_Sym Esym;
|
||||
|
||||
static Ehdr
|
||||
readEhdr(int fd)
|
||||
{
|
||||
Ehdr h;
|
||||
|
||||
assert(pread(fd, &h, sizeof(h), 0) == h.e_ehsize);
|
||||
assert(IS_ELF(h) == 1);
|
||||
return h;
|
||||
}
|
||||
|
||||
static Ephdr
|
||||
readEphdr(int fd, Ehdr h, int i)
|
||||
{
|
||||
Ephdr ph;
|
||||
int off;
|
||||
|
||||
off = h.e_phoff+i*h.e_phentsize;
|
||||
assert(pread(fd, &ph, h.e_phentsize, off)
|
||||
== sizeof(Ephdr));
|
||||
return ph;
|
||||
}
|
||||
|
||||
static Eshdr
|
||||
readEshdr(int fd, Ehdr h, int i)
|
||||
{
|
||||
Eshdr sh;
|
||||
int off;
|
||||
|
||||
off = h.e_shoff + i*h.e_shentsize;
|
||||
assert(pread(fd, &sh, h.e_shentsize, off) == sizeof(sh));
|
||||
return sh;
|
||||
}
|
||||
|
||||
static void*
|
||||
readEcode(int fd, Ehdr h, Ephdr ph, void *dst)
|
||||
{
|
||||
if(dst == NULL)
|
||||
assert((dst = calloc(1, ph.p_filesz)) != NULL);
|
||||
assert(pread(fd, dst, ph.p_filesz, ph.p_offset) ==
|
||||
ph.p_filesz);
|
||||
return dst;
|
||||
}
|
||||
|
||||
static void*
|
||||
readsymtab(int fd, Eshdr sh, void *dst)
|
||||
{
|
||||
if(dst == NULL)
|
||||
assert((dst = calloc(1, sh.sh_size)) != NULL);
|
||||
assert(pread(fd, dst, sh.sh_size, sh.sh_offset)
|
||||
== sh.sh_size);
|
||||
return dst;
|
||||
}
|
||||
34
installboot/filecopy.sh
Executable file
34
installboot/filecopy.sh
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/bin/sh
|
||||
|
||||
abort()
|
||||
{
|
||||
umount $dir 2>/dev/null
|
||||
rm -rf $dir
|
||||
echo >&2 "fail to install"
|
||||
exit 0
|
||||
}
|
||||
|
||||
trap 'abort' 0
|
||||
set -eu
|
||||
|
||||
dir=$(mktemp -d)
|
||||
nsec=$((($(blockdev --getsz $1) - 64)/2))
|
||||
|
||||
if [ ${nsec} -ge $((16*1024)) ]
|
||||
then
|
||||
nsec=$((16*1024-64/2))
|
||||
fi
|
||||
|
||||
mkfs.fat -F16 -R 1 -r 512 -a -I --offset 64 $1 $nsec
|
||||
|
||||
mount -o offset=$((512*64)) $1 $dir
|
||||
|
||||
mkdir -p $dir/root
|
||||
|
||||
cp -f build/boot $dir/root/boot
|
||||
|
||||
trap - 0
|
||||
umount $dir >&2
|
||||
rm -rf $dir
|
||||
sync
|
||||
exit 1
|
||||
244
installboot/installboot.c
Normal file
244
installboot/installboot.c
Normal file
@@ -0,0 +1,244 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/wait.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include "dat.h"
|
||||
#include "elf32.h"
|
||||
|
||||
static char *devpath;
|
||||
static char *stage1 = "build/biosboot";
|
||||
static char *shpath = "build/filecopy.sh";
|
||||
static Disk dsk;
|
||||
static int btpart;
|
||||
static char btcode[512];
|
||||
|
||||
// need patch
|
||||
static struct{
|
||||
char *name;
|
||||
u32 size;
|
||||
u32 addr;
|
||||
union{
|
||||
u32 val;
|
||||
struct{
|
||||
u16 low;
|
||||
u16 high;
|
||||
};
|
||||
u8 byte;
|
||||
};
|
||||
}syms[] = {
|
||||
{"start_cluster", 2},
|
||||
{"dst_seg_off", 2},
|
||||
{"spc_sqrt", 1},
|
||||
{"clu_off", 2},
|
||||
{"part_offset", 2},
|
||||
{"shift_magic", 1},
|
||||
{"and_magic", 2},
|
||||
};
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "usgae: ./installboot device [bin]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
streq(char *a, char *b)
|
||||
{
|
||||
int la = strlen(a);
|
||||
return la==strlen(b) && memcmp(a, b, la)==0;
|
||||
}
|
||||
|
||||
void
|
||||
loadelf(char *fname)
|
||||
{
|
||||
int fd;
|
||||
char *tbbeg, *tbstr;
|
||||
Ehdr h;
|
||||
Ephdr ph;
|
||||
Eshdr shsym, shstr;
|
||||
Esym *tbsym;
|
||||
|
||||
assert((fd = open(fname, O_RDONLY))!=-1);
|
||||
h = readEhdr(fd);
|
||||
assert(h.e_phnum == 1); // only 1 program header
|
||||
assert(h.e_shnum >= 2);
|
||||
ph = readEphdr(fd, h, 0);
|
||||
assert(ph.p_filesz == sizeof(btcode));
|
||||
|
||||
for(int i = 0; i < h.e_shnum; ++i)
|
||||
if((shsym = readEshdr(fd, h, i)).sh_type == SHT_SYMTAB)
|
||||
goto found;
|
||||
assert(0 && "Can't find shymbol table\n");
|
||||
|
||||
found:
|
||||
shstr = readEshdr(fd, h, shsym.sh_link);
|
||||
assert(shstr.sh_type == SHT_STRTAB);
|
||||
assert((tbbeg = calloc(1, shstr.sh_size + shsym.sh_size))!=NULL);
|
||||
tbstr = readsymtab(fd, shstr, tbbeg);
|
||||
tbsym = readsymtab(fd, shsym, tbbeg+shstr.sh_size);
|
||||
|
||||
for(int i = 0; i < elem(syms); ++i){
|
||||
for(int j = 0; j < shsym.sh_size/sizeof(*tbsym); ++j)
|
||||
if(streq(syms[i].name, tbstr + tbsym[j].st_name)){
|
||||
syms[i].addr = tbsym[j].st_value;
|
||||
break;
|
||||
}
|
||||
assert(syms[i].addr != 0&& "Can't find symbol in symtab\n");
|
||||
}
|
||||
|
||||
readEcode(fd, h, ph, btcode);
|
||||
free(tbbeg);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void
|
||||
symset(char *name, u32 val)
|
||||
{
|
||||
for(int i = 0; i < elem(syms); ++i){
|
||||
if(streq(name, syms[i].name)){
|
||||
syms[i].val = val;
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(0 && "symbol not exist");
|
||||
}
|
||||
|
||||
uint
|
||||
tou32(u8 *str, int i)
|
||||
{
|
||||
uint x = 0;
|
||||
|
||||
do{
|
||||
x = x << 8;
|
||||
x |= str[--i];
|
||||
}while(i > 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
u16
|
||||
exponent(u16 x)
|
||||
{
|
||||
switch(x){
|
||||
case 1: return 0;
|
||||
case 2: return 1;
|
||||
case 4: return 2;
|
||||
case 8: return 4;
|
||||
case 16: return 8;
|
||||
case 32: return 16;
|
||||
case 512: return 9;
|
||||
case 1024: return 10;
|
||||
case 2048: return 11;
|
||||
case 4096: return 12;
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
emit(u64 off)
|
||||
{
|
||||
for(int i = 0; i < elem(syms); ++i){
|
||||
switch(syms[i].size){
|
||||
case 1:
|
||||
btcode[syms[i].addr] = syms[i].byte;
|
||||
break;
|
||||
case 2:
|
||||
*(u16*)&btcode[syms[i].addr] = syms[i].low;
|
||||
break;
|
||||
case 4:
|
||||
*(u32*)&btcode[syms[i].addr] = syms[i].val;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
assert(pwrite(dsk.fd, btcode+0x3c, sizeof(btcode)-0x3c, off+0x3c) ==
|
||||
sizeof(btcode)-0x3c);
|
||||
}
|
||||
|
||||
void
|
||||
setbootparam(int ino, int off, int sec)
|
||||
{
|
||||
u8 buf[512];
|
||||
u16 rdsecsz, dasec;
|
||||
|
||||
assert(sizeof(buf) == pread(dsk.fd, buf, sizeof(buf), off));
|
||||
|
||||
u32 bps = tou32(buf+0x0b, 2);
|
||||
u32 spc = tou32(buf+0x0d, 1);
|
||||
u32 res = tou32(buf+0x0e, 2);
|
||||
u32 nfat = tou32(buf+0x10, 1);
|
||||
u32 nrde = tou32(buf+0x11, 2);
|
||||
// u32 nsec = tou32(buf+0x13, 2);
|
||||
u32 nspf = tou32(buf+0x16, 2); // numberof sector per fat16
|
||||
rdsecsz = (nrde*32 + (bps - 1))/bps;
|
||||
dasec = res + (nspf*nfat) + rdsecsz;
|
||||
assert(0xaa55 == tou32(buf+0x1fe, 2));
|
||||
|
||||
symset("dst_seg_off", bps>>4);
|
||||
symset("start_cluster", ino);
|
||||
symset("spc_sqrt", exponent(spc));
|
||||
symset("clu_off", dasec - 2 * spc);
|
||||
symset("part_offset", sec);
|
||||
symset("shift_magic", exponent(bps)-3);
|
||||
symset("and_magic", bps-1);
|
||||
}
|
||||
|
||||
void
|
||||
catpath(char *dst, char *s1, char *s2)
|
||||
{
|
||||
while(*s1)
|
||||
*dst++ = *s1++;
|
||||
*dst++ = '/';
|
||||
while(*s2)
|
||||
*dst++ = *s2++;
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
void
|
||||
install(void)
|
||||
{
|
||||
char *args[] = {shpath, devpath, NULL};
|
||||
pid_t pid;
|
||||
u64 beg;
|
||||
|
||||
switch(pid = fork()){
|
||||
default:
|
||||
assert(wait(NULL) == pid);
|
||||
sync();
|
||||
break;
|
||||
case 0:
|
||||
assert(execvp(args[0], args) != -1);
|
||||
case -1:
|
||||
assert(0);
|
||||
}
|
||||
dsk = diskopen(devpath, O_RDWR);
|
||||
for(int i = 0; i < elem(dsk.parts); ++i)
|
||||
if(dsk.parts[i].type == DOSPTYP_FAT16 && dsk.parts[i].flag == DOSACTIVE){
|
||||
btpart = i;
|
||||
goto found;
|
||||
}
|
||||
assert(0);
|
||||
|
||||
found:
|
||||
beg = dsk.parts[btpart].beg * dsk.bps;
|
||||
setbootparam(4, beg, dsk.parts[btpart].beg);
|
||||
emit(beg);
|
||||
close(dsk.fd);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
if(argc < 2 || argc > 3)
|
||||
usage();
|
||||
devpath = argv[1];
|
||||
loadelf(stage1);
|
||||
install();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user