This new patch merge the cdboot function into lnxboot, now you can use g2ldr as eltorito boot file !
mkdir cdroot cat lnxboot.img core.img > cdroot/g2ldr mkisofs -R -no-emul-boot -boot-info-table --boot-load-size 4 -b g2ldr -o aa.iso cdroot diff --git a/boot/i386/pc/lnxboot.S b/boot/i386/pc/lnxboot.S index 6a4de8d..5af9b6b 100644 --- a/boot/i386/pc/lnxboot.S +++ b/boot/i386/pc/lnxboot.S @@ -30,6 +30,9 @@ #define BLCK_LENG 0x4000 +#define CDSEC_SHIFT 11 +#define CDBLK_LENG 16 + .text .code16 @@ -38,7 +41,116 @@ data_start: xorl %ebp, %ebp - jmp linux_next + call data_next + +data_next: + jmp 1f + . = data_start + 8 + +bi_pvd: + .long 0 /* LBA of primary volume descript. */ +bi_file: + .long 0 /* LBA of boot file. */ +bi_length: + .long 0 /* Length of boot file. */ +bi_csum: + .long 0 /* Checksum of boot file */ +bi_reserved: + .space (10*4) /* Reserved */ + +1: + popw %bx + movl %cs: bi_length - data_next(%bx), %ecx + orl %ecx, %ecx + jz linux_next + + /* Boot from CDROM. */ + + xorw %ax, %ax + movw %ax, %ss + movw $(CODE_ADDR), %sp + movw %ax, %ds + movw %ax, %es + + addl $((1 << CDSEC_SHIFT) - 1), %ecx + shrl $CDSEC_SHIFT, %ecx + + movl %cs: bi_file - data_next(%bx), %esi + + call read_cdrom + + ljmp $(DATA_ADDR >> 4), $0 + + +/* + * Parameters: + * esi: start sector + * ecx: number of sectors + */ +read_cdrom: + xorl %eax, %eax + + /* Number of blocks to read. */ + pushw $CDBLK_LENG + + /* Block number. */ + pushl %eax + pushl %esi + + /* Buffer address. */ + pushw $((DATA_ADDR - CODE_LENG - 0x400)>> 4) + pushl %eax + pushw $0x10 + + xorl %edi, %edi + movw %sp, %si + +1: + movw 0x10(%si), %di + cmpl %ecx, %edi + jbe 2f + movl %ecx, %edi + +2: + mov %di, 2(%si) + + pushl %ecx + + movb $0x42, %ah + int $0x13 + + jnc 3f + + movb $0x42, %ah /* Try again. */ + int $0x13 + + jnc 3f + +2: + shrw $1, %di /* Reduce transfer size. */ + jz cdrom_fail + movw %di, 0x10(%si) + movw %di, 2(%si) + movb $0x42, %ah + int $0x13 + jc 2b + +3: + + movw %di, %ax + shlw $(CDSEC_SHIFT - 4), %ax + addw %ax, 6(%si) + + popl %ecx + subl %edi, %ecx + jnz 1b + + addw $0x12, %sp + ret + +cdrom_fail: + movw $(0x7C00 + err_cdfail_msg - data_start), %si + jmp fail . = data_start + 0x1F1 @@ -142,8 +254,7 @@ normalize: real_code: subw $0x20, %ax movw %ax, %ds - movw (setup_sects - data_start), %cx - shlw $7, %cx + movw $((CODE_LENG) >> 2), %cx /* Setup stack. */ @@ -286,6 +397,9 @@ fail: err_int15_msg: .ascii "move memory fails\0" +err_cdfail_msg: + .ascii "cdrom read fails\0" + . = (. & (~0x1FF)) + 0x1FF .byte 0 diff --git a/disk/i386/pc/biosdisk.c b/disk/i386/pc/biosdisk.c index eb22e6d..e846e37 100644 --- a/disk/i386/pc/biosdisk.c +++ b/disk/i386/pc/biosdisk.c @@ -26,12 +26,15 @@ #include <grub/err.h> #include <grub/term.h> +static int cd_start = 0xe0; +static int cd_count = 0; + static int grub_biosdisk_get_drive (const char *name) { unsigned long drive; - if ((name[0] != 'f' && name[0] != 'h') || name[1] != 'd') + if ((name[0] != 'f' && name[0] != 'h' && name[0] != 'c') || name[1] != 'd') goto fail; drive = grub_strtoul (name + 2, 0, 10); @@ -40,6 +43,8 @@ grub_biosdisk_get_drive (const char *name) if (name[0] == 'h') drive += 0x80; + else if (name[0] == 'c') + drive += cd_start; return (int) drive ; @@ -53,7 +58,10 @@ grub_biosdisk_call_hook (int (*hook) (const char *name), int drive) { char name[10]; - grub_sprintf (name, (drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80)); + if (drive >= cd_start) + grub_sprintf (name, "cd%d", drive - cd_start); + else + grub_sprintf (name, (drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80)); return hook (name); } @@ -82,7 +90,11 @@ grub_biosdisk_iterate (int (*hook) (const char *name)) if (grub_biosdisk_call_hook (hook, drive)) return 1; } - + + for (drive = cd_start; drive < cd_start + cd_count; drive++) + if (grub_biosdisk_call_hook (hook, drive)) + return 1; + return 0; } @@ -97,7 +109,7 @@ grub_biosdisk_open (const char *name, grub_disk_t disk) if (drive < 0) return grub_errno; - disk->has_partitions = (drive & 0x80); + disk->has_partitions = ((drive & 0x80) && (drive < cd_start)); disk->id = drive; data = (struct grub_biosdisk_data *) grub_malloc (sizeof (*data)); @@ -106,8 +118,14 @@ grub_biosdisk_open (const char *name, grub_disk_t disk) data->drive = drive; data->flags = 0; - - if (drive & 0x80) + + if (drive >= cd_start) + { + data->flags = GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM; + data->sectors = 32; + total_sectors = 9000000; /* TODO: get the correct size. */ + } + else if (drive & 0x80) { /* HDD */ int version; @@ -136,18 +154,21 @@ grub_biosdisk_open (const char *name, grub_disk_t disk) } } - if (grub_biosdisk_get_diskinfo_standard (drive, - &data->cylinders, - &data->heads, - &data->sectors) != 0) + if (drive < cd_start) { - grub_free (data); - return grub_error (GRUB_ERR_BAD_DEVICE, "cannot get C/H/S values"); + if (grub_biosdisk_get_diskinfo_standard (drive, + &data->cylinders, + &data->heads, + &data->sectors) != 0) + { + grub_free (data); + return grub_error (GRUB_ERR_BAD_DEVICE, "cannot get C/H/S values"); + } + + if (! total_sectors) + total_sectors = data->cylinders * data->heads * data->sectors; } - if (! total_sectors) - total_sectors = data->cylinders * data->heads * data->sectors; - disk->total_sectors = total_sectors; disk->data = data; @@ -184,13 +205,22 @@ grub_biosdisk_rw (int cmd, grub_disk_t disk, dap->buffer = segment << 16; /* The format SEGMENT:ADDRESS. */ dap->block = sector; - if (grub_biosdisk_rw_int13_extensions (cmd + 0x42, data->drive, dap)) - { - /* Fall back to the CHS mode. */ - data->flags &= ~GRUB_BIOSDISK_FLAG_LBA; - disk->total_sectors = data->cylinders * data->heads * data->sectors; - return grub_biosdisk_rw (cmd, disk, sector, size, segment); + if (data->flags & GRUB_BIOSDISK_FLAG_CDROM) + { + dap->blocks >>= 2; + dap->block >>= 2; + + if (grub_biosdisk_rw_int13_extensions (cmd + 0x42, data->drive, dap)) + return grub_errno; } + else + if (grub_biosdisk_rw_int13_extensions (cmd + 0x42, data->drive, dap)) + { + /* Fall back to the CHS mode. */ + data->flags &= ~GRUB_BIOSDISK_FLAG_LBA; + disk->total_sectors = data->cylinders * data->heads * data->sectors; + return grub_biosdisk_rw (cmd, disk, sector, size, segment); + } } else { @@ -323,6 +353,8 @@ grub_disk_biosdisk_fini (void) GRUB_MOD_INIT(biosdisk) { + int drive, found = 0; + if (grub_disk_firmware_is_tainted) { grub_printf ("Firmware is marked as tainted, refusing to initialize.\n"); @@ -331,6 +363,23 @@ GRUB_MOD_INIT(biosdisk) grub_disk_firmware_fini = grub_disk_biosdisk_fini; grub_disk_dev_register (&grub_biosdisk_dev); + + for (drive = 0xe0; drive < 0xff; drive++) + { + if (grub_biosdisk_check_int13_extensions (drive)) + { + if (! found) + cd_start = drive; + found++; + } + else + { + if (found) + break; + } + } + + cd_count = found; } GRUB_MOD_FINI(biosdisk) diff --git a/include/grub/i386/pc/biosdisk.h b/include/grub/i386/pc/biosdisk.h index 3591c2b..8319135 100644 --- a/include/grub/i386/pc/biosdisk.h +++ b/include/grub/i386/pc/biosdisk.h @@ -23,6 +23,7 @@ #include <grub/types.h> #define GRUB_BIOSDISK_FLAG_LBA 1 +#define GRUB_BIOSDISK_FLAG_CDROM 2 struct grub_biosdisk_data { diff --git a/kern/i386/pc/init.c b/kern/i386/pc/init.c index acaf20b..1a4e9df 100644 --- a/kern/i386/pc/init.c +++ b/kern/i386/pc/init.c @@ -71,9 +71,12 @@ make_install_device (void) } else if (grub_install_dos_part != -2) { - grub_sprintf (dev, "(%cd%u", - (grub_boot_drive & 0x80) ? 'h' : 'f', - grub_boot_drive & 0x7f); + if (grub_boot_drive >= 0xe0) + grub_sprintf (dev, "(cd%u", grub_boot_drive - 0xe0); + else + grub_sprintf (dev, "(%cd%u", + (grub_boot_drive & 0x80) ? 'h' : 'f', + grub_boot_drive & 0x7f); if (grub_install_dos_part >= 0) grub_sprintf (dev + grub_strlen (dev), ",%u", grub_install_dos_part + 1); -- Bean _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel