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