xref: /kvm-unit-tests/lib/powerpc/processor.c (revision 16bff5dbf92897f7ea756b5bda2bb79a5b6f28ce)
1 /*
2  * processor control and status function
3  *
4  * This code is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU Library General Public License version 2.
6  */
7 
8 #include <libcflat.h>
9 #include <asm/processor.h>
10 #include <asm/ptrace.h>
11 #include <asm/setup.h>
12 #include <asm/barrier.h>
13 #include <asm/hcall.h>
14 #include <asm/handlers.h>
15 
16 static struct {
17 	void (*func)(struct pt_regs *, void *data);
18 	void *data;
19 } handlers[16];
20 
21 void handle_exception(int trap, void (*func)(struct pt_regs *, void *),
22 		      void * data)
23 {
24 	assert(!(trap & ~0xf00));
25 
26 	trap >>= 8;
27 
28 	if (func && handlers[trap].func) {
29 		printf("exception handler installed twice %#x\n", trap);
30 		abort();
31 	}
32 	handlers[trap].func = func;
33 	handlers[trap].data = data;
34 }
35 
36 void do_handle_exception(struct pt_regs *regs)
37 {
38 	unsigned char v;
39 
40 	v = regs->trap >> 8;
41 
42 	if (v < 16 && handlers[v].func) {
43 		handlers[v].func(regs, handlers[v].data);
44 		return;
45 	}
46 
47 	printf("unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n", regs->trap, regs->nip, regs->msr);
48 	abort();
49 }
50 
51 void delay(uint64_t cycles)
52 {
53 	uint64_t start = get_tb();
54 
55 	while ((get_tb() - start) < cycles)
56 		cpu_relax();
57 }
58 
59 void udelay(uint64_t us)
60 {
61 	delay((us * tb_hz) / 1000000);
62 }
63 
64 void sleep_tb(uint64_t cycles)
65 {
66 	uint64_t start, end, now;
67 
68 	start = now = get_tb();
69 	end = start + cycles;
70 
71 	while (end > now) {
72 		uint64_t left = end - now;
73 
74 		/* TODO: Could support large decrementer */
75 		if (left > 0x7fffffff)
76 			left = 0x7fffffff;
77 
78 		/* DEC won't fire until H_CEDE is called because EE=0 */
79 		asm volatile ("mtdec %0" : : "r" (left));
80 		handle_exception(0x900, &dec_handler_oneshot, NULL);
81 		/*
82 		 * H_CEDE is called with MSR[EE] clear and enables it as part
83 		 * of the hcall, returning with EE enabled. The dec interrupt
84 		 * is then taken immediately and the handler disables EE.
85 		 *
86 		 * If H_CEDE returned for any other interrupt than dec
87 		 * expiring, that is considered an unhandled interrupt and
88 		 * the test case would be stopped.
89 		 */
90 		if (hcall(H_CEDE) != H_SUCCESS) {
91 			printf("H_CEDE failed\n");
92 			abort();
93 		}
94 		handle_exception(0x900, NULL, NULL);
95 
96 		now = get_tb();
97 	}
98 }
99 
100 void usleep(uint64_t us)
101 {
102 	sleep_tb((us * tb_hz) / 1000000);
103 }
104