Angel Pons | 118a9c7 | 2020-04-02 23:48:34 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 2 | |
| 3 | #include <stdint.h> |
Aaron Durbin | 4dd87fb | 2013-04-24 16:28:52 -0500 | [diff] [blame] | 4 | #include <bootstate.h> |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 5 | #include <cbmem.h> |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 6 | |
| 7 | typedef struct file { |
| 8 | uint32_t magic; |
| 9 | struct file *next; |
| 10 | char *filename; |
| 11 | char *data; |
| 12 | int offset; |
| 13 | int len; |
| 14 | } FILE; |
| 15 | |
| 16 | #define SEEK_SET 0 /* Seek from beginning of file. */ |
| 17 | |
| 18 | #define DIR_SEPARATOR '/' |
| 19 | #define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) |
| 20 | #define HAS_DRIVE_SPEC(f) (0) |
| 21 | |
| 22 | #define COVERAGE_SIZE (32*1024) |
| 23 | |
Jean Lucas | 9ab9c33 | 2016-01-30 01:20:54 -0500 | [diff] [blame] | 24 | #define COVERAGE_MAGIC 0x584d4153 |
Paul Menzel | c824c26 | 2015-10-05 20:02:09 +0200 | [diff] [blame] | 25 | |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 26 | static FILE *current_file = NULL; |
| 27 | static FILE *previous_file = NULL; |
| 28 | |
| 29 | static FILE *fopen(const char *path, const char *mode) |
| 30 | { |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 31 | #if CONFIG(DEBUG_COVERAGE) |
Elyes Haouas | 39efcd1 | 2023-01-22 11:53:56 +0100 | [diff] [blame] | 32 | printk(BIOS_DEBUG, "%s %s with mode %s\n", __func__, path, mode); |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 33 | #endif |
| 34 | if (!current_file) { |
| 35 | current_file = cbmem_add(CBMEM_ID_COVERAGE, 32*1024); |
| 36 | } else { |
| 37 | previous_file = current_file; |
Lee Leahy | 7340217 | 2017-03-10 15:23:24 -0800 | [diff] [blame] | 38 | current_file = |
Elyes Haouas | d6b6b22 | 2022-10-10 12:34:21 +0200 | [diff] [blame] | 39 | (FILE *)(ALIGN_UP(((unsigned long)previous_file->data |
Lee Leahy | 7340217 | 2017-03-10 15:23:24 -0800 | [diff] [blame] | 40 | + previous_file->len), 16)); |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 41 | } |
| 42 | |
| 43 | // TODO check if we're at the end of the CBMEM region (ENOMEM) |
| 44 | if (current_file) { |
Paul Menzel | c824c26 | 2015-10-05 20:02:09 +0200 | [diff] [blame] | 45 | current_file->magic = COVERAGE_MAGIC; |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 46 | current_file->next = NULL; |
| 47 | if (previous_file) |
| 48 | previous_file->next = current_file; |
| 49 | current_file->filename = (char *)¤t_file[1]; |
| 50 | strcpy(current_file->filename, path); |
Lee Leahy | 7340217 | 2017-03-10 15:23:24 -0800 | [diff] [blame] | 51 | current_file->data = |
Elyes Haouas | d6b6b22 | 2022-10-10 12:34:21 +0200 | [diff] [blame] | 52 | (char *)ALIGN_UP(((unsigned long)current_file->filename |
Lee Leahy | 7340217 | 2017-03-10 15:23:24 -0800 | [diff] [blame] | 53 | + strlen(path) + 1), 16); |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 54 | current_file->offset = 0; |
| 55 | current_file->len = 0; |
| 56 | } |
| 57 | |
| 58 | return current_file; |
| 59 | } |
| 60 | |
| 61 | static int fclose(FILE *stream) |
| 62 | { |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 63 | #if CONFIG(DEBUG_COVERAGE) |
Elyes Haouas | 39efcd1 | 2023-01-22 11:53:56 +0100 | [diff] [blame] | 64 | printk(BIOS_DEBUG, "%s %s\n", __func__, stream->filename); |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 65 | #endif |
| 66 | return 0; |
| 67 | } |
| 68 | |
| 69 | static int fseek(FILE *stream, long offset, int whence) |
| 70 | { |
| 71 | /* fseek should only be called with offset==0 and whence==SEEK_SET |
| 72 | * to a freshly opened file. */ |
Lee Leahy | 38768c3 | 2017-03-09 14:07:18 -0800 | [diff] [blame] | 73 | gcc_assert(offset == 0 && whence == SEEK_SET); |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 74 | #if CONFIG(DEBUG_COVERAGE) |
Elyes Haouas | 39efcd1 | 2023-01-22 11:53:56 +0100 | [diff] [blame] | 75 | printk(BIOS_DEBUG, "%s %s offset=%ld whence=%d\n", |
| 76 | __func__, stream->filename, offset, whence); |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 77 | #endif |
| 78 | return 0; |
| 79 | } |
| 80 | |
| 81 | static long ftell(FILE *stream) |
| 82 | { |
| 83 | /* ftell should currently not be called */ |
Patrick Georgi | ac01106 | 2020-08-03 08:40:11 +0200 | [diff] [blame] | 84 | BUG(); |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 85 | #if CONFIG(DEBUG_COVERAGE) |
Elyes Haouas | 39efcd1 | 2023-01-22 11:53:56 +0100 | [diff] [blame] | 86 | printk(BIOS_DEBUG, "%s %s\n", __func__, stream->filename); |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 87 | #endif |
| 88 | return 0; |
| 89 | } |
| 90 | |
| 91 | static size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) |
| 92 | { |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 93 | #if CONFIG(DEBUG_COVERAGE) |
Elyes Haouas | 39efcd1 | 2023-01-22 11:53:56 +0100 | [diff] [blame] | 94 | printk(BIOS_DEBUG, "%s: ptr=%p size=%zd nmemb=%zd FILE*=%p\n", |
| 95 | __func__, ptr, size, nmemb, stream); |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 96 | #endif |
| 97 | return 0; |
| 98 | } |
| 99 | |
| 100 | static size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) |
| 101 | { |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 102 | #if CONFIG(DEBUG_COVERAGE) |
Elyes Haouas | 39efcd1 | 2023-01-22 11:53:56 +0100 | [diff] [blame] | 103 | printk(BIOS_DEBUG, "%s: %zd * %zd bytes to file %s\n", |
| 104 | __func__, nmemb, size, stream->filename); |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 105 | #endif |
| 106 | // TODO check if file is last opened file and fail otherwise. |
| 107 | |
| 108 | memcpy(stream->data + stream->offset, ptr, size * nmemb); |
| 109 | stream->len += (nmemb * size) - (stream->len - stream->offset); |
| 110 | stream->offset += nmemb * size; |
| 111 | return nmemb; |
| 112 | } |
| 113 | |
| 114 | static void setbuf(FILE *stream, char *buf) |
| 115 | { |
| 116 | gcc_assert(buf == 0); |
| 117 | } |
| 118 | |
Aaron Durbin | 4dd87fb | 2013-04-24 16:28:52 -0500 | [diff] [blame] | 119 | static void coverage_init(void *unused) |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 120 | { |
| 121 | extern long __CTOR_LIST__; |
Lee Leahy | 35af5c4 | 2017-03-09 17:35:28 -0800 | [diff] [blame] | 122 | typedef void (*func_ptr)(void); |
Lee Leahy | b2d834a | 2017-03-08 16:52:22 -0800 | [diff] [blame] | 123 | func_ptr *ctor = (func_ptr *) &__CTOR_LIST__; |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 124 | if (ctor == NULL) |
| 125 | return; |
| 126 | |
Lee Leahy | 2f919ec | 2017-03-08 17:37:06 -0800 | [diff] [blame] | 127 | for (; *ctor != (func_ptr) 0; ctor++) |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 128 | (*ctor)(); |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 129 | } |
| 130 | |
| 131 | void __gcov_flush(void); |
Aaron Durbin | 4dd87fb | 2013-04-24 16:28:52 -0500 | [diff] [blame] | 132 | static void coverage_exit(void *unused) |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 133 | { |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 134 | #if CONFIG(DEBUG_COVERAGE) |
Stefan Reinauer | d37ab45 | 2012-12-18 16:23:28 -0800 | [diff] [blame] | 135 | printk(BIOS_DEBUG, "Syncing coverage data.\n"); |
| 136 | #endif |
| 137 | __gcov_flush(); |
| 138 | } |
| 139 | |
Aaron Durbin | 9ef9d85 | 2015-03-16 17:30:09 -0500 | [diff] [blame] | 140 | BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, coverage_init, NULL); |
| 141 | BOOT_STATE_INIT_ENTRY(BS_OS_RESUME, BS_ON_ENTRY, coverage_exit, NULL); |
| 142 | BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_EXIT, coverage_exit, NULL); |