TCCBOOT/lib.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;
}