* GRUB device names wrt. ieee1275
@ 2009-03-14 22:14 David Miller
2009-03-14 23:44 ` phcoder
` (2 more replies)
0 siblings, 3 replies; 18+ messages in thread
From: David Miller @ 2009-03-14 22:14 UTC (permalink / raw)
To: grub-devel
One issue I need to resolve before I can send finalized
patches out for sparc is about device naming.
Currently the PowerPC ieee1275 support allows using both device
aliases and full openfirmware device path names with the usual GRUB
partition specification concatenated at the end. For the most part
this is fine.
This works for a large group of cases, but in general it will not
work.
The problem is two fold:
1) "," characters can appear anywhere in an openfirmware path
name. For example my workstations disk is:
/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0
There are no quick workarounds for this. For example, even if we
can change the partition fetching code in GRUB to use "strrchr()"
instead of "strchr()" in kern/disk.c:grub_disk_open() it will
still think the above path has partition ",600000" or something
silly like that.
2) Disks can have multiple comma seperated components especially
on SCSI in OF path names. For example a disk on target 2,
lun 3, would have final path component "disk@2,3"
And currently that ",3" would look like a parition specification
to GRUB.
Therefore, I would suggest that we adopt the openfirmware partition
specification of ":" on GRUB for ieee1275 platforms.
Then we just have a machine specific path seperator, defined in
some <grub/machine/foo.h> header file and the kernel/disk.c code
and elsewhere use the macro instead of ","
Any objections?
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: GRUB device names wrt. ieee1275
2009-03-14 22:14 GRUB device names wrt. ieee1275 David Miller
@ 2009-03-14 23:44 ` phcoder
2009-03-15 5:24 ` David Miller
2009-03-15 9:22 ` Vesa Jääskeläinen
2009-03-15 15:45 ` Robert Millan
2 siblings, 1 reply; 18+ messages in thread
From: phcoder @ 2009-03-14 23:44 UTC (permalink / raw)
To: The development of GRUB 2
For me it looks like it's disk driver-specific (ofdisk) and not
platform-specific. Perhaps quoting or escaping could offer a better
solution?
David Miller wrote:
> One issue I need to resolve before I can send finalized
> patches out for sparc is about device naming.
>
> Currently the PowerPC ieee1275 support allows using both device
> aliases and full openfirmware device path names with the usual GRUB
> partition specification concatenated at the end. For the most part
> this is fine.
>
> This works for a large group of cases, but in general it will not
> work.
>
> The problem is two fold:
>
> 1) "," characters can appear anywhere in an openfirmware path
> name. For example my workstations disk is:
>
> /pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0
>
> There are no quick workarounds for this. For example, even if we
> can change the partition fetching code in GRUB to use "strrchr()"
> instead of "strchr()" in kern/disk.c:grub_disk_open() it will
> still think the above path has partition ",600000" or something
> silly like that.
>
> 2) Disks can have multiple comma seperated components especially
> on SCSI in OF path names. For example a disk on target 2,
> lun 3, would have final path component "disk@2,3"
>
> And currently that ",3" would look like a parition specification
> to GRUB.
>
> Therefore, I would suggest that we adopt the openfirmware partition
> specification of ":" on GRUB for ieee1275 platforms.
>
> Then we just have a machine specific path seperator, defined in
> some <grub/machine/foo.h> header file and the kernel/disk.c code
> and elsewhere use the macro instead of ","
>
> Any objections?
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
--
Regards
Vladimir 'phcoder' Serbinenko
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: GRUB device names wrt. ieee1275
2009-03-14 23:44 ` phcoder
@ 2009-03-15 5:24 ` David Miller
0 siblings, 0 replies; 18+ messages in thread
From: David Miller @ 2009-03-15 5:24 UTC (permalink / raw)
To: grub-devel, phcoder
From: phcoder <phcoder@gmail.com>
Date: Sun, 15 Mar 2009 00:44:15 +0100
> For me it looks like it's disk driver-specific (ofdisk) and not
> platform-specific. Perhaps quoting or escaping could offer a better
> solution?
Specifying partitions using "/path/to/device:partition" syntax is an
attribute of openfirmware.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: GRUB device names wrt. ieee1275
2009-03-14 22:14 GRUB device names wrt. ieee1275 David Miller
2009-03-14 23:44 ` phcoder
@ 2009-03-15 9:22 ` Vesa Jääskeläinen
2009-03-15 22:52 ` David Miller
2009-03-15 15:45 ` Robert Millan
2 siblings, 1 reply; 18+ messages in thread
From: Vesa Jääskeläinen @ 2009-03-15 9:22 UTC (permalink / raw)
To: The development of GRUB 2
David Miller wrote:
> One issue I need to resolve before I can send finalized
> patches out for sparc is about device naming.
>
> Currently the PowerPC ieee1275 support allows using both device
> aliases and full openfirmware device path names with the usual GRUB
> partition specification concatenated at the end. For the most part
> this is fine.
>
> This works for a large group of cases, but in general it will not
> work.
>
> The problem is two fold:
>
> 1) "," characters can appear anywhere in an openfirmware path
> name. For example my workstations disk is:
>
> /pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0
>
> There are no quick workarounds for this. For example, even if we
> can change the partition fetching code in GRUB to use "strrchr()"
> instead of "strchr()" in kern/disk.c:grub_disk_open() it will
> still think the above path has partition ",600000" or something
> silly like that.
Actually related question here is that how do you specify similar device
paths in x86? Now that there is pci support and some kinda usb support
it could be good idea to specify exact device somehow in some use cases.
> 2) Disks can have multiple comma seperated components especially
> on SCSI in OF path names. For example a disk on target 2,
> lun 3, would have final path component "disk@2,3"
>
> And currently that ",3" would look like a parition specification
> to GRUB.
>
> Therefore, I would suggest that we adopt the openfirmware partition
> specification of ":" on GRUB for ieee1275 platforms.
>
> Then we just have a machine specific path seperator, defined in
> some <grub/machine/foo.h> header file and the kernel/disk.c code
> and elsewhere use the macro instead of ","
>
> Any objections?
So you propose following:
(/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0:1)
(/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0:a,1)
( $FW_DISK_NAME + ':' + $GRUB_PARTITION_SCHEME )
?
If we go that path we should use same delimeter for other archs to make
it a bit easier for users to understand how it works.
Lets try couple of examples:
1. (hd0) => a-d) device alias 'hd0', no partition
2. (hd0,1) => a-d) device alias 'hd0', partition '1'
3. (hd0:1) =>
a) device alias 'hd0:1', no partition
b) device alias 'hd0:1', no partition
c) device alias 'hd0', partition '1'
d) device alias 'hd0:1', no partition
4. (/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0)
a) => device alias '/pci@1e', partition
'600000/pci@0/pci@9/pci@0/scsi@1/disk@0'
b) => device alias '/pci@1e', partition '600000'
c) => device alias '/pci@1e', partition
'600000/pci@0/pci@9/pci@0/scsi@1/disk@0'
d) => device alias '/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0',
no partition
5. (/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0:1)
a) => device alias '/pci@1e', partition
'600000/pci@0/pci@9/pci@0/scsi@1/disk@0:1'
b) => device alias '/pci@1e', partition '600000'
c) => device alias '/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0',
parition '1'.
d) => device alias '/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0',
parition '1'.
6. (/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0:)
a) => device alias '/pci@1e', partition
'600000/pci@0/pci@9/pci@0/scsi@1/disk@0:1'
b) => device alias '/pci@1e', partition '600000'
c) => device alias '/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0',
no partition parition.
d) => device alias '/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0',
no partition parition.
Now the algorithms for a-d:
a) look for first comma, split there
b) look for first comma, split there, filter out results
c) look for ':', if found split there, otherwise go to a)
d) look for '/' at start, if found look for ':' to differentiate
partitions, if not found go to a)
Now lets play with phcoder's idea:
("/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0")
("/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0",1)
("/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0",a,1)
This could be easier to get right. Thou still needs some learning curve
for user. This extension could be used to look out for all firmware
names (assuming they map to ascii/utf-8).
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: GRUB device names wrt. ieee1275
2009-03-14 22:14 GRUB device names wrt. ieee1275 David Miller
2009-03-14 23:44 ` phcoder
2009-03-15 9:22 ` Vesa Jääskeläinen
@ 2009-03-15 15:45 ` Robert Millan
2009-03-15 22:41 ` David Miller
2 siblings, 1 reply; 18+ messages in thread
From: Robert Millan @ 2009-03-15 15:45 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, Mar 14, 2009 at 03:14:17PM -0700, David Miller wrote:
>
> One issue I need to resolve before I can send finalized
> patches out for sparc is about device naming.
>
> Currently the PowerPC ieee1275 support allows using both device
> aliases and full openfirmware device path names with the usual GRUB
> partition specification concatenated at the end. For the most part
> this is fine.
>
> This works for a large group of cases, but in general it will not
> work.
>
> The problem is two fold:
>
> 1) "," characters can appear anywhere in an openfirmware path
> name. For example my workstations disk is:
>
> /pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0
>
> There are no quick workarounds for this. For example, even if we
> can change the partition fetching code in GRUB to use "strrchr()"
> instead of "strchr()" in kern/disk.c:grub_disk_open() it will
> still think the above path has partition ",600000" or something
> silly like that.
>
> 2) Disks can have multiple comma seperated components especially
> on SCSI in OF path names. For example a disk on target 2,
> lun 3, would have final path component "disk@2,3"
>
> And currently that ",3" would look like a parition specification
> to GRUB.
>
> Therefore, I would suggest that we adopt the openfirmware partition
> specification of ":" on GRUB for ieee1275 platforms.
It's not an absolute must that device names are unique. You can still
identify partitions by their filesystem UUID or label, and in fact this
is what our default scripts (grub-mkconfig) do anyway.
Making GRUB specify partitions differently depending on the platform we're
on seems troublesome, specially if we end up with such long an ugly names.
If we really need this, can't we just assign names dynamically like
hd0, hd1, etc, and keep a memory structure that matches them with the
actual OFW device?
--
Robert Millan
The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
how) you may access your data; but nobody's threatening your freedom: we
still allow you to remove your data and not access it at all."
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: GRUB device names wrt. ieee1275
2009-03-15 15:45 ` Robert Millan
@ 2009-03-15 22:41 ` David Miller
2009-03-18 10:18 ` Robert Millan
0 siblings, 1 reply; 18+ messages in thread
From: David Miller @ 2009-03-15 22:41 UTC (permalink / raw)
To: grub-devel, rmh
From: Robert Millan <rmh@aybabtu.com>
Date: Sun, 15 Mar 2009 16:45:31 +0100
> It's not an absolute must that device names are unique. You can still
> identify partitions by their filesystem UUID or label, and in fact this
> is what our default scripts (grub-mkconfig) do anyway.
Things like UUID and labels are not an option for the 512-byte
boot block where I have to know the exact OBP path of the boot
device, and this is what the GRUB kernel fetches from the
'bootpath' environment variable to compose the root device
and path.
So the point is that we need this information anyways.
> Making GRUB specify partitions differently depending on the platform we're
> on seems troublesome, specially if we end up with such long an ugly names.
If there are commas in the openfirmware paths, which there are,
there are only two ways to resolve the conflict between how
GRUB uses comma characters (to delimit partition specifications)
and how the firmware uses them:
1) My suggestion, which is to use ":" on openfirmware platforms.
To me this is the best because people using openfirmware
platforms are familiar with this syntax. We gain nothing by
giving them something else to learn, on top of openfirmware
path naming, just for the sake of GRUB.
2) Munge the openfirmware path back and forth, for example changing
the openfirmware "," characters into something else.
We'd need to do this back and forth, as device paths go in and
out of GRUB's realm. I don't really think that is maintainable.
> If we really need this, can't we just assign names dynamically like
> hd0, hd1, etc, and keep a memory structure that matches them with the
> actual OFW device?
I need the fully expanded path for things like the boot block
anyways. Here is the devicemap file on my workstation:
(/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0) /dev/sda
(/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@1) /dev/sdb
And that looks just fine to me.
We could enhance this (and I planned on implementing this) by
using the shorter devalias names which match the above paths.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: GRUB device names wrt. ieee1275
2009-03-15 9:22 ` Vesa Jääskeläinen
@ 2009-03-15 22:52 ` David Miller
0 siblings, 0 replies; 18+ messages in thread
From: David Miller @ 2009-03-15 22:52 UTC (permalink / raw)
To: grub-devel, chaac
From: Vesa Jääskeläinen <chaac@nic.fi>
Date: Sun, 15 Mar 2009 11:22:21 +0200
> David Miller wrote:
> > The problem is two fold:
> >
> > 1) "," characters can appear anywhere in an openfirmware path
> > name. For example my workstations disk is:
> >
> > /pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0
> >
> > There are no quick workarounds for this. For example, even if we
> > can change the partition fetching code in GRUB to use "strrchr()"
> > instead of "strchr()" in kern/disk.c:grub_disk_open() it will
> > still think the above path has partition ",600000" or something
> > silly like that.
>
> Actually related question here is that how do you specify similar device
> paths in x86? Now that there is pci support and some kinda usb support
> it could be good idea to specify exact device somehow in some use cases.
I have no idea, it has to be something very similar.
My suspicion is that they've been purely using device aliases which
elides the whole "commas in the path" issue.
> > 2) Disks can have multiple comma seperated components especially
> > on SCSI in OF path names. For example a disk on target 2,
> > lun 3, would have final path component "disk@2,3"
> >
> > And currently that ",3" would look like a parition specification
> > to GRUB.
> >
> > Therefore, I would suggest that we adopt the openfirmware partition
> > specification of ":" on GRUB for ieee1275 platforms.
> >
> > Then we just have a machine specific path seperator, defined in
> > some <grub/machine/foo.h> header file and the kernel/disk.c code
> > and elsewhere use the macro instead of ","
> >
> > Any objections?
>
> So you propose following:
>
> (/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0:1)
> (/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0:a,1)
>
> ( $FW_DISK_NAME + ':' + $GRUB_PARTITION_SCHEME )
I'm proposing purely ":a" instead of how grub currently says ",1".
There is work some folks are doing on EFI support for openfirmware.
One consequence of that is that you have to support more partitions
than 'a' - 'z' can represent, and the encoding there would be to
use decimal numbers for partitions larger than 25 so it would be
":26", ":27", etc.
> Lets try couple of examples:
>
> 1. (hd0) => a-d) device alias 'hd0', no partition
>
> 2. (hd0,1) => a-d) device alias 'hd0', partition '1'
>
> 3. (hd0:1) =>
> a) device alias 'hd0:1', no partition
> b) device alias 'hd0:1', no partition
> c) device alias 'hd0', partition '1'
> d) device alias 'hd0:1', no partition
This is not what I'm proposing at all.
On openfirmware platforms (only) what you would call
"hd0,1" would become "$(OPENFIRMWARE_PATH_OR_DEVALIAS):a"
So we'd have things like:
disk:a /* openfirmware devalias */
disk1:a /* openfirmware devalias */
/pci@1e,600000/pci@0/pci@9/pci@0/scsi@1/disk@0:a /* full path */
etc.
There is no confusion here, ":" always means the path has ended
and we are about to see a partition specifier.
Lack of ":" means whole-disk.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: GRUB device names wrt. ieee1275
2009-03-15 22:41 ` David Miller
@ 2009-03-18 10:18 ` Robert Millan
2009-03-18 20:55 ` David Miller
0 siblings, 1 reply; 18+ messages in thread
From: Robert Millan @ 2009-03-18 10:18 UTC (permalink / raw)
To: The development of GRUB 2
On Sun, Mar 15, 2009 at 03:41:16PM -0700, David Miller wrote:
> From: Robert Millan <rmh@aybabtu.com>
> Date: Sun, 15 Mar 2009 16:45:31 +0100
>
> > It's not an absolute must that device names are unique. You can still
> > identify partitions by their filesystem UUID or label, and in fact this
> > is what our default scripts (grub-mkconfig) do anyway.
>
> Things like UUID and labels are not an option for the 512-byte
> boot block where I have to know the exact OBP path of the boot
> device, and this is what the GRUB kernel fetches from the
> 'bootpath' environment variable to compose the root device
> and path.
What 512-byte boot block?
--
Robert Millan
The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
how) you may access your data; but nobody's threatening your freedom: we
still allow you to remove your data and not access it at all."
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: GRUB device names wrt. ieee1275
2009-03-18 10:18 ` Robert Millan
@ 2009-03-18 20:55 ` David Miller
2009-03-18 21:01 ` David Miller
0 siblings, 1 reply; 18+ messages in thread
From: David Miller @ 2009-03-18 20:55 UTC (permalink / raw)
To: grub-devel, rmh
From: Robert Millan <rmh@aybabtu.com>
Date: Wed, 18 Mar 2009 11:18:46 +0100
> On Sun, Mar 15, 2009 at 03:41:16PM -0700, David Miller wrote:
> > From: Robert Millan <rmh@aybabtu.com>
> > Date: Sun, 15 Mar 2009 16:45:31 +0100
> >
> > > It's not an absolute must that device names are unique. You can still
> > > identify partitions by their filesystem UUID or label, and in fact this
> > > is what our default scripts (grub-mkconfig) do anyway.
> >
> > Things like UUID and labels are not an option for the 512-byte
> > boot block where I have to know the exact OBP path of the boot
> > device, and this is what the GRUB kernel fetches from the
> > 'bootpath' environment variable to compose the root device
> > and path.
>
> What 512-byte boot block?
The one I add in my sparc64 support changes.
Included here for reference:
/* -*-Asm-*- */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 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>
.text
.align 4
.globl _start
_start:
/* OF CIF entry point arrives in %o4 */
pic_base:
call boot_continue
mov %o4, CIF_REG
. = _start + GRUB_BOOT_MACHINE_VER_MAJ
boot_version: .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
/* The offsets to these locations are defined by the
* GRUB_BOOT_MACHINE_foo macros in include/grub/sparc/ieee1275/boot.h,
* and grub-setup uses this to patch these next three values as needed.
*
* The boot_path will be the OF device path of the partition where the
* rest of the GRUB kernel image resides. kernel_sector will be set to
* the location of the first block of the GRUB kernel, and
* kernel_address is the location where we should load that first block.
*
* After loading in that block we will execute it by jumping to the
* load address plus the size of the prepended A.OUT header (32 bytes).
*/
boot_path:
. = _start + GRUB_BOOT_MACHINE_KERNEL_SECTOR
kernel_sector: .xword 2
kernel_address: .word GRUB_BOOT_MACHINE_KERNEL_ADDR
prom_finddev_name: .asciz "finddevice"
prom_chosen_path: .asciz "/chosen"
prom_getprop_name: .asciz "getprop"
prom_stdout_name: .asciz "stdout"
prom_write_name: .asciz "write"
prom_bootpath_name: .asciz "bootpath"
prom_open_name: .asciz "open"
prom_seek_name: .asciz "seek"
prom_read_name: .asciz "read"
prom_exit_name: .asciz "exit"
grub_name: .asciz "GRUB "
#define GRUB_NAME_LEN 5
.align 4
prom_open_error:
GET_ABS(prom_open_name, %o2)
call console_write
mov 4, %o3
/* fallthru */
prom_error:
GET_ABS(prom_exit_name, %o0)
/* fallthru */
/* %o0: OF call name
* %o1: input arg 1
*/
prom_call_1_1:
mov 1, %g1
ba prom_call
mov 1, %o5
/* %o2: message string
* %o3: message length
*/
console_write:
GET_ABS(prom_write_name, %o0)
mov STDOUT_NODE_REG, %o1
/* fallthru */
/* %o0: OF call name
* %o1: input arg 1
* %o2: input arg 2
* %o3: input arg 3
*/
prom_call_3_1:
mov 3, %g1
mov 1, %o5
/* fallthru */
/* %o0: OF call name
* %g1: num inputs
* %o5: num outputs
* %o1-%o4: inputs
*/
prom_call:
stx %o0, [%l1 + 0x00]
stx %g1, [%l1 + 0x08]
stx %o5, [%l1 + 0x10]
stx %o1, [%l1 + 0x18]
stx %o2, [%l1 + 0x20]
stx %o3, [%l1 + 0x28]
stx %o4, [%l1 + 0x30]
jmpl CIF_REG, %g0
mov %l1, %o0
boot_continue:
mov %o7, PIC_REG /* PIC base */
sethi %hi(SCRATCH_PAD), %l1 /* OF argument slots */
/* Find the /chosen node so we can fetch the stdout handle,
* and thus perform console output.
*
* chosen_node = prom_finddevice("/chosen")
*/
GET_ABS(prom_finddev_name, %o0)
GET_ABS(prom_chosen_path, %o1)
call prom_call_1_1
clr %o2
ldx [%l1 + 0x20], CHOSEN_NODE_REG
brz CHOSEN_NODE_REG, prom_error
/* getprop(chosen_node, "stdout", &buffer, buffer_size) */
GET_ABS(prom_getprop_name, %o0)
mov 4, %g1
mov 1, %o5
mov CHOSEN_NODE_REG, %o1
GET_ABS(prom_stdout_name, %o2)
add %l1, 256, %o3
mov 1024, %o4
call prom_call
stx %g1, [%l1 + 256]
lduw [%l1 + 256], STDOUT_NODE_REG
brz,pn STDOUT_NODE_REG, prom_error
/* write(stdout_node, "GRUB ", strlen("GRUB ")) */
GET_ABS(grub_name, %o2)
call console_write
mov GRUB_NAME_LEN, %o3
/* Open up the boot_path, and use that handle to read the
* first block of the GRUB kernel image.
*
* bootdev_handle = open(boot_path)
*/
GET_ABS(prom_open_name, %o0)
GET_ABS(boot_path, %o1)
call prom_call_1_1
clr %o2
ldx [%l1 + 0x20], BOOTDEV_REG
brz,pn BOOTDEV_REG, prom_open_error
/* Since we have 64-bit cells, the high cell of the seek offset
* is zero and the low cell is the entire value.
*
* seek(bootdev, 0, *kernel_sector << 9)
*/
GET_ABS(prom_seek_name, %o0)
mov BOOTDEV_REG, %o1
clr %o2
LDX_ABS(kernel_sector, 0x00, %o3)
call prom_call_3_1
sllx %o3, 9, %o3
/* read(bootdev, *kernel_address, 512) */
GET_ABS(prom_read_name, %o0)
mov BOOTDEV_REG, %o1
LDUW_ABS(kernel_address, 0x00, %o2)
call prom_call_3_1
mov 512, %o3
LDUW_ABS(kernel_address, 0x00, %o2)
jmpl %o2, %o7
nop
1: ba,a 1b
. = _start + GRUB_BOOT_MACHINE_CODE_END
/* the last 4 bytes in the sector 0 contain the signature */
.word GRUB_BOOT_MACHINE_SIGNATURE
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: GRUB device names wrt. ieee1275
2009-03-18 20:55 ` David Miller
@ 2009-03-18 21:01 ` David Miller
2009-03-22 0:41 ` phcoder
0 siblings, 1 reply; 18+ messages in thread
From: David Miller @ 2009-03-18 21:01 UTC (permalink / raw)
To: grub-devel, rmh
From: David Miller <davem@davemloft.net>
Date: Wed, 18 Mar 2009 13:55:22 -0700 (PDT)
> From: Robert Millan <rmh@aybabtu.com>
> Date: Wed, 18 Mar 2009 11:18:46 +0100
>
> > On Sun, Mar 15, 2009 at 03:41:16PM -0700, David Miller wrote:
> > > From: Robert Millan <rmh@aybabtu.com>
> > > Date: Sun, 15 Mar 2009 16:45:31 +0100
> > >
> > > > It's not an absolute must that device names are unique. You can still
> > > > identify partitions by their filesystem UUID or label, and in fact this
> > > > is what our default scripts (grub-mkconfig) do anyway.
> > >
> > > Things like UUID and labels are not an option for the 512-byte
> > > boot block where I have to know the exact OBP path of the boot
> > > device, and this is what the GRUB kernel fetches from the
> > > 'bootpath' environment variable to compose the root device
> > > and path.
> >
> > What 512-byte boot block?
>
> The one I add in my sparc64 support changes.
>
> Included here for reference:
BTW, I explained exactly how this 512 byte boot block works, in
extreme detail, when I first posted my grub sparc64 patches.
I am including it here _again_, please read it, it's informative,
I promise, and I didn't post it the first time for my health!
Thanks!
--------------------
The first task is to get the first stage boot block going. There are
two choices on how to do this. When you type "boot" for a block
device, the firmware loads 7.5K starting at the second 512-byte
block. If this block device is the third partition (the "all disk"
partition in the Sun disk label) this bootblock starts after the disk
label.
Under Linux we really can only use 512 bytes of that boot block area,
because it's possible for the filesystem superblock to show up as
early as the very next 512 byte block.
The firmware lets you put in the block some sparc executable image
(tried by the firmware as 64-bit ELF, then 32-bit ELF, and finally as
A.OUT) or tokenized forth. Since 1) we only have 512 bytes and 2)
there are no fully GPL'd forth tokenizer implementations (the openbios
folks use something that is BSD and MIT licensed) we'll need to go the
sparc image route.
The task of this 512 byte sequence of code is to load the next stage
of the bootloader. For GRUB I've choosen a multi-tiered scheme similar
to how the x86 stuff works. The first stage bootloader loads a single
block from the disk and jumps to it. This block we load is actually a
header block of the main boot loader binary, a second stage loader,
which loads the rest of the image.
This first stage loader therefore needs a few parameters. It needs to
know the OF device path where the second stage header block
resides. It needs to know the block to read, and finally it needs to
know where to load that block and thus where to jump to it for
execution.
We'd also like to print some status messages to the screen while this
happens and have at least some minimal error handling. Not a small
feat in 512 bytes.
We put everything in the text section, and the first thing we do is
jump over our embedded data bits:
.text
.align 4
.globl _start
_start:
/* OF CIF entry point arrives in %o4 */
pic_base:
call boot_continue
mov %o4, CIF_REG
The "CIF" is the client interface to openfirmware. Calls are made by
initializing an array of cells (64-bits on sparc64) in memory which
describe the call to be made, the input arguments, and the return
values (if any). This value provided in %o4 is the OF entry point we
jump to when making calls. The only register argument goes in %o0 and
is the base of the aforementioned array of cells.
The offsets into the bits coming up are defined in a GRUB boot.h
header file so that tools can patch in values during bootblock
installation.
. = _start + GRUB_BOOT_MACHINE_VER_MAJ
boot_version: .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
boot_path:
. = _start + GRUB_BOOT_MACHINE_KERNEL_ADDRESS
kernel_sector: .xword 2
kernel_address: .word GRUB_BOOT_MACHINE_KERNEL_ADDR
The boot_version is just a version blob that various tools and
sub-bootloaders could validate for compatibility if they wanted to. It
is unused currently.
The boot_path will be filled in by the boot block installation tools
with the boot device OF path. kernel_sector and kernel_address tell
where to load the image from the device into memory. Next, we have
string constants we'll need to make OF calls and put messages onto the
console:
prom_finddev_name: .asciz "finddevice"
prom_chosen_path: .asciz "/chosen"
prom_getprop_name: .asciz "getprop"
prom_stdout_name: .asciz "stdout"
prom_write_name: .asciz "write"
prom_bootpath_name: .asciz "bootpath"
prom_open_name: .asciz "open"
prom_seek_name: .asciz "seek"
prom_read_name: .asciz "read"
prom_exit_name: .asciz "exit"
grub_name: .asciz "GRUB "
To simplify things we'll write all of our code as position
independent. There are other macros in the boot.h header which
describe these register name macros such as CIF_REG, PIC_REG,
etc. most are local registers which are not volatils across OF calls,
so we can keep stable values in them. It also defines macros to
compute absolute addresses of a symbol using this PIC_REG, into a
register.
The next chunk of code are helpers for doing OF calls with various
sets of input and output arguments.
prom_open_error:
GET_ABS(prom_open_name, %o2)
call console_write
mov 4, %o3
/* fallthru */
prom_error:
GET_ABS(prom_exit_name, %o0)
/* fallthru */
/* %o0: OF call name
* %o1: input arg 1
*/
prom_call_1_1:
mov 1, %g1
ba prom_call
mov 1, %o5
/* %o2: message string
* %o3: message length
*/
console_write:
GET_ABS(prom_write_name, %o0)
mov STDOUT_NODE_REG, %o1
/* fallthru */
/* %o0: OF call name
* %o1: input arg 1
* %o2: input arg 2
* %o3: input arg 3
*/
prom_call_3_1:
mov 3, %g1
mov 1, %o5
/* fallthru */
/* %o0: OF call name
* %g1: num inputs
* %o5: num outputs
* %o1-%o4: inputs
*/
prom_call:
stx %o0, [%l1 + 0x00]
stx %g1, [%l1 + 0x08]
stx %o5, [%l1 + 0x10]
stx %o1, [%l1 + 0x18]
stx %o2, [%l1 + 0x20]
stx %o3, [%l1 + 0x28]
stx %o4, [%l1 + 0x30]
jmpl CIF_REG, %g0
mov %l1, %o0
All of those routines are "call" invoked, and we do the CIF OF call
using "jmpl" with no return register write in order to make the CIF OF
call return to the stub caller, ie. a tail call. This way we don't
need to allocate a register window here or anything complicated like
that.
Now for the code we jumped to at the _start header. Our first task is
to save away the PIC_REG (%o7 was set by the initial "call"
instruction, and will be equal to _start, we use it to reference our
data blobs PC relative). Also we setup register %l1 which holds the
base of the OF cell argument data block used above. SCRATCH_PAD is
defined to 0x10000, which is guarenteed to be mapped by OF and outside
of where we will be executing (which is at 0x4000).
boot_continue:
mov %o7, PIC_REG /* PIC base */
sethi %hi(SCRATCH_PAD), %l1 /* OF argument slots */
We need the console stdout handle to write console messages, this is
done by finding the "/chosen" directory in the OF device tree, and
fetching from there the "stdout" property which is a 32-bit handle.
GET_ABS(prom_finddev_name, %o0)
GET_ABS(prom_chosen_path, %o1)
call prom_call_1_1
clr %o2
ldx [%l1 + 0x20], CHOSEN_NODE_REG
brz CHOSEN_NODE_REG, prom_error
GET_ABS(prom_getprop_name, %o0)
mov 4, %g1
mov 1, %o5
mov CHOSEN_NODE_REG, %o1
GET_ABS(prom_stdout_name, %o2)
add %l1, 256, %o3
mov 1024, %o4
call prom_call
stx %g1, [%l1 + 256]
lduw [%l1 + 256], STDOUT_NODE_REG
brz,pn STDOUT_NODE_REG, prom_error
Since we have very little space, the error handling has to be
small. The "clr %o2" in the prom_call_1_1 invocation causes the return
value cell slot (at %l1 + 0x20) to be cleared by the prom_call
code. Zero is not a prom handle we'll get back, so if the slot stays
zero we took an error. In the getprop call to get the 'stdout' handle,
we rely upon OF providing us with zero'd memory outside of the boot
block image.
Now that we have the console output cookie, we can print out a message:
GET_ABS(grub_name, %o2)
call console_write
mov 5, %o3
Next, we open up the boot device:
GET_ABS(prom_open_name, %o0)
GET_ABS(boot_path, %o1)
call prom_call_1_1
clr %o2
ldx [%l1 + 0x20], BOOTDEV_REG
brz,pn BOOTDEV_REG, prom_open_error
We now seek to the appropriate block:
GET_ABS(prom_seek_name, %o0)
mov BOOTDEV_REG, %o1
clr %o2
LDX_ABS(kernel_sector, 0x00, %o3)
call prom_call_3_1
sllx %o3, 9, %o3
and finally read the block into memory:
GET_ABS(prom_read_name, %o0)
mov BOOTDEV_REG, %o1
LDUW_ABS(kernel_address, 0x00, %o2)
call prom_call_3_1
mov 512, %o3
This image will be an A.OUT image as well, so we jump into it right
past the A.OUT header:
LDUW_ABS(kernel_address, 0x00, %o2)
jmpl %o2 + GRUB_BOOT_AOUT_HEADER_SIZE, %o7
nop
1: ba,a 1b
Just for fun we put an endless loop after the jump in case it does
return for some reason. We could, alternatively, call prom_error
instead. Now skip to 4 bytes right before the end of the 512-byte
block and write a signature cookie.
. = _start + GRUB_BOOT_MACHINE_CODE_END
/* the last 4 bytes in the sector 0 contain the signature */
.word GRUB_BOOT_MACHINE_SIGNATURE
And that's the whole boot block implementation. This file is compiled
normally into first an ELF image using GCC. Then we strip out all the
symbols and other junk, and finally use objcopy to output an A.OUT
object. It is exactly 512 bytes in size and the bootblock installer
verifies this.
The second stage header block code now can take advantage of all of
the values the first stage has computed, such as the stdout handle,
the handle for the boot device, etc. In the second stage image, it
begins with assembler just like the first stage does above. But, it
implements a block + length tuple list which grows down from the end
of the block. This tells us where to read in the rest of the GRUB
kernel from the actual file on the disk.
The GRUB installer program links in with modules that understand how
various filesystems work. It has a block traverser that can be run on
arbitrary files. This is the mechanism used to build the block list
which is patched into this second stage loader block list.
I've tested both of these using a Sun LDOM guest, which is the fastest
way to test low-level stuff like this since resetting (which you need
to do every test boot attempt) is nearly instantaneous.
The current task is to flesh out the installer programs and make sure
the rest of the GRUB ieee1275 code is going to work properly on
sparc. I already know some bits that will need some tweaking. For
example, partitions on OF paths are indicated (aparently) by adding
":N" where N is a partition number. On sparc this "N" is instead a
letter.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: GRUB device names wrt. ieee1275
2009-03-18 21:01 ` David Miller
@ 2009-03-22 0:41 ` phcoder
2009-03-22 0:48 ` phcoder
` (2 more replies)
0 siblings, 3 replies; 18+ messages in thread
From: phcoder @ 2009-03-22 0:41 UTC (permalink / raw)
To: The development of GRUB 2
Device name in boot block will anyway be written in it's complete raw
OFW form, no matter how the rest of the grub2 accessing the disks. Using
UUIDs in this place would be nice. On IRC you said that we have 120
bytes for the name. UUID is 16 or 32 bytes depending on FS. Is it
possible to fit something like <read first sector> of every disk,
<compare data at given offset>?
I don't agree that all devices should be accessed exclusively by UUID.
It makes things difficult to maintain because of internal naming. IMO
quoting and escaping offers the best universal solution. I don't see why
sth like
(/pci@1e\,600000/pci@0/pci@9/pci@0/scsi@1/disk@0,1)
is a problem. Anyway you don't type such a thing manually and probably
use tab-completition instead
David Miller wrote:
> From: David Miller <davem@davemloft.net>
> Date: Wed, 18 Mar 2009 13:55:22 -0700 (PDT)
>
>> From: Robert Millan <rmh@aybabtu.com>
>> Date: Wed, 18 Mar 2009 11:18:46 +0100
>>
>>> On Sun, Mar 15, 2009 at 03:41:16PM -0700, David Miller wrote:
>>>> From: Robert Millan <rmh@aybabtu.com>
>>>> Date: Sun, 15 Mar 2009 16:45:31 +0100
>>>>
>>>>> It's not an absolute must that device names are unique. You can still
>>>>> identify partitions by their filesystem UUID or label, and in fact this
>>>>> is what our default scripts (grub-mkconfig) do anyway.
>>>> Things like UUID and labels are not an option for the 512-byte
>>>> boot block where I have to know the exact OBP path of the boot
>>>> device, and this is what the GRUB kernel fetches from the
>>>> 'bootpath' environment variable to compose the root device
>>>> and path.
>>> What 512-byte boot block?
>> The one I add in my sparc64 support changes.
>>
>> Included here for reference:
>
> BTW, I explained exactly how this 512 byte boot block works, in
> extreme detail, when I first posted my grub sparc64 patches.
>
> I am including it here _again_, please read it, it's informative,
> I promise, and I didn't post it the first time for my health!
>
> Thanks!
>
> --------------------
>
> The first task is to get the first stage boot block going. There are
> two choices on how to do this. When you type "boot" for a block
> device, the firmware loads 7.5K starting at the second 512-byte
> block. If this block device is the third partition (the "all disk"
> partition in the Sun disk label) this bootblock starts after the disk
> label.
>
> Under Linux we really can only use 512 bytes of that boot block area,
> because it's possible for the filesystem superblock to show up as
> early as the very next 512 byte block.
>
> The firmware lets you put in the block some sparc executable image
> (tried by the firmware as 64-bit ELF, then 32-bit ELF, and finally as
> A.OUT) or tokenized forth. Since 1) we only have 512 bytes and 2)
> there are no fully GPL'd forth tokenizer implementations (the openbios
> folks use something that is BSD and MIT licensed) we'll need to go the
> sparc image route.
>
> The task of this 512 byte sequence of code is to load the next stage
> of the bootloader. For GRUB I've choosen a multi-tiered scheme similar
> to how the x86 stuff works. The first stage bootloader loads a single
> block from the disk and jumps to it. This block we load is actually a
> header block of the main boot loader binary, a second stage loader,
> which loads the rest of the image.
>
> This first stage loader therefore needs a few parameters. It needs to
> know the OF device path where the second stage header block
> resides. It needs to know the block to read, and finally it needs to
> know where to load that block and thus where to jump to it for
> execution.
>
> We'd also like to print some status messages to the screen while this
> happens and have at least some minimal error handling. Not a small
> feat in 512 bytes.
>
> We put everything in the text section, and the first thing we do is
> jump over our embedded data bits:
>
> .text
> .align 4
> .globl _start
> _start:
> /* OF CIF entry point arrives in %o4 */
> pic_base:
> call boot_continue
> mov %o4, CIF_REG
>
> The "CIF" is the client interface to openfirmware. Calls are made by
> initializing an array of cells (64-bits on sparc64) in memory which
> describe the call to be made, the input arguments, and the return
> values (if any). This value provided in %o4 is the OF entry point we
> jump to when making calls. The only register argument goes in %o0 and
> is the base of the aforementioned array of cells.
>
> The offsets into the bits coming up are defined in a GRUB boot.h
> header file so that tools can patch in values during bootblock
> installation.
>
> . = _start + GRUB_BOOT_MACHINE_VER_MAJ
> boot_version: .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
> boot_path:
> . = _start + GRUB_BOOT_MACHINE_KERNEL_ADDRESS
> kernel_sector: .xword 2
> kernel_address: .word GRUB_BOOT_MACHINE_KERNEL_ADDR
>
> The boot_version is just a version blob that various tools and
> sub-bootloaders could validate for compatibility if they wanted to. It
> is unused currently.
>
> The boot_path will be filled in by the boot block installation tools
> with the boot device OF path. kernel_sector and kernel_address tell
> where to load the image from the device into memory. Next, we have
> string constants we'll need to make OF calls and put messages onto the
> console:
>
> prom_finddev_name: .asciz "finddevice"
> prom_chosen_path: .asciz "/chosen"
> prom_getprop_name: .asciz "getprop"
> prom_stdout_name: .asciz "stdout"
> prom_write_name: .asciz "write"
> prom_bootpath_name: .asciz "bootpath"
> prom_open_name: .asciz "open"
> prom_seek_name: .asciz "seek"
> prom_read_name: .asciz "read"
> prom_exit_name: .asciz "exit"
> grub_name: .asciz "GRUB "
>
> To simplify things we'll write all of our code as position
> independent. There are other macros in the boot.h header which
> describe these register name macros such as CIF_REG, PIC_REG,
> etc. most are local registers which are not volatils across OF calls,
> so we can keep stable values in them. It also defines macros to
> compute absolute addresses of a symbol using this PIC_REG, into a
> register.
>
> The next chunk of code are helpers for doing OF calls with various
> sets of input and output arguments.
>
> prom_open_error:
> GET_ABS(prom_open_name, %o2)
> call console_write
> mov 4, %o3
> /* fallthru */
>
> prom_error:
> GET_ABS(prom_exit_name, %o0)
> /* fallthru */
>
> /* %o0: OF call name
> * %o1: input arg 1
> */
> prom_call_1_1:
> mov 1, %g1
> ba prom_call
> mov 1, %o5
>
> /* %o2: message string
> * %o3: message length
> */
> console_write:
> GET_ABS(prom_write_name, %o0)
> mov STDOUT_NODE_REG, %o1
> /* fallthru */
>
> /* %o0: OF call name
> * %o1: input arg 1
> * %o2: input arg 2
> * %o3: input arg 3
> */
> prom_call_3_1:
> mov 3, %g1
> mov 1, %o5
> /* fallthru */
>
> /* %o0: OF call name
> * %g1: num inputs
> * %o5: num outputs
> * %o1-%o4: inputs
> */
> prom_call:
> stx %o0, [%l1 + 0x00]
> stx %g1, [%l1 + 0x08]
> stx %o5, [%l1 + 0x10]
> stx %o1, [%l1 + 0x18]
> stx %o2, [%l1 + 0x20]
> stx %o3, [%l1 + 0x28]
> stx %o4, [%l1 + 0x30]
> jmpl CIF_REG, %g0
> mov %l1, %o0
>
> All of those routines are "call" invoked, and we do the CIF OF call
> using "jmpl" with no return register write in order to make the CIF OF
> call return to the stub caller, ie. a tail call. This way we don't
> need to allocate a register window here or anything complicated like
> that.
>
> Now for the code we jumped to at the _start header. Our first task is
> to save away the PIC_REG (%o7 was set by the initial "call"
> instruction, and will be equal to _start, we use it to reference our
> data blobs PC relative). Also we setup register %l1 which holds the
> base of the OF cell argument data block used above. SCRATCH_PAD is
> defined to 0x10000, which is guarenteed to be mapped by OF and outside
> of where we will be executing (which is at 0x4000).
>
> boot_continue:
> mov %o7, PIC_REG /* PIC base */
> sethi %hi(SCRATCH_PAD), %l1 /* OF argument slots */
>
> We need the console stdout handle to write console messages, this is
> done by finding the "/chosen" directory in the OF device tree, and
> fetching from there the "stdout" property which is a 32-bit handle.
>
> GET_ABS(prom_finddev_name, %o0)
> GET_ABS(prom_chosen_path, %o1)
> call prom_call_1_1
> clr %o2
> ldx [%l1 + 0x20], CHOSEN_NODE_REG
> brz CHOSEN_NODE_REG, prom_error
> GET_ABS(prom_getprop_name, %o0)
> mov 4, %g1
> mov 1, %o5
> mov CHOSEN_NODE_REG, %o1
> GET_ABS(prom_stdout_name, %o2)
> add %l1, 256, %o3
> mov 1024, %o4
> call prom_call
> stx %g1, [%l1 + 256]
> lduw [%l1 + 256], STDOUT_NODE_REG
> brz,pn STDOUT_NODE_REG, prom_error
>
> Since we have very little space, the error handling has to be
> small. The "clr %o2" in the prom_call_1_1 invocation causes the return
> value cell slot (at %l1 + 0x20) to be cleared by the prom_call
> code. Zero is not a prom handle we'll get back, so if the slot stays
> zero we took an error. In the getprop call to get the 'stdout' handle,
> we rely upon OF providing us with zero'd memory outside of the boot
> block image.
>
> Now that we have the console output cookie, we can print out a message:
>
> GET_ABS(grub_name, %o2)
> call console_write
> mov 5, %o3
>
> Next, we open up the boot device:
>
> GET_ABS(prom_open_name, %o0)
> GET_ABS(boot_path, %o1)
> call prom_call_1_1
> clr %o2
>
> ldx [%l1 + 0x20], BOOTDEV_REG
> brz,pn BOOTDEV_REG, prom_open_error
>
> We now seek to the appropriate block:
>
> GET_ABS(prom_seek_name, %o0)
> mov BOOTDEV_REG, %o1
> clr %o2
> LDX_ABS(kernel_sector, 0x00, %o3)
> call prom_call_3_1
> sllx %o3, 9, %o3
>
> and finally read the block into memory:
>
> GET_ABS(prom_read_name, %o0)
> mov BOOTDEV_REG, %o1
> LDUW_ABS(kernel_address, 0x00, %o2)
> call prom_call_3_1
> mov 512, %o3
>
> This image will be an A.OUT image as well, so we jump into it right
> past the A.OUT header:
>
> LDUW_ABS(kernel_address, 0x00, %o2)
> jmpl %o2 + GRUB_BOOT_AOUT_HEADER_SIZE, %o7
> nop
> 1: ba,a 1b
>
> Just for fun we put an endless loop after the jump in case it does
> return for some reason. We could, alternatively, call prom_error
> instead. Now skip to 4 bytes right before the end of the 512-byte
> block and write a signature cookie.
>
> . = _start + GRUB_BOOT_MACHINE_CODE_END
>
> /* the last 4 bytes in the sector 0 contain the signature */
> .word GRUB_BOOT_MACHINE_SIGNATURE
>
> And that's the whole boot block implementation. This file is compiled
> normally into first an ELF image using GCC. Then we strip out all the
> symbols and other junk, and finally use objcopy to output an A.OUT
> object. It is exactly 512 bytes in size and the bootblock installer
> verifies this.
>
> The second stage header block code now can take advantage of all of
> the values the first stage has computed, such as the stdout handle,
> the handle for the boot device, etc. In the second stage image, it
> begins with assembler just like the first stage does above. But, it
> implements a block + length tuple list which grows down from the end
> of the block. This tells us where to read in the rest of the GRUB
> kernel from the actual file on the disk.
>
> The GRUB installer program links in with modules that understand how
> various filesystems work. It has a block traverser that can be run on
> arbitrary files. This is the mechanism used to build the block list
> which is patched into this second stage loader block list.
>
> I've tested both of these using a Sun LDOM guest, which is the fastest
> way to test low-level stuff like this since resetting (which you need
> to do every test boot attempt) is nearly instantaneous.
>
> The current task is to flesh out the installer programs and make sure
> the rest of the GRUB ieee1275 code is going to work properly on
> sparc. I already know some bits that will need some tweaking. For
> example, partitions on OF paths are indicated (aparently) by adding
> ":N" where N is a partition number. On sparc this "N" is instead a
> letter.
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
--
Regards
Vladimir 'phcoder' Serbinenko
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: GRUB device names wrt. ieee1275
2009-03-22 0:41 ` phcoder
@ 2009-03-22 0:48 ` phcoder
2009-03-22 1:57 ` David Miller
2009-03-22 1:56 ` David Miller
2009-03-22 12:22 ` Robert Millan
2 siblings, 1 reply; 18+ messages in thread
From: phcoder @ 2009-03-22 0:48 UTC (permalink / raw)
To: The development of GRUB 2
phcoder wrote:
> Device name in boot block will anyway be written in it's complete raw
> OFW form, no matter how the rest of the grub2 accessing the disks. Using
> UUIDs in this place would be nice. On IRC you said that we have 120
> bytes for the name. UUID is 16 or 32 bytes depending on FS. Is it
> possible to fit something like <read first sector> of every disk,
> <compare data at given offset>?
Could we use label checksum for finding right disk?
> I don't agree that all devices should be accessed exclusively by UUID.
> It makes things difficult to maintain because of internal naming. IMO
> quoting and escaping offers the best universal solution. I don't see why
> sth like
> (/pci@1e\,600000/pci@0/pci@9/pci@0/scsi@1/disk@0,1)
> is a problem. Anyway you don't type such a thing manually and probably
> use tab-completition instead
>
>
> David Miller wrote:
>> From: David Miller <davem@davemloft.net>
>> Date: Wed, 18 Mar 2009 13:55:22 -0700 (PDT)
>>
>>> From: Robert Millan <rmh@aybabtu.com>
>>> Date: Wed, 18 Mar 2009 11:18:46 +0100
>>>
>>>> On Sun, Mar 15, 2009 at 03:41:16PM -0700, David Miller wrote:
>>>>> From: Robert Millan <rmh@aybabtu.com>
>>>>> Date: Sun, 15 Mar 2009 16:45:31 +0100
>>>>>
>>>>>> It's not an absolute must that device names are unique. You can
>>>>>> still
>>>>>> identify partitions by their filesystem UUID or label, and in fact
>>>>>> this
>>>>>> is what our default scripts (grub-mkconfig) do anyway.
>>>>> Things like UUID and labels are not an option for the 512-byte
>>>>> boot block where I have to know the exact OBP path of the boot
>>>>> device, and this is what the GRUB kernel fetches from the
>>>>> 'bootpath' environment variable to compose the root device
>>>>> and path.
>>>> What 512-byte boot block?
>>> The one I add in my sparc64 support changes.
>>>
>>> Included here for reference:
>>
>> BTW, I explained exactly how this 512 byte boot block works, in
>> extreme detail, when I first posted my grub sparc64 patches.
>>
>> I am including it here _again_, please read it, it's informative,
>> I promise, and I didn't post it the first time for my health!
>>
>> Thanks!
>>
>> --------------------
>>
>> The first task is to get the first stage boot block going. There are
>> two choices on how to do this. When you type "boot" for a block
>> device, the firmware loads 7.5K starting at the second 512-byte
>> block. If this block device is the third partition (the "all disk"
>> partition in the Sun disk label) this bootblock starts after the disk
>> label.
>>
>> Under Linux we really can only use 512 bytes of that boot block area,
>> because it's possible for the filesystem superblock to show up as
>> early as the very next 512 byte block.
>>
>> The firmware lets you put in the block some sparc executable image
>> (tried by the firmware as 64-bit ELF, then 32-bit ELF, and finally as
>> A.OUT) or tokenized forth. Since 1) we only have 512 bytes and 2)
>> there are no fully GPL'd forth tokenizer implementations (the openbios
>> folks use something that is BSD and MIT licensed) we'll need to go the
>> sparc image route.
>>
>> The task of this 512 byte sequence of code is to load the next stage
>> of the bootloader. For GRUB I've choosen a multi-tiered scheme similar
>> to how the x86 stuff works. The first stage bootloader loads a single
>> block from the disk and jumps to it. This block we load is actually a
>> header block of the main boot loader binary, a second stage loader,
>> which loads the rest of the image.
>>
>> This first stage loader therefore needs a few parameters. It needs to
>> know the OF device path where the second stage header block
>> resides. It needs to know the block to read, and finally it needs to
>> know where to load that block and thus where to jump to it for
>> execution.
>>
>> We'd also like to print some status messages to the screen while this
>> happens and have at least some minimal error handling. Not a small
>> feat in 512 bytes.
>>
>> We put everything in the text section, and the first thing we do is
>> jump over our embedded data bits:
>>
>> .text
>> .align 4
>> .globl _start
>> _start:
>> /* OF CIF entry point arrives in %o4 */
>> pic_base:
>> call boot_continue
>> mov %o4, CIF_REG
>>
>> The "CIF" is the client interface to openfirmware. Calls are made by
>> initializing an array of cells (64-bits on sparc64) in memory which
>> describe the call to be made, the input arguments, and the return
>> values (if any). This value provided in %o4 is the OF entry point we
>> jump to when making calls. The only register argument goes in %o0 and
>> is the base of the aforementioned array of cells.
>>
>> The offsets into the bits coming up are defined in a GRUB boot.h
>> header file so that tools can patch in values during bootblock
>> installation.
>>
>> . = _start + GRUB_BOOT_MACHINE_VER_MAJ
>> boot_version: .byte GRUB_BOOT_VERSION_MAJOR,
>> GRUB_BOOT_VERSION_MINOR
>> boot_path:
>> . = _start + GRUB_BOOT_MACHINE_KERNEL_ADDRESS
>> kernel_sector: .xword 2
>> kernel_address: .word GRUB_BOOT_MACHINE_KERNEL_ADDR
>>
>> The boot_version is just a version blob that various tools and
>> sub-bootloaders could validate for compatibility if they wanted to. It
>> is unused currently.
>>
>> The boot_path will be filled in by the boot block installation tools
>> with the boot device OF path. kernel_sector and kernel_address tell
>> where to load the image from the device into memory. Next, we have
>> string constants we'll need to make OF calls and put messages onto the
>> console:
>>
>> prom_finddev_name: .asciz "finddevice"
>> prom_chosen_path: .asciz "/chosen"
>> prom_getprop_name: .asciz "getprop"
>> prom_stdout_name: .asciz "stdout"
>> prom_write_name: .asciz "write"
>> prom_bootpath_name: .asciz "bootpath"
>> prom_open_name: .asciz "open"
>> prom_seek_name: .asciz "seek"
>> prom_read_name: .asciz "read"
>> prom_exit_name: .asciz "exit"
>> grub_name: .asciz "GRUB "
>>
>> To simplify things we'll write all of our code as position
>> independent. There are other macros in the boot.h header which
>> describe these register name macros such as CIF_REG, PIC_REG,
>> etc. most are local registers which are not volatils across OF calls,
>> so we can keep stable values in them. It also defines macros to
>> compute absolute addresses of a symbol using this PIC_REG, into a
>> register.
>>
>> The next chunk of code are helpers for doing OF calls with various
>> sets of input and output arguments.
>>
>> prom_open_error:
>> GET_ABS(prom_open_name, %o2)
>> call console_write
>> mov 4, %o3
>> /* fallthru */
>>
>> prom_error:
>> GET_ABS(prom_exit_name, %o0)
>> /* fallthru */
>>
>> /* %o0: OF call name
>> * %o1: input arg 1
>> */
>> prom_call_1_1:
>> mov 1, %g1
>> ba prom_call
>> mov 1, %o5
>>
>> /* %o2: message string
>> * %o3: message length
>> */
>> console_write:
>> GET_ABS(prom_write_name, %o0)
>> mov STDOUT_NODE_REG, %o1
>> /* fallthru */
>>
>> /* %o0: OF call name
>> * %o1: input arg 1
>> * %o2: input arg 2
>> * %o3: input arg 3
>> */
>> prom_call_3_1:
>> mov 3, %g1
>> mov 1, %o5
>> /* fallthru */
>>
>> /* %o0: OF call name
>> * %g1: num inputs
>> * %o5: num outputs
>> * %o1-%o4: inputs
>> */
>> prom_call:
>> stx %o0, [%l1 + 0x00]
>> stx %g1, [%l1 + 0x08]
>> stx %o5, [%l1 + 0x10]
>> stx %o1, [%l1 + 0x18]
>> stx %o2, [%l1 + 0x20]
>> stx %o3, [%l1 + 0x28]
>> stx %o4, [%l1 + 0x30]
>> jmpl CIF_REG, %g0
>> mov %l1, %o0
>>
>> All of those routines are "call" invoked, and we do the CIF OF call
>> using "jmpl" with no return register write in order to make the CIF OF
>> call return to the stub caller, ie. a tail call. This way we don't
>> need to allocate a register window here or anything complicated like
>> that.
>>
>> Now for the code we jumped to at the _start header. Our first task is
>> to save away the PIC_REG (%o7 was set by the initial "call"
>> instruction, and will be equal to _start, we use it to reference our
>> data blobs PC relative). Also we setup register %l1 which holds the
>> base of the OF cell argument data block used above. SCRATCH_PAD is
>> defined to 0x10000, which is guarenteed to be mapped by OF and outside
>> of where we will be executing (which is at 0x4000).
>>
>> boot_continue:
>> mov %o7, PIC_REG /* PIC base */
>> sethi %hi(SCRATCH_PAD), %l1 /* OF argument slots */
>>
>> We need the console stdout handle to write console messages, this is
>> done by finding the "/chosen" directory in the OF device tree, and
>> fetching from there the "stdout" property which is a 32-bit handle.
>>
>> GET_ABS(prom_finddev_name, %o0)
>> GET_ABS(prom_chosen_path, %o1)
>> call prom_call_1_1
>> clr %o2
>> ldx [%l1 + 0x20], CHOSEN_NODE_REG
>> brz CHOSEN_NODE_REG, prom_error
>> GET_ABS(prom_getprop_name, %o0)
>> mov 4, %g1
>> mov 1, %o5
>> mov CHOSEN_NODE_REG, %o1
>> GET_ABS(prom_stdout_name, %o2)
>> add %l1, 256, %o3
>> mov 1024, %o4
>> call prom_call
>> stx %g1, [%l1 + 256]
>> lduw [%l1 + 256], STDOUT_NODE_REG
>> brz,pn STDOUT_NODE_REG, prom_error
>>
>> Since we have very little space, the error handling has to be
>> small. The "clr %o2" in the prom_call_1_1 invocation causes the return
>> value cell slot (at %l1 + 0x20) to be cleared by the prom_call
>> code. Zero is not a prom handle we'll get back, so if the slot stays
>> zero we took an error. In the getprop call to get the 'stdout' handle,
>> we rely upon OF providing us with zero'd memory outside of the boot
>> block image.
>>
>> Now that we have the console output cookie, we can print out a message:
>>
>> GET_ABS(grub_name, %o2)
>> call console_write
>> mov 5, %o3
>>
>> Next, we open up the boot device:
>>
>> GET_ABS(prom_open_name, %o0)
>> GET_ABS(boot_path, %o1)
>> call prom_call_1_1
>> clr %o2
>>
>> ldx [%l1 + 0x20], BOOTDEV_REG
>> brz,pn BOOTDEV_REG, prom_open_error
>>
>> We now seek to the appropriate block:
>>
>> GET_ABS(prom_seek_name, %o0)
>> mov BOOTDEV_REG, %o1
>> clr %o2
>> LDX_ABS(kernel_sector, 0x00, %o3)
>> call prom_call_3_1
>> sllx %o3, 9, %o3
>>
>> and finally read the block into memory:
>>
>> GET_ABS(prom_read_name, %o0)
>> mov BOOTDEV_REG, %o1
>> LDUW_ABS(kernel_address, 0x00, %o2)
>> call prom_call_3_1
>> mov 512, %o3
>>
>> This image will be an A.OUT image as well, so we jump into it right
>> past the A.OUT header:
>>
>> LDUW_ABS(kernel_address, 0x00, %o2)
>> jmpl %o2 + GRUB_BOOT_AOUT_HEADER_SIZE, %o7
>> nop
>> 1: ba,a 1b
>>
>> Just for fun we put an endless loop after the jump in case it does
>> return for some reason. We could, alternatively, call prom_error
>> instead. Now skip to 4 bytes right before the end of the 512-byte
>> block and write a signature cookie.
>>
>> . = _start + GRUB_BOOT_MACHINE_CODE_END
>>
>> /* the last 4 bytes in the sector 0 contain the signature */
>> .word GRUB_BOOT_MACHINE_SIGNATURE
>>
>> And that's the whole boot block implementation. This file is compiled
>> normally into first an ELF image using GCC. Then we strip out all the
>> symbols and other junk, and finally use objcopy to output an A.OUT
>> object. It is exactly 512 bytes in size and the bootblock installer
>> verifies this.
>>
>> The second stage header block code now can take advantage of all of
>> the values the first stage has computed, such as the stdout handle,
>> the handle for the boot device, etc. In the second stage image, it
>> begins with assembler just like the first stage does above. But, it
>> implements a block + length tuple list which grows down from the end
>> of the block. This tells us where to read in the rest of the GRUB
>> kernel from the actual file on the disk.
>>
>> The GRUB installer program links in with modules that understand how
>> various filesystems work. It has a block traverser that can be run on
>> arbitrary files. This is the mechanism used to build the block list
>> which is patched into this second stage loader block list.
>>
>> I've tested both of these using a Sun LDOM guest, which is the fastest
>> way to test low-level stuff like this since resetting (which you need
>> to do every test boot attempt) is nearly instantaneous.
>>
>> The current task is to flesh out the installer programs and make sure
>> the rest of the GRUB ieee1275 code is going to work properly on
>> sparc. I already know some bits that will need some tweaking. For
>> example, partitions on OF paths are indicated (aparently) by adding
>> ":N" where N is a partition number. On sparc this "N" is instead a
>> letter.
>>
>>
>> _______________________________________________
>> Grub-devel mailing list
>> Grub-devel@gnu.org
>> http://lists.gnu.org/mailman/listinfo/grub-devel
>
>
--
Regards
Vladimir 'phcoder' Serbinenko
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: GRUB device names wrt. ieee1275
2009-03-22 0:41 ` phcoder
2009-03-22 0:48 ` phcoder
@ 2009-03-22 1:56 ` David Miller
[not found] ` <49C61E3D.3040901@gmail.com>
2009-03-22 12:22 ` Robert Millan
2 siblings, 1 reply; 18+ messages in thread
From: David Miller @ 2009-03-22 1:56 UTC (permalink / raw)
To: grub-devel, phcoder
From: phcoder <phcoder@gmail.com>
Date: Sun, 22 Mar 2009 01:41:52 +0100
> Device name in boot block will anyway be written in it's complete
> raw OFW form, no matter how the rest of the grub2 accessing the
> disks. Using UUIDs in this place would be nice. On IRC you said that
> we have 120 bytes for the name. UUID is 16 or 32 bytes depending on
> FS. Is it possible to fit something like <read first sector> of
> every disk, <compare data at given offset>?
This is possible, but I know that Solaris folks would like to use the
Sparc GRUB support I'm writing and I'm not so sure whether they have
FS UUIDs or not.
> I don't agree that all devices should be accessed exclusively by
> UUID. It makes things difficult to maintain because of internal
> naming. IMO quoting and escaping offers the best universal
> solution. I don't see why sth like
> (/pci@1e\,600000/pci@0/pci@9/pci@0/scsi@1/disk@0,1) is a
> problem. Anyway you don't type such a thing manually and probably
> use tab-completition instead
We could use escaping, sure.
Actually most of the time users use device aliases, however:
1) GRUB should work when a device lacks a alias.
2) GRUB should keep working even if the user deletes one of
the aliases.
While convenient I'm not so sure that OF device aliases are
a good basis for the names GRUB should use because they are
by their very nature transient.
It does take quite a bit of effort to translate between different
OS device naming formats into OF native ones. So whatever universal
naming convention is choosen, it should be such that it can be
mechanically and statelessly converted to OF.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: GRUB device names wrt. ieee1275
2009-03-22 0:48 ` phcoder
@ 2009-03-22 1:57 ` David Miller
0 siblings, 0 replies; 18+ messages in thread
From: David Miller @ 2009-03-22 1:57 UTC (permalink / raw)
To: grub-devel, phcoder
From: phcoder <phcoder@gmail.com>
Date: Sun, 22 Mar 2009 01:48:14 +0100
> phcoder wrote:
> > Device name in boot block will anyway be written in it's complete raw OFW form, no matter how the rest of the grub2 accessing the disks. Using UUIDs in this place would be nice. On IRC you said that we have 120 bytes for the name. UUID is 16 or 32 bytes depending on FS. Is it possible to fit something like <read first sector> of every disk, <compare data at given offset>?
> Could we use label checksum for finding right disk?
And if I reconfigure or add a partition I have to rerun grub-install ?
I don't think that's a friendly usage model.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: GRUB device names wrt. ieee1275
2009-03-22 0:41 ` phcoder
2009-03-22 0:48 ` phcoder
2009-03-22 1:56 ` David Miller
@ 2009-03-22 12:22 ` Robert Millan
2009-03-23 4:23 ` David Miller
2 siblings, 1 reply; 18+ messages in thread
From: Robert Millan @ 2009-03-22 12:22 UTC (permalink / raw)
To: The development of GRUB 2
On Sun, Mar 22, 2009 at 01:41:52AM +0100, phcoder wrote:
> I don't see why
> sth like
> (/pci@1e\,600000/pci@0/pci@9/pci@0/scsi@1/disk@0,1)
> is a problem.
FWIW, I like this much better than replacing our comma separator with
something else, thereby making GRUB inconsistent among platforms.
I'll see if I can read the whole thread and think if there can be other
solutions, but can't do it today. Maybe wednesday or next weekend.
--
Robert Millan
The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
how) you may access your data; but nobody's threatening your freedom: we
still allow you to remove your data and not access it at all."
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: GRUB device names wrt. ieee1275
[not found] ` <20090322.153022.233646325.davem@davemloft.net>
@ 2009-03-22 22:51 ` phcoder
2009-03-23 1:13 ` David Miller
0 siblings, 1 reply; 18+ messages in thread
From: phcoder @ 2009-03-22 22:51 UTC (permalink / raw)
To: David Miller, The development of GRUB 2
You could do it the way similar to how it's done on i386-pc:
jmp use_hardcoded
<code to retrieve boot block path>
use_hardcoded:
And then the grub-setup tool nops out the first jump if stage2 resides
on a disk different than where bootblock is
David Miller wrote:
> From: phcoder <phcoder@gmail.com>
> Date: Sun, 22 Mar 2009 12:17:17 +0100
>
>> As for the boot block I would prefer to acquire bootpath from OFW
>> instead of hardcoding in the boot sector. It has an obvious
>> advantage of e.g. USB booting even if no "usb" alias is defined. Is
>> it possible? (It seems it is but I'm not familiar with OFW yet,
>> looking at nvram is a bad idea because user may manually boot
>> another device from OFW console)
>
> You can obtain the disk where the boot block was loaded from but with
> GRUB that can be miles away from where the second stage boot block and
> rest of the GRUB kernel reside.
>
> I've been through this thought process already, that's why I've
> designed it this way with the full path encoded into the first stage
> boot block.
--
Regards
Vladimir 'phcoder' Serbinenko
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: GRUB device names wrt. ieee1275
2009-03-22 22:51 ` phcoder
@ 2009-03-23 1:13 ` David Miller
0 siblings, 0 replies; 18+ messages in thread
From: David Miller @ 2009-03-23 1:13 UTC (permalink / raw)
To: phcoder; +Cc: grub-devel
From: phcoder <phcoder@gmail.com>
Date: Sun, 22 Mar 2009 23:51:14 +0100
> You could do it the way similar to how it's done on i386-pc:
> jmp use_hardcoded
> <code to retrieve boot block path>
> use_hardcoded:
> And then the grub-setup tool nops out the first jump if stage2
> resides on a disk different than where bootblock is
Sure we could do that.
But I'm trying to figure out why to bother with this if I
already have all of the (tested) logic and infrastructure to
fill in the device path already?
It just seems like another case in the matrix which needs to
be tested, and can thus go wrong.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: GRUB device names wrt. ieee1275
2009-03-22 12:22 ` Robert Millan
@ 2009-03-23 4:23 ` David Miller
0 siblings, 0 replies; 18+ messages in thread
From: David Miller @ 2009-03-23 4:23 UTC (permalink / raw)
To: grub-devel, rmh
From: Robert Millan <rmh@aybabtu.com>
Date: Sun, 22 Mar 2009 13:22:34 +0100
> On Sun, Mar 22, 2009 at 01:41:52AM +0100, phcoder wrote:
> > I don't see why
> > sth like
> > (/pci@1e\,600000/pci@0/pci@9/pci@0/scsi@1/disk@0,1)
> > is a problem.
>
> FWIW, I like this much better than replacing our comma separator with
> something else, thereby making GRUB inconsistent among platforms.
I'm fine with this kind of scheme too.
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2009-03-23 4:23 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-14 22:14 GRUB device names wrt. ieee1275 David Miller
2009-03-14 23:44 ` phcoder
2009-03-15 5:24 ` David Miller
2009-03-15 9:22 ` Vesa Jääskeläinen
2009-03-15 22:52 ` David Miller
2009-03-15 15:45 ` Robert Millan
2009-03-15 22:41 ` David Miller
2009-03-18 10:18 ` Robert Millan
2009-03-18 20:55 ` David Miller
2009-03-18 21:01 ` David Miller
2009-03-22 0:41 ` phcoder
2009-03-22 0:48 ` phcoder
2009-03-22 1:57 ` David Miller
2009-03-22 1:56 ` David Miller
[not found] ` <49C61E3D.3040901@gmail.com>
[not found] ` <20090322.153022.233646325.davem@davemloft.net>
2009-03-22 22:51 ` phcoder
2009-03-23 1:13 ` David Miller
2009-03-22 12:22 ` Robert Millan
2009-03-23 4:23 ` David Miller
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.