|
|
1.1 ! root 1: /* ! 2: * pc partition support ! 3: * ! 4: * Copyright (C) 2004 Stefan Reinauer ! 5: * ! 6: * This code is based (and copied in many places) from ! 7: * mac partition support by Samuel Rydh ([email protected]) ! 8: * ! 9: * This program is free software; you can redistribute it and/or ! 10: * modify it under the terms of the GNU General Public License ! 11: * version 2 ! 12: * ! 13: */ ! 14: ! 15: #include "config.h" ! 16: #include "libopenbios/bindings.h" ! 17: #include "libopenbios/load.h" ! 18: #include "libc/byteorder.h" ! 19: #include "libc/vsprintf.h" ! 20: #include "packages.h" ! 21: ! 22: //#define DEBUG_PC_PARTS ! 23: ! 24: #ifdef DEBUG_PC_PARTS ! 25: #define DPRINTF(fmt, args...) \ ! 26: do { printk(fmt , ##args); } while (0) ! 27: #else ! 28: #define DPRINTF(fmt, args...) ! 29: #endif ! 30: ! 31: typedef struct { ! 32: xt_t seek_xt, read_xt; ! 33: ucell offs_hi, offs_lo; ! 34: ucell size_hi, size_lo; ! 35: phandle_t filesystem_ph; ! 36: } pcparts_info_t; ! 37: ! 38: DECLARE_NODE( pcparts, INSTALL_OPEN, sizeof(pcparts_info_t), "+/packages/pc-parts" ); ! 39: ! 40: #define SEEK( pos ) ({ DPUSH(pos); call_parent(di->seek_xt); POP(); }) ! 41: #define READ( buf, size ) ({ PUSH(pointer2cell(buf)); PUSH(size); call_parent(di->read_xt); POP(); }) ! 42: ! 43: /* three helper functions */ ! 44: ! 45: static inline int has_pc_valid_partition(unsigned char *sect) ! 46: { ! 47: /* Make sure the partition table contains at least one valid entry */ ! 48: return (sect[0x1c2] != 0 || sect[0x1d2] != 0 || sect[0x1e2] != 0); ! 49: } ! 50: ! 51: static inline int has_pc_part_magic(unsigned char *sect) ! 52: { ! 53: return sect[0x1fe]==0x55 && sect[0x1ff]==0xAA; ! 54: } ! 55: ! 56: static inline int is_pc_extended_part(unsigned char type) ! 57: { ! 58: return type==5 || type==0xf || type==0x85; ! 59: } ! 60: ! 61: /* ( open -- flag ) */ ! 62: static void ! 63: pcparts_open( pcparts_info_t *di ) ! 64: { ! 65: char *str = my_args_copy(); ! 66: char *argstr = strdup(""); ! 67: char *parstr = strdup(""); ! 68: int bs, parnum=-1; ! 69: int found = 0; ! 70: phandle_t ph; ! 71: ducell offs, size; ! 72: ! 73: /* Layout of PC partition table */ ! 74: struct pc_partition { ! 75: unsigned char boot; ! 76: unsigned char head; ! 77: unsigned char sector; ! 78: unsigned char cyl; ! 79: unsigned char type; ! 80: unsigned char e_head; ! 81: unsigned char e_sector; ! 82: unsigned char e_cyl; ! 83: u32 start_sect; /* unaligned little endian */ ! 84: u32 nr_sects; /* ditto */ ! 85: } *p, *partition; ! 86: ! 87: unsigned char buf[512]; ! 88: ! 89: DPRINTF("pcparts_open '%s'\n", str ); ! 90: ! 91: /* ! 92: Arguments that we accept: ! 93: id: [0-7] ! 94: [(id)][,][filespec] ! 95: */ ! 96: ! 97: if( str ) { ! 98: if ( !strlen(str) ) ! 99: parnum = -1; ! 100: else { ! 101: /* Detect the boot parameters */ ! 102: char *ptr; ! 103: ptr = str; ! 104: ! 105: /* <id>,<file> */ ! 106: if (*ptr >= '0' && *ptr <= '9' && *(ptr + 1) == ',') { ! 107: parstr = ptr; ! 108: *(ptr + 1) = '\0'; ! 109: argstr = ptr + 2; ! 110: } ! 111: ! 112: /* <id> */ ! 113: else if (*ptr >= '0' && *ptr <='9' && *(ptr + 1) == '\0') { ! 114: parstr = ptr; ! 115: } ! 116: ! 117: /* ,<file> */ ! 118: else if (*ptr == ',') { ! 119: argstr = ptr + 1; ! 120: } ! 121: ! 122: /* <file> */ ! 123: else { ! 124: argstr = str; ! 125: } ! 126: ! 127: /* Convert the id to a partition number */ ! 128: if (strlen(parstr)) ! 129: parnum = atol(parstr); ! 130: } ! 131: } ! 132: ! 133: DPRINTF("parstr: %s argstr: %s parnum: %d\n", parstr, argstr, parnum); ! 134: free(parstr); ! 135: ! 136: if( parnum < 0 ) ! 137: parnum = 0; ! 138: ! 139: di->filesystem_ph = 0; ! 140: di->read_xt = find_parent_method("read"); ! 141: di->seek_xt = find_parent_method("seek"); ! 142: ! 143: SEEK( 0 ); ! 144: if( READ(buf, 512) != 512 ) ! 145: RET(0); ! 146: ! 147: /* Check Magic */ ! 148: if (!has_pc_part_magic(buf)) { ! 149: DPRINTF("pc partition magic not found.\n"); ! 150: RET(0); ! 151: } ! 152: ! 153: /* Actual partition data */ ! 154: partition = (struct pc_partition *) (buf + 0x1be); ! 155: ! 156: /* Make sure we use a copy accessible from an aligned pointer (some archs ! 157: e.g. SPARC will crash otherwise) */ ! 158: p = malloc(sizeof(struct pc_partition)); ! 159: ! 160: bs = 512; ! 161: ! 162: if (parnum < 4) { ! 163: /* primary partition */ ! 164: partition += parnum; ! 165: memcpy(p, partition, sizeof(struct pc_partition)); ! 166: ! 167: if (p->type == 0 || is_pc_extended_part(p->type)) { ! 168: DPRINTF("partition %d does not exist\n", parnum+1 ); ! 169: RET( 0 ); ! 170: } ! 171: ! 172: offs = (long long)(__le32_to_cpu(p->start_sect)) * bs; ! 173: di->offs_hi = offs >> BITS; ! 174: di->offs_lo = offs & (ucell) -1; ! 175: ! 176: size = (long long)(__le32_to_cpu(p->nr_sects)) * bs; ! 177: di->size_hi = size >> BITS; ! 178: di->size_lo = size & (ucell) -1; ! 179: ! 180: DPRINTF("Primary partition at sector %x\n", __le32_to_cpu(p->start_sect)); ! 181: ! 182: found = 1; ! 183: } else { ! 184: /* Extended partition */ ! 185: int i, cur_part; ! 186: unsigned long ext_start, cur_table; ! 187: ! 188: /* Search for the extended partition ! 189: * which contains logical partitions */ ! 190: for (i = 0; i < 4; i++) { ! 191: if (is_pc_extended_part(p[i].type)) ! 192: break; ! 193: } ! 194: ! 195: if (i >= 4) { ! 196: DPRINTF("Extended partition not found\n"); ! 197: RET( 0 ); ! 198: } ! 199: ! 200: DPRINTF("Extended partition at %d\n", i+1); ! 201: ! 202: /* Visit each logical partition labels */ ! 203: ext_start = __le32_to_cpu(p[i].start_sect); ! 204: cur_table = ext_start; ! 205: cur_part = 4; ! 206: ! 207: while (cur_part <= parnum) { ! 208: DPRINTF("cur_part=%d at %lx\n", cur_part, cur_table); ! 209: ! 210: SEEK( cur_table * bs ); ! 211: if( READ(buf, sizeof(512)) != sizeof(512) ) ! 212: RET( 0 ); ! 213: ! 214: if (!has_pc_part_magic(buf)) { ! 215: DPRINTF("Extended partition has no magic\n"); ! 216: break; ! 217: } ! 218: ! 219: /* Read the extended partition, making sure we are aligned again */ ! 220: partition = (struct pc_partition *) (buf + 0x1be); ! 221: memcpy(p, partition, sizeof(struct pc_partition)); ! 222: ! 223: /* First entry is the logical partition */ ! 224: if (cur_part == parnum) { ! 225: if (p->type == 0) { ! 226: DPRINTF("Partition %d is empty\n", parnum+1); ! 227: RET( 0 ); ! 228: } ! 229: ! 230: offs = (long long)(cur_table+__le32_to_cpu(p->start_sect)) * bs; ! 231: di->offs_hi = offs >> BITS; ! 232: di->offs_lo = offs & (ucell) -1; ! 233: ! 234: size = (long long)__le32_to_cpu(p->nr_sects) * bs; ! 235: di->size_hi = size >> BITS; ! 236: di->size_lo = size & (ucell) -1; ! 237: ! 238: found = 1; ! 239: break; ! 240: } ! 241: ! 242: /* Second entry is link to next partition */ ! 243: if (!is_pc_extended_part(p[1].type)) { ! 244: DPRINTF("no link\n"); ! 245: break; ! 246: } ! 247: ! 248: cur_table = ext_start + __le32_to_cpu(p[1].start_sect); ! 249: cur_part++; ! 250: } ! 251: ! 252: if (!found) { ! 253: DPRINTF("Logical partition %d does not exist\n", parnum+1); ! 254: RET( 0 ); ! 255: } ! 256: } ! 257: ! 258: free(p); ! 259: ! 260: if (found) { ! 261: /* We have a valid partition - so probe for a filesystem at the current offset */ ! 262: DPRINTF("pc-parts: about to probe for fs\n"); ! 263: DPUSH( offs ); ! 264: PUSH_ih( my_parent() ); ! 265: parword("find-filesystem"); ! 266: DPRINTF("pc-parts: done fs probe\n"); ! 267: ! 268: ph = POP_ph(); ! 269: if( ph ) { ! 270: DPRINTF("pc-parts: filesystem found with ph " FMT_ucellx " and args %s\n", ph, argstr); ! 271: di->filesystem_ph = ph; ! 272: ! 273: /* If we have been asked to open a particular file, interpose the filesystem package with ! 274: the passed filename as an argument */ ! 275: if (strlen(argstr)) { ! 276: push_str( argstr ); ! 277: PUSH_ph( ph ); ! 278: fword("interpose"); ! 279: } ! 280: } else { ! 281: DPRINTF("pc-parts: no filesystem found; bypassing misc-files interpose\n"); ! 282: } ! 283: ! 284: free( str ); ! 285: RET( -1 ); ! 286: } else { ! 287: DPRINTF("pc-parts: unable to locate partition\n"); ! 288: ! 289: free( str ); ! 290: RET( 0 ); ! 291: } ! 292: } ! 293: ! 294: /* ( block0 -- flag? ) */ ! 295: static void ! 296: pcparts_probe( pcparts_info_t *dummy ) ! 297: { ! 298: unsigned char *buf = (unsigned char *)cell2pointer(POP()); ! 299: ! 300: DPRINTF("probing for PC partitions\n"); ! 301: ! 302: /* We also check that at least one valid partition exists; this is because ! 303: some CDs seem broken in that they have a partition table but it is empty ! 304: e.g. MorphOS. */ ! 305: RET ( has_pc_part_magic(buf) && has_pc_valid_partition(buf) ); ! 306: } ! 307: ! 308: /* ( -- type offset.d size.d ) */ ! 309: static void ! 310: pcparts_get_info( pcparts_info_t *di ) ! 311: { ! 312: DPRINTF("PC get_info\n"); ! 313: PUSH( -1 ); /* no type */ ! 314: PUSH( di->offs_lo ); ! 315: PUSH( di->offs_hi ); ! 316: PUSH( di->size_lo ); ! 317: PUSH( di->size_hi ); ! 318: } ! 319: ! 320: static void ! 321: pcparts_block_size( __attribute__((unused))pcparts_info_t *di ) ! 322: { ! 323: PUSH(512); ! 324: } ! 325: ! 326: static void ! 327: pcparts_initialize( pcparts_info_t *di ) ! 328: { ! 329: fword("register-partition-package"); ! 330: } ! 331: ! 332: /* ( pos.d -- status ) */ ! 333: static void ! 334: pcparts_seek(pcparts_info_t *di ) ! 335: { ! 336: long long pos = DPOP(); ! 337: long long offs, size; ! 338: ! 339: DPRINTF("pcparts_seek %llx:\n", pos); ! 340: ! 341: /* Seek is invalid if we reach the end of the device */ ! 342: size = ((ducell)di->size_hi << BITS) | di->size_lo; ! 343: if (pos > size) ! 344: RET( -1 ); ! 345: ! 346: /* Calculate the seek offset for the parent */ ! 347: offs = ((ducell)di->offs_hi << BITS) | di->offs_lo; ! 348: offs += pos; ! 349: DPUSH(offs); ! 350: ! 351: DPRINTF("pcparts_seek parent offset %llx:\n", offs); ! 352: ! 353: call_package(di->seek_xt, my_parent()); ! 354: } ! 355: ! 356: /* ( buf len -- actlen ) */ ! 357: static void ! 358: pcparts_read(pcparts_info_t *di ) ! 359: { ! 360: DPRINTF("pcparts_read\n"); ! 361: ! 362: /* Pass the read back up to the parent */ ! 363: call_package(di->read_xt, my_parent()); ! 364: } ! 365: ! 366: /* ( addr -- size ) */ ! 367: static void ! 368: pcparts_load( __attribute__((unused))pcparts_info_t *di ) ! 369: { ! 370: /* Invoke the loader */ ! 371: load(my_self()); ! 372: } ! 373: ! 374: /* ( pathstr len -- ) */ ! 375: static void ! 376: pcparts_dir( pcparts_info_t *di ) ! 377: { ! 378: if ( di->filesystem_ph ) { ! 379: PUSH( my_self() ); ! 380: push_str("dir"); ! 381: PUSH( di->filesystem_ph ); ! 382: fword("find-method"); ! 383: POP(); ! 384: fword("execute"); ! 385: } else { ! 386: forth_printf("pc-parts: Unable to determine filesystem\n"); ! 387: POP(); ! 388: POP(); ! 389: } ! 390: } ! 391: ! 392: NODE_METHODS( pcparts ) = { ! 393: { "probe", pcparts_probe }, ! 394: { "open", pcparts_open }, ! 395: { "seek", pcparts_seek }, ! 396: { "read", pcparts_read }, ! 397: { "load", pcparts_load }, ! 398: { "dir", pcparts_dir }, ! 399: { "get-info", pcparts_get_info }, ! 400: { "block-size", pcparts_block_size }, ! 401: { NULL, pcparts_initialize }, ! 402: }; ! 403: ! 404: void ! 405: pcparts_init( void ) ! 406: { ! 407: REGISTER_NODE( pcparts ); ! 408: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.