4 * Copyright (C) 2004 Stefan Reinauer
6 * This code is based (and copied in many places) from
7 * mac partition support by Samuel Rydh (samuel@ibrium.se)
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
16 #include "libopenbios/bindings.h"
17 #include "libopenbios/load.h"
18 #include "libc/byteorder.h"
19 #include "libc/vsprintf.h"
22 //#define DEBUG_PC_PARTS
25 #define DPRINTF(fmt, args...) \
26 do { printk(fmt , ##args); } while (0)
28 #define DPRINTF(fmt, args...)
32 xt_t seek_xt
, read_xt
;
33 ucell offs_hi
, offs_lo
;
34 ucell size_hi
, size_lo
;
35 phandle_t filesystem_ph
;
38 DECLARE_NODE( pcparts
, INSTALL_OPEN
, sizeof(pcparts_info_t
), "+/packages/pc-parts" );
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(); })
43 /* three helper functions */
45 static inline int has_pc_valid_partition(unsigned char *sect
)
47 /* Make sure the partition table contains at least one valid entry */
48 return (sect
[0x1c2] != 0 || sect
[0x1d2] != 0 || sect
[0x1e2] != 0);
51 static inline int has_pc_part_magic(unsigned char *sect
)
53 return sect
[0x1fe]==0x55 && sect
[0x1ff]==0xAA;
56 static inline int is_pc_extended_part(unsigned char type
)
58 return type
==5 || type
==0xf || type
==0x85;
61 /* ( open -- flag ) */
63 pcparts_open( pcparts_info_t
*di
)
65 char *str
= my_args_copy();
66 char *argstr
= strdup("");
67 char *parstr
= strdup("");
73 /* Layout of PC partition table */
81 unsigned char e_sector
;
83 u32 start_sect
; /* unaligned little endian */
84 u32 nr_sects
; /* ditto */
87 unsigned char buf
[512];
89 DPRINTF("pcparts_open '%s'\n", str
);
92 Arguments that we accept:
101 /* Detect the boot parameters */
106 if (*ptr
>= '0' && *ptr
<= '9' && *(ptr
+ 1) == ',') {
113 else if (*ptr
>= '0' && *ptr
<='9' && *(ptr
+ 1) == '\0') {
118 else if (*ptr
== ',') {
127 /* Convert the id to a partition number */
129 parnum
= atol(parstr
);
133 DPRINTF("parstr: %s argstr: %s parnum: %d\n", parstr
, argstr
, parnum
);
139 di
->filesystem_ph
= 0;
140 di
->read_xt
= find_parent_method("read");
141 di
->seek_xt
= find_parent_method("seek");
144 if( READ(buf
, 512) != 512 )
148 if (!has_pc_part_magic(buf
)) {
149 DPRINTF("pc partition magic not found.\n");
153 /* Actual partition data */
154 partition
= (struct pc_partition
*) (buf
+ 0x1be);
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
));
163 /* primary partition */
165 memcpy(p
, partition
, sizeof(struct pc_partition
));
167 if (p
->type
== 0 || is_pc_extended_part(p
->type
)) {
168 DPRINTF("partition %d does not exist\n", parnum
+1 );
172 offs
= (long long)(__le32_to_cpu(p
->start_sect
)) * bs
;
173 di
->offs_hi
= offs
>> BITS
;
174 di
->offs_lo
= offs
& (ucell
) -1;
176 size
= (long long)(__le32_to_cpu(p
->nr_sects
)) * bs
;
177 di
->size_hi
= size
>> BITS
;
178 di
->size_lo
= size
& (ucell
) -1;
180 DPRINTF("Primary partition at sector %x\n", __le32_to_cpu(p
->start_sect
));
184 /* Extended partition */
186 unsigned long ext_start
, cur_table
;
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
))
196 DPRINTF("Extended partition not found\n");
200 DPRINTF("Extended partition at %d\n", i
+1);
202 /* Visit each logical partition labels */
203 ext_start
= __le32_to_cpu(p
[i
].start_sect
);
204 cur_table
= ext_start
;
207 while (cur_part
<= parnum
) {
208 DPRINTF("cur_part=%d at %lx\n", cur_part
, cur_table
);
210 SEEK( cur_table
* bs
);
211 if( READ(buf
, sizeof(512)) != sizeof(512) )
214 if (!has_pc_part_magic(buf
)) {
215 DPRINTF("Extended partition has no magic\n");
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
));
223 /* First entry is the logical partition */
224 if (cur_part
== parnum
) {
226 DPRINTF("Partition %d is empty\n", parnum
+1);
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;
234 size
= (long long)__le32_to_cpu(p
->nr_sects
) * bs
;
235 di
->size_hi
= size
>> BITS
;
236 di
->size_lo
= size
& (ucell
) -1;
242 /* Second entry is link to next partition */
243 if (!is_pc_extended_part(p
[1].type
)) {
244 DPRINTF("no link\n");
248 cur_table
= ext_start
+ __le32_to_cpu(p
[1].start_sect
);
253 DPRINTF("Logical partition %d does not exist\n", parnum
+1);
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");
264 PUSH_ih( my_parent() );
265 parword("find-filesystem");
266 DPRINTF("pc-parts: done fs probe\n");
270 DPRINTF("pc-parts: filesystem found with ph " FMT_ucellx
" and args %s\n", ph
, argstr
);
271 di
->filesystem_ph
= ph
;
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
)) {
281 DPRINTF("pc-parts: no filesystem found; bypassing misc-files interpose\n");
287 DPRINTF("pc-parts: unable to locate partition\n");
294 /* ( block0 -- flag? ) */
296 pcparts_probe( pcparts_info_t
*dummy
)
298 unsigned char *buf
= (unsigned char *)cell2pointer(POP());
300 DPRINTF("probing for PC partitions\n");
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
305 RET ( has_pc_part_magic(buf
) && has_pc_valid_partition(buf
) );
308 /* ( -- type offset.d size.d ) */
310 pcparts_get_info( pcparts_info_t
*di
)
312 DPRINTF("PC get_info\n");
313 PUSH( -1 ); /* no type */
321 pcparts_block_size( __attribute__((unused
))pcparts_info_t
*di
)
327 pcparts_initialize( pcparts_info_t
*di
)
329 fword("register-partition-package");
332 /* ( pos.d -- status ) */
334 pcparts_seek(pcparts_info_t
*di
)
336 long long pos
= DPOP();
337 long long offs
, size
;
339 DPRINTF("pcparts_seek %llx:\n", pos
);
341 /* Seek is invalid if we reach the end of the device */
342 size
= ((ducell
)di
->size_hi
<< BITS
) | di
->size_lo
;
346 /* Calculate the seek offset for the parent */
347 offs
= ((ducell
)di
->offs_hi
<< BITS
) | di
->offs_lo
;
351 DPRINTF("pcparts_seek parent offset %llx:\n", offs
);
353 call_package(di
->seek_xt
, my_parent());
356 /* ( buf len -- actlen ) */
358 pcparts_read(pcparts_info_t
*di
)
360 DPRINTF("pcparts_read\n");
362 /* Pass the read back up to the parent */
363 call_package(di
->read_xt
, my_parent());
366 /* ( addr -- size ) */
368 pcparts_load( __attribute__((unused
))pcparts_info_t
*di
)
370 /* Invoke the loader */
374 /* ( pathstr len -- ) */
376 pcparts_dir( pcparts_info_t
*di
)
378 if ( di
->filesystem_ph
) {
381 PUSH( di
->filesystem_ph
);
382 fword("find-method");
386 forth_printf("pc-parts: Unable to determine filesystem\n");
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
},
407 REGISTER_NODE( pcparts
);