Commit 7e6fab33 authored by Eric Snowberg's avatar Eric Snowberg Committed by Colin Watson

Add support for modern sparc64 hardware

Origin: other, https://github.com/esnowberg/grub2-sparc/tree/sparc-next-v4
Bug-Debian: https://bugs.debian.org/854568
Last-Update: 2018-03-02

Patch-Name: sparc64-support.patch
parent 14c4f884
......@@ -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;
......
......@@ -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
......
......@@ -201,6 +201,8 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
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)
......
......@@ -66,6 +66,7 @@ get_uuid (const char *name, char **uuid, int getnative)
/* 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:
......
This diff is collapsed.
......@@ -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 *curcan)
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, const char *path)
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);
......
......@@ -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
......
......@@ -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)
......@@ -482,6 +483,93 @@ grub_ieee1275_close (grub_ieee1275_ihandle_t ihandle)
return 0;
}
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_t *msecs)
*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;
}
......@@ -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 **device __attribute__ ((unused)),
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 ();
}
}
......
......@@ -561,3 +561,30 @@ grub_ieee1275_canonicalise_devname (const char *path)
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;
}
......@@ -30,7 +30,6 @@ static struct grub_parser_state_transition state_transitions[] = {
{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},
......
......@@ -89,3 +89,56 @@ grub_ieee1275_alloc_physmem (grub_addr_t *paddr, grub_size_t size,
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));
}
......@@ -58,6 +58,11 @@ grub_install_get_blocklist (grub_device_t root_dev,
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);
......
......@@ -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
......@@ -120,6 +158,8 @@ find_obppath (const char *sysfs_path_orig)
#endif
fd = open(path, O_RDONLY);
#ifndef __sparc__
if (fd < 0 || fstat (fd, &st) < 0)
{
if (fd >= 0)
......@@ -127,6 +167,7 @@ find_obppath (const char *sysfs_path_orig)
snprintf(path, path_size, "%s/devspec", sysfs_path);
fd = open(path, O_RDONLY);
}
#endif
if (fd < 0 || fstat (fd, &st) < 0)
{
......@@ -307,6 +348,55 @@ of_path_of_ide(const char *sys_devname __attribute__((unused)), const char *devi
return ret;
}
#ifdef __sparc__
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);
if (of_path)
strcat (of_path, disk);
free (sysfs_path);
return of_path;
}
#endif
static int
vendor_is_ATA(const char *path)
{
......@@ -335,6 +425,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 +546,7 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
{
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 +563,11 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
}