|
|
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.