blob: 49e4941181dc69095a44979014b284b92d9294e2 [file] [log] [blame]
Patrick Georgi6de1ee4a2011-07-21 15:43:14 +02001/*
2 * This file is part of the libpayload project.
3 *
4 * Copyright (C) 2011 secunet Security Networks AG
Hung-Te Lind01d0362013-01-25 12:42:40 +08005 * Copyright (C) 2013 Google, Inc.
Patrick Georgi6de1ee4a2011-07-21 15:43:14 +02006 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
Hung-Te Lind01d0362013-01-25 12:42:40 +080030#define LIBPAYLOAD
Patrick Georgi6de1ee4a2011-07-21 15:43:14 +020031
Hung-Te Lind01d0362013-01-25 12:42:40 +080032#ifdef LIBPAYLOAD
33# include <libpayload-config.h>
Stefan Reinauer1b4d3942015-06-29 15:47:34 -070034# if IS_ENABLED(CONFIG_LP_LZMA)
Hung-Te Lind01d0362013-01-25 12:42:40 +080035# include <lzma.h>
36# define CBFS_CORE_WITH_LZMA
37# endif
38# define CBFS_MINI_BUILD
39#elif defined(__SMM__)
40# define CBFS_MINI_BUILD
41#else
42# define CBFS_CORE_WITH_LZMA
43# include <lib.h>
Patrick Georgi6de1ee4a2011-07-21 15:43:14 +020044#endif
45
Hung-Te Lind01d0362013-01-25 12:42:40 +080046#include <cbfs.h>
47#include <string.h>
Patrick Georgi6de1ee4a2011-07-21 15:43:14 +020048
Hung-Te Lind01d0362013-01-25 12:42:40 +080049#ifdef LIBPAYLOAD
50# include <stdio.h>
51# define DEBUG(x...)
Patrick Georgi9a91ba12013-03-14 15:11:34 +010052# define LOG(x...)
Hung-Te Lind01d0362013-01-25 12:42:40 +080053# define ERROR(x...) printf(x)
54#else
55# include <console/console.h>
56# define ERROR(x...) printk(BIOS_ERR, "CBFS: " x)
57# define LOG(x...) printk(BIOS_INFO, "CBFS: " x)
Gabe Black1ee2c6d2013-08-09 04:27:35 -070058# if CONFIG_LP_DEBUG_CBFS
Hung-Te Lind01d0362013-01-25 12:42:40 +080059# define DEBUG(x...) printk(BIOS_SPEW, "CBFS: " x)
60# else
61# define DEBUG(x...)
62# endif
63#endif
Patrick Georgi6de1ee4a2011-07-21 15:43:14 +020064
Patrick Georgi6de1ee4a2011-07-21 15:43:14 +020065#include "cbfs_core.c"
66
Hung-Te Lind01d0362013-01-25 12:42:40 +080067#ifndef __SMM__
68static inline int tohex4(unsigned int c)
Stefan Reinauer09e16dc2013-01-14 10:20:15 -080069{
Hung-Te Lind01d0362013-01-25 12:42:40 +080070 return (c <= 9) ? (c + '0') : (c - 10 + 'a');
Patrick Georgi409d17d2012-01-17 15:52:05 +010071}
72
Hung-Te Lind01d0362013-01-25 12:42:40 +080073static void tohex16(unsigned int val, char* dest)
Stefan Reinauer09e16dc2013-01-14 10:20:15 -080074{
Hung-Te Lind01d0362013-01-25 12:42:40 +080075 dest[0] = tohex4(val>>12);
76 dest[1] = tohex4((val>>8) & 0xf);
77 dest[2] = tohex4((val>>4) & 0xf);
78 dest[3] = tohex4(val & 0xf);
Patrick Georgi409d17d2012-01-17 15:52:05 +010079}
80
Hung-Te Lind01d0362013-01-25 12:42:40 +080081void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor,
Daisuke Nojirid66f1da2015-07-09 15:07:45 -070082 uint16_t device)
Patrick Georgi409d17d2012-01-17 15:52:05 +010083{
Hung-Te Lind01d0362013-01-25 12:42:40 +080084 char name[17] = "pciXXXX,XXXX.rom";
Hung-Te Lind01d0362013-01-25 12:42:40 +080085
86 tohex16(vendor, name+3);
87 tohex16(device, name+8);
88
Daisuke Nojirid66f1da2015-07-09 15:07:45 -070089 return cbfs_get_file_content(media, name, CBFS_TYPE_OPTIONROM, NULL);
Patrick Georgi409d17d2012-01-17 15:52:05 +010090}
91
Hung-Te Lind01d0362013-01-25 12:42:40 +080092void * cbfs_load_stage(struct cbfs_media *media, const char *name)
Patrick Georgi409d17d2012-01-17 15:52:05 +010093{
Hung-Te Lind01d0362013-01-25 12:42:40 +080094 struct cbfs_stage *stage = (struct cbfs_stage *)
Vladimir Serbinenko0af61b62014-01-12 13:45:52 +010095 cbfs_get_file_content(media, name, CBFS_TYPE_STAGE, NULL);
Hung-Te Lind01d0362013-01-25 12:42:40 +080096 /* this is a mess. There is no ntohll. */
97 /* for now, assume compatible byte order until we solve this. */
Furquan Shaikh79a591f2014-05-13 13:47:32 -070098 uintptr_t entry;
Gabe Blackec3a4622013-07-01 04:34:29 -070099 uint32_t final_size;
Hung-Te Lind01d0362013-01-25 12:42:40 +0800100
101 if (stage == NULL)
102 return (void *) -1;
103
Furquan Shaikh79a591f2014-05-13 13:47:32 -0700104 LOG("loading stage %s @ 0x%p (%d bytes), entry @ 0x%llx\n",
Hung-Te Lind01d0362013-01-25 12:42:40 +0800105 name,
Furquan Shaikh79a591f2014-05-13 13:47:32 -0700106 (void*)(uintptr_t) stage->load, stage->memlen,
Hung-Te Lind01d0362013-01-25 12:42:40 +0800107 stage->entry);
Hung-Te Lind01d0362013-01-25 12:42:40 +0800108
Gabe Blackec3a4622013-07-01 04:34:29 -0700109 final_size = cbfs_decompress(stage->compression,
110 ((unsigned char *) stage) +
111 sizeof(struct cbfs_stage),
Furquan Shaikh79a591f2014-05-13 13:47:32 -0700112 (void *) (uintptr_t) stage->load,
Gabe Blackec3a4622013-07-01 04:34:29 -0700113 stage->len);
114 if (!final_size)
Hung-Te Lind01d0362013-01-25 12:42:40 +0800115 return (void *) -1;
116
Gabe Blackec3a4622013-07-01 04:34:29 -0700117 memset((void *)((uintptr_t)stage->load + final_size), 0,
118 stage->memlen - final_size);
119
Hung-Te Lind01d0362013-01-25 12:42:40 +0800120 DEBUG("stage loaded.\n");
121
122 entry = stage->entry;
123 // entry = ntohll(stage->entry);
124
Daisuke Nojirid66f1da2015-07-09 15:07:45 -0700125 free(stage);
Hung-Te Lind01d0362013-01-25 12:42:40 +0800126 return (void *) entry;
Patrick Georgi409d17d2012-01-17 15:52:05 +0100127}
Hung-Te Lind01d0362013-01-25 12:42:40 +0800128
129int cbfs_execute_stage(struct cbfs_media *media, const char *name)
130{
131 struct cbfs_stage *stage = (struct cbfs_stage *)
Vladimir Serbinenko0af61b62014-01-12 13:45:52 +0100132 cbfs_get_file_content(media, name, CBFS_TYPE_STAGE, NULL);
Hung-Te Lind01d0362013-01-25 12:42:40 +0800133
134 if (stage == NULL)
135 return 1;
136
137 if (ntohl(stage->compression) != CBFS_COMPRESS_NONE) {
138 LOG("Unable to run %s: Compressed file"
139 "Not supported for in-place execution\n", name);
Daisuke Nojirid66f1da2015-07-09 15:07:45 -0700140 free(stage);
Hung-Te Lind01d0362013-01-25 12:42:40 +0800141 return 1;
142 }
143
Furquan Shaikh79a591f2014-05-13 13:47:32 -0700144 LOG("run @ %p\n", (void *) (uintptr_t)ntohll(stage->entry));
Daisuke Nojirid66f1da2015-07-09 15:07:45 -0700145 int result = run_address((void *)(uintptr_t)ntohll(stage->entry));
146 free(stage);
147 return result;
Hung-Te Lind01d0362013-01-25 12:42:40 +0800148}
149
150void *cbfs_load_payload(struct cbfs_media *media, const char *name)
151{
152 return (struct cbfs_payload *)cbfs_get_file_content(
Vladimir Serbinenko0af61b62014-01-12 13:45:52 +0100153 media, name, CBFS_TYPE_PAYLOAD, NULL);
Hung-Te Lind01d0362013-01-25 12:42:40 +0800154}
155
156struct cbfs_file *cbfs_find(const char *name) {
157 return cbfs_get_file(CBFS_DEFAULT_MEDIA, name);
158}
159
160void *cbfs_find_file(const char *name, int type) {
Vladimir Serbinenko0af61b62014-01-12 13:45:52 +0100161 return cbfs_get_file_content(CBFS_DEFAULT_MEDIA, name, type, NULL);
Hung-Te Lind01d0362013-01-25 12:42:40 +0800162}
163
164const struct cbfs_header *get_cbfs_header(void) {
165 return cbfs_get_header(CBFS_DEFAULT_MEDIA);
166}
167
168/* Simple buffer */
169
170void *cbfs_simple_buffer_map(struct cbfs_simple_buffer *buffer,
171 struct cbfs_media *media,
172 size_t offset, size_t count) {
173 void *address = buffer->buffer + buffer->allocated;;
Daisuke Nojiri03e81882015-07-28 09:21:08 -0700174 DEBUG("simple_buffer_map(offset=%zu, count=%zu): "
175 "allocated=%zu, size=%zu, last_allocate=%zu\n",
Hung-Te Lind01d0362013-01-25 12:42:40 +0800176 offset, count, buffer->allocated, buffer->size,
177 buffer->last_allocate);
178 if (buffer->allocated + count >= buffer->size)
179 return CBFS_MEDIA_INVALID_MAP_ADDRESS;
180 if (media->read(media, address, offset, count) != count) {
181 ERROR("simple_buffer: fail to read %zd bytes from 0x%zx\n",
182 count, offset);
183 return CBFS_MEDIA_INVALID_MAP_ADDRESS;
184 }
185 buffer->allocated += count;
186 buffer->last_allocate = count;
187 return address;
188}
189
190void *cbfs_simple_buffer_unmap(struct cbfs_simple_buffer *buffer,
191 const void *address) {
192 // TODO Add simple buffer management so we can free more than last
193 // allocated one.
194 DEBUG("simple_buffer_unmap(address=0x%p): "
Daisuke Nojiri03e81882015-07-28 09:21:08 -0700195 "allocated=%zu, size=%zu, last_allocate=%zu\n",
Hung-Te Lind01d0362013-01-25 12:42:40 +0800196 address, buffer->allocated, buffer->size,
197 buffer->last_allocate);
198 if ((buffer->buffer + buffer->allocated - buffer->last_allocate) ==
199 address) {
200 buffer->allocated -= buffer->last_allocate;
201 buffer->last_allocate = 0;
202 }
203 return NULL;
204}
205
206/**
207 * run_address is passed the address of a function taking no parameters and
208 * jumps to it, returning the result.
209 * @param f the address to call as a function.
210 * @return value returned by the function.
211 */
212
213int run_address(void *f)
214{
215 int (*v) (void);
216 v = f;
217 return v();
218}
219
220#endif