summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/packages/disk-label.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/openbios/packages/disk-label.c')
-rw-r--r--qemu/roms/openbios/packages/disk-label.c245
1 files changed, 245 insertions, 0 deletions
diff --git a/qemu/roms/openbios/packages/disk-label.c b/qemu/roms/openbios/packages/disk-label.c
new file mode 100644
index 000000000..1ca9bd867
--- /dev/null
+++ b/qemu/roms/openbios/packages/disk-label.c
@@ -0,0 +1,245 @@
+/*
+ * Creation Date: <2003/12/03 22:10:45 samuel>
+ * Time-stamp: <2004/01/07 19:17:45 samuel>
+ *
+ * <disk-label.c>
+ *
+ * Partition support
+ *
+ * Copyright (C) 2003, 2004 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/diskio.h"
+#include "libc/vsprintf.h"
+#include "packages.h"
+
+//#define DEBUG_DISK_LABEL
+
+#ifdef DEBUG_DISK_LABEL
+#define DPRINTF(fmt, args...) \
+do { printk("DISK-LABEL - %s: " fmt, __func__ , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do { } while (0)
+#endif
+
+typedef struct {
+ xt_t parent_seek_xt;
+ xt_t parent_tell_xt;
+ xt_t parent_read_xt;
+
+ ucell offs_hi, offs_lo;
+ ucell size_hi, size_lo;
+ int block_size;
+ int type; /* partition type or -1 */
+
+ ihandle_t part_ih;
+ phandle_t filesystem_ph;
+} dlabel_info_t;
+
+DECLARE_NODE( dlabel, 0, sizeof(dlabel_info_t), "/packages/disk-label" );
+
+
+/* ( -- ) */
+static void
+dlabel_close( __attribute__((unused))dlabel_info_t *di )
+{
+}
+
+/* ( -- success? ) */
+static void
+dlabel_open( dlabel_info_t *di )
+{
+ char *path;
+ char block0[512];
+ phandle_t ph;
+ int success=0;
+ cell status;
+
+ path = my_args_copy();
+
+ DPRINTF("dlabel-open '%s'\n", path );
+
+ di->part_ih = 0;
+
+ /* Find parent methods */
+ di->filesystem_ph = 0;
+ di->parent_seek_xt = find_parent_method("seek");
+ di->parent_tell_xt = find_parent_method("tell");
+ di->parent_read_xt = find_parent_method("read");
+
+ /* If arguments have been passed, determine the partition/filesystem type */
+ if (path && strlen(path)) {
+
+ /* Read first block from parent device */
+ DPUSH(0);
+ call_package(di->parent_seek_xt, my_parent());
+ POP();
+
+ PUSH(pointer2cell(block0));
+ PUSH(sizeof(block0));
+ call_package(di->parent_read_xt, my_parent());
+ status = POP();
+ if (status != sizeof(block0))
+ goto out;
+
+ /* Find partition handler */
+ PUSH( pointer2cell(block0) );
+ selfword("find-part-handler");
+ ph = POP_ph();
+ if( ph ) {
+ /* We found a suitable partition handler, so interpose it */
+ DPRINTF("Partition found on disk - scheduling interpose with ph " FMT_ucellx "\n", ph);
+
+ push_str(path);
+ PUSH_ph(ph);
+ fword("interpose");
+
+ success = 1;
+ } else {
+ /* unknown (or missing) partition map,
+ * try the whole disk
+ */
+
+ DPRINTF("Unknown or missing partition map; trying whole disk\n");
+
+ /* Probe for filesystem from start of device */
+ DPUSH ( 0 );
+ PUSH_ih( my_self() );
+ selfword("find-filesystem");
+ ph = POP_ph();
+ if( ph ) {
+ /* If we have been asked to open a particular file, interpose the filesystem package with the passed filename as an argument */
+ di->filesystem_ph = ph;
+
+ DPRINTF("Located filesystem with ph " FMT_ucellx "\n", ph);
+ DPRINTF("path: %s length: %d\n", path, strlen(path));
+
+ if (path && strlen(path)) {
+ DPRINTF("INTERPOSE!\n");
+
+ push_str( path );
+ PUSH_ph( ph );
+ fword("interpose");
+ }
+ } else if (path && strcmp(path, "%BOOT") != 0) {
+ goto out;
+ }
+
+ success = 1;
+ }
+ } else {
+ /* No arguments were passed, so we just use the parent raw device directly */
+ success = 1;
+ }
+
+out:
+ if( path )
+ free( path );
+ if( !success ) {
+ dlabel_close( di );
+ RET(0);
+ }
+ PUSH(-1);
+}
+
+/* ( addr len -- actual ) */
+static void
+dlabel_read( dlabel_info_t *di )
+{
+ /* Call back up to parent */
+ call_package(di->parent_read_xt, my_parent());
+}
+
+/* ( pos.d -- status ) */
+static void
+dlabel_seek( dlabel_info_t *di )
+{
+ /* Call back up to parent */
+ call_package(di->parent_seek_xt, my_parent());
+}
+
+/* ( -- filepos.d ) */
+static void
+dlabel_tell( dlabel_info_t *di )
+{
+ /* Call back up to parent */
+ call_package(di->parent_tell_xt, my_parent());
+}
+
+/* ( addr len -- actual ) */
+static void
+dlabel_write( __attribute__((unused)) dlabel_info_t *di )
+{
+ DDROP();
+ PUSH( -1 );
+}
+
+/* ( addr -- size ) */
+static void
+dlabel_load( __attribute__((unused)) dlabel_info_t *di )
+{
+ /* Try the load method of the part package */
+ xt_t xt;
+
+ /* If we have a partition handle, invoke the load word on it */
+ if (di->part_ih) {
+ xt = find_ih_method("load", di->part_ih);
+ if (!xt) {
+ forth_printf("load currently not implemented for ihandle " FMT_ucellx "\n", di->part_ih);
+ PUSH(0);
+ return;
+ }
+
+ DPRINTF("calling load on ihandle " FMT_ucellx "\n", di->part_ih);
+
+ call_package(xt, di->part_ih);
+ } else {
+ /* Otherwise attempt load directly on the raw disk */
+ DPRINTF("calling load on raw disk ihandle " FMT_ucellx "\n", my_self());
+
+ load(my_self());
+ }
+}
+
+/* ( pathstr len -- ) */
+static void
+dlabel_dir( dlabel_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("disk-label: Unable to determine filesystem\n");
+ POP();
+ POP();
+ }
+}
+
+NODE_METHODS( dlabel ) = {
+ { "open", dlabel_open },
+ { "close", dlabel_close },
+ { "load", dlabel_load },
+ { "read", dlabel_read },
+ { "write", dlabel_write },
+ { "seek", dlabel_seek },
+ { "tell", dlabel_tell },
+ { "dir", dlabel_dir },
+};
+
+void
+disklabel_init( void )
+{
+ REGISTER_NODE( dlabel );
+}