1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <types.h>
21#include <string.h>
22#include <console/console.h>
23#include <cbfs.h>
24#include <lib.h>
25
26#ifndef CONFIG_BIG_ENDIAN
27#define ntohl(x) ( ((x&0xff)<<24) | ((x&0xff00)<<8) | \
28 ((x&0xff0000) >> 8) | ((x&0xff000000) >> 24) )
29#else
30#define ntohl(x) (x)
31#endif
32
33int cbfs_decompress(int algo, void *src, void *dst, int len)
34{
35 switch(algo) {
36 case CBFS_COMPRESS_NONE:
37 memcpy(dst, src, len);
38 return 0;
39
40 case CBFS_COMPRESS_LZMA:
41 if (!ulzma(src, dst)) {
42 printk_err("CBFS: LZMA decompression failed!\n");
43 return -1;
44 }
45 return 0;
46
47 default:
48 printk_info( "CBFS: Unknown compression type %d\n", algo);
49 return -1;
50 }
51}
52
53int cbfs_check_magic(struct cbfs_file *file)
54{
55 return !strcmp(file->magic, CBFS_FILE_MAGIC) ? 1 : 0;
56}
57
58struct cbfs_header *cbfs_master_header(void)
59{
60 struct cbfs_header *header;
61
62 void *ptr = (void *)*((unsigned long *) CBFS_HEADPTR_ADDR);
63 printk_spew("Check CBFS header at %p\n", ptr);
64 header = (struct cbfs_header *) ptr;
65
66 printk_spew("magic is %08x\n", ntohl(header->magic));
67 if (ntohl(header->magic) != CBFS_HEADER_MAGIC) {
68 printk_err("ERROR: No valid CBFS header found!\n");
69 return NULL;
70 }
71
72 printk_spew("Found CBFS header at %p\n", ptr);
73 return header;
74}
75
76struct cbfs_file *cbfs_find(const char *name)
77{
78 struct cbfs_header *header = cbfs_master_header();
79 unsigned long offset;
80
81 if (header == NULL)
82 return NULL;
83 offset = 0 - ntohl(header->romsize) + ntohl(header->offset);
84
85 int align= ntohl(header->align);
86
87 while(1) {
88 struct cbfs_file *file = (struct cbfs_file *) offset;
89 if (!cbfs_check_magic(file)) return NULL;
90 printk_spew("Check %s\n", CBFS_NAME(file));
91 if (!strcmp(CBFS_NAME(file), name))
92 return file;
93
94 int flen = ntohl(file->len);
95 int foffset = ntohl(file->offset);
96 printk_spew("CBFS: follow chain: %p + %x + %x + align -> ", (void *)offset, foffset, flen);
97
98 unsigned long oldoffset = offset;
99 offset = ALIGN(offset + foffset + flen, align);
100 printk_spew("%p\n", (void *)offset);
101 if (offset <= oldoffset) return NULL;
102
103 if (offset < 0xFFFFFFFF - ntohl(header->romsize))
104 return NULL;
105 }
106}
107
108struct cbfs_stage *cbfs_find_file(const char *name, int type)
109{
110 struct cbfs_file *file = cbfs_find(name);
111
112 if (file == NULL) {
113 printk_info( "CBFS: Could not find file %s\n",
114 name);
115 return NULL;
116 }
117
118 if (ntohl(file->type) != type) {
119 printk_info( "CBFS: File %s is of type %x instead of"
120 "type %x\n", name, file->type, type);
121
122 return NULL;
123 }
124
125 return (void *) CBFS_SUBHEADER(file);
126}
127
128static int tohex4(unsigned int c)
129{
130 return (c<=9)?(c+'0'):(c-10+'a');
131}
132
133static void tohex16(unsigned int val, char* dest)
134{
135 dest[0]=tohex4(val>>12);
136 dest[1]=tohex4((val>>8) & 0xf);
137 dest[2]=tohex4((val>>4) & 0xf);
138 dest[3]=tohex4(val & 0xf);
139}
140
141void *cbfs_load_optionrom(u16 vendor, u16 device, void * dest)
142{
143 char name[17]="pciXXXX,XXXX.rom";
144 struct cbfs_optionrom *orom;
145 u8 *src;
146
147 tohex16(vendor, name+3);
148 tohex16(device, name+8);
149
150 orom = (struct cbfs_optionrom *)
151 cbfs_find_file(name, CBFS_TYPE_OPTIONROM);
152
153 if (orom == NULL)
154 return NULL;
155
156
157
158
159
160
161
162
163
164 src = ((unsigned char *) orom);
165
166 if (! dest)
167 return src;
168
169 if (cbfs_decompress(ntohl(orom->compression),
170 src,
171 dest,
172 ntohl(orom->len)))
173 return NULL;
174
175 return dest;
176}
177
178void * cbfs_load_stage(const char *name)
179{
180 struct cbfs_stage *stage = (struct cbfs_stage *)
181 cbfs_find_file(name, CBFS_TYPE_STAGE);
182
183
184 u32 entry;
185
186 if (stage == NULL)
187 return (void *) -1;
188
189 printk_info("Stage: loading %s @ 0x%x (%d bytes), entry @ 0x%llx\n",
190 name,
191 (u32) stage->load, stage->memlen,
192 stage->entry);
193 memset((void *) (u32) stage->load, 0, stage->memlen);
194
195 if (cbfs_decompress(stage->compression,
196 ((unsigned char *) stage) +
197 sizeof(struct cbfs_stage),
198 (void *) (u32) stage->load,
199 stage->len))
200 return (void *) -1;
201
202 printk_debug("Stage: done loading.\n");
203
204 entry = stage->entry;
205
206
207 return (void *) entry;
208}
209
210void * cbfs_get_file(const char *name)
211{
212 return cbfs_find(name);
213}
214
215int cbfs_execute_stage(const char *name)
216{
217 struct cbfs_stage *stage = (struct cbfs_stage *)
218 cbfs_find_file(name, CBFS_TYPE_STAGE);
219
220 if (stage == NULL)
221 return 1;
222
223 if (ntohl(stage->compression) != CBFS_COMPRESS_NONE) {
224 printk_info( "CBFS: Unable to run %s: Compressed file"
225 "Not supported for in-place execution\n", name);
226 return 1;
227 }
228
229
230 printk_info( "CBFS: run @ %p\n", (void *) ntohl((u32) stage->entry));
231 return run_address((void *) ntohl((u32) stage->entry));
232}
233
234
235
236
237
238
239
240
241int run_address(void *f)
242{
243 int (*v) (void);
244 v = f;
245 return v();
246}
247
248