2 * Creation Date: <2003/12/04 17:07:05 samuel>
3 * Time-stamp: <2004/01/07 19:36:09 samuel>
7 * macintosh partition support
9 * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
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"
25 //#define CONFIG_DEBUG_MAC_PARTS
27 #ifdef CONFIG_DEBUG_MAC_PARTS
28 #define DPRINTF(fmt, args...) \
29 do { printk("MAC-PARTS: " fmt , ##args); } while (0)
31 #define DPRINTF(fmt, args...) do {} while(0)
35 xt_t seek_xt, read_xt;
36 ucell offs_hi, offs_lo;
37 ucell size_hi, size_lo;
38 ucell bootcode_addr, bootcode_entry;
39 unsigned int blocksize;
40 phandle_t filesystem_ph;
43 DECLARE_NODE( macparts, INSTALL_OPEN, sizeof(macparts_info_t), "+/packages/mac-parts" );
45 #define SEEK( pos ) ({ DPUSH(pos); call_parent(di->seek_xt); POP(); })
46 #define READ( buf, size ) ({ PUSH(pointer2cell(buf)); PUSH(size); call_parent(di->read_xt); POP(); })
48 /* ( open -- flag ) */
50 macparts_open( macparts_info_t *di )
52 char *str = my_args_copy();
53 char *parstr = NULL, *argstr = NULL;
55 int bs, parnum=-1, apple_parnum=-1;
56 int parlist[2], parlist_size = 0;
59 int ret = 0, i = 0, j = 0;
60 int want_bootcode = 0;
62 ducell offs = 0, size = -1;
64 DPRINTF("macparts_open '%s'\n", str );
67 Arguments that we accept:
72 if ( str && strlen(str) ) {
73 /* Detect the arguments */
74 if ((*str >= '0' && *str <= '9') || (*str == ',')) {
77 fword("left-parse-string");
78 parstr = pop_fstr_copy();
79 argstr = pop_fstr_copy();
84 /* Make sure argstr is not null */
88 /* Convert the id to a partition number */
89 if (parstr && strlen(parstr))
90 parnum = atol(parstr);
92 /* Detect if we are looking for the bootcode */
93 if (strcmp(argstr, "%BOOT") == 0) {
98 DPRINTF("parstr: %s argstr: %s parnum: %d\n", parstr, argstr, parnum);
100 DPRINTF("want_bootcode %d\n", want_bootcode);
101 DPRINTF("macparts_open %d\n", parnum);
103 di->filesystem_ph = 0;
104 di->read_xt = find_parent_method("read");
105 di->seek_xt = find_parent_method("seek");
108 if( READ(&dmap, sizeof(dmap)) != sizeof(dmap) )
111 /* partition maps might support multiple block sizes; in this case,
112 * pmPyPartStart is typically given in terms of 512 byte blocks.
114 bs = __be16_to_cpu(dmap.sbBlockSize);
117 READ( &par, sizeof(par) );
118 if( __be16_to_cpu(par.pmSig) == DESC_PART_SIGNATURE )
122 if( READ(&par, sizeof(par)) != sizeof(par) )
124 if (__be16_to_cpu(par.pmSig) != DESC_PART_SIGNATURE)
128 * Implement partition selection as per the PowerPC Microprocessor CHRP bindings
131 if (argstr == NULL || parnum == 0) {
132 /* According to the spec, partition 0 as well as no arguments means the whole disk */
134 size = (long long)__be32_to_cpu(dmap.sbBlkCount) * bs;
136 di->blocksize = (unsigned int)bs;
138 di->offs_hi = offs >> BITS;
139 di->offs_lo = offs & (ucell) -1;
141 di->size_hi = size >> BITS;
142 di->size_lo = size & (ucell) -1;
147 } else if (parnum == -1) {
149 DPRINTF("mac-parts: counted %d partitions\n", __be32_to_cpu(par.pmMapBlkCnt));
151 /* No partition was explicitly requested so let's find a suitable partition... */
152 for (i = 1; i <= __be32_to_cpu(par.pmMapBlkCnt); i++) {
154 READ( &par, sizeof(par) );
155 if ( __be16_to_cpu(par.pmSig) != DESC_PART_SIGNATURE ||
156 !__be32_to_cpu(par.pmPartBlkCnt) )
159 DPRINTF("found partition %d type: %s with status %x\n", i, par.pmPartType, __be32_to_cpu(par.pmPartStatus));
161 /* If we have a valid, allocated and readable partition... */
162 if( (__be32_to_cpu(par.pmPartStatus) & kPartitionAUXIsValid) &&
163 (__be32_to_cpu(par.pmPartStatus) & kPartitionAUXIsAllocated) &&
164 (__be32_to_cpu(par.pmPartStatus) & kPartitionAUXIsReadable) ) {
166 /* Unfortunately Apple's OF implementation doesn't follow the OF PowerPC CHRP bindings
167 * and instead will brute-force boot the first valid partition it finds with a
168 * type of either "Apple_Boot", "Apple_HFS" or "DOS_FAT_". Here we store the id
169 * of the first partition that matches these criteria to use as a fallback later
172 if (apple_parnum == -1 &&
173 (strcmp(par.pmPartType, "Apple_Boot") == 0 ||
174 strcmp(par.pmPartType, "Apple_Bootstrap") == 0 ||
175 strcmp(par.pmPartType, "Apple_HFS") == 0 ||
176 strcmp(par.pmPartType, "DOS_FAT_") == 0)) {
179 DPRINTF("Located Apple OF fallback partition %d\n", apple_parnum);
182 /* If the partition is also bootable and the pmProcessor field matches "PowerPC" (insensitive
183 * match), then according to the CHRP bindings this is our chosen partition */
184 for (j = 0; j < strlen(par.pmProcessor); j++) {
185 par.pmProcessor[j] = tolower(par.pmProcessor[j]);
188 if ((__be32_to_cpu(par.pmPartStatus) & kPartitionAUXIsBootValid) &&
189 strcmp(par.pmProcessor, "powerpc") == 0) {
192 DPRINTF("Located CHRP-compliant boot partition %d\n", parnum);
197 /* If we found a valid CHRP partition, add it to the list */
199 parlist[parlist_size++] = parnum;
202 /* If we found an Apple OF fallback partition, add it to the list */
203 if (apple_parnum > 0 && apple_parnum != parnum) {
204 parlist[parlist_size++] = apple_parnum;
208 /* Another partition was explicitly requested */
209 parlist[parlist_size++] = parnum;
211 DPRINTF("Partition %d explicitly requested\n", parnum);
214 /* Attempt to use our CHRP partition, optionally followed by our Apple OF fallback partition */
215 for (j = 0; j < parlist_size; j++) {
217 /* Make sure our partition is valid */
220 DPRINTF("Selected partition %d\n", parnum);
223 READ( &par, sizeof(par) );
225 if(! ((__be32_to_cpu(par.pmPartStatus) & kPartitionAUXIsValid) &&
226 (__be32_to_cpu(par.pmPartStatus) & kPartitionAUXIsAllocated) &&
227 (__be32_to_cpu(par.pmPartStatus) & kPartitionAUXIsReadable)) ) {
228 DPRINTF("Partition %d is not valid, allocated and readable\n", parnum);
234 offs = (long long)__be32_to_cpu(par.pmPyPartStart) * bs;
235 size = (long long)__be32_to_cpu(par.pmPartBlkCnt) * bs;
239 /* If size == 0 then fail because we requested bootcode but it doesn't exist */
240 size = (long long)__be32_to_cpu(par.pmBootSize);
246 /* Adjust seek position so 0 = start of bootcode */
247 offs += (long long)__be32_to_cpu(par.pmLgBootStart) * bs;
249 di->bootcode_addr = __be32_to_cpu(par.pmBootLoad);
250 di->bootcode_entry = __be32_to_cpu(par.pmBootEntry);
253 di->blocksize = (unsigned int)bs;
255 di->offs_hi = offs >> BITS;
256 di->offs_lo = offs & (ucell) -1;
258 di->size_hi = size >> BITS;
259 di->size_lo = size & (ucell) -1;
261 /* If we're trying to execute bootcode then we're all done */
266 /* We have a valid partition - so probe for a filesystem at the current offset */
267 DPRINTF("mac-parts: about to probe for fs\n");
269 PUSH_ih( my_parent() );
270 parword("find-filesystem");
271 DPRINTF("mac-parts: done fs probe\n");
275 DPRINTF("mac-parts: filesystem found on partition %d with ph " FMT_ucellx " and args %s\n", parnum, ph, argstr);
276 di->filesystem_ph = ph;
278 /* In case no partition was specified, set a special selected-partition-args property
279 giving the device parameters that we can use to generate bootpath */
280 tmpstr = malloc(strlen(argstr) + 2 + 1);
281 if (strlen(argstr)) {
282 sprintf(tmpstr, "%d,%s", parnum, argstr);
284 sprintf(tmpstr, "%d", parnum);
288 feval("strdup encode-string \" selected-partition-args\" property");
292 /* If we have been asked to open a particular file, interpose the filesystem package with
293 the passed filename as an argument */
294 if (strlen(argstr)) {
302 DPRINTF("mac-parts: no filesystem found on partition %d; bypassing misc-files interpose\n", parnum);
304 /* Here we have a valid partition; however if we tried to pass in a file argument for a
305 partition that doesn't contain a filesystem, then we must fail */
306 if (strlen(argstr)) {
318 /* ( block0 -- flag? ) */
320 macparts_probe( macparts_info_t *dummy )
322 desc_map_t *dmap = (desc_map_t*)cell2pointer(POP());
324 DPRINTF("macparts_probe %x ?= %x\n", dmap->sbSig, DESC_MAP_SIGNATURE);
325 if( __be16_to_cpu(dmap->sbSig) != DESC_MAP_SIGNATURE )
330 /* ( -- type offset.d size.d ) */
332 macparts_get_info( macparts_info_t *di )
334 DPRINTF("macparts_get_info");
336 PUSH( -1 ); /* no type */
343 /* ( -- size entry addr ) */
345 macparts_get_bootcode_info( macparts_info_t *di )
347 DPRINTF("macparts_get_bootcode_info");
350 PUSH( di->bootcode_entry );
351 PUSH( di->bootcode_addr );
355 macparts_block_size( macparts_info_t *di )
357 DPRINTF("macparts_block_size = %x\n", di->blocksize);
362 macparts_initialize( macparts_info_t *di )
364 fword("register-partition-package");
367 /* ( pos.d -- status ) */
369 macparts_seek(macparts_info_t *di )
371 long long pos = DPOP();
372 long long offs, size;
374 DPRINTF("macparts_seek %llx:\n", pos);
376 /* Seek is invalid if we reach the end of the device */
377 size = ((ducell)di->size_hi << BITS) | di->size_lo;
381 /* Calculate the seek offset for the parent */
382 offs = ((ducell)di->offs_hi << BITS) | di->offs_lo;
386 DPRINTF("macparts_seek parent offset %llx:\n", offs);
388 call_package(di->seek_xt, my_parent());
391 /* ( buf len -- actlen ) */
393 macparts_read(macparts_info_t *di )
395 DPRINTF("macparts_read\n");
397 /* Pass the read back up to the parent */
398 call_package(di->read_xt, my_parent());
401 /* ( addr -- size ) */
403 macparts_load( __attribute__((unused))macparts_info_t *di )
405 /* Invoke the loader */
409 /* ( pathstr len -- ) */
411 macparts_dir( macparts_info_t *di )
413 /* On PPC Mac, the first partition chosen according to the CHRP boot
414 specification (i.e. marked as bootable) may not necessarily contain
416 if ( di->filesystem_ph ) {
419 PUSH( di->filesystem_ph );
420 fword("find-method");
424 forth_printf("mac-parts: Unable to determine filesystem\n");
430 NODE_METHODS( macparts ) = {
431 { "probe", macparts_probe },
432 { "open", macparts_open },
433 { "seek", macparts_seek },
434 { "read", macparts_read },
435 { "load", macparts_load },
436 { "dir", macparts_dir },
437 { "get-info", macparts_get_info },
438 { "get-bootcode-info", macparts_get_bootcode_info },
439 { "block-size", macparts_block_size },
440 { NULL, macparts_initialize },
444 macparts_init( void )
446 REGISTER_NODE( macparts );