2 * This file is part of the coreboot project.
4 * Copyright (C) 2011 secunet Security Networks AG
5 * Copyright 2015 Google Inc.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
20 #include <boot_device.h>
22 #include <commonlib/compression.h>
26 #include <timestamp.h>
28 #include "fmap_config.h"
30 #define ERROR(x...) printk(BIOS_ERR, "CBFS: " x)
31 #define LOG(x...) printk(BIOS_INFO, "CBFS: " x)
32 #if IS_ENABLED(CONFIG_DEBUG_CBFS)
33 #define DEBUG(x...) printk(BIOS_SPEW, "CBFS: " x)
38 int cbfs_boot_locate(struct cbfsf
*fh
, const char *name
, uint32_t *type
)
40 struct region_device rdev
;
41 const struct region_device
*boot_dev
;
42 struct cbfs_props props
;
44 if (cbfs_boot_region_properties(&props
))
47 /* All boot CBFS operations are performed using the RO devie. */
48 boot_dev
= boot_device_ro();
53 if (rdev_chain(&rdev
, boot_dev
, props
.offset
, props
.size
))
56 return cbfs_locate(fh
, &rdev
, name
, type
);
59 void *cbfs_boot_map_with_leak(const char *name
, uint32_t type
, size_t *size
)
64 if (cbfs_boot_locate(&fh
, name
, &type
))
67 fsize
= region_device_sz(&fh
.data
);
72 return rdev_mmap(&fh
.data
, 0, fsize
);
75 size_t cbfs_load_and_decompress(const struct region_device
*rdev
, size_t offset
,
76 size_t in_size
, void *buffer
, size_t buffer_size
, uint32_t compression
)
80 switch (compression
) {
81 case CBFS_COMPRESS_NONE
:
82 if (rdev_readat(rdev
, buffer
, offset
, in_size
) != in_size
)
86 case CBFS_COMPRESS_LZ4
:
87 if ((ENV_BOOTBLOCK
|| ENV_VERSTAGE
) &&
88 !IS_ENABLED(CONFIG_COMPRESS_PRERAM_STAGES
))
91 /* Load the compressed image to the end of the available memory
92 * area for in-place decompression. It is the responsibility of
93 * the caller to ensure that buffer_size is large enough
94 * (see compression.h, guaranteed by cbfstool for stages). */
95 void *compr_start
= buffer
+ buffer_size
- in_size
;
96 if (rdev_readat(rdev
, compr_start
, offset
, in_size
) != in_size
)
99 timestamp_add_now(TS_START_ULZ4F
);
100 out_size
= ulz4fn(compr_start
, in_size
, buffer
, buffer_size
);
101 timestamp_add_now(TS_END_ULZ4F
);
104 case CBFS_COMPRESS_LZMA
:
105 if (ENV_BOOTBLOCK
|| ENV_VERSTAGE
)
107 if ((ENV_ROMSTAGE
|| ENV_POSTCAR
)
108 && !IS_ENABLED(CONFIG_COMPRESS_RAMSTAGE
))
110 void *map
= rdev_mmap(rdev
, offset
, in_size
);
114 /* Note: timestamp not useful for memory-mapped media (x86) */
115 timestamp_add_now(TS_START_ULZMA
);
116 out_size
= ulzman(map
, in_size
, buffer
, buffer_size
);
117 timestamp_add_now(TS_END_ULZMA
);
119 rdev_munmap(rdev
, map
);
128 static inline int tohex4(unsigned int c
)
130 return (c
<= 9) ? (c
+ '0') : (c
- 10 + 'a');
133 static void tohex16(unsigned int val
, char* dest
)
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);
141 void *cbfs_boot_map_optionrom(uint16_t vendor
, uint16_t device
)
143 char name
[17] = "pciXXXX,XXXX.rom";
145 tohex16(vendor
, name
+3);
146 tohex16(device
, name
+8);
148 return cbfs_boot_map_with_leak(name
, CBFS_TYPE_OPTIONROM
, NULL
);
151 void *cbfs_boot_load_stage_by_name(const char *name
)
154 struct prog stage
= PROG_INIT(PROG_UNKNOWN
, name
);
155 uint32_t type
= CBFS_TYPE_STAGE
;
157 if (cbfs_boot_locate(&fh
, name
, &type
))
160 /* Chain data portion in the prog. */
161 cbfs_file_data(prog_rdev(&stage
), &fh
);
163 if (cbfs_prog_stage_load(&stage
))
166 return prog_entry(&stage
);
169 int cbfs_prog_stage_load(struct prog
*pstage
)
171 struct cbfs_stage stage
;
176 const struct region_device
*fh
= prog_rdev(pstage
);
178 if (rdev_readat(fh
, &stage
, 0, sizeof(stage
)) != sizeof(stage
))
181 fsize
= region_device_sz(fh
);
182 fsize
-= sizeof(stage
);
184 foffset
+= sizeof(stage
);
186 assert(fsize
== stage
.len
);
188 /* Note: cbfs_stage fields are currently in the endianness of the
189 * running processor. */
190 load
= (void *)(uintptr_t)stage
.load
;
191 entry
= (void *)(uintptr_t)stage
.entry
;
193 /* Hacky way to not load programs over read only media. The stages
194 * that would hit this path initialize themselves. */
195 if (ENV_VERSTAGE
&& !IS_ENABLED(CONFIG_NO_XIP_EARLY_STAGES
) &&
196 IS_ENABLED(CONFIG_SPI_FLASH_MEMORY_MAPPED
)) {
197 void *mapping
= rdev_mmap(fh
, foffset
, fsize
);
198 rdev_munmap(fh
, mapping
);
203 fsize
= cbfs_load_and_decompress(fh
, foffset
, fsize
, load
,
204 stage
.memlen
, stage
.compression
);
208 /* Clear area not covered by file. */
209 memset(&load
[fsize
], 0, stage
.memlen
- fsize
);
211 prog_segment_loaded((uintptr_t)load
, stage
.memlen
, SEG_FINAL
);
214 prog_set_area(pstage
, load
, stage
.memlen
);
215 prog_set_entry(pstage
, entry
, NULL
);
220 /* This only supports the "COREBOOT" fmap region. */
221 static int cbfs_master_header_props(struct cbfs_props
*props
)
223 struct cbfs_header header
;
224 const struct region_device
*bdev
;
228 bdev
= boot_device_ro();
233 size_t fmap_top
= ___FMAP__COREBOOT_BASE
+ ___FMAP__COREBOOT_SIZE
;
235 /* Find location of header using signed 32-bit offset from
236 * end of CBFS region. */
237 offset
= fmap_top
- sizeof(int32_t);
238 if (rdev_readat(bdev
, &rel_offset
, offset
, sizeof(int32_t)) < 0)
241 offset
= fmap_top
+ rel_offset
;
242 if (rdev_readat(bdev
, &header
, offset
, sizeof(header
)) < 0)
245 header
.magic
= ntohl(header
.magic
);
246 header
.romsize
= ntohl(header
.romsize
);
247 header
.offset
= ntohl(header
.offset
);
249 if (header
.magic
!= CBFS_HEADER_MAGIC
)
252 props
->offset
= header
.offset
;
253 props
->size
= header
.romsize
;
254 props
->size
-= props
->offset
;
256 printk(BIOS_SPEW
, "CBFS @ %zx size %zx\n", props
->offset
, props
->size
);
261 /* This struct is marked as weak to allow a particular platform to
262 * override the master header logic. This implementation should work for most
264 const struct cbfs_locator
__attribute__((weak
)) cbfs_master_header_locator
= {
265 .name
= "Master Header Locator",
266 .locate
= cbfs_master_header_props
,
269 extern const struct cbfs_locator vboot_locator
;
271 static const struct cbfs_locator
*locators
[] = {
275 &cbfs_master_header_locator
,
278 int cbfs_boot_region_properties(struct cbfs_props
*props
)
284 for (i
= 0; i
< ARRAY_SIZE(locators
); i
++) {
285 const struct cbfs_locator
*ops
;
289 if (ops
->locate
== NULL
)
292 if (ops
->locate(props
))
295 LOG("'%s' located CBFS at [%zx:%zx)\n",
296 ops
->name
, props
->offset
, props
->offset
+ props
->size
);
304 void cbfs_prepare_program_locate(void)
310 for (i
= 0; i
< ARRAY_SIZE(locators
); i
++) {
311 if (locators
[i
]->prepare
== NULL
)
313 locators
[i
]->prepare();