ppc64: Re-enable SF bit after returning from ELF binary
[openbios.git] / packages / pc-parts.c
blobcb737902bbfde37b024048f1bd70ec4a3a40af83
1 /*
2 * pc partition support
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
11 * version 2
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"
22 //#define DEBUG_PC_PARTS
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
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;
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 ) */
62 static void
63 pcparts_open( pcparts_info_t *di )
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;
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;
87 unsigned char buf[512];
89 DPRINTF("pcparts_open '%s'\n", str );
91 /*
92 Arguments that we accept:
93 id: [0-7]
94 [(id)][,][filespec]
97 if( str ) {
98 if ( !strlen(str) )
99 parnum = -1;
100 else {
101 /* Detect the boot parameters */
102 char *ptr;
103 ptr = str;
105 /* <id>,<file> */
106 if (*ptr >= '0' && *ptr <= '9' && *(ptr + 1) == ',') {
107 parstr = ptr;
108 *(ptr + 1) = '\0';
109 argstr = ptr + 2;
112 /* <id> */
113 else if (*ptr >= '0' && *ptr <='9' && *(ptr + 1) == '\0') {
114 parstr = ptr;
117 /* ,<file> */
118 else if (*ptr == ',') {
119 argstr = ptr + 1;
122 /* <file> */
123 else {
124 argstr = str;
127 /* Convert the id to a partition number */
128 if (strlen(parstr))
129 parnum = atol(parstr);
133 DPRINTF("parstr: %s argstr: %s parnum: %d\n", parstr, argstr, parnum);
134 free(parstr);
136 if( parnum < 0 )
137 parnum = 0;
139 di->filesystem_ph = 0;
140 di->read_xt = find_parent_method("read");
141 di->seek_xt = find_parent_method("seek");
143 SEEK( 0 );
144 if( READ(buf, 512) != 512 )
145 RET(0);
147 /* Check Magic */
148 if (!has_pc_part_magic(buf)) {
149 DPRINTF("pc partition magic not found.\n");
150 RET(0);
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));
160 bs = 512;
162 if (parnum < 4) {
163 /* primary partition */
164 partition += parnum;
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 );
169 RET( 0 );
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));
182 found = 1;
183 } else {
184 /* Extended partition */
185 int i, cur_part;
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))
192 break;
195 if (i >= 4) {
196 DPRINTF("Extended partition not found\n");
197 RET( 0 );
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;
205 cur_part = 4;
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) )
212 RET( 0 );
214 if (!has_pc_part_magic(buf)) {
215 DPRINTF("Extended partition has no magic\n");
216 break;
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) {
225 if (p->type == 0) {
226 DPRINTF("Partition %d is empty\n", parnum+1);
227 RET( 0 );
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;
238 found = 1;
239 break;
242 /* Second entry is link to next partition */
243 if (!is_pc_extended_part(p[1].type)) {
244 DPRINTF("no link\n");
245 break;
248 cur_table = ext_start + __le32_to_cpu(p[1].start_sect);
249 cur_part++;
252 if (!found) {
253 DPRINTF("Logical partition %d does not exist\n", parnum+1);
254 RET( 0 );
258 free(p);
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");
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;
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");
280 } else {
281 DPRINTF("pc-parts: no filesystem found; bypassing misc-files interpose\n");
284 free( str );
285 RET( -1 );
286 } else {
287 DPRINTF("pc-parts: unable to locate partition\n");
289 free( str );
290 RET( 0 );
294 /* ( block0 -- flag? ) */
295 static void
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
304 e.g. MorphOS. */
305 RET ( has_pc_part_magic(buf) && has_pc_valid_partition(buf) );
308 /* ( -- type offset.d size.d ) */
309 static void
310 pcparts_get_info( pcparts_info_t *di )
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 );
320 static void
321 pcparts_block_size( __attribute__((unused))pcparts_info_t *di )
323 PUSH(512);
326 static void
327 pcparts_initialize( pcparts_info_t *di )
329 fword("register-partition-package");
332 /* ( pos.d -- status ) */
333 static void
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;
343 if (pos > size)
344 RET( -1 );
346 /* Calculate the seek offset for the parent */
347 offs = ((ducell)di->offs_hi << BITS) | di->offs_lo;
348 offs += pos;
349 DPUSH(offs);
351 DPRINTF("pcparts_seek parent offset %llx:\n", offs);
353 call_package(di->seek_xt, my_parent());
356 /* ( buf len -- actlen ) */
357 static void
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 ) */
367 static void
368 pcparts_load( __attribute__((unused))pcparts_info_t *di )
370 /* Invoke the loader */
371 load(my_self());
374 /* ( pathstr len -- ) */
375 static void
376 pcparts_dir( pcparts_info_t *di )
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();
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 },
404 void
405 pcparts_init( void )
407 REGISTER_NODE( pcparts );