diff options
author | Yang Zhang <yang.z.zhang@intel.com> | 2015-08-28 09:58:54 +0800 |
---|---|---|
committer | Yang Zhang <yang.z.zhang@intel.com> | 2015-09-01 12:44:00 +0800 |
commit | e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch) | |
tree | 66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/openbios/packages/sun-parts.c | |
parent | 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (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.c | 343 |
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 ); +} |