1 /*
2 * Creation Date: <2003/12/03 22:10:45 samuel>
3 * Time-stamp: <2004/01/07 19:17:45 samuel>
4 *
5 * <disk-label.c>
6 *
7 * Partition support
8 *
9 * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
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 "libc/diskio.h"
21 #include "libc/vsprintf.h"
22 #include "packages.h"
23
24 //#define DEBUG_DISK_LABEL
25
26 #ifdef DEBUG_DISK_LABEL
27 #define DPRINTF(fmt, args...) \
28 do { printk("DISK-LABEL - %s: " fmt, __func__ , ##args); } while (0)
29 #else
30 #define DPRINTF(fmt, args...) do { } while (0)
31 #endif
32
33 typedef struct {
34 xt_t parent_seek_xt;
35 xt_t parent_tell_xt;
36 xt_t parent_read_xt;
37
38 ucell offs_hi, offs_lo;
39 ucell size_hi, size_lo;
40 int block_size;
41 int type; /* partition type or -1 */
42
43 ihandle_t part_ih;
44 phandle_t filesystem_ph;
45 } dlabel_info_t;
46
47 DECLARE_NODE( dlabel, 0, sizeof(dlabel_info_t), "/packages/disk-label" );
48
49
50 /* ( -- ) */
51 static void
dlabel_close(dlabel_info_t * di)52 dlabel_close( __attribute__((unused))dlabel_info_t *di )
53 {
54 }
55
56 /* ( -- success? ) */
57 static void
dlabel_open(dlabel_info_t * di)58 dlabel_open( dlabel_info_t *di )
59 {
60 char *path;
61 char block0[512];
62 phandle_t ph;
63 int success=0;
64 cell status;
65
66 path = my_args_copy();
67
68 DPRINTF("dlabel-open '%s'\n", path );
69
70 di->part_ih = 0;
71
72 /* Find parent methods */
73 di->filesystem_ph = 0;
74 di->parent_seek_xt = find_parent_method("seek");
75 di->parent_tell_xt = find_parent_method("tell");
76 di->parent_read_xt = find_parent_method("read");
77
78 /* If arguments have been passed, determine the partition/filesystem type */
79 if (path && strlen(path)) {
80
81 /* Read first block from parent device */
82 DPUSH(0);
83 call_package(di->parent_seek_xt, my_parent());
84 POP();
85
86 PUSH(pointer2cell(block0));
87 PUSH(sizeof(block0));
88 call_package(di->parent_read_xt, my_parent());
89 status = POP();
90 if (status != sizeof(block0))
91 goto out;
92
93 /* Find partition handler */
94 PUSH( pointer2cell(block0) );
95 selfword("find-part-handler");
96 ph = POP_ph();
97 if( ph ) {
98 /* We found a suitable partition handler, so interpose it */
99 DPRINTF("Partition found on disk - scheduling interpose with ph " FMT_ucellx "\n", ph);
100
101 push_str(path);
102 PUSH_ph(ph);
103 fword("interpose");
104
105 success = 1;
106 } else {
107 /* unknown (or missing) partition map,
108 * try the whole disk
109 */
110
111 DPRINTF("Unknown or missing partition map; trying whole disk\n");
112
113 /* Probe for filesystem from start of device */
114 DPUSH ( 0 );
115 PUSH_ih( my_self() );
116 selfword("find-filesystem");
117 ph = POP_ph();
118 if( ph ) {
119 /* If we have been asked to open a particular file, interpose the filesystem package with the passed filename as an argument */
120 di->filesystem_ph = ph;
121
122 DPRINTF("Located filesystem with ph " FMT_ucellx "\n", ph);
123 DPRINTF("path: %s length: %d\n", path, strlen(path));
124
125 if (path && strlen(path)) {
126 DPRINTF("INTERPOSE!\n");
127
128 push_str( path );
129 PUSH_ph( ph );
130 fword("interpose");
131 }
132 } else if (path && strcmp(path, "%BOOT") != 0) {
133 goto out;
134 }
135
136 success = 1;
137 }
138 } else {
139 /* No arguments were passed, so we just use the parent raw device directly */
140 success = 1;
141 }
142
143 out:
144 if( path )
145 free( path );
146 if( !success ) {
147 dlabel_close( di );
148 RET(0);
149 }
150 PUSH(-1);
151 }
152
153 /* ( addr len -- actual ) */
154 static void
dlabel_read(dlabel_info_t * di)155 dlabel_read( dlabel_info_t *di )
156 {
157 /* Call back up to parent */
158 call_package(di->parent_read_xt, my_parent());
159 }
160
161 /* ( pos.d -- status ) */
162 static void
dlabel_seek(dlabel_info_t * di)163 dlabel_seek( dlabel_info_t *di )
164 {
165 /* Call back up to parent */
166 call_package(di->parent_seek_xt, my_parent());
167 }
168
169 /* ( -- filepos.d ) */
170 static void
dlabel_tell(dlabel_info_t * di)171 dlabel_tell( dlabel_info_t *di )
172 {
173 /* Call back up to parent */
174 call_package(di->parent_tell_xt, my_parent());
175 }
176
177 /* ( addr len -- actual ) */
178 static void
dlabel_write(dlabel_info_t * di)179 dlabel_write( __attribute__((unused)) dlabel_info_t *di )
180 {
181 DDROP();
182 PUSH( -1 );
183 }
184
185 /* ( addr -- size ) */
186 static void
dlabel_load(dlabel_info_t * di)187 dlabel_load( __attribute__((unused)) dlabel_info_t *di )
188 {
189 /* Try the load method of the part package */
190 xt_t xt;
191
192 /* If we have a partition handle, invoke the load word on it */
193 if (di->part_ih) {
194 xt = find_ih_method("load", di->part_ih);
195 if (!xt) {
196 forth_printf("load currently not implemented for ihandle " FMT_ucellx "\n", di->part_ih);
197 PUSH(0);
198 return;
199 }
200
201 DPRINTF("calling load on ihandle " FMT_ucellx "\n", di->part_ih);
202
203 call_package(xt, di->part_ih);
204 } else {
205 /* Otherwise attempt load directly on the raw disk */
206 DPRINTF("calling load on raw disk ihandle " FMT_ucellx "\n", my_self());
207
208 load(my_self());
209 }
210 }
211
212 /* ( pathstr len -- ) */
213 static void
dlabel_dir(dlabel_info_t * di)214 dlabel_dir( dlabel_info_t *di )
215 {
216 if ( di->filesystem_ph ) {
217 PUSH( my_self() );
218 push_str("dir");
219 PUSH( di->filesystem_ph );
220 fword("find-method");
221 POP();
222 fword("execute");
223 } else {
224 forth_printf("disk-label: Unable to determine filesystem\n");
225 POP();
226 POP();
227 }
228 }
229
230 NODE_METHODS( dlabel ) = {
231 { "open", dlabel_open },
232 { "close", dlabel_close },
233 { "load", dlabel_load },
234 { "read", dlabel_read },
235 { "write", dlabel_write },
236 { "seek", dlabel_seek },
237 { "tell", dlabel_tell },
238 { "dir", dlabel_dir },
239 };
240
241 void
disklabel_init(void)242 disklabel_init( void )
243 {
244 REGISTER_NODE( dlabel );
245 }
246