1 /*-
2 * Copyright (c) 2021 Colin Percival
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/types.h>
28
29 #if defined(__amd64__) || defined(__i386__)
30 #include <machine/cpufunc.h>
31 #elif defined(__aarch64__)
32 #include <machine/armreg.h>
33 #endif
34
35 #include <stand.h>
36
37 /* Buffer for holding tslog data in string format. */
38 static char * tslog_buf = NULL;
39 static size_t tslog_buflen = 0;
40 static size_t tslog_bufpos = 0;
41
42 static size_t
tsccat(char * buf,uint64_t tsc)43 tsccat(char * buf, uint64_t tsc)
44 {
45 size_t len;
46
47 /* Handle upper digits. */
48 if (tsc >= 10)
49 len = tsccat(buf, tsc / 10);
50 else
51 len = 0;
52
53 /* Write the last digit. */
54 buf[len] = "0123456789"[tsc % 10];
55
56 /* Return the length written. */
57 return (len + 1);
58 }
59
60 void
tslog_setbuf(void * buf,size_t len)61 tslog_setbuf(void * buf, size_t len)
62 {
63
64 tslog_buf = (char *)buf;
65 tslog_buflen = len;
66 tslog_bufpos = 0;
67 }
68
69 void
tslog_getbuf(void ** buf,size_t * len)70 tslog_getbuf(void ** buf, size_t * len)
71 {
72
73 *buf = (void *)tslog_buf;
74 *len = tslog_bufpos;
75 }
76
77 void
tslog(const char * type,const char * f,const char * s)78 tslog(const char * type, const char * f, const char * s)
79 {
80 #if defined(__amd64__) || defined(__i386__)
81 uint64_t tsc = rdtsc();
82 #elif defined(__aarch64__)
83 uint64_t tsc = READ_SPECIALREG(cntvct_el0);
84 #else
85 uint64_t tsc = 0;
86 #endif
87
88 /* If we have no buffer, do nothing. */
89 if (tslog_buf == NULL)
90 return;
91
92 /* Check that we have enough space. */
93 if (tslog_buflen - tslog_bufpos < 32 + strlen(type) + strlen(f) +
94 (s ? strlen(s) : 0))
95 return;
96
97 /* Append to existing buffer. */
98 strcpy(&tslog_buf[tslog_bufpos], "0x0 ");
99 tslog_bufpos += 4;
100 tslog_bufpos += tsccat(&tslog_buf[tslog_bufpos], tsc);
101 strcpy(&tslog_buf[tslog_bufpos], " ");
102 tslog_bufpos += 1;
103 strcpy(&tslog_buf[tslog_bufpos], type);
104 tslog_bufpos += strlen(type);
105 strcpy(&tslog_buf[tslog_bufpos], " ");
106 tslog_bufpos += 1;
107 strcpy(&tslog_buf[tslog_bufpos], f);
108 tslog_bufpos += strlen(f);
109 if (s != NULL) {
110 strcpy(&tslog_buf[tslog_bufpos], " ");
111 tslog_bufpos += 1;
112 strcpy(&tslog_buf[tslog_bufpos], s);
113 tslog_bufpos += strlen(s);
114 }
115 strcpy(&tslog_buf[tslog_bufpos], "\n");
116 tslog_bufpos += 1;
117 }
118