blob: 9e9f4a7bf8d120b8a051906a700f587565f042b4 [file] [log] [blame]
Peter Stuge483b7bb2009-04-14 07:40:01 +00001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008, Jordan Crouse <jordan@cosmicpenguin.net>
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +08005 * Copyright (C) 2013 The Chromium OS Authors. All rights reserved.
Peter Stuge483b7bb2009-04-14 07:40:01 +00006 *
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.
10 *
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.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
19 */
20
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +080021
Edward O'Callaghancdabc882014-11-11 12:22:04 +110022#include "cbfs_core.h"
Peter Stuge483b7bb2009-04-14 07:40:01 +000023
Sven Schnelle4297a9a2011-06-12 14:35:11 +020024#ifndef __SMM__
Stefan Reinauer800379f2010-03-01 08:34:19 +000025static inline int tohex4(unsigned int c)
Patrick Georgib203c2f2009-08-20 14:48:03 +000026{
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +080027 return (c <= 9) ? (c + '0') : (c - 10 + 'a');
Patrick Georgib203c2f2009-08-20 14:48:03 +000028}
29
30static void tohex16(unsigned int val, char* dest)
31{
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +080032 dest[0] = tohex4(val>>12);
33 dest[1] = tohex4((val>>8) & 0xf);
34 dest[2] = tohex4((val>>4) & 0xf);
35 dest[3] = tohex4(val & 0xf);
Patrick Georgib203c2f2009-08-20 14:48:03 +000036}
37
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +080038void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor,
39 uint16_t device, void *dest)
Peter Stuge483b7bb2009-04-14 07:40:01 +000040{
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +080041 char name[17] = "pciXXXX,XXXX.rom";
Peter Stuge483b7bb2009-04-14 07:40:01 +000042 struct cbfs_optionrom *orom;
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +080043 uint8_t *src;
Peter Stuge483b7bb2009-04-14 07:40:01 +000044
Patrick Georgib203c2f2009-08-20 14:48:03 +000045 tohex16(vendor, name+3);
46 tohex16(device, name+8);
Peter Stuge483b7bb2009-04-14 07:40:01 +000047
48 orom = (struct cbfs_optionrom *)
Vladimir Serbinenko0af61b62014-01-12 13:45:52 +010049 cbfs_get_file_content(media, name, CBFS_TYPE_OPTIONROM, NULL);
Peter Stuge483b7bb2009-04-14 07:40:01 +000050
51 if (orom == NULL)
52 return NULL;
53
Stefan Reinauer14e22772010-04-27 06:56:47 +000054 /* They might have specified a dest address. If so, we can decompress.
Peter Stuge483b7bb2009-04-14 07:40:01 +000055 * If not, there's not much hope of decompressing or relocating the rom.
56 * in the common case, the expansion rom is uncompressed, we
Stefan Reinauer14e22772010-04-27 06:56:47 +000057 * pass 0 in for the dest, and all we have to do is find the rom and
58 * return a pointer to it.
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +080059 */
Peter Stuge483b7bb2009-04-14 07:40:01 +000060
61 /* BUG: the cbfstool is (not yet) including a cbfs_optionrom header */
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +080062 src = (uint8_t *)orom; // + sizeof(struct cbfs_optionrom);
Peter Stuge483b7bb2009-04-14 07:40:01 +000063
64 if (! dest)
65 return src;
66
Gabe Black0c605a52013-07-01 04:57:37 -070067 if (!cbfs_decompress(ntohl(orom->compression),
Peter Stuge483b7bb2009-04-14 07:40:01 +000068 src,
69 dest,
70 ntohl(orom->len)))
71 return NULL;
72
73 return dest;
74}
75
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +080076void * cbfs_load_stage(struct cbfs_media *media, const char *name)
Peter Stuge483b7bb2009-04-14 07:40:01 +000077{
78 struct cbfs_stage *stage = (struct cbfs_stage *)
Edward O'Callaghancdabc882014-11-11 12:22:04 +110079 cbfs_get_file_content(media, name, CBFS_TYPE_STAGE, NULL);
Peter Stuge483b7bb2009-04-14 07:40:01 +000080 /* this is a mess. There is no ntohll. */
81 /* for now, assume compatible byte order until we solve this. */
Ronald G. Minnichff178be2014-10-16 10:57:01 +000082 uintptr_t entry;
Gabe Black0c605a52013-07-01 04:57:37 -070083 uint32_t final_size;
Peter Stuge483b7bb2009-04-14 07:40:01 +000084
85 if (stage == NULL)
86 return (void *) -1;
87
Marcelo Povoad3436242014-02-06 15:17:40 -080088 LOG("loading stage %s @ 0x%llx (%d bytes), entry @ 0x%llx\n",
Patrick Georgif1075382009-07-18 14:20:39 +000089 name,
Marcelo Povoad3436242014-02-06 15:17:40 -080090 stage->load, stage->memlen,
Peter Stuge483b7bb2009-04-14 07:40:01 +000091 stage->entry);
Peter Stuge483b7bb2009-04-14 07:40:01 +000092
Gabe Black0c605a52013-07-01 04:57:37 -070093 final_size = cbfs_decompress(stage->compression,
94 ((unsigned char *) stage) +
95 sizeof(struct cbfs_stage),
Ronald G. Minnichff178be2014-10-16 10:57:01 +000096 (void *) (uintptr_t) stage->load,
Gabe Black0c605a52013-07-01 04:57:37 -070097 stage->len);
98 if (!final_size)
Peter Stuge483b7bb2009-04-14 07:40:01 +000099 return (void *) -1;
Stefan Reinauerb4f3da52009-10-26 17:15:53 +0000100
Gabe Blackec3a4622013-07-01 04:34:29 -0700101 /* Stages rely the below clearing so that the bss is initialized. */
102 memset((void *)((uintptr_t)stage->load + final_size), 0,
103 stage->memlen - final_size);
104
Stefan Reinauerfe422182012-05-02 16:33:18 -0700105 DEBUG("stage loaded.\n");
Peter Stuge483b7bb2009-04-14 07:40:01 +0000106
107 entry = stage->entry;
Stefan Reinauer02e75b22011-10-17 09:51:15 -0700108 // entry = ntohll(stage->entry);
Stefan Reinauerb4f3da52009-10-26 17:15:53 +0000109
Peter Stuge483b7bb2009-04-14 07:40:01 +0000110 return (void *) entry;
111}
112
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +0800113/* Simple buffer */
114
115void *cbfs_simple_buffer_map(struct cbfs_simple_buffer *buffer,
116 struct cbfs_media *media,
117 size_t offset, size_t count) {
Idwer Volleringd26da9c2013-12-22 21:38:18 +0000118 void *address = buffer->buffer + buffer->allocated;
Hung-Te Lin966e2db2013-02-06 12:25:27 +0800119 DEBUG("simple_buffer_map(offset=%zd, count=%zd): "
120 "allocated=%zd, size=%zd, last_allocate=%zd\n",
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +0800121 offset, count, buffer->allocated, buffer->size,
122 buffer->last_allocate);
123 if (buffer->allocated + count >= buffer->size)
124 return CBFS_MEDIA_INVALID_MAP_ADDRESS;
125 if (media->read(media, address, offset, count) != count) {
126 ERROR("simple_buffer: fail to read %zd bytes from 0x%zx\n",
127 count, offset);
128 return CBFS_MEDIA_INVALID_MAP_ADDRESS;
129 }
130 buffer->allocated += count;
131 buffer->last_allocate = count;
132 return address;
133}
134
135void *cbfs_simple_buffer_unmap(struct cbfs_simple_buffer *buffer,
136 const void *address) {
137 // TODO Add simple buffer management so we can free more than last
138 // allocated one.
139 DEBUG("simple_buffer_unmap(address=0x%p): "
Hung-Te Lin966e2db2013-02-06 12:25:27 +0800140 "allocated=%zd, size=%zd, last_allocate=%zd\n",
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +0800141 address, buffer->allocated, buffer->size,
142 buffer->last_allocate);
143 if ((buffer->buffer + buffer->allocated - buffer->last_allocate) ==
144 address) {
145 buffer->allocated -= buffer->last_allocate;
146 buffer->last_allocate = 0;
147 }
148 return NULL;
Peter Stuge483b7bb2009-04-14 07:40:01 +0000149}
150
151/**
152 * run_address is passed the address of a function taking no parameters and
Stefan Reinauer14e22772010-04-27 06:56:47 +0000153 * jumps to it, returning the result.
154 * @param f the address to call as a function.
155 * @return value returned by the function.
Peter Stuge483b7bb2009-04-14 07:40:01 +0000156 */
157
158int run_address(void *f)
159{
160 int (*v) (void);
161 v = f;
162 return v();
163}
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +0800164
Sven Schnelle4297a9a2011-06-12 14:35:11 +0200165#endif