# HG changeset patch # User Pascal Bellard # Date 1258890400 -3600 # Node ID aa65a927a2f378aa7c8a7698048092a380e15daf # Parent fd85055f79dbe4a98062202fd66dc3bc1d52ab32 linux: add floppy boot support diff -r fd85055f79db -r aa65a927a2f3 linux/receipt --- a/linux/receipt Sun Nov 22 12:40:18 2009 +0100 +++ b/linux/receipt Sun Nov 22 12:46:40 2009 +0100 @@ -29,6 +29,7 @@ mkdir slitaz echo "$WGET_URL" > slitaz/url cp ../stuff/gztazmod.sh ../stuff/list_modules.sh slitaz + cp ../stuff/bootloader.sh slitaz # Misc patches from pascal while read patch_file; do echo "$patch_file" >> slitaz/patches @@ -49,6 +50,7 @@ aufs2-base.patch aufs2-kbuild.patch aufs2-standalone.patch +$PACKAGE-header-$VERSION.u EOT make mrproper cp ../stuff/$PACKAGE-$VERSION-slitaz.config .config diff -r fd85055f79db -r aa65a927a2f3 linux/stuff/bootloader.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux/stuff/bootloader.sh Sun Nov 22 12:46:40 2009 +0100 @@ -0,0 +1,155 @@ +#!/bin/sh +# +# This script creates a floppy image set from a linux bzImage and can merge +# a cmdline and/or one or more initramfs. +# The total size can not exceed 15M because INT 15H function 87H limitations. +# +# (C) 2009 Pascal Bellard - GNU General Public License v3. + +usage() +{ +cat <>8) & 255 )) \ + $(( ($2>>16) & 255 )) $(( ($2>>24) & 255 )) | \ + hexdump -R | dd bs=1 conv=notrunc of=$3 seek=$(( $1 )) 2> /dev/null +} + +# read a 32 bits data +# usage: getlong offset file +getlong() +{ + dd if=$2 bs=1 skip=$(( $1 )) count=4 2> /dev/null | \ + hexdump -e '"" 1/4 "%d" "\n"' +} + +floppyset() +{ + # bzImage offsets + SetupSzOfs=497 + SyssizeOfs=500 + CodeAdrOfs=0x214 + RamfsAdrOfs=0x218 + RamfsLenOfs=0x21C + ArgPtrOfs=0x228 + + # boot+setup address + SetupBase=0x90000 + + stacktop=0x9E00 + + bs=/tmp/bs$$ + + # Get and patch boot sector + dd if=$KERNEL bs=512 count=1 of=$bs 2> /dev/null + uudecode < /dev/null +begin-base64 644 - +v/Sd/GgAkAcxyQYXify7eACO2cU3sQbzpY7ZiSeMRwKg8X2YQAYfxkX4P/qX +mEEw9jHb6FcBvgACgEwRgMdEJACcA3QO6GYBvigCORxyLkeLHFboQQFfizXo +UgGwIOg+AbAIzRBOmM0WPAh0BZiJBEZGOzV08OgmATwKdd+5GABqAOL8ieaw +D7/0Af5NHLEFtJOJRBywAYlEFJmJVBCJVBhmMdtD0+NLZgMdZtPraAAQB7+A +ACn7nHMCAd9TVjHb6NQAXrkAgLSH/kQczRVbnXfcoRoCSL8cArEJOEQccrAx +wM0T6gAAIJCwRijIvrkB6L0AXesjgPkTcgQ4wXdogP4CcgQ45ndpgP1Qc3Ng +BlJRU5a0AlC5BgBRsQTBxQSwDyHoBJAnFEAn6HMA4u6wIM0QWeK0mM0TYTH2 +rZGtkq1QKMh3ArABmDn4cgKJ+FBStALNE1qVXlhynCn3AfHB5gkB8zjBdSaI +yP7GsQE45nUciPS2AP7FPBN1EoD9UHINtQBgvrwB6CUAmM0WYaMEAFJRZo8G +AAAJ/3WeFgewLrQOuwcAzRA8DXUOsArr8bAN6Oz/rAjAdfjDWDoASW5zZXJ0 +IG5leHQgZmxvcHB5IGFuZCBwcmVzcyBhbnkga2V5IHRvIGNvbnRpbnVlLgcN +AA== +==== +EOT + + # Get setup + setupsz=$(getlong $SetupSzOfs $bs) + setupszb=$(( $setupsz & 255 )) + dd if=$KERNEL bs=512 skip=1 count=$setupszb 2> /dev/null >> $bs + + # Store cmdline after setup + if [ -n "$CMDLINE" ]; then + echo -n "$CMDLINE" | dd bs=512 count=1 conv=sync 2> /dev/null >> $bs + storelong ArgPtrOfs $(( $SetupBase + $stacktop )) $bs + fi + + # Compute initramfs size + initrdlen=0 + padding=0 + for i in $( echo $INITRD | sed 's/,/ /' ); do + [ -s "$i" ] || continue + initrdlen=$(( $initrdlen + $padding )) + padding=$(stat -c %s $i) + initrdlen=$(( $initrdlen + $padding )) + padding=$(( 4096 - ($padding & 4095) )) + [ $padding -eq 4096 ] && padding=0 + done + Ksize=$(( $(getlong $SyssizeOfs $bs)*16 )) + Kpad=$(( (($Ksize+4095)/4096)*4096 - Ksize )) + if [ $initrdlen -ne 0 ]; then + Kbase=$(getlong $CodeAdrOfs $bs) + storelong $RamfsAdrOfs \ + $(( (0x1000000 - $initrdlen) & 0xFFFF0000 )) $bs + storelong $RamfsLenOfs $initrdlen $bs + fi + + # Output boot sector + setup + cmdline + dd if=$bs 2> /dev/null + + # Output kernel code + dd if=$KERNEL bs=512 skip=$(( $setupszb + 1 )) 2> /dev/null + + # Pad to next sector + Kpad=$(( 512 - ($(stat -c %s $KERNEL) & 511) )) + [ $Kpad -eq 512 ] || dd if=/dev/zero bs=1 count=$Kpad 2> /dev/null + + # Output initramfs + padding=0 + for i in $( echo $INITRD | sed 's/,/ /' ); do + [ -s "$i" ] || continue + [ $padding -ne 0 ] && dd if=/dev/zero bs=1 count=$padding + dd if=$i 2> /dev/null + padding=$(( 4096 - ($(stat -c %s $i) & 4095) )) + [ $padding -eq 4096 ] && padding=0 + done + + # Cleanup + rm -f $bs +} + +floppyset | split -b ${FORMAT}k /dev/stdin floppy$$ +i=1 +ls floppy$$* | while read file ; do + output=$PREFIX.$(printf "%03d" $i) + cat $file /dev/zero | dd bs=1k count=$FORMAT conv=sync of=$output 2> /dev/null + echo $output + rm -f $file + i=$(( $i + 1 )) +done diff -r fd85055f79db -r aa65a927a2f3 linux/stuff/linux-header-2.6.30.6.u --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux/stuff/linux-header-2.6.30.6.u Sun Nov 22 12:46:40 2009 +0100 @@ -0,0 +1,445 @@ +--- linux-2.6.30.6/arch/x86/boot/header.S ++++ linux-2.6.30.6/arch/x86/boot/header.S +@@ -6,7 +6,7 @@ + * Based on bootsect.S and setup.S + * modified by more people than can be counted + * +- * Rewritten as a common file by H. Peter Anvin (Apr 2007) ++ * Rewritten Pascal Bellard (Nov 2009) + * + * BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment + * addresses must be multiplied by 16 to obtain their respective linear +@@ -26,6 +26,8 @@ + + BOOTSEG = 0x07C0 /* original address of boot-sector */ + SYSSEG = 0x1000 /* historical load address >> 4 */ ++INITSEG = 0x9000 /* boot address >> 4 */ ++SETUPSEG = 0x9020 /* setup address >> 4 */ + + #ifndef SVGA_MODE + #define SVGA_MODE ASK_VGA +@@ -39,53 +41,392 @@ + #define ROOT_RDONLY 1 + #endif + ++#define SHOW_REGS show int13 status & parameters ++#define EDIT_CMDLINE add kernel command line support ++ + .code16 + .section ".bstext", "ax" + + .global bootsect_start + bootsect_start: ++stacktop = 0x9E00 # in 0x8000 .. 0xA000 ++ # with 512 bytes for cmdline ++ movw $stacktop-12, %di # stacktop is an arbitrary value >= ++ # length of bootsect + length of ++ # setup + room for stack; ++ # 12 is disk parm size. ++ # gdt will heat 48 more bytes. ++curcx = 0 ++curdx = curcx+2 ++ cld # assume nothing ++#ifndef FLOPPY_1440K_ONLY ++limits = 4 ++#endif + +- # Normalize the start address +- ljmp $BOOTSEG, $start2 ++ pushw $INITSEG ++ popw %es # %es = INITSEG ++ xorw %cx, %cx # %cx = 0 + +-start2: +- movw %cs, %ax +- movw %ax, %ds +- movw %ax, %es +- movw %ax, %ss +- xorw %sp, %sp +- sti +- cld ++ pushw %es ++ popw %ss # %ss and %es already contain INITSEG ++ movw %di, %sp # put stack at INITSEG:stacktop-12. + +- movw $bugger_off_msg, %si ++# 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. + +-msg_loop: +- lodsb +- andb %al, %al +- jz bs_die +- movb $0xe, %ah +- movw $7, %bx ++ 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 = stacktop-12 ++ movw %es, 2(%bx) ++ ++ movb setup_sects+0x7C00, %al # read bootsector + setup (%ds = 0) ++ cbw ++ incw %ax ++ ++ pushw %es ++ popw %ds # now %ds = %es = %ss = INITSEG ++ movb $63, 0x4-12(%di) # patch sector count, %di = stacktop ++ ++ cli ++ ++ xchg %ax, %di # sector count ++ cbw # limits = 0 ++ incw %cx # cylinder 0, sector 1 ++ xorb %dh, %dh # head 0, current drive ++ xorw %bx, %bx ++ call read_first_sectors # read setup ++ ++#define version_offset 0xE ++#define loadflags_offset 0x11 ++#define heap_end_ptr_offset 0x24 ++ ++ movw $_start,%si ++ orb $0x80, loadflags_offset(%si) ++ movw $stacktop-0x200, heap_end_ptr_offset(%si) ++ ++ addw version_offset(%si),%si # starting protocol 2.00, Kernel 1.3.73 ++ call puts # show which kernel we are loading ++ ++#ifdef EDIT_CMDLINE ++# The cmdline can be entered and modifed on hot key. ++# Only characters before the cursor are passed to the kernel. ++ movw $cmd_line_ptr, %si ++ cmpw %bx,(%si) # %bx = 7 ++ jb nocmdline ++ incw %di # read 1 sector ++ movw (%si), %bx ++ pushw %si ++ call read_sectors ++ popw %di ++ movw (%di), %si ++ call puts ++cmdlp: ++ movb $32, %al # clear end of line ++ call putc # with Space ++ movb $8, %al # and BackSpace + int $0x10 +- jmp msg_loop ++ 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 (%di), %si # lower limit is checked ++ je cmdget # but upper limit not ++ call putc ++ cmpb $10, %al # Enter ? ++ jne cmdlp ++endcmdline: ++ ++nocmdline: ++#endif + +-bs_die: +- # Allow the user to press a key, then reboot +- xorw %ax, %ax ++# 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. ++ ++ movw $24, %cx # allocate 48 bytes in stack ++init_gdt: ++ push $0 # initialized with 0 ++ loop init_gdt ++ movw %sp, %si # for bootsect_gdt ++ movb $0x0F, %al # destination = 0x100000 ++ movw $syssize, %di ++#define type_of_loader_offset 0x1C /* type_of_loader - syssize */ ++ decb type_of_loader_offset(%di) # loader type = 0xFF ++ movb $5, %cl ++initrdlp: ++ movb $0x93,%ah ++ movw %ax, 28(%si) # bootsect_dst_base+2 ++ movb $(SYSSEG/4096), %al # source = SYSSEG ++ movw %ax, 20(%si) # bootsect_src_base+2 ++ cwd ++ movw %dx, 16(%si) # bootsect_src = 64Kb ++ movw %dx, 24(%si) # bootsect_dst = 64Kb ++ xorl %ebx, %ebx ++ incw %bx ++ shlw %cl,%bx ++ decw %bx ++ addl (%di),%ebx ++ shrl %cl, %ebx ++syslp: ++ pushw $SYSSEG ++ popw %es ++ movw $128,%di # 64Kb ++ subw %di, %bx # max 32M > int 15 limit ++ pushf ++ jnc not_last ++ addw %bx, %di ++not_last: ++ pushw %bx ++ pushw %si ++ xorw %bx, %bx ++ call read_sectors ++ popw %si ++ movw $0x8000, %cx # full 64K ++ movb $0x87, %ah ++ incb 28(%si) # bootsect_dst_base+2 ++ int $0x15 # max 16M ++ popw %bx ++ popf ++ ja syslp ++ movw ramdisk_image+2,%ax ++ decw %ax ++ movw $ramdisk_size,%di ++ movb $9, %cl ++ cmpb %al,28(%si) ++ jb initrdlp ++ ++# 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. ++ ++kill_motor: ++ xorw %ax, %ax # reset FDC ++ int $0x13 ++ ++# 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 FLOPPY_CYLINDERS 80 /* 80 cylinders minimum */ ++#define FLOPPY_HEADS 2 /* 2 heads minimum */ ++#define FLOPPY_SECTORS 18 /* 18 sectors minimum */ ++ ++#ifdef SHOW_REGS ++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 ++ jmp print_all # print %bp (status) ++#endif ++check_limits: ++#ifndef FLOPPY_1440K_ONLY ++ cmpb $FLOPPY_SECTORS+1, %cl # 18 sectors minimum ++ jb check_head ++ cmpb %al, %cl # max sector known ? ++ ja next_head # no -> store it ++check_head: ++ cmpb $FLOPPY_HEADS, %dh # 2 heads minimum ++ jb check_cylinder ++ cmpb %ah, %dh # max head known ? ++ ja next_cylinder # no -> store it ++check_cylinder: ++ cmpb $FLOPPY_CYLINDERS, %ch # 80 cylinders minimum ++ jae next_floppy ++#endif ++ pushaw ++#ifdef SHOW_REGS ++ pushw %es # print %es (named EX) ++ pushw %dx # print %dx ++ pushw %cx # print %cx ++ pushw %bx # print %bx ++#ifndef FLOPPY_1440K_ONLY ++ xchgw %ax, %si ++#endif ++ movb $2,%ah ++ pushw %ax # print %ax ++ movw $6,%cx ++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 ++#endif ++ cbw # %ah = 0 ++ int $0x13 # reset controler ++ popaw ++read_sectorslp: ++ xorw %si, %si ++ lodsw ++ xchgw %ax,%cx # restore disk state ++ lodsw ++ xchgw %ax,%dx ++#ifndef FLOPPY_1440K_ONLY ++# al is last sector+1 ++# ah is last cylinder+1 ++ lodsw ++#endif ++#ifndef FLOPPY_1440K_ONLY ++ pushw %ax # limits ++ subb %cl, %al # sectors remaining in track ++ ja tolastsect ++ movb $1, %al # 1 sector mini ++tolastsect: ++#else ++ mov $FLOPPY_SECTORS+1, %al ++ subb %cl, %al # sectors remaining in track ++#endif ++ cbw ++ cmpw %di, %ax ++ jb more1trk ++ movw %di, %ax # sectors to read ++more1trk: ++ pushw %ax # save context ++ pushw %dx # some bios break dx... ++ movb $2, %ah # cmd: read chs ++ int $0x13 ++ popw %dx ++ xchgw %ax, %bp # status ++#ifndef FLOPPY_1440K_ONLY ++ popw %si # save %ax ++ popw %ax # limits ++#else ++ popw %ax # restore context ++#endif ++ jc check_limits ++#ifndef FLOPPY_1440K_ONLY ++ subw %si,%di # update sector counter ++ addw %si,%cx # next sector ++ shlw $9,%si ++ addw %si,%bx # next location ++#else ++ subw %ax,%di # update sector counter ++ addw %ax,%cx # next sector ++ addw %ax,%ax ++ addb %al,%bh # next location ++#endif ++#ifndef FLOPPY_1440K_ONLY ++ cmpb %al,%cl # reach sector limit ? ++ jne bdendlp ++next_head: ++ movb %cl,%al ++#else ++ cmpb $FLOPPY_SECTORS+1,%cl # reach sector limit ? ++ jne bdendlp ++#endif ++ incb %dh # next head ++ movb $1,%cl # first sector ++#ifndef FLOPPY_1440K_ONLY ++ cmpb %ah, %dh # reach head limit ? ++ jne bdendlp ++next_cylinder: ++ movb %dh,%ah ++#else ++ cmpb %cl,%dh # reach head limit ? ++ je bdendlp ++#endif ++ movb $0,%dh # first head ++# NOTE : support 256 cylinders max ++ incb %ch # next cylinder ++#ifndef FLOPPY_1440K_ONLY ++ cmpb $FLOPPY_SECTORS+1,%al # 1.44M floppy ? ++ jne bdendlp ++#endif ++ cmpb $FLOPPY_CYLINDERS,%ch # reach cylinder limit ? ++ jb bdendlp ++next_floppy: ++ movb $0,%ch # first cylinder ++ pushaw ++ movw $swap_floppy,%si ++ call puts ++ cbw # %ah = 0, get keyboard character + int $0x16 +- int $0x19 ++ popaw ++bdendlp: ++read_first_sectors: ++#ifndef FLOPPY_1440K_ONLY ++ movw %ax, limits ++#endif ++ pushw %dx ++ pushw %cx ++ popl curcx # save disk state ++read_sectors: ++ orw %di,%di ++ jne read_sectorslp ++ pushw %ss ++ popw %es # restore es ++ movb $0x2e, %al # loading... message 2e = . ++putc: ++ movb $0xe, %ah ++ movw $7, %bx # one dot each 64k ++ int $0x10 ++ cmp $0xd, %al # CR ? ++ jne return ++ movb $0xa, %al # LF ++ jmp putc + +- # int 0x19 should never return. In case it does anyway, +- # invoke the BIOS reset code... +- ljmp $0xf000,$0xfff0 ++puts: ++ movb $0xd, %al # CR ++putcs: ++ call putc ++ lodsb ++ orb %al,%al # end of string is \0 ++ jnz putcs ++return: ++ ret + +- .section ".bsdata", "a" +-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 ++regs: .asciz "X:" + ++swap_floppy: ++ .ascii "Insert next floppy and press any key to continue." ++ .byte 7,13,0 + + # Kernel attributes; used by setup. This is part 1 of the + # header, from the old boot sector.