-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Pascal Bellard wrote:
> Hello,
>
> Please find attached a patch to build i386/x86_64 kernel directly
> bootable. It may be usefull for rescue floppies and installation
> floppies.
Pascal,
In commit f8eeaaf4180334a8e5c3582fe62a5f8176a8c124, build.c has already
changed, and I don't believe it's very compatible with this change.
See
http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=f8eeaaf4180334a8e5c3582fe62a5f8176a8c124
Also, we'll need to see comments from H. Peter Anvin on this patch.
CC'ing him.
> System sector count is updated by tools/bluid.c at offset 495. The
> system could be up to 32 Mb long.
>
> -- support any drive geometry --
>
> Disk geometry detection assumes that no error raises on first track.
> First track is read sector by sector and the first error determinates
> the sectors per track count. Next, reads are performed track by track.
> Tested on floppy H2/S18 and harddisk H16/S63. Should work on
> every exotic drive supporting Int13h CHS.
>
> -- cmdline support --
>
> If ram_size (offset 504) bit 13 is set, the kernel cmdline
> is load from the sector following the kernel image.
>
> If Ctrl, Alt, Shift or CapsLock is pressed the kernel cmdline is
> prompted until Enter key. BackSpace is supported.
>
> Regards,
>
> -pascal
Frank
- --
Frank Sorenson - KD7TZK
Systems Manager, Computer Science Department
Brigham Young University
[email protected]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org
iD8DBQFDJyKhaI0dwg4A47wRAjMoAJ9laL5kvIzkbJAxigSJahqkdnmx8gCg6dOy
V6ML9fJQjmfjcdxNGnbSuZ0=
=7P9o
-----END PGP SIGNATURE-----
diff -purN linux-2.6.13/arch/i386/boot/bootsect.S linux-2.6.13-bootblock/arch/i386/boot/bootsect.S
--- linux-2.6.13/arch/i386/boot/bootsect.S 2005-09-12 10:37:52.000000000 +0200
+++ linux-2.6.13-bootblock/arch/i386/boot/bootsect.S 2005-09-12 10:40:19.000000000 +0200
@@ -4,20 +4,31 @@
* modified by Drew Eckhardt
* modified by Bruce Evans (bde)
* modified by Chris Noe (May 1999) (as86 -> gas)
- * gutted by H. Peter Anvin (Jan 2003)
+ *
+ * rewritten to support up to 32Mb kernel, cmdline
+ * and any disk geometry by <[email protected]>
*
* BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment
* addresses must be multiplied by 16 to obtain their respective linear
* addresses. To avoid confusion, linear addresses are written using leading
* hex while segment addresses are written as segment:offset.
*
+ * bde - should not jump blindly, there may be systems with only 512K low
+ * memory. Use int 0x12 to get the top of memory, etc.
+ *
+ * It then loads 'setup' directly after itself (0x90200), and the system
+ * at 0x10000, using BIOS interrupts.
+ *
+ * The loader has been made as simple as possible, and continuous
+ * read errors will result in a unbreakable loop. Reboot by hand. It
+ * loads pretty fast by getting whole tracks at a time whenever possible.
*/
#include <asm/boot.h>
SETUPSECTS = 4 /* default nr of setup-sectors */
BOOTSEG = 0x07C0 /* original address of boot-sector */
-INITSEG = DEF_INITSEG /* we move boot here - out of the way */
+INITSEG = DEF_INITSEG /* we load boot here - out of the way */
SETUPSEG = DEF_SETUPSEG /* setup starts here */
SYSSEG = DEF_SYSSEG /* system loaded at 0x10000 (65536) */
SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */
@@ -25,6 +36,12 @@ SYSSIZE = DEF_SYSSIZE /* system size:
ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */
SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */
+/* some extra features */
+#define DISPLAY_KERNEL_VERSION as soon as possible
+#define EDIT_CMDLINE on hotkey
+#define LOAD_CMDLINE according to bit ramsize.13
+#define EXTRA_DEVICES to fill root_device
+
#ifndef SVGA_MODE
#define SVGA_MODE ASK_VGA
#endif
@@ -42,57 +59,470 @@ SWAP_DEV = 0 /* SWAP_DEV is now writte
.global _start
_start:
+ cld # assume nothing
+ movw $INITSEG, %ax
+ movw %ax, %es # %ax = %es = INITSEG
+#if MOVE_BOOTSECTOR
+# First things first. Move ourself from 0x7C00 -> 0x90000 and jump there.
+ movw $BOOTSEG, %cx
+ movw %cx, %ds # %ds = BOOTSEG
+ movb $1, %ch # %cx = 256
+ subw %si, %si
+ subw %di, %di
+ rep
+ movsw
+ ljmp $INITSEG, $go
+go:
+#else
+ xorw %cx, %cx # %cx = 0
+#endif
- # Normalize the start address
- jmpl $BOOTSEG, $start2
+# bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We
+# wouldn't have to worry about this if we checked the top of memory. Also
+# my BIOS can be configured to put the wini drive tables in high memory
+# instead of in the vector table. The old stack might have clobbered the
+# drive table.
+
+ movw $0x4000-12, %di # 0x4000 is an arbitrary value >=
+ # length of bootsect + length of
+ # setup + room for stack;
+ # 12 is disk parm size.
+ # gdt will heat 48 more bytes.
+ movw %ax, %ss # %ax and %es already contain INITSEG
+ movw %di, %sp # put stack at INITSEG:0x4000-12.
+
+# Many BIOS's default disk parameter tables will not recognize
+# multi-sector reads beyond the maximum sector number specified
+# in the default diskette parameter tables - this may mean 7
+# sectors in some cases.
+#
+# Since single sector reads are slow and out of the question,
+# we must take care of this by creating new parameter tables
+# (for the first disk) in RAM. We can set the maximum sector
+# count to 36 - the most we will encounter on an ED 2.88.
+#
+# High doesn't hurt. Low does. Let's use the max: 63
+#
+# Segments are as follows: %es = %ss = INITSEG,
+# %fs and %gs are unused.
+
+ movw $0x78, %bx # %ds:%bx is parameter table address
+ movw %cx, %ds # %ds = 0
+ ldsw (%bx), %si # %ds:%si is source
+ movb $6, %cl # copy 12 bytes
+ rep # don't worry about cld
+ movsw # already done above
+ movw %cx, %ds # %ds = 0
+ movw %sp, (%bx) # %sp = 0x4000-12
+ movw %es, 2(%bx)
+ pushw %es
+ popw %ds # now %ds = %es = %ss = INITSEG
+ movb $63, 0x4-12(%di) # patch sector count, %di = 0x4000
+
+ cli
+ cbw # %ax = 0 : geometry unknown yet
+ xorb %dh, %dh # head 0, current drive
+ incw %cx # cylinder 0, sector 1
+ movw %cx, %di # read 1 sector
+ call read_first_sector # read bootsector again to have
+ # access to data segment
+
+#ifndef DISPLAY_KERNEL_VERSION
+ movw $msg1, %si
+ call puts
+#endif
-start2:
- movw %cs, %ax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %ss
- movw $0x7c00, %sp
- sti
- cld
+# Load the setup-sectors directly after the moved bootblock (at 0x90200).
- movw $bugger_off_msg, %si
+ movb setup_sects, %al
+#ifdef CHECK_SETUP_SIZE
+ orb %al, %al
+ jne setup_size_ok
+ movb $SETUPSECTS, %al
+setup_size_ok:
+#endif
+ cbw
+ xchg %ax, %di
+ call read_sectors # read setup
+
+#ifdef DISPLAY_KERNEL_VERSION
+#define kernel_version 0xE
+ movw $0x200,%si
+ addw kernel_version(%si),%si # starting protocol 2.00, Kernel 1.3.73
+ call puts # show which kernel we are loading
+#endif
-msg_loop:
- lodsb
- andb %al, %al
- jz die
- movb $0xe, %ah
- movw $7, %bx
- int $0x10
- jmp msg_loop
+# This routine loads the system at address SYSSEG, making sure
+# no 64kB boundaries are crossed. We try to load it as fast as
+# possible, loading whole tracks whenever we can.
+
+#ifdef __BIG_KERNEL__
+type_of_loader = 528
+ movw $24, %cx # allocate 48 bytes in stack
+init_gdt:
+ push $0 # initialized with 0
+ loop init_gdt
+ movw %sp, %si # for bootsect_gdt
+ movw $0x9300+(SYSSEG/4096), %ax # source = SYSSEG
+ cwd
+ movw %ax, 20(%si) # bootsect_src_base+2
+ movb $0x10-1, %al # destination = 0x100000
+ movw %ax, 28(%si) # bootsect_dst_base+2
+ movw %dx, 16(%si) # bootsect_src = 64Kb
+ movw %dx, 24(%si) # bootsect_dst = 64Kb
+ movb %dl, type_of_loader # loader type = 0xFF
+syslp:
+ movw $SYSSEG, %ax
+ movw %ax, %es
+ movw $128,%di # 64Kb in sectors
+ subw %di, sys_sects
+ pushf
+ jnc not_last
+ addw sys_sects, %di
+not_last:
+ call read_sectors
+ incw 28(%si) # bootsect_dst_base+2
+ movw $0x8000, %cx # full 64K
+ movb $0x87, %ah
+ push %ss
+ pop %es # gdt in es:si
+ int $0x15
+ popf
+ ja syslp
+#else
+ movw $SYSSEG, %ax
+ movw %ax, %es
+syslp:
+ movw $128*32,%ax # 64Kb in paragraphs
+ subw %ax, syssize
+ pushf
+ jnc not_last
+ addw syssize, %ax
+not_last:
+ movb $5, %cl # paragraphs -> sectors
+ shrw %cl, %ax
+ xchg %ax, %di
+ call read_sectors
+ popf
+ ja syslp
+#endif
-die:
- # Allow the user to press a key, then reboot
- xorw %ax, %ax
- int $0x16
- int $0x19
+# After that we check which root-device to use. If the device is
+# defined (!= 0), nothing is done and the given device is used.
+# Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8)
+# depending on the number of sectors we pretend to know we have.
+
+
+ movw root_dev, %ax
+ orw %ax, %ax
+ jnz root_defined
+
+ movw $floppy_table,%si
+scan_floppy_table:
+ lodsw
+ cmpb limits, %ah
+ je set_root
+ jno scan_floppy_table
+set_root:
+ movb $2, %ah
+ addb %dl, %al # add current (floppy) drive
+ movw %ax, root_dev
+root_defined:
+
+#if defined(LOAD_CMDLINE) || defined(EDIT_CMDLINE)
+#define BUFFER 0x7F00
+ movw $BUFFER, %si
+ movw %si, (%si) # default : no cmdline
+#endif
- # int 0x19 should never return. In case it does anyway,
- # invoke the BIOS reset code...
- ljmp $0xf000,$0xfff0
+#ifdef LOAD_CMDLINE
+ testb $0x20,ram_size+1 # bit 11 to 13 where unused
+ # now bit 13 means: load cmdline
+ jz nocmd
+ movw $BUFFER/16+INITSEG, %ax
+ movw %ax, %es
+ movw $1, %di # cmdline = 512 bytes max
+ call read_sectors
+nocmd:
+#endif
+#define RSHFT 0x01
+#define LSHFT 0x02
+#define CTRL 0x04
+#define ALT 0x08
+#define SCRLCK 0x10
+#define NUMLCK 0x20
+#define CAPSLCK 0x40
+#define INSERT 0x80
+
+#ifdef EDIT_CMDLINE
+# The cmdline can be entered and modifed on hot key.
+# Only characters before the cursor are passed to the kernel.
+ movb $2, %ah # get keyboard status
+ int $0x16
+ testb $RSHFT|LSHFT|CTRL|ALT|CAPSLCK, %al
+ jz nocmdline
+ pushw %si
+ call puts # set %ah and %bx
+cmdlp:
+# if 1
+ movb $32, %al # clear end of line
+ int $0x10 # with Space
+ movb $8, %al # and BackSpace
+ int $0x10
+# endif
+ decw %si
+cmdget:
+ cbw # %ah = 0, get keyboard character
+ int $0x16
+ cmpb $8, %al # BackSpace ?
+ je cmdbs
+ cbw
+ movw %ax, (%si) # store end of string too
+ incw %si
+ incw %si
+cmdbs:
+ cmpw $BUFFER, %si # lower limit is checked
+ je cmdget # but upper limit not
+ call putc
+ cmpb $13, %al # Enter ?
+ jne cmdlp
+ popw %si
+nocmdline:
+#endif
-bugger_off_msg:
- .ascii "Direct booting from floppy is no longer supported.\r\n"
- .ascii "Please use a boot loader program instead.\r\n"
- .ascii "\n"
- .ascii "Remove disk and press any key to reboot . . .\r\n"
- .byte 0
+#if defined(LOAD_CMDLINE) || defined(EDIT_CMDLINE)
+#if 1
+cmd_line_magic = 0x20
+cmd_line_offset = 0x22
+ movw $0xA33F, cmd_line_magic
+ movw %si, cmd_line_offset
+#else
+# protocol >= 2.02, starting Kernel 2.4.0-test3-pre3
+cmd_line_ptr = 0x228
+ movzx %si, %eax
+ addl $INITSEG*16, %eax
+ movl %eax, cmd_line_ptr
+#endif
+emptycmdline:
+#endif
+
+# This procedure turns off the floppy drive motor, so
+# that we enter the kernel in a known state, and
+# don't have to worry about it later.
+
+#if 1
+kill_motor:
+ xorw %ax, %ax # reset FDC
+ int $0x13
+#else
+kill_motor:
+ movw $0x3f2, %dx
+ xorb %al, %al
+ outb %al, %dx
+#endif
+ call print_nl
- # Kernel attributes; used by setup
+# After that (everything loaded), we jump to the setup-routine
+# loaded directly after the bootblock:
+# Segments are as follows: %ds = %ss = INITSEG
+
+ ljmp $SETUPSEG, $0
+
+# read_sectors reads %di sectors into %es:0 buffer.
+# %es:0 is updated to the next memory location.
+# First, sectors are read sector by sector until
+# sector per track count is known. Then they are
+# read track by track.
+# Assume no error on first track.
+
+#define TRACK_BY_TRACK load as fast as possible !
+#define SHOW_REGS show int13 status & parameters
+
+check_limits:
+ cmpb %al, %cl # max sector known ?
+ ja next_head # no -> store it
+ cmpb %ah, %dh # max head known ?
+ ja next_track # no -> store it
+ pusha # save context
+#ifdef SHOW_REGS
+ pushw %es # print %es (named EX)
+ pushw %dx # print %dx
+ pushw %cx # print %cx
+ xorw %cx, %cx
+ pushw %cx # print %bx
+# ifdef TRACK_BY_TRACK
+ movb $2, %bh
+# endif
+ pushw %bx # print %ax
+ movb $6,%cl
+ jmp print_all # print %bp (status)
+print_loop:
+ movb $0x6 + 'A' - 1, %al
+ subb %cl, %al
+ movw $regs, %si # caller %si is saved
+ call putcs # putc(%al) + puts(%si)
+# it will print out all of the registers.
+ popw %bp # load word into %bp
+print_all:
+ pushw %cx # save count remaining
+ movb $4, %cl # 4 hex digits
+print_digit:
+ rolw $4, %bp # rotate to use low 4 bits
+ movb $0x0f, %al
+ andw %bp, %ax # %al = mask for nybble
+ addb $0x90, %al # convert %al to ascii hex
+ daa # in only four instructions!
+ adcb $0x40, %al
+ daa
+ call putc # set %ah and %bx
+ loop print_digit
+ movb $0x20, %al # SPACE
+ int $0x10
+ popw %cx
+ loop print_loop
+ xchg %ax, %cx # %ah = 0
+#else
+ cbw # %ah = 0
+#endif
+ int $0x13 # reset controler
+ popa # restore context
+read_sectorslp:
+read_first_sector:
+ pushw %di # sector count
+ pushw %ax # limits
+ pushw %dx
+ pushw %cx
+ xorw %bx, %bx
+#ifdef TRACK_BY_TRACK
+ subb %cl, %al # sectors remaining in track
+ ja tolastsect
+ movb $1, %al # 1 sector mini
+tolastsect:
+ cbw
+ cmpw %di, %ax
+ jb more1trk
+ movw %di, %ax # sectors to read
+more1trk:
+ push %ax
+ movb $2, %ah # cmd: read chs
+#else
+ movw $0x201, %ax # sector by sector
+ push %ax
+#endif
+ int $0x13
+ xchg %ax, %bp # status
+ popw %bx # %ax
+ popw %cx
+ popw %dx
+ popw %ax # limits
+ popw %di # sector count
+ jc check_limits
+next_sector:
+#ifdef TRACK_BY_TRACK
+ subw %bx,%di # update sector counter
+ addw %bx,%cx # next sector
+ shlw $5,%bx # sectors -> paragraghs
+ movw %es, %bp
+ addw %bx, %bp
+#else
+ decw %di # update sector counter
+ incw %cx # next sector
+ movw %es, %bp
+ addw $32, %bp # sector size in paragraghs
+#endif
+ movw %bp, %es # next location
+ cmpb %al,%cl # reach sector limit ?
+ jne bdendlp
+next_head:
+ movb %cl,%al
+ incb %dh # next head
+ movb $1,%cl # first sector
+ cmpb %ah,%dh # reach head limit ?
+ jne bdendlp
+next_track:
+ movb %dh,%ah
+ movb $0,%dh # first head
+# NOTE : support 256 cylinders max
+ incb %ch # next cylinder
+bdendlp:
+curdrive = _start
+curdx = _start
+curcx = _start+2
+limits = _start+4
+ movw %dx, curdx # save disk state
+ movw %cx, curcx
+ movw %ax, limits
+read_sectors:
+ movw curdx, %dx # restore disk state
+ movw curcx, %cx
+# al is last sector+1
+# ah is last head+1
+ movw limits, %ax
+ orw %di,%di
+ jne read_sectorslp
+ movb $0x2e, %al # loading... message 2e = .
+putc:
+ movb $0xe, %ah
+ movw $7, %bx # one dot each 64k
+ int $0x10
+return:
+ ret
+
+print_nl:
+
+ movb $0xd, %al # CR
+ call putc
+ movb $0xa, %al # LF
+ jmp putc
+
+puts:
+ call print_nl # set %ah and %bx
+putslp:
+ lodsb
+ orb %al,%al # end of string is \0
+ jz return
+putcs:
+ int $0x10
+ jmp putslp
- .org 497
+floppy_table:
+#ifdef EXTRA_DEVICES
+ .byte 16,9 # /dev/fd0u720
+ .byte 12,10 # /dev/fd0u800
+ .byte 80,11 # /dev/fd0u880
+ .byte 125,20 # /dev/fd0u1600
+ .byte 44,21 # /dev/fd0u1680
+ .byte 96,22 # /dev/fd0u1760
+ .byte 116,23 # /dev/fd0u1840
+ .byte 100,24 # /dev/fd0u1920
+ .byte 105,40 # /dev/fd0u3200
+ .byte 109,44 # /dev/fd0u3520
+ .byte 113,48 # /dev/fd0u3840
+#endif
+ .byte 8,15 # /dev/fd0h1200 - /dev/ps0
+ .byte 28,18 # /dev/fd0u1440 - /dev/PS0
+ .byte 32,36 # /dev/fd0u2880 - /dev/fd0H2880
+ .byte 0,128 # /dev/fd0 - default: autodetect
+
+regs: .asciz "X:"
+
+#ifndef DISPLAY_KERNEL_VERSION
+msg1: .asciz "Loading"
+#endif
+
+tail:
+ .space 495+start-tail
+
+#.org 495
+sys_sects: .word SYSSIZE / 32 # size max is now 32Mb
+#.org 497
setup_sects: .byte SETUPSECTS
root_flags: .word ROOT_RDONLY
-syssize: .word SYSSIZE
+syssize: .word SYSSIZE % 0x10000 # size max was 1Mb
swap_dev: .word SWAP_DEV
-ram_size: .word RAMDISK
+ram_size: .word RAMDISK # ramdisk size, ramdisk flags and cmdline flag
vid_mode: .word SVGA_MODE
root_dev: .word ROOT_DEV
boot_flag: .word 0xAA55
diff -purN linux-2.6.13/arch/i386/boot/tools/build.c linux-2.6.13-bootblock/arch/i386/boot/tools/build.c
--- linux-2.6.13/arch/i386/boot/tools/build.c 2005-09-12 10:38:52.000000000 +0200
+++ linux-2.6.13-bootblock/arch/i386/boot/tools/build.c 2005-09-12 10:46:25.000000000 +0200
@@ -168,10 +168,13 @@ int main(int argc, char ** argv)
}
close(fd);
- if (lseek(1, 497, SEEK_SET) != 497) /* Write sizes to the bootsector */
+ if (lseek(1, 495, SEEK_SET) != 495) /* Write sizes to the bootsector */
die("Output: seek failed");
- buf[0] = setup_sectors;
- if (write(1, buf, 1) != 1)
+ sz = (sb.st_size + 511) / 512;
+ buf[0] = (sz & 0xff);
+ buf[1] = ((sz >> 8) & 0xff);
+ buf[2] = setup_sectors;
+ if (write(1, buf, 3) != 3)
die("Write of setup sector count failed");
if (lseek(1, 500, SEEK_SET) != 500)
die("Output: seek failed");
diff -purN linux-2.6.13/arch/i386/kernel/setup.c linux-2.6.13-bootblock/arch/i386/kernel/setup.c
--- linux-2.6.13/arch/i386/kernel/setup.c 2005-09-12 10:38:53.000000000 +0200
+++ linux-2.6.13-bootblock/arch/i386/kernel/setup.c 2005-09-12 10:57:01.000000000 +0200
@@ -156,6 +156,7 @@ unsigned long saved_videomode;
#define RAMDISK_IMAGE_START_MASK 0x07FF
#define RAMDISK_PROMPT_FLAG 0x8000
#define RAMDISK_LOAD_FLAG 0x4000
+#define CMDLINE_LOAD_FLAG 0x2000
static char command_line[COMMAND_LINE_SIZE];
diff -purN linux-2.6.13/arch/x86_64/boot/bootsect.S linux-2.6.13-bootblock/arch/x86_64/boot/bootsect.S
--- linux-2.6.13/arch/x86_64/boot/bootsect.S 2005-09-12 10:37:58.000000000 +0200
+++ linux-2.6.13-bootblock/arch/x86_64/boot/bootsect.S 2005-09-12 10:58:07.000000000 +0200
@@ -4,20 +4,31 @@
* modified by Drew Eckhardt
* modified by Bruce Evans (bde)
* modified by Chris Noe (May 1999) (as86 -> gas)
- * gutted by H. Peter Anvin (Jan 2003)
+ *
+ * rewritten to support up to 32Mb kernel, cmdline
+ * and any disk geometry by <[email protected]>
*
* BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment
* addresses must be multiplied by 16 to obtain their respective linear
* addresses. To avoid confusion, linear addresses are written using leading
* hex while segment addresses are written as segment:offset.
*
+ * bde - should not jump blindly, there may be systems with only 512K low
+ * memory. Use int 0x12 to get the top of memory, etc.
+ *
+ * It then loads 'setup' directly after itself (0x90200), and the system
+ * at 0x10000, using BIOS interrupts.
+ *
+ * The loader has been made as simple as possible, and continuous
+ * read errors will result in a unbreakable loop. Reboot by hand. It
+ * loads pretty fast by getting whole tracks at a time whenever possible.
*/
#include <asm/boot.h>
SETUPSECTS = 4 /* default nr of setup-sectors */
BOOTSEG = 0x07C0 /* original address of boot-sector */
-INITSEG = DEF_INITSEG /* we move boot here - out of the way */
+INITSEG = DEF_INITSEG /* we load boot here - out of the way */
SETUPSEG = DEF_SETUPSEG /* setup starts here */
SYSSEG = DEF_SYSSEG /* system loaded at 0x10000 (65536) */
SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */
@@ -25,6 +36,12 @@ SYSSIZE = DEF_SYSSIZE /* system size:
ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */
SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */
+/* some extra features */
+#define DISPLAY_KERNEL_VERSION as soon as possible
+#define EDIT_CMDLINE on hotkey
+#define LOAD_CMDLINE according to bit ramsize.13
+#define EXTRA_DEVICES to fill root_device
+
#ifndef SVGA_MODE
#define SVGA_MODE ASK_VGA
#endif
@@ -42,57 +59,470 @@ SWAP_DEV = 0 /* SWAP_DEV is now writte
.global _start
_start:
+ cld # assume nothing
+ movw $INITSEG, %ax
+ movw %ax, %es # %ax = %es = INITSEG
+#if MOVE_BOOTSECTOR
+# First things first. Move ourself from 0x7C00 -> 0x90000 and jump there.
+ movw $BOOTSEG, %cx
+ movw %cx, %ds # %ds = BOOTSEG
+ movb $1, %ch # %cx = 256
+ subw %si, %si
+ subw %di, %di
+ rep
+ movsw
+ ljmp $INITSEG, $go
+go:
+#else
+ xorw %cx, %cx # %cx = 0
+#endif
- # Normalize the start address
- jmpl $BOOTSEG, $start2
+# bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We
+# wouldn't have to worry about this if we checked the top of memory. Also
+# my BIOS can be configured to put the wini drive tables in high memory
+# instead of in the vector table. The old stack might have clobbered the
+# drive table.
+
+ movw $0x4000-12, %di # 0x4000 is an arbitrary value >=
+ # length of bootsect + length of
+ # setup + room for stack;
+ # 12 is disk parm size.
+ # gdt will heat 48 more bytes.
+ movw %ax, %ss # %ax and %es already contain INITSEG
+ movw %di, %sp # put stack at INITSEG:0x4000-12.
+
+# Many BIOS's default disk parameter tables will not recognize
+# multi-sector reads beyond the maximum sector number specified
+# in the default diskette parameter tables - this may mean 7
+# sectors in some cases.
+#
+# Since single sector reads are slow and out of the question,
+# we must take care of this by creating new parameter tables
+# (for the first disk) in RAM. We can set the maximum sector
+# count to 36 - the most we will encounter on an ED 2.88.
+#
+# High doesn't hurt. Low does. Let's use the max: 63
+#
+# Segments are as follows: %es = %ss = INITSEG,
+# %fs and %gs are unused.
+
+ movw $0x78, %bx # %ds:%bx is parameter table address
+ movw %cx, %ds # %ds = 0
+ ldsw (%bx), %si # %ds:%si is source
+ movb $6, %cl # copy 12 bytes
+ rep # don't worry about cld
+ movsw # already done above
+ movw %cx, %ds # %ds = 0
+ movw %sp, (%bx) # %sp = 0x4000-12
+ movw %es, 2(%bx)
+ pushw %es
+ popw %ds # now %ds = %es = %ss = INITSEG
+ movb $63, 0x4-12(%di) # patch sector count, %di = 0x4000
+
+ cli
+ cbw # %ax = 0 : geometry unknown yet
+ xorb %dh, %dh # head 0, current drive
+ incw %cx # cylinder 0, sector 1
+ movw %cx, %di # read 1 sector
+ call read_first_sector # read bootsector again to have
+ # access to data segment
+
+#ifndef DISPLAY_KERNEL_VERSION
+ movw $msg1, %si
+ call puts
+#endif
-start2:
- movw %cs, %ax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %ss
- movw $0x7c00, %sp
- sti
- cld
+# Load the setup-sectors directly after the moved bootblock (at 0x90200).
- movw $bugger_off_msg, %si
+ movb setup_sects, %al
+#ifdef CHECK_SETUP_SIZE
+ orb %al, %al
+ jne setup_size_ok
+ movb $SETUPSECTS, %al
+setup_size_ok:
+#endif
+ cbw
+ xchg %ax, %di
+ call read_sectors # read setup
+
+#ifdef DISPLAY_KERNEL_VERSION
+#define kernel_version 0xE
+ movw $0x200,%si
+ addw kernel_version(%si),%si # starting protocol 2.00, Kernel 1.3.73
+ call puts # show which kernel we are loading
+#endif
-msg_loop:
- lodsb
- andb %al, %al
- jz die
- movb $0xe, %ah
- movw $7, %bx
- int $0x10
- jmp msg_loop
+# This routine loads the system at address SYSSEG, making sure
+# no 64kB boundaries are crossed. We try to load it as fast as
+# possible, loading whole tracks whenever we can.
+
+#ifdef __BIG_KERNEL__
+type_of_loader = 528
+ movw $24, %cx # allocate 48 bytes in stack
+init_gdt:
+ push $0 # initialized with 0
+ loop init_gdt
+ movw %sp, %si # for bootsect_gdt
+ movw $0x9300+(SYSSEG/4096), %ax # source = SYSSEG
+ cwd
+ movw %ax, 20(%si) # bootsect_src_base+2
+ movb $0x10-1, %al # destination = 0x100000
+ movw %ax, 28(%si) # bootsect_dst_base+2
+ movw %dx, 16(%si) # bootsect_src = 64Kb
+ movw %dx, 24(%si) # bootsect_dst = 64Kb
+ movb %dl, type_of_loader # loader type = 0xFF
+syslp:
+ movw $SYSSEG, %ax
+ movw %ax, %es
+ movw $128,%di # 64Kb in sectors
+ subw %di, sys_sects
+ pushf
+ jnc not_last
+ addw sys_sects, %di
+not_last:
+ call read_sectors
+ incw 28(%si) # bootsect_dst_base+2
+ movw $0x8000, %cx # full 64K
+ movb $0x87, %ah
+ push %ss
+ pop %es # gdt in es:si
+ int $0x15
+ popf
+ ja syslp
+#else
+ movw $SYSSEG, %ax
+ movw %ax, %es
+syslp:
+ movw $128*32,%ax # 64Kb in paragraphs
+ subw %ax, syssize
+ pushf
+ jnc not_last
+ addw syssize, %ax
+not_last:
+ movb $5, %cl # paragraphs -> sectors
+ shrw %cl, %ax
+ xchg %ax, %di
+ call read_sectors
+ popf
+ ja syslp
+#endif
-die:
- # Allow the user to press a key, then reboot
- xorw %ax, %ax
- int $0x16
- int $0x19
+# After that we check which root-device to use. If the device is
+# defined (!= 0), nothing is done and the given device is used.
+# Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8)
+# depending on the number of sectors we pretend to know we have.
+
+
+ movw root_dev, %ax
+ orw %ax, %ax
+ jnz root_defined
+
+ movw $floppy_table,%si
+scan_floppy_table:
+ lodsw
+ cmpb limits, %ah
+ je set_root
+ jno scan_floppy_table
+set_root:
+ movb $2, %ah
+ addb %dl, %al # add current (floppy) drive
+ movw %ax, root_dev
+root_defined:
+
+#if defined(LOAD_CMDLINE) || defined(EDIT_CMDLINE)
+#define BUFFER 0x7F00
+ movw $BUFFER, %si
+ movw %si, (%si) # default : no cmdline
+#endif
- # int 0x19 should never return. In case it does anyway,
- # invoke the BIOS reset code...
- ljmp $0xf000,$0xfff0
+#ifdef LOAD_CMDLINE
+ testb $0x20,ram_size+1 # bit 11 to 13 where unused
+ # now bit 13 means: load cmdline
+ jz nocmd
+ movw $BUFFER/16+INITSEG, %ax
+ movw %ax, %es
+ movw $1, %di # cmdline = 512 bytes max
+ call read_sectors
+nocmd:
+#endif
+#define RSHFT 0x01
+#define LSHFT 0x02
+#define CTRL 0x04
+#define ALT 0x08
+#define SCRLCK 0x10
+#define NUMLCK 0x20
+#define CAPSLCK 0x40
+#define INSERT 0x80
+
+#ifdef EDIT_CMDLINE
+# The cmdline can be entered and modifed on hot key.
+# Only characters before the cursor are passed to the kernel.
+ movb $2, %ah # get keyboard status
+ int $0x16
+ testb $RSHFT|LSHFT|CTRL|ALT|CAPSLCK, %al
+ jz nocmdline
+ pushw %si
+ call puts # set %ah and %bx
+cmdlp:
+# if 1
+ movb $32, %al # clear end of line
+ int $0x10 # with Space
+ movb $8, %al # and BackSpace
+ int $0x10
+# endif
+ decw %si
+cmdget:
+ cbw # %ah = 0, get keyboard character
+ int $0x16
+ cmpb $8, %al # BackSpace ?
+ je cmdbs
+ cbw
+ movw %ax, (%si) # store end of string too
+ incw %si
+ incw %si
+cmdbs:
+ cmpw $BUFFER, %si # lower limit is checked
+ je cmdget # but upper limit not
+ call putc
+ cmpb $13, %al # Enter ?
+ jne cmdlp
+ popw %si
+nocmdline:
+#endif
-bugger_off_msg:
- .ascii "Direct booting from floppy is no longer supported.\r\n"
- .ascii "Please use a boot loader program instead.\r\n"
- .ascii "\n"
- .ascii "Remove disk and press any key to reboot . . .\r\n"
- .byte 0
+#if defined(LOAD_CMDLINE) || defined(EDIT_CMDLINE)
+#if 1
+cmd_line_magic = 0x20
+cmd_line_offset = 0x22
+ movw $0xA33F, cmd_line_magic
+ movw %si, cmd_line_offset
+#else
+# protocol >= 2.02, starting Kernel 2.4.0-test3-pre3
+cmd_line_ptr = 0x228
+ movzx %si, %eax
+ addl $INITSEG*16, %eax
+ movl %eax, cmd_line_ptr
+#endif
+emptycmdline:
+#endif
+
+# This procedure turns off the floppy drive motor, so
+# that we enter the kernel in a known state, and
+# don't have to worry about it later.
+
+#if 1
+kill_motor:
+ xorw %ax, %ax # reset FDC
+ int $0x13
+#else
+kill_motor:
+ movw $0x3f2, %dx
+ xorb %al, %al
+ outb %al, %dx
+#endif
+ call print_nl
- # Kernel attributes; used by setup
+# After that (everything loaded), we jump to the setup-routine
+# loaded directly after the bootblock:
+# Segments are as follows: %ds = %ss = INITSEG
+
+ ljmp $SETUPSEG, $0
+
+# read_sectors reads %di sectors into %es:0 buffer.
+# %es:0 is updated to the next memory location.
+# First, sectors are read sector by sector until
+# sector per track count is known. Then they are
+# read track by track.
+# Assume no error on first track.
+
+#define TRACK_BY_TRACK load as fast as possible !
+#define SHOW_REGS show int13 status & parameters
+
+check_limits:
+ cmpb %al, %cl # max sector known ?
+ ja next_head # no -> store it
+ cmpb %ah, %dh # max head known ?
+ ja next_track # no -> store it
+ pusha # save context
+#ifdef SHOW_REGS
+ pushw %es # print %es (named EX)
+ pushw %dx # print %dx
+ pushw %cx # print %cx
+ xorw %cx, %cx
+ pushw %cx # print %bx
+# ifdef TRACK_BY_TRACK
+ movb $2, %bh
+# endif
+ pushw %bx # print %ax
+ movb $6,%cl
+ jmp print_all # print %bp (status)
+print_loop:
+ movb $0x6 + 'A' - 1, %al
+ subb %cl, %al
+ movw $regs, %si # caller %si is saved
+ call putcs # putc(%al) + puts(%si)
+# it will print out all of the registers.
+ popw %bp # load word into %bp
+print_all:
+ pushw %cx # save count remaining
+ movb $4, %cl # 4 hex digits
+print_digit:
+ rolw $4, %bp # rotate to use low 4 bits
+ movb $0x0f, %al
+ andw %bp, %ax # %al = mask for nybble
+ addb $0x90, %al # convert %al to ascii hex
+ daa # in only four instructions!
+ adcb $0x40, %al
+ daa
+ call putc # set %ah and %bx
+ loop print_digit
+ movb $0x20, %al # SPACE
+ int $0x10
+ popw %cx
+ loop print_loop
+ xchg %ax, %cx # %ah = 0
+#else
+ cbw # %ah = 0
+#endif
+ int $0x13 # reset controler
+ popa # restore context
+read_sectorslp:
+read_first_sector:
+ pushw %di # sector count
+ pushw %ax # limits
+ pushw %dx
+ pushw %cx
+ xorw %bx, %bx
+#ifdef TRACK_BY_TRACK
+ subb %cl, %al # sectors remaining in track
+ ja tolastsect
+ movb $1, %al # 1 sector mini
+tolastsect:
+ cbw
+ cmpw %di, %ax
+ jb more1trk
+ movw %di, %ax # sectors to read
+more1trk:
+ push %ax
+ movb $2, %ah # cmd: read chs
+#else
+ movw $0x201, %ax # sector by sector
+ push %ax
+#endif
+ int $0x13
+ xchg %ax, %bp # status
+ popw %bx # %ax
+ popw %cx
+ popw %dx
+ popw %ax # limits
+ popw %di # sector count
+ jc check_limits
+next_sector:
+#ifdef TRACK_BY_TRACK
+ subw %bx,%di # update sector counter
+ addw %bx,%cx # next sector
+ shlw $5,%bx # sectors -> paragraghs
+ movw %es, %bp
+ addw %bx, %bp
+#else
+ decw %di # update sector counter
+ incw %cx # next sector
+ movw %es, %bp
+ addw $32, %bp # sector size in paragraghs
+#endif
+ movw %bp, %es # next location
+ cmpb %al,%cl # reach sector limit ?
+ jne bdendlp
+next_head:
+ movb %cl,%al
+ incb %dh # next head
+ movb $1,%cl # first sector
+ cmpb %ah,%dh # reach head limit ?
+ jne bdendlp
+next_track:
+ movb %dh,%ah
+ movb $0,%dh # first head
+# NOTE : support 256 cylinders max
+ incb %ch # next cylinder
+bdendlp:
+curdrive = _start
+curdx = _start
+curcx = _start+2
+limits = _start+4
+ movw %dx, curdx # save disk state
+ movw %cx, curcx
+ movw %ax, limits
+read_sectors:
+ movw curdx, %dx # restore disk state
+ movw curcx, %cx
+# al is last sector+1
+# ah is last head+1
+ movw limits, %ax
+ orw %di,%di
+ jne read_sectorslp
+ movb $0x2e, %al # loading... message 2e = .
+putc:
+ movb $0xe, %ah
+ movw $7, %bx # one dot each 64k
+ int $0x10
+return:
+ ret
+
+print_nl:
+
+ movb $0xd, %al # CR
+ call putc
+ movb $0xa, %al # LF
+ jmp putc
+
+puts:
+ call print_nl # set %ah and %bx
+putslp:
+ lodsb
+ orb %al,%al # end of string is \0
+ jz return
+putcs:
+ int $0x10
+ jmp putslp
- .org 497
+floppy_table:
+#ifdef EXTRA_DEVICES
+ .byte 16,9 # /dev/fd0u720
+ .byte 12,10 # /dev/fd0u800
+ .byte 80,11 # /dev/fd0u880
+ .byte 125,20 # /dev/fd0u1600
+ .byte 44,21 # /dev/fd0u1680
+ .byte 96,22 # /dev/fd0u1760
+ .byte 116,23 # /dev/fd0u1840
+ .byte 100,24 # /dev/fd0u1920
+ .byte 105,40 # /dev/fd0u3200
+ .byte 109,44 # /dev/fd0u3520
+ .byte 113,48 # /dev/fd0u3840
+#endif
+ .byte 8,15 # /dev/fd0h1200 - /dev/ps0
+ .byte 28,18 # /dev/fd0u1440 - /dev/PS0
+ .byte 32,36 # /dev/fd0u2880 - /dev/fd0H2880
+ .byte 0,128 # /dev/fd0 - default: autodetect
+
+regs: .asciz "X:"
+
+#ifndef DISPLAY_KERNEL_VERSION
+msg1: .asciz "Loading"
+#endif
+
+tail:
+ .space 495+start-tail
+
+#.org 495
+sys_sects: .word SYSSIZE / 32 # size max is now 32Mb
+#.org 497
setup_sects: .byte SETUPSECTS
root_flags: .word ROOT_RDONLY
-syssize: .word SYSSIZE
+syssize: .word SYSSIZE % 0x10000 # size max was 1Mb
swap_dev: .word SWAP_DEV
-ram_size: .word RAMDISK
+ram_size: .word RAMDISK # ramdisk size, ramdisk flags and cmdline flag
vid_mode: .word SVGA_MODE
root_dev: .word ROOT_DEV
boot_flag: .word 0xAA55
diff -purN linux-2.6.13/arch/x86_64/boot/tools/build.c linux-2.6.13-bootblock/arch/x86_64/boot/tools/build.c
--- linux-2.6.13/arch/x86_64/boot/tools/build.c 2005-09-12 10:38:57.000000000 +0200
+++ linux-2.6.13-bootblock/arch/x86_64/boot/tools/build.c 2005-09-12 11:00:44.000000000 +0200
@@ -169,10 +169,13 @@ int main(int argc, char ** argv)
}
close(fd);
- if (lseek(1, 497, SEEK_SET) != 497) /* Write sizes to the bootsector */
+ if (lseek(1, 495, SEEK_SET) != 495) /* Write sizes to the bootsector */
die("Output: seek failed");
- buf[0] = setup_sectors;
- if (write(1, buf, 1) != 1)
+ sz = (sb.st_size + 511) / 512;
+ buf[0] = (sz & 0xff);
+ buf[1] = ((sz >> 8) & 0xff);
+ buf[2] = setup_sectors;
+ if (write(1, buf, 3) != 3)
die("Write of setup sector count failed");
if (lseek(1, 500, SEEK_SET) != 500)
die("Output: seek failed");
diff -purN linux-2.6.13/Documentation/i386/boot.txt linux-2.6.13-bootblock/Documentation/i386/boot.txt
--- linux-2.6.13/Documentation/i386/boot.txt 2005-09-12 10:36:50.000000000 +0200
+++ linux-2.6.13-bootblock/Documentation/i386/boot.txt 2005-09-12 12:22:43.000000000 +0200
@@ -103,6 +103,7 @@ The header looks like:
Offset Proto Name Meaning
/Size
+01EF/2 N/A sys_sects DO NOT USE - for bootsect.S use only
01F1/1 ALL setup_sects The size of the setup in sectors
01F2/2 ALL root_flags If set, the root is mounted readonly
01F4/2 ALL syssize DO NOT USE - for bootsect.S use only
diff -purN linux-2.6.13/Documentation/ramdisk.txt linux-2.6.13-bootblock/Documentation/ramdisk.txt
--- linux-2.6.13/Documentation/ramdisk.txt 2005-09-12 10:35:39.000000000 +0200
+++ linux-2.6.13-bootblock/Documentation/ramdisk.txt 2005-09-12 10:55:35.000000000 +0200
@@ -63,12 +63,14 @@ to 2 MB (2^11) of where to find the RAM
14 indicates that a RAM disk is to be loaded, and bit 15 indicates whether a
prompt/wait sequence is to be given before trying to read the RAM disk. Since
the RAM disk dynamically grows as data is being written into it, a size field
-is not required. Bits 11 to 13 are not currently used and may as well be zero.
+is not required. Bit 13 indicates that a cmdline is to be loaded by the kernel
+bootblock, Bits 11 to 12 are not currently used and may as well be zero.
These numbers are no magical secrets, as seen below:
./arch/i386/kernel/setup.c:#define RAMDISK_IMAGE_START_MASK 0x07FF
./arch/i386/kernel/setup.c:#define RAMDISK_PROMPT_FLAG 0x8000
./arch/i386/kernel/setup.c:#define RAMDISK_LOAD_FLAG 0x4000
+./arch/i386/kernel/setup.c:#define CMDLINE_LOAD_FLAG 0x2000
Consider a typical two floppy disk setup, where you will have the
kernel on disk one, and have already put a RAM disk image onto disk #2.
@@ -159,6 +161,8 @@ users may wish to combine steps (d) and
Changelog:
----------
+09-05 : Reserve CMDLINE_LOAD bit.
+
10-22-04 : Updated to reflect changes in command line options, remove
obsolete references, general cleanup.
James Nelson ([email protected])
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
|
|