xref: /kvm-unit-tests/lib/powerpc/processor.c (revision ba33a96fdc5274e047d96919ae09ee3c97d4fd4e)
16842bc34SLaurent Vivier /*
26842bc34SLaurent Vivier  * processor control and status function
3b1a6fd7dSThomas Huth  *
4b1a6fd7dSThomas Huth  * This code is free software; you can redistribute it and/or modify it
5b1a6fd7dSThomas Huth  * under the terms of the GNU Library General Public License version 2.
66842bc34SLaurent Vivier  */
76842bc34SLaurent Vivier 
86842bc34SLaurent Vivier #include <libcflat.h>
96842bc34SLaurent Vivier #include <asm/processor.h>
106842bc34SLaurent Vivier #include <asm/ptrace.h>
11f4d8d939SSuraj Jitindar Singh #include <asm/setup.h>
12f4d8d939SSuraj Jitindar Singh #include <asm/barrier.h>
13*ba33a96fSNicholas Piggin #include <asm/hcall.h>
14*ba33a96fSNicholas Piggin #include <asm/handlers.h>
156842bc34SLaurent Vivier 
166842bc34SLaurent Vivier static struct {
176842bc34SLaurent Vivier 	void (*func)(struct pt_regs *, void *data);
186842bc34SLaurent Vivier 	void *data;
196842bc34SLaurent Vivier } handlers[16];
206842bc34SLaurent Vivier 
216842bc34SLaurent Vivier void handle_exception(int trap, void (*func)(struct pt_regs *, void *),
226842bc34SLaurent Vivier 		      void * data)
236842bc34SLaurent Vivier {
245d571097SNicholas Piggin 	assert(!(trap & ~0xf00));
255d571097SNicholas Piggin 
266842bc34SLaurent Vivier 	trap >>= 8;
276842bc34SLaurent Vivier 
285d571097SNicholas Piggin 	if (func && handlers[trap].func) {
295d571097SNicholas Piggin 		printf("exception handler installed twice %#x\n", trap);
305d571097SNicholas Piggin 		abort();
315d571097SNicholas Piggin 	}
326842bc34SLaurent Vivier 	handlers[trap].func = func;
336842bc34SLaurent Vivier 	handlers[trap].data = data;
346842bc34SLaurent Vivier }
356842bc34SLaurent Vivier 
366842bc34SLaurent Vivier void do_handle_exception(struct pt_regs *regs)
376842bc34SLaurent Vivier {
386842bc34SLaurent Vivier 	unsigned char v;
396842bc34SLaurent Vivier 
406842bc34SLaurent Vivier 	v = regs->trap >> 8;
416842bc34SLaurent Vivier 
426842bc34SLaurent Vivier 	if (v < 16 && handlers[v].func) {
436842bc34SLaurent Vivier 		handlers[v].func(regs, handlers[v].data);
446842bc34SLaurent Vivier 		return;
456842bc34SLaurent Vivier 	}
466842bc34SLaurent Vivier 
478e458b76SNicholas Piggin 	printf("unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n", regs->trap, regs->nip, regs->msr);
486842bc34SLaurent Vivier 	abort();
496842bc34SLaurent Vivier }
50f4d8d939SSuraj Jitindar Singh 
51f4d8d939SSuraj Jitindar Singh void delay(uint64_t cycles)
52f4d8d939SSuraj Jitindar Singh {
53f4d8d939SSuraj Jitindar Singh 	uint64_t start = get_tb();
54f4d8d939SSuraj Jitindar Singh 
55f4d8d939SSuraj Jitindar Singh 	while ((get_tb() - start) < cycles)
56f4d8d939SSuraj Jitindar Singh 		cpu_relax();
57f4d8d939SSuraj Jitindar Singh }
58f4d8d939SSuraj Jitindar Singh 
59f4d8d939SSuraj Jitindar Singh void udelay(uint64_t us)
60f4d8d939SSuraj Jitindar Singh {
61f4d8d939SSuraj Jitindar Singh 	delay((us * tb_hz) / 1000000);
62f4d8d939SSuraj Jitindar Singh }
63*ba33a96fSNicholas Piggin 
64*ba33a96fSNicholas Piggin void sleep_tb(uint64_t cycles)
65*ba33a96fSNicholas Piggin {
66*ba33a96fSNicholas Piggin 	uint64_t start, end, now;
67*ba33a96fSNicholas Piggin 
68*ba33a96fSNicholas Piggin 	start = now = get_tb();
69*ba33a96fSNicholas Piggin 	end = start + cycles;
70*ba33a96fSNicholas Piggin 
71*ba33a96fSNicholas Piggin 	while (end > now) {
72*ba33a96fSNicholas Piggin 		uint64_t left = end - now;
73*ba33a96fSNicholas Piggin 
74*ba33a96fSNicholas Piggin 		/* TODO: Could support large decrementer */
75*ba33a96fSNicholas Piggin 		if (left > 0x7fffffff)
76*ba33a96fSNicholas Piggin 			left = 0x7fffffff;
77*ba33a96fSNicholas Piggin 
78*ba33a96fSNicholas Piggin 		/* DEC won't fire until H_CEDE is called because EE=0 */
79*ba33a96fSNicholas Piggin 		asm volatile ("mtdec %0" : : "r" (left));
80*ba33a96fSNicholas Piggin 		handle_exception(0x900, &dec_handler_oneshot, NULL);
81*ba33a96fSNicholas Piggin 		/*
82*ba33a96fSNicholas Piggin 		 * H_CEDE is called with MSR[EE] clear and enables it as part
83*ba33a96fSNicholas Piggin 		 * of the hcall, returning with EE enabled. The dec interrupt
84*ba33a96fSNicholas Piggin 		 * is then taken immediately and the handler disables EE.
85*ba33a96fSNicholas Piggin 		 *
86*ba33a96fSNicholas Piggin 		 * If H_CEDE returned for any other interrupt than dec
87*ba33a96fSNicholas Piggin 		 * expiring, that is considered an unhandled interrupt and
88*ba33a96fSNicholas Piggin 		 * the test case would be stopped.
89*ba33a96fSNicholas Piggin 		 */
90*ba33a96fSNicholas Piggin 		if (hcall(H_CEDE) != H_SUCCESS) {
91*ba33a96fSNicholas Piggin 			printf("H_CEDE failed\n");
92*ba33a96fSNicholas Piggin 			abort();
93*ba33a96fSNicholas Piggin 		}
94*ba33a96fSNicholas Piggin 		handle_exception(0x900, NULL, NULL);
95*ba33a96fSNicholas Piggin 
96*ba33a96fSNicholas Piggin 		now = get_tb();
97*ba33a96fSNicholas Piggin 	}
98*ba33a96fSNicholas Piggin }
99*ba33a96fSNicholas Piggin 
100*ba33a96fSNicholas Piggin void usleep(uint64_t us)
101*ba33a96fSNicholas Piggin {
102*ba33a96fSNicholas Piggin 	sleep_tb((us * tb_hz) / 1000000);
103*ba33a96fSNicholas Piggin }
104