mtd/docboot Makefile, 1.3, 1.4 README, 1.2, 1.3 doc_bootstub.S, 1.3,
1.4 doc_bootstub.h, 1.2, 1.3 makespl.c, 1.2, 1.3
dbrown at infradead.org
dbrown at infradead.org
Mon Jan 3 13:31:13 EST 2005
Update of /home/cvs/mtd/docboot
In directory phoenix.infradead.org:/tmp/cvs-serv20894
Modified Files:
Makefile README doc_bootstub.S doc_bootstub.h makespl.c
Log Message:
Major code reorganization and new features: initrd support, keyboard abort.
If this were kernel code, a huge patch like this would be unacceptable;
hopefully nobody will care for a small utility like this.
Index: Makefile
===================================================================
RCS file: /home/cvs/mtd/docboot/Makefile,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- Makefile 3 Aug 2004 08:21:54 -0000 1.3
+++ Makefile 3 Jan 2005 18:31:10 -0000 1.4
@@ -1,7 +1,23 @@
# $Id$
-doc_spl: doc_bootstub makespl bzImage cmdline
- cat cmdline | ./makespl doc_bootstub bzImage doc_spl
+ifneq ($(KERN),)
+ KERN_ARG = $(KERN)
+else
+ KERN_ARG = ./bzImage
+endif
+
+ifneq ($(INITRD),)
+ INITRD_ARG = -i $(INITRD)
+ ifneq ($(INITRD_OUT),)
+ INITRD_OUT_ARG = -o $(INITRD_OUT)
+ endif
+endif
+
+nonbios: doc_bootstub makespl
+ cat cmdline | ./makespl doc_bootstub $(KERN_ARG) doc_spl $(INITRD_ARG) $(INITRD_OUT_ARG)
+
+bios: doc_bootstub makespl
+ cat cmdline | ./makespl doc_bootstub $(KERN_ARG) doc_spl -b bios_ext $(INITRD_ARG) $(INITRD_OUT_ARG)
doc_bootstub.o: doc_bootstub.S doc_bootstub.h Makefile
$(CC) -O2 $(STDEFINE) -fno-builtin -nostdinc -c doc_bootstub.S
@@ -12,8 +28,8 @@
doc_bootstub: doc_bootstub.elf
objcopy -O binary doc_bootstub.elf doc_bootstub
-bios: doc_bootstub makespl bzImage cmdline
- cat cmdline | ./makespl doc_bootstub bzImage doc_spl bios_ext
+makespl: makespl.c doc_bootstub.elf
+ cc makespl.c -o makespl -DCHECKSUM_LOCATION=0x`nm doc_bootstub.elf | grep checksum | cut -d " " -f 1`
clean:
rm -f doc_spl *.o *.elf doc_bootstub makespl bios_ext
Index: README
===================================================================
RCS file: /home/cvs/mtd/docboot/README,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- README 2 Aug 2004 19:27:15 -0000 1.2
+++ README 3 Jan 2005 18:31:10 -0000 1.3
@@ -18,11 +18,11 @@
Like LILO and Grub, DOCBoot is a Linux bootloader. It dispenses with many of
the amenities provided by other bootloaders, however. Command line editing,
-multiple image support, initrd loading, serial port support, fancy prompts and
-menus, timeouts, and all kinds of error checking are not present. Unlike Grub,
-DOCBoot does not understand filesystems, nor can it load a kernel scattered
-throughout the blocks of a filesystem like LILO. Instead, DOCBoot reads your
-kernel directly from a contiguous section of the DiskOnChip.
+multiple image support, serial port support, fancy prompts and menus, timeouts,
+and all kinds of error checking are not present. Unlike Grub, DOCBoot does not
+understand filesystems, nor can it load a kernel scattered throughout the
+blocks of a filesystem like LILO. Instead, DOCBoot reads your kernel directly
+from a contiguous section of the DiskOnChip.
DOCBoot supports kernel versions 2.4.0-test3-pre3 or later. Bad things may
happen if you try it with an earlier version.
@@ -34,9 +34,7 @@
Support for the older (NFTL) DiskOnChip 2000 parts and DOC Millennium Plus 32 MB
is planned.
-initrd support would be easy, though I imagine most people will simply use
-jffs2 as their root filesystem. Some minimal keyboard interaction
-(possibly including commandline editing) would also be a nice addition.
+DOCBoot now supports INITRD image loading.
Quick Start
@@ -61,8 +59,30 @@
flash_eraseall /dev/mtd1
nandwrite -o /dev/mtd1 doc_spl
DONT FORGET the -o flag to nandwrite!
+ IMPORTANT: You must have mtd partition support compiled into your kernel/
+ modules! If you run these commands on /dev/mtd0, you'll erase your entire
+ device!
6. Reboot. DOCBoot will run if no other drives (floppy, CD, HD, etc) are
- bootable.
+ bootable. (This behavior can be altered, see DOC_BIOS_HOOK below).
+
+
+Make Options
+------------
+
+There are a few options that can be given to the 'make' command in step 4
+above:
+
+KERN=<file> Allows you to specify the location and name of your
+ kernel image, instead of using the default "./bzImage".
+
+INITRD=<file> Configures DOCBoot to load the specified initrd image.
+ The initrd data will be added to the end of doc_spl.
+ Depending on your initrd, this can make doc_spl quite
+ large -- be sure your partition is large enough!
+
+Example:
+
+ make KERN=/usr/src/linux/arch/i386/boot/bzImage INITRD=../../initrd.gz
How it works
@@ -103,17 +123,17 @@
device to boot, configure DOCBoot as an INT 19h handler instead. (See the
Configuration section).
-When executed, our replacement interrupt handler loads the Linux kernel into
-memory. Adopting the same technique as the IPL, it finds your kernel by
-scanning the DOC for a special signature in the OOB area. This code marks
-every block containing the kernel (this is very important, as it allows us to
-skip over bad blocks).
+When executed, our replacement interrupt handler loads the Linux kernel (and
+optionally initrd) into memory. Adopting the same technique as the IPL, it
+finds your kernel/initrd by scanning the DOC for a special signature in the OOB
+area. This code marks every block containing the kernel or initrd (this is
+very important, as it allows us to skip over bad blocks).
As with any x86 Linux bootloader, DOCBoot loads a small section of the kernel
(the real mode setup code) into low memory (below the 1Mbyte mark) and the rest
into high memory. It then sets up some variables to let the kernel find the
-commandline (and a few other things), and jumps to the kernel setup code it just
-loaded. The rest is up to Linux.
+commandline and initrd, and jumps to the kernel setup code it just loaded. The
+rest is up to Linux.
Configuration
@@ -141,13 +161,41 @@
detail below.
+Keyboard Abort
+--------------
+
+When the interrupt handler is installed, the message "Installing DOCBoot." will
+be printed to the screen. If you do NOT want DOCBoot to run, hold down any
+shift, control, or alt key during your system bootup. If DOCBoot detects any
+of these keys are depressed (at the point in the bootup sequence where the
+"Installing DOCBoot." message gets printed), installation of the interrupt
+handler will not take place, and the message will not be printed.
+
+This only works at the point in time where the interrupt handler is about to be
+installed. The interrupt handler itself (the code that prints "Loading
+kernel...") does not check the keyboard.
+
+The ability to abort is particularly important if you have DOC_BIOS_HOOK set to
+0x19 (bootstrap loader). If your Linux system on the DOC is unusable due to a
+broken installation (either of DOCBoot itself, your kernel, your commandline,
+your initrd, etc) and DOC_BIOS_HOOK is set to 0x19, it can be very hard to fix
+your installation. Since the INT 19h handler makes DOCBoot the first (and
+only) boot device, the only way to boot from some other device (so you can go
+in and fix your installation!) is to disable or remove the DOC. But if you do
+that, the DOC is not available from Linux and you can't fix the problem. The
+author has actually been forced to solve this problem by physically inserting
+his DiskOnChip into the socket after BIOS scan but before the Linux kernel
+starts (NOT a recommended practice!) Keyboard abort removes the need for that
+kind of insanity.
+
+
BIOS Extension Support
----------------------
Normally, the makefile uses the program 'makespl' to combine the DOCBoot
-executable, your commandline information, and your kernel into a single file
-which you can then write to your device. This is appropriate when using the
-standard M-Systems IPL.
+executable, your commandline information, and your kernel+initrd into a single
+file which you can then write to your device. This is appropriate when using
+the standard M-Systems IPL.
In applications which use a custom BIOS, you may instead want to use DOCBoot as
a BIOS extension (loaded with your BIOS), rather than as a SPL (loaded by the
@@ -156,9 +204,9 @@
To do this you must (1) #define BIOS_EXTENSION in doc_bootstub.h, and
(2) run 'make bios' rather than 'make'. This will produce two files:
-'doc_spl' contains your kernel image in a form suitable for writing to your
-device with nandwrite -o. Unlike in the normal build method, this does not
-contain DOCBoot itself.
+'doc_spl' contains your kernel+initrd image in a form suitable for writing to
+your device with nandwrite -o. Unlike in the normal build method, this does
+not contain DOCBoot itself.
'bios_ext' is a 1024-byte file containing DOCBoot and your commandline info,
formatted as a standard PC BIOS extension. Merging this into your BIOS is up
Index: doc_bootstub.S
===================================================================
RCS file: /home/cvs/mtd/docboot/doc_bootstub.S,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- doc_bootstub.S 2 Aug 2004 18:41:29 -0000 1.3
+++ doc_bootstub.S 3 Jan 2005 18:31:10 -0000 1.4
@@ -45,70 +45,22 @@
* DS will be the segment of the DOC itself.
*/
-#ifndef DOC_ADDRESS
- /* Store the DiskOnChip segment */
- movw %ds, %cs:doc_seg
-#endif
#ifdef BIOS_EXTENSION
- .byte 0x55, 0xAA /* BIOS extension signature */
- .byte 0x02 /* BIOS extension size in 512 byte blocks */
+ #ifndef DOC_ADDRESS
+ #error BIOS_EXTENSION requires DOC_ADDRESS
+ #endif
+
+ .word BIOS_SIG /* BIOS extension signature */
+ .byte ((stub_end-_start)>>9) /* BIOS extension size in 512 byte blocks */
/* BIOS will call far _start + 3 */
#endif
- cld
- /* Test for multiple loads due to aliased ROM addresses. If
- the code pointed to by the interrupt vector is identical to
- our code, just return. */
- xorw %dx, %dx
- movw %dx, %ds
- movw (DOC_BIOS_HOOK * 4), %es
- pushw %cs
- popw %ds
- xorw %di, %di
- xorw %si, %si
- movw $code_end, %cx
- repe
- cmpsb
- je skip_install
-
- /* What we need to do is:
- 1. Check the current end-of-memory in the BIOS
- 2. Reduce it by the amount of memory we need for our INT 18h/19h
- 3. Return, and wait for our INT 18h/19h to be called.
- */
-
- MSG(spl_string)
-
- /* Store the setup segment */
- movw %cs, setup_seg
-
- /* Find top of memory */
- movw %dx, %ds
- movw 0x0413, %ax
-
- /* Steal 1k from the top */
- decw %ax
- movw %ax,0x0413
-
- /* Generate segment address */
- shlw $6,%ax
- movw %ax,%es
-
- /* Set up our shiny new INT 18h/19h handler */
- movw %ax,(DOC_BIOS_HOOK * 4 + 2)
- movw $handler,(DOC_BIOS_HOOK * 4)
-
- /* Copy ourself into the new segment we've just reserved */
- movw $0x200, %cx
- pushw %cs
- popw %ds
- xorw %si,%si
- xorw %di,%di
- rep
- movsw
-skip_install:
- lret
+/* Jump to the installer, which will install an int 18h or 19h handler and then
+ return, waiting for the handler to be called. The installer is placed after
+ the handler to minimize the amount of interrupt handler code copied to the
+ top of low memory. */
+ jmp install
/* The actual int 18h/19h handler does three things:
1) Copy the real-mode kernel from the DOC into the same 64k memory segment
@@ -124,7 +76,7 @@
handler:
pushw %cs
popw %ds
- MSG(loading_string)
+ MSG(kernel_string)
/*
mov $0x88, %ah
@@ -189,43 +141,57 @@
#endif
movw $0x8000, %di /* Go to 32k from setup base */
-read_kernel_sects:
- call doc_readpage
- movw %cx, %di /* re-use the same memory buffer */
- pushw %es
+ call read_high_sects /* copy the kernel sectors */
+
pushw %cs
- popw %es
+ popw %ds
+ movw initrd_sects, %ax
+ orw %ax, high_sects /* high_sects was previously 0 */
+ jz skip_initrd
+ movw initrd_start, %ax
+ movw %ax, gdt_dst_mid
+
pushw %si
- movw $gdt, %si
- movw $0x200, %cx
- movb $0x87, %ah
- int $0x15
+ pushw %bx
+ MSG(initrd_string)
+ popw %bx
popw %si
- popw %es
- addw $2, %cs:gdt_dst_mid
- decw %cs:high_sects
- jnz read_kernel_sects
-/* We're done with the DOC. Set up some things a kernel loader is supposed
- to set, then try to boot! */
+ movw doc_seg, %ds
+
+ call read_high_sects /* copy the initrd sectors */
pushw %cs
popw %ds
+
+skip_initrd:
+
+/* We're done with the DOC. Set up some things a kernel loader is supposed
+ to set, then try to boot! */
+
MSG(done_string)
MSG(cmdline)
MSG(boot_string)
+ movl initrd_bytes, %eax
+
pushw %es
popw %ds /* Now write parameters into setup segment */
- /* The commandline is at offset 512 from CS. Compute the
- physical address and store into cmd_line_ptr. Simplified
- by the fact that CS must be 1k-aligned. */
+ orl %eax, ramdisk_size /* ramdisk_size should be 0 before this */
+ jz skip_initrd2
+ movw %cs:initrd_start, %ax
+ movw %ax, ramdisk_image + 1
+skip_initrd2:
+
+ /* Compute the physical address of the commandline and
+ store into cmd_line_ptr. Simplified by the fact that
+ CS must be 1k-aligned and cmdline is at a 256-byte-aligned
+ offset from CS. */
pushw %cs
popw %ax
shrw $4, %ax
- incw %ax
- incw %ax
+ addw $((cmdline-_start)>>8), %ax
movw %ax, cmd_line_ptr + 1
movb $0x81, loadflags
@@ -248,6 +214,29 @@
lret /* GO! */
/***************************************************************************/
+ /* read_high_sects: Read pages from DOC into high memory.
+ Each page is first loaded into low memory using doc_readpage,
+ then copied to high memory using int 15h function 87h.
+ We read cs:high_sects pages (leaving cs:high_sects = 0 when
+ we're done.) */
+read_high_sects:
+ call doc_readpage
+ movw %cx, %di /* re-use the same low memory buffer */
+ pushw %es
+ pushw %cs
+ popw %es
+ pushw %si
+ movw $gdt, %si
+ movw $0x200, %cx
+ movb $0x87, %ah
+ int $0x15
+ popw %si
+ popw %es
+ addw $2, %cs:gdt_dst_mid
+ decw %cs:high_sects
+ jnz read_high_sects
+ ret
+/***************************************************************************/
/* doc_readpage: Read a page from DOC to es:di
Then read the OOB. If the magic tag (0xdbb1) isn't found
@@ -413,7 +402,7 @@
#endif
/***************************************************************************/
-code_end:
+handler_end:
#ifdef DOC_ADDRESS
doc_seg: .word DOC_ADDRESS
@@ -421,6 +410,8 @@
doc_seg: .word 0
#endif
+initrd_start: .word 0
+
/* gdt structure for high loading using int15/87 */
gdt:
.skip 0x10
@@ -438,28 +429,140 @@
.word 0
.skip 0x10
-spl_string: .string "Installing DiskOnChip bootloader.\n\r"
-loading_string: .string "Loading kernel... "
+kernel_string: .string "Loading kernel... "
+initrd_string: .string "Loading initrd... "
done_string: .string "done.\n\rCommandline: "
boot_string: .string "\n\rBooting!\n\r"
- .org CHECKSUM_LOCATION
checksum:
setup_seg: .word 0
low_sects: .word 0
high_sects: .word 0
+initrd_sects: .word 0
+initrd_bytes: .long 0
- .org 512
+/* Make sure our parameters are in sync with the C code. */
+.if ((.-checksum) <> PARAM_BYTES)
+ .err
+.endif
+
+ .balign 256, 0xff /* cmdline starts on 256-byte boundary... */
cmdline:
+ .skip 256, 0xff /* .. and is 256-bytes long. */
+reloc_end:
+
+
+/***************************************************************************
+ ***************************************************************************
+ Everything ABOVE this point is needed by the int 18h/19h handler, and will
+ be copied to the top of low memory by the installer (below). Everything
+ below this point is needed only by the installer.
+ ***************************************************************************
+ ***************************************************************************/
+
+
+install:
+#ifndef DOC_ADDRESS
+ /* Store the DiskOnChip segment */
+ movw %ds, %cs:doc_seg
+#endif
+ cld
+ xorw %dx, %dx
+ movw %dx, %ds
+
+ /* Abort installation if any shift, control, or alt key is
+ depressed. */
+ movb 0x0417, %al
+ andb $0x0f, %al
+ jnz skip_install
+
+ /* Test for multiple loads due to aliased ROM addresses. If
+ the code pointed to by the interrupt vector is identical to
+ our code, just return. */
+ movw (DOC_BIOS_HOOK * 4 + 2), %es
+ pushw %cs
+ popw %ds
+ xorw %di, %di
+ xorw %si, %si
+ movw $handler_end, %cx
+ repe
+ cmpsb
+ je skip_install
-/******************************************************/
-/* This section adapted from arch/i386/boot/boot.S */
-/******************************************************/
-/* Although the data defined here will be placed in the object file by the
- compiler, only the first 512 bytes (above) are copied into the SPL. This
+ MSG(installer_string)
+
+ /* Store the setup segment */
+ movw %cs, setup_seg
+
+ movb $0x88, %ah
+ int $0x15 /* Get top of high mem (-1M) in 1k-blocks */
+ cmpw $(0x4000-0x400), %ax /* safety check: if it's above 15M ... */
+ jae topmem_ok
+ movw $(0x4000-0x400), %ax /* ... replace with 15M. */
+topmem_ok:
+ addw $0x400, %ax /* Adjust for 1M offset */
+ shlw $1, %ax /* Convert to sectors */
+ subw initrd_sects, %ax /* Compute start of initrd */
+ shlw $1, %ax /* Convert to 256-byte blocks */
+ andw $0xfff0, %ax /* Round down to 4k block (req'd by kernel) */
+ movw %ax, initrd_start /* Store initrd start for later use */
+
+ /* Now install the handler. What we need to do is:
+ 1. Check the current end-of-memory in the BIOS
+ 2. Reduce it by the amount of memory we need for our INT 18h/19h
+ 3. Copy the handler code and data into the area we just reserved.
+ 4. Return, and wait for our INT 18h/19h to be called.
+ */
+
+ /* Find top of low memory */
+ movw %dx, %ds
+ movw 0x0413, %ax
+
+ /* Steal enough room from the top. The line below is
+ suboptimal for relocated code size of 2k bytes or less, but
+ it's not a big deal (1-2 bytes). */
+ subw $(((reloc_end-_start)+1023)>>10), %ax
+ movw %ax,0x0413
+
+ /* Generate segment address */
+ shlw $6,%ax
+ movw %ax,%es
+
+ /* Set up our shiny new INT 18h/19h handler */
+ movw %ax,(DOC_BIOS_HOOK * 4 + 2)
+ movw $handler,(DOC_BIOS_HOOK * 4)
+
+ /* Copy the handler into the new segment we've just reserved */
+ movw $(reloc_end-_start), %cx
+ pushw %cs
+ popw %ds
+ xorw %si,%si
+ xorw %di,%di
+ rep
+ movsb
+
+skip_install:
+ lret
+
+installer_string: .string "Installing DOCBoot.\n\r"
+
+install_end:
+
+ .balign 512, 0xff /* Pad the entire stub to a 512-byte boundary */
+stub_end:
+
+
+/**************************************************************************
+ **************************************************************************
+ The symbols defined below will not be emitted by the assembler. This
is just here as a convenient way of encoding the offsets for use in the
bootloader.
- */
+ This section adapted from arch/i386/boot/boot.S
+ **************************************************************************
+ **************************************************************************/
+
+ .section absolute
+ .org 512
kernel_start: .word 0
# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
header_sig: .ascii "...." # header signature
@@ -478,4 +581,3 @@
pad1: .word 0
cmd_line_ptr: .long 0 # If nonzero, a 32-bit pointer
ramdisk_max: .long 0 # The highest safe address
-/******************************************************/
Index: doc_bootstub.h
===================================================================
RCS file: /home/cvs/mtd/docboot/doc_bootstub.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- doc_bootstub.h 2 Aug 2004 18:41:28 -0000 1.2
+++ doc_bootstub.h 3 Jan 2005 18:31:10 -0000 1.3
@@ -137,10 +137,12 @@
/* Print message string */
#define MSG(x) movw $(x), %si; call message
-#define CHECKSUM_LOCATION (512-6)
+#define BIOS_SIG 0xAA55
+
+#define PARAM_BYTES 12
#define SETUP_SECTS_LOCATION 497
-#define DOC_BIOS_HOOK 0x19
+#define DOC_BIOS_HOOK 0x18
/* #define DOC_ADDRESS 0xc800 */
/* #define BIOS_EXTENSION */
Index: makespl.c
===================================================================
RCS file: /home/cvs/mtd/docboot/makespl.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- makespl.c 2 Aug 2004 18:41:29 -0000 1.2
+++ makespl.c 3 Jan 2005 18:31:10 -0000 1.3
@@ -2,19 +2,35 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <unistd.h>
#include "doc_bootstub.h"
+/* The commandline is at the next 256-byte boundary after the parameters. */
+#define CMDLINE_LOCATION ((CHECKSUM_LOCATION+PARAM_BYTES+255)&0xffffff00)
+
unsigned char buf[0x3000];
unsigned char spl_sig[16] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55,
0x84, 0xa8, 0xac, 0xa0, 0x30, 0x30, 0x30, 0x30 };
-unsigned char cmdline_sig[16] =
+unsigned char stub_sig[16] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-unsigned char kern_sig[16] =
+unsigned char image_sig[16] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xb1,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+/* Keep this in sync with doc_bootstub.S */
+struct params {
+ union {
+ unsigned short setup_seg;
+ unsigned char checksum;
+ };
+ unsigned short low_sects;
+ unsigned short high_sects;
+ unsigned short initrd_sects;
+ unsigned long initrd_bytes;
+};
+
void writeblocks(int outfd, unsigned char *buf, int len, unsigned char *oob) {
int ret;
@@ -46,115 +62,204 @@
}
}
+void usage(void)
+{
+ fprintf(stderr,
+"Usage: makespl <stub input file> <kernel input file> <stub output file>\n"
+" [-b <bios extension output file>] [-i <initrd input file>]\n"
+" [-o <initrd output file>]\n"
+"Specifying -b turns bios extension mode on. In this case the stub output\n"
+"file actually contains only kernel/initrd data.\n"
+"If -i is specified but -o is not, the initrd output is appended to the stub\n"
+"output file (default behavior).\n"
+ );
+ exit(1);
+}
+
int main(int argc, char **argv)
{
- int len, i, stubfd, imgfd, outfd, biosfd;
+ int len, i, stubfd, imgfd, outfd, biosfd, initfd, initrd_outfd;
int ret;
- char bios_extension;
+ char *bios_extension = NULL;
+ char *initrd = NULL;
+ char *initrd_out = NULL;
unsigned char checksum=0;
- int imglen;
- int total_sects, setup_sects, kernel_sects;
+ int imglen, initrd_len, stublen;
+ int stub_sects, initrd_sects;
+ int image_sects, setup_sects, kernel_sects, image_start;
+ struct params *params = (struct params *) (buf + CHECKSUM_LOCATION);
+
+ if (sizeof(struct params) != PARAM_BYTES) {
+ fprintf(stderr,
+"Param size mismatch! Some idiot changed the code wrong! Aborting.\n");
+ exit(1);
+ }
- //memset(buf, 0xff, sizeof(buf));
+ while (1) {
+ int c = getopt(argc, argv, "b:B:i:I:");
+ if (c == -1) break;
- if (argc < 4) {
- fprintf(stderr, "Usage: makespl <stubfile> <kernelfile> <outfile> [bios_extensionfile]\n");
- exit(1);
+ switch (c) {
+ case 'b':
+ case 'B':
+ bios_extension = optarg;
+ break;
+ case 'i':
+ case 'I':
+ initrd = optarg;
+ break;
+ case 'o':
+ case 'O':
+ initrd_out = optarg;
+ break;
+ default:
+ usage();
+ }
}
+
+ if ((argc - optind) != 3) usage();
- if (argv[4])
- bios_extension=1;
- else
- bios_extension=0;
-
- stubfd = open(argv[1], O_RDONLY);
+ stubfd = open(argv[optind++], O_RDONLY);
if (stubfd < 0) {
- perror("open stub file");
+ perror("open stub input file");
exit(1);
}
+ stublen = lseek(stubfd, 0, SEEK_END);
+ lseek(stubfd, 0, SEEK_SET);
+ stub_sects = (stublen + 511) >> 9;
+ image_start = stub_sects << 9;
+ /* Note: image_start should be == stublen, because doc_bootstub.S
+ * should always pad to a 512-byte boundary. Still, better safe than
+ * sorry. */
- imgfd = open(argv[2], O_RDONLY);
+ imgfd = open(argv[optind++], O_RDONLY);
if (imgfd < 0) {
- perror("open kernel image file");
+ perror("open kernel input file");
exit(1);
}
// get image length
imglen = lseek(imgfd, 0, SEEK_END);
lseek(imgfd, 0, SEEK_SET);
- total_sects = (imglen + 511) >> 9;
+ image_sects = (imglen + 511) >> 9;
- outfd = open(argv[3], O_WRONLY | O_CREAT | O_TRUNC, 0664);
+ outfd = open(argv[optind++], O_WRONLY | O_CREAT | O_TRUNC, 0664);
if (outfd < 0) {
- perror("open output file");
+ perror("open stub output file");
exit(1);
}
if (bios_extension) {
- biosfd = open(argv[4], O_WRONLY | O_CREAT | O_TRUNC, 0664);
+ biosfd = open(bios_extension, O_WRONLY | O_CREAT | O_TRUNC, 0664);
if (biosfd < 0) {
perror("open BIOS extension output file");
exit(1);
}
}
+ if (initrd) {
+ initfd = open(initrd, O_RDONLY);
+ if (initfd < 0) {
+ perror("open BIOS extension output file");
+ exit(1);
+ }
+ initrd_len = lseek(initfd, 0, SEEK_END);
+ lseek(initfd, 0, SEEK_SET);
+ initrd_sects = (initrd_len + 511) >> 9;
+ initrd_outfd = outfd;
+ if (initrd_out) {
+ initrd_outfd = open(initrd_out, O_WRONLY | O_CREAT | O_TRUNC, 0664);
+ if (initrd_outfd < 0) {
+ perror("open initrd output file");
+ exit(1);
+ }
+ }
+ }
+
/* Read the bootstub */
- len = read(stubfd, buf, 512);
+ len = read(stubfd, buf, stublen);
if (len < 0) {
- perror("read from stub file");
+ perror("read from stub input file");
exit(1);
}
- if (len != 512) {
- fprintf(stderr, "Unexpected EOF in stub file\n");
+ if (len != stublen) {
+ fprintf(stderr, "Unexpected EOF in stub input file\n");
exit(1);
}
close(stubfd);
+ if (*((unsigned short *) buf) == BIOS_SIG) {
+ if (!bios_extension) {
+ fprintf(stderr,
+"Stub file was built as a Bios Extension, but bios extension mode was not\n"
+"selected. Aborting.\n");
+ exit(1);
+ }
+ } else if (bios_extension) {
+ fprintf(stderr,
+"Stub file was not built as a Bios Extension, but bios extension mode was\n"
+"selected. Aborting.\n");
+ exit(1);
+ }
+
if (isatty(0))
fprintf(stderr, "Enter commandline: ");
- len = strlen(fgets(buf + 512, 256, stdin));
+ len = strlen(fgets(buf + CMDLINE_LOCATION, 256, stdin));
len--;
- if (buf[512+len] == '\n')
- buf[512+len] = 0;
- fprintf(stderr, "Commandline is \"%s\"\n", buf + 512);
+ if (buf[CMDLINE_LOCATION+len] == '\n')
+ buf[CMDLINE_LOCATION+len] = 0;
+ fprintf(stderr, "Commandline is \"%s\"\n", buf + CMDLINE_LOCATION);
+/*fprintf(stderr, "checksum is at %x, cmdline is at %x\n", CHECKSUM_LOCATION, CMDLINE_LOCATION);*/
/* Read the kernel */
- len = read(imgfd, buf + 1024, sizeof(buf) - 1024);
+ len = read(imgfd, buf + image_start, sizeof(buf) - image_start);
if (len < 0) {
- perror("read from kernel");
+ perror("read from kernel input file");
exit(1);
}
- setup_sects = buf[1024 + SETUP_SECTS_LOCATION];
+ setup_sects = buf[image_start + SETUP_SECTS_LOCATION];
setup_sects++;
- kernel_sects = total_sects - setup_sects;
+ kernel_sects = image_sects - setup_sects;
- fprintf(stderr, "2 bootstub sectors, %d real-mode sectors, %d kernel sectors\n",
+ if (bios_extension)
+ fprintf(stderr, "%d Bios Extension sectors, ", stub_sects);
+ else
+ fprintf(stderr, "%d bootstub sectors, ", stub_sects);
+ fprintf(stderr, "%d real-mode sectors, %d kernel sectors",
setup_sects, kernel_sects);
+ if (initrd)
+ fprintf(stderr, ", %d initrd sectors\n", initrd_sects);
+ else
+ fprintf(stderr, "\n");
- *((unsigned short *) &buf[CHECKSUM_LOCATION+2]) = setup_sects;
- *((unsigned short *) &buf[CHECKSUM_LOCATION+4]) = kernel_sects;
+ params->low_sects = setup_sects;
+ params->high_sects = kernel_sects;
+ if (initrd) {
+ params->initrd_sects = initrd_sects;
+ params->initrd_bytes = initrd_len;
+ }
/* Calculate the csum */
- buf[CHECKSUM_LOCATION] = 0;
+ params->checksum = 0; /* unnecessary */
if (bios_extension) {
- for (i = 0; i < 1024; i++)
+ for (i = 0; i < image_start; i++)
checksum += buf[i];
/* Set the slack byte to fix the csum */
- buf[CHECKSUM_LOCATION] = 0 - checksum;
+ params->checksum = 0 - checksum;
} else {
for (i = 0; i < sizeof(buf); i++)
checksum += buf[i];
/* Set the slack byte to fix the csum */
- buf[CHECKSUM_LOCATION] = 0x55 - checksum;
+ params->checksum = 0x55 - checksum;
}
if (bios_extension) {
/* Write the bootstub and commandline to one file */
- ret = write(biosfd, buf, 1024);
+ ret = write(biosfd, buf, image_start);
if (ret < 0) {
perror("write BIOS extension output file");
exit(1);
@@ -163,23 +268,41 @@
/* Write the bootstub page */
writeblocks(outfd, buf, 512, spl_sig);
/* Write the commandline page */
- writeblocks(outfd, buf + 512, 512, cmdline_sig);
+ writeblocks(outfd, buf + 512, image_start - 512, stub_sig);
}
/* Write the rest of the first buffer */
- writeblocks(outfd, buf + 1024, sizeof(buf) - 1024, kern_sig);
+ writeblocks(outfd, buf + image_start, sizeof(buf) - image_start,
+ image_sig);
/* Now chuck out the rest of the kernel */
while (1) {
len = read(imgfd, buf, sizeof(buf));
if (len < 0) {
- perror("read from kernel");
+ perror("read from kernel input file");
+ exit(1);
+ }
+ if (len == 0)
+ break;
+
+ writeblocks(outfd, buf, len, image_sig);
+ }
+
+ if (!initrd) return 0;
+
+ /* And the initrd right after that. */
+
+ while (1) {
+ len = read(initfd, buf, sizeof(buf));
+ if (len < 0) {
+ perror("read from initrd input file");
exit(1);
}
if (len == 0)
break;
- writeblocks(outfd, buf, len, kern_sig);
+ writeblocks(initrd_outfd, buf, len, image_sig);
}
+
return 0;
}
More information about the linux-mtd-cvs
mailing list