diff options
Diffstat (limited to 'arch/mn10300/boot')
-rw-r--r-- | arch/mn10300/boot/.gitignore | 1 | ||||
-rw-r--r-- | arch/mn10300/boot/Makefile | 28 | ||||
-rw-r--r-- | arch/mn10300/boot/compressed/Makefile | 22 | ||||
-rw-r--r-- | arch/mn10300/boot/compressed/head.S | 86 | ||||
-rw-r--r-- | arch/mn10300/boot/compressed/misc.c | 429 | ||||
-rw-r--r-- | arch/mn10300/boot/compressed/misc.h | 18 | ||||
-rw-r--r-- | arch/mn10300/boot/compressed/vmlinux.lds | 9 | ||||
-rw-r--r-- | arch/mn10300/boot/install.sh | 67 | ||||
-rw-r--r-- | arch/mn10300/boot/tools/build.c | 190 |
9 files changed, 850 insertions, 0 deletions
diff --git a/arch/mn10300/boot/.gitignore b/arch/mn10300/boot/.gitignore new file mode 100644 index 00000000000..b6718de2369 --- /dev/null +++ b/arch/mn10300/boot/.gitignore @@ -0,0 +1 @@ +zImage diff --git a/arch/mn10300/boot/Makefile b/arch/mn10300/boot/Makefile new file mode 100644 index 00000000000..36c9caf8ea0 --- /dev/null +++ b/arch/mn10300/boot/Makefile @@ -0,0 +1,28 @@ +# MN10300 kernel compressor and wrapper +# +# Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd. +# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. +# Written by David Howells (dhowells@redhat.com) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public Licence +# as published by the Free Software Foundation; either version +# 2 of the Licence, or (at your option) any later version. +# + +targets := vmlinux.bin zImage + +subdir- := compressed + +# --------------------------------------------------------------------------- + + +$(obj)/zImage: $(obj)/compressed/vmlinux FORCE + $(call if_changed,objcopy) + @echo 'Kernel: $@ is ready' + +$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE + $(call if_changed,objcopy) + +$(obj)/compressed/vmlinux: FORCE + $(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@ diff --git a/arch/mn10300/boot/compressed/Makefile b/arch/mn10300/boot/compressed/Makefile new file mode 100644 index 00000000000..08a95e17168 --- /dev/null +++ b/arch/mn10300/boot/compressed/Makefile @@ -0,0 +1,22 @@ +# +# Create a compressed vmlinux image from the original vmlinux +# + +targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o + +LDFLAGS_vmlinux := -Ttext $(CONFIG_KERNEL_ZIMAGE_BASE_ADDRESS) -e startup_32 + +$(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE + $(call if_changed,ld) + @: + +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) + +$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE + $(call if_changed,gzip) + +LDFLAGS_piggy.o := -r --format binary --oformat elf32-am33lin -T + +$(obj)/piggy.o: $(obj)/vmlinux.lds $(obj)/vmlinux.bin.gz FORCE + $(call if_changed,ld) diff --git a/arch/mn10300/boot/compressed/head.S b/arch/mn10300/boot/compressed/head.S new file mode 100644 index 00000000000..502e1eb5670 --- /dev/null +++ b/arch/mn10300/boot/compressed/head.S @@ -0,0 +1,86 @@ +/* Boot entry point for a compressed MN10300 kernel + * + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + .section .text + +#define DEBUG + +#include <linux/linkage.h> +#include <asm/cpu-regs.h> + + .globl startup_32 +startup_32: + # first save off parameters from bootloader + mov param_save_area,a0 + mov d0,(a0) + mov d1,(4,a0) + mov d2,(8,a0) + + mov sp,a3 + mov decomp_stack+0x2000-4,a0 + mov a0,sp + + # invalidate and enable both of the caches + mov CHCTR,a0 + clr d0 + movhu d0,(a0) # turn off first + mov CHCTR_ICINV|CHCTR_DCINV,d0 + movhu d0,(a0) + setlb + mov (a0),d0 + btst CHCTR_ICBUSY|CHCTR_DCBUSY,d0 # wait till not busy + lne + mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD,d0 # writethru dcache + movhu d0,(a0) # enable + + # clear the BSS area + mov __bss_start,a0 + mov _end,a1 + clr d0 +bssclear: + cmp a1,a0 + bge bssclear_end + movbu d0,(a0) + inc a0 + bra bssclear +bssclear_end: + + # decompress the kernel + call decompress_kernel[],0 + + # disable caches again + mov CHCTR,a0 + clr d0 + movhu d0,(a0) + setlb + mov (a0),d0 + btst CHCTR_ICBUSY|CHCTR_DCBUSY,d0 # wait till not busy + lne + + mov param_save_area,a0 + mov (a0),d0 + mov (4,a0),d1 + mov (8,a0),d2 + + mov a3,sp + mov CONFIG_KERNEL_TEXT_ADDRESS,a0 + jmp (a0) + + .data + .align 4 +param_save_area: + .rept 3 + .word 0 + .endr + + .section .bss + .align 4 +decomp_stack: + .space 0x2000 diff --git a/arch/mn10300/boot/compressed/misc.c b/arch/mn10300/boot/compressed/misc.c new file mode 100644 index 00000000000..ded207efc97 --- /dev/null +++ b/arch/mn10300/boot/compressed/misc.c @@ -0,0 +1,429 @@ +/* MN10300 Miscellaneous helper routines for kernel decompressor + * + * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd. + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. + * Modified by David Howells (dhowells@redhat.com) + * - Derived from arch/x86/boot/compressed/misc_32.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ +#include <linux/compiler.h> +#include <asm/serial-regs.h> +#include "misc.h" + +#ifndef CONFIG_GDBSTUB_ON_TTYSx +/* display 'Uncompressing Linux... ' messages on ttyS0 or ttyS1 */ +#if 1 /* ttyS0 */ +#define CYG_DEV_BASE 0xA6FB0000 +#else /* ttyS1 */ +#define CYG_DEV_BASE 0xA6FC0000 +#endif + +#define CYG_DEV_THR (*((volatile __u8*)(CYG_DEV_BASE + 0x00))) +#define CYG_DEV_MCR (*((volatile __u8*)(CYG_DEV_BASE + 0x10))) +#define SIO_MCR_DTR 0x01 +#define SIO_MCR_RTS 0x02 +#define CYG_DEV_LSR (*((volatile __u8*)(CYG_DEV_BASE + 0x14))) +#define SIO_LSR_THRE 0x20 /* transmitter holding register empty */ +#define SIO_LSR_TEMT 0x40 /* transmitter register empty */ +#define CYG_DEV_MSR (*((volatile __u8*)(CYG_DEV_BASE + 0x18))) +#define SIO_MSR_CTS 0x10 /* clear to send */ +#define SIO_MSR_DSR 0x20 /* data set ready */ + +#define LSR_WAIT_FOR(STATE) \ + do { while (!(CYG_DEV_LSR & SIO_LSR_##STATE)) {} } while (0) +#define FLOWCTL_QUERY(LINE) \ + ({ CYG_DEV_MSR & SIO_MSR_##LINE; }) +#define FLOWCTL_WAIT_FOR(LINE) \ + do { while (!(CYG_DEV_MSR & SIO_MSR_##LINE)) {} } while (0) +#define FLOWCTL_CLEAR(LINE) \ + do { CYG_DEV_MCR &= ~SIO_MCR_##LINE; } while (0) +#define FLOWCTL_SET(LINE) \ + do { CYG_DEV_MCR |= SIO_MCR_##LINE; } while (0) +#endif + +/* + * gzip declarations + */ + +#define OF(args) args +#define STATIC static + +#undef memset +#undef memcpy + +static inline void *memset(const void *s, int c, size_t n) +{ + int i; + char *ss = (char *) s; + + for (i = 0; i < n; i++) + ss[i] = c; + return (void *)s; +} + +#define memzero(s, n) memset((s), 0, (n)) + +static inline void *memcpy(void *__dest, const void *__src, size_t __n) +{ + int i; + const char *s = __src; + char *d = __dest; + + for (i = 0; i < __n; i++) + d[i] = s[i]; + return __dest; +} + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define WSIZE 0x8000 /* Window size must be at least 32k, and a power of + * two */ + +static uch *inbuf; /* input buffer */ +static uch window[WSIZE]; /* sliding window buffer */ + +static unsigned insize; /* valid bytes in inbuf */ +static unsigned inptr; /* index of next byte to be processed in inbuf */ +static unsigned outcnt; /* bytes in output buffer */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond, msg) { if (!(cond)) error(msg); } +# define Trace(x) fprintf x +# define Tracev(x) { if (verbose) fprintf x ; } +# define Tracevv(x) { if (verbose > 1) fprintf x ; } +# define Tracec(c, x) { if (verbose && (c)) fprintf x ; } +# define Tracecv(c, x) { if (verbose > 1 && (c)) fprintf x ; } +#else +# define Assert(cond, msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c, x) +# define Tracecv(c, x) +#endif + +static int fill_inbuf(void); +static void flush_window(void); +static void error(const char *) __attribute__((noreturn)); +static void kputs(const char *); + +static inline unsigned char get_byte(void) +{ + unsigned char ch = inptr < insize ? inbuf[inptr++] : fill_inbuf(); + +#if 0 + char hex[3]; + hex[0] = ((ch & 0x0f) > 9) ? + ((ch & 0x0f) + 'A' - 0xa) : ((ch & 0x0f) + '0'); + hex[1] = ((ch >> 4) > 9) ? + ((ch >> 4) + 'A' - 0xa) : ((ch >> 4) + '0'); + hex[2] = 0; + kputs(hex); +#endif + return ch; +} + +/* + * This is set up by the setup-routine at boot-time + */ +#define EXT_MEM_K (*(unsigned short *)0x90002) +#ifndef STANDARD_MEMORY_BIOS_CALL +#define ALT_MEM_K (*(unsigned long *) 0x901e0) +#endif +#define SCREEN_INFO (*(struct screen_info *)0x90000) + +static long bytes_out; +static uch *output_data; +static unsigned long output_ptr; + + +static void *malloc(int size); + +static inline void free(void *where) +{ /* Don't care */ +} + +static unsigned long free_mem_ptr = (unsigned long) &end; +static unsigned long free_mem_end_ptr = (unsigned long) &end + 0x90000; + +static inline void gzip_mark(void **ptr) +{ + kputs("."); + *ptr = (void *) free_mem_ptr; +} + +static inline void gzip_release(void **ptr) +{ + free_mem_ptr = (unsigned long) *ptr; +} + +#define INPLACE_MOVE_ROUTINE 0x1000 +#define LOW_BUFFER_START 0x2000 +#define LOW_BUFFER_END 0x90000 +#define LOW_BUFFER_SIZE (LOW_BUFFER_END - LOW_BUFFER_START) +#define HEAP_SIZE 0x3000 +static int high_loaded; +static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/; + +static char *vidmem = (char *)0xb8000; +static int lines, cols; + +#include "../../../../lib/inflate.c" + +static void *malloc(int size) +{ + void *p; + + if (size < 0) + error("Malloc error\n"); + if (!free_mem_ptr) + error("Memory error\n"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *) free_mem_ptr; + free_mem_ptr += size; + + if (free_mem_ptr >= free_mem_end_ptr) + error("\nOut of memory\n"); + + return p; +} + +static inline 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] = ' '; +} + +static inline void kputchar(unsigned char ch) +{ +#ifdef CONFIG_MN10300_UNIT_ASB2305 + while (SC0STR & SC01STR_TBF) + continue; + + if (ch == 0x0a) { + SC0TXB = 0x0d; + while (SC0STR & SC01STR_TBF) + continue; + } + + SC0TXB = ch; + +#else + while (SC1STR & SC01STR_TBF) + continue; + + if (ch == 0x0a) { + SC1TXB = 0x0d; + while (SC1STR & SC01STR_TBF) + continue; + } + + SC1TXB = ch; + +#endif +} + +static void kputs(const char *s) +{ +#ifdef CONFIG_DEBUG_DECOMPRESS_KERNEL +#ifndef CONFIG_GDBSTUB_ON_TTYSx + char ch; + + FLOWCTL_SET(DTR); + + while (*s) { + LSR_WAIT_FOR(THRE); + + ch = *s++; + if (ch == 0x0a) { + CYG_DEV_THR = 0x0d; + LSR_WAIT_FOR(THRE); + } + CYG_DEV_THR = ch; + } + + FLOWCTL_CLEAR(DTR); +#else + + for (; *s; s++) + kputchar(*s); + +#endif +#endif /* CONFIG_DEBUG_DECOMPRESS_KERNEL */ +} + +/* =========================================================================== + * Fill the input buffer. This is called only when the buffer is empty + * and at least one byte is really needed. + */ +static int fill_inbuf() +{ + if (insize != 0) + error("ran out of input data\n"); + + inbuf = input_data; + insize = input_len; + inptr = 1; + return inbuf[0]; +} + +/* =========================================================================== + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ +static void flush_window_low(void) +{ + ulg c = crc; /* temporary variable */ + unsigned n; + uch *in, *out, ch; + + in = window; + out = &output_data[output_ptr]; + for (n = 0; n < outcnt; n++) { + ch = *out++ = *in++; + c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + output_ptr += (ulg)outcnt; + outcnt = 0; +} + +static void flush_window_high(void) +{ + ulg c = crc; /* temporary variable */ + unsigned n; + uch *in, ch; + in = window; + for (n = 0; n < outcnt; n++) { + ch = *output_data++ = *in++; + if ((ulg) output_data == LOW_BUFFER_END) + output_data = high_buffer_start; + c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + outcnt = 0; +} + +static void flush_window(void) +{ + if (high_loaded) + flush_window_high(); + else + flush_window_low(); +} + +static void error(const char *x) +{ + kputs("\n\n"); + kputs(x); + kputs("\n\n -- System halted"); + + while (1) + /* Halt */; +} + +#define STACK_SIZE (4096) + +long user_stack[STACK_SIZE]; + +struct { + long *a; + short b; +} stack_start = { &user_stack[STACK_SIZE], 0 }; + +void setup_normal_output_buffer(void) +{ +#ifdef STANDARD_MEMORY_BIOS_CALL + if (EXT_MEM_K < 1024) + error("Less than 2MB of memory.\n"); +#else + if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) + error("Less than 2MB of memory.\n"); +#endif + output_data = (char *) 0x100000; /* Points to 1M */ +} + +struct moveparams { + uch *low_buffer_start; + int lcount; + uch *high_buffer_start; + int hcount; +}; + +void setup_output_buffer_if_we_run_high(struct moveparams *mv) +{ + high_buffer_start = (uch *)(((ulg) &end) + HEAP_SIZE); +#ifdef STANDARD_MEMORY_BIOS_CALL + if (EXT_MEM_K < (3 * 1024)) + error("Less than 4MB of memory.\n"); +#else + if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3 * 1024)) + error("Less than 4MB of memory.\n"); +#endif + mv->low_buffer_start = output_data = (char *) LOW_BUFFER_START; + high_loaded = 1; + free_mem_end_ptr = (long) high_buffer_start; + if (0x100000 + LOW_BUFFER_SIZE > (ulg) high_buffer_start) { + high_buffer_start = (uch *)(0x100000 + LOW_BUFFER_SIZE); + mv->hcount = 0; /* say: we need not to move high_buffer */ + } else { + mv->hcount = -1; + } + mv->high_buffer_start = high_buffer_start; +} + +void close_output_buffer_if_we_run_high(struct moveparams *mv) +{ + mv->lcount = bytes_out; + if (bytes_out > LOW_BUFFER_SIZE) { + mv->lcount = LOW_BUFFER_SIZE; + if (mv->hcount) + mv->hcount = bytes_out - LOW_BUFFER_SIZE; + } else { + mv->hcount = 0; + } +} + +#undef DEBUGFLAG +#ifdef DEBUGFLAG +int debugflag; +#endif + +int decompress_kernel(struct moveparams *mv) +{ +#ifdef DEBUGFLAG + while (!debugflag) + barrier(); +#endif + + output_data = (char *) CONFIG_KERNEL_TEXT_ADDRESS; + + makecrc(); + kputs("Uncompressing Linux... "); + gunzip(); + kputs("Ok, booting the kernel.\n"); + return 0; +} diff --git a/arch/mn10300/boot/compressed/misc.h b/arch/mn10300/boot/compressed/misc.h new file mode 100644 index 00000000000..da921cd172f --- /dev/null +++ b/arch/mn10300/boot/compressed/misc.h @@ -0,0 +1,18 @@ +/* Internal definitions for the MN10300 kernel decompressor + * + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +extern int end; + +/* + * vmlinux.lds + */ +extern char input_data[]; +extern int input_len; diff --git a/arch/mn10300/boot/compressed/vmlinux.lds b/arch/mn10300/boot/compressed/vmlinux.lds new file mode 100644 index 00000000000..a084903603f --- /dev/null +++ b/arch/mn10300/boot/compressed/vmlinux.lds @@ -0,0 +1,9 @@ +SECTIONS +{ + .data : { + input_len = .; + LONG(input_data_end - input_data) input_data = .; + *(.data) + input_data_end = .; + } +} diff --git a/arch/mn10300/boot/install.sh b/arch/mn10300/boot/install.sh new file mode 100644 index 00000000000..072951c8397 --- /dev/null +++ b/arch/mn10300/boot/install.sh @@ -0,0 +1,67 @@ +#!/bin/sh +# +# arch/mn10300/boot/install -c.sh +# +# This file is subject to the terms and conditions of the GNU General Public +# Licence. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1995 by Linus Torvalds +# +# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin +# +# "make install -c" script for i386 architecture +# +# Arguments: +# $1 - kernel version +# $2 - kernel image file +# $3 - kernel map file +# $4 - default install -c path (blank if root directory) +# $5 - boot rom file +# + +# User may have a custom install -c script + +rm -fr $4/../usr/include/linux $4/../usr/include/asm +install -c -m 0755 $2 $4/vmlinuz +install -c -m 0755 $5 $4/boot.rom +install -c -m 0755 -d $4/../usr/include/linux +cd $TOPDIR/include/linux +for i in `find . -maxdepth 1 -name '*.h' -print`; do + install -c -m 0644 $i $4/../usr/include/linux +done +install -c -m 0755 -d $4/../usr/include/linux/byteorder +cd $TOPDIR/include/linux/byteorder +for i in `find . -name '*.h' -print`; do + install -c -m 0644 $i $4/../usr/include/linux/byteorder +done +install -c -m 0755 -d $4/../usr/include/linux/lockd +cd $TOPDIR/include/linux/lockd +for i in `find . -name '*.h' -print`; do + install -c -m 0644 $i $4/../usr/include/linux/lockd +done +install -c -m 0755 -d $4/../usr/include/linux/netfilter_ipv4 +cd $TOPDIR/include/linux/netfilter_ipv4 +for i in `find . -name '*.h' -print`; do + install -c -m 0644 $i $4/../usr/include/linux/netfilter_ipv4 +done +install -c -m 0755 -d $4/../usr/include/linux/nfsd +cd $TOPDIR/include/linux/nfsd +for i in `find . -name '*.h' -print`; do + install -c -m 0644 $i $4/../usr/include/linux/nfsd/$i +done +install -c -m 0755 -d $4/../usr/include/linux/raid +cd $TOPDIR/include/linux/raid +for i in `find . -name '*.h' -print`; do + install -c -m 0644 $i $4/../usr/include/linux/raid +done +install -c -m 0755 -d $4/../usr/include/linux/sunrpc +cd $TOPDIR/include/linux/sunrpc +for i in `find . -name '*.h' -print`; do + install -c -m 0644 $i $4/../usr/include/linux/sunrpc +done +install -c -m 0755 -d $4/../usr/include/asm +cd $TOPDIR/include/asm +for i in `find . -name '*.h' -print`; do + install -c -m 0644 $i $4/../usr/include/asm +done diff --git a/arch/mn10300/boot/tools/build.c b/arch/mn10300/boot/tools/build.c new file mode 100644 index 00000000000..4f552ead0f8 --- /dev/null +++ b/arch/mn10300/boot/tools/build.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1997 Martin Mares + */ + +/* + * This file builds a disk-image from three different files: + * + * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest + * - setup: 8086 machine code, sets up system parm + * - system: 80386 code for actual system + * + * It does some checking that all files are of the correct type, and + * just writes the result to stdout, removing headers and padding to + * the right amount. It also writes some system data to stderr. + */ + +/* + * Changes by tytso to allow root device specification + * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 + * Cross compiling fixes by Gertjan van Wingerde, July 1996 + * Rewritten by Martin Mares, April 1997 + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> +#include <unistd.h> +#include <fcntl.h> +#include <asm/boot.h> + +#define DEFAULT_MAJOR_ROOT 0 +#define DEFAULT_MINOR_ROOT 0 + +/* Minimal number of setup sectors (see also bootsect.S) */ +#define SETUP_SECTS 4 + +uint8_t buf[1024]; +int fd; +int is_big_kernel; + +__attribute__((noreturn)) +void die(const char *str, ...) +{ + va_list args; + va_start(args, str); + vfprintf(stderr, str, args); + fputc('\n', stderr); + exit(1); +} + +void file_open(const char *name) +{ + fd = open(name, O_RDONLY, 0); + if (fd < 0) + die("Unable to open `%s': %m", name); +} + +__attribute__((noreturn)) +void usage(void) +{ + die("Usage: build [-b] bootsect setup system [rootdev] [> image]"); +} + +int main(int argc, char **argv) +{ + unsigned int i, c, sz, setup_sectors; + uint32_t sys_size; + uint8_t major_root, minor_root; + struct stat sb; + + if (argc > 2 && !strcmp(argv[1], "-b")) { + is_big_kernel = 1; + argc--, argv++; + } + if ((argc < 4) || (argc > 5)) + usage(); + if (argc > 4) { + if (!strcmp(argv[4], "CURRENT")) { + if (stat("/", &sb)) { + perror("/"); + die("Couldn't stat /"); + } + major_root = major(sb.st_dev); + minor_root = minor(sb.st_dev); + } else if (strcmp(argv[4], "FLOPPY")) { + if (stat(argv[4], &sb)) { + perror(argv[4]); + die("Couldn't stat root device."); + } + major_root = major(sb.st_rdev); + minor_root = minor(sb.st_rdev); + } else { + major_root = 0; + minor_root = 0; + } + } else { + major_root = DEFAULT_MAJOR_ROOT; + minor_root = DEFAULT_MINOR_ROOT; + } + fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); + + file_open(argv[1]); + i = read(fd, buf, sizeof(buf)); + fprintf(stderr, "Boot sector %d bytes.\n", i); + if (i != 512) + die("Boot block must be exactly 512 bytes"); + if (buf[510] != 0x55 || buf[511] != 0xaa) + die("Boot block hasn't got boot flag (0xAA55)"); + buf[508] = minor_root; + buf[509] = major_root; + if (write(1, buf, 512) != 512) + die("Write call failed"); + close(fd); + + /* Copy the setup code */ + file_open(argv[2]); + for (i = 0; (c = read(fd, buf, sizeof(buf))) > 0; i += c) + if (write(1, buf, c) != c) + die("Write call failed"); + if (c != 0) + die("read-error on `setup'"); + close(fd); + + /* Pad unused space with zeros */ + setup_sectors = (i + 511) / 512; + /* for compatibility with ancient versions of LILO. */ + if (setup_sectors < SETUP_SECTS) + setup_sectors = SETUP_SECTS; + fprintf(stderr, "Setup is %d bytes.\n", i); + memset(buf, 0, sizeof(buf)); + while (i < setup_sectors * 512) { + c = setup_sectors * 512 - i; + if (c > sizeof(buf)) + c = sizeof(buf); + if (write(1, buf, c) != c) + die("Write call failed"); + i += c; + } + + file_open(argv[3]); + if (fstat(fd, &sb)) + die("Unable to stat `%s': %m", argv[3]); + sz = sb.st_size; + fprintf(stderr, "System is %d kB\n", sz / 1024); + sys_size = (sz + 15) / 16; + /* 0x28000*16 = 2.5 MB, conservative estimate for the current maximum */ + if (sys_size > (is_big_kernel ? 0x28000 : DEF_SYSSIZE)) + die("System is too big. Try using %smodules.", + is_big_kernel ? "" : "bzImage or "); + if (sys_size > 0xffff) + fprintf(stderr, + "warning: kernel is too big for standalone boot " + "from floppy\n"); + while (sz > 0) { + int l, n; + + l = (sz > sizeof(buf)) ? sizeof(buf) : sz; + n = read(fd, buf, l); + if (n != l) { + if (n < 0) + die("Error reading %s: %m", argv[3]); + else + die("%s: Unexpected EOF", argv[3]); + } + if (write(1, buf, l) != l) + die("Write failed"); + sz -= l; + } + close(fd); + + /* Write sizes to the bootsector */ + if (lseek(1, 497, SEEK_SET) != 497) + die("Output: seek failed"); + buf[0] = setup_sectors; + if (write(1, buf, 1) != 1) + die("Write of setup sector count failed"); + if (lseek(1, 500, SEEK_SET) != 500) + die("Output: seek failed"); + buf[0] = (sys_size & 0xff); + buf[1] = ((sys_size >> 8) & 0xff); + if (write(1, buf, 2) != 2) + die("Write of image length failed"); + + return 0; +} |