1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2019 Intel Corporation. All rights reserved.
4 //
5 // Author: Marcin Rajwa <marcin.rajwa@linux.intel.com>
6 
7 /*
8  * Xtensa related functions for GDB.
9  *
10  */
11 #define GDB_DISABLE_LOWER_INTERRUPTS_MASK ~0x1F
12 
13 #include <arch/debug/gdb/utilities.h>
14 #include <xtensa/config/core-isa.h>
15 #include <xtensa/specreg.h>
16 
arch_gdb_read_sr(int sr)17 void arch_gdb_read_sr(int sr)
18 {
19 	int val;
20 
21 	asm volatile ("movi	a3, 1f + 1\n"
22 		      "s8i	%1, a3, 0\n"
23 		      "dhwb	a3, 0\n"
24 		      "ihi	a3, 0\n"
25 		      "isync\n"
26 		      "1:\n"
27 		      "rsr	%0, lbeg\n"
28 		      : "=r"(val)
29 		      : "r"(sr)
30 		      : "a3", "memory");
31 }
32 
arch_gdb_write_sr(int sr,int * sregs)33 void arch_gdb_write_sr(int sr, int *sregs)
34 {
35 	asm volatile ("movi	a3, 1f + 1\n"
36 		      "s8i	%1, a3, 0\n"
37 		      "dhwb	a3, 0\n"
38 		      "ihi	a3, 0\n"
39 		      "isync\n"
40 		      "1:\n"
41 		      "wsr	%0, lbeg\n"
42 		      :
43 		      : "r"(sregs[sr]), "r"(sr)
44 		      : "a3", "memory");
45 }
46 
arch_gdb_load_from_memory(void * mem)47 unsigned char arch_gdb_load_from_memory(void *mem)
48 {
49 	unsigned long v;
50 	unsigned long addr = (unsigned long)mem;
51 	unsigned char ch;
52 
53 	asm volatile ("_l32i	%0, %1, 0\n"
54 	      : "=r"(v)
55 	      : "r"(addr & ~3)
56 	      : "memory");
57 	ch = v >> (addr & 3) * 8;
58 
59 	return ch;
60 }
61 
arch_gdb_memory_load_and_store(void * mem,unsigned char ch)62 void arch_gdb_memory_load_and_store(void *mem, unsigned char ch)
63 {
64 	unsigned long tmp;
65 	unsigned long addr = (unsigned long)mem;
66 
67 	asm volatile ("_l32i	%0, %1, 0\n"
68 		      "and	%0, %0, %2\n"
69 		      "or	%0, %0, %3\n"
70 		      "_s32i	%0, %1, 0\n"
71 		      "dhwb	%1, 0\n"
72 		      "ihi	%1, 0\n"
73 		      : "=&r"(tmp)
74 		      : "r"(addr & ~3), "r"(0xffffffff ^ (0xff <<
75 						(addr & 3) * 8)),
76 			"r"(ch << (addr & 3) * 8)
77 		      : "memory");
78 }
79 
arch_gdb_single_step(int * sregs)80 void arch_gdb_single_step(int *sregs)
81 {
82 	/* leave debug just for one instruction */
83 	sregs[ICOUNT] = 0xfffffffe;
84 	sregs[ICOUNTLEVEL] = XCHAL_DEBUGLEVEL;
85 	/* disable low level interrupts */
86 	sregs[INTENABLE]  &= ~GDB_DISABLE_LOWER_INTERRUPTS_MASK;
87 	arch_gdb_write_sr(ICOUNTLEVEL, sregs);
88 	arch_gdb_write_sr(ICOUNT, sregs);
89 	arch_gdb_write_sr(INTENABLE, sregs);
90 }
91