Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright (C) 2012 Google, Inc. All rights reserved. |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; version 2 of the License. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
Patrick Georgi | b890a12 | 2015-03-26 15:17:45 +0100 | [diff] [blame] | 17 | * Foundation, Inc. |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 18 | */ |
| 19 | |
| 20 | #include <stdint.h> |
Aaron Durbin | 4dd87fb | 2013-04-24 16:28:52 -0500 | [diff] [blame] | 21 | #include <bootstate.h> |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 22 | #include <cbmem.h> |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 23 | |
| 24 | typedef struct file { |
| 25 | uint32_t magic; |
| 26 | struct file *next; |
| 27 | char *filename; |
| 28 | char *data; |
| 29 | int offset; |
| 30 | int len; |
| 31 | } FILE; |
| 32 | |
| 33 | #define SEEK_SET 0 /* Seek from beginning of file. */ |
| 34 | |
| 35 | #define DIR_SEPARATOR '/' |
| 36 | #define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) |
| 37 | #define HAS_DRIVE_SPEC(f) (0) |
| 38 | |
| 39 | #define COVERAGE_SIZE (32*1024) |
| 40 | |
| 41 | static FILE *current_file = NULL; |
| 42 | static FILE *previous_file = NULL; |
| 43 | |
| 44 | static FILE *fopen(const char *path, const char *mode) |
| 45 | { |
| 46 | #if CONFIG_DEBUG_COVERAGE |
| 47 | printk(BIOS_DEBUG, "fopen %s with mode %s\n", |
| 48 | path, mode); |
| 49 | #endif |
| 50 | if (!current_file) { |
| 51 | current_file = cbmem_add(CBMEM_ID_COVERAGE, 32*1024); |
| 52 | } else { |
| 53 | previous_file = current_file; |
| 54 | current_file = (FILE *)(ALIGN(((unsigned long)previous_file->data + previous_file->len), 16)); |
| 55 | } |
| 56 | |
| 57 | // TODO check if we're at the end of the CBMEM region (ENOMEM) |
| 58 | if (current_file) { |
| 59 | current_file->magic = 0x584d4153; |
| 60 | current_file->next = NULL; |
| 61 | if (previous_file) |
| 62 | previous_file->next = current_file; |
| 63 | current_file->filename = (char *)¤t_file[1]; |
| 64 | strcpy(current_file->filename, path); |
| 65 | current_file->data = (char *)ALIGN(((unsigned long)current_file->filename + strlen(path) + 1), 16); |
| 66 | current_file->offset = 0; |
| 67 | current_file->len = 0; |
| 68 | } |
| 69 | |
| 70 | return current_file; |
| 71 | } |
| 72 | |
| 73 | static int fclose(FILE *stream) |
| 74 | { |
| 75 | #if CONFIG_DEBUG_COVERAGE |
| 76 | printk(BIOS_DEBUG, "fclose %s\n", stream->filename); |
| 77 | #endif |
| 78 | return 0; |
| 79 | } |
| 80 | |
| 81 | static int fseek(FILE *stream, long offset, int whence) |
| 82 | { |
| 83 | /* fseek should only be called with offset==0 and whence==SEEK_SET |
| 84 | * to a freshly opened file. */ |
| 85 | gcc_assert (offset == 0 && whence == SEEK_SET); |
| 86 | #if CONFIG_DEBUG_COVERAGE |
Stefan Reinauer | 84463ef | 2013-04-05 13:49:55 -0700 | [diff] [blame] | 87 | printk(BIOS_DEBUG, "fseek %s offset=%ld whence=%d\n", |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 88 | stream->filename, offset, whence); |
| 89 | #endif |
| 90 | return 0; |
| 91 | } |
| 92 | |
| 93 | static long ftell(FILE *stream) |
| 94 | { |
| 95 | /* ftell should currently not be called */ |
| 96 | gcc_assert(0); |
| 97 | #if CONFIG_DEBUG_COVERAGE |
| 98 | printk(BIOS_DEBUG, "ftell %s\n", stream->filename); |
| 99 | #endif |
| 100 | return 0; |
| 101 | } |
| 102 | |
| 103 | static size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) |
| 104 | { |
| 105 | #if CONFIG_DEBUG_COVERAGE |
| 106 | printk(BIOS_DEBUG, "fread: ptr=%p size=%zd nmemb=%zd FILE*=%p\n", |
| 107 | ptr, size, nmemb, stream); |
| 108 | #endif |
| 109 | return 0; |
| 110 | } |
| 111 | |
| 112 | static size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) |
| 113 | { |
| 114 | #if CONFIG_DEBUG_COVERAGE |
| 115 | printk(BIOS_DEBUG, "fwrite: %zd * 0x%zd bytes to file %s\n", |
| 116 | nmemb, size, stream->filename); |
| 117 | #endif |
| 118 | // TODO check if file is last opened file and fail otherwise. |
| 119 | |
| 120 | memcpy(stream->data + stream->offset, ptr, size * nmemb); |
| 121 | stream->len += (nmemb * size) - (stream->len - stream->offset); |
| 122 | stream->offset += nmemb * size; |
| 123 | return nmemb; |
| 124 | } |
| 125 | |
| 126 | static void setbuf(FILE *stream, char *buf) |
| 127 | { |
| 128 | gcc_assert(buf == 0); |
| 129 | } |
| 130 | |
Aaron Durbin | 4dd87fb | 2013-04-24 16:28:52 -0500 | [diff] [blame] | 131 | static void coverage_init(void *unused) |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 132 | { |
| 133 | extern long __CTOR_LIST__; |
| 134 | typedef void (*func_ptr)(void) ; |
| 135 | func_ptr *ctor = (func_ptr*) &__CTOR_LIST__; |
| 136 | if (ctor == NULL) |
| 137 | return; |
| 138 | |
| 139 | for ( ; *ctor != (func_ptr) 0; ctor++) { |
| 140 | (*ctor)(); |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | void __gcov_flush(void); |
Aaron Durbin | 4dd87fb | 2013-04-24 16:28:52 -0500 | [diff] [blame] | 145 | static void coverage_exit(void *unused) |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 146 | { |
| 147 | #if CONFIG_DEBUG_COVERAGE |
| 148 | printk(BIOS_DEBUG, "Syncing coverage data.\n"); |
| 149 | #endif |
| 150 | __gcov_flush(); |
| 151 | } |
| 152 | |
Aaron Durbin | 9ef9d85 | 2015-03-16 17:30:09 -0500 | [diff] [blame] | 153 | BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, coverage_init, NULL); |
| 154 | BOOT_STATE_INIT_ENTRY(BS_OS_RESUME, BS_ON_ENTRY, coverage_exit, NULL); |
| 155 | BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_EXIT, coverage_exit, NULL); |