493 lines
10 KiB
C
493 lines
10 KiB
C
|
#include "tccboot.h"
|
||
|
|
||
|
//#define ROMFS_DEBUG
|
||
|
|
||
|
char msg_buf[1024];
|
||
|
|
||
|
void puts(const char *s)
|
||
|
{
|
||
|
putstr(s);
|
||
|
putstr("\n");
|
||
|
}
|
||
|
|
||
|
int printf(const char *fmt, ...)
|
||
|
{
|
||
|
va_list ap;
|
||
|
va_start(ap, fmt);
|
||
|
|
||
|
vsnprintf(msg_buf, sizeof(msg_buf), fmt, ap);
|
||
|
putstr(msg_buf);
|
||
|
va_end(ap);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
FILE *stderr;
|
||
|
|
||
|
int fprintf(FILE *f, const char *fmt, ...)
|
||
|
{
|
||
|
va_list ap;
|
||
|
va_start(ap, fmt);
|
||
|
|
||
|
vsnprintf(msg_buf, sizeof(msg_buf), fmt, ap);
|
||
|
putstr(msg_buf);
|
||
|
va_end(ap);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void getcwd(char *buf, size_t buf_size)
|
||
|
{
|
||
|
strcpy(buf, "/");
|
||
|
}
|
||
|
|
||
|
void fatal(const char *fmt, ...)
|
||
|
{
|
||
|
va_list ap;
|
||
|
va_start(ap, fmt);
|
||
|
|
||
|
putstr("tccboot: panic: ");
|
||
|
vsnprintf(msg_buf, sizeof(msg_buf), fmt, ap);
|
||
|
putstr(msg_buf);
|
||
|
putstr("\n");
|
||
|
va_end(ap);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
/**********************************************************/
|
||
|
|
||
|
int errno;
|
||
|
|
||
|
long strtol(const char *nptr, char **endptr, int base)
|
||
|
{
|
||
|
return simple_strtol(nptr, endptr, base);
|
||
|
}
|
||
|
|
||
|
long long strtoll(const char *nptr, char **endptr, int base)
|
||
|
{
|
||
|
return simple_strtoll(nptr, endptr, base);
|
||
|
}
|
||
|
|
||
|
unsigned long strtoul(const char *nptr, char **endptr, int base)
|
||
|
{
|
||
|
return simple_strtoul(nptr, endptr, base);
|
||
|
}
|
||
|
|
||
|
unsigned long long strtoull(const char *nptr, char **endptr, int base)
|
||
|
{
|
||
|
return simple_strtoull(nptr, endptr, base);
|
||
|
}
|
||
|
|
||
|
int atoi(const char *s)
|
||
|
{
|
||
|
return strtol(s, NULL, 10);
|
||
|
}
|
||
|
|
||
|
/**********************************************************/
|
||
|
|
||
|
int gettimeofday(struct timeval *tv, struct timezone *tz)
|
||
|
{
|
||
|
tv->tv_sec = 0;
|
||
|
tv->tv_usec = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
time_t time(time_t *t)
|
||
|
{
|
||
|
if (t)
|
||
|
*t = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
struct tm *localtime(const time_t *timep)
|
||
|
{
|
||
|
static struct tm static_tm;
|
||
|
return &static_tm;
|
||
|
}
|
||
|
|
||
|
int setjmp(jmp_buf buf)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void longjmp(jmp_buf buf, int val)
|
||
|
{
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
/**********************************************************/
|
||
|
#define MALLOC_MAX_SIZE (128 * 1024 * 1024)
|
||
|
extern uint8_t _end;
|
||
|
uint8_t *malloc_ptr = &_end;
|
||
|
|
||
|
void *sbrk(int increment)
|
||
|
{
|
||
|
uint8_t *ptr, *new_ptr;
|
||
|
|
||
|
if (increment == 0)
|
||
|
return malloc_ptr;
|
||
|
ptr = malloc_ptr;
|
||
|
new_ptr = malloc_ptr + increment;
|
||
|
if (new_ptr > (&_end + MALLOC_MAX_SIZE)) {
|
||
|
errno = ENOMEM;
|
||
|
return (void *)-1;
|
||
|
}
|
||
|
malloc_ptr = new_ptr;
|
||
|
return ptr;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
#define MALLOC_ALIGN 4096
|
||
|
|
||
|
void free(void *ptr)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void *realloc(void *oldptr, size_t size)
|
||
|
{
|
||
|
void *ptr;
|
||
|
if (size == 0) {
|
||
|
free(oldptr);
|
||
|
return NULL;
|
||
|
} else {
|
||
|
ptr = malloc(size);
|
||
|
/* XXX: incorrect */
|
||
|
if (oldptr) {
|
||
|
memcpy(ptr, oldptr, size);
|
||
|
free(oldptr);
|
||
|
}
|
||
|
return ptr;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
/**********************************************************/
|
||
|
|
||
|
uint8_t *romfs_base;
|
||
|
|
||
|
/* The basic structures of the romfs filesystem */
|
||
|
|
||
|
#define ROMBSIZE BLOCK_SIZE
|
||
|
#define ROMBSBITS BLOCK_SIZE_BITS
|
||
|
#define ROMBMASK (ROMBSIZE-1)
|
||
|
#define ROMFS_MAGIC 0x7275
|
||
|
|
||
|
#define ROMFS_MAXFN 128
|
||
|
|
||
|
#define __mkw(h,l) (((h)&0x00ff)<< 8|((l)&0x00ff))
|
||
|
#define __mkl(h,l) (((h)&0xffff)<<16|((l)&0xffff))
|
||
|
#define __mk4(a,b,c,d) htonl(__mkl(__mkw(a,b),__mkw(c,d)))
|
||
|
#define ROMSB_WORD0 __mk4('-','r','o','m')
|
||
|
#define ROMSB_WORD1 __mk4('1','f','s','-')
|
||
|
|
||
|
/* On-disk "super block" */
|
||
|
|
||
|
struct romfs_super_block {
|
||
|
uint32_t word0;
|
||
|
uint32_t word1;
|
||
|
uint32_t size;
|
||
|
uint32_t checksum;
|
||
|
char name[0]; /* volume name */
|
||
|
};
|
||
|
|
||
|
/* On disk inode */
|
||
|
|
||
|
struct romfs_inode {
|
||
|
uint32_t next; /* low 4 bits see ROMFH_ */
|
||
|
uint32_t spec;
|
||
|
uint32_t size;
|
||
|
uint32_t checksum;
|
||
|
char name[0];
|
||
|
};
|
||
|
|
||
|
#define ROMFH_TYPE 7
|
||
|
#define ROMFH_HRD 0
|
||
|
#define ROMFH_DIR 1
|
||
|
#define ROMFH_REG 2
|
||
|
#define ROMFH_SYM 3
|
||
|
#define ROMFH_BLK 4
|
||
|
#define ROMFH_CHR 5
|
||
|
#define ROMFH_SCK 6
|
||
|
#define ROMFH_FIF 7
|
||
|
#define ROMFH_EXEC 8
|
||
|
|
||
|
/* Alignment */
|
||
|
|
||
|
#define ROMFH_ALIGN 16
|
||
|
|
||
|
#define MAX_FILE_HANDLES 256
|
||
|
|
||
|
typedef struct FileHandle {
|
||
|
uint8_t *base;
|
||
|
unsigned long size, max_size;
|
||
|
unsigned long pos;
|
||
|
int is_rw;
|
||
|
} FileHandle;
|
||
|
|
||
|
static FileHandle file_handles[MAX_FILE_HANDLES];
|
||
|
|
||
|
static uint8_t *output_base;
|
||
|
static size_t output_max_size, output_size;
|
||
|
static uint8_t output_filename[128];
|
||
|
|
||
|
void set_output_file(const char *filename,
|
||
|
uint8_t *base, size_t size)
|
||
|
{
|
||
|
strcpy(output_filename, filename);
|
||
|
output_base = base;
|
||
|
output_max_size = size;
|
||
|
}
|
||
|
|
||
|
long get_output_file_size(void)
|
||
|
{
|
||
|
return output_size;
|
||
|
}
|
||
|
|
||
|
static inline int get_file_handle(void)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for(i = 0; i < MAX_FILE_HANDLES; i++) {
|
||
|
if (!file_handles[i].base)
|
||
|
return i;
|
||
|
}
|
||
|
errno = ENOMEM;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
int open(const char *filename, int access, ...)
|
||
|
{
|
||
|
struct romfs_super_block *sb;
|
||
|
unsigned long addr, next;
|
||
|
struct romfs_inode *inode;
|
||
|
int type, fd, len;
|
||
|
char dir[1024];
|
||
|
const char *p, *r;
|
||
|
|
||
|
if (access & O_CREAT) {
|
||
|
/* specific case for file creation */
|
||
|
if (strcmp(filename, output_filename) != 0)
|
||
|
return -EPERM;
|
||
|
fd = get_file_handle();
|
||
|
if (fd < 0)
|
||
|
return fd;
|
||
|
file_handles[fd].base = output_base;
|
||
|
file_handles[fd].max_size = output_max_size;
|
||
|
file_handles[fd].is_rw = 1;
|
||
|
file_handles[fd].pos = 0;
|
||
|
file_handles[fd].size = 0;
|
||
|
return fd;
|
||
|
}
|
||
|
|
||
|
show_filename(filename);
|
||
|
|
||
|
sb = (void *)romfs_base;
|
||
|
if (sb->word0 != ROMSB_WORD0 ||
|
||
|
sb->word1 != ROMSB_WORD1)
|
||
|
goto fail;
|
||
|
addr = ((unsigned long)sb->name + strlen(sb->name) + 1 + ROMFH_ALIGN - 1) &
|
||
|
~(ROMFH_ALIGN - 1);
|
||
|
inode = (void *)addr;
|
||
|
|
||
|
/* search the directory */
|
||
|
p = filename;
|
||
|
while (*p == '/')
|
||
|
p++;
|
||
|
for(;;) {
|
||
|
r = strchr(p, '/');
|
||
|
if (!r)
|
||
|
break;
|
||
|
len = r - p;
|
||
|
if (len > sizeof(dir) - 1)
|
||
|
goto fail;
|
||
|
memcpy(dir, p, len);
|
||
|
dir[len] = '\0';
|
||
|
p = r + 1;
|
||
|
#ifdef ROMFS_DEBUG
|
||
|
printf("dir=%s\n", dir);
|
||
|
#endif
|
||
|
|
||
|
for(;;) {
|
||
|
next = ntohl(inode->next);
|
||
|
type = next & 0xf;
|
||
|
next &= ~0xf;
|
||
|
if (!strcmp(dir, inode->name)) {
|
||
|
#ifdef ROMFS_DEBUG
|
||
|
printf("dirname=%s type=0x%x\n", inode->name, type);
|
||
|
#endif
|
||
|
if ((type & ROMFH_TYPE) == ROMFH_DIR) {
|
||
|
chdir:
|
||
|
addr = ((unsigned long)inode->name + strlen(inode->name) +
|
||
|
1 + ROMFH_ALIGN - 1) &
|
||
|
~(ROMFH_ALIGN - 1);
|
||
|
inode = (void *)addr;
|
||
|
break;
|
||
|
} else if ((type & ROMFH_TYPE) == ROMFH_HRD) {
|
||
|
addr = ntohl(inode->spec);
|
||
|
inode = (void *)(romfs_base + addr);
|
||
|
next = ntohl(inode->next);
|
||
|
type = next & 0xf;
|
||
|
if ((type & ROMFH_TYPE) != ROMFH_DIR)
|
||
|
goto fail;
|
||
|
goto chdir;
|
||
|
}
|
||
|
}
|
||
|
if (next == 0)
|
||
|
goto fail;
|
||
|
inode = (void *)(romfs_base + next);
|
||
|
}
|
||
|
}
|
||
|
for(;;) {
|
||
|
next = ntohl(inode->next);
|
||
|
type = next & 0xf;
|
||
|
next &= ~0xf;
|
||
|
#ifdef ROMFS_DEBUG
|
||
|
printf("name=%s type=0x%x\n", inode->name, type);
|
||
|
#endif
|
||
|
if ((type & ROMFH_TYPE) == ROMFH_REG) {
|
||
|
if (!strcmp(p, inode->name)) {
|
||
|
fd = get_file_handle();
|
||
|
if (fd < 0)
|
||
|
return fd;
|
||
|
addr = ((unsigned long)inode->name + strlen(inode->name) +
|
||
|
1 + ROMFH_ALIGN - 1) &
|
||
|
~(ROMFH_ALIGN - 1);
|
||
|
file_handles[fd].base = (void *)addr;
|
||
|
file_handles[fd].is_rw = 0;
|
||
|
file_handles[fd].pos = 0;
|
||
|
file_handles[fd].size = ntohl(inode->size);
|
||
|
return fd;
|
||
|
}
|
||
|
}
|
||
|
if (next == 0)
|
||
|
break;
|
||
|
inode = (void *)(romfs_base + next);
|
||
|
}
|
||
|
fail:
|
||
|
errno = ENOENT;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
int read(int fd, void *buf, size_t size)
|
||
|
{
|
||
|
FileHandle *fh = &file_handles[fd];
|
||
|
int len;
|
||
|
|
||
|
len = fh->size - fh->pos;
|
||
|
if (len > (int)size)
|
||
|
len = size;
|
||
|
memcpy(buf, fh->base + fh->pos, len);
|
||
|
fh->pos += len;
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
int write(int fd, const void *buf, size_t size)
|
||
|
{
|
||
|
FileHandle *fh = &file_handles[fd];
|
||
|
int len;
|
||
|
|
||
|
if (!fh->is_rw)
|
||
|
return -EIO;
|
||
|
len = fh->max_size - fh->pos;
|
||
|
if ((int)size > len) {
|
||
|
errno = ENOSPC;
|
||
|
return -1;
|
||
|
}
|
||
|
memcpy(fh->base + fh->pos, buf, size);
|
||
|
fh->pos += size;
|
||
|
if (fh->pos > fh->size) {
|
||
|
fh->size = fh->pos;
|
||
|
output_size = fh->pos;
|
||
|
}
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
long lseek(int fd, long offset, int whence)
|
||
|
{
|
||
|
FileHandle *fh = &file_handles[fd];
|
||
|
|
||
|
switch(whence) {
|
||
|
case SEEK_SET:
|
||
|
break;
|
||
|
case SEEK_END:
|
||
|
offset += fh->size;
|
||
|
break;
|
||
|
case SEEK_CUR:
|
||
|
offset += fh->pos;
|
||
|
break;
|
||
|
default:
|
||
|
errno = EINVAL;
|
||
|
return -1;
|
||
|
}
|
||
|
if (offset < 0) {
|
||
|
errno = EINVAL;
|
||
|
return -1;
|
||
|
}
|
||
|
fh->pos = offset;
|
||
|
return offset;
|
||
|
}
|
||
|
|
||
|
int close(int fd)
|
||
|
{
|
||
|
FileHandle *fh = &file_handles[fd];
|
||
|
fh->base = NULL;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**********************************************************/
|
||
|
|
||
|
float strtof(const char *nptr, char **endptr)
|
||
|
{
|
||
|
fatal("unimplemented: %s", __func__ );
|
||
|
}
|
||
|
|
||
|
long double strtold(const char *nptr, char **endptr)
|
||
|
{
|
||
|
fatal("unimplemented: %s", __func__ );
|
||
|
}
|
||
|
|
||
|
double ldexp(double x, int exp)
|
||
|
{
|
||
|
fatal("unimplemented: %s", __func__ );
|
||
|
}
|
||
|
|
||
|
FILE *fopen(const char *path, const char *mode)
|
||
|
{
|
||
|
fatal("unimplemented: %s", __func__ );
|
||
|
}
|
||
|
|
||
|
FILE *fdopen(int fildes, const char *mode)
|
||
|
{
|
||
|
FILE *f;
|
||
|
f = malloc(sizeof(FILE));
|
||
|
f->fd = fildes;
|
||
|
return f;
|
||
|
}
|
||
|
|
||
|
int fclose(FILE *stream)
|
||
|
{
|
||
|
close(stream->fd);
|
||
|
free(stream);
|
||
|
}
|
||
|
|
||
|
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
|
||
|
{
|
||
|
int ret;
|
||
|
if (nmemb == 1) {
|
||
|
ret = write(stream->fd, ptr, size);
|
||
|
if (ret < 0)
|
||
|
return ret;
|
||
|
} else {
|
||
|
ret = write(stream->fd, ptr, size * nmemb);
|
||
|
if (ret < 0)
|
||
|
return ret;
|
||
|
if (nmemb != 0)
|
||
|
ret /= nmemb;
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int fputc(int c, FILE *stream)
|
||
|
{
|
||
|
uint8_t ch = c;
|
||
|
write(stream->fd, &ch, 1);
|
||
|
return 0;
|
||
|
}
|