254 lines
6.1 KiB
C
254 lines
6.1 KiB
C
|
#include "tccboot.h"
|
||
|
#include <linux/tty.h>
|
||
|
#include <asm/io.h>
|
||
|
|
||
|
#define TCCARGS_FILE "/boot/tccargs"
|
||
|
#define KERNEL_MAX_SIZE (8 * 1024 * 1024)
|
||
|
#define INITRD_MAX_SIZE (20 * 1024 * 1024)
|
||
|
#define INITRD_MIN_ADDR 0x800000
|
||
|
#define KERNEL_FILENAME "kernel"
|
||
|
|
||
|
//#define DEBUG_INITRD_ADDR
|
||
|
|
||
|
#define MAX_ARGS 1024
|
||
|
|
||
|
struct moveparams {
|
||
|
uint8_t *low_buffer_start; int lcount;
|
||
|
uint8_t *high_buffer_start; int hcount;
|
||
|
};
|
||
|
|
||
|
static unsigned char *real_mode; /* Pointer to real-mode data */
|
||
|
#define EXT_MEM_K (*(unsigned short *)(real_mode + 0x2))
|
||
|
#ifndef STANDARD_MEMORY_BIOS_CALL
|
||
|
#define ALT_MEM_K (*(unsigned long *)(real_mode + 0x1e0))
|
||
|
#endif
|
||
|
#define SCREEN_INFO (*(struct screen_info *)(real_mode+0))
|
||
|
#define INITRD_START (*(unsigned long *) (real_mode+0x218))
|
||
|
#define INITRD_SIZE (*(unsigned long *) (real_mode+0x21c))
|
||
|
|
||
|
#define STACK_SIZE (256 * 1024)
|
||
|
|
||
|
long user_stack [STACK_SIZE];
|
||
|
|
||
|
struct {
|
||
|
long * a;
|
||
|
short b;
|
||
|
} stack_start = { & user_stack [STACK_SIZE] , __KERNEL_DS };
|
||
|
|
||
|
|
||
|
static char *vidmem = (char *)0xb8000;
|
||
|
static int vidport;
|
||
|
static int lines, cols;
|
||
|
|
||
|
void video_init(void)
|
||
|
{
|
||
|
if (SCREEN_INFO.orig_video_mode == 7) {
|
||
|
vidmem = (char *) 0xb0000;
|
||
|
vidport = 0x3b4;
|
||
|
} else {
|
||
|
vidmem = (char *) 0xb8000;
|
||
|
vidport = 0x3d4;
|
||
|
}
|
||
|
|
||
|
lines = SCREEN_INFO.orig_video_lines;
|
||
|
cols = SCREEN_INFO.orig_video_cols;
|
||
|
}
|
||
|
|
||
|
static void scroll(void)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
|
||
|
for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
|
||
|
vidmem[i] = ' ';
|
||
|
}
|
||
|
|
||
|
void putstr(const char *s)
|
||
|
{
|
||
|
int x,y,pos;
|
||
|
char c;
|
||
|
|
||
|
x = SCREEN_INFO.orig_x;
|
||
|
y = SCREEN_INFO.orig_y;
|
||
|
|
||
|
while ( ( c = *s++ ) != '\0' ) {
|
||
|
if ( c == '\n' ) {
|
||
|
x = 0;
|
||
|
if ( ++y >= lines ) {
|
||
|
scroll();
|
||
|
y--;
|
||
|
}
|
||
|
} else if (c == '\r') {
|
||
|
x = 0;
|
||
|
} else {
|
||
|
vidmem [ ( x + cols * y ) * 2 ] = c;
|
||
|
if ( ++x >= cols ) {
|
||
|
x = 0;
|
||
|
if ( ++y >= lines ) {
|
||
|
scroll();
|
||
|
y--;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SCREEN_INFO.orig_x = x;
|
||
|
SCREEN_INFO.orig_y = y;
|
||
|
|
||
|
pos = (x + cols * y) * 2; /* Update cursor position */
|
||
|
outb_p(14, vidport);
|
||
|
outb_p(0xff & (pos >> 9), vidport+1);
|
||
|
outb_p(15, vidport);
|
||
|
outb_p(0xff & (pos >> 1), vidport+1);
|
||
|
}
|
||
|
|
||
|
void exit(int val)
|
||
|
{
|
||
|
printf("\n\n -- System halted");
|
||
|
while (1);
|
||
|
}
|
||
|
|
||
|
char *tcc_args[MAX_ARGS];
|
||
|
|
||
|
static int expand_args(char ***pargv, const char *str)
|
||
|
{
|
||
|
const char *s1;
|
||
|
char **argv, *arg;
|
||
|
int argc, len;
|
||
|
|
||
|
argc = 0;
|
||
|
argv = tcc_args;
|
||
|
argv[argc++] = "tcc";
|
||
|
for(;;) {
|
||
|
while (isspace(*str))
|
||
|
str++;
|
||
|
if (*str == '\0')
|
||
|
break;
|
||
|
if (*str == '#') {
|
||
|
while (*str != '\n')
|
||
|
str++;
|
||
|
continue;
|
||
|
}
|
||
|
s1 = str;
|
||
|
while (*str != '\0' && !isspace(*str))
|
||
|
str++;
|
||
|
len = str - s1;
|
||
|
arg = malloc(len + 1);
|
||
|
memcpy(arg, s1, len);
|
||
|
arg[len] = '\0';
|
||
|
argv[argc++] = arg;
|
||
|
}
|
||
|
*pargv = argv;
|
||
|
return argc;
|
||
|
}
|
||
|
|
||
|
void show_filename(const char *filename)
|
||
|
{
|
||
|
int len;
|
||
|
static int counter;
|
||
|
char counter_ch[4] = "-\\|/";
|
||
|
|
||
|
len = strlen(filename);
|
||
|
if (len >= 2 && filename[len - 2] == '.' && filename[len - 1] == 'c') {
|
||
|
printf("%c %-50s\r", counter_ch[counter], filename);
|
||
|
counter = (counter + 1) & 3;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int compile_kernel(struct moveparams *mv, void *rmode)
|
||
|
{
|
||
|
int fd, len;
|
||
|
char *args_buf;
|
||
|
char **argv;
|
||
|
int argc, ret, romfs_len;
|
||
|
uint8_t *kernel_ptr, *initrd_ptr;
|
||
|
unsigned long romfs_base1;
|
||
|
|
||
|
real_mode = rmode;
|
||
|
|
||
|
video_init();
|
||
|
|
||
|
/* this is risky, but normally the initrd is not mapped inside the
|
||
|
malloc structures. However, it can overlap with its new
|
||
|
location */
|
||
|
if (!INITRD_SIZE || !INITRD_START)
|
||
|
fatal("the kernel source must be in a ROMFS filesystem stored as Initial Ram Disk (INITRD)");
|
||
|
len = INITRD_SIZE;
|
||
|
/* NOTE: it is very important to move initrd first to avoid
|
||
|
destroying it later */
|
||
|
initrd_ptr = memalign(16, len);
|
||
|
memmove(initrd_ptr, (void *)INITRD_START, len);
|
||
|
if (initrd_ptr[0] == 037 && ((initrd_ptr[1] == 0213) ||
|
||
|
(initrd_ptr[1] == 0236))) {
|
||
|
printf("Decompressing initrd...\n");
|
||
|
romfs_base = memalign(16, INITRD_MAX_SIZE);
|
||
|
romfs_len = do_gunzip(romfs_base, initrd_ptr, len);
|
||
|
/* realloc it to minimize memory usage */
|
||
|
romfs_base = realloc(romfs_base, romfs_len);
|
||
|
free(initrd_ptr);
|
||
|
} else {
|
||
|
romfs_base = initrd_ptr;
|
||
|
romfs_len = len;
|
||
|
}
|
||
|
|
||
|
kernel_ptr = malloc(KERNEL_MAX_SIZE);
|
||
|
set_output_file("kernel", kernel_ptr, KERNEL_MAX_SIZE);
|
||
|
|
||
|
#ifdef DEBUG_INITRD_ADDR
|
||
|
printf("romfs_base=%p romfs_len=%d kernel_ptr=%p\n",
|
||
|
romfs_base, romfs_len, kernel_ptr);
|
||
|
#endif
|
||
|
printf("Compiling kernel...\n");
|
||
|
|
||
|
fd = open("/boot/tccargs", O_RDONLY);
|
||
|
if (fd < 0)
|
||
|
fatal("Could not find '%s'", TCCARGS_FILE);
|
||
|
len = lseek(fd, 0, SEEK_END);
|
||
|
lseek(fd, 0, SEEK_SET);
|
||
|
args_buf = malloc(len + 1);
|
||
|
len = read(fd, args_buf, len);
|
||
|
close(fd);
|
||
|
|
||
|
args_buf[len] = '\0';
|
||
|
argc = expand_args(&argv, args_buf);
|
||
|
argv[argc] = NULL;
|
||
|
free(args_buf);
|
||
|
#if 0
|
||
|
{
|
||
|
int i;
|
||
|
for(i=0;i<argc;i++) {
|
||
|
printf("%d: '%s'\n", i, argv[i]);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
ret = main(argc, argv);
|
||
|
|
||
|
printf("%-50s\n", "");
|
||
|
|
||
|
printf("Ok, booting the kernel.\n");
|
||
|
|
||
|
mv->lcount = 0;
|
||
|
mv->hcount = get_output_file_size();
|
||
|
mv->high_buffer_start = kernel_ptr;
|
||
|
|
||
|
/* relocate the uncompressed initrd so that the kernel cannot
|
||
|
overwrite it */
|
||
|
romfs_base1 = ((unsigned long)(mv->high_buffer_start) +
|
||
|
mv->hcount + PAGE_SIZE - 1) &
|
||
|
~(PAGE_SIZE - 1);
|
||
|
if (romfs_base1 < INITRD_MIN_ADDR)
|
||
|
romfs_base1 = INITRD_MIN_ADDR;
|
||
|
if (!(kernel_ptr >= romfs_base + romfs_len &&
|
||
|
(unsigned long)romfs_base >= INITRD_MIN_ADDR) &&
|
||
|
(unsigned long)romfs_base < romfs_base1) {
|
||
|
memmove((void *)romfs_base1, romfs_base, romfs_len);
|
||
|
romfs_base = (void *)romfs_base1;
|
||
|
}
|
||
|
#ifdef DEBUG_INITRD_ADDR
|
||
|
printf("initrd_start=%p initrd_size=%d\n", romfs_base, romfs_len);
|
||
|
#endif
|
||
|
INITRD_START = (unsigned long)romfs_base;
|
||
|
INITRD_SIZE = romfs_len;
|
||
|
return 1;
|
||
|
}
|