2008-01-31 Bean <bean123ch@gmail.com>

* conf/i386-pc.rmk (pkglib_IMAGES): Add cdboot.img.
        (cdboot_img_SOURCES): New variable.
        (cdboot_img_ASFLAGS): New variable.
        (cdboot_img_LDFLAGS): New variable.

        * boot/i386/pc/cdboot.S: New file.

        * disk/i386/pc/biosdisk.c (cd_start): New variable.
        (cd_count): Likewise.
        (grub_biosdisk_get_drive): Add support for cd device.
        (grub_biosdisk_call_hook): Likewise.
        (grub_biosdisk_iterate): Likewise.
        (grub_biosdisk_open): Likewise.
        (GRUB_BIOSDISK_CDROM_RETRY_COUNT): New macro.
        (grub_biosdisk_rw): Support reading from cd device.
        (GRUB_MOD_INIT): Iterate cd devices.

        * include/grub/i386/pc/biosdisk.h (GRUB_BIOSDISK_FLAG_CDROM): New macro.
        (GRUB_BIOSDISK_MACHINE_CDROM_START): Likewise.
        (GRUB_BIOSDISK_MACHINE_CDROM_END): Likewise.

        * kern/i386/pc/init.c (make_install_device): Check for cd device.
This commit is contained in:
bean 2008-02-03 08:27:15 +00:00
parent 4020aa53c0
commit 9be665dd11
7 changed files with 317 additions and 26 deletions

View File

@ -1,3 +1,28 @@
2008-01-31 Bean <bean123ch@gmail.com>
* conf/i386-pc.rmk (pkglib_IMAGES): Add cdboot.img.
(cdboot_img_SOURCES): New variable.
(cdboot_img_ASFLAGS): New variable.
(cdboot_img_LDFLAGS): New variable.
* boot/i386/pc/cdboot.S: New file.
* disk/i386/pc/biosdisk.c (cd_start): New variable.
(cd_count): Likewise.
(grub_biosdisk_get_drive): Add support for cd device.
(grub_biosdisk_call_hook): Likewise.
(grub_biosdisk_iterate): Likewise.
(grub_biosdisk_open): Likewise.
(GRUB_BIOSDISK_CDROM_RETRY_COUNT): New macro.
(grub_biosdisk_rw): Support reading from cd device.
(GRUB_MOD_INIT): Iterate cd devices.
* include/grub/i386/pc/biosdisk.h (GRUB_BIOSDISK_FLAG_CDROM): New macro.
(GRUB_BIOSDISK_MACHINE_CDROM_START): Likewise.
(GRUB_BIOSDISK_MACHINE_CDROM_END): Likewise.
* kern/i386/pc/init.c (make_install_device): Check for cd device.
2008-02-02 Robert Millan <rmh@aybabtu.com>
* commands/read.c: New file.

171
boot/i386/pc/cdboot.S Normal file
View File

@ -0,0 +1,171 @@
/* -*-Asm-*- */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2008 Free Software Foundation, Inc.
*
* GRUB 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 3 of the License, or
* (at your option) any later version.
*
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/boot.h>
#include <grub/machine/boot.h>
#include <grub/machine/kernel.h>
#include <multiboot.h>
.file "cdboot.S"
#define CODE_ADDR 0x6000
#define DATA_ADDR ((GRUB_BOOT_MACHINE_KERNEL_ADDR) + 0x200)
#define CDSEC_SHIFT 11
#define CDBLK_LENG 16
.text
.code16
.globl start, _start
start:
call next
next:
jmp 1f
. = 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
/* Boot from CDROM. */
xorw %ax, %ax
movw %ax, %ss
movw $(CODE_ADDR), %sp
movw %ax, %ds
movw %ax, %es
movw $(0x7C00 + err_noboot_msg - start), %si
movl %cs: bi_length - next(%bx), %ecx
orl %ecx, %ecx
jz fail
addl $((1 << CDSEC_SHIFT) - 1), %ecx
shrl $CDSEC_SHIFT, %ecx
movl %cs: bi_file - 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 - 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)
addl %edi, 8(%si)
popl %ecx
subl %edi, %ecx
jnz 1b
addw $0x12, %sp
ret
cdrom_fail:
movw $(0x7C00 + err_cdfail_msg - start), %si
fail:
movb $0x0e, %ah
xorw %bx, %bx
1:
lodsb (%si), %al
int $0x10
cmpb $0, %al
jne 1b
1: jmp 1b
err_noboot_msg:
.ascii "no boot info\0"
err_cdfail_msg:
.ascii "cdrom read fails\0"
. = start + 0x1FF
.byte 0

View File

