xref: /kvm-unit-tests/lib/powerpc/processor.c (revision ac6e1abfedf922c87abac7c2aba03ed9c25b6cc8)
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>
108b10d4faSNicholas Piggin #include <asm/time.h>
116842bc34SLaurent Vivier #include <asm/ptrace.h>
12f4d8d939SSuraj Jitindar Singh #include <asm/setup.h>
13f4d8d939SSuraj Jitindar Singh #include <asm/barrier.h>
14ba33a96fSNicholas Piggin #include <asm/hcall.h>
15ba33a96fSNicholas Piggin #include <asm/handlers.h>
166842bc34SLaurent Vivier 
176842bc34SLaurent Vivier static struct {
186842bc34SLaurent Vivier 	void (*func)(struct pt_regs *, void *data);
196842bc34SLaurent Vivier 	void *data;
200ec01e27SNicholas Piggin } handlers[128];
216842bc34SLaurent Vivier 
220ec01e27SNicholas Piggin /*
230ec01e27SNicholas Piggin  * Exception handlers span from 0x100 to 0x1000 and can have a granularity
240ec01e27SNicholas Piggin  * of 0x20 bytes in some cases. Indexing spans 0-0x1000 with 0x20 increments
250ec01e27SNicholas Piggin  * resulting in 128 slots.
260ec01e27SNicholas Piggin  */
276842bc34SLaurent Vivier void handle_exception(int trap, void (*func)(struct pt_regs *, void *),
286842bc34SLaurent Vivier 		      void * data)
296842bc34SLaurent Vivier {
300ec01e27SNicholas Piggin 	assert(!(trap & ~0xfe0));
315d571097SNicholas Piggin 
320ec01e27SNicholas Piggin 	trap >>= 5;
336842bc34SLaurent Vivier 
345d571097SNicholas Piggin 	if (func && handlers[trap].func) {
358791cea0SNicholas Piggin 		printf("exception handler installed twice %#x\n", trap << 5);
365d571097SNicholas Piggin 		abort();
375d571097SNicholas Piggin 	}
380ec01e27SNicholas Piggin 
396842bc34SLaurent Vivier 	handlers[trap].func = func;
406842bc34SLaurent Vivier 	handlers[trap].data = data;
416842bc34SLaurent Vivier }
426842bc34SLaurent Vivier 
436842bc34SLaurent Vivier void do_handle_exception(struct pt_regs *regs)
446842bc34SLaurent Vivier {
456842bc34SLaurent Vivier 	unsigned char v;
466842bc34SLaurent Vivier 
470ec01e27SNicholas Piggin 	v = regs->trap >> 5;
486842bc34SLaurent Vivier 
490ec01e27SNicholas Piggin 	if (v < 128 && handlers[v].func) {
506842bc34SLaurent Vivier 		handlers[v].func(regs, handlers[v].data);
516842bc34SLaurent Vivier 		return;
526842bc34SLaurent Vivier 	}
536842bc34SLaurent Vivier 
54*ac6e1abfSNicholas Piggin 	printf("Unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n",
55*ac6e1abfSNicholas Piggin 			regs->trap, regs->nip, regs->msr);
56*ac6e1abfSNicholas Piggin 	dump_frame_stack((void *)regs->nip, (void *)regs->gpr[1]);
576842bc34SLaurent Vivier 	abort();
586842bc34SLaurent Vivier }
59f4d8d939SSuraj Jitindar Singh 
608b10d4faSNicholas Piggin uint64_t get_clock_us(void)
618b10d4faSNicholas Piggin {
628b10d4faSNicholas Piggin 	return get_tb() * 1000000 / tb_hz;
638b10d4faSNicholas Piggin }
648b10d4faSNicholas Piggin 
658b10d4faSNicholas Piggin uint64_t get_clock_ms(void)
668b10d4faSNicholas Piggin {
678b10d4faSNicholas Piggin 	return get_tb() * 1000 / tb_hz;
688b10d4faSNicholas Piggin }
698b10d4faSNicholas Piggin 
70f4d8d939SSuraj Jitindar Singh void delay(uint64_t cycles)
71f4d8d939SSuraj Jitindar Singh {
72f4d8d939SSuraj Jitindar Singh 	uint64_t start = get_tb();
73f4d8d939SSuraj Jitindar Singh 
74f4d8d939SSuraj Jitindar Singh 	while ((get_tb() - start) < cycles)
75f4d8d939SSuraj Jitindar Singh 		cpu_relax();
76f4d8d939SSuraj Jitindar Singh }
77f4d8d939SSuraj Jitindar Singh 
78f4d8d939SSuraj Jitindar Singh void udelay(uint64_t us)
79f4d8d939SSuraj Jitindar Singh {
80f4d8d939SSuraj Jitindar Singh 	delay((us * tb_hz) / 1000000);
81f4d8d939SSuraj Jitindar Singh }
82ba33a96fSNicholas Piggin 
83ba33a96fSNicholas Piggin void sleep_tb(uint64_t cycles)
84ba33a96fSNicholas Piggin {
85ba33a96fSNicholas Piggin 	uint64_t start, end, now;
86ba33a96fSNicholas Piggin 
87ba33a96fSNicholas Piggin 	start = now = get_tb();
88ba33a96fSNicholas Piggin 	end = start + cycles;
89ba33a96fSNicholas Piggin 
90ba33a96fSNicholas Piggin 	while (end > now) {
91ba33a96fSNicholas Piggin 		uint64_t left = end - now;
92ba33a96fSNicholas Piggin 
93ba33a96fSNicholas Piggin 		/* TODO: Could support large decrementer */
94ba33a96fSNicholas Piggin 		if (left > 0x7fffffff)
95ba33a96fSNicholas Piggin 			left = 0x7fffffff;
96ba33a96fSNicholas Piggin 
97ba33a96fSNicholas Piggin 		/* DEC won't fire until H_CEDE is called because EE=0 */
98ba33a96fSNicholas Piggin 		asm volatile ("mtdec %0" : : "r" (left));
99ba33a96fSNicholas Piggin 		handle_exception(0x900, &dec_handler_oneshot, NULL);
100ba33a96fSNicholas Piggin 		/*
101ba33a96fSNicholas Piggin 		 * H_CEDE is called with MSR[EE] clear and enables it as part
102ba33a96fSNicholas Piggin 		 * of the hcall, returning with EE enabled. The dec interrupt
103ba33a96fSNicholas Piggin 		 * is then taken immediately and the handler disables EE.
104ba33a96fSNicholas Piggin 		 *
105ba33a96fSNicholas Piggin 		 * If H_CEDE returned for any other interrupt than dec
106ba33a96fSNicholas Piggin 		 * expiring, that is considered an unhandled interrupt and
107ba33a96fSNicholas Piggin 		 * the test case would be stopped.
108ba33a96fSNicholas Piggin 		 */
109ba33a96fSNicholas Piggin 		if (hcall(H_CEDE) != H_SUCCESS) {
110ba33a96fSNicholas Piggin 			printf("H_CEDE failed\n");
111ba33a96fSNicholas Piggin 			abort();
112ba33a96fSNicholas Piggin 		}
113ba33a96fSNicholas Piggin 		handle_exception(0x900, NULL, NULL);
114ba33a96fSNicholas Piggin 
115ba33a96fSNicholas Piggin 		now = get_tb();
116ba33a96fSNicholas Piggin 	}
117ba33a96fSNicholas Piggin }
118ba33a96fSNicholas Piggin 
119ba33a96fSNicholas Piggin void usleep(uint64_t us)
120ba33a96fSNicholas Piggin {
121ba33a96fSNicholas Piggin 	sleep_tb((us * tb_hz) / 1000000);
122ba33a96fSNicholas Piggin }
123