|
|
1.1 root 1: /*
2: * Creation Date: <2003/12/04 17:07:05 samuel>
3: * Time-stamp: <2004/01/07 19:36:09 samuel>
4: *
5: * <mac-parts.c>
6: *
7: * macintosh partition support
8: *
9: * Copyright (C) 2003, 2004 Samuel Rydh ([email protected])
10: *
11: * This program is free software; you can redistribute it and/or
12: * modify it under the terms of the GNU General Public License
13: * version 2
14: *
15: */
16:
17: #include "config.h"
18: #include "libopenbios/bindings.h"
19: #include "libopenbios/load.h"
20: #include "mac-parts.h"
21: #include "libc/byteorder.h"
22: #include "libc/vsprintf.h"
23: #include "packages.h"
24:
25: //#define CONFIG_DEBUG_MAC_PARTS
26:
27: #ifdef CONFIG_DEBUG_MAC_PARTS
28: #define DPRINTF(fmt, args...) \
29: do { printk("MAC-PARTS: " fmt , ##args); } while (0)
30: #else
31: #define DPRINTF(fmt, args...) do {} while(0)
32: #endif
33:
34: typedef struct {
35: xt_t seek_xt, read_xt;
36: ucell offs_hi, offs_lo;
37: ucell size_hi, size_lo;
38: unsigned int blocksize;
39: phandle_t filesystem_ph;
40: } macparts_info_t;
41:
42: DECLARE_NODE( macparts, INSTALL_OPEN, sizeof(macparts_info_t), "+/packages/mac-parts" );
43:
44: #define SEEK( pos ) ({ DPUSH(pos); call_parent(di->seek_xt); POP(); })
45: #define READ( buf, size ) ({ PUSH(pointer2cell(buf)); PUSH(size); call_parent(di->read_xt); POP(); })
46:
47: /* ( open -- flag ) */
48: static void
49: macparts_open( macparts_info_t *di )
50: {
51: char *str = my_args_copy();
52: char *argstr = strdup("");
53: char *parstr = strdup("");
54: int bs, parnum=-1;
55: desc_map_t dmap;
56: part_entry_t par;
57: int ret = 0;
58: int want_bootcode = 0;
59: phandle_t ph;
60: ducell offs = 0, size = -1;
61:
62: DPRINTF("macparts_open '%s'\n", str );
63:
64: /*
65: Arguments that we accept:
66: id: [0-7]
67: [(id)][,][filespec]
68: */
69:
70: if( str ) {
71: if ( !strlen(str) )
72: parnum = -1;
73: else {
74: /* Detect the boot parameters */
75: char *ptr;
76: ptr = str;
77:
78: /* <id>,<file> */
79: if (*ptr >= '0' && *ptr <= '9' && *(ptr + 1) == ',') {
80: parstr = ptr;
81: *(ptr + 1) = '\0';
82: argstr = ptr + 2;
83: }
84:
85: /* <id> */
86: else if (*ptr >= '0' && *ptr <='9' && *(ptr + 1) == '\0') {
87: parstr = ptr;
88: }
89:
90: /* ,<file> */
91: else if (*ptr == ',') {
92: argstr = ptr + 1;
93: }
94:
95: /* <file> */
96: else {
97: argstr = str;
98: }
99:
100: /* Convert the id to a partition number */
101: if (strlen(parstr))
102: parnum = atol(parstr);
103:
104: /* Detect if we are looking for the bootcode */
105: if (strcmp(argstr, "%BOOT") == 0)
106: want_bootcode = 1;
107: }
108: }
109:
110: DPRINTF("parstr: %s argstr: %s parnum: %d\n", parstr, argstr, parnum);
111:
112: DPRINTF("want_bootcode %d\n", want_bootcode);
113: DPRINTF("macparts_open %d\n", parnum);
114:
115: di->filesystem_ph = 0;
116: di->read_xt = find_parent_method("read");
117: di->seek_xt = find_parent_method("seek");
118:
119: SEEK( 0 );
120: if( READ(&dmap, sizeof(dmap)) != sizeof(dmap) )
121: goto out;
122:
123: /* partition maps might support multiple block sizes; in this case,
124: * pmPyPartStart is typically given in terms of 512 byte blocks.
125: */
126: bs = __be16_to_cpu(dmap.sbBlockSize);
127: if( bs != 512 ) {
128: SEEK( 512 );
129: READ( &par, sizeof(par) );
130: if( __be16_to_cpu(par.pmSig) == DESC_PART_SIGNATURE )
131: bs = 512;
132: }
133: SEEK( bs );
134: if( READ(&par, sizeof(par)) != sizeof(par) )
135: goto out;
136: if (__be16_to_cpu(par.pmSig) != DESC_PART_SIGNATURE)
137: goto out;
138:
139: /*
140: * Implement partition selection as per the PowerPC Microprocessor CHRP bindings
141: */
142:
143: if (str == NULL || parnum == 0) {
144: /* According to the spec, partition 0 as well as no arguments means the whole disk */
145: offs = (long long)0;
146: size = (long long)__be32_to_cpu(dmap.sbBlkCount) * bs;
147:
148: di->blocksize = (unsigned int)bs;
149:
150: di->offs_hi = offs >> BITS;
151: di->offs_lo = offs & (ucell) -1;
152:
153: di->size_hi = size >> BITS;
154: di->size_lo = size & (ucell) -1;
155:
156: ret = -1;
157: goto out;
158:
159: } else if (parnum == -1 && strlen(argstr)) {
160:
161: DPRINTF("mac-parts: counted %d partitions\n", __be32_to_cpu(par.pmMapBlkCnt));
162:
163: /* No partition was explicitly requested, but an argstr was passed in.
164: So let's find a suitable partition... */
165: for (parnum = 1; parnum <= __be32_to_cpu(par.pmMapBlkCnt); parnum++) {
166: SEEK( bs * parnum );
167: READ( &par, sizeof(par) );
168: if( __be16_to_cpu(par.pmSig) != DESC_PART_SIGNATURE ||
169: !__be32_to_cpu(par.pmPartBlkCnt) )
170: break;
171:
172: DPRINTF("found partition type: %s with status %x\n", par.pmPartType, __be32_to_cpu(par.pmPartStatus));
173:
174: /* If we have a valid, allocated and readable partition... */
175: if( (__be32_to_cpu(par.pmPartStatus) & kPartitionAUXIsValid) &&
176: (__be32_to_cpu(par.pmPartStatus) & kPartitionAUXIsAllocated) &&
177: (__be32_to_cpu(par.pmPartStatus) & kPartitionAUXIsReadable) ) {
178: offs = (long long)__be32_to_cpu(par.pmPyPartStart) * bs;
179: size = (long long)__be32_to_cpu(par.pmPartBlkCnt) * bs;
180:
181: /* If the filename was set to %BOOT, we actually want the bootcode */
182: if (want_bootcode && (__be32_to_cpu(par.pmPartStatus) & kPartitionAUXIsBootValid)) {
183: offs += (long long)__be32_to_cpu(par.pmLgBootStart) * bs;
184: size = (long long)__be32_to_cpu(par.pmBootSize);
185:
186: goto found;
187: } else {
188: /* Otherwise we were passed a filename and path. So let's
189: choose the first partition with a valid filesystem */
190: DPUSH( offs );
191: PUSH_ih( my_parent() );
192: parword("find-filesystem");
193:
194: ph = POP_ph();
195: if (ph)
196: goto found;
197: }
198: }
199: }
200:
201: } else {
202: /* Another partition was explicitly requested */
203: SEEK( bs * parnum );
204: READ( &par, sizeof(par) );
205:
206: if( (__be32_to_cpu(par.pmPartStatus) & kPartitionAUXIsValid) &&
207: (__be32_to_cpu(par.pmPartStatus) & kPartitionAUXIsAllocated) &&
208: (__be32_to_cpu(par.pmPartStatus) & kPartitionAUXIsReadable) ) {
209:
210: offs = (long long)__be32_to_cpu(par.pmPyPartStart) * bs;
211: size = (long long)__be32_to_cpu(par.pmPartBlkCnt) * bs;
212: }
213: }
214:
215: /* If we couldn't find a partition, exit */
216: if (size == -1) {
217: DPRINTF("Unable to automatically find partition!\n");
218: goto out;
219: }
220:
221: found:
222:
223: ret = -1;
224: di->blocksize = (unsigned int)bs;
225:
226: di->offs_hi = offs >> BITS;
227: di->offs_lo = offs & (ucell) -1;
228:
229: di->size_hi = size >> BITS;
230: di->size_lo = size & (ucell) -1;
231:
232: /* We have a valid partition - so probe for a filesystem at the current offset */
233: DPRINTF("mac-parts: about to probe for fs\n");
234: DPUSH( offs );
235: PUSH_ih( my_parent() );
236: parword("find-filesystem");
237: DPRINTF("mac-parts: done fs probe\n");
238:
239: ph = POP_ph();
240: if( ph ) {
241: DPRINTF("mac-parts: filesystem found with ph " FMT_ucellx " and args %s\n", ph, argstr);
242: di->filesystem_ph = ph;
243:
244: /* If the filename was %BOOT then it's not a real filename, so clear argstr before
245: attempting interpose */
246: if (want_bootcode)
247: argstr = strdup("");
248:
249: /* If we have been asked to open a particular file, interpose the filesystem package with
250: the passed filename as an argument */
251: if (strlen(argstr)) {
252: push_str( argstr );
253: PUSH_ph( ph );
254: fword("interpose");
255: }
256: } else {
257: DPRINTF("mac-parts: no filesystem found; bypassing misc-files interpose\n");
258: }
259:
260: free( str );
261:
262: out:
263: PUSH( ret );
264: }
265:
266: /* ( block0 -- flag? ) */
267: static void
268: macparts_probe( macparts_info_t *dummy )
269: {
270: desc_map_t *dmap = (desc_map_t*)cell2pointer(POP());
271:
272: DPRINTF("macparts_probe %x ?= %x\n", dmap->sbSig, DESC_MAP_SIGNATURE);
273: if( __be16_to_cpu(dmap->sbSig) != DESC_MAP_SIGNATURE )
274: RET(0);
275: RET(-1);
276: }
277:
278: /* ( -- type offset.d size.d ) */
279: static void
280: macparts_get_info( macparts_info_t *di )
281: {
282: DPRINTF("macparts_get_info");
283:
284: PUSH( -1 ); /* no type */
285: PUSH( di->offs_lo );
286: PUSH( di->offs_hi );
287: PUSH( di->size_lo );
288: PUSH( di->size_hi );
289: }
290:
291: static void
292: macparts_block_size( macparts_info_t *di )
293: {
294: DPRINTF("macparts_block_size = %x\n", di->blocksize);
295: PUSH(di->blocksize);
296: }
297:
298: static void
299: macparts_initialize( macparts_info_t *di )
300: {
301: fword("register-partition-package");
302: }
303:
304: /* ( pos.d -- status ) */
305: static void
306: macparts_seek(macparts_info_t *di )
307: {
308: long long pos = DPOP();
309: long long offs, size;
310:
311: DPRINTF("macparts_seek %llx:\n", pos);
312:
313: /* Seek is invalid if we reach the end of the device */
314: size = ((ducell)di->size_hi << BITS) | di->size_lo;
315: if (pos > size)
316: RET( -1 );
317:
318: /* Calculate the seek offset for the parent */
319: offs = ((ducell)di->offs_hi << BITS) | di->offs_lo;
320: offs += pos;
321: DPUSH(offs);
322:
323: DPRINTF("macparts_seek parent offset %llx:\n", offs);
324:
325: call_package(di->seek_xt, my_parent());
326: }
327:
328: /* ( buf len -- actlen ) */
329: static void
330: macparts_read(macparts_info_t *di )
331: {
332: DPRINTF("macparts_read\n");
333:
334: /* Pass the read back up to the parent */
335: call_package(di->read_xt, my_parent());
336: }
337:
338: /* ( addr -- size ) */
339: static void
340: macparts_load( __attribute__((unused))macparts_info_t *di )
341: {
342: /* Invoke the loader */
343: load(my_self());
344: }
345:
346: /* ( pathstr len -- ) */
347: static void
348: macparts_dir( macparts_info_t *di )
349: {
350: /* On PPC Mac, the first partition chosen according to the CHRP boot
351: specification (i.e. marked as bootable) may not necessarily contain
352: a valid FS */
353: if ( di->filesystem_ph ) {
354: PUSH( my_self() );
355: push_str("dir");
356: PUSH( di->filesystem_ph );
357: fword("find-method");
358: POP();
359: fword("execute");
360: } else {
361: forth_printf("mac-parts: Unable to determine filesystem\n");
362: POP();
363: POP();
364: }
365: }
366:
367: NODE_METHODS( macparts ) = {
368: { "probe", macparts_probe },
369: { "open", macparts_open },
370: { "seek", macparts_seek },
371: { "read", macparts_read },
372: { "load", macparts_load },
373: { "dir", macparts_dir },
374: { "get-info", macparts_get_info },
375: { "block-size", macparts_block_size },
376: { NULL, macparts_initialize },
377: };
378:
379: void
380: macparts_init( void )
381: {
382: REGISTER_NODE( macparts );
383: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.