@ -11,7 +11,8 @@ normal/execute.c_DEPENDENCIES = grub_script.tab.h
normal/command.c_DEPENDENCIES = grub_script.tab.h
# Images.
pkglib_IMAGES = boot.img diskboot.img kernel.img pxeboot.img lnxboot.img
pkglib_IMAGES = boot.img diskboot.img kernel.img pxeboot.img lnxboot.img \
cdboot.img
# For boot.img.
boot_img_SOURCES = boot/i386/pc/boot.S
@ -85,6 +86,24 @@ lnxboot_img-boot_i386_pc_lnxboot.o: boot/i386/pc/lnxboot.S $(boot/i386/pc/lnxboo
lnxboot_img_ASFLAGS = $(COMMON_ASFLAGS)
lnxboot_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,6000
# For cdboot.img.
cdboot_img_SOURCES = boot/i386/pc/cdboot.S
CLEANFILES += cdboot.img cdboot.exec cdboot_img-boot_i386_pc_cdboot.o
MOSTLYCLEANFILES += cdboot_img-boot_i386_pc_cdboot.d
cdboot.img: cdboot.exec
$(OBJCOPY) -O binary -R .note -R .comment $< $@
cdboot.exec: cdboot_img-boot_i386_pc_cdboot.o
$(TARGET_CC) -o $@ $^ $(TARGET_LDFLAGS) $(cdboot_img_LDFLAGS)
cdboot_img-boot_i386_pc_cdboot.o: boot/i386/pc/cdboot.S $(boot/i386/pc/cdboot.S_DEPENDENCIES)
$(TARGET_CC) -Iboot/i386/pc -I$(srcdir)/boot/i386/pc $(TARGET_CPPFLAGS) -DASM_FILE=1 $(TARGET_ASFLAGS) $(cdboot_img_ASFLAGS) -MD -c -o $@ $<
-include cdboot_img-boot_i386_pc_cdboot.d
cdboot_img_ASFLAGS = $(COMMON_ASFLAGS)
cdboot_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,7C00
# For kernel.img.
kernel_img_SOURCES = kern/i386/pc/startup.S kern/main.c kern/device.c \
kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \

View File

@ -11,7 +11,8 @@ normal/execute.c_DEPENDENCIES = grub_script.tab.h
normal/command.c_DEPENDENCIES = grub_script.tab.h
# Images.
pkglib_IMAGES = boot.img diskboot.img kernel.img pxeboot.img lnxboot.img
pkglib_IMAGES = boot.img diskboot.img kernel.img pxeboot.img lnxboot.img \
cdboot.img
# For boot.img.
boot_img_SOURCES = boot/i386/pc/boot.S
@ -33,6 +34,11 @@ lnxboot_img_SOURCES = boot/i386/pc/lnxboot.S
lnxboot_img_ASFLAGS = $(COMMON_ASFLAGS)
lnxboot_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,6000
# For cdboot.img.
cdboot_img_SOURCES = boot/i386/pc/cdboot.S
cdboot_img_ASFLAGS = $(COMMON_ASFLAGS)
cdboot_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,7C00
# For kernel.img.
kernel_img_SOURCES = kern/i386/pc/startup.S kern/main.c kern/device.c \
kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \

View File

@ -26,12 +26,15 @@
#include <grub/err.h>
#include <grub/term.h>
static int cd_start = GRUB_BIOSDISK_MACHINE_CDROM_START;
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,17 +154,20 @@ 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;
@ -164,6 +185,8 @@ grub_biosdisk_close (grub_disk_t disk)
#define GRUB_BIOSDISK_READ 0
#define GRUB_BIOSDISK_WRITE 1
#define GRUB_BIOSDISK_CDROM_RETRY_COUNT 3
static grub_err_t
grub_biosdisk_rw (int cmd, grub_disk_t disk,
grub_disk_addr_t sector, grub_size_t size,
@ -184,13 +207,31 @@ 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)
{
int i;
if (cmd)
return grub_error (GRUB_ERR_WRITE_ERROR, "can\'t write to cdrom");
dap->blocks = (dap->blocks + 3) >> 2;
dap->block >>= 2;
for (i = 0; i < GRUB_BIOSDISK_CDROM_RETRY_COUNT; i++)
if (! grub_biosdisk_rw_int13_extensions (0x42, data->drive, dap))
break;
if (i == GRUB_BIOSDISK_CDROM_RETRY_COUNT)
return grub_error (GRUB_ERR_READ_ERROR, "cdrom read error");
}
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 +364,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 +374,24 @@ GRUB_MOD_INIT(biosdisk)
grub_disk_firmware_fini = grub_disk_biosdisk_fini;
grub_disk_dev_register (&grub_biosdisk_dev);
for (drive = GRUB_BIOSDISK_MACHINE_CDROM_START;
drive < GRUB_BIOSDISK_MACHINE_CDROM_END; 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)

View File

@ -23,6 +23,10 @@
#include <grub/types.h>
#define GRUB_BIOSDISK_FLAG_LBA 1
#define GRUB_BIOSDISK_FLAG_CDROM 2
#define GRUB_BIOSDISK_MACHINE_CDROM_START 0xe0
#define GRUB_BIOSDISK_MACHINE_CDROM_END 0xf0
struct grub_biosdisk_data
{

View File

@ -22,6 +22,7 @@
#include <grub/machine/memory.h>
#include <grub/machine/console.h>
#include <grub/machine/kernel.h>
#include <grub/machine/biosdisk.h>
#include <grub/types.h>
#include <grub/err.h>
#include <grub/dl.h>
@ -71,9 +72,13 @@ 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 >= GRUB_BIOSDISK_MACHINE_CDROM_START)
grub_sprintf (dev, "(cd%u",
grub_boot_drive - GRUB_BIOSDISK_MACHINE_CDROM_START);
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);