Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright (C) 2008, Jordan Crouse <jordan@cosmicpenguin.net> |
Hung-Te Lin | 6fe0cab | 2013-01-22 18:57:56 +0800 | [diff] [blame] | 5 | * Copyright (C) 2013 The Chromium OS Authors. All rights reserved. |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 6 | * |
| 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 Lin | 6fe0cab | 2013-01-22 18:57:56 +0800 | [diff] [blame] | 21 | |
Edward O'Callaghan | cdabc88 | 2014-11-11 12:22:04 +1100 | [diff] [blame] | 22 | #include "cbfs_core.h" |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 23 | |
Sven Schnelle | 4297a9a | 2011-06-12 14:35:11 +0200 | [diff] [blame] | 24 | #ifndef __SMM__ |
Stefan Reinauer | 800379f | 2010-03-01 08:34:19 +0000 | [diff] [blame] | 25 | static inline int tohex4(unsigned int c) |
Patrick Georgi | b203c2f | 2009-08-20 14:48:03 +0000 | [diff] [blame] | 26 | { |
Hung-Te Lin | 6fe0cab | 2013-01-22 18:57:56 +0800 | [diff] [blame] | 27 | return (c <= 9) ? (c + '0') : (c - 10 + 'a'); |
Patrick Georgi | b203c2f | 2009-08-20 14:48:03 +0000 | [diff] [blame] | 28 | } |
| 29 | |
| 30 | static void tohex16(unsigned int val, char* dest) |
| 31 | { |
Hung-Te Lin | 6fe0cab | 2013-01-22 18:57:56 +0800 | [diff] [blame] | 32 | 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 Georgi | b203c2f | 2009-08-20 14:48:03 +0000 | [diff] [blame] | 36 | } |
| 37 | |
Hung-Te Lin | 6fe0cab | 2013-01-22 18:57:56 +0800 | [diff] [blame] | 38 | void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor, |
| 39 | uint16_t device, void *dest) |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 40 | { |
Hung-Te Lin | 6fe0cab | 2013-01-22 18:57:56 +0800 | [diff] [blame] | 41 | char name[17] = "pciXXXX,XXXX.rom"; |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 42 | struct cbfs_optionrom *orom; |
Hung-Te Lin | 6fe0cab | 2013-01-22 18:57:56 +0800 | [diff] [blame] | 43 | uint8_t *src; |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 44 | |
Patrick Georgi | b203c2f | 2009-08-20 14:48:03 +0000 | [diff] [blame] | 45 | tohex16(vendor, name+3); |
| 46 | tohex16(device, name+8); |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 47 | |
| 48 | orom = (struct cbfs_optionrom *) |
Vladimir Serbinenko | 0af61b6 | 2014-01-12 13:45:52 +0100 | [diff] [blame] | 49 | cbfs_get_file_content(media, name, CBFS_TYPE_OPTIONROM, NULL); |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 50 | |
| 51 | if (orom == NULL) |
| 52 | return NULL; |
| 53 | |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 54 | /* They might have specified a dest address. If so, we can decompress. |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 55 | * 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 Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 57 | * 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 Lin | 6fe0cab | 2013-01-22 18:57:56 +0800 | [diff] [blame] | 59 | */ |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 60 | |
| 61 | /* BUG: the cbfstool is (not yet) including a cbfs_optionrom header */ |
Hung-Te Lin | 6fe0cab | 2013-01-22 18:57:56 +0800 | [diff] [blame] | 62 | src = (uint8_t *)orom; // + sizeof(struct cbfs_optionrom); |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 63 | |
| 64 | if (! dest) |
| 65 | return src; |
| 66 | |
Gabe Black | 0c605a5 | 2013-07-01 04:57:37 -0700 | [diff] [blame] | 67 | if (!cbfs_decompress(ntohl(orom->compression), |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 68 | src, |
| 69 | dest, |
| 70 | ntohl(orom->len))) |
| 71 | return NULL; |
| 72 | |
| 73 | return dest; |
| 74 | } |
| 75 | |
Hung-Te Lin | 6fe0cab | 2013-01-22 18:57:56 +0800 | [diff] [blame] | 76 | void * cbfs_load_stage(struct cbfs_media *media, const char *name) |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 77 | { |
| 78 | struct cbfs_stage *stage = (struct cbfs_stage *) |
Edward O'Callaghan | cdabc88 | 2014-11-11 12:22:04 +1100 | [diff] [blame] | 79 | cbfs_get_file_content(media, name, CBFS_TYPE_STAGE, NULL); |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 80 | /* this is a mess. There is no ntohll. */ |
| 81 | /* for now, assume compatible byte order until we solve this. */ |
Ronald G. Minnich | ff178be | 2014-10-16 10:57:01 +0000 | [diff] [blame] | 82 | uintptr_t entry; |
Gabe Black | 0c605a5 | 2013-07-01 04:57:37 -0700 | [diff] [blame] | 83 | uint32_t final_size; |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 84 | |
| 85 | if (stage == NULL) |
| 86 | return (void *) -1; |
| 87 | |
Marcelo Povoa | d343624 | 2014-02-06 15:17:40 -0800 | [diff] [blame] | 88 | LOG("loading stage %s @ 0x%llx (%d bytes), entry @ 0x%llx\n", |
Patrick Georgi | f107538 | 2009-07-18 14:20:39 +0000 | [diff] [blame] | 89 | name, |
Marcelo Povoa | d343624 | 2014-02-06 15:17:40 -0800 | [diff] [blame] | 90 | stage->load, stage->memlen, |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 91 | stage->entry); |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 92 | |
Gabe Black | 0c605a5 | 2013-07-01 04:57:37 -0700 | [diff] [blame] | 93 | final_size = cbfs_decompress(stage->compression, |
| 94 | ((unsigned char *) stage) + |
| 95 | sizeof(struct cbfs_stage), |
Ronald G. Minnich | ff178be | 2014-10-16 10:57:01 +0000 | [diff] [blame] | 96 | (void *) (uintptr_t) stage->load, |
Gabe Black | 0c605a5 | 2013-07-01 04:57:37 -0700 | [diff] [blame] | 97 | stage->len); |
| 98 | if (!final_size) |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 99 | return (void *) -1; |
Stefan Reinauer | b4f3da5 | 2009-10-26 17:15:53 +0000 | [diff] [blame] | 100 | |
Gabe Black | ec3a462 | 2013-07-01 04:34:29 -0700 | [diff] [blame] | 101 | /* 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 Reinauer | fe42218 | 2012-05-02 16:33:18 -0700 | [diff] [blame] | 105 | DEBUG("stage loaded.\n"); |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 106 | |
| 107 | entry = stage->entry; |
Stefan Reinauer | 02e75b2 | 2011-10-17 09:51:15 -0700 | [diff] [blame] | 108 | // entry = ntohll(stage->entry); |
Stefan Reinauer | b4f3da5 | 2009-10-26 17:15:53 +0000 | [diff] [blame] | 109 | |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 110 | return (void *) entry; |
| 111 | } |
| 112 | |
Hung-Te Lin | 6fe0cab | 2013-01-22 18:57:56 +0800 | [diff] [blame] | 113 | /* Simple buffer */ |
| 114 | |
| 115 | void *cbfs_simple_buffer_map(struct cbfs_simple_buffer *buffer, |
| 116 | struct cbfs_media *media, |
| 117 | size_t offset, size_t count) { |
Idwer Vollering | d26da9c | 2013-12-22 21:38:18 +0000 | [diff] [blame] | 118 | void *address = buffer->buffer + buffer->allocated; |
Hung-Te Lin | 966e2db | 2013-02-06 12:25:27 +0800 | [diff] [blame] | 119 | DEBUG("simple_buffer_map(offset=%zd, count=%zd): " |
| 120 | "allocated=%zd, size=%zd, last_allocate=%zd\n", |
Hung-Te Lin | 6fe0cab | 2013-01-22 18:57:56 +0800 | [diff] [blame] | 121 | 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 | |
| 135 | void *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 Lin | 966e2db | 2013-02-06 12:25:27 +0800 | [diff] [blame] | 140 | "allocated=%zd, size=%zd, last_allocate=%zd\n", |
Hung-Te Lin | 6fe0cab | 2013-01-22 18:57:56 +0800 | [diff] [blame] | 141 | 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 Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 149 | } |
| 150 | |
| 151 | /** |
| 152 | * run_address is passed the address of a function taking no parameters and |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 153 | * jumps to it, returning the result. |
| 154 | * @param f the address to call as a function. |
| 155 | * @return value returned by the function. |
Peter Stuge | 483b7bb | 2009-04-14 07:40:01 +0000 | [diff] [blame] | 156 | */ |
| 157 | |
| 158 | int run_address(void *f) |
| 159 | { |
| 160 | int (*v) (void); |
| 161 | v = f; |
| 162 | return v(); |
| 163 | } |
Hung-Te Lin | 6fe0cab | 2013-01-22 18:57:56 +0800 | [diff] [blame] | 164 | |
Sven Schnelle | 4297a9a | 2011-06-12 14:35:11 +0200 | [diff] [blame] | 165 | #endif |