1 /* $OpenBSD: mips64_machdep.c,v 1.43 2023/08/23 01:55:47 cheloha Exp $ */
2
3 /*
4 * Copyright (c) 2009, 2010, 2012 Miodrag Vallat.
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 /*
19 * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions
23 * are met:
24 * 1. Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
26 * 2. Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in the
28 * documentation and/or other materials provided with the distribution.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
31 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
34 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
41 *
42 */
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/clockintr.h>
48 #include <sys/proc.h>
49 #include <sys/exec.h>
50 #include <sys/sysctl.h>
51 #include <sys/timetc.h>
52
53 #include <machine/autoconf.h>
54 #include <machine/cpu.h>
55 #include <mips64/cache.h>
56 #include <mips64/mips_cpu.h>
57 #include <mips64/mips_opcode.h>
58
59 #include <uvm/uvm_extern.h>
60
61 #include <dev/clock_subr.h>
62
63 /*
64 * Build a tlb trampoline
65 */
66 void
build_trampoline(vaddr_t addr,vaddr_t dest)67 build_trampoline(vaddr_t addr, vaddr_t dest)
68 {
69 const uint32_t insns[] = {
70 0x3c1a0000, /* lui k0, imm16 */
71 0x675a0000, /* daddiu k0, k0, imm16 */
72 0x001ad438, /* dsll k0, k0, 0x10 */
73 0x675a0000, /* daddiu k0, k0, imm16 */
74 0x001ad438, /* dsll k0, k0, 0x10 */
75 0x675a0000, /* daddiu k0, k0, imm16 */
76 0x03400008, /* jr k0 */
77 0x00000000 /* nop */
78 };
79 uint32_t *dst = (uint32_t *)addr;
80 const uint32_t *src = insns;
81 uint32_t a, b, c, d;
82
83 /*
84 * Decompose the handler address in the four components which,
85 * added with sign extension, will produce the correct address.
86 */
87 d = dest & 0xffff;
88 dest >>= 16;
89 if (d & 0x8000)
90 dest++;
91 c = dest & 0xffff;
92 dest >>= 16;
93 if (c & 0x8000)
94 dest++;
95 b = dest & 0xffff;
96 dest >>= 16;
97 if (b & 0x8000)
98 dest++;
99 a = dest & 0xffff;
100
101 /*
102 * Build the trampoline, skipping noop computations.
103 */
104 *dst++ = *src++ | a;
105 if (b != 0)
106 *dst++ = *src++ | b;
107 else
108 src++;
109 *dst++ = *src++;
110 if (c != 0)
111 *dst++ = *src++ | c;
112 else
113 src++;
114 *dst++ = *src++;
115 if (d != 0)
116 *dst++ = *src++ | d;
117 else
118 src++;
119 *dst++ = *src++;
120 *dst++ = *src++;
121
122 /*
123 * Note that we keep the delay slot instruction a nop, instead
124 * of branching to the second instruction of the handler and
125 * having its first instruction in the delay slot, so that the
126 * tlb handler is free to use k0 immediately.
127 */
128 }
129
130 /*
131 * Prototype status registers value for userland processes.
132 */
133 register_t protosr = SR_FR_32 | SR_XX | SR_UX | SR_KSU_USER | SR_EXL |
134 SR_KX | SR_INT_ENAB;
135
136 /*
137 * Set registers on exec for native exec format. For o64/64.
138 */
139 void
setregs(struct proc * p,struct exec_package * pack,u_long stack,struct ps_strings * arginfo)140 setregs(struct proc *p, struct exec_package *pack, u_long stack,
141 struct ps_strings *arginfo)
142 {
143 struct cpu_info *ci = curcpu();
144 struct trapframe *tf = p->p_md.md_regs;
145
146 memset(tf, 0, sizeof *tf);
147 tf->sp = stack;
148 tf->pc = pack->ep_entry & ~3;
149 tf->t9 = pack->ep_entry & ~3; /* abicall req */
150 tf->sr = protosr | (idle_mask & SR_INT_MASK);
151
152 if (CPU_HAS_FPU(ci))
153 p->p_md.md_flags &= ~MDP_FPUSED;
154 if (ci->ci_fpuproc == p)
155 ci->ci_fpuproc = NULL;
156 }
157
158 int
exec_md_map(struct proc * p,struct exec_package * pack)159 exec_md_map(struct proc *p, struct exec_package *pack)
160 {
161 #ifdef FPUEMUL
162 struct cpu_info *ci = curcpu();
163 vaddr_t va;
164 int rc;
165
166 if (CPU_HAS_FPU(ci))
167 return 0;
168
169 /*
170 * If we are running with FPU instruction emulation, we need
171 * to allocate a special page in the process' address space,
172 * in order to be able to emulate delay slot instructions of
173 * successful conditional branches.
174 */
175
176 va = 0;
177 rc = uvm_map(&p->p_vmspace->vm_map, &va, PAGE_SIZE, NULL,
178 UVM_UNKNOWN_OFFSET, 0,
179 UVM_MAPFLAG(PROT_NONE, PROT_MASK, MAP_INHERIT_COPY,
180 MADV_NORMAL, UVM_FLAG_COPYONW));
181 if (rc != 0)
182 return rc;
183 #ifdef DEBUG
184 printf("%s: p %p fppgva %p\n", __func__, p, (void *)va);
185 #endif
186 p->p_md.md_fppgva = va;
187 #endif
188
189 return 0;
190 }
191
192 /*
193 * Initial TLB setup for the current processor.
194 */
195 void
tlb_init(unsigned int tlbsize)196 tlb_init(unsigned int tlbsize)
197 {
198 tlb_set_page_mask(TLB_PAGE_MASK);
199 tlb_set_wired(0);
200 tlb_flush(tlbsize);
201 #if UPAGES > 1
202 tlb_set_wired(UPAGES / 2);
203 #endif
204 }
205
206 /*
207 * Handle an ASID wrap.
208 */
209 void
tlb_asid_wrap(struct cpu_info * ci)210 tlb_asid_wrap(struct cpu_info *ci)
211 {
212 tlb_flush(ci->ci_hw.tlbsize);
213 #if defined(CPU_OCTEON)
214 Mips_InvalidateICache(ci, 0, ci->ci_l1inst.size);
215 #endif
216 }
217
218 /*
219 * Mips machine independent clock routines.
220 */
221
222 void (*md_initclock)(void);
223 void (*md_startclock)(struct cpu_info *);
224 void (*md_triggerclock)(void);
225
226 extern todr_chip_handle_t todr_handle;
227
228 /*
229 * Wait "n" microseconds.
230 */
231 void
delay(int n)232 delay(int n)
233 {
234 int dly;
235 int p, c;
236 struct cpu_info *ci = curcpu();
237 uint32_t delayconst;
238
239 delayconst = ci->ci_delayconst;
240 if (delayconst == 0)
241 delayconst = bootcpu_hwinfo.clock / CP0_CYCLE_DIVIDER;
242 p = cp0_get_count();
243 dly = (delayconst / 1000000) * n;
244 while (dly > 0) {
245 c = cp0_get_count();
246 dly -= c - p;
247 p = c;
248 }
249 }
250
251 u_int cp0_get_timecount(struct timecounter *);
252
253 struct timecounter cp0_timecounter = {
254 .tc_get_timecount = cp0_get_timecount,
255 .tc_counter_mask = 0xffffffff,
256 .tc_frequency = 0,
257 .tc_name = "CP0",
258 .tc_quality = 0,
259 .tc_priv = NULL,
260 .tc_user = 0,
261 };
262
263 u_int
cp0_get_timecount(struct timecounter * tc)264 cp0_get_timecount(struct timecounter *tc)
265 {
266 return (cp0_get_count());
267 }
268
269 /*
270 * Calibrate cpu internal counter against the TOD clock if available.
271 */
272 void
cp0_calibrate(struct cpu_info * ci)273 cp0_calibrate(struct cpu_info *ci)
274 {
275 struct timeval rtctime;
276 u_int first_cp0, second_cp0, cycles_per_sec;
277 int first_sec;
278
279 if (todr_handle == NULL)
280 return;
281
282 if (todr_gettime(todr_handle, &rtctime) != 0)
283 return;
284 first_sec = rtctime.tv_sec;
285
286 /* Let the clock tick one second. */
287 do {
288 first_cp0 = cp0_get_count();
289 if (todr_gettime(todr_handle, &rtctime) != 0)
290 return;
291 } while (rtctime.tv_sec == first_sec);
292 first_sec = rtctime.tv_sec;
293 /* Let the clock tick one more second. */
294 do {
295 second_cp0 = cp0_get_count();
296 if (todr_gettime(todr_handle, &rtctime) != 0)
297 return;
298 } while (rtctime.tv_sec == first_sec);
299
300 cycles_per_sec = second_cp0 - first_cp0;
301 ci->ci_hw.clock = cycles_per_sec * CP0_CYCLE_DIVIDER;
302 ci->ci_delayconst = cycles_per_sec;
303 }
304
305 /*
306 * Prepare to start the clock interrupt dispatch cycle.
307 */
308 void
cpu_initclocks(void)309 cpu_initclocks(void)
310 {
311 struct cpu_info *ci = curcpu();
312
313 tick = 1000000 / hz; /* number of micro-seconds between interrupts */
314 tick_nsec = 1000000000 / hz;
315
316 cp0_calibrate(ci);
317
318 #ifndef MULTIPROCESSOR
319 cpu_has_synced_cp0_count = 1;
320 #endif
321 if (cpu_setperf == NULL && cpu_has_synced_cp0_count) {
322 cp0_timecounter.tc_frequency =
323 (uint64_t)ci->ci_hw.clock / CP0_CYCLE_DIVIDER;
324 tc_init(&cp0_timecounter);
325 }
326
327 if (md_initclock != NULL)
328 (*md_initclock)();
329 }
330
331 void
cpu_startclock(void)332 cpu_startclock(void)
333 {
334 #ifdef DIAGNOSTIC
335 if (md_startclock == NULL)
336 panic("no clock");
337 #endif
338 (*md_startclock)(curcpu());
339 }
340
341 void
setstatclockrate(int newhz)342 setstatclockrate(int newhz)
343 {
344 }
345
346 /*
347 * Decode instruction and figure out type.
348 */
349 int
classify_insn(uint32_t insn)350 classify_insn(uint32_t insn)
351 {
352 InstFmt inst;
353
354 inst.word = insn;
355 switch (inst.JType.op) {
356 case OP_SPECIAL:
357 switch (inst.RType.func) {
358 case OP_JR:
359 return INSNCLASS_BRANCH;
360 case OP_JALR:
361 return INSNCLASS_CALL;
362 }
363 break;
364
365 case OP_BCOND:
366 switch (inst.IType.rt) {
367 case OP_BLTZ:
368 case OP_BLTZL:
369 case OP_BGEZ:
370 case OP_BGEZL:
371 return INSNCLASS_BRANCH;
372 case OP_BLTZAL:
373 case OP_BLTZALL:
374 case OP_BGEZAL:
375 case OP_BGEZALL:
376 return INSNCLASS_CALL;
377 }
378 break;
379
380 case OP_JAL:
381 return INSNCLASS_CALL;
382
383 case OP_J:
384 case OP_BEQ:
385 case OP_BEQL:
386 case OP_BNE:
387 case OP_BNEL:
388 case OP_BLEZ:
389 case OP_BLEZL:
390 case OP_BGTZ:
391 case OP_BGTZL:
392 return INSNCLASS_BRANCH;
393
394 case OP_COP1:
395 switch (inst.RType.rs) {
396 case OP_BC:
397 return INSNCLASS_BRANCH;
398 }
399 break;
400 }
401
402 return INSNCLASS_NEUTRAL;
403 }
404
405 /*
406 * Smash the startup code. There is no way to really unmap it
407 * because the kernel runs in the kseg0 or xkphys space.
408 */
409 void
unmap_startup(void)410 unmap_startup(void)
411 {
412 extern uint32_t kernel_text[], endboot[];
413 uint32_t *word = kernel_text;
414
415 while (word < endboot)
416 *word++ = 0x00000034u; /* TEQ zero, zero */
417 }
418