Annotation of qemu/roms/openbios/packages/pc-parts.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.