* [PATCH] eltorito cdrom boot
@ 2008-01-29 19:22 Bean
2008-01-29 20:33 ` Robert Millan
2008-01-29 20:58 ` Marco Gerards
0 siblings, 2 replies; 15+ messages in thread
From: Bean @ 2008-01-29 19:22 UTC (permalink / raw)
To: The development of GRUB 2
Hi,
This patch enable grub2 to read files from cdrom using int13 service.
To create bootable cdrom:
mkdir cdroot
cat cdboot.img core.img > cdroot/grub2cd.bin
mkisofs -R -no-emul-boot -boot-info-table --boot-load-size 4 -b
grub2cd.bin -o aa.iso cdroot
diff --git a/boot/i386/pc/cdboot.S b/boot/i386/pc/cdboot.S
new file mode 100755
index 0000000..d020651
--- /dev/null
+++ b/boot/i386/pc/cdboot.S
@@ -0,0 +1,292 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1994-2002 H. Peter Anvin
+ * Copyright (C) 1999,2000,2001,2004 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.
+ *
+ */
+
+/*
+ Most of this file was originally "isolinux.asm" from SYSLINUX package.
+ It has been very heavily modified.
+*/
+
+ /* 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+0x7C00)
+
+#define SECTOR_SIZE 0x200
+
+#define ISO_SECTOR_SIZE 0x800
+#define ISO_SECTOR_BITS 11
+
+#define STAGE_ADDR (0x8000 - SECTOR_SIZE)
+
+#define STAGE1_STACKSEG 0x2000
+
+ /* Print message string */
+#define MSG(x) mov $ABS(x), %si; call message;
+
+ .file "cdboot.S"
+
+ .text
+
+ /* Tell GAS to generate 16-bit instructions so that this code works
+ in real mode. */
+ .code16
+
+ .globl start, _start
+
+/*
+ * Primary entry point. Because BIOSes are buggy, we only load the first
+ * CD-ROM sector (2K) of the file, so the number one priority is actually
+ * loading the rest.
+ */
+start:
+_start:
+ cli
+ ljmp $0, $ABS(real_start)
+
+ . = _start + 8 /* Pad to file offset 8 */
+
+ /* This table gets filled in by mkisofs using the
+ -boot-info-table option */
+bi_pvd: .long 0xDEADBEEF /* LBA of primary volume descript */
+bi_file: .long 0xDEADBEEF /* LBA of boot file */
+bi_length: .long 0xDEADBEEF /* Length of boot file */
+bi_csum: .long 0xDEADBEEF /* Checksum of boot file */
+bi_reserved: .space (10*4) /* Reserved */
+
+real_start:
+ xor %ax, %ax
+ mov %ax, %ss
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+ mov $STAGE1_STACKSEG, %sp /* set up the REAL stack */
+ sti
+ cld
+
+ /* save drive reference first thing! */
+ mov %dl, ABS(BootDrive)
+
+ /* print a notification message on the screen */
+ MSG(notification_string)
+
+load_image:
+ /* Set up boot file sector, size, load address */
+ mov ABS(bi_length), %eax
+ add $(ISO_SECTOR_SIZE-1), %eax
+ shr $ISO_SECTOR_BITS, %eax /* dwords->sectors */
+ mov %ax, %bp /* boot file sectors */
+ mov $(STAGE_ADDR >> 4), %bx
+ mov %bx, %es
+ xor %bx, %bx
+ mov ABS(bi_file), %eax
+ call getlinsec
+ mov %ds, %ax
+ mov %ax, %es
+
+ MSG(notification_done)
+bootit:
+ mov ABS(BootDrive), %dl /* this makes sure %dl is our "boot" drive */
+ ljmp $0, $(STAGE_ADDR + SECTOR_SIZE * 2) /* jump to main() in asm.S */
+
+/* go here when you need to stop the machine hard after an error condition */
+stop: jmp stop
+
+
+/*
+ * Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
+ *
+ * Note that we can't always do this as a single request, because at least
+ * Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick
+ * to 16 sectors (32K) per request.
+ *
+ * Input:
+ * EAX - Linear sector number
+ * ES:BX - Target buffer
+ * BP - Sector count
+ */
+getlinsec:
+ mov $ABS(dapa), %si /* Load up the DAPA */
+ mov %bx, 4(%si)
+ mov %es, %bx
+ mov %bx, 6(%si)
+ mov %eax, 8(%si)
+1:
+ push %bp
+ push %si
+ cmp ABS(MaxTransfer), %bp
+ jbe 2f
+ mov ABS(MaxTransfer), %bp
+2:
+ mov %bp, 2(%si)
+ mov ABS(BootDrive), %dl
+ mov $0x42, %ah /* Extended Read */
+ call xint13
+ pop %si
+ pop %bp
+ movzwl 2(%si), %eax /* Sectors we read */
+ add %eax, 8(%si) /* Advance sector pointer */
+ sub %ax, %bp /* Sectors left */
+ shl $(ISO_SECTOR_BITS-4), %ax /* 2048-byte sectors -> segment */
+ add %ax, 6(%si) /* Advance buffer pointer */
+
+ pushal
+ MSG(notification_step)
+ popal
+ cmp $0, %bp
+ ja 1b
+ mov 8(%si), %eax /* Return next sector */
+ ret
+
+/*
+ * INT 13h with retry
+ */
+xint13:
+ movb $6, ABS(RetryCount)
+ pushal
+.try:
+ int $0x13
+ jc 1f
+ add $(8*4), %sp /* Clean up stack */
+ ret
+1:
+ mov %ah, %dl /* Save error code */
+ decb ABS(RetryCount)
+ jz .real_error
+ mov ABS(RetryCount), %al
+ mov ABS(dapa+2), %ah /* Sector transfer count */
+ cmp $2, %al /* Only 2 attempts left */
+ ja 2f
+ mov $1, %ah /* Drop transfer size to 1 */
+ jmp .setmaxtr
+2:
+ cmp $3, %al
+ ja 3f /* First time, just try again */
+ shr $1, %ah /* Otherwise, try to reduce */
+ adc $0, %ah /* the max transfer size, but not */
+.setmaxtr:
+ mov %ah, ABS(MaxTransfer)
+ mov %ah, ABS(dapa+2)
+3:
+ popal
+ jmp .try
+
+.real_error:
+ MSG(read_error_string)
+ mov %dl, %al
+ call printhex2
+ popal
+ jmp stop
+
+
+
+/*
+ * 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:
+ mov $0x0001, %bx
+ mov $0x0E, %ah
+ int $0x10 /* display a byte */
+
+message:
+ lodsb
+ or %al, %al
+ jne 1b /* if not end of string, jmp to display */
+ ret
+
+/*
+ * printhex[248]: Write a hex number in (AL, AX, EAX) to the console
+ */
+printhex2:
+ pushal
+ rol $24, %eax
+ mov $2, %cx
+ jmp 1f
+printhex4:
+ pushal
+ rol $16, %eax
+ mov $4, %cx
+ jmp 1f
+printhex8:
+ pushal
+ mov $8, %cx
+1:
+ rol $4, %eax
+ push %eax
+ and $0x0F, %al
+ cmp $10, %al
+ jae .high
+.low: add $('0'), %al
+ jmp 2f
+.high: add $('A'-10), %al
+2:
+ mov $0x0001, %bx
+ mov $0x0E, %ah
+ int $0x10 /* display a char */
+ pop %eax
+ loop 1b
+ popal
+ ret
+
+/**************************************************************************/
+#ifdef STAGE1_5
+notification_string: .string "Loading stage1.5 "
+#else
+notification_string: .string "Loading stage2 "
+#endif
+
+notification_step: .string "."
+notification_done: .string "\r\n"
+
+read_error_string: .string "Read error 0x"
+
+/*
+ * EBIOS disk address packet
+ */
+ .align 8
+dapa: .byte 16 /* Packet size */
+ .byte 0 /* reserved */
+ .word 0 /* +2 Block count */
+ .word 0 /* +4 Offset of buffer */
+ .word 0 /* +6 Segment of buffer */
+ .long 0 /* +8 LBA (LSW) */
+ .long 0 /* +C LBA (MSW) */
+
+BootDrive:
+ .byte 0xFF
+MaxTransfer:
+ .word 16 /* Max sectors per transfer (32Kb) */
+RetryCount:
+ .byte 0
+
+
+ . = _start + SECTOR_SIZE - 2
+
+ .word 0
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index 5902608..ad337cb 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -7,7 +7,8 @@ COMMON_CFLAGS = -fno-builtin -mrtd -mregparm=3 -m32
COMMON_LDFLAGS = -m32 -nostdlib
# 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
@@ -29,6 +30,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 \
diff --git a/disk/i386/pc/biosdisk.c b/disk/i386/pc/biosdisk.c
index eb22e6d..01a67c4 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 ;
@@ -52,8 +57,11 @@ static int
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
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH] eltorito cdrom boot
2008-01-29 19:22 [PATCH] eltorito cdrom boot Bean
@ 2008-01-29 20:33 ` Robert Millan
2008-01-29 20:58 ` Marco Gerards
1 sibling, 0 replies; 15+ messages in thread
From: Robert Millan @ 2008-01-29 20:33 UTC (permalink / raw)
To: The development of GRUB 2
On Wed, Jan 30, 2008 at 03:22:58AM +0800, Bean wrote:
> Hi,
>
> This patch enable grub2 to read files from cdrom using int13 service.
>
> [...]
> + * Copyright (C) 1994-2002 H. Peter Anvin
> [...]
> +
> +/*
> + Most of this file was originally "isolinux.asm" from SYSLINUX package.
> + It has been very heavily modified.
This was, unfortunately, the part of Alex's work that we couldn't merge due
to legal problems.
I think the rest is fine (legal-wise) and only has technical issues.
--
Robert Millan
<GPLv2> I know my rights; I want my phone call!
<DRM> What use is a phone call… if you are unable to speak?
(as seen on /.)
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] eltorito cdrom boot
2008-01-29 19:22 [PATCH] eltorito cdrom boot Bean
2008-01-29 20:33 ` Robert Millan
@ 2008-01-29 20:58 ` Marco Gerards
2008-01-30 15:13 ` Bean
1 sibling, 1 reply; 15+ messages in thread
From: Marco Gerards @ 2008-01-29 20:58 UTC (permalink / raw)
To: The development of GRUB 2
Bean <bean123ch@gmail.com> writes:
Hi Bean!
> This patch enable grub2 to read files from cdrom using int13 service.
Wow, you are active! :-)
> To create bootable cdrom:
>
> mkdir cdroot
> cat cdboot.img core.img > cdroot/grub2cd.bin
> mkisofs -R -no-emul-boot -boot-info-table --boot-load-size 4 -b
> grub2cd.bin -o aa.iso cdroot
>
>
> diff --git a/boot/i386/pc/cdboot.S b/boot/i386/pc/cdboot.S
> new file mode 100755
> index 0000000..d020651
> --- /dev/null
> +++ b/boot/i386/pc/cdboot.S
> @@ -0,0 +1,292 @@
> +/*
> + * GRUB -- GRand Unified Bootloader
> + * Copyright (C) 1994-2002 H. Peter Anvin
> + * Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc.
Please be careful with patches that include code from other sources.
If you do so, please mention it explicitly.
You know that very often, it cannot just be merged... :-/
--
Marco
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] eltorito cdrom boot
2008-01-29 20:58 ` Marco Gerards
@ 2008-01-30 15:13 ` Bean
2008-01-31 8:38 ` Bean
0 siblings, 1 reply; 15+ messages in thread
From: Bean @ 2008-01-30 15:13 UTC (permalink / raw)
To: The development of GRUB 2
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
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH] eltorito cdrom boot
2008-01-30 15:13 ` Bean
@ 2008-01-31 8:38 ` Bean
2008-01-31 11:09 ` Robert Millan
0 siblings, 1 reply; 15+ messages in thread
From: Bean @ 2008-01-31 8:38 UTC (permalink / raw)
To: The development of GRUB 2
Changes in this new version:
Fix a bug in lnxboot.
Use macro for magic values.
Try 3 times when reading from cdrom.
2008-01-31 Bean <bean123ch@gmail.com>
* boot/i396/pc/lnxboot.S (data_start): Add cdrom boot support.
* 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.
diff --git a/boot/i386/pc/lnxboot.S b/boot/i386/pc/lnxboot.S
index 6a4de8d..99f896f 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,122 @@
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
+
+ cmpb $0xe0, %dl
+ jb linux_next
+
+ 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)
+ addl %edi, 8(%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 +260,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 +403,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..9c0ecc5 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 = 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,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;
@@ -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)
diff --git a/include/grub/i386/pc/biosdisk.h b/include/grub/i386/pc/biosdisk.h
index 3591c2b..2b67cbf 100644
--- a/include/grub/i386/pc/biosdisk.h
+++ b/include/grub/i386/pc/biosdisk.h
@@ -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
{
diff --git a/kern/i386/pc/init.c b/kern/i386/pc/init.c
index acaf20b..908e2d7 100644
--- a/kern/i386/pc/init.c
+++ b/kern/i386/pc/init.c
@@ -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);
--
Bean
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH] eltorito cdrom boot
2008-01-31 8:38 ` Bean
@ 2008-01-31 11:09 ` Robert Millan
2008-01-31 11:36 ` Yoshinori K. Okuji
2008-01-31 12:47 ` Robert Millan
0 siblings, 2 replies; 15+ messages in thread
From: Robert Millan @ 2008-01-31 11:09 UTC (permalink / raw)
To: The development of GRUB 2
On Thu, Jan 31, 2008 at 04:38:15PM +0800, Bean wrote:
> Changes in this new version:
>
> Fix a bug in lnxboot.
> Use macro for magic values.
> Try 3 times when reading from cdrom.
>
> 2008-01-31 Bean <bean123ch@gmail.com>
>
> * boot/i396/pc/lnxboot.S (data_start): Add cdrom boot support.
Typo (i396).
Do we really want to mix linux boot with eltorito boot? Is much core from
original lnxboot reused by eltorito boot?
--
Robert Millan
<GPLv2> I know my rights; I want my phone call!
<DRM> What use is a phone call… if you are unable to speak?
(as seen on /.)
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] eltorito cdrom boot
2008-01-31 11:09 ` Robert Millan
@ 2008-01-31 11:36 ` Yoshinori K. Okuji
2008-01-31 12:43 ` Bean
2008-01-31 12:47 ` Robert Millan
1 sibling, 1 reply; 15+ messages in thread
From: Yoshinori K. Okuji @ 2008-01-31 11:36 UTC (permalink / raw)
To: The development of GRUB 2
On Thursday 31 January 2008 12:09, Robert Millan wrote:
> On Thu, Jan 31, 2008 at 04:38:15PM +0800, Bean wrote:
> > Changes in this new version:
> >
> > Fix a bug in lnxboot.
> > Use macro for magic values.
> > Try 3 times when reading from cdrom.
> >
> > 2008-01-31 Bean <bean123ch@gmail.com>
> >
> > * boot/i396/pc/lnxboot.S (data_start): Add cdrom boot support.
>
> Typo (i396).
>
> Do we really want to mix linux boot with eltorito boot? Is much core from
> original lnxboot reused by eltorito boot?
That should be separate. Look at stage2/start_eltorito.S in GRUB Legacy. It is
very small.
Okuji
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] eltorito cdrom boot
2008-01-31 11:36 ` Yoshinori K. Okuji
@ 2008-01-31 12:43 ` Bean
2008-02-02 14:19 ` Bean
0 siblings, 1 reply; 15+ messages in thread
From: Bean @ 2008-01-31 12:43 UTC (permalink / raw)
To: The development of GRUB 2
Hi,
ok, this is the new patch, the cdboot function is implemented in
separate file cdboot.S. To create a eltorito boot file, use:
cat cdboot.img core.img > grub2cd.bin
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.
diff --git a/boot/i386/pc/cdboot.S b/boot/i386/pc/cdboot.S
new file mode 100644
index 0000000..430496f
--- /dev/null
+++ b/boot/i386/pc/cdboot.S
@@ -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
+
+data_start:
+ 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
+
+ /* Boot from CDROM. */
+
+ xorw %ax, %ax
+ movw %ax, %ss
+ movw $(CODE_ADDR), %sp
+ movw %ax, %ds
+ movw %ax, %es
+
+ movw $(0x7C00 + err_noboot_msg - data_start), %si
+ movl %cs: bi_length - data_next(%bx), %ecx
+ orl %ecx, %ecx
+ jz fail
+
+ 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 - 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 - data_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"
+
+ . = data_start + 0x1FF
+
+ .byte 0
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index fb435bc..2e4005d 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -7,7 +7,8 @@ COMMON_CFLAGS = -fno-builtin -mrtd -mregparm=3 -m32
COMMON_LDFLAGS = -m32 -nostdlib
# 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
@@ -29,6 +30,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 \
diff --git a/disk/i386/pc/biosdisk.c b/disk/i386/pc/biosdisk.c
index eb22e6d..ddcc666 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 = 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,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;
@@ -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)
diff --git a/include/grub/i386/pc/biosdisk.h b/include/grub/i386/pc/biosdisk.h
index 3591c2b..2b67cbf 100644
--- a/include/grub/i386/pc/biosdisk.h
+++ b/include/grub/i386/pc/biosdisk.h
@@ -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
{
diff --git a/kern/i386/pc/init.c b/kern/i386/pc/init.c
index acaf20b..908e2d7 100644
--- a/kern/i386/pc/init.c
+++ b/kern/i386/pc/init.c
@@ -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);
--
Bean
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH] eltorito cdrom boot
2008-01-31 11:09 ` Robert Millan
2008-01-31 11:36 ` Yoshinori K. Okuji
@ 2008-01-31 12:47 ` Robert Millan
2008-01-31 13:04 ` Bean
1 sibling, 1 reply; 15+ messages in thread
From: Robert Millan @ 2008-01-31 12:47 UTC (permalink / raw)
To: The development of GRUB 2
On Thu, Jan 31, 2008 at 12:09:06PM +0100, Robert Millan wrote:
>
> Typo (i396).
>
> Do we really want to mix linux boot with eltorito boot? Is much core from
> original lnxboot reused by eltorito boot?
I meant `code' of course.
--
Robert Millan
<GPLv2> I know my rights; I want my phone call!
<DRM> What use is a phone call… if you are unable to speak?
(as seen on /.)
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] eltorito cdrom boot
2008-01-31 12:47 ` Robert Millan
@ 2008-01-31 13:04 ` Bean
0 siblings, 0 replies; 15+ messages in thread
From: Bean @ 2008-01-31 13:04 UTC (permalink / raw)
To: The development of GRUB 2
On Jan 31, 2008 8:47 PM, Robert Millan <rmh@aybabtu.com> wrote:
> On Thu, Jan 31, 2008 at 12:09:06PM +0100, Robert Millan wrote:
> >
> > Typo (i396).
> >
> > Do we really want to mix linux boot with eltorito boot? Is much core from
> > original lnxboot reused by eltorito boot?
>
> I meant `code' of course.
the error report routine is shared, other code is separate.
--
Bean
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] eltorito cdrom boot
2008-01-31 12:43 ` Bean
@ 2008-02-02 14:19 ` Bean
2008-02-02 16:33 ` Robert Millan
0 siblings, 1 reply; 15+ messages in thread
From: Bean @ 2008-02-02 14:19 UTC (permalink / raw)
To: The development of GRUB 2
On Jan 31, 2008 8:43 PM, Bean <bean123ch@gmail.com> wrote:
> 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.
>
any objection for this patch ? i would like to commit it soon.
--
Bean
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] eltorito cdrom boot
2008-02-02 14:19 ` Bean
@ 2008-02-02 16:33 ` Robert Millan
2008-02-02 17:16 ` Bean
0 siblings, 1 reply; 15+ messages in thread
From: Robert Millan @ 2008-02-02 16:33 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, Feb 02, 2008 at 10:19:55PM +0800, Bean wrote:
>
> any objection for this patch ? i would like to commit it soon.
Looks fine to me. Just a minor comment:
> +#define GRUB_BIOSDISK_MACHINE_CDROM_START 0xe0
> +#define GRUB_BIOSDISK_MACHINE_CDROM_END 0xf0
could you make this tab-indented?
Also, I notice that GRUB_BIOSDISK_MACHINE_CDROM_END is not used. Did you plan
to add a sanity check in init.c using this macro ?
--
Robert Millan
<GPLv2> I know my rights; I want my phone call!
<DRM> What use is a phone call… if you are unable to speak?
(as seen on /.)
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] eltorito cdrom boot
2008-02-02 16:33 ` Robert Millan
@ 2008-02-02 17:16 ` Bean
2008-02-02 17:24 ` Robert Millan
0 siblings, 1 reply; 15+ messages in thread
From: Bean @ 2008-02-02 17:16 UTC (permalink / raw)
To: The development of GRUB 2
On Feb 3, 2008 12:33 AM, Robert Millan <rmh@aybabtu.com> wrote:
> On Sat, Feb 02, 2008 at 10:19:55PM +0800, Bean wrote:
> >
> > any objection for this patch ? i would like to commit it soon.
>
> Looks fine to me. Just a minor comment:
>
> > +#define GRUB_BIOSDISK_MACHINE_CDROM_START 0xe0
> > +#define GRUB_BIOSDISK_MACHINE_CDROM_END 0xf0
>
> could you make this tab-indented?
no problem.
>
> Also, I notice that GRUB_BIOSDISK_MACHINE_CDROM_END is not used. Did you plan
> to add a sanity check in init.c using this macro ?
it's used in GRUB_MOD_INIT(biosdisk) as the end drive letter to scan for cds.
--
Bean
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] eltorito cdrom boot
2008-02-02 17:16 ` Bean
@ 2008-02-02 17:24 ` Robert Millan
2008-02-03 8:27 ` Bean
0 siblings, 1 reply; 15+ messages in thread
From: Robert Millan @ 2008-02-02 17:24 UTC (permalink / raw)
To: The development of GRUB 2
On Sun, Feb 03, 2008 at 01:16:50AM +0800, Bean wrote:
> On Feb 3, 2008 12:33 AM, Robert Millan <rmh@aybabtu.com> wrote:
> > On Sat, Feb 02, 2008 at 10:19:55PM +0800, Bean wrote:
> > >
> > > any objection for this patch ? i would like to commit it soon.
> >
> > Looks fine to me. Just a minor comment:
> >
> > > +#define GRUB_BIOSDISK_MACHINE_CDROM_START 0xe0
> > > +#define GRUB_BIOSDISK_MACHINE_CDROM_END 0xf0
> >
> > could you make this tab-indented?
>
> no problem.
>
> >
> > Also, I notice that GRUB_BIOSDISK_MACHINE_CDROM_END is not used. Did you plan
> > to add a sanity check in init.c using this macro ?
>
> it's used in GRUB_MOD_INIT(biosdisk) as the end drive letter to scan for cds.
Ah, sorry I got confused.
--
Robert Millan
<GPLv2> I know my rights; I want my phone call!
<DRM> What use is a phone call… if you are unable to speak?
(as seen on /.)
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] eltorito cdrom boot
2008-02-02 17:24 ` Robert Millan
@ 2008-02-03 8:27 ` Bean
0 siblings, 0 replies; 15+ messages in thread
From: Bean @ 2008-02-03 8:27 UTC (permalink / raw)
To: The development of GRUB 2
Committed.
--
Bean
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2008-02-03 8:27 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-29 19:22 [PATCH] eltorito cdrom boot Bean
2008-01-29 20:33 ` Robert Millan
2008-01-29 20:58 ` Marco Gerards
2008-01-30 15:13 ` Bean
2008-01-31 8:38 ` Bean
2008-01-31 11:09 ` Robert Millan
2008-01-31 11:36 ` Yoshinori K. Okuji
2008-01-31 12:43 ` Bean
2008-02-02 14:19 ` Bean
2008-02-02 16:33 ` Robert Millan
2008-02-02 17:16 ` Bean
2008-02-02 17:24 ` Robert Millan
2008-02-03 8:27 ` Bean
2008-01-31 12:47 ` Robert Millan
2008-01-31 13:04 ` Bean
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.