Tidy cell types and format strings
[openbios.git] / packages / mac-parts.c
blob18e4aa37a5b87243a20ef4380f49b50e382819f4
1 /*
2 * Creation Date: <2003/12/04 17:07:05 samuel>
3 * Time-stamp: <2004/01/07 19:36:09 samuel>
5 * <mac-parts.c>
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
13 * version 2
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"
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)
30 #else
31 #define DPRINTF(fmt, args...) do {} while(0)
32 #endif
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;
42 DECLARE_NODE( macparts, INSTALL_OPEN, sizeof(macparts_info_t), "+/packages/mac-parts" );
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(); })
47 /* ( open -- flag ) */
48 static void
49 macparts_open( macparts_info_t *di )
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;
62 DPRINTF("macparts_open '%s'\n", str );
64 /*
65 Arguments that we accept:
66 id: [0-7]
67 [(id)][,][filespec]
70 if( str ) {
71 if ( !strlen(str) )
72 parnum = -1;
73 else {
74 /* Detect the boot parameters */
75 char *ptr;
76 ptr = str;
78 /* <id>,<file> */
79 if (*ptr >= '0' && *ptr <= '9' && *(ptr + 1) == ',') {
80 parstr = ptr;
81 *(ptr + 1) = '\0';
82 argstr = ptr + 2;
85 /* <id> */
86 else if (*ptr >= '0' && *ptr <='9' && *(ptr + 1) == '\0') {
87 parstr = ptr;
90 /* ,<file> */
91 else if (*ptr == ',') {
92 argstr = ptr + 1;
95 /* <file> */
96 else {
97 argstr = str;
100 /* Convert the id to a partition number */
101 if (strlen(parstr))
102 parnum = atol(parstr);
104 /* Detect if we are looking for the bootcode */
105 if (strcmp(argstr, "%BOOT") == 0)
106 want_bootcode = 1;
110 DPRINTF("parstr: %s argstr: %s parnum: %d\n", parstr, argstr, parnum);
112 DPRINTF("want_bootcode %d\n", want_bootcode);
113 DPRINTF("macparts_open %d\n", parnum);
115 di->filesystem_ph = 0;
116 di->read_xt = find_parent_method("read");
117 di->seek_xt = find_parent_method("seek");
119 SEEK( 0 );
120 if( READ(&dmap, sizeof(dmap)) != sizeof(dmap) )
121 goto out;
123 /* partition maps might support multiple block sizes; in this case,
124 * pmPyPartStart is typically given in terms of 512 byte blocks.
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;
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;
140 * Implement partition selection as per the PowerPC Microprocessor CHRP bindings
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;
148 di->blocksize = (unsigned int)bs;
150 di->offs_hi = offs >> BITS;
151 di->offs_lo = offs & (ucell) -1;
153 di->size_hi = size >> BITS;
154 di->size_lo = size & (ucell) -1;
156 ret = -1;
157 goto out;
159 } else if (parnum == -1 && strlen(argstr)) {
161 DPRINTF("mac-parts: counted %d partitions\n", __be32_to_cpu(par.pmMapBlkCnt));
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;
172 DPRINTF("found partition type: %s with status %x\n", par.pmPartType, __be32_to_cpu(par.pmPartStatus));
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;
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);
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");
194 ph = POP_ph();
195 if (ph)
196 goto found;
201 } else {
202 /* Another partition was explicitly requested */
203 SEEK( bs * parnum );
204 READ( &par, sizeof(par) );
206 if( (__be32_to_cpu(par.pmPartStatus) & kPartitionAUXIsValid) &&
207 (__be32_to_cpu(par.pmPartStatus) & kPartitionAUXIsAllocated) &&
208 (__be32_to_cpu(par.pmPartStatus) & kPartitionAUXIsReadable) ) {
210 offs = (long long)__be32_to_cpu(par.pmPyPartStart) * bs;
211 size = (long long)__be32_to_cpu(par.pmPartBlkCnt) * bs;
215 /* If we couldn't find a partition, exit */
216 if (size == -1) {
217 DPRINTF("Unable to automatically find partition!\n");
218 goto out;
221 found:
223 ret = -1;
224 di->blocksize = (unsigned int)bs;
226 di->offs_hi = offs >> BITS;
227 di->offs_lo = offs & (ucell) -1;
229 di->size_hi = size >> BITS;
230 di->size_lo = size & (ucell) -1;
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");
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;
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("");
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");
256 } else {
257 DPRINTF("mac-parts: no filesystem found; bypassing misc-files interpose\n");
260 free( str );
262 out:
263 PUSH( ret );
266 /* ( block0 -- flag? ) */
267 static void
268 macparts_probe( macparts_info_t *dummy )
270 desc_map_t *dmap = (desc_map_t*)cell2pointer(POP());
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);
278 /* ( -- type offset.d size.d ) */
279 static void
280 macparts_get_info( macparts_info_t *di )
282 DPRINTF("macparts_get_info");
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 );
291 static void
292 macparts_block_size( macparts_info_t *di )
294 DPRINTF("macparts_block_size = %x\n", di->blocksize);
295 PUSH(di->blocksize);
298 static void
299 macparts_initialize( macparts_info_t *di )
301 fword("register-partition-package");
304 /* ( pos.d -- status ) */
305 static void
306 macparts_seek(macparts_info_t *di )
308 long long pos = DPOP();
309 long long offs, size;
311 DPRINTF("macparts_seek %llx:\n", pos);
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 );
318 /* Calculate the seek offset for the parent */
319 offs = ((ducell)di->offs_hi << BITS) | di->offs_lo;
320 offs += pos;
321 DPUSH(offs);
323 DPRINTF("macparts_seek parent offset %llx:\n", offs);
325 call_package(di->seek_xt, my_parent());
328 /* ( buf len -- actlen ) */
329 static void
330 macparts_read(macparts_info_t *di )
332 DPRINTF("macparts_read\n");
334 /* Pass the read back up to the parent */
335 call_package(di->read_xt, my_parent());
338 /* ( addr -- size ) */
339 static void
340 macparts_load( __attribute__((unused))macparts_info_t *di )
342 /* Invoke the loader */
343 load(my_self());
346 /* ( pathstr len -- ) */
347 static void
348 macparts_dir( macparts_info_t *di )
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();
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 },
379 void
380 macparts_init( void )
382 REGISTER_NODE( macparts );