1*84cd9327SGabe Black /* 2*84cd9327SGabe Black * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. 3*84cd9327SGabe Black * 4*84cd9327SGabe Black * See file CREDITS for list of people who contributed to this 5*84cd9327SGabe Black * project. 6*84cd9327SGabe Black * 7*84cd9327SGabe Black * This program is free software; you can redistribute it and/or 8*84cd9327SGabe Black * modify it under the terms of the GNU General Public License as 9*84cd9327SGabe Black * published by the Free Software Foundation; either version 2 of 10*84cd9327SGabe Black * the License, or (at your option) any later version. 11*84cd9327SGabe Black * 12*84cd9327SGabe Black * This program is distributed in the hope that it will be useful, 13*84cd9327SGabe Black * but WITHOUT ANY WARRANTY; without even the implied warranty of 14*84cd9327SGabe Black * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*84cd9327SGabe Black * GNU General Public License for more details. 16*84cd9327SGabe Black * 17*84cd9327SGabe Black * You should have received a copy of the GNU General Public License 18*84cd9327SGabe Black * along with this program; if not, write to the Free Software 19*84cd9327SGabe Black * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 20*84cd9327SGabe Black * MA 02111-1307 USA 21*84cd9327SGabe Black */ 22*84cd9327SGabe Black 23*84cd9327SGabe Black #include <cbfs.h> 24*84cd9327SGabe Black #include <malloc.h> 25*84cd9327SGabe Black #include <asm/byteorder.h> 26*84cd9327SGabe Black 27*84cd9327SGabe Black enum cbfs_result file_cbfs_result; 28*84cd9327SGabe Black 29*84cd9327SGabe Black const char *file_cbfs_error(void) 30*84cd9327SGabe Black { 31*84cd9327SGabe Black switch (file_cbfs_result) { 32*84cd9327SGabe Black case CBFS_SUCCESS: 33*84cd9327SGabe Black return "Success"; 34*84cd9327SGabe Black case CBFS_NOT_INITIALIZED: 35*84cd9327SGabe Black return "CBFS not initialized"; 36*84cd9327SGabe Black case CBFS_BAD_HEADER: 37*84cd9327SGabe Black return "Bad CBFS header"; 38*84cd9327SGabe Black case CBFS_BAD_FILE: 39*84cd9327SGabe Black return "Bad CBFS file"; 40*84cd9327SGabe Black case CBFS_FILE_NOT_FOUND: 41*84cd9327SGabe Black return "File not found"; 42*84cd9327SGabe Black default: 43*84cd9327SGabe Black return "Unknown"; 44*84cd9327SGabe Black } 45*84cd9327SGabe Black } 46*84cd9327SGabe Black 47*84cd9327SGabe Black 48*84cd9327SGabe Black static const u32 good_magic = 0x4f524243; 49*84cd9327SGabe Black static const u8 good_file_magic[] = "LARCHIVE"; 50*84cd9327SGabe Black 51*84cd9327SGabe Black 52*84cd9327SGabe Black static int initialized; 53*84cd9327SGabe Black static struct cbfs_header cbfs_header; 54*84cd9327SGabe Black static struct cbfs_cachenode *file_cache; 55*84cd9327SGabe Black 56*84cd9327SGabe Black /* Do endian conversion on the CBFS header structure. */ 57*84cd9327SGabe Black static void swap_header(struct cbfs_header *dest, struct cbfs_header *src) 58*84cd9327SGabe Black { 59*84cd9327SGabe Black dest->magic = be32_to_cpu(src->magic); 60*84cd9327SGabe Black dest->version = be32_to_cpu(src->version); 61*84cd9327SGabe Black dest->rom_size = be32_to_cpu(src->rom_size); 62*84cd9327SGabe Black dest->boot_block_size = be32_to_cpu(src->boot_block_size); 63*84cd9327SGabe Black dest->align = be32_to_cpu(src->align); 64*84cd9327SGabe Black dest->offset = be32_to_cpu(src->offset); 65*84cd9327SGabe Black } 66*84cd9327SGabe Black 67*84cd9327SGabe Black /* Do endian conversion on a CBFS file header. */ 68*84cd9327SGabe Black static void swap_file_header(struct cbfs_fileheader *dest, 69*84cd9327SGabe Black const struct cbfs_fileheader *src) 70*84cd9327SGabe Black { 71*84cd9327SGabe Black memcpy(&dest->magic, &src->magic, sizeof(dest->magic)); 72*84cd9327SGabe Black dest->len = be32_to_cpu(src->len); 73*84cd9327SGabe Black dest->type = be32_to_cpu(src->type); 74*84cd9327SGabe Black dest->checksum = be32_to_cpu(src->checksum); 75*84cd9327SGabe Black dest->offset = be32_to_cpu(src->offset); 76*84cd9327SGabe Black } 77*84cd9327SGabe Black 78*84cd9327SGabe Black /* 79*84cd9327SGabe Black * Given a starting position in memory, scan forward, bounded by a size, and 80*84cd9327SGabe Black * find the next valid CBFS file. No memory is allocated by this function. The 81*84cd9327SGabe Black * caller is responsible for allocating space for the new file structure. 82*84cd9327SGabe Black * 83*84cd9327SGabe Black * @param start The location in memory to start from. 84*84cd9327SGabe Black * @param size The size of the memory region to search. 85*84cd9327SGabe Black * @param align The alignment boundaries to check on. 86*84cd9327SGabe Black * @param newNode A pointer to the file structure to load. 87*84cd9327SGabe Black * @param used A pointer to the count of of bytes scanned through, 88*84cd9327SGabe Black * including the file if one is found. 89*84cd9327SGabe Black * 90*84cd9327SGabe Black * @return 1 if a file is found, 0 if one isn't. 91*84cd9327SGabe Black */ 92*84cd9327SGabe Black static int file_cbfs_next_file(u8 *start, u32 size, u32 align, 93*84cd9327SGabe Black struct cbfs_cachenode *newNode, u32 *used) 94*84cd9327SGabe Black { 95*84cd9327SGabe Black struct cbfs_fileheader header; 96*84cd9327SGabe Black 97*84cd9327SGabe Black *used = 0; 98*84cd9327SGabe Black 99*84cd9327SGabe Black while (size >= align) { 100*84cd9327SGabe Black const struct cbfs_fileheader *fileHeader = 101*84cd9327SGabe Black (const struct cbfs_fileheader *)start; 102*84cd9327SGabe Black u32 name_len; 103*84cd9327SGabe Black u32 step; 104*84cd9327SGabe Black 105*84cd9327SGabe Black /* Check if there's a file here. */ 106*84cd9327SGabe Black if (memcmp(good_file_magic, &(fileHeader->magic), 107*84cd9327SGabe Black sizeof(fileHeader->magic))) { 108*84cd9327SGabe Black *used += align; 109*84cd9327SGabe Black size -= align; 110*84cd9327SGabe Black start += align; 111*84cd9327SGabe Black continue; 112*84cd9327SGabe Black } 113*84cd9327SGabe Black 114*84cd9327SGabe Black swap_file_header(&header, fileHeader); 115*84cd9327SGabe Black if (header.offset < sizeof(const struct cbfs_cachenode *) || 116*84cd9327SGabe Black header.offset > header.len) { 117*84cd9327SGabe Black file_cbfs_result = CBFS_BAD_FILE; 118*84cd9327SGabe Black return -1; 119*84cd9327SGabe Black } 120*84cd9327SGabe Black newNode->next = NULL; 121*84cd9327SGabe Black newNode->type = header.type; 122*84cd9327SGabe Black newNode->data = start + header.offset; 123*84cd9327SGabe Black newNode->data_length = header.len; 124*84cd9327SGabe Black name_len = header.offset - sizeof(struct cbfs_cachenode *); 125*84cd9327SGabe Black newNode->name = (char *)fileHeader + 126*84cd9327SGabe Black sizeof(struct cbfs_cachenode *); 127*84cd9327SGabe Black newNode->name_length = name_len; 128*84cd9327SGabe Black newNode->checksum = header.checksum; 129*84cd9327SGabe Black 130*84cd9327SGabe Black step = header.len; 131*84cd9327SGabe Black if (step % align) 132*84cd9327SGabe Black step = step + align - step % align; 133*84cd9327SGabe Black 134*84cd9327SGabe Black *used += step; 135*84cd9327SGabe Black return 1; 136*84cd9327SGabe Black } 137*84cd9327SGabe Black return 0; 138*84cd9327SGabe Black } 139*84cd9327SGabe Black 140*84cd9327SGabe Black /* Look through a CBFS instance and copy file metadata into regular memory. */ 141*84cd9327SGabe Black static void file_cbfs_fill_cache(u8 *start, u32 size, u32 align) 142*84cd9327SGabe Black { 143*84cd9327SGabe Black struct cbfs_cachenode *cache_node; 144*84cd9327SGabe Black struct cbfs_cachenode *newNode; 145*84cd9327SGabe Black struct cbfs_cachenode **cache_tail = &file_cache; 146*84cd9327SGabe Black 147*84cd9327SGabe Black /* Clear out old information. */ 148*84cd9327SGabe Black cache_node = file_cache; 149*84cd9327SGabe Black while (cache_node) { 150*84cd9327SGabe Black struct cbfs_cachenode *oldNode = cache_node; 151*84cd9327SGabe Black cache_node = cache_node->next; 152*84cd9327SGabe Black free(oldNode); 153*84cd9327SGabe Black } 154*84cd9327SGabe Black file_cache = NULL; 155*84cd9327SGabe Black 156*84cd9327SGabe Black while (size >= align) { 157*84cd9327SGabe Black int result; 158*84cd9327SGabe Black u32 used; 159*84cd9327SGabe Black 160*84cd9327SGabe Black newNode = (struct cbfs_cachenode *) 161*84cd9327SGabe Black malloc(sizeof(struct cbfs_cachenode)); 162*84cd9327SGabe Black result = file_cbfs_next_file(start, size, align, 163*84cd9327SGabe Black newNode, &used); 164*84cd9327SGabe Black 165*84cd9327SGabe Black if (result < 0) { 166*84cd9327SGabe Black free(newNode); 167*84cd9327SGabe Black return; 168*84cd9327SGabe Black } else if (result == 0) { 169*84cd9327SGabe Black free(newNode); 170*84cd9327SGabe Black break; 171*84cd9327SGabe Black } 172*84cd9327SGabe Black *cache_tail = newNode; 173*84cd9327SGabe Black cache_tail = &newNode->next; 174*84cd9327SGabe Black 175*84cd9327SGabe Black size -= used; 176*84cd9327SGabe Black start += used; 177*84cd9327SGabe Black } 178*84cd9327SGabe Black file_cbfs_result = CBFS_SUCCESS; 179*84cd9327SGabe Black } 180*84cd9327SGabe Black 181*84cd9327SGabe Black /* Get the CBFS header out of the ROM and do endian conversion. */ 182*84cd9327SGabe Black static int file_cbfs_load_header(uintptr_t end_of_rom, 183*84cd9327SGabe Black struct cbfs_header *header) 184*84cd9327SGabe Black { 185*84cd9327SGabe Black struct cbfs_header *header_in_rom; 186*84cd9327SGabe Black 187*84cd9327SGabe Black header_in_rom = (struct cbfs_header *)(uintptr_t) 188*84cd9327SGabe Black *(u32 *)(end_of_rom - 3); 189*84cd9327SGabe Black swap_header(header, header_in_rom); 190*84cd9327SGabe Black 191*84cd9327SGabe Black if (header->magic != good_magic || header->offset > 192*84cd9327SGabe Black header->rom_size - header->boot_block_size) { 193*84cd9327SGabe Black file_cbfs_result = CBFS_BAD_HEADER; 194*84cd9327SGabe Black return 1; 195*84cd9327SGabe Black } 196*84cd9327SGabe Black return 0; 197*84cd9327SGabe Black } 198*84cd9327SGabe Black 199*84cd9327SGabe Black void file_cbfs_init(uintptr_t end_of_rom) 200*84cd9327SGabe Black { 201*84cd9327SGabe Black u8 *start_of_rom; 202*84cd9327SGabe Black initialized = 0; 203*84cd9327SGabe Black 204*84cd9327SGabe Black if (file_cbfs_load_header(end_of_rom, &cbfs_header)) 205*84cd9327SGabe Black return; 206*84cd9327SGabe Black 207*84cd9327SGabe Black start_of_rom = (u8 *)(end_of_rom + 1 - cbfs_header.rom_size); 208*84cd9327SGabe Black 209*84cd9327SGabe Black file_cbfs_fill_cache(start_of_rom + cbfs_header.offset, 210*84cd9327SGabe Black cbfs_header.rom_size, cbfs_header.align); 211*84cd9327SGabe Black if (file_cbfs_result == CBFS_SUCCESS) 212*84cd9327SGabe Black initialized = 1; 213*84cd9327SGabe Black } 214*84cd9327SGabe Black 215*84cd9327SGabe Black const struct cbfs_header *file_cbfs_get_header(void) 216*84cd9327SGabe Black { 217*84cd9327SGabe Black if (initialized) { 218*84cd9327SGabe Black file_cbfs_result = CBFS_SUCCESS; 219*84cd9327SGabe Black return &cbfs_header; 220*84cd9327SGabe Black } else { 221*84cd9327SGabe Black file_cbfs_result = CBFS_NOT_INITIALIZED; 222*84cd9327SGabe Black return NULL; 223*84cd9327SGabe Black } 224*84cd9327SGabe Black } 225*84cd9327SGabe Black 226*84cd9327SGabe Black const struct cbfs_cachenode *file_cbfs_get_first(void) 227*84cd9327SGabe Black { 228*84cd9327SGabe Black if (!initialized) { 229*84cd9327SGabe Black file_cbfs_result = CBFS_NOT_INITIALIZED; 230*84cd9327SGabe Black return NULL; 231*84cd9327SGabe Black } else { 232*84cd9327SGabe Black file_cbfs_result = CBFS_SUCCESS; 233*84cd9327SGabe Black return file_cache; 234*84cd9327SGabe Black } 235*84cd9327SGabe Black } 236*84cd9327SGabe Black 237*84cd9327SGabe Black void file_cbfs_get_next(const struct cbfs_cachenode **file) 238*84cd9327SGabe Black { 239*84cd9327SGabe Black if (!initialized) { 240*84cd9327SGabe Black file_cbfs_result = CBFS_NOT_INITIALIZED; 241*84cd9327SGabe Black file = NULL; 242*84cd9327SGabe Black return; 243*84cd9327SGabe Black } 244*84cd9327SGabe Black 245*84cd9327SGabe Black if (*file) 246*84cd9327SGabe Black *file = (*file)->next; 247*84cd9327SGabe Black file_cbfs_result = CBFS_SUCCESS; 248*84cd9327SGabe Black } 249*84cd9327SGabe Black 250*84cd9327SGabe Black const struct cbfs_cachenode *file_cbfs_find(const char *name) 251*84cd9327SGabe Black { 252*84cd9327SGabe Black struct cbfs_cachenode *cache_node = file_cache; 253*84cd9327SGabe Black 254*84cd9327SGabe Black if (!initialized) { 255*84cd9327SGabe Black file_cbfs_result = CBFS_NOT_INITIALIZED; 256*84cd9327SGabe Black return NULL; 257*84cd9327SGabe Black } 258*84cd9327SGabe Black 259*84cd9327SGabe Black while (cache_node) { 260*84cd9327SGabe Black if (!strcmp(name, cache_node->name)) 261*84cd9327SGabe Black break; 262*84cd9327SGabe Black cache_node = cache_node->next; 263*84cd9327SGabe Black } 264*84cd9327SGabe Black if (!cache_node) 265*84cd9327SGabe Black file_cbfs_result = CBFS_FILE_NOT_FOUND; 266*84cd9327SGabe Black else 267*84cd9327SGabe Black file_cbfs_result = CBFS_SUCCESS; 268*84cd9327SGabe Black 269*84cd9327SGabe Black return cache_node; 270*84cd9327SGabe Black } 271*84cd9327SGabe Black 272*84cd9327SGabe Black const struct cbfs_cachenode *file_cbfs_find_uncached(uintptr_t end_of_rom, 273*84cd9327SGabe Black const char *name) 274*84cd9327SGabe Black { 275*84cd9327SGabe Black u8 *start; 276*84cd9327SGabe Black u32 size; 277*84cd9327SGabe Black u32 align; 278*84cd9327SGabe Black static struct cbfs_cachenode node; 279*84cd9327SGabe Black 280*84cd9327SGabe Black if (file_cbfs_load_header(end_of_rom, &cbfs_header)) 281*84cd9327SGabe Black return NULL; 282*84cd9327SGabe Black 283*84cd9327SGabe Black start = (u8 *)(end_of_rom + 1 - cbfs_header.rom_size); 284*84cd9327SGabe Black size = cbfs_header.rom_size; 285*84cd9327SGabe Black align = cbfs_header.align; 286*84cd9327SGabe Black 287*84cd9327SGabe Black while (size >= align) { 288*84cd9327SGabe Black int result; 289*84cd9327SGabe Black u32 used; 290*84cd9327SGabe Black 291*84cd9327SGabe Black result = file_cbfs_next_file(start, size, align, &node, &used); 292*84cd9327SGabe Black 293*84cd9327SGabe Black if (result < 0) 294*84cd9327SGabe Black return NULL; 295*84cd9327SGabe Black else if (result == 0) 296*84cd9327SGabe Black break; 297*84cd9327SGabe Black 298*84cd9327SGabe Black if (!strcmp(name, node.name)) 299*84cd9327SGabe Black return &node; 300*84cd9327SGabe Black 301*84cd9327SGabe Black size -= used; 302*84cd9327SGabe Black start += used; 303*84cd9327SGabe Black } 304*84cd9327SGabe Black file_cbfs_result = CBFS_FILE_NOT_FOUND; 305*84cd9327SGabe Black return NULL; 306*84cd9327SGabe Black } 307*84cd9327SGabe Black 308*84cd9327SGabe Black const char *file_cbfs_name(const struct cbfs_cachenode *file) 309*84cd9327SGabe Black { 310*84cd9327SGabe Black file_cbfs_result = CBFS_SUCCESS; 311*84cd9327SGabe Black return file->name; 312*84cd9327SGabe Black } 313*84cd9327SGabe Black 314*84cd9327SGabe Black u32 file_cbfs_size(const struct cbfs_cachenode *file) 315*84cd9327SGabe Black { 316*84cd9327SGabe Black file_cbfs_result = CBFS_SUCCESS; 317*84cd9327SGabe Black return file->data_length; 318*84cd9327SGabe Black } 319*84cd9327SGabe Black 320*84cd9327SGabe Black u32 file_cbfs_type(const struct cbfs_cachenode *file) 321*84cd9327SGabe Black { 322*84cd9327SGabe Black file_cbfs_result = CBFS_SUCCESS; 323*84cd9327SGabe Black return file->type; 324*84cd9327SGabe Black } 325*84cd9327SGabe Black 326*84cd9327SGabe Black long file_cbfs_read(const struct cbfs_cachenode *file, void *buffer, 327*84cd9327SGabe Black unsigned long maxsize) 328*84cd9327SGabe Black { 329*84cd9327SGabe Black u32 size; 330*84cd9327SGabe Black 331*84cd9327SGabe Black size = file->data_length; 332*84cd9327SGabe Black if (maxsize && size > maxsize) 333*84cd9327SGabe Black size = maxsize; 334*84cd9327SGabe Black 335*84cd9327SGabe Black memcpy(buffer, file->data, size); 336*84cd9327SGabe Black 337*84cd9327SGabe Black file_cbfs_result = CBFS_SUCCESS; 338*84cd9327SGabe Black return size; 339*84cd9327SGabe Black } 340