Hi! Attaching an updated patch for the current 2.02-2 package.
I am working now on integrating GRUB for sparc and sparc64 in debian-installer and upstream has gotten new maintainers who have promised to get the sparc64 patches merged soonish [1]. Adrian > [1] http://lists.gnu.org/archive/html/grub-devel/2017-09/msg00086.html -- .''`. John Paul Adrian Glaubitz : :' : Debian Developer - glaub...@debian.org `. `' Freie Universitaet Berlin - glaub...@physik.fu-berlin.de `- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913
Description: Add support for sparc64 Author: Eric Snowberg <eric.snowb...@oracle.com> Last-Update: 2017-09-29 Source: https://github.com/esnowberg/grub2-sparc/tree/sparc-next-v4 Index: grub2-2.02/grub-core/Makefile.core.def =================================================================== --- grub2-2.02.orig/grub-core/Makefile.core.def +++ grub2-2.02/grub-core/Makefile.core.def @@ -270,6 +270,7 @@ kernel = { sparc64_ieee1275 = kern/sparc64/cache.S; sparc64_ieee1275 = kern/sparc64/dl.c; sparc64_ieee1275 = kern/sparc64/ieee1275/ieee1275.c; + sparc64_ieee1275 = disk/ieee1275/obdisk.c; arm = kern/arm/dl.c; arm = kern/arm/dl_helper.c; Index: grub2-2.02/grub-core/boot/sparc64/ieee1275/boot.S =================================================================== --- grub2-2.02.orig/grub-core/boot/sparc64/ieee1275/boot.S +++ grub2-2.02/grub-core/boot/sparc64/ieee1275/boot.S @@ -69,6 +69,10 @@ prom_seek_name: .asciz "seek" prom_read_name: .asciz "read" prom_exit_name: .asciz "exit" grub_name: .asciz "GRUB " +#ifdef CDBOOT +prom_close_name: .asciz "close" +#endif + #define GRUB_NAME_LEN 5 .align 4 @@ -213,6 +217,12 @@ bootpath_known: call prom_call_3_1_o1 #ifdef CDBOOT LDUW_ABS(kernel_size, 0x00, %o3) + + GET_ABS(prom_close_name, %o0) + mov 1, %g1 + mov 0, %o5 + call prom_call + mov BOOTDEV_REG, %o1 #else mov 512, %o3 #endif Index: grub2-2.02/grub-core/commands/ls.c =================================================================== --- grub2-2.02.orig/grub-core/commands/ls.c +++ grub2-2.02/grub-core/commands/ls.c @@ -201,6 +201,8 @@ grub_ls_list_files (char *dirname, int l if (grub_errno == GRUB_ERR_UNKNOWN_FS) grub_errno = GRUB_ERR_NONE; + grub_device_close (dev); + dev = NULL; grub_normal_print_device_info (device_name); } else if (fs) Index: grub2-2.02/grub-core/commands/nativedisk.c =================================================================== --- grub2-2.02.orig/grub-core/commands/nativedisk.c +++ grub2-2.02/grub-core/commands/nativedisk.c @@ -66,6 +66,7 @@ get_uuid (const char *name, char **uuid, /* Firmware disks. */ case GRUB_DISK_DEVICE_BIOSDISK_ID: case GRUB_DISK_DEVICE_OFDISK_ID: + case GRUB_DISK_DEVICE_OBDISK_ID: case GRUB_DISK_DEVICE_EFIDISK_ID: case GRUB_DISK_DEVICE_NAND_ID: case GRUB_DISK_DEVICE_ARCDISK_ID: Index: grub2-2.02/grub-core/disk/ieee1275/obdisk.c =================================================================== --- /dev/null +++ grub2-2.02/grub-core/disk/ieee1275/obdisk.c @@ -0,0 +1,1079 @@ +/* obdisk.c - Open Boot disk access. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2017 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/disk.h> +#include <grub/env.h> +#include <grub/i18n.h> +#include <grub/kernel.h> +#include <grub/list.h> +#include <grub/misc.h> +#include <grub/mm.h> +#include <grub/scsicmd.h> +#include <grub/time.h> +#include <grub/ieee1275/ieee1275.h> +#include <grub/ieee1275/obdisk.h> + +struct disk_dev +{ + struct disk_dev *next; + struct disk_dev **prev; + /* open boot canonical name */ + char *name; + /* open boot raw disk name to access entire disk */ + char *raw_name; + /* grub encoded device name */ + char *grub_devpath; + /* grub encoded alias name */ + char *grub_alias_devpath; + /* grub unescaped name */ + char *grub_decoded_devpath; + grub_ieee1275_ihandle_t ihandle; + grub_uint32_t block_size; + grub_uint64_t num_blocks; + unsigned int log_sector_size; + grub_uint32_t opened; + grub_uint32_t valid; + grub_uint32_t boot_dev; +}; + +struct parent_dev +{ + struct parent_dev *next; + struct parent_dev **prev; + /* canonical parent name */ + char *name; + char *type; + grub_ieee1275_ihandle_t ihandle; + grub_uint32_t address_cells; +}; + +static struct grub_scsi_test_unit_ready tur = +{ + .opcode = grub_scsi_cmd_test_unit_ready, + .lun = 0, + .reserved1 = 0, + .reserved2 = 0, + .reserved3 = 0, + .control = 0, +}; + +static int disks_enumerated = 0; +static struct disk_dev *disk_devs = NULL; +static struct parent_dev *parent_devs = NULL; + +static const char *block_blacklist[] = { + /* Requires addition work in grub before being able to be used */ + "/iscsi-hba", + /* This block device should never be used by grub */ + "/reboot-memory@0", + 0 +}; + +#define STRCMP(a, b) ((a) && (b) && (grub_strcmp (a, b) == 0)) + +static char * +strip_ob_partition (char *path) +{ + char *sptr; + + sptr = grub_strstr (path, ":"); + + if (sptr) + *sptr = '\0'; + + return path; +} + +static char * +remove_escaped_commas (char *src) +{ + char *iptr; + + for (iptr = src; *iptr; ) + { + if ((*iptr == '\\') && (*(iptr + 1) == ',')) + { + *iptr++ = '_'; + *iptr++ = '_'; + } + iptr++; + } + + return src; +} + +static int +count_commas (const char *src) +{ + int count = 0; + + for ( ; *src; src++) + if (*src == ',') + count++; + + return count; +} + +static void +escape_commas (const char *src, char *dest) +{ + const char *iptr; + + for (iptr = src; *iptr; ) + { + if (*iptr == ',') + *dest++ ='\\'; + + *dest++ = *iptr++; + } + + *dest = '\0'; +} + +static char * +decode_grub_devname (const char *name) +{ + char *devpath = grub_malloc (grub_strlen (name) + 1); + char *p, c; + + if (!devpath) + return NULL; + + /* Un-escape commas. */ + p = devpath; + while ((c = *name++) != '\0') + { + if (c == '\\' && *name == ',') + { + *p++ = ','; + name++; + } + else + *p++ = c; + } + + *p++ = '\0'; + + return devpath; +} + +static char * +encode_grub_devname (const char *path) +{ + char *encoding, *optr; + + if (path == NULL) + return NULL; + + encoding = grub_malloc (sizeof ("ieee1275/") + count_commas (path) + + grub_strlen (path) + 1); + + if (encoding == NULL) + { + grub_print_error (); + return NULL; + } + + optr = grub_stpcpy (encoding, "ieee1275/"); + escape_commas (path, optr); + return encoding; +} + +static char * +get_parent_devname (const char *devname) +{ + char *parent, *pptr; + + parent = grub_strdup (devname); + + if (parent == NULL) + { + grub_print_error (); + return NULL; + } + + pptr = grub_strstr (parent, "/disk@"); + + if (pptr) + *pptr = '\0'; + + return parent; +} + +static void +free_parent_dev (struct parent_dev *parent) +{ + if (parent) + { + grub_free (parent->name); + grub_free (parent->type); + grub_free (parent); + } +} + +static struct parent_dev * +init_parent (const char *parent) +{ + struct parent_dev *op; + + op = grub_zalloc (sizeof (struct parent_dev)); + + if (op == NULL) + { + grub_print_error (); + return NULL; + } + + op->name = grub_strdup (parent); + op->type = grub_malloc (IEEE1275_MAX_PROP_LEN); + + if ((op->name == NULL) || (op->type == NULL)) + { + grub_print_error (); + free_parent_dev (op); + return NULL; + } + + return op; +} + +static struct parent_dev * +open_new_parent (const char *parent) +{ + struct parent_dev *op = init_parent(parent); + grub_ieee1275_ihandle_t ihandle; + grub_ieee1275_phandle_t phandle; + grub_uint32_t address_cells = 2; + grub_ssize_t actual = 0; + + if (op == NULL) + return NULL; + + grub_ieee1275_open (parent, &ihandle); + + if (ihandle == 0) + { + grub_error (GRUB_ERR_BAD_DEVICE, "unable to open %s", parent); + grub_print_error (); + free_parent_dev (op); + return NULL; + } + + if (grub_ieee1275_instance_to_package (ihandle, &phandle)) + { + grub_error (GRUB_ERR_BAD_DEVICE, "unable to get parent %s", parent); + grub_print_error (); + free_parent_dev (op); + return NULL; + } + + /* IEEE Std 1275-1994 page 110: A missing â#address-cellsâ property + signifies that the number of address cells is two. So ignore on error. */ + grub_ieee1275_get_integer_property (phandle, "#address-cells", &address_cells, + sizeof (address_cells), 0); + + grub_ieee1275_get_property (phandle, "device_type", op->type, + IEEE1275_MAX_PROP_LEN, &actual); + op->ihandle = ihandle; + op->address_cells = address_cells; + return op; +} + +static struct parent_dev * +open_parent (const char *parent) +{ + struct parent_dev *op; + + if ((op = + grub_named_list_find (GRUB_AS_NAMED_LIST (parent_devs), parent)) == NULL) + { + op = open_new_parent (parent); + + if (op) + grub_list_push (GRUB_AS_LIST_P (&parent_devs), GRUB_AS_LIST (op)); + } + + return op; +} + +static void +display_parents (void) +{ + struct parent_dev *parent; + + grub_printf ("-------------------- PARENTS --------------------\n"); + + FOR_LIST_ELEMENTS (parent, parent_devs) + { + grub_printf ("name: %s\n", parent->name); + grub_printf ("type: %s\n", parent->type); + grub_printf ("address_cells %x\n", parent->address_cells); + } + + grub_printf ("-------------------------------------------------\n"); +} + +static char * +canonicalise_4cell_ua (grub_ieee1275_ihandle_t ihandle, char *unit_address) +{ + grub_uint32_t phy_lo, phy_hi, lun_lo, lun_hi; + int valid_phy = 0; + grub_size_t size; + char *canon = NULL; + + valid_phy = grub_ieee1275_decode_unit4 (ihandle, unit_address, + grub_strlen (unit_address), &phy_lo, + &phy_hi, &lun_lo, &lun_hi); + + if ((!valid_phy) && (phy_hi != 0xffffffff)) + canon = grub_ieee1275_encode_uint4 (ihandle, phy_lo, phy_hi, + lun_lo, lun_hi, &size); + + return canon; +} + +static char * +canonicalise_disk (const char *devname) +{ + char *canon, *parent; + struct parent_dev *op; + + canon = grub_ieee1275_canonicalise_devname (devname); + + if (canon == NULL) + { + /* This should not happen */ + grub_error (GRUB_ERR_BAD_DEVICE, "canonicalise devname failed"); + grub_print_error (); + return NULL; + } + + /* Don't try to open the parent of a virtual device */ + if (grub_strstr (canon, "virtual-devices")) + return canon; + + parent = get_parent_devname (canon); + + if (parent == NULL) + return NULL; + + op = open_parent (parent); + + /* Devices with 4 address cells can have many different types of addressing + (phy, wwn, and target lun). Use the parents encode-unit / decode-unit + to find the true canonical name. */ + if ((op) && (op->address_cells == 4)) + { + char *unit_address, *real_unit_address, *real_canon; + + unit_address = grub_strstr (canon, "/disk@"); + unit_address += grub_strlen ("/disk@"); + + if (unit_address == NULL) + { + /* This should not be possible, but return the canonical name for + the non-disk block device */ + grub_free (parent); + return (canon); + } + + real_unit_address = canonicalise_4cell_ua (op->ihandle, unit_address); + + if (real_unit_address == NULL) + { + /* This is not an error, since this function could be called with a devalias + containing a drive that isn't installed in the system. */ + grub_free (parent); + return NULL; + } + + real_canon = grub_malloc (grub_strlen (op->name) + sizeof ("/disk@") + + grub_strlen (real_unit_address)); + + grub_snprintf (real_canon, grub_strlen (op->name) + sizeof ("/disk@") + + grub_strlen (real_unit_address), "%s/disk@%s", + op->name, real_unit_address); + + grub_free (canon); + canon = real_canon; + } + + grub_free (parent); + return (canon); +} + +static struct disk_dev * +add_canon_disk (const char *cname) +{ + struct disk_dev *dev; + + dev = grub_zalloc (sizeof (struct disk_dev)); + + if (!dev) + goto failed; + + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_RAW_DEVNAMES)) + { + /* Append :nolabel to the end of all SPARC disks. + + nolabel is mutually exclusive with all other + arguments and allows a client program to open + the entire (raw) disk. Any disk label is ignored. */ + dev->raw_name = grub_malloc (grub_strlen (cname) + sizeof (":nolabel")); + + if (dev->raw_name == NULL) + goto failed; + + grub_snprintf (dev->raw_name, grub_strlen (cname) + sizeof (":nolabel"), + "%s:nolabel", cname); + } + + /* Don't use grub_ieee1275_encode_devname here, the devpath in grub.cfg doesn't + understand device aliases, which the layer above sometimes sends us. */ + dev->grub_devpath = encode_grub_devname(cname); + + if (dev->grub_devpath == NULL) + goto failed; + + dev->name = grub_strdup (cname); + + if (dev->name == NULL) + goto failed; + + dev->valid = 1; + grub_list_push (GRUB_AS_LIST_P (&disk_devs), GRUB_AS_LIST (dev)); + return dev; + +failed: + grub_print_error (); + + if (dev) + { + grub_free (dev->name); + grub_free (dev->grub_devpath); + grub_free (dev->raw_name); + } + + grub_free (dev); + return NULL; +} + +static grub_err_t +add_disk (const char *path) +{ + grub_err_t rval = GRUB_ERR_NONE; + struct disk_dev *dev; + char *canon; + + canon = canonicalise_disk (path); + dev = grub_named_list_find (GRUB_AS_NAMED_LIST (disk_devs), canon); + + if ((canon != NULL) && (dev == NULL)) + { + struct disk_dev *ob_device; + + ob_device = add_canon_disk (canon); + + if (ob_device == NULL) + rval = grub_error (GRUB_ERR_OUT_OF_MEMORY, "failure to add disk"); + } + else if (dev) + dev->valid = 1; + + grub_free (canon); + return (rval); +} + +static grub_err_t +grub_obdisk_read (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, char *dest) +{ + grub_err_t rval = GRUB_ERR_NONE; + struct disk_dev *dev; + unsigned long long pos; + grub_ssize_t result = 0; + + if (disk->data == NULL) + return grub_error (GRUB_ERR_BAD_DEVICE, "invalid disk data"); + + dev = (struct disk_dev *)disk->data; + pos = sector << disk->log_sector_size; + grub_ieee1275_seek (dev->ihandle, pos, &result); + + if (result < 0) + { + dev->opened = 0; + return grub_error (GRUB_ERR_READ_ERROR, "seek error, can't seek block %llu", + (long long) sector); + } + + grub_ieee1275_read (dev->ihandle, dest, size << disk->log_sector_size, + &result); + + if (result != (grub_ssize_t) (size << disk->log_sector_size)) + { + dev->opened = 0; + return grub_error (GRUB_ERR_READ_ERROR, N_("failure reading sector 0x%llx " + "from `%s'"), + (unsigned long long) sector, + disk->name); + } + return rval; +} + +static void +grub_obdisk_close (grub_disk_t disk) +{ + disk->data = NULL; + disk->id = 0; + disk->total_sectors = 0; + disk->log_sector_size = 0; +} + +static void +scan_usb_disk (const char *parent) +{ + struct parent_dev *op; + grub_ssize_t result; + + op = open_parent (parent); + + if (op == NULL) + { + grub_error (GRUB_ERR_BAD_DEVICE, "unable to open %s", parent); + grub_print_error (); + return; + } + + if ((grub_ieee1275_set_address (op->ihandle, 0, 0) == 0) && + (grub_ieee1275_no_data_command (op->ihandle, &tur, &result) == 0) && + (result == 0)) + { + char *buf; + + buf = grub_malloc (IEEE1275_MAX_PATH_LEN); + + if (buf == NULL) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, "disk scan failure"); + grub_print_error (); + return; + } + + grub_snprintf (buf, IEEE1275_MAX_PATH_LEN, "%s/disk@0", parent); + add_disk (buf); + grub_free (buf); + } +} + +static void +scan_nvme_disk (const char *path) +{ + char *buf; + + buf = grub_malloc (IEEE1275_MAX_PATH_LEN); + + if (buf == NULL) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, "disk scan failure"); + grub_print_error (); + return; + } + + grub_snprintf (buf, IEEE1275_MAX_PATH_LEN, "%s/disk@1", path); + add_disk (buf); + grub_free (buf); +} + +static void +scan_sparc_sas_2cell (struct parent_dev *op) +{ + grub_ssize_t result; + grub_uint8_t tgt; + char *buf; + + buf = grub_malloc (IEEE1275_MAX_PATH_LEN); + + if (buf == NULL) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, "disk scan failure"); + grub_print_error (); + return; + } + + for (tgt = 0; tgt < 0xf; tgt++) + { + + if ((grub_ieee1275_set_address(op->ihandle, tgt, 0) == 0) && + (grub_ieee1275_no_data_command (op->ihandle, &tur, &result) == 0) && + (result == 0)) + { + + grub_snprintf (buf, IEEE1275_MAX_PATH_LEN, "%s/disk@%" + PRIxGRUB_UINT32_T, op->name, tgt); + + add_disk (buf); + } + } +} + +static void +scan_sparc_sas_4cell (struct parent_dev *op) +{ + grub_uint16_t exp; + grub_uint8_t phy; + char *buf; + + buf = grub_malloc (IEEE1275_MAX_PATH_LEN); + + if (buf == NULL) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, "disk scan failure"); + grub_print_error (); + return; + } + + for (exp = 0; exp <= 0x100; exp+=0x100) + + for (phy = 0; phy < 0x20; phy++) + { + char *canon = NULL; + + grub_snprintf (buf, IEEE1275_MAX_PATH_LEN, "p%" PRIxGRUB_UINT32_T ",0", + exp | phy); + + canon = canonicalise_4cell_ua (op->ihandle, buf); + + if (canon) + { + grub_snprintf (buf, IEEE1275_MAX_PATH_LEN, "%s/disk@%s", + op->name, canon); + + add_disk (buf); + grub_free (canon); + } + } + + grub_free (buf); +} + +static void +scan_sparc_sas_disk (const char *parent) +{ + struct parent_dev *op; + + op = open_parent (parent); + + if ((op) && (op->address_cells == 4)) + scan_sparc_sas_4cell (op); + else if ((op) && (op->address_cells == 2)) + scan_sparc_sas_2cell (op); +} + +static void +iterate_devtree (const struct grub_ieee1275_devalias *alias) +{ + struct grub_ieee1275_devalias child; + + if ((grub_strcmp (alias->type, "scsi-2") == 0) || + (grub_strcmp (alias->type, "scsi-sas") == 0)) + return scan_sparc_sas_disk (alias->path); + + else if (grub_strcmp (alias->type, "nvme") == 0) + return scan_nvme_disk (alias->path); + + else if (grub_strcmp (alias->type, "scsi-usb") == 0) + return scan_usb_disk (alias->path); + + else if (grub_strcmp (alias->type, "block") == 0) + { + const char **bl = block_blacklist; + + while (*bl != NULL) + { + if (grub_strstr (alias->path, *bl)) + return; + bl++; + } + + add_disk (alias->path); + return; + } + + FOR_IEEE1275_DEVCHILDREN (alias->path, child) + iterate_devtree (&child); +} + +static void +unescape_devices (void) +{ + struct disk_dev *dev; + + FOR_LIST_ELEMENTS (dev, disk_devs) + { + grub_free (dev->grub_decoded_devpath); + + if ((dev->grub_alias_devpath) && + (grub_strcmp (dev->grub_alias_devpath, dev->grub_devpath) != 0)) + dev->grub_decoded_devpath = + remove_escaped_commas (grub_strdup (dev->grub_alias_devpath)); + else + dev->grub_decoded_devpath = + remove_escaped_commas (grub_strdup (dev->grub_devpath)); + } +} + +static void +enumerate_disks (void) +{ + struct grub_ieee1275_devalias alias; + + FOR_IEEE1275_DEVCHILDREN("/", alias) + iterate_devtree (&alias); +} + +static grub_err_t +add_bootpath (void) +{ + struct disk_dev *ob_device; + grub_err_t rval = GRUB_ERR_NONE; + char *dev, *alias; + char *type; + + grub_ieee1275_get_boot_dev (&dev); + type = grub_ieee1275_get_device_type (dev); + + if (!(type && grub_strcmp (type, "network") == 0)) + { + dev = strip_ob_partition (dev); + ob_device = add_canon_disk (dev); + + if (ob_device == NULL) + rval = grub_error (GRUB_ERR_OUT_OF_MEMORY, "failure adding boot device"); + + ob_device->valid = 1; + + alias = grub_ieee1275_get_devname (dev); + + if (grub_strcmp (alias, dev) != 0) + ob_device->grub_alias_devpath = grub_ieee1275_encode_devname (dev); + + ob_device->boot_dev = 1; + } + + grub_free (type); + grub_free (dev); + grub_free (alias); + return rval; +} + +static void +enumerate_aliases (void) +{ + struct grub_ieee1275_devalias alias; + + /* Some block device aliases are not in canonical form + + For example: + + disk3 /pci@301/pci@1/scsi@0/disk@p3 + disk2 /pci@301/pci@1/scsi@0/disk@p2 + disk1 /pci@301/pci@1/scsi@0/disk@p1 + disk /pci@301/pci@1/scsi@0/disk@p0 + disk0 /pci@301/pci@1/scsi@0/disk@p0 + + None of these devices are in canonical form. + + Also, just because there is a devalias, doesn't mean there is a disk + at that location. And a valid boot block device doesn't have to have + a devalias at all. + + At this point, all valid disks have been found in the system + and devaliases that point to canonical names are stored in the + disk_devs list already. */ + FOR_IEEE1275_DEVALIASES (alias) + { + struct disk_dev *dev; + char *canon; + + if (grub_strcmp (alias.type, "block") != 0) + continue; + + canon = canonicalise_disk (alias.name); + + if (canon == NULL) + /* This is not an error, a devalias could point to a + nonexistent disk */ + continue; + + dev = grub_named_list_find (GRUB_AS_NAMED_LIST (disk_devs), canon); + + if (dev) + { + /* If more than one alias points to the same device, + remove the previous one unless it is the boot dev, + since the upper level will use the first one. The reason + all the others are redone is in the case of hot-plugging + a disk. If the boot disk gets hot-plugged, it will come + thru here with a different name without the boot_dev flag + set. */ + if ((dev->boot_dev) && (dev->grub_alias_devpath)) + continue; + + grub_free (dev->grub_alias_devpath); + dev->grub_alias_devpath = grub_ieee1275_encode_devname (alias.path); + } + grub_free (canon); + } +} + +static void +display_disks (void) +{ + struct disk_dev *dev; + + grub_printf ("--------------------- DISKS ---------------------\n"); + + FOR_LIST_ELEMENTS (dev, disk_devs) + { + grub_printf ("name: %s\n", dev->name); + grub_printf ("grub_devpath: %s\n", dev->grub_devpath); + grub_printf ("grub_alias_devpath: %s\n", dev->grub_alias_devpath); + grub_printf ("grub_decoded_devpath: %s\n", dev->grub_decoded_devpath); + grub_printf ("valid: %s\n", (dev->valid) ? "yes" : "no"); + grub_printf ("boot_dev: %s\n", (dev->boot_dev) ? "yes" : "no"); + grub_printf ("opened: %s\n", (dev->ihandle) ? "yes" : "no"); + grub_printf ("block size: %" PRIuGRUB_UINT32_T "\n", dev->block_size); + grub_printf ("num blocks: %" PRIuGRUB_UINT64_T "\n", dev->num_blocks); + grub_printf ("log sector size: %" PRIuGRUB_UINT32_T "\n", + dev->log_sector_size); + grub_printf ("\n"); + } + + grub_printf ("-------------------------------------------------\n"); +} + +static void +display_stats (void) +{ + const char *debug = grub_env_get ("debug"); + + if (! debug) + return; + + if (grub_strword (debug, "all") || grub_strword (debug, "obdisk")) + { + display_parents (); + display_disks (); + } +} + +static void +invalidate_all_disks (void) +{ + struct disk_dev *dev = NULL; + + if (disks_enumerated) + FOR_LIST_ELEMENTS (dev, disk_devs) + dev->valid = 0; +} + +/* This is for backwards compatibility, since the path should be generated + correctly now. */ +static struct disk_dev * +find_legacy_grub_devpath (const char *name) +{ + struct disk_dev *dev = NULL; + char *canon, *devpath = NULL; + + devpath = decode_grub_devname (name + sizeof ("ieee1275")); + canon = canonicalise_disk (devpath); + + if (canon != NULL) + dev = grub_named_list_find (GRUB_AS_NAMED_LIST (disk_devs), canon); + + grub_free (devpath); + grub_free (canon); + return dev; +} + +static void +enumerate_devices (void) +{ + invalidate_all_disks (); + enumerate_disks (); + enumerate_aliases (); + unescape_devices (); + disks_enumerated = 1; + display_stats (); +} + +static struct disk_dev * +find_grub_devpath_real (const char *name) +{ + struct disk_dev *dev = NULL; + + FOR_LIST_ELEMENTS (dev, disk_devs) + { + if ((STRCMP (dev->grub_devpath, name)) + || (STRCMP (dev->grub_alias_devpath, name)) + || (STRCMP (dev->grub_decoded_devpath, name))) + break; + } + + return dev; +} + +static struct disk_dev * +find_grub_devpath (const char *name) +{ + struct disk_dev *dev = NULL; + int enumerated; + + do { + enumerated = disks_enumerated; + dev = find_grub_devpath_real (name); + + if (dev) + break; + + dev = find_legacy_grub_devpath (name); + + if (dev) + break; + + enumerate_devices (); + } while (enumerated == 0); + + return dev; +} + +static int +grub_obdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, + grub_disk_pull_t pull) +{ + struct disk_dev *dev; + + if (pull != GRUB_DISK_PULL_NONE) + return 0; + + enumerate_devices (); + + FOR_LIST_ELEMENTS (dev, disk_devs) + { + if (dev->valid == 1) + if (hook (dev->grub_decoded_devpath, hook_data)) + return 1; + } + + return 0; +} + +static grub_err_t +grub_obdisk_open (const char *name, grub_disk_t disk) +{ + grub_ieee1275_ihandle_t ihandle = 0; + struct disk_dev *dev = NULL; + + if (grub_strncmp (name, "ieee1275/", sizeof ("ieee1275/") - 1) != 0) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not IEEE1275 device"); + + dev = find_grub_devpath (name); + + if (dev == NULL) + { + grub_printf ("UNKNOWN DEVICE: %s\n", name); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "%s", name); + } + + if (dev->opened == 0) + { + if (dev->raw_name) + grub_ieee1275_open (dev->raw_name, &ihandle); + else + grub_ieee1275_open (dev->name, &ihandle); + + if (ihandle == 0) + { + grub_printf ("Can't open device %s\n", name); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device %s", name); + } + + dev->block_size = grub_ieee1275_get_block_size (ihandle); + dev->num_blocks = grub_ieee1275_num_blocks (ihandle); + + if (dev->num_blocks == 0) + dev->num_blocks = grub_ieee1275_num_blocks64 (ihandle); + + if (dev->num_blocks == 0) + dev->num_blocks = GRUB_DISK_SIZE_UNKNOWN; + + if (dev->block_size != 0) + { + for (dev->log_sector_size = 0; + (1U << dev->log_sector_size) < dev->block_size; + dev->log_sector_size++); + } + else + dev->log_sector_size = 9; + + dev->ihandle = ihandle; + dev->opened = 1; + } + + disk->total_sectors = dev->num_blocks; + disk->id = dev->ihandle; + disk->data = dev; + disk->log_sector_size = dev->log_sector_size; + return GRUB_ERR_NONE; +} + + +static struct grub_disk_dev grub_obdisk_dev = + { + .name = "obdisk", + .id = GRUB_DISK_DEVICE_OBDISK_ID, + .iterate = grub_obdisk_iterate, + .open = grub_obdisk_open, + .close = grub_obdisk_close, + .read = grub_obdisk_read, + .next = 0 + }; + +void +grub_obdisk_init (void) +{ + grub_disk_firmware_fini = grub_obdisk_fini; + add_bootpath (); + grub_disk_dev_register (&grub_obdisk_dev); +} + +void +grub_obdisk_fini (void) +{ + struct disk_dev *dev; + + FOR_LIST_ELEMENTS (dev, disk_devs) + { + if (dev->opened) + grub_ieee1275_close (dev->ihandle); + } + + grub_disk_dev_unregister (&grub_obdisk_dev); +} Index: grub2-2.02/grub-core/disk/ieee1275/ofdisk.c =================================================================== --- grub2-2.02.orig/grub-core/disk/ieee1275/ofdisk.c +++ grub2-2.02/grub-core/disk/ieee1275/ofdisk.c @@ -74,7 +74,7 @@ ofdisk_hash_find (const char *devpath) } static struct ofdisk_hash_ent * -ofdisk_hash_add_real (char *devpath) +ofdisk_hash_add_real (const char *devpath) { struct ofdisk_hash_ent *p; struct ofdisk_hash_ent **head = &ofdisk_hash[ofdisk_hash_fn(devpath)]; @@ -85,13 +85,20 @@ ofdisk_hash_add_real (char *devpath) if (!p) return NULL; - p->devpath = devpath; + p->devpath = grub_strdup (devpath); + + if (!p->devpath) + { + grub_free (p); + return NULL; + } p->grub_devpath = grub_malloc (sizeof ("ieee1275/") + 2 * grub_strlen (p->devpath)); if (!p->grub_devpath) { + grub_free (p->devpath); grub_free (p); return NULL; } @@ -101,6 +108,7 @@ ofdisk_hash_add_real (char *devpath) p->open_path = grub_malloc (grub_strlen (p->devpath) + 3); if (!p->open_path) { + grub_free (p->devpath); grub_free (p->grub_devpath); grub_free (p); return NULL; @@ -140,7 +148,7 @@ check_string_removable (const char *str) } static struct ofdisk_hash_ent * -ofdisk_hash_add (char *devpath, char *curcan) +ofdisk_hash_add (const char *devpath, const char *curcan) { struct ofdisk_hash_ent *p, *pcan; @@ -160,8 +168,6 @@ ofdisk_hash_add (char *devpath, char *cu pcan = ofdisk_hash_find (curcan); if (!pcan) pcan = ofdisk_hash_add_real (curcan); - else - grub_free (curcan); if (check_string_removable (devpath) || check_string_removable (curcan)) pcan->is_removable = 1; @@ -191,18 +197,7 @@ dev_iterate_real (const char *name, cons op = ofdisk_hash_find (path); if (!op) - { - char *name_dup = grub_strdup (name); - char *can = grub_strdup (path); - if (!name_dup || !can) - { - grub_errno = GRUB_ERR_NONE; - grub_free (name_dup); - grub_free (can); - return; - } - op = ofdisk_hash_add (name_dup, can); - } + op = ofdisk_hash_add (name, path); return; } @@ -658,6 +653,7 @@ insert_bootpath (void) char *device = grub_ieee1275_get_devname (bootpath); op = ofdisk_hash_add (device, NULL); op->is_boot = 1; + grub_free (device); } grub_free (type); grub_free (bootpath); Index: grub2-2.02/grub-core/kern/ieee1275/cmain.c =================================================================== --- grub2-2.02.orig/grub-core/kern/ieee1275/cmain.c +++ grub2-2.02/grub-core/kern/ieee1275/cmain.c @@ -108,6 +108,9 @@ grub_ieee1275_find_options (void) if (rc >= 0) { char *ptr; + + if (grub_strncmp (tmp, "sun4v", 5) == 0) + grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_RAW_DEVNAMES); for (ptr = tmp; ptr - tmp < actual; ptr += grub_strlen (ptr) + 1) { if (grub_memcmp (ptr, "MacRISC", sizeof ("MacRISC") - 1) == 0 Index: grub2-2.02/grub-core/kern/ieee1275/ieee1275.c =================================================================== --- grub2-2.02.orig/grub-core/kern/ieee1275/ieee1275.c +++ grub2-2.02/grub-core/kern/ieee1275/ieee1275.c @@ -19,6 +19,7 @@ #include <grub/ieee1275/ieee1275.h> #include <grub/types.h> +#include <grub/misc.h> #define IEEE1275_PHANDLE_INVALID ((grub_ieee1275_cell_t) -1) #define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_cell_t) 0) @@ -483,6 +484,93 @@ grub_ieee1275_close (grub_ieee1275_ihand } int +grub_ieee1275_decode_unit4 (grub_ieee1275_ihandle_t ihandle, + void *addr, grub_size_t size, + grub_uint32_t *phy_lo, grub_uint32_t *phy_hi, + grub_uint32_t *lun_lo, grub_uint32_t *lun_hi) +{ + struct decode_args + { + struct grub_ieee1275_common_hdr common; + grub_ieee1275_cell_t method; + grub_ieee1275_cell_t ihandle; + grub_ieee1275_cell_t size; + grub_ieee1275_cell_t addr; + grub_ieee1275_cell_t catch_result; + grub_ieee1275_cell_t tgt_h; + grub_ieee1275_cell_t tgt_l; + grub_ieee1275_cell_t lun_h; + grub_ieee1275_cell_t lun_l; + } + args; + + INIT_IEEE1275_COMMON (&args.common, "call-method", 4, 5); + args.method = (grub_ieee1275_cell_t) "decode-unit"; + args.ihandle = ihandle; + args.size = size; + args.addr = (grub_ieee1275_cell_t) addr; + args.catch_result = 1; + + if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.catch_result)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "decode-unit failed\n"); + return -1; + } + + *phy_lo = args.tgt_l; + *phy_hi = args.tgt_h; + *lun_lo = args.lun_l; + *lun_hi = args.lun_h; + return 0; +} + +char * +grub_ieee1275_encode_uint4 (grub_ieee1275_ihandle_t ihandle, + grub_uint32_t phy_lo, grub_uint32_t phy_hi, + grub_uint32_t lun_lo, grub_uint32_t lun_hi, + grub_size_t *size) +{ + char *addr; + struct encode_args + { + struct grub_ieee1275_common_hdr common; + grub_ieee1275_cell_t method; + grub_ieee1275_cell_t ihandle; + grub_ieee1275_cell_t tgt_h; + grub_ieee1275_cell_t tgt_l; + grub_ieee1275_cell_t lun_h; + grub_ieee1275_cell_t lun_l; + grub_ieee1275_cell_t catch_result; + grub_ieee1275_cell_t size; + grub_ieee1275_cell_t addr; + } + args; + + INIT_IEEE1275_COMMON (&args.common, "call-method", 6, 3); + args.method = (grub_ieee1275_cell_t) "encode-unit"; + args.ihandle = ihandle; + + args.tgt_l = phy_lo; + args.tgt_h = phy_hi; + args.lun_l = lun_lo; + args.lun_h = lun_hi; + args.catch_result = 1; + + if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.catch_result)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "encode-unit failed\n"); + return 0; + } + + addr = (void *)args.addr; + *size = args.size; + addr = grub_strdup ((char *)args.addr); + return addr; +} + + + +int grub_ieee1275_claim (grub_addr_t addr, grub_size_t size, unsigned int align, grub_addr_t *result) { @@ -607,3 +695,114 @@ grub_ieee1275_milliseconds (grub_uint32_ *msecs = args.msecs; return 0; } + +int +grub_ieee1275_set_address (grub_ieee1275_ihandle_t ihandle, + grub_uint32_t target, grub_uint32_t lun) +{ + struct set_address + { + struct grub_ieee1275_common_hdr common; + grub_ieee1275_cell_t method; + grub_ieee1275_cell_t ihandle; + grub_ieee1275_cell_t tgt; + grub_ieee1275_cell_t lun; + grub_ieee1275_cell_t catch_result; + } + args; + + INIT_IEEE1275_COMMON (&args.common, "call-method", 4, 1); + + /* IEEE Standard for Boot (Initialization Configuration) + Firmware: Core Requirements and Practices + E.3.2.2 Bus-specific methods for bus nodes + + A package implementing the scsi-2 device type shall implement the + following bus-specific method: + + set-address ( unit# target# -- ) + Sets the SCSI target number (0x0..0xf) and unit number (0..7) to which + subsequent commands apply. + */ + args.method = (grub_ieee1275_cell_t) "set-address"; + args.ihandle = ihandle; + args.tgt = target; + args.lun = lun; + + if (IEEE1275_CALL_ENTRY_FN (&args) == -1) + return -1; + + return args.catch_result; +} + +int +grub_ieee1275_no_data_command (grub_ieee1275_ihandle_t ihandle, + const void *cmd_addr, grub_ssize_t *result) +{ + struct set_address + { + struct grub_ieee1275_common_hdr common; + grub_ieee1275_cell_t method; + grub_ieee1275_cell_t ihandle; + grub_ieee1275_cell_t cmd_addr; + grub_ieee1275_cell_t error; + grub_ieee1275_cell_t catch_result; + } + args; + + INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2); + /* IEEE 1275-1994 Standard for Boot (Initialization Configuration) + Firmware: Core Requirements and Practices + + E.3.2.2 Bus-specific methods for bus nodes + + A package implementing the scsi-2 device type shall implement the + following bus-specific method: + + no-data-command ( cmd-addr -- error? ) + Executes a simple SCSI command, automatically retrying under + certain conditions. cmd-addr is the address of a 6-byte command buffer + containing an SCSI command that does not have a data transfer phase. + Executes the command, retrying indefinitely with the same retry criteria + as retry-command. + + error? is nonzero if an error occurred, zero otherwise. + NOTE no-data-command is a convenience function. It provides + no capabilities that are not present in retry-command, but for + those commands that meet its restrictions, it is easier to use. + */ + args.method = (grub_ieee1275_cell_t) "no-data-command"; + args.ihandle = ihandle; + args.cmd_addr = (grub_ieee1275_cell_t) cmd_addr; + + if (IEEE1275_CALL_ENTRY_FN (&args) == -1) + return -1; + + if (result) + *result = args.error; + + return args.catch_result; +} + +int +grub_ieee1275_get_block_size (grub_ieee1275_ihandle_t ihandle) +{ + struct size_args_ieee1275 + { + struct grub_ieee1275_common_hdr common; + grub_ieee1275_cell_t method; + grub_ieee1275_cell_t ihandle; + grub_ieee1275_cell_t result; + grub_ieee1275_cell_t size; + } args; + + INIT_IEEE1275_COMMON (&args.common, "call-method", 2, 2); + args.method = (grub_ieee1275_cell_t) "block-size"; + args.ihandle = ihandle; + args.result = 1; + + if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.result)) + return 0; + + return args.size; +} Index: grub2-2.02/grub-core/kern/ieee1275/init.c =================================================================== --- grub2-2.02.orig/grub-core/kern/ieee1275/init.c +++ grub2-2.02/grub-core/kern/ieee1275/init.c @@ -30,6 +30,9 @@ #include <grub/time.h> #include <grub/ieee1275/console.h> #include <grub/ieee1275/ofdisk.h> +#ifdef __sparc__ +#include <grub/ieee1275/obdisk.h> +#endif #include <grub/ieee1275/ieee1275.h> #include <grub/net.h> #include <grub/offsets.h> @@ -103,29 +106,13 @@ grub_machine_get_bootlocation (char **de void grub_machine_get_bootlocation (char **device, char **path) { - char *bootpath; - grub_ssize_t bootpath_size; + char *bootpath = NULL; char *filename; char *type; - if (grub_ieee1275_get_property_length (grub_ieee1275_chosen, "bootpath", - &bootpath_size) - || bootpath_size <= 0) - { - /* Should never happen. */ - grub_printf ("/chosen/bootpath property missing!\n"); - return; - } - - bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64); - if (! bootpath) - { - grub_print_error (); - return; - } - grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath", bootpath, - (grub_size_t) bootpath_size + 1, 0); - bootpath[bootpath_size] = '\0'; + grub_ieee1275_get_boot_dev (&bootpath); + if (bootpath == NULL) + return; /* Transform an OF device path to a GRUB path. */ @@ -305,8 +292,11 @@ grub_machine_init (void) grub_console_init_early (); grub_claim_heap (); grub_console_init_lately (); +#ifdef __sparc__ + grub_obdisk_init (); +#else grub_ofdisk_init (); - +#endif grub_parse_cmdline (); #ifdef __i386__ @@ -321,7 +311,11 @@ grub_machine_fini (int flags) { if (flags & GRUB_LOADER_FLAG_NORETURN) { +#ifdef __sparc__ + grub_obdisk_fini (); +#else grub_ofdisk_fini (); +#endif grub_console_fini (); } } Index: grub2-2.02/grub-core/kern/ieee1275/openfw.c =================================================================== --- grub2-2.02.orig/grub-core/kern/ieee1275/openfw.c +++ grub2-2.02/grub-core/kern/ieee1275/openfw.c @@ -561,3 +561,30 @@ grub_ieee1275_canonicalise_devname (cons return NULL; } +void +grub_ieee1275_get_boot_dev (char **boot_dev) +{ + char *bootpath; + grub_ssize_t bootpath_size; + + if (grub_ieee1275_get_property_length (grub_ieee1275_chosen, "bootpath", + &bootpath_size) + || bootpath_size <= 0) + { + /* Should never happen. */ + grub_printf ("/chosen/bootpath property missing!\n"); + return; + } + + bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64); + if (! bootpath) + { + grub_print_error (); + return; + } + grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath", bootpath, + (grub_size_t) bootpath_size + 1, 0); + bootpath[bootpath_size] = '\0'; + + *boot_dev = bootpath; +} Index: grub2-2.02/grub-core/kern/parser.c =================================================================== --- grub2-2.02.orig/grub-core/kern/parser.c +++ grub2-2.02/grub-core/kern/parser.c @@ -30,7 +30,6 @@ static struct grub_parser_state_transiti {GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_QUOTE, '\'', 0}, {GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_DQUOTE, '\"', 0}, {GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_VAR, '$', 0}, - {GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_ESC, '\\', 0}, {GRUB_PARSER_STATE_ESC, GRUB_PARSER_STATE_TEXT, 0, 1}, Index: grub2-2.02/grub-core/kern/sparc64/ieee1275/ieee1275.c =================================================================== --- grub2-2.02.orig/grub-core/kern/sparc64/ieee1275/ieee1275.c +++ grub2-2.02/grub-core/kern/sparc64/ieee1275/ieee1275.c @@ -89,3 +89,56 @@ grub_ieee1275_alloc_physmem (grub_addr_t return args.catch_result; } + +grub_uint64_t +grub_ieee1275_num_blocks (grub_ieee1275_ihandle_t ihandle) +{ + struct nblocks_args_ieee1275 + { + struct grub_ieee1275_common_hdr common; + grub_ieee1275_cell_t method; + grub_ieee1275_cell_t ihandle; + grub_ieee1275_cell_t catch_result; + grub_ieee1275_cell_t blocks; + } + args; + + INIT_IEEE1275_COMMON (&args.common, "call-method", 2, 2); + args.method = (grub_ieee1275_cell_t) "#blocks"; + args.ihandle = ihandle; + args.catch_result = 1; + + if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.catch_result != 0)) + return -1; + + /* If the number of blocks exceeds the range of an unsigned number, + return 0 to alert the caller to try the #blocks64 command. */ + if (args.blocks >= 0xffffffffULL) + return 0; + + return args.blocks; +} +grub_uint64_t +grub_ieee1275_num_blocks64 (grub_ieee1275_ihandle_t ihandle) +{ + struct nblocks_args_ieee1275 + { + struct grub_ieee1275_common_hdr common; + grub_ieee1275_cell_t method; + grub_ieee1275_cell_t ihandle; + grub_ieee1275_cell_t catch_result; + grub_ieee1275_cell_t hi_blocks; + grub_ieee1275_cell_t lo_blocks; + } + args; + + INIT_IEEE1275_COMMON (&args.common, "call-method", 2, 3); + args.method = (grub_ieee1275_cell_t) "#blocks64"; + args.ihandle = ihandle; + args.catch_result = 1; + + if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.catch_result != 0)) + return -1; + + return ((args.hi_blocks << 32) | (args.lo_blocks)); +} Index: grub2-2.02/grub-core/osdep/linux/blocklist.c =================================================================== --- grub2-2.02.orig/grub-core/osdep/linux/blocklist.c +++ grub2-2.02/grub-core/osdep/linux/blocklist.c @@ -58,6 +58,11 @@ grub_install_get_blocklist (grub_device_ struct fiemap fie1; int fd; +#ifdef __sparc__ + if (grub_strstr (container->partmap->name, "gpt")) + container_start = 0; +#endif + /* Write the first two sectors of the core image onto the disk. */ grub_util_info ("opening the core image `%s'", core_path); fd = open (core_path, O_RDONLY); Index: grub2-2.02/grub-core/osdep/linux/ofpath.c =================================================================== --- grub2-2.02.orig/grub-core/osdep/linux/ofpath.c +++ grub2-2.02/grub-core/osdep/linux/ofpath.c @@ -38,6 +38,44 @@ #include <errno.h> #include <ctype.h> +#ifdef __sparc__ +typedef enum + { + GRUB_OFPATH_SPARC_WWN_ADDR = 1, + GRUB_OFPATH_SPARC_TGT_LUN, + } ofpath_sparc_addressing; + +struct ofpath_sparc_hba +{ + grub_uint32_t device_id; + ofpath_sparc_addressing addressing; +}; + +static struct ofpath_sparc_hba sparc_lsi_hba[] = { + /* Rhea, Jasper 320, LSI53C1020/1030. */ + {0x30, GRUB_OFPATH_SPARC_TGT_LUN}, + /* SAS-1068E. */ + {0x50, GRUB_OFPATH_SPARC_TGT_LUN}, + /* SAS-1064E. */ + {0x56, GRUB_OFPATH_SPARC_TGT_LUN}, + /* Pandora SAS-1068E. */ + {0x58, GRUB_OFPATH_SPARC_TGT_LUN}, + /* Aspen, Invader, LSI SAS-3108. */ + {0x5d, GRUB_OFPATH_SPARC_TGT_LUN}, + /* Niwot, SAS 2108. */ + {0x79, GRUB_OFPATH_SPARC_TGT_LUN}, + /* Erie, Falcon, LSI SAS 2008. */ + {0x72, GRUB_OFPATH_SPARC_WWN_ADDR}, + /* LSI WarpDrive 6203. */ + {0x7e, GRUB_OFPATH_SPARC_WWN_ADDR}, + /* LSI SAS 2308. */ + {0x87, GRUB_OFPATH_SPARC_WWN_ADDR}, + /* LSI SAS 3008. */ + {0x97, GRUB_OFPATH_SPARC_WWN_ADDR}, + {0, 0} +}; +#endif + #ifdef OFPATH_STANDALONE #define xmalloc malloc void @@ -307,6 +345,50 @@ of_path_of_ide(const char *sys_devname _ return ret; } +static char * +of_path_of_nvme(const char *sys_devname __attribute__((unused)), + const char *device, + const char *devnode __attribute__((unused)), + const char *devicenode) +{ + char *sysfs_path, *of_path, disk[MAX_DISK_CAT]; + const char *digit_string, *part_end; + + digit_string = trailing_digits (device); + part_end = devicenode + strlen (devicenode) - 1; + + if ((digit_string != '\0') && (*part_end == 'p')) + { + /* We have a partition number, strip it off. */ + int part; + char *nvmedev, *end; + + nvmedev = strdup (devicenode); + + if (nvmedev == NULL) + return NULL; + + end = nvmedev + strlen (nvmedev) - 1; + /* Remove the p. */ + *end = '\0'; + sscanf (digit_string, "%d", &part); + snprintf (disk, sizeof (disk), "/disk@1:%c", 'a' + (part - 1)); + sysfs_path = block_device_get_sysfs_path_and_link (nvmedev); + free (nvmedev); + } + else + { + /* We do not have the parition. */ + snprintf (disk, sizeof (disk), "/disk@1"); + sysfs_path = block_device_get_sysfs_path_and_link (device); + } + + of_path = find_obppath (sysfs_path); + free (sysfs_path); + strcat (of_path, disk); + return of_path; +} + static int vendor_is_ATA(const char *path) { @@ -335,6 +417,66 @@ vendor_is_ATA(const char *path) return (memcmp(bufcont, "ATA", 3) == 0); } +#ifdef __sparc__ +static void +check_hba_identifiers (const char *sysfs_path, int *vendor, int *device_id) +{ + char *ed = strstr (sysfs_path, "host"); + size_t path_size; + char *p = NULL, *path = NULL; + char buf[8]; + int fd; + + if (!ed) + return; + + p = xstrdup (sysfs_path); + ed = strstr (p, "host"); + + if (!ed) + goto out; + + *ed = '\0'; + + path_size = (strlen (p) + sizeof ("vendor")); + path = xmalloc (path_size); + + if (!path) + goto out; + + snprintf (path, path_size, "%svendor", p); + fd = open (path, O_RDONLY); + + if (fd < 0) + goto out; + + memset (buf, 0, sizeof (buf)); + + if (read (fd, buf, sizeof (buf) - 1) < 0) + goto out; + + close (fd); + sscanf (buf, "%x", vendor); + snprintf (path, path_size, "%sdevice", p); + fd = open (path, O_RDONLY); + + if (fd < 0) + goto out; + + memset (buf, 0, sizeof (buf)); + + if (read (fd, buf, sizeof (buf) - 1) < 0) + goto out; + + close (fd); + sscanf (buf, "%x", device_id); + +out: + free (path); + free (p); +} +#endif + static void check_sas (const char *sysfs_path, int *tgt, unsigned long int *sas_address) { @@ -396,7 +538,7 @@ of_path_of_scsi(const char *sys_devname { const char *p, *digit_string, *disk_name; int host, bus, tgt, lun; - unsigned long int sas_address; + unsigned long int sas_address = 0; char *sysfs_path, disk[MAX_DISK_CAT - sizeof ("/fp@0,0")]; char *of_path; @@ -413,9 +555,11 @@ of_path_of_scsi(const char *sys_devname } of_path = find_obppath(sysfs_path); - free (sysfs_path); if (!of_path) - return NULL; + { + free (sysfs_path); + return NULL; + } if (strstr (of_path, "qlc")) strcat (of_path, "/fp@0,0"); @@ -444,6 +588,45 @@ of_path_of_scsi(const char *sys_devname } else { +#ifdef __sparc__ + ofpath_sparc_addressing addressing = GRUB_OFPATH_SPARC_TGT_LUN; + int vendor = 0, device_id = 0; + char *optr = disk; + + check_hba_identifiers (sysfs_path, &vendor, &device_id); + + /* LSI Logic Vendor ID */ + if (vendor == 0x1000) + { + struct ofpath_sparc_hba *lsi_hba; + + /* Over time different OF addressing schemes have been supported. + There is no generic addressing scheme that works across + every HBA. */ + for (lsi_hba = sparc_lsi_hba; lsi_hba->device_id; lsi_hba++) + if (lsi_hba->device_id == device_id) + { + addressing = lsi_hba->addressing; + break; + } + } + + if (addressing == GRUB_OFPATH_SPARC_WWN_ADDR) + optr += snprintf (disk, sizeof (disk), "/%s@w%lx,%x", disk_name, + sas_address, lun); + else + optr += snprintf (disk, sizeof (disk), "/%s@%x,%x", disk_name, tgt, + lun); + + if (*digit_string != '\0') + { + int part; + + sscanf (digit_string, "%d", &part); + snprintf (optr, sizeof (disk) - (optr - disk - 1), ":%c", 'a' + + (part - 1)); + } +#else if (lun == 0) { int sas_id = 0; @@ -491,7 +674,9 @@ of_path_of_scsi(const char *sys_devname } free (lunstr); } +#endif } + free (sysfs_path); strcat(of_path, disk); return of_path; } @@ -537,6 +722,9 @@ grub_util_devname_to_ofpath (const char /* All the models I've seen have a devalias "floppy". New models have no floppy at all. */ ofpath = xstrdup ("floppy"); + else if (device[0] == 'n' && device[1] == 'v' && device[2] == 'm' + && device[3] == 'e') + ofpath = of_path_of_nvme (name_buf, device, devnode, devicenode); else { grub_util_warn (_("unknown device type %s"), device); Index: grub2-2.02/include/grub/disk.h =================================================================== --- grub2-2.02.orig/include/grub/disk.h +++ grub2-2.02/include/grub/disk.h @@ -49,6 +49,7 @@ enum grub_disk_dev_id GRUB_DISK_DEVICE_CBFSDISK_ID, GRUB_DISK_DEVICE_UBOOTDISK_ID, GRUB_DISK_DEVICE_XEN, + GRUB_DISK_DEVICE_OBDISK_ID, }; struct grub_disk; Index: grub2-2.02/include/grub/ieee1275/ieee1275.h =================================================================== --- grub2-2.02.orig/include/grub/ieee1275/ieee1275.h +++ grub2-2.02/include/grub/ieee1275/ieee1275.h @@ -146,6 +146,8 @@ enum grub_ieee1275_flag GRUB_IEEE1275_FLAG_BROKEN_REPEAT, GRUB_IEEE1275_FLAG_CURSORONOFF_ANSI_BROKEN, + + GRUB_IEEE1275_FLAG_RAW_DEVNAMES, }; extern int EXPORT_FUNC(grub_ieee1275_test_flag) (enum grub_ieee1275_flag flag); @@ -211,6 +213,30 @@ int EXPORT_FUNC(grub_ieee1275_set_color) int index, int r, int g, int b); int EXPORT_FUNC(grub_ieee1275_milliseconds) (grub_uint32_t *msecs); +int EXPORT_FUNC(grub_ieee1275_set_address) (grub_ieee1275_ihandle_t ihandle, + grub_uint32_t target, + grub_uint32_t lun); + +int EXPORT_FUNC(grub_ieee1275_no_data_command) (grub_ieee1275_ihandle_t ihandle, + const void *cmd_addr, + grub_ssize_t *result); + +int EXPORT_FUNC(grub_ieee1275_decode_unit4) (grub_ieee1275_ihandle_t ihandle, + void *addr, grub_size_t size, + grub_uint32_t *phy_lo, + grub_uint32_t *phy_hi, + grub_uint32_t *lun_lo, + grub_uint32_t *lun_hi); + +char *EXPORT_FUNC(grub_ieee1275_encode_uint4) (grub_ieee1275_ihandle_t ihandle, + grub_uint32_t phy_lo, + grub_uint32_t phy_hi, + grub_uint32_t lun_lo, + grub_uint32_t lun_hi, + grub_size_t *size); + +int EXPORT_FUNC(grub_ieee1275_get_block_size) (grub_ieee1275_ihandle_t ihandle); + grub_err_t EXPORT_FUNC(grub_claimmap) (grub_addr_t addr, grub_size_t size); @@ -235,6 +261,7 @@ void EXPORT_FUNC(grub_ieee1275_children_ void EXPORT_FUNC(grub_ieee1275_children_first) (const char *devpath, struct grub_ieee1275_devalias *alias); +void EXPORT_FUNC(grub_ieee1275_get_boot_dev) (char **boot_dev); #define FOR_IEEE1275_DEVALIASES(alias) for (grub_ieee1275_devalias_init_iterator (&(alias)); grub_ieee1275_devalias_next (&(alias));) #define FOR_IEEE1275_DEVCHILDREN(devpath, alias) for (grub_ieee1275_children_first ((devpath), &(alias)); \ Index: grub2-2.02/include/grub/ieee1275/obdisk.h =================================================================== --- /dev/null +++ grub2-2.02/include/grub/ieee1275/obdisk.h @@ -0,0 +1,25 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2017 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/>. + */ + +#ifndef GRUB_OBDISK_HEADER +#define GRUB_OBDISK_HEADER 1 + +extern void grub_obdisk_init (void); +extern void grub_obdisk_fini (void); + +#endif Index: grub2-2.02/include/grub/sparc64/ieee1275/ieee1275.h =================================================================== --- grub2-2.02.orig/include/grub/sparc64/ieee1275/ieee1275.h +++ grub2-2.02/include/grub/sparc64/ieee1275/ieee1275.h @@ -42,6 +42,8 @@ extern int EXPORT_FUNC(grub_ieee1275_cla extern int EXPORT_FUNC(grub_ieee1275_alloc_physmem) (grub_addr_t *paddr, grub_size_t size, grub_uint32_t align); +extern grub_uint64_t EXPORT_FUNC(grub_ieee1275_num_blocks) (grub_uint32_t ihandle); +extern grub_uint64_t EXPORT_FUNC(grub_ieee1275_num_blocks64) (grub_uint32_t ihandle); extern grub_addr_t EXPORT_VAR (grub_ieee1275_original_stack); Index: grub2-2.02/util/grub-install.c =================================================================== --- grub2-2.02.orig/util/grub-install.c +++ grub2-2.02/util/grub-install.c @@ -1616,6 +1616,7 @@ main (int argc, char *argv[]) { grub_util_fprint_full_disk_name (load_cfg_f, g, dev); fprintf (load_cfg_f, " "); + free (g); } if (dev != grub_dev) grub_device_close (dev); Index: grub2-2.02/util/ieee1275/grub-ofpathname.c =================================================================== --- grub2-2.02.orig/util/ieee1275/grub-ofpathname.c +++ grub2-2.02/util/ieee1275/grub-ofpathname.c @@ -46,7 +46,9 @@ int main(int argc, char **argv) } of_path = grub_util_devname_to_ofpath (argv[1]); - printf("%s\n", of_path); + + if (of_path) + printf ("%s\n", of_path); free (of_path); Index: grub2-2.02/util/setup.c =================================================================== --- grub2-2.02.orig/util/setup.c +++ grub2-2.02/util/setup.c @@ -200,7 +200,6 @@ save_blocklists (grub_disk_addr_t sector #endif } -#ifdef GRUB_SETUP_BIOS /* Context for setup/identify_partmap. */ struct identify_partmap_ctx { @@ -236,7 +235,6 @@ identify_partmap (grub_disk_t disk __att ctx->multiple_partmaps = 1; return 1; } -#endif #ifdef GRUB_SETUP_BIOS #define SETUP grub_util_bios_setup @@ -257,9 +255,7 @@ SETUP (const char *dir, char *boot_img, *core_img, *boot_path; char *root = 0; size_t boot_size, core_size; -#ifdef GRUB_SETUP_BIOS grub_uint16_t core_sectors; -#endif grub_device_t root_dev = 0, dest_dev, core_dev; grub_util_fd_t fp; struct blocklists bl; @@ -283,10 +279,8 @@ SETUP (const char *dir, core_path = grub_util_get_path (dir, core_file); core_size = grub_util_get_image_size (core_path); -#ifdef GRUB_SETUP_BIOS core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); -#endif if (core_size < GRUB_DISK_SECTOR_SIZE) grub_util_error (_("the size of `%s' is too small"), core_path); #ifdef GRUB_SETUP_BIOS @@ -368,8 +362,8 @@ SETUP (const char *dir, if (grub_env_set ("root", root) != GRUB_ERR_NONE) grub_util_error ("%s", grub_errmsg); -#ifdef GRUB_SETUP_BIOS { +#ifdef GRUB_SETUP_BIOS char *tmp_img; grub_uint8_t *boot_drive_check; @@ -394,6 +388,7 @@ SETUP (const char *dir, boot_drive_check[0] = 0x90; boot_drive_check[1] = 0x90; } +#endif struct identify_partmap_ctx ctx = { .dest_partmap = NULL, @@ -409,6 +404,7 @@ SETUP (const char *dir, grub_partition_iterate (dest_dev->disk, identify_partmap, &ctx); +#ifdef GRUB_SETUP_BIOS /* Copy the partition table. */ if (ctx.dest_partmap || (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk))) @@ -417,6 +413,7 @@ SETUP (const char *dir, GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC); free (tmp_img); +#endif if (ctx.container && grub_strcmp (ctx.container->partmap->name, "msdos") == 0 @@ -504,10 +501,21 @@ SETUP (const char *dir, else maxsec = core_sectors; +#ifdef GRUB_SETUP_BIOS if (maxsec > ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR) >> GRUB_DISK_SECTOR_BITS)) maxsec = ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR) >> GRUB_DISK_SECTOR_BITS); +#endif + +#ifdef GRUB_SETUP_SPARC64 + /* On SPARC we need two extra. One is because we are combining the + * core.img with the boot.img. The other is because the boot sector + * starts at 1. + */ + nsec += 2; + maxsec += 2; +#endif if (is_ldm) err = grub_util_ldm_embed (dest_dev->disk, &nsec, maxsec, @@ -556,9 +564,35 @@ SETUP (const char *dir, bl.block--; bl.block->start = 0; bl.block->len = 0; +#ifdef GRUB_SETUP_BIOS bl.block->segment = 0; +#endif + +#ifdef GRUB_SETUP_SPARC64 + { + /* On SPARC, the block-list entries need to be based off the beginning + of the parition, not the beginning of the disk. */ + struct grub_boot_blocklist *block; + block = bl.first_block; + + while (block->len) + { + block->start -= bl.first_sector; + block--; + } + } + + /* Reserve space for the boot block since it can not be in the + Parition table on SPARC */ + assert (bl.first_block->len > 2); + bl.first_block->start += 2; + bl.first_block->len -= 2; + write_rootdev (root_dev, boot_img, sectors[BOOT_SECTOR + 1] - bl.first_sector); +#endif +#ifdef GRUB_SETUP_BIOS write_rootdev (root_dev, boot_img, bl.first_sector); +#endif /* Round up to the nearest sector boundary, and zero the extra memory */ core_img = xrealloc (core_img, nsec * GRUB_DISK_SECTOR_SIZE); @@ -568,7 +602,7 @@ SETUP (const char *dir, bl.first_block = (struct grub_boot_blocklist *) (core_img + GRUB_DISK_SECTOR_SIZE - sizeof (*bl.block)); - +#if GRUB_SETUP_BIOS grub_size_t no_rs_length; no_rs_length = grub_target_to_host16 (grub_get_unaligned16 (core_img @@ -599,6 +633,26 @@ SETUP (const char *dir, grub_disk_write (dest_dev->disk, sectors[i], 0, GRUB_DISK_SECTOR_SIZE, core_img + i * GRUB_DISK_SECTOR_SIZE); +#endif +#ifdef GRUB_SETUP_SPARC64 + { + int isec = BOOT_SECTOR; + + /* Write the boot image onto the disk. */ + if (grub_disk_write (dest_dev->disk, sectors[isec++], 0, + GRUB_DISK_SECTOR_SIZE, boot_img)) + grub_util_error ("%s", grub_errmsg); + + /* Write the core image onto the disk. */ + for (i = 0 ; isec < nsec; i++, isec++) + { + if (grub_disk_write (dest_dev->disk, sectors[isec], 0, + GRUB_DISK_SECTOR_SIZE, + core_img + i * GRUB_DISK_SECTOR_SIZE)) + grub_util_error ("%s", grub_errmsg); + } + } +#endif grub_free (sectors); @@ -608,7 +662,6 @@ SETUP (const char *dir, } unable_to_embed: -#endif if (dest_dev->disk->dev->id != root_dev->disk->dev->id) grub_util_error ("%s", _("embedding is not possible, but this is required for " @@ -729,15 +782,21 @@ unable_to_embed: { char *buf, *ptr = core_img; size_t len = core_size; - grub_uint64_t blk; + grub_uint64_t blk, offset = 0; grub_partition_t container = core_dev->disk->partition; grub_err_t err; core_dev->disk->partition = 0; +#ifdef GRUB_SETUP_SPARC64 + { + if (grub_strstr (container->partmap->name, "gpt")) + offset = grub_partition_get_start (container); + } +#endif buf = xmalloc (core_size); blk = bl.first_sector; - err = grub_disk_read (core_dev->disk, blk, 0, GRUB_DISK_SECTOR_SIZE, buf); + err = grub_disk_read (core_dev->disk, blk + offset, 0, GRUB_DISK_SECTOR_SIZE, buf); if (err) grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name, grub_errmsg); @@ -756,7 +815,7 @@ unable_to_embed: if (cur > len) cur = len; - err = grub_disk_read (core_dev->disk, blk, 0, cur, buf); + err = grub_disk_read (core_dev->disk, blk + offset, 0, cur, buf); if (err) grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name, grub_errmsg); @@ -786,6 +845,10 @@ unable_to_embed: 0, GRUB_DISK_SECTOR_SIZE, boot_img)) grub_util_error ("%s", grub_errmsg); +#ifdef GRUB_SETUP_SPARC64 + finish: +#endif + grub_util_biosdisk_flush (root_dev->disk); grub_util_biosdisk_flush (dest_dev->disk);