* CD-ROM booting staus update
@ 2007-06-27 1:36 Alex Roman
2007-06-28 14:04 ` Alex Roman
0 siblings, 1 reply; 10+ messages in thread
From: Alex Roman @ 2007-06-27 1:36 UTC (permalink / raw)
To: The development of GRUB 2
Thought I'd write a little status update on this project.
So far I can:
* identify CD-ROM drives
* read Eltorito descriptors off the CD
* parse Eltorito descriptors, and interpret them
* load bootable images from the CD in memory
Currently, the nag is that ISOLINUX at least uses Eltorito Int 13h
extensions which are not present on the QEMU/Bochs BIOS. And it seems
they may not be available unless booted from the CD on any system.
So, the only option I see at this point is to write a hook to Int 13h
which provides the Eltorito Int 13h extensions. I've looked at the
Smart Boot Manager (http://btmgr.sourceforge.net/) and I saw how they
do this. They actually use the direct ATAPI interface to talk to the
CD-ROM drive.
Their code is GPL licensed, but it is written for NASM, not GAS, and
also it is ~2000 lines of real-mode assembly programming. So, I don't
neccessarily know if it is desirable to port some of their code to GAS
so that we may use it...
Would there be any way to write 16 bit code, for real mode, in C, with
GCC, so that at least part of the Int 13h hook would be a bit more
maintainable? If not, is it acceptable to write that much code in asm?
Thank you!
.. regards!
PS: I know this has been a little slow going, but I have been doing a
lot of learning in the process...
--
Alex Roman <alex.roman@gmail.com>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: CD-ROM booting staus update
2007-06-27 1:36 CD-ROM booting staus update Alex Roman
@ 2007-06-28 14:04 ` Alex Roman
2007-07-01 11:57 ` Robert Millan
2007-07-04 3:14 ` Alex Roman
0 siblings, 2 replies; 10+ messages in thread
From: Alex Roman @ 2007-06-28 14:04 UTC (permalink / raw)
To: The development of GRUB 2
On 26/06/07, Alex Roman <alex.roman@gmail.com> wrote:
> Thought I'd write a little status update on this project.
All right, I took a look at the Bochs BIOS source code, and they seem
to be implementing just one Int 13h function that is specified in the
Eltorito specification: the 4B01h that isolinux needs to boot.
Next, I started to use Bochs' internal debugger and I noticed that the
grub_gate_a20 function clobbers %edx which was what was causing me the
grief, since I was holding the number of bytes to copy from my buffer
(that I read into from the CD) to 7c00h. So, instead of copying at
least 2k which is what ISOLINUX expects, it was copying only 224 bytes
(or something like that, the leftover value in %edx).
Now that I figured that out, *I managed to get the FreeDOS CD to boot! :)*
However, this relies on a little trick: my grub_eltorito_boot()
function in startup.S is placed at the very end of the file. It takes
in 3 parameters:
* the BIOS drive we're booting from (to be later placed in %dl)
* a pointer (linear address) to a buffer which stores the boot image
read from the CD
* the number of bytes to copy from the buffer to 7c00h
The function will then turn off the a20 gate, switch to real mode.
Then it will copy however many bytes I tell it from the buffer to
7c00h, overwriting parts of GRUB (including the functions needed to
gate a20 and go to real mode, which is why we do it early on).
After that it will clear all segments and perform a long jump (to set
%cs) to 0:7c00h and the boot process is completed.
The issues with this are:
* As soon as we enter the grub_eltorito_boot() function, there's no
chance of returning
* Other boot codes (not isolinux) may expect that more than 2k will
be copied to 7c00h, which means we may end up overwriting code in this
grub_eltorito_boot() function
A possible solution is to figure out a place where this function could
copy itself, high in memory so that it will be able to copy more than
2k, without overwriting itself, or the buffer I use to copy data into
from the CD.
That being said, I will clean up the code I have so far and send it as
a patch for review ASAP (tonight or tomorrow latest)...
I'd like any comments or objections on the current solution... Also,
sorry for the long email :)
Thanks!
--
Alex Roman <alex.roman@gmail.com>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: CD-ROM booting staus update
2007-06-28 14:04 ` Alex Roman
@ 2007-07-01 11:57 ` Robert Millan
2007-07-04 3:14 ` Alex Roman
1 sibling, 0 replies; 10+ messages in thread
From: Robert Millan @ 2007-07-01 11:57 UTC (permalink / raw)
To: The development of GRUB 2
On Thu, Jun 28, 2007 at 10:04:12AM -0400, Alex Roman wrote:
> On 26/06/07, Alex Roman <alex.roman@gmail.com> wrote:
> >Thought I'd write a little status update on this project.
>
> All right, I took a look at the Bochs BIOS source code, and they seem
> to be implementing just one Int 13h function that is specified in the
> Eltorito specification: the 4B01h that isolinux needs to boot.
>
> Next, I started to use Bochs' internal debugger and I noticed that the
> grub_gate_a20 function clobbers %edx which was what was causing me the
> grief, since I was holding the number of bytes to copy from my buffer
> (that I read into from the CD) to 7c00h. So, instead of copying at
> least 2k which is what ISOLINUX expects, it was copying only 224 bytes
> (or something like that, the leftover value in %edx).
>
> Now that I figured that out, *I managed to get the FreeDOS CD to boot! :)*
Congrats :-)
--
Robert Millan
My spam trap is honeypot@aybabtu.com. Note: this address is only intended
for spam harvesters. Writing to it will get you added to my black list.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: CD-ROM booting staus update
2007-06-28 14:04 ` Alex Roman
2007-07-01 11:57 ` Robert Millan
@ 2007-07-04 3:14 ` Alex Roman
2007-07-04 19:47 ` Uwe Hermann
2007-07-09 11:56 ` Johan Rydberg
1 sibling, 2 replies; 10+ messages in thread
From: Alex Roman @ 2007-07-04 3:14 UTC (permalink / raw)
To: The development of GRUB 2
[-- Attachment #1: Type: text/plain, Size: 800 bytes --]
On 28/06/07, Alex Roman <alex.roman@gmail.com> wrote:
> That being said, I will clean up the code I have so far and send it as
> a patch for review ASAP (tonight or tomorrow latest)...
I've cleaned up the code and created a patch which will enable allow
booting from the first CD-ROM on a system. This is my first patch so I
checked my code many times... hopefully it won't cause unwanted side
effects, and hopefully my patch is in the correct format.
This patch adds support for CD-ROM devices in biosdisk.c (cd0, cd1,
etc). It also adds 2 new files, eltorito.c and .h which implement a
command which will boot from the first CD-ROM device, cd0.
There are a few TODO's in the code.. This is just the first version,
more will come :)
Thanks,
... regards!
--
Alex Roman <alex.roman@gmail.com>
[-- Attachment #2: grub2-eltorito.patch --]
[-- Type: text/x-patch, Size: 23491 bytes --]
2007-07-03 Alex Roman <alex.roman@gmail.com>
* conf/i386-pc.rmk: Add eltorito.mod
* include/grub/i386/pc/biosdisk.h: Add DPTE structure
* include/grub/i386/pc/loader.h: Add grub_eltorito_boot function declaration
* kern/i386/pc/startup.S: Add grub_eltorito_boot function
* disk/i386/pc/biosdisk.c: Initial support for CD-ROM drives as "cd?"
* loader/i386/pc/eltorito.c: New file
* include/grub/eltorito.h: New file
Index: conf/i386-pc.rmk
===================================================================
RCS file: /sources/grub/grub2/conf/i386-pc.rmk,v
retrieving revision 1.81
diff -u -r1.81 i386-pc.rmk
--- conf/i386-pc.rmk 23 Jun 2007 14:44:37 -0000 1.81
+++ conf/i386-pc.rmk 4 Jul 2007 03:06:38 -0000
@@ -131,7 +131,8 @@
pkgdata_MODULES = _chain.mod _linux.mod linux.mod normal.mod \
_multiboot.mod chain.mod multiboot.mod reboot.mod halt.mod \
vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \
- videotest.mod play.mod bitmap.mod tga.mod cpuid.mod serial.mod
+ videotest.mod play.mod bitmap.mod tga.mod cpuid.mod serial.mod \
+ eltorito.mod
# For _chain.mod.
_chain_mod_SOURCES = loader/i386/pc/chainloader.c
@@ -153,6 +154,11 @@
linux_mod_CFLAGS = $(COMMON_CFLAGS)
linux_mod_LDFLAGS = $(COMMON_LDFLAGS)
+# For eltorito.mod.
+eltorito_mod_SOURCES = loader/i386/pc/eltorito.c
+eltorito_mod_CFLAGS = $(COMMON_CFLAGS)
+eltorito_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
# For normal.mod.
normal_mod_DEPENDENCIES = grub_script.tab.c grub_script.tab.h
normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c \
Index: include/grub/i386/pc/biosdisk.h
===================================================================
RCS file: /sources/grub/grub2/include/grub/i386/pc/biosdisk.h,v
retrieving revision 1.5
diff -u -r1.5 biosdisk.h
--- include/grub/i386/pc/biosdisk.h 29 Jul 2006 10:11:01 -0000 1.5
+++ include/grub/i386/pc/biosdisk.h 4 Jul 2007 03:06:38 -0000
@@ -81,6 +81,24 @@
grub_uint64_t block;
} __attribute__ ((packed));
+/* Device Parameter Table Extension */
+struct grub_biosdisk_dpte
+{
+ grub_uint16_t io_port_base;
+ grub_uint16_t ctrl_port_base;
+ grub_uint8_t head_register; /* upper nibble only */
+ grub_uint8_t bios_vendor_specific;
+ grub_uint8_t irq_info;
+ grub_uint8_t block_count;
+ grub_uint8_t dma_info;
+ grub_uint8_t pio_info;
+ grub_uint16_t bios_hw_flags;
+ grub_uint16_t reserved;
+ grub_uint8_t revision;
+ grub_uint8_t checksum;
+} __attribute__ ((packed));
+
+
int EXPORT_FUNC(grub_biosdisk_rw_int13_extensions) (int ah, int drive, void *dap);
int EXPORT_FUNC(grub_biosdisk_rw_standard) (int ah, int drive, int coff, int hoff,
int soff, int nsec, int segment);
Index: include/grub/i386/pc/loader.h
===================================================================
RCS file: /sources/grub/grub2/include/grub/i386/pc/loader.h,v
retrieving revision 1.7
diff -u -r1.7 loader.h
--- include/grub/i386/pc/loader.h 12 Sep 2004 12:20:52 -0000 1.7
+++ include/grub/i386/pc/loader.h 4 Jul 2007 03:06:38 -0000
@@ -39,6 +39,8 @@
struct grub_multiboot_info *mbi)
__attribute__ ((noreturn));
+ void EXPORT_FUNC(grub_eltorito_boot) (int drive, void *addr, int size) __attribute__ ((noreturn));
+
/* It is necessary to export these functions, because normal mode commands
reuse rescue mode commands. */
void grub_rescue_cmd_linux (int argc, char *argv[]);
Index: kern/i386/pc/startup.S
===================================================================
RCS file: /sources/grub/grub2/kern/i386/pc/startup.S,v
retrieving revision 1.24
diff -u -r1.24 startup.S
--- kern/i386/pc/startup.S 21 Jun 2007 21:01:11 -0000 1.24
+++ kern/i386/pc/startup.S 4 Jul 2007 03:06:38 -0000
@@ -2200,3 +2200,69 @@
popl %ebx
popl %ebp
ret
+
+/*
+ * grub_eltorito_boot (
+ * int drive, // %eax
+ * void *addr. // %edx
+ * int size // %ecx
+ * );
+ *
+ * This function will load *size* bytes from *addr* at 7C00h, save drive in
+ * %dl, clear the segment registers and perform a long jump to 0:7C00h.
+ *
+ * The address is a linear address and will be converted to seg:off format.
+ */
+FUNCTION(grub_eltorito_boot)
+
+ /* Re-organize the contents of registers using the stack */
+ pushl %ecx /* size */
+ pushl %eax /* drive */
+ pushl %edx /* addr */
+
+ popl %ebx /* addr */
+ popl %edx /* drive */
+ popl %ecx /* size */
+
+ xorl %eax, %eax
+ movl %eax, %edi
+ movl %eax, %esi
+
+ /* Turn off Gate A20 */
+ pusha
+ xorl %eax, %eax
+ call EXT_C(grub_gate_a20)
+ popa
+ call EXT_C(prot_to_real)
+
+ .code16
+
+ /* rep movsb will copy %ecx bytes from %ds:%si to %es:%di */
+
+ /* compute "copy from" address in %ds:%si */
+ movw %bx, %si
+ xorw %bx, %bx
+ shrl $4, %ebx
+ movw %bx, %ds
+
+ /* load "copy to" address in %es:%di */
+ xorw %ax, %ax
+ movw %ax, %di
+ movw $0x07C0, %ax
+ movw %ax, %es
+
+ /* %ecx contains number of bytes, so go ahead and copy! */
+ rep
+ movsb
+
+ xorw %ax, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ movw %ax, %ss
+
+ /* jump to 0:7C00h */
+ ljmp $0,$0x7C00
+
+ .code32
\ No newline at end of file
Index: disk/i386/pc/biosdisk.c
===================================================================
RCS file: /sources/grub/grub2/disk/i386/pc/biosdisk.c,v
retrieving revision 1.9
diff -u -r1.9 biosdisk.c
--- disk/i386/pc/biosdisk.c 29 Jul 2006 10:11:01 -0000 1.9
+++ disk/i386/pc/biosdisk.c 4 Jul 2007 03:06:38 -0000
@@ -31,7 +31,7 @@
{
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 +40,8 @@
if (name[0] == 'h')
drive += 0x80;
+ else if (name[0] == 'c')
+ drive += 0xe0;
return (int) drive ;
@@ -52,8 +54,14 @@
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 & 0xe0)
+ grub_sprintf (name, "cd%d", drive & (~0xe0));
+ else if (drive & 0x80)
+ grub_sprintf (name, "hd%d", drive & (~0x80));
+ else
+ grub_sprintf (name, "fd%d", drive);
+
return hook (name);
}
@@ -80,6 +88,8 @@
return 1;
}
+ /* TODO: What to do for CD drives? */
+
return 0;
}
@@ -94,7 +104,7 @@
if (drive < 0)
return grub_errno;
- disk->has_partitions = (drive & 0x80);
+ disk->has_partitions = ((drive & 0x80) && !(drive & 0xe0));
disk->id = drive;
data = (struct grub_biosdisk_data *) grub_malloc (sizeof (*data));
@@ -133,17 +143,21 @@
}
}
- 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;
+ /* We can't do this for CD drives */
+ if ( ! (drive & 0xe0) )
+ {
+ 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;
+ }
disk->total_sectors = total_sectors;
disk->data = data;
@@ -167,20 +181,23 @@
unsigned segment)
{
struct grub_biosdisk_data *data = disk->data;
-
+
if (data->flags & GRUB_BIOSDISK_FLAG_LBA)
{
struct grub_biosdisk_dap *dap;
+ /* Place the DAP as the last thing in the scratch buffer */
dap = (struct grub_biosdisk_dap *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR
- + (data->sectors
- << GRUB_DISK_SECTOR_BITS));
+ + GRUB_MEMORY_MACHINE_SCRATCH_SIZE
+ - sizeof (struct grub_biosdisk_dap));
+
+ grub_memset( dap, 0, sizeof (*dap) );
dap->length = sizeof (*dap);
dap->reserved = 0;
dap->blocks = size;
dap->buffer = segment << 16; /* The format SEGMENT:ADDRESS. */
- dap->block = sector;
-
+ dap->block = sector;
+
if (grub_biosdisk_rw_int13_extensions (cmd + 0x42, data->drive, dap))
{
/* Fall back to the CHS mode. */
Index: loader/i386/pc/eltorito.c
===================================================================
RCS file: loader/i386/pc/eltorito.c
diff -N loader/i386/pc/eltorito.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ loader/i386/pc/eltorito.c 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,301 @@
+/* eltorito.c - ElTorito CD-ROM Boot Standard, Loader */
+/*
+* GRUB -- GRand Unified Bootloader
+* Copyright (C) 2003 Free Software Foundation, Inc.
+* Copyright (C) 2003 NIIBE Yutaka <gniibe@m17n.org>
+*
+* 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/biosdisk.h>
+#include <grub/machine/memory.h>
+#include <grub/machine/loader.h>
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include <grub/device.h>
+#include <grub/disk.h>
+
+#include <grub/eltorito.h>
+
+/*
+ * Decode and print a Boot Record Volume Descriptor structure
+ */
+static void
+eltorito_dump_brvd( void * _brvd )
+{
+ grub_eltorito_boot_record_vol_descr brvd = _brvd;
+ char scrap[6];
+
+ grub_memcpy (scrap, brvd->iso9660_identifier, 5);
+ scrap[5] = 0;
+
+ grub_printf ("BOOT RECORD VOLUME DESCRIPTOR @ 0x%08x\n", (grub_uint32_t)brvd);
+ grub_printf ("boot_record_indicator : %d\n", brvd->boot_record_indicator);
+ grub_printf ("iso9660_identifier : %s\n", scrap);
+ grub_printf ("version : %d\n", brvd->version);
+ grub_printf ("boot_system_identifier : %s\n", brvd->boot_system_identifier);
+ grub_printf ("boot_catalog_pointer : 0x%08x\n", brvd->boot_catalog_pointer);
+}
+
+/*
+ * Decode and print a Validation Entry structure
+ */
+static void
+eltorito_dump_ve (void *_ve)
+{
+ grub_eltorito_validation_entry ve = _ve;
+ grub_printf ("VALIDATION ENTRY @ 0x%08x:\n", (grub_uint32_t)ve);
+ grub_printf ("header_id : %d\n", ve->header_id);
+ grub_printf ("platform_id : %d\n", ve->platform_id);
+ grub_printf ("id_string : %s\n", ve->id_string);
+ grub_printf ("checksum : 0x%04x\n", ve->checksum);
+ grub_printf ("key : 0x%04x\n", ve->key);
+}
+
+/*
+ * Decode and print an Initial/Default Entry structure
+ */
+static void
+eltorito_dump_de (void *_de)
+{
+ grub_eltorito_default_entry de = _de;
+ grub_printf ("INITIAL/DEFAULT ENTRY @ 0x%08x:\n", (grub_uint32_t)de);
+ grub_printf ("boot_indicator : 0x%x\n", de->boot_indicator);
+ grub_printf ("boot_media_type : %d\n", de->boot_media_type);
+ grub_printf ("load_segment : 0x%04x\n", de->load_segment);
+ grub_printf ("system_type: : %d\n", de->system_type);
+ grub_printf ("sector_count : %d\n", de->sector_count);
+ grub_printf ("load_rba : 0x%08x\n", de->load_rba);
+}
+
+/*
+ * Dump a region in memory as hex bytes
+ */
+static void
+eltorito_dump_memory (void *edmp_buf, int count)
+{
+ int i;
+ grub_uint8_t *b = (grub_uint8_t *)edmp_buf;
+
+ for (i=0; i<count; i++)
+ {
+ if ((i % 16) == 0)
+ grub_printf ("\n%04d: ", i);
+ grub_printf ("%02x ", b[i]);
+ }
+ grub_printf ("\n");
+}
+
+/*
+ * The main command function
+ */
+static grub_err_t
+grub_cmd_eltorito (struct grub_arg_list *state __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ /* A few structure pointers that we'll need. */
+ grub_eltorito_boot_record_vol_descr brvd;
+ grub_eltorito_validation_entry ve;
+ grub_eltorito_default_entry de;
+
+ /* Some other variables we'll need. */
+ grub_device_t cd_dev;
+ grub_disk_t disk;
+ grub_err_t err;
+
+ /*
+ * Open the first CD device.
+ * TODO: make use of multiple CD-ROM devices, perhaps through parameters.
+ */
+ cd_dev = grub_device_open ("cd0");
+ if (!cd_dev)
+ {
+ return GRUB_ERR_BAD_DEVICE;
+ }
+
+ /* Make sure there's a disk associated with the device. */
+ disk = cd_dev->disk;
+ if (!disk)
+ {
+ return GRUB_ERR_BAD_DEVICE;
+ }
+
+ /*
+ * Attempt to read the Boot Record Volume Descriptor which is located at
+ * block 0x11, according to spec.
+ */
+ err = disk->dev->read (disk, 0x11, 1,
+ (char *)GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
+ if (err != GRUB_ERR_NONE)
+ {
+ grub_printf ("Error reading the BRVD (err=0x%x)\n", err);
+ return GRUB_ERR_READ_ERROR;
+ }
+
+ brvd = (grub_eltorito_boot_record_vol_descr)GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
+
+ /* For debugging, dump the BRVD */
+ eltorito_dump_brvd (brvd);
+
+ /*
+ * Make sure the BRVD's contents make sense:
+ * + boot_record_indicator needs to be 0
+ * + version needs to be 1
+ * + iso9660_identifier needs to be "CD001", not NULL terminated
+ * + boot_system_identifier needs to be "EL_TORITO_SPECIFICATION"
+ */
+ if ( !(brvd->boot_record_indicator == 0 &&
+ brvd->version == 1 &&
+ grub_memcmp (brvd->iso9660_identifier, "CD001", 5) == 0 &&
+ grub_memcmp (brvd->boot_system_identifier, "EL TORITO SPECIFICATION", 24) == 0) )
+ {
+ grub_printf ("Read bad BRVD. Is the CD bootable?\n");
+ grub_printf ("bri = %d\n", brvd->boot_record_indicator);
+ grub_printf ("version = %d\n", brvd->version);
+ grub_printf ("%d\n", grub_memcmp (brvd->iso9660_identifier, "CD001", 5));
+ grub_printf ("%d\n", grub_memcmp (brvd->boot_system_identifier, "EL TORITO SPECIFICATION", 24));
+ return GRUB_ERR_READ_ERROR;
+ }
+
+ /*
+ * All good! The BRVD will provide a pointer to the boot catalog.
+ * Attempt to read that block from the CD device.
+ */
+ err = disk->dev->read (disk, brvd->boot_catalog_pointer, 1,
+ (char *)GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
+ if (err != GRUB_ERR_NONE)
+ {
+ grub_printf ("Error reading the boot catalog from block 0x%x\n",
+ brvd->boot_catalog_pointer);
+ return GRUB_ERR_READ_ERROR;
+ }
+
+ /* The Validation Entry, VE, is the first entry in the Boot Catalog. */
+ ve = (grub_eltorito_validation_entry)GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
+
+ /* For debugging, dump the VE. */
+ eltorito_dump_ve (ve);
+
+ /*
+ * Make sure the VE makes sense:
+ * + header_id must be 1
+ * + reserved field must be 0
+ * + key must be 0xaa55
+ * TODO: check the checksum
+ */
+ if ( !( ve->header_id == 0x01 &&
+ ve->reserved == 0x00 &&
+ ve->key == 0xaa55
+ ) )
+ {
+ grub_printf ("Error parsing the Validation Entry\n");
+ return GRUB_ERR_READ_ERROR;
+ }
+
+ /* Make sure we are running on the right platform. */
+ if (ve->platform_id == 0x00)
+ {
+ /* All good. */
+ }
+ else
+ {
+ /* Don't support non-x86 platforms yet, since it's not been ported yet. */
+ return GRUB_ERR_NOT_IMPLEMENTED_YET;
+ }
+
+ /*
+ * The Validation Entry makes sense.
+ * The next entry is the Default/Initial Entry (DE).
+ */
+ de = (grub_eltorito_default_entry)(GRUB_MEMORY_MACHINE_SCRATCH_ADDR + 32);
+
+ /* For debugging, dump the DE.*/
+ eltorito_dump_de (de);
+
+ /*
+ * Make sure the Default Entry is bootable.
+ * TODO: support entries that point to other entries, etc.
+ */
+ if ( de->boot_indicator != 0x88 )
+ {
+ grub_printf ("Error parsing the Default Entry\n");
+ return GRUB_ERR_READ_ERROR;
+ }
+
+ /* Figure out if we need to set up some sort of emulation. */
+ if (de->boot_media_type == 0x00) /* No Emulation */
+ {
+ /* All good, nothing to do. */
+ }
+ else
+ {
+ /* Not so good, not sure what to do yet... */
+ /* TODO: fail gratiously */
+ return GRUB_ERR_NOT_IMPLEMENTED_YET;
+ }
+
+ /* Figure out at what address we need to load the boot image. */
+ if (de->load_segment == 0x00)
+ {
+ /* Load at the traditional 0x7c00. */
+ }
+ else
+ {
+ /*
+ * Other segments not supported/tested yet...
+ * TODO: make this work
+ */
+ return GRUB_ERR_NOT_IMPLEMENTED_YET;
+ }
+
+ /* All good, let's read the boot image. */
+ err = disk->dev->read (disk, de->load_rba, de->sector_count,
+ (char *)GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
+ if (err != GRUB_ERR_NONE)
+ {
+ grub_printf ("Error reading the boot image from block 0x%x\n",
+ de->load_rba);
+ return GRUB_ERR_READ_ERROR;
+ }
+
+ /* Okay, now let's try to boot... */
+ grub_eltorito_boot (disk->id, (char*)GRUB_MEMORY_MACHINE_SCRATCH_ADDR, 2048);
+
+ /* Should never get here... */
+ grub_printf ("Something BAD has happened...\n");
+
+ /* Dump the first 2K of the boot image. */
+ eltorito_dump_memory ((void*)0x7c00, 2048);
+
+ return GRUB_ERR_NONE;
+}
+
+GRUB_MOD_INIT(eltorito)
+{
+ (void)mod; /* To stop warning. */
+ grub_register_command ("eltorito", grub_cmd_eltorito, GRUB_COMMAND_FLAG_BOTH,
+ "eltorito", "ElTorito CD-ROM Booting", 0);
+}
+
+GRUB_MOD_FINI(eltorito)
+{
+ grub_unregister_command ("eltorito");
+}
Index: include/grub/eltorito.h
===================================================================
RCS file: include/grub/eltorito.h
diff -N include/grub/eltorito.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ include/grub/eltorito.h 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,150 @@
+/* eltorito.h - ElTorito CD-ROM Boot Standard */
+/*
+* GRUB -- GRand Unified Bootloader
+* Copyright (C) 2003 Free Software Foundation, Inc.
+* Copyright (C) 2003 NIIBE Yutaka <gniibe@m17n.org>
+*
+* 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.
+*/
+
+#ifndef GRUB_ELTORITO_HEADER
+#define GRUB_ELTORITO_HEADER
+
+struct eltorito_spec_packet_tag
+{
+ grub_uint8_t size;
+ grub_uint8_t media_type;
+ grub_uint8_t drive;
+ grub_uint8_t controller_index;
+ grub_uint32_t lba;
+ grub_uint16_t dev_spec;
+ grub_uint16_t user_buf;
+ grub_uint16_t load_segment;
+ grub_uint16_t sector_count;
+ grub_uint8_t cylinder_count_ch;
+ grub_uint8_t cylinder_count_cl;
+ grub_uint8_t head_count;
+
+} __attribute__ ((packed));
+typedef struct grub_eltorito_spec_packet_tag * eltorito_spec_packet;
+
+struct grub_eltorito_cmd_packet_tag
+{
+ grub_uint8_t size;
+ grub_uint8_t sector_count;
+ grub_uint32_t buffer;
+ grub_uint16_t start_sector;
+} __attribute__ ((packed));
+typedef struct grub_eltorito_cmd_packet_tage * grub_eltorito_cmd_packet;
+
+struct grub_eltorito_boot_record_vol_descr_tag
+{
+ // Boot Record Indicator, must be 0x00
+ grub_uint8_t boot_record_indicator;
+
+ // ISO-9660 Identifier, must be "CD001"
+ grub_uint8_t iso9660_identifier[5];
+
+ // Version of this descriptor, must be 1
+ grub_uint8_t version;
+
+ // Boot System Identifier, must be "EL TORITO SPECIFICATION" padded
+ // with 0's
+ grub_uint8_t boot_system_identifier[23];
+
+ // Unused, must be 0.
+ grub_uint8_t unused1[41];
+
+ // Absolute pointer to first sector of Boot Catalog
+ grub_uint32_t boot_catalog_pointer;
+
+ // Unused, must be 0.
+ grub_uint8_t unused2[1973];
+} __attribute__ ((packed));
+typedef struct grub_eltorito_boot_record_vol_descr_tag* grub_eltorito_boot_record_vol_descr;
+
+struct grub_eltorito_validation_entry_tag
+{
+ // Header ID, must be 0x01.
+ grub_uint8_t header_id;
+
+ // Platform ID
+ // 0 = 80x86
+ // 1 = Power PC
+ // 2 = Mac
+ grub_uint8_t platform_id;
+
+ // Reserved, must be 0.
+ grub_uint16_t reserved;
+
+ // ID string. This is intended to identify the manufacturer/developer
+ // of this CD-ROM.
+ char id_string[24];
+
+ // Checksum Word. This sum of all the words in this record should be 0.
+ grub_int16_t checksum;
+
+ // Key word, must be 0x55AA. This value is included in the checksum
+ grub_uint16_t key;
+} __attribute__ ((packed));
+typedef struct grub_eltorito_validation_entry_tag* grub_eltorito_validation_entry;
+
+struct grub_eltorito_default_entry_tag
+{
+ // Boot Indicator.
+ // 0x88 = Bootable, 0x00 = Not Bootable
+ grub_uint8_t boot_indicator;
+
+ // Boot media type. This specifies what media the boot image is intended
+ // to emulate in bits 0-3 as follows, bits 4-7 are reserved and must be 0.
+ //
+ // Bits 0-3 count as follows:
+ // 0 = No Emulation
+ // 1 = 1.2 meg diskette
+ // 2 = 2.44 meg diskette
+ // 3 = 2.88 meg diskette
+ // 4 = Hard Disk (drive 80)
+ //
+ // 5-F Reserved, invalid at this time
+ grub_uint8_t boot_media_type;
+
+ // Load Segment. This is the load segment for the initial boot image. If
+ // this value is 0 the system will use the traditional segment of 0x7C0.
+ // If this value is non-zero the system will use the specified segment.
+ // This applies to x86 architectures only. For "flat" model architectures
+ // (such as Motorola) this is the address divided by 0x10.
+ grub_uint16_t load_segment;
+
+ // System Type. This must be a copy of byte 5 (System Type) from the
+ // Partition Table found in the boot image.
+ grub_uint8_t system_type;
+
+ // Unused, must be 0
+ grub_uint8_t unused1;
+
+ // Sector Count. This is the number of virtual/emulated sectors the system
+ // will store at Load Segment during the initial boot procedure
+ grub_uint16_t sector_count;
+
+ // Load RBA. This is the start address of the virtual disk. CD's use
+ // Relative/Logical block addressing
+ grub_uint32_t load_rba;
+
+ // Unused, must be 0
+ grub_uint8_t unused2[20];
+} __attribute__ ((packed));
+typedef struct grub_eltorito_default_entry_tag* grub_eltorito_default_entry;
+
+#endif /* GRUB_ELTORITO_HEADER */
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: CD-ROM booting staus update
2007-07-04 3:14 ` Alex Roman
@ 2007-07-04 19:47 ` Uwe Hermann
2007-07-04 20:14 ` Alex Roman
2007-07-09 11:56 ` Johan Rydberg
1 sibling, 1 reply; 10+ messages in thread
From: Uwe Hermann @ 2007-07-04 19:47 UTC (permalink / raw)
To: The development of GRUB 2
[-- Attachment #1: Type: text/plain, Size: 1368 bytes --]
On Tue, Jul 03, 2007 at 11:14:40PM -0400, Alex Roman wrote:
> On 28/06/07, Alex Roman <alex.roman@gmail.com> wrote:
>> That being said, I will clean up the code I have so far and send it as
>> a patch for review ASAP (tonight or tomorrow latest)...
>
> I've cleaned up the code and created a patch which will enable allow
> booting from the first CD-ROM on a system. This is my first patch so I
> checked my code many times... hopefully it won't cause unwanted side
> effects, and hopefully my patch is in the correct format.
>
> This patch adds support for CD-ROM devices in biosdisk.c (cd0, cd1,
> etc). It also adds 2 new files, eltorito.c and .h which implement a
> command which will boot from the first CD-ROM device, cd0.
Quick question:
Does the code require a BIOS to work, i.e., do you rely on BIOS
callbacks in the CDROM code? It would be great if you would _not_ do
that, but instead use/write a small CDROM driver which directly accesses the
hardware. This would make it possible to use grub2 with modern firmware
implementations such as LinuxBIOS (www.linuxbios.org), which do not
provide the legacy BIOS callbacks. Let the BIOS die it's well-deserved death.
Thanks for considering, Uwe.
--
http://www.hermann-uwe.de | http://www.holsham-traders.de
http://www.crazy-hacks.org | http://www.unmaintained-free-software.org
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: CD-ROM booting staus update
2007-07-04 19:47 ` Uwe Hermann
@ 2007-07-04 20:14 ` Alex Roman
2007-07-05 0:10 ` Alex Roman
0 siblings, 1 reply; 10+ messages in thread
From: Alex Roman @ 2007-07-04 20:14 UTC (permalink / raw)
To: The development of GRUB 2
On 04/07/07, Uwe Hermann <uwe@hermann-uwe.de> wrote:
> On Tue, Jul 03, 2007 at 11:14:40PM -0400, Alex Roman wrote:
> > On 28/06/07, Alex Roman <alex.roman@gmail.com> wrote:
> Does the code require a BIOS to work, i.e., do you rely on BIOS
> callbacks in the CDROM code? It would be great if you would _not_ do
> that, but instead use/write a small CDROM driver which directly accesses the
> hardware. This would make it possible to use grub2 with modern firmware
> implementations such as LinuxBIOS (www.linuxbios.org), which do not
> provide the legacy BIOS callbacks. Let the BIOS die it's well-deserved death.
Currently I rely on Int 13h functions to read data from the CD-ROM, so
yes, that would be a legacy BIOS call.
That will be the second stage of my Summer of Code project... Provided
people have no objections against my patch, and all is well, I will
soon start working on an ATA driver that will allow directly reading
from a CD-ROM drive.
--
Alex Roman <alex.roman@gmail.com>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: CD-ROM booting staus update
2007-07-04 20:14 ` Alex Roman
@ 2007-07-05 0:10 ` Alex Roman
2007-07-07 18:57 ` Robert Millan
0 siblings, 1 reply; 10+ messages in thread
From: Alex Roman @ 2007-07-05 0:10 UTC (permalink / raw)
To: The development of GRUB 2
On 04/07/07, Alex Roman <alex.roman@gmail.com> wrote:
> On 04/07/07, Uwe Hermann <uwe@hermann-uwe.de> wrote:
> > On Tue, Jul 03, 2007 at 11:14:40PM -0400, Alex Roman wrote:
> That will be the second stage of my Summer of Code project... Provided
> people have no objections against my patch, and all is well, I will
> soon start working on an ATA driver that will allow directly reading
> from a CD-ROM drive.
Bear in mind, though, that current CD-ROM boot sectors (e.g. ISOLINUX)
rely on Int 13h calls to continue the boot process. This means that,
even though writing an ATA driver will allow GRUB to boot a CD on a
platform which doesn't provide legacy interrupts, the loaded boot
sector won't work properly after being booted.
A possible solution to this is to write a rudimentary Int 13h handler
which will make use of the ATA driver...
--
Alex Roman <alex.roman@gmail.com>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: CD-ROM booting staus update
2007-07-05 0:10 ` Alex Roman
@ 2007-07-07 18:57 ` Robert Millan
2007-07-08 13:52 ` Alex Roman
0 siblings, 1 reply; 10+ messages in thread
From: Robert Millan @ 2007-07-07 18:57 UTC (permalink / raw)
To: The development of GRUB 2
On Wed, Jul 04, 2007 at 08:10:29PM -0400, Alex Roman wrote:
> On 04/07/07, Alex Roman <alex.roman@gmail.com> wrote:
> >On 04/07/07, Uwe Hermann <uwe@hermann-uwe.de> wrote:
> >> On Tue, Jul 03, 2007 at 11:14:40PM -0400, Alex Roman wrote:
> >That will be the second stage of my Summer of Code project... Provided
> >people have no objections against my patch, and all is well, I will
> >soon start working on an ATA driver that will allow directly reading
> >from a CD-ROM drive.
>
> Bear in mind, though, that current CD-ROM boot sectors (e.g. ISOLINUX)
> rely on Int 13h calls to continue the boot process. This means that,
> even though writing an ATA driver will allow GRUB to boot a CD on a
> platform which doesn't provide legacy interrupts, the loaded boot
> sector won't work properly after being booted.
>
> A possible solution to this is to write a rudimentary Int 13h handler
> which will make use of the ATA driver...
Since we're on free software, we can do better. Instead of sticking to an
obsolete interface, we can define our own in both sides. E.g. define how
a CD layout has to be to be bootable by BIOS-less GRUB.
--
Robert Millan
My spam trap is honeypot@aybabtu.com. Note: this address is only intended
for spam harvesters. Writing to it will get you added to my black list.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: CD-ROM booting staus update
2007-07-07 18:57 ` Robert Millan
@ 2007-07-08 13:52 ` Alex Roman
0 siblings, 0 replies; 10+ messages in thread
From: Alex Roman @ 2007-07-08 13:52 UTC (permalink / raw)
To: The development of GRUB 2
On 07/07/07, Robert Millan <rmh@aybabtu.com> wrote:
> Since we're on free software, we can do better. Instead of sticking to an
> obsolete interface, we can define our own in both sides. E.g. define how
> a CD layout has to be to be bootable by BIOS-less GRUB.
Well, the ElTorito standard is used all throughout the world as *the*
standard for bootable CDs. A really good thing about it is that it
does not break a CD's compatibility with the ISO9660 standard.
Another great thing about it is that it is very flexible: you can
specify all sorts of parameters to your boot image, such as computer
architecture, load address, size and you can have more than one boot
image, among other things that are outlined in the spec.
Writing our own means that only our CDs will be bootable on our
interface... I personally don't think there is a need to move away
from the ElTorito standard. It's been proven by years of usage without
much complaint, from what I can gather.
However, we could work on defining a new interface to accessing the
CD-ROM drive that doesn't rely on old constructs. However, like I've
said, current software relies on the Int 13h interface to continue
booting. So, although we would use a "nice" interface to read the boot
image, load it in memory and boot it, the boot image itself wouldn't
work until we provided the Int 13h interface.
Just my opinion...
--
Alex Roman <alex.roman@gmail.com>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: CD-ROM booting staus update
2007-07-04 3:14 ` Alex Roman
2007-07-04 19:47 ` Uwe Hermann
@ 2007-07-09 11:56 ` Johan Rydberg
1 sibling, 0 replies; 10+ messages in thread
From: Johan Rydberg @ 2007-07-09 11:56 UTC (permalink / raw)
To: The development of GRUB 2
[-- Attachment #1: Type: text/plain, Size: 2975 bytes --]
"Alex Roman" <alex.roman@gmail.com> writes:
> I've cleaned up the code and created a patch which will enable allow
> booting from the first CD-ROM on a system. This is my first patch so I
> checked my code many times... hopefully it won't cause unwanted side
> effects, and hopefully my patch is in the correct format.
Hi Alex,
I haven't seen any reviews of this patch, so I'll give it a go.
Remember that I do not do any active GRUB2 development at the moment,
so I'll mostly comment on style related issues.
> + void EXPORT_FUNC(grub_eltorito_boot) (int drive, void *addr, int size) __attribute__ ((noreturn));
> +
If this line is longer than 72 characters, please try to break it.
> + /* We can't do this for CD drives */
> + if ( ! (drive & 0xe0) )
> + {
> + 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;
> + }
I guess the outer braces are misaligned because of whitespace issues
(tab vs space)? Otherwise you need to indent them two steps further.
>
> disk->total_sectors = total_sectors;
> disk->data = data;
> @@ -167,20 +181,23 @@
> unsigned segment)
> {
> struct grub_biosdisk_data *data = disk->data;
> -
> +
Whitespace alterations. No need for those.
> - dap->block = sector;
> -
> + dap->block = sector;
> +
Same here.
> +/*
> + * Decode and print a Boot Record Volume Descriptor structure
> + */
Even though the license header in each file prefixes each line with a
star, we normally don't do that for other multiline comments.
> +/*
> + * The main command function
> + */
If you ask me, no need for this comment.
> +static grub_err_t
> +grub_cmd_eltorito (struct grub_arg_list *state __attribute__ ((unused)),
> + int argc __attribute__ ((unused)),
> + char **args __attribute__ ((unused)))
> +{
> + /* A few structure pointers that we'll need. */
> + grub_eltorito_boot_record_vol_descr brvd;
> + grub_eltorito_validation_entry ve;
> + grub_eltorito_default_entry de;
> +
> + /* Some other variables we'll need. */
> + grub_device_t cd_dev;
> + grub_disk_t disk;
> + grub_err_t err;
Instead of commenting that you have declared those variables, comment
WHY. If a comment is needed at all. The rule of thumb is to comment
why something is done, not how.
> +struct grub_eltorito_validation_entry_tag
> +{
> + // Header ID, must be 0x01.
> + grub_uint8_t header_id;
Please do not use C++ style single-line comments.
Besides these cosmetic comments I think the overall patch looks just
fine. Great work Alex.
~j
[-- Attachment #2: Type: application/pgp-signature, Size: 190 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2007-07-09 11:33 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-06-27 1:36 CD-ROM booting staus update Alex Roman
2007-06-28 14:04 ` Alex Roman
2007-07-01 11:57 ` Robert Millan
2007-07-04 3:14 ` Alex Roman
2007-07-04 19:47 ` Uwe Hermann
2007-07-04 20:14 ` Alex Roman
2007-07-05 0:10 ` Alex Roman
2007-07-07 18:57 ` Robert Millan
2007-07-08 13:52 ` Alex Roman
2007-07-09 11:56 ` Johan Rydberg
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.