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