summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/packages/sun-parts.c
diff options
context:
space:
mode:
authorYang Zhang <yang.z.zhang@intel.com>2015-08-28 09:58:54 +0800
committerYang Zhang <yang.z.zhang@intel.com>2015-09-01 12:44:00 +0800
commite44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch)
tree66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/openbios/packages/sun-parts.c
parent9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff)
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5 Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/openbios/packages/sun-parts.c')
-rw-r--r--qemu/roms/openbios/packages/sun-parts.c343
1 files changed, 343 insertions, 0 deletions
diff --git a/qemu/roms/openbios/packages/sun-parts.c b/qemu/roms/openbios/packages/sun-parts.c
new file mode 100644
index 000000000..16b281b6e
--- /dev/null
+++ b/qemu/roms/openbios/packages/sun-parts.c
@@ -0,0 +1,343 @@
+/*
+ * Sun (Sparc32/64) partition support
+ *
+ * Copyright (C) 2004 Stefan Reinauer
+ *
+ * This code is based (and copied in many places) from
+ * mac partition support by Samuel Rydh (samuel@ibrium.se)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2
+ *
+ */
+
+#include "config.h"
+#include "libopenbios/bindings.h"
+#include "libopenbios/load.h"
+#include "libc/byteorder.h"
+#include "libc/vsprintf.h"
+#include "packages.h"
+
+//#define DEBUG_SUN_PARTS
+
+#ifdef DEBUG_SUN_PARTS
+#define DPRINTF(fmt, args...) \
+ do { printk(fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...)
+#endif
+
+typedef struct {
+ xt_t seek_xt, read_xt;
+ ucell offs_hi, offs_lo;
+ ucell size_hi, size_lo;
+ int type;
+ phandle_t filesystem_ph;
+} sunparts_info_t;
+
+DECLARE_NODE( sunparts, INSTALL_OPEN, sizeof(sunparts_info_t), "+/packages/sun-parts" );
+
+#define SEEK( pos ) ({ DPUSH(pos); call_parent(di->seek_xt); POP(); })
+#define READ( buf, size ) ({ PUSH((ucell)buf); PUSH(size); call_parent(di->read_xt); POP(); })
+
+/* Layout of SUN partition table */
+struct sun_disklabel {
+ uint8_t info[128]; /* Informative text string */
+ uint8_t spare0[14];
+ struct sun_info {
+ uint16_t id;
+ uint16_t flags;
+ } infos[8];
+ uint8_t spare[246]; /* Boot information etc. */
+ uint16_t rspeed; /* Disk rotational speed */
+ uint16_t pcylcount; /* Physical cylinder count */
+ uint16_t sparecyl; /* extra sects per cylinder */
+ uint8_t spare2[4]; /* More magic... */
+ uint16_t ilfact; /* Interleave factor */
+ uint16_t ncyl; /* Data cylinder count */
+ uint16_t nacyl; /* Alt. cylinder count */
+ uint16_t ntrks; /* Tracks per cylinder */
+ uint16_t nsect; /* Sectors per track */
+ uint8_t spare3[4]; /* Even more magic... */
+ struct sun_partition {
+ uint32_t start_cylinder;
+ uint32_t num_sectors;
+ } partitions[8];
+ uint16_t magic; /* Magic number */
+ uint16_t csum; /* Label xor'd checksum */
+};
+
+/* two helper functions */
+
+static inline int
+has_sun_part_magic(unsigned char *sect)
+{
+ struct sun_disklabel *p = (struct sun_disklabel *)sect;
+ uint16_t csum, *ush, tmp16;
+
+ if (__be16_to_cpu(p->magic) != 0xDABE)
+ return 0;
+
+ csum = 0;
+ for (ush = (uint16_t *)p; ush < (uint16_t *)(p + 1); ush++) {
+ tmp16 = __be16_to_cpu(*ush);
+ csum ^= tmp16;
+ }
+ return csum == 0;
+}
+
+/* ( open -- flag ) */
+static void
+sunparts_open( sunparts_info_t *di )
+{
+ char *str = my_args_copy();
+ char *argstr = NULL;
+ char *parstr = NULL;
+ int parnum = -1;
+ unsigned char buf[512];
+ struct sun_disklabel *p;
+ unsigned int i, bs;
+ ducell offs, size;
+ phandle_t ph;
+
+ DPRINTF("sunparts_open '%s'\n", str );
+
+ /*
+ Arguments that we accept:
+ id: [0-7] | [a-h]
+ [(id)][,][filespec]
+ */
+
+ if ( str && strlen(str) ) {
+ /* Detect the arguments */
+ if ((*str >= '0' && *str <= '9') || (*str >= 'a' && *str < ('a' + 8)) || (*str == ',')) {
+ push_str(str);
+ PUSH(',');
+ fword("left-parse-string");
+ parstr = pop_fstr_copy();
+ argstr = pop_fstr_copy();
+ } else {
+ argstr = str;
+ }
+
+ /* Convert the id to a partition number */
+ if (parstr && strlen(parstr)) {
+ if (parstr[0] >= 'a' && parstr[0] < ('a' + 8))
+ parnum = parstr[0] - 'a';
+ else
+ parnum = atol(parstr);
+ }
+ }
+
+ /* Make sure argstr is not null */
+ if (argstr == NULL)
+ argstr = strdup("");
+
+ DPRINTF("parstr: %s argstr: %s parnum: %d\n", parstr, argstr, parnum);
+
+ di->filesystem_ph = 0;
+ di->read_xt = find_parent_method("read");
+ di->seek_xt = find_parent_method("seek");
+
+ SEEK( 0 );
+ if (READ(buf, 512) != 512) {
+ free(str);
+ RET(0);
+ }
+
+ /* Check Magic */
+ if (!has_sun_part_magic(buf)) {
+ DPRINTF("Sun partition magic not found.\n");
+ free(str);
+ RET(0);
+ }
+
+ bs = 512;
+ /* get partition data */
+ p = (struct sun_disklabel *)buf;
+
+ for (i = 0; i < 8; i++) {
+ DPRINTF("%c: %d + %d, id %x, flags %x\n", 'a' + i,
+ __be32_to_cpu(p->partitions[i].start_cylinder),
+ __be32_to_cpu(p->partitions[i].num_sectors),
+ __be16_to_cpu(p->infos[i].id),
+ __be16_to_cpu(p->infos[i].flags));
+ }
+
+ if (parnum < 0)
+ parnum = 0;
+
+ DPRINTF("Selected partition %d\n", parnum);
+
+ offs = (long long)__be32_to_cpu(p->partitions[parnum].start_cylinder) *
+ __be16_to_cpu(p->ntrks) * __be16_to_cpu(p->nsect) * bs;
+
+ di->offs_hi = offs >> BITS;
+ di->offs_lo = offs & (ucell) -1;
+ size = (long long)__be32_to_cpu(p->partitions[parnum].num_sectors) * bs;
+ if (size == 0) {
+ DPRINTF("Partition size is 0, exiting\n");
+ free(str);
+ RET(0);
+ }
+ di->size_hi = size >> BITS;
+ di->size_lo = size & (ucell) -1;
+ di->type = __be16_to_cpu(p->infos[parnum].id);
+
+ DPRINTF("Found Sun partition, offs %lld size %lld\n",
+ (long long)offs, (long long)size);
+
+ /* Probe for filesystem at current offset */
+ DPRINTF("sun-parts: about to probe for fs\n");
+ DPUSH( offs );
+ PUSH_ih( my_parent() );
+ parword("find-filesystem");
+ DPRINTF("sun-parts: done fs probe\n");
+
+ ph = POP_ph();
+ if( ph ) {
+ DPRINTF("sun-parts: filesystem found with ph " FMT_ucellx " and args %s\n", ph, argstr);
+ di->filesystem_ph = ph;
+
+ /* If we have been asked to open a particular file, interpose the filesystem package with
+ the passed filename as an argument */
+ if (argstr && strlen(argstr)) {
+ push_str( argstr );
+ PUSH_ph( ph );
+ fword("interpose");
+ }
+ } else {
+ DPRINTF("sun-parts: no filesystem found; bypassing misc-files interpose\n");
+
+ /* Solaris Fcode boot blocks assume that the disk-label package will always
+ automatically interpose the "ufs-file-system" package if it exists! We
+ need to mimic this behaviour in order for the boot to work. */
+ push_str("ufs-file-system");
+ feval("find-package");
+ ph = POP_ph();
+
+ if (argstr && strlen(argstr) && ph) {
+ ph = POP_ph();
+ push_str(argstr);
+ PUSH_ph(ph);
+ fword("interpose");
+ }
+ }
+
+ free( str );
+ RET( -1 );
+}
+
+/* ( block0 -- flag? ) */
+static void
+sunparts_probe( __attribute__((unused))sunparts_info_t *dummy )
+{
+ unsigned char *buf = (unsigned char *)POP();
+
+ DPRINTF("probing for Sun partitions\n");
+
+ RET ( has_sun_part_magic(buf) );
+}
+
+/* ( -- type offset.d size.d ) */
+static void
+sunparts_get_info( sunparts_info_t *di )
+{
+ DPRINTF("Sun get_info\n");
+ PUSH( di->type );
+ PUSH( di->offs_lo );
+ PUSH( di->offs_hi );
+ PUSH( di->size_lo );
+ PUSH( di->size_hi );
+}
+
+static void
+sunparts_block_size( __attribute__((unused))sunparts_info_t *di )
+{
+ PUSH(512);
+}
+
+static void
+sunparts_initialize( __attribute__((unused))sunparts_info_t *di )
+{
+ fword("register-partition-package");
+}
+
+/* ( pos.d -- status ) */
+static void
+sunparts_seek(sunparts_info_t *di )
+{
+ long long pos = DPOP();
+ long long offs, size;;
+
+ DPRINTF("sunparts_seek %llx:\n", pos);
+
+ /* Seek is invalid if we reach the end of the device */
+ size = ((ducell)di->size_hi << BITS) | di->size_lo;
+ if (pos > size)
+ RET( -1 );
+
+ /* Calculate the seek offset for the parent */
+ offs = ((ducell)di->offs_hi << BITS) | di->offs_lo;
+ offs += pos;
+ DPUSH(offs);
+
+ DPRINTF("sunparts_seek parent offset %llx:\n", offs);
+
+ call_package(di->seek_xt, my_parent());
+}
+
+/* ( buf len -- actlen ) */
+static void
+sunparts_read(sunparts_info_t *di )
+{
+ DPRINTF("sunparts_read\n");
+
+ /* Pass the read back up to the parent */
+ call_package(di->read_xt, my_parent());
+}
+
+/* ( addr -- size ) */
+static void
+sunparts_load( __attribute__((unused))sunparts_info_t *di )
+{
+ /* Invoke the loader */
+ load(my_self());
+}
+
+/* ( pathstr len -- ) */
+static void
+sunparts_dir( sunparts_info_t *di )
+{
+ if ( di->filesystem_ph) {
+ PUSH( my_self() );
+ push_str("dir");
+ PUSH( di->filesystem_ph );
+ fword("find-method");
+ POP();
+ fword("execute");
+ } else {
+ forth_printf("sun-parts: Unable to determine filesystem\n");
+ POP();
+ POP();
+ }
+}
+
+NODE_METHODS( sunparts ) = {
+ { "probe", sunparts_probe },
+ { "open", sunparts_open },
+ { "get-info", sunparts_get_info },
+ { "block-size", sunparts_block_size },
+ { "seek", sunparts_seek },
+ { "read", sunparts_read },
+ { "load", sunparts_load },
+ { "dir", sunparts_dir },
+ { NULL, sunparts_initialize },
+};
+
+void
+sunparts_init( void )
+{
+ REGISTER_NODE( sunparts );
+}