blob: d8ebe70e9e4207deb3c0a8fb927bf0b4866539fa [file] [log] [blame]
Angel Pons118a9c72020-04-02 23:48:34 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauerd37ab452012-12-18 16:23:28 -08002
3#include <stdint.h>
Aaron Durbin4dd87fb2013-04-24 16:28:52 -05004#include <bootstate.h>
Stefan Reinauerd37ab452012-12-18 16:23:28 -08005#include <cbmem.h>
Stefan Reinauerd37ab452012-12-18 16:23:28 -08006
7typedef 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 Lucas9ab9c332016-01-30 01:20:54 -050024#define COVERAGE_MAGIC 0x584d4153
Paul Menzelc824c262015-10-05 20:02:09 +020025
Stefan Reinauerd37ab452012-12-18 16:23:28 -080026static FILE *current_file = NULL;
27static FILE *previous_file = NULL;
28
29static FILE *fopen(const char *path, const char *mode)
30{
Julius Wernercd49cce2019-03-05 16:53:33 -080031#if CONFIG(DEBUG_COVERAGE)
Elyes Haouas39efcd12023-01-22 11:53:56 +010032 printk(BIOS_DEBUG, "%s %s with mode %s\n", __func__, path, mode);
Stefan Reinauerd37ab452012-12-18 16:23:28 -080033#endif
34 if (!current_file) {
35 current_file = cbmem_add(CBMEM_ID_COVERAGE, 32*1024);
36 } else {
37 previous_file = current_file;
Lee Leahy73402172017-03-10 15:23:24 -080038 current_file =
Elyes Haouasd6b6b222022-10-10 12:34:21 +020039 (FILE *)(ALIGN_UP(((unsigned long)previous_file->data
Lee Leahy73402172017-03-10 15:23:24 -080040 + previous_file->len), 16));
Stefan Reinauerd37ab452012-12-18 16:23:28 -080041 }
42
43 // TODO check if we're at the end of the CBMEM region (ENOMEM)
44 if (current_file) {
Paul Menzelc824c262015-10-05 20:02:09 +020045 current_file->magic = COVERAGE_MAGIC;
Stefan Reinauerd37ab452012-12-18 16:23:28 -080046 current_file->next = NULL;
47 if (previous_file)
48 previous_file->next = current_file;
49 current_file->filename = (char *)&current_file[1];
50 strcpy(current_file->filename, path);
Lee Leahy73402172017-03-10 15:23:24 -080051 current_file->data =
Elyes Haouasd6b6b222022-10-10 12:34:21 +020052 (char *)ALIGN_UP(((unsigned long)current_file->filename
Lee Leahy73402172017-03-10 15:23:24 -080053 + strlen(path) + 1), 16);
Stefan Reinauerd37ab452012-12-18 16:23:28 -080054 current_file->offset = 0;
55 current_file->len = 0;
56 }
57
58 return current_file;
59}
60
61static int fclose(FILE *stream)
62{
Julius Wernercd49cce2019-03-05 16:53:33 -080063#if CONFIG(DEBUG_COVERAGE)
Elyes Haouas39efcd12023-01-22 11:53:56 +010064 printk(BIOS_DEBUG, "%s %s\n", __func__, stream->filename);
Stefan Reinauerd37ab452012-12-18 16:23:28 -080065#endif
66 return 0;
67}
68
69static 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 Leahy38768c32017-03-09 14:07:18 -080073 gcc_assert(offset == 0 && whence == SEEK_SET);
Julius Wernercd49cce2019-03-05 16:53:33 -080074#if CONFIG(DEBUG_COVERAGE)
Elyes Haouas39efcd12023-01-22 11:53:56 +010075 printk(BIOS_DEBUG, "%s %s offset=%ld whence=%d\n",
76 __func__, stream->filename, offset, whence);
Stefan Reinauerd37ab452012-12-18 16:23:28 -080077#endif
78 return 0;
79}
80
81static long ftell(FILE *stream)
82{
83 /* ftell should currently not be called */
Patrick Georgiac011062020-08-03 08:40:11 +020084 BUG();
Julius Wernercd49cce2019-03-05 16:53:33 -080085#if CONFIG(DEBUG_COVERAGE)
Elyes Haouas39efcd12023-01-22 11:53:56 +010086 printk(BIOS_DEBUG, "%s %s\n", __func__, stream->filename);
Stefan Reinauerd37ab452012-12-18 16:23:28 -080087#endif
88 return 0;
89}
90
91static size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
92{
Julius Wernercd49cce2019-03-05 16:53:33 -080093#if CONFIG(DEBUG_COVERAGE)
Elyes Haouas39efcd12023-01-22 11:53:56 +010094 printk(BIOS_DEBUG, "%s: ptr=%p size=%zd nmemb=%zd FILE*=%p\n",
95 __func__, ptr, size, nmemb, stream);
Stefan Reinauerd37ab452012-12-18 16:23:28 -080096#endif
97 return 0;
98}
99
100static size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
101{
Julius Wernercd49cce2019-03-05 16:53:33 -0800102#if CONFIG(DEBUG_COVERAGE)
Elyes Haouas39efcd12023-01-22 11:53:56 +0100103 printk(BIOS_DEBUG, "%s: %zd * %zd bytes to file %s\n",
104 __func__, nmemb, size, stream->filename);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800105#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
114static void setbuf(FILE *stream, char *buf)
115{
116 gcc_assert(buf == 0);
117}
118
Aaron Durbin4dd87fb2013-04-24 16:28:52 -0500119static void coverage_init(void *unused)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800120{
121 extern long __CTOR_LIST__;
Lee Leahy35af5c42017-03-09 17:35:28 -0800122 typedef void (*func_ptr)(void);
Lee Leahyb2d834a2017-03-08 16:52:22 -0800123 func_ptr *ctor = (func_ptr *) &__CTOR_LIST__;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800124 if (ctor == NULL)
125 return;
126
Lee Leahy2f919ec2017-03-08 17:37:06 -0800127 for (; *ctor != (func_ptr) 0; ctor++)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800128 (*ctor)();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800129}
130
131void __gcov_flush(void);
Aaron Durbin4dd87fb2013-04-24 16:28:52 -0500132static void coverage_exit(void *unused)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800133{
Julius Wernercd49cce2019-03-05 16:53:33 -0800134#if CONFIG(DEBUG_COVERAGE)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800135 printk(BIOS_DEBUG, "Syncing coverage data.\n");
136#endif
137 __gcov_flush();
138}
139
Aaron Durbin9ef9d852015-03-16 17:30:09 -0500140BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, coverage_init, NULL);
141BOOT_STATE_INIT_ENTRY(BS_OS_RESUME, BS_ON_ENTRY, coverage_exit, NULL);
142BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_EXIT, coverage_exit, NULL);