1 /*
2  * Copyright (c) 2022 Intel Corporation
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #include <zephyr/device.h>
7 #include <zephyr/init.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/sys/winstream.h>
10 #include <zephyr/sys/printk-hooks.h>
11 #include <zephyr/sys/libc-hooks.h>
12 #include <zephyr/devicetree.h>
13 #include <zephyr/cache.h>
14 
15 #ifdef CONFIG_SOC_FAMILY_INTEL_ADSP
16 #include <adsp_memory.h>
17 #include <mem_window.h>
18 #endif
19 
20 struct k_spinlock trace_lock;
21 
22 static struct sys_winstream *winstream;
23 
winstream_console_trace_out(int8_t * str,size_t len)24 void winstream_console_trace_out(int8_t *str, size_t len)
25 {
26 	if (len == 0) {
27 		return;
28 	}
29 
30 #ifdef CONFIG_ADSP_TRACE_SIMCALL
31 	register int a2 __asm__("a2") = 4; /* SYS_write */
32 	register int a3 __asm__("a3") = 1; /* fd 1 == stdout */
33 	register int a4 __asm__("a4") = (int)str;
34 	register int a5 __asm__("a5") = len;
35 
36 	__asm__ volatile("simcall" : "+r"(a2), "+r"(a3) : "r"(a4), "r"(a5) : "memory");
37 #endif
38 
39 	k_spinlock_key_t key = k_spin_lock(&trace_lock);
40 
41 	sys_winstream_write(winstream, str, len);
42 	k_spin_unlock(&trace_lock, key);
43 }
44 
arch_printk_char_out(int c)45 int arch_printk_char_out(int c)
46 {
47 	int8_t s = c;
48 
49 	winstream_console_trace_out(&s, 1);
50 	return 0;
51 }
52 
winstream_console_hook_install(void)53 static void winstream_console_hook_install(void)
54 {
55 #if defined(CONFIG_STDOUT_CONSOLE)
56 	__stdout_hook_install(arch_printk_char_out);
57 #endif
58 #if defined(CONFIG_PRINTK)
59 	__printk_hook_install(arch_printk_char_out);
60 #endif
61 }
62 
63 /* This gets optionally defined by the platform layer as it needs (it
64  * might want to go in a special location to coordinate with linux
65  * userspace, etc...)
66  */
67 extern char _winstream_console_buf[];
68 
69 /* This descriptor with a 96-bit magic number gets linked into the
70  * binary when enabled so that external tooling can easily find it at
71  * runtime (e.g. by searching the binary image file, etc...)
72  */
73 #define WINSTREAM_CONSOLE_MAGIC1 0xd06a5f74U
74 #define WINSTREAM_CONSOLE_MAGIC2 0x004fe279U
75 #define WINSTREAM_CONSOLE_MAGIC3 0xf9bdb8cdU
76 
77 struct winstream_console_desc {
78 	uint32_t magic1;
79 	uint32_t magic2;
80 	uint32_t magic3;
81 	uint32_t buf_addr;
82 	uint32_t size;
83 };
84 
85 static const __used struct winstream_console_desc wsdesc = {
86 	.magic1 = WINSTREAM_CONSOLE_MAGIC1,
87 	.magic2 = WINSTREAM_CONSOLE_MAGIC2,
88 	.magic3 = WINSTREAM_CONSOLE_MAGIC3,
89 	.buf_addr = (uint32_t) &_winstream_console_buf,
90 	.size = CONFIG_WINSTREAM_CONSOLE_STATIC_SIZE,
91 };
92 
winstream_console_init(void)93 static int winstream_console_init(void)
94 {
95 	void *buf = NULL;
96 	size_t size = 0;
97 
98 #ifdef CONFIG_SOC_FAMILY_INTEL_ADSP
99 	/* These have a SOC-specific "mem_window" device.  FIXME: The
100 	 * type handling is backwards here.  We shouldn't be grabbing
101 	 * an arbitrary DTS alias and assuming it's a mem_window at
102 	 * runtime, that's not safe.  The mem_window init code (which
103 	 * is typesafe by construction) should be detecting that it's
104 	 * supposed to be the console and starting the console hook
105 	 * registration process.
106 	 */
107 	const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
108 
109 	if (!device_is_ready(dev)) {
110 		return -ENODEV;
111 	}
112 	const struct mem_win_config *config = dev->config;
113 	buf = sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *)config->mem_base);
114 	size = config->size;
115 #endif
116 
117 #ifdef CONFIG_WINSTREAM_CONSOLE_STATIC
118 	/* Dirty trick to prevent linker garbage collection */
119 	_winstream_console_buf[0] = ((volatile char*) &wsdesc)[0];
120 
121 	buf = &_winstream_console_buf;
122 	size = CONFIG_WINSTREAM_CONSOLE_STATIC_SIZE;
123 #endif
124 
125 	__ASSERT_NO_MSG(buf != NULL && size != 0);
126 	winstream = sys_winstream_init(buf, size);
127 	winstream_console_hook_install();
128 
129 	return 0;
130 }
131 
132 SYS_INIT(winstream_console_init, PRE_KERNEL_1, CONFIG_CONSOLE_INIT_PRIORITY);
133