7b7f169684537be79361b6128fa437207dfb2d6e
[yaboot.git] / second / fs_of.c
1 /* OpenFirmware-based filesystem
2    
3    Copyright (C) 1999 Benjamin Herrenschmidt
4    
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19    BrokenFirmware cannot "read" from the network. We use tftp "load" method
20    for network boot for now, we may provide our own NFS implementation in
21    a later version. That means that we allocate a huge block of memory for
22    the entire file before loading it. We use the location where the kernel puts
23    RTAS, it's not used by the bootloader and if freed when the kernel is booted.
24    This will have to be changed if we plan to instanciate RTAS in the bootloader
25    itself
26    
27 */
28
29 #include "ctype.h"
30 #include "types.h"
31 #include "stddef.h"
32 #include "stdlib.h"
33 #include "file.h"
34 #include "prom.h"
35 #include "string.h"
36 #include "partition.h"
37 #include "fs.h"
38 #include "errors.h"
39 #include "debug.h"
40
41 #define LOAD_BUFFER_POS         0x600000
42 #define LOAD_BUFFER_SIZE        0x400000
43
44 static int of_open(struct boot_file_t* file, const char* dev_name,
45                    struct partition_t* part, const char* file_name);
46 static int of_read(struct boot_file_t* file, unsigned int size, void* buffer);
47 static int of_seek(struct boot_file_t* file, unsigned int newpos);
48 static int of_close(struct boot_file_t* file);
49
50
51 static int of_net_open(struct boot_file_t* file, const char* dev_name,
52                        struct partition_t* part, const char* file_name);
53 static int of_net_read(struct boot_file_t* file, unsigned int size, void* buffer);
54 static int of_net_seek(struct boot_file_t* file, unsigned int newpos);
55
56
57 struct fs_t of_filesystem =
58 {
59      "built-in",
60      of_open,
61      of_read,
62      of_seek,
63      of_close
64 };
65
66 struct fs_t of_net_filesystem =
67 {
68      "built-in network",
69      of_net_open,
70      of_net_read,
71      of_net_seek,
72      of_close
73 };
74
75 static int
76 of_open(struct boot_file_t* file, const char* dev_name,
77         struct partition_t* part, const char* file_name)
78 {
79      static char        buffer[1024];
80      char               *filename;
81      char               *p;
82         
83      DEBUG_ENTER;
84      DEBUG_OPEN;
85
86      strncpy(buffer, dev_name, 768);
87      strcat(buffer, ":");
88      if (part) {
89           char pn[3];
90           sprintf(pn, "%02d", part->part_number);
91           strcat(buffer, pn);
92      }
93      if (file_name && strlen(file_name)) {
94           if (part)
95                strcat(buffer, ",");
96           filename = strdup(file_name);
97           for (p = filename; *p; p++)
98                if (*p == '/') 
99                     *p = '\\';
100           strcat(buffer, filename);
101           free(filename);
102      }
103
104      DEBUG_F("opening: \"%s\"\n", buffer);
105
106      file->of_device = prom_open(buffer);
107
108      DEBUG_F("file->of_device = %p\n", file->of_device);
109
110      file->pos = 0;
111      file->buffer = NULL;
112      if ((file->of_device == PROM_INVALID_HANDLE) || (file->of_device == 0))
113      {
114           DEBUG_LEAVE(FILE_ERR_BAD_FSYS);
115           return FILE_ERR_BAD_FSYS;
116      }
117         
118      DEBUG_LEAVE(FILE_ERR_OK);
119      return FILE_ERR_OK;
120 }
121
122 static int
123 of_net_open(struct boot_file_t* file, const char* dev_name,
124             struct partition_t* part, const char* file_name)
125 {
126      static char        buffer[1024];
127      char               *filename;
128      char               *p;
129
130      DEBUG_ENTER;
131      DEBUG_OPEN;
132
133      strncpy(buffer, dev_name, 768);
134      if (file_name && strlen(file_name)) {
135           strcat(buffer, ",");
136           filename = strdup(file_name);
137           for (p = filename; *p; p++)
138                if (*p == '/') 
139                     *p = '\\';
140           strcat(buffer, filename);
141           free(filename);
142      }
143                         
144      DEBUG_F("Opening: \"%s\"\n", buffer);
145
146      file->of_device = prom_open(buffer);
147
148      DEBUG_F("file->of_device = %p\n", file->of_device);
149
150      file->pos = 0;
151      if ((file->of_device == PROM_INVALID_HANDLE) || (file->of_device == 0))
152      {
153           DEBUG_LEAVE(FILE_ERR_BAD_FSYS);
154           return FILE_ERR_BAD_FSYS;
155      }
156         
157      file->buffer = prom_claim((void *)LOAD_BUFFER_POS, LOAD_BUFFER_SIZE, 0);
158      if (file->buffer == (void *)-1) {
159           prom_printf("Can't claim memory for TFTP download\n");
160           prom_close(file->of_device);
161           DEBUG_LEAVE(FILE_IOERR);
162           return FILE_IOERR;
163      }
164      memset(file->buffer, 0, LOAD_BUFFER_SIZE);
165
166      DEBUG_F("TFP...\n");
167
168      file->len = prom_loadmethod(file->of_device, file->buffer);
169         
170      DEBUG_F("result: %Ld\n", file->len);
171         
172      DEBUG_LEAVE(FILE_ERR_OK);
173      return FILE_ERR_OK;
174 }
175
176 static int
177 of_read(struct boot_file_t* file, unsigned int size, void* buffer)
178 {
179      unsigned int count;
180         
181      count = prom_read(file->of_device, buffer, size);
182      file->pos += count;
183      return count;
184 }
185
186 static int
187 of_net_read(struct boot_file_t* file, unsigned int size, void* buffer)
188 {
189      unsigned int count, av;
190         
191      av = file->len - file->pos;
192      count = size > av ? av : size; 
193      memcpy(buffer, file->buffer + file->pos, count);
194      file->pos += count;
195      return count;
196 }
197
198 static int
199 of_seek(struct boot_file_t* file, unsigned int newpos)
200 {
201      if (prom_seek(file->of_device, newpos)) {
202           file->pos = newpos;
203           return FILE_ERR_OK;
204      }
205                 
206      return FILE_CANT_SEEK;
207 }
208
209 static int
210 of_net_seek(struct boot_file_t* file, unsigned int newpos)
211 {
212      file->pos = (newpos > file->len) ? file->len : newpos;
213      return FILE_ERR_OK;
214 }
215
216 static int
217 of_close(struct boot_file_t* file)
218 {
219
220      DEBUG_ENTER;
221      DEBUG_F("<@%p>\n", file->of_device);
222
223      if (file->buffer) {
224           prom_release(file->buffer, LOAD_BUFFER_SIZE);
225      }
226      prom_close(file->of_device);
227      DEBUG_F("of_close called\n");
228
229      DEBUG_LEAVE(0);    
230      return 0;
231 }
232
233 /* 
234  * Local variables:
235  * c-file-style: "K&R"
236  * c-basic-offset: 5
237  * End:
238  */