Commit yaboot 1.3.4-pre1
[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
40 #define LOAD_BUFFER_POS         0x600000
41 #define LOAD_BUFFER_SIZE        0x400000
42
43 static int of_open(struct boot_file_t* file, const char* dev_name,
44                    struct partition_t* part, const char* file_name);
45 static int of_read(struct boot_file_t* file, unsigned int size, void* buffer);
46 static int of_seek(struct boot_file_t* file, unsigned int newpos);
47 static int of_close(struct boot_file_t* file);
48
49
50 static int of_net_open(struct boot_file_t* file, const char* dev_name,
51                        struct partition_t* part, const char* file_name);
52 static int of_net_read(struct boot_file_t* file, unsigned int size, void* buffer);
53 static int of_net_seek(struct boot_file_t* file, unsigned int newpos);
54
55
56 struct fs_t of_filesystem =
57 {
58      "built-in",
59      of_open,
60      of_read,
61      of_seek,
62      of_close
63 };
64
65 struct fs_t of_net_filesystem =
66 {
67      "built-in network",
68      of_net_open,
69      of_net_read,
70      of_net_seek,
71      of_close
72 };
73
74 static int
75 of_open(struct boot_file_t* file, const char* dev_name,
76         struct partition_t* part, const char* file_name)
77 {
78      static char        buffer[1024];
79      char               *filename;
80      char               *p;
81         
82      DEBUG_ENTER;
83      DEBUG_OPEN;
84
85      strncpy(buffer, dev_name, 768);
86      strcat(buffer, ":");
87      if (part) {
88           char pn[3];
89           sprintf(pn, "%02d", part->part_number);
90           strcat(buffer, pn);
91      }
92      if (file_name && strlen(file_name)) {
93           if (part)
94                strcat(buffer, ",");
95           filename = strdup(file_name);
96           for (p = filename; *p; p++)
97                if (*p == '/') 
98                     *p = '\\';
99           strcat(buffer, filename);
100           free(filename);
101      }
102
103      DEBUG_F("opening: \"%s\"\n", buffer);
104
105      file->of_device = prom_open(buffer);
106
107      DEBUG_F("file->of_device = %p\n", file->of_device);
108
109      file->pos = 0;
110      file->buffer = NULL;
111      if ((file->of_device == PROM_INVALID_HANDLE) || (file->of_device == 0))
112      {
113           DEBUG_LEAVE(FILE_ERR_BAD_FSYS);
114           return FILE_ERR_BAD_FSYS;
115      }
116         
117      DEBUG_LEAVE(FILE_ERR_OK);
118      return FILE_ERR_OK;
119 }
120
121 static int
122 of_net_open(struct boot_file_t* file, const char* dev_name,
123             struct partition_t* part, const char* file_name)
124 {
125      static char        buffer[1024];
126      char               *filename;
127      char               *p;
128
129      DEBUG_ENTER;
130      DEBUG_OPEN;
131
132      strncpy(buffer, dev_name, 768);
133      if (file_name && strlen(file_name)) {
134           strcat(buffer, ",");
135           filename = strdup(file_name);
136           for (p = filename; *p; p++)
137                if (*p == '/') 
138                     *p = '\\';
139           strcat(buffer, filename);
140           free(filename);
141      }
142                         
143      DEBUG_F("Opening: \"%s\"\n", buffer);
144
145      file->of_device = prom_open(buffer);
146
147      DEBUG_F("file->of_device = %p\n", file->of_device);
148
149      file->pos = 0;
150      if ((file->of_device == PROM_INVALID_HANDLE) || (file->of_device == 0))
151      {
152           DEBUG_LEAVE(FILE_ERR_BAD_FSYS);
153           return FILE_ERR_BAD_FSYS;
154      }
155         
156      file->buffer = prom_claim((void *)LOAD_BUFFER_POS, LOAD_BUFFER_SIZE, 0);
157      if (file->buffer == (void *)-1) {
158           prom_printf("Can't claim memory for TFTP download\n");
159           prom_close(file->of_device);
160           DEBUG_LEAVE(FILE_IOERR);
161           return FILE_IOERR;
162      }
163      memset(file->buffer, 0, LOAD_BUFFER_SIZE);
164
165      DEBUG_F("TFP...\n");
166
167      file->len = prom_loadmethod(file->of_device, file->buffer);
168         
169      DEBUG_F("result: %Ld\n", file->len);
170         
171      DEBUG_LEAVE(FILE_ERR_OK);
172      return FILE_ERR_OK;
173 }
174
175 static int
176 of_read(struct boot_file_t* file, unsigned int size, void* buffer)
177 {
178      unsigned int count;
179         
180      count = prom_read(file->of_device, buffer, size);
181      file->pos += count;
182      return count;
183 }
184
185 static int
186 of_net_read(struct boot_file_t* file, unsigned int size, void* buffer)
187 {
188      unsigned int count, av;
189         
190      av = file->len - file->pos;
191      count = size > av ? av : size; 
192      memcpy(buffer, file->buffer + file->pos, count);
193      file->pos += count;
194      return count;
195 }
196
197 static int
198 of_seek(struct boot_file_t* file, unsigned int newpos)
199 {
200      if (prom_seek(file->of_device, newpos)) {
201           file->pos = newpos;
202           return FILE_ERR_OK;
203      }
204                 
205      return FILE_CANT_SEEK;
206 }
207
208 static int
209 of_net_seek(struct boot_file_t* file, unsigned int newpos)
210 {
211      file->pos = (newpos > file->len) ? file->len : newpos;
212      return FILE_ERR_OK;
213 }
214
215 static int
216 of_close(struct boot_file_t* file)
217 {
218
219      DEBUG_ENTER;
220      DEBUG_F("<@%p>\n", file->of_device);
221
222      if (file->buffer) {
223           prom_release(file->buffer, LOAD_BUFFER_SIZE);
224      }
225      prom_close(file->of_device);
226      DEBUG_F("of_close called\n");
227
228      DEBUG_LEAVE(0);    
229      return 0;
230 }
231
232 /* 
233  * Local variables:
234  * c-file-style: "K&R"
235  * c-basic-offset: 5
236  * End:
237  */