grub/boot/i386/pc/diskboot.S
okuji 524a1e6a40 2006-06-04 Yoshinori K. Okuji <okuji@enbug.org>
Clean up the code to support 64-bit addressing in disks and
        files. This change is not enough for filesystems yet.

        * util/i386/pc/grub-setup.c (struct boot_blocklist): Change the
        type of "start" to grub_uint64_t.
        (setup): Change the types of KERNEL_SECTOR and FIRST_SECTOR to
        grub_disk_addr_t * and grub_disk_addr_t. Fix the format string in
        save_first_sector and save_blocklists. Use grub_le_to_cpu64 to
        convert addresses.

        * util/i386/pc/biosdisk.c (open_device): Change the type of SECTOR
        to grub_disk_addr_t.

        * partmap/gpt.c (gpt_partition_map_iterate): Fix the format
        string.

        * partmap/pc.c (pc_partition_map_iterate): Likewise.

        * partmap/amiga.c (amiga_partition_map_iterate): Cast RDSK.MAGIC
        to char *.

        * normal/script.c (grub_script_parse): Remove unused MEMFREE.

        * normal/parser.y (YYLTYPE_IS_TRIVIAL): New macro.

        * normal/lexer.c (grub_script_yyerror): Specify unused to LEX.

        * loader/i386/pc/multiboot.c (grub_multiboot_load_elf64): Cast -1
        to grub_off_t, to detect an error from grub_file_seek.
        (grub_multiboot_load_elf32): Likewise.

        * kern/misc.c (grub_strtoul): Use grub_strtoull. Return the
        maximum unsigned long value when an overflow is detected.
        (grub_strtoull): New function.
        (grub_divmod64): Likewise.
        (grub_lltoa): use grub_divmod64.

        * kern/fs.c (struct grub_fs_block): Change the type of "offset" to
        grub_disk_addr_t.
        (grub_fs_blocklist_open): Increase P if P is not NULL to advance
        the pointer to next character. Use grub_strtoull instead of
        grub_strtoul.
        (grub_fs_blocklist_read): Change the types of SECTOR, OFFSET and
        SIZE to grub_disk_addr_t, grub_off_t and grub_size_t,
        respectively.

        * kern/file.c (grub_file_read): Prevent an oveflow of LEN, as the
        return value is signed.
        (grub_file_seek): Change the type of OLD to grub_off_t. Do not
        test if OFFSET is less than zero, as OFFSET is unsigned now.

        * kern/disk.c (struct grub_disk_cache): Change the type of
        "sector" to grub_disk_addr_t.
        (grub_disk_cache_get_index): Change the type of SECTOR to
        grub_disk_addr_t. Calculate the hash with SECTOR casted to
        unsigned after shifting.
        (grub_disk_cache_invalidate): Change the type of SECTOR to
        grub_disk_addr_t.
        (grub_disk_cache_unlock): Likewise.
        (grub_disk_cache_store): Likewise.
        (grub_disk_check_range): Change the types of SECTOR, OFFSET, SIZE,
        START and LEN to grub_disk_addr_t *, grub_off_t *, grub_size_t,
        grub_disk_addr_t and grub_uint64_t, respectively.
        (grub_disk_read): Use an unsigned variable REAL_OFFSET for the
        body, as the value of OFFSET is tweaked by
        grub_disk_check_range. Change the types of START_SECTOR, LEN and
        POS to grub_disk_addr_t, grub_size_t and grub_size_t,
        respectively.
        (grub_disk_write): Use an unsigned variable REAL_OFFSET for the
        body, as the value of OFFSET is tweaked by
        grub_disk_check_range. Change the types of LEN and N to
        grub_size_t.

        * io/gzio.c (struct grub_gzio): Change the types of "data_offset"
        and "saved_offset" to grub_off_t.
        (test_header): Cast BUF to char *.
        (get_byte): Cast GZIO->DATA_OFFSET to grub_off_t. Cast GZIO->INBUF
        to char *.
        (grub_gzio_read): Change the types of OFFSET and SIZE to
        grub_off_t and grub_size_t, respectively.

        * include/grub/i386/pc/boot.h (GRUB_BOOT_MACHINE_FORCE_LBA):
        Removed.
        (GRUB_BOOT_MACHINE_BOOT_DRIVE): Changed to 0x4c.
        (GRUB_BOOT_MACHINE_KERNEL_ADDRESS): Changed to 0x40.
        (GRUB_BOOT_MACHINE_KERNEL_SEGMENT): Changed to 0x42.
        (GRUB_BOOT_MACHINE_DRIVE_CHECK): Changed to 0x4e.
        (GRUB_BOOT_MACHINE_LIST_SIZE): Increased to 12.

        * include/grub/types.h (grub_off_t): Unconditionally set to
        grub_uint64_t.
        (grub_disk_addr_t): Changed to grub_uint64_t.

        * include/grub/partition.h (struct grub_partition): Change the
        types of "start", "len" and "offset" to grub_disk_addr_t,
        grub_uint64_t and grub_disk_addr_t, respectively.
        (grub_partition_get_start): Return grub_disk_addr_t.
        (grub_partition_get_len): Return grub_uint64_t.

        * include/grub/misc.h (grub_strtoull): New prototype.
        (grub_divmod64): Likewise.

        * include/grub/fshelp.h (grub_fshelp_read_file): Change the types
        of SECTOR, LEN and FILESIZE to grub_disk_addr_t, grub_size_t and
        grub_off_t, respectively.
        All callers and references changed.

        * include/grub/fs.h (struct grub_fs): Change the type of LEN to
        grub_size_t in "read".
        All callers and references changed.

        * include/grub/file.h (struct grub_file): Change the types of
        "offset" and "size" to grub_off_t and grub_off_t,
        respectively. Change the type of SECTOR to grub_disk_addr_t in
        "read_hook".
        (grub_file_read): Change the type of LEN to grub_size_t.
        (grub_file_seek): Return grub_off_t. Change the type of OFFSET to
        grub_off_t.
        (grub_file_size): Return grub_off_t.
        (grub_file_tell): Likewise.
        All callers and references changed.

        * include/grub/disk.h (struct grub_disk_dev): Change the types of
        SECTOR and SIZE to grub_disk_addr_t and grub_size_t in "read" and
        "write".
        (struct grub_disk): Change the type of "total_sectors" to
        grub_uint64_t. Change the type of SECTOR to grub_disk_addr_t in
        "read_hook".
        (grub_disk_read): Change the types of SECTOR, OFFSET and SIZE to
        grub_disk_addr_t, grub_off_t and grub_size_t, respectively.
        (grub_disk_write): Likewise.
        All callers and references changed.

        * fs/iso9660.c (grub_iso9660_susp_iterate): Cast parameters to
        char * for grub_strncmp to silence gcc.
        (grub_iso9660_mount): Likewise.
        (grub_iso9660_mount): Likewise.
        (grub_iso9660_read_symlink): Likewise. Also, remove the nonsense
        return statement.
        (grub_iso9660_iterate_dir): Likewise.
        (grub_iso9660_label): Cast DATA->VOLDESC.VOLNAME to char *.

        * fs/hfs.c (grub_hfs_read_file): Change the types of SECTOR and
        LEN to grub_disk_addr_t and grub_size_t, respectively.

        * fs/hfsplus.c (grub_hfsplus_read_file): Likewise.

        * fs/jfs.c (grub_jfs_read_file): Likewise.

        * fs/minix.c (grub_jfs_read_file): Likewise.

        * fs/sfs.c (grub_jfs_read_file): Likewise.

        * fs/ufs.c (grub_jfs_read_file): Likewise.

        * fs/xfs.c (grub_jfs_read_file): Likewise.

        * fs/fat.c (grub_fat_read_data): Change the types of SECTOR, LEN
        and SIZE to grub_disk_addr_t, grub_size_t and grub_size_t,
        respectively.

        * fs/ext2.c (grub_ext2_read_block): When an error happens, set
        BLKNR to -1 instead of returning GRUB_ERRNO.
        (grub_ext2_read_file): Change the types of SECTOR and
        LEN to grub_disk_addr_t and grub_size_t, respectively.

        * fs/affs.c (grub_affs_read_file): Change the types of SECTOR and
        LEN to grub_disk_addr_t and grub_size_t, respectively.

        * font/manager.c (grub_font_get_glyph): Cast BITMAP to char * for
        grub_file_read.

        * disk/ieee1275/ofdisk.c (grub_ofdisk_read): Fix the format
        string. Do not cast SECTOR explicitly.

        * disk/i386/pc/biosdisk.c (grub_biosdisk_open): Change the type of
        TOTAL_SECTORS to grub_uint64_t. Do not mask DRP->TOTAL_SECTORS.
        (grub_biosdisk_rw): Change the types of SECTOR and SIZE to
        grub_disk_addr_t and grub_size_t, respectively. If the sector is
        over 2TB and LBA mode is not supported, raise an error.
        (get_safe_sectors): New function.
        (grub_biosdisk_read): Use get_safe_sectors.
        (grub_biosdisk_write): Likewise.

        * disk/efi/efidisk.c (grub_efidisk_read): Fix the format string.
        (grub_efidisk_write): Likewise.

        * disk/loopback.c (delete_loopback): Cosmetic changes.
        (grub_cmd_loopback): Likewise. Also, test NEWDEV->FILENAME
        correctly.
        (grub_loopback_open): Likewise.
        (grub_loopback_read): Likewise. Also, change the type of POS to
        grub_off_t, and fix the usage of grub_memset.

        * commands/i386/pc/play.c: Include grub/machine/time.h.

        * commands/ls.c (grub_ls_list_files): Use "llu" instead of "d" to
        print FILE->SIZE.

        * commands/configfile.c: Include grub/env.h.

        * commands/cmp.c (grub_cmd_cmp): Do not use ERR, but use
        GRUB_ERRNO directly instead. Change the type of POS to
        grub_off_t. Follow the coding standard.

        * commands/blocklist.c: Include grub/partition.h.
        (grub_cmd_blocklist): Return an error if the underlying device is
        not a disk. Take the starting sector of a partition into account,
        if a partition is used.

        * boot/i386/pc/diskboot.S (bootloop): Adapted to the new offset of
        a length field.
        (lba_mode): Support 64-bit addresses.
        (chs_mode): Likewise.
        (copy_buffer): Adapted to the new offsets of a length field and a
        segment field.
        (blocklist_default_start): Allocate 64-bit space.

        * boot/i386/pc/boot.S (force_lba): Removed.
        (boot_drive): Moved to under KERNEL_SECTOR.
        (kernel_sector): Moved to under KENREL_SEGMENT. Allocate 64-bit
        space.
        (real_start): Set %si earlier. Remove code for FORCE_LBA, since it
        is useless.
        (lba_mode): Refactored to support a 64-bit address. More size
        optimization.
        (setup_sectors): Likewise.
2006-06-04 15:56:55 +00:00

388 lines
8.7 KiB
ArmAsm

/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2006 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <grub/machine/boot.h>
/*
* defines for the code go here
*/
/* Absolute addresses
This makes the assembler generate the address without support
from the linker. (ELF can't relocate 16-bit addresses!) */
#define ABS(x) (x-_start+GRUB_BOOT_MACHINE_KERNEL_ADDR)
/* Print message string */
#define MSG(x) movw $ABS(x), %si; call message
.file "diskboot.S"
.text
/* Tell GAS to generate 16-bit instructions so that this code works
in real mode. */
.code16
.globl start, _start
start:
_start:
/*
* _start is loaded at 0x2000 and is jumped to with
* CS:IP 0:0x2000 in kernel.
*/
/*
* we continue to use the stack for boot.img and assume that
* some registers are set to correct values. See boot.S
* for more information.
*/
/* save drive reference first thing! */
pushw %dx
/* print a notification message on the screen */
pushw %si
MSG(notification_string)
popw %si
/* this sets up for the first run through "bootloop" */
movw $ABS(firstlist - GRUB_BOOT_MACHINE_LIST_SIZE), %di
/* save the sector number of the second sector in %ebp */
movl (%di), %ebp
/* this is the loop for reading the rest of the kernel in */
bootloop:
/* check the number of sectors to read */
cmpw $0, 8(%di)
/* if zero, go to the start function */
je bootit
setup_sectors:
/* check if we use LBA or CHS */
cmpb $0, -1(%si)
/* jump to chs_mode if zero */
je chs_mode
lba_mode:
/* load logical sector start */
movl (%di), %ebx
movl 4(%di), %ecx
/* the maximum is limited to 0x7f because of Phoenix EDD */
xorl %eax, %eax
movb $0x7f, %al
/* how many do we really want to read? */
cmpw %ax, 8(%di) /* compare against total number of sectors */
/* which is greater? */
jg 1f
/* if less than, set to total */
movw 8(%di), %ax
1:
/* subtract from total */
subw %ax, 8(%di)
/* add into logical sector start */
addl %eax, (%di)
adcl $0, 4(%di)
/* set up disk address packet */
/* the size and the reserved byte */
movw $0x0010, (%si)
/* the number of sectors */
movw %ax, 2(%si)
/* the absolute address */
movl %ebx, 8(%si)
movl %ecx, 12(%si)
/* the segment of buffer address */
movw $GRUB_BOOT_MACHINE_BUFFER_SEG, 6(%si)
/* save %ax from destruction! */
pushw %ax
/* the offset of buffer address */
movw $0, 4(%si)
/*
* BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory
* Call with %ah = 0x42
* %dl = drive number
* %ds:%si = segment:offset of disk address packet
* Return:
* %al = 0x0 on success; err code on failure
*/
movb $0x42, %ah
int $0x13
jc read_error
movw $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx
jmp copy_buffer
chs_mode:
/* load logical sector start (top half) */
movl 4(%di), %eax
orl %eax, %eax
jnz geometry_error
/* load logical sector start (bottom half) */
movl (%di), %eax
/* zero %edx */
xorl %edx, %edx
/* divide by number of sectors */
divl (%si)
/* save sector start */
movb %dl, 10(%si)
xorl %edx, %edx /* zero %edx */
divl 4(%si) /* divide by number of heads */
/* save head start */
movb %dl, 11(%si)
/* save cylinder start */
movw %ax, 12(%si)
/* do we need too many cylinders? */
cmpw 8(%si), %ax
jge geometry_error
/* determine the maximum sector length of this read */
movw (%si), %ax /* get number of sectors per track/head */
/* subtract sector start */
subb 10(%si), %al
/* how many do we really want to read? */
cmpw %ax, 8(%di) /* compare against total number of sectors */
/* which is greater? */
jg 2f
/* if less than, set to total */
movw 8(%di), %ax
2:
/* subtract from total */
subw %ax, 8(%di)
/* add into logical sector start */
addl %eax, (%di)
adcl $0, 4(%di)
/*
* This is the loop for taking care of BIOS geometry translation (ugh!)
*/
/* get high bits of cylinder */
movb 13(%si), %dl
shlb $6, %dl /* shift left by 6 bits */
movb 10(%si), %cl /* get sector */
incb %cl /* normalize sector (sectors go
from 1-N, not 0-(N-1) ) */
orb %dl, %cl /* composite together */
movb 12(%si), %ch /* sector+hcyl in cl, cylinder in ch */
/* restore %dx */
popw %dx
pushw %dx
/* head number */
movb 11(%si), %dh
pushw %ax /* save %ax from destruction! */
/*
* BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
* Call with %ah = 0x2
* %al = number of sectors
* %ch = cylinder
* %cl = sector (bits 6-7 are high bits of "cylinder")
* %dh = head
* %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
* %es:%bx = segment:offset of buffer
* Return:
* %al = 0x0 on success; err code on failure
*/
movw $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx
movw %bx, %es /* load %es segment with disk buffer */
xorw %bx, %bx /* %bx = 0, put it at 0 in the segment */
movb $0x2, %ah /* function 2 */
int $0x13
jc read_error
/* save source segment */
movw %es, %bx
copy_buffer:
/* load addresses for copy from disk buffer to destination */
movw 10(%di), %es /* load destination segment */
/* restore %ax */
popw %ax
/* determine the next possible destination address (presuming
512 byte sectors!) */
shlw $5, %ax /* shift %ax five bits to the left */
addw %ax, 10(%di) /* add the corrected value to the destination
address for next time */
/* save addressing regs */
pusha
pushw %ds
/* get the copy length */
shlw $3, %ax
movw %ax, %cx
xorw %di, %di /* zero offset of destination addresses */
xorw %si, %si /* zero offset of source addresses */
movw %bx, %ds /* restore the source segment */
cld /* sets the copy direction to forward */
/* perform copy */
rep /* sets a repeat */
movsw /* this runs the actual copy */
/* restore addressing regs and print a dot with correct DS
(MSG modifies SI, which is saved, and unused AX and BX) */
popw %ds
MSG(notification_step)
popa
/* check if finished with this dataset */
cmpw $0, 8(%di)
jne setup_sectors
/* update position to load from */
subw $GRUB_BOOT_MACHINE_LIST_SIZE, %di
/* jump to bootloop */
jmp bootloop
/* END OF MAIN LOOP */
bootit:
/* print a newline */
MSG(notification_done)
popw %dx /* this makes sure %dl is our "boot" drive */
ljmp $0, $(GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
/*
* BIOS Geometry translation error (past the end of the disk geometry!).
*/
geometry_error:
MSG(geometry_error_string)
jmp general_error
/*
* Read error on the disk.
*/
read_error:
MSG(read_error_string)
general_error:
MSG(general_error_string)
/* go here when you need to stop the machine hard after an error condition */
stop: jmp stop
notification_string: .string "Loading kernel"
notification_step: .string "."
notification_done: .string "\r\n"
geometry_error_string: .string "Geom"
read_error_string: .string "Read"
general_error_string: .string " Error"
/*
* message: write the string pointed to by %si
*
* WARNING: trashes %si, %ax, and %bx
*/
/*
* Use BIOS "int 10H Function 0Eh" to write character in teletype mode
* %ah = 0xe %al = character
* %bh = page %bl = foreground color (graphics modes)
*/
1:
movw $0x0001, %bx
movb $0xe, %ah
int $0x10 /* display a byte */
incw %si
message:
movb (%si), %al
cmpb $0, %al
jne 1b /* if not end of string, jmp to display */
ret
lastlist:
/*
* This area is an empty space between the main body of code below which
* grows up (fixed after compilation, but between releases it may change
* in size easily), and the lists of sectors to read, which grows down
* from a fixed top location.
*/
.word 0
.word 0
. = _start + 0x200 - GRUB_BOOT_MACHINE_LIST_SIZE
/* fill the first data listing with the default */
blocklist_default_start:
/* this is the sector start parameter, in logical sectors from
the start of the disk, sector 0 */
.long 2, 0
blocklist_default_len:
/* this is the number of sectors to read the command "install"
will fill this up */
.word 0
blocklist_default_seg:
/* this is the segment of the starting address to load the data into */
.word (GRUB_BOOT_MACHINE_KERNEL_SEG + 0x20)
firstlist: /* this label has to be after the list data!!! */