/* * Creation Date: <2003/12/03 22:10:45 samuel> * Time-stamp: <2004/01/07 19:17:45 samuel> * * * * 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 ); }