Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / packages / disk-label.c
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
52 dlabel_close( __attribute__((unused))dlabel_info_t *di )
53 {
54 }
55
56 /* ( -- success? ) */
57 static void
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
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
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
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
179 dlabel_write( __attribute__((unused)) dlabel_info_t *di )
180 {
181         DDROP();
182         PUSH( -1 );
183 }
184
185 /* ( addr -- size ) */
186 static void
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
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
242 disklabel_init( void )
243 {
244         REGISTER_NODE( dlabel );
245 }