1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* CPU-specific functions needed by the Kernel-Debugger Interface (KDI). These
* functions are invoked directly by the kernel debugger (kmdb) while the system
* has been stopped, and as such must not use any kernel facilities that block
* or otherwise rely on forward progress by other parts of the kernel.
*
* These functions may also be called before unix`_start, and as such cannot
* use any kernel facilities that must be initialized as part of system start.
* An example of such a facility is drv_usecwait(), which relies on a parameter
* that is initialized by the unix module. As a result, drv_usecwait() may not
* be used by KDI functions.
*/
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/archsystm.h>
#include <sys/machsystm.h>
#include <sys/cpu_module.h>
#include <sys/xc_impl.h>
#include <sys/intreg.h>
#include <sys/kdi_impl.h>
/*
* We keep our own copies, used for cache flushing, because we can be called
* before cpu_fiximpl().
*/
static int kdi_dcache_size;
static int kdi_dcache_linesize;
static int kdi_icache_size;
static int kdi_icache_linesize;
/*
* Assembly support for SPARC64-VI modules in opl_olympus_asm.s
*/
extern int idsr_busy(void);
extern void init_mondo_nocheck(xcfunc_t *func, uint64_t arg1, uint64_t arg2);
extern void shipit(int, int);
extern void kdi_flush_idcache(int, int, int, int);
extern int kdi_get_stick(uint64_t *);
static void kdi_tickwait(clock_t);
static int
kdi_cpu_ready_iter(int (*cb)(int, void *), void *arg)
{
int rc, i;
for (rc = 0, i = 0; i < NCPU; i++) {
if (CPU_IN_SET(cpu_ready_set, i))
rc += cb(i, arg);
}
return (rc);
}
/*
* Sends a cross-call to a specified processor. The caller assumes
* responsibility for repetition of cross-calls, as appropriate (MARSA for
* debugging).
*/
static int
kdi_xc_one(int cpuid, void (*func)(uintptr_t, uintptr_t), uintptr_t arg1,
uintptr_t arg2)
{
uint64_t idsr;
uint64_t endtick, tick;
init_mondo_nocheck((xcfunc_t *)func, arg1, arg2);
shipit(cpuid, 0);
/* Spin for at most 1 second for checking */
endtick = gettick() + (uint64_t)sys_tick_freq;
idsr = getidsr();
if (idsr & IDSR_BUSY) {
do {
idsr = getidsr();
tick = gettick();
if (tick > endtick) {
return (KDI_XC_RES_BUSY);
}
} while (idsr & IDSR_BUSY);
}
kdi_tickwait(20000);
if (idsr & IDSR_NACK)
return (KDI_XC_RES_NACK);
else
return (KDI_XC_RES_OK);
}
static void
kdi_tickwait(clock_t nticks)
{
clock_t endtick = gettick() + nticks;
while (gettick() < endtick)
;
}
static void
kdi_cpu_init(int dcache_size, int dcache_linesize, int icache_size,
int icache_linesize)
{
kdi_dcache_size = dcache_size;
kdi_dcache_linesize = dcache_linesize;
kdi_icache_size = icache_size;
kdi_icache_linesize = icache_linesize;
}
/* used directly by kdi_read/write_phys */
void
kdi_flush_caches(void)
{
kdi_flush_idcache(kdi_dcache_size, kdi_dcache_linesize,
kdi_icache_size, kdi_icache_linesize);
}
void
cpu_kdi_init(kdi_t *kdi)
{
kdi->kdi_flush_caches = kdi_flush_caches;
kdi->mkdi_cpu_init = kdi_cpu_init;
kdi->mkdi_cpu_ready_iter = kdi_cpu_ready_iter;
kdi->mkdi_xc_one = kdi_xc_one;
kdi->mkdi_tickwait = kdi_tickwait;
kdi->mkdi_get_stick = kdi_get_stick;
}
|