xref: /kvm-unit-tests/lib/powerpc/processor.c (revision d4c8e725478d05179b23be44fc61357a92da4912)
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>
16*d4c8e725SNicholas Piggin #include <asm/mmu.h>
17c76b0d0aSNicholas Piggin #include <asm/smp.h>
186842bc34SLaurent Vivier 
196842bc34SLaurent Vivier static struct {
206842bc34SLaurent Vivier 	void (*func)(struct pt_regs *, void *data);
216842bc34SLaurent Vivier 	void *data;
220ec01e27SNicholas Piggin } handlers[128];
236842bc34SLaurent Vivier 
240ec01e27SNicholas Piggin /*
250ec01e27SNicholas Piggin  * Exception handlers span from 0x100 to 0x1000 and can have a granularity
260ec01e27SNicholas Piggin  * of 0x20 bytes in some cases. Indexing spans 0-0x1000 with 0x20 increments
270ec01e27SNicholas Piggin  * resulting in 128 slots.
280ec01e27SNicholas Piggin  */
296842bc34SLaurent Vivier void handle_exception(int trap, void (*func)(struct pt_regs *, void *),
306842bc34SLaurent Vivier 		      void * data)
316842bc34SLaurent Vivier {
320ec01e27SNicholas Piggin 	assert(!(trap & ~0xfe0));
335d571097SNicholas Piggin 
340ec01e27SNicholas Piggin 	trap >>= 5;
356842bc34SLaurent Vivier 
365d571097SNicholas Piggin 	if (func && handlers[trap].func) {
378791cea0SNicholas Piggin 		printf("exception handler installed twice %#x\n", trap << 5);
385d571097SNicholas Piggin 		abort();
395d571097SNicholas Piggin 	}
400ec01e27SNicholas Piggin 
416842bc34SLaurent Vivier 	handlers[trap].func = func;
426842bc34SLaurent Vivier 	handlers[trap].data = data;
436842bc34SLaurent Vivier }
446842bc34SLaurent Vivier 
456842bc34SLaurent Vivier void do_handle_exception(struct pt_regs *regs)
466842bc34SLaurent Vivier {
476842bc34SLaurent Vivier 	unsigned char v;
486842bc34SLaurent Vivier 
49c76b0d0aSNicholas Piggin 	__current_cpu = (struct cpu *)mfspr(SPR_SPRG0);
50c76b0d0aSNicholas Piggin 
51*d4c8e725SNicholas Piggin 	/*
52*d4c8e725SNicholas Piggin 	 * We run with AIL=0, so interrupts taken with MMU disabled.
53*d4c8e725SNicholas Piggin 	 * Enable here.
54*d4c8e725SNicholas Piggin 	 */
55*d4c8e725SNicholas Piggin 	assert(!(mfmsr() & (MSR_IR|MSR_DR)));
56*d4c8e725SNicholas Piggin 	if (mmu_enabled())
57*d4c8e725SNicholas Piggin 		mtmsr(mfmsr() | (MSR_IR|MSR_DR));
58*d4c8e725SNicholas Piggin 
590ec01e27SNicholas Piggin 	v = regs->trap >> 5;
606842bc34SLaurent Vivier 
610ec01e27SNicholas Piggin 	if (v < 128 && handlers[v].func) {
626842bc34SLaurent Vivier 		handlers[v].func(regs, handlers[v].data);
636842bc34SLaurent Vivier 		return;
646842bc34SLaurent Vivier 	}
656842bc34SLaurent Vivier 
66c76b0d0aSNicholas Piggin 	printf("Unhandled CPU%d exception %#lx at NIA:0x%016lx MSR:0x%016lx\n",
67c76b0d0aSNicholas Piggin 		smp_processor_id(), regs->trap, regs->nip, regs->msr);
68ac6e1abfSNicholas Piggin 	dump_frame_stack((void *)regs->nip, (void *)regs->gpr[1]);
696842bc34SLaurent Vivier 	abort();
706842bc34SLaurent Vivier }
71f4d8d939SSuraj Jitindar Singh 
728b10d4faSNicholas Piggin uint64_t get_clock_us(void)
738b10d4faSNicholas Piggin {
748b10d4faSNicholas Piggin 	return get_tb() * 1000000 / tb_hz;
758b10d4faSNicholas Piggin }
768b10d4faSNicholas Piggin 
778b10d4faSNicholas Piggin uint64_t get_clock_ms(void)
788b10d4faSNicholas Piggin {
798b10d4faSNicholas Piggin 	return get_tb() * 1000 / tb_hz;
808b10d4faSNicholas Piggin }
818b10d4faSNicholas Piggin 
82f4d8d939SSuraj Jitindar Singh void delay(uint64_t cycles)
83f4d8d939SSuraj Jitindar Singh {
84f4d8d939SSuraj Jitindar Singh 	uint64_t start = get_tb();
85f4d8d939SSuraj Jitindar Singh 
86f4d8d939SSuraj Jitindar Singh 	while ((get_tb() - start) < cycles)
87f4d8d939SSuraj Jitindar Singh 		cpu_relax();
88f4d8d939SSuraj Jitindar Singh }
89f4d8d939SSuraj Jitindar Singh 
90f4d8d939SSuraj Jitindar Singh void udelay(uint64_t us)
91f4d8d939SSuraj Jitindar Singh {
92f4d8d939SSuraj Jitindar Singh 	delay((us * tb_hz) / 1000000);
93f4d8d939SSuraj Jitindar Singh }
94ba33a96fSNicholas Piggin 
95ba33a96fSNicholas Piggin void sleep_tb(uint64_t cycles)
96ba33a96fSNicholas Piggin {
97ba33a96fSNicholas Piggin 	uint64_t start, end, now;
98ba33a96fSNicholas Piggin 
99610c5a9cSNicholas Piggin 	if (!machine_is_pseries()) {
100610c5a9cSNicholas Piggin 		/*
101610c5a9cSNicholas Piggin 		 * P9/10 Could use 'stop' to sleep here which would be
102610c5a9cSNicholas Piggin 		 * interesting.  stop with ESL=0 should be simple enough, ESL=1
103610c5a9cSNicholas Piggin 		 * would require SRESET based wakeup which is more involved.
104610c5a9cSNicholas Piggin 		 */
105610c5a9cSNicholas Piggin 		delay(cycles);
106610c5a9cSNicholas Piggin 		return;
107610c5a9cSNicholas Piggin 	}
108610c5a9cSNicholas Piggin 
109ba33a96fSNicholas Piggin 	start = now = get_tb();
110ba33a96fSNicholas Piggin 	end = start + cycles;
111ba33a96fSNicholas Piggin 
112ba33a96fSNicholas Piggin 	while (end > now) {
113ba33a96fSNicholas Piggin 		uint64_t left = end - now;
114ba33a96fSNicholas Piggin 
115ba33a96fSNicholas Piggin 		/* TODO: Could support large decrementer */
116ba33a96fSNicholas Piggin 		if (left > 0x7fffffff)
117ba33a96fSNicholas Piggin 			left = 0x7fffffff;
118ba33a96fSNicholas Piggin 
119ba33a96fSNicholas Piggin 		/* DEC won't fire until H_CEDE is called because EE=0 */
120ba33a96fSNicholas Piggin 		asm volatile ("mtdec %0" : : "r" (left));
121ba33a96fSNicholas Piggin 		handle_exception(0x900, &dec_handler_oneshot, NULL);
122ba33a96fSNicholas Piggin 		/*
123ba33a96fSNicholas Piggin 		 * H_CEDE is called with MSR[EE] clear and enables it as part
124ba33a96fSNicholas Piggin 		 * of the hcall, returning with EE enabled. The dec interrupt
125ba33a96fSNicholas Piggin 		 * is then taken immediately and the handler disables EE.
126ba33a96fSNicholas Piggin 		 *
127ba33a96fSNicholas Piggin 		 * If H_CEDE returned for any other interrupt than dec
128ba33a96fSNicholas Piggin 		 * expiring, that is considered an unhandled interrupt and
129ba33a96fSNicholas Piggin 		 * the test case would be stopped.
130ba33a96fSNicholas Piggin 		 */
131ba33a96fSNicholas Piggin 		if (hcall(H_CEDE) != H_SUCCESS) {
132ba33a96fSNicholas Piggin 			printf("H_CEDE failed\n");
133ba33a96fSNicholas Piggin 			abort();
134ba33a96fSNicholas Piggin 		}
135ba33a96fSNicholas Piggin 		handle_exception(0x900, NULL, NULL);
136ba33a96fSNicholas Piggin 
137ba33a96fSNicholas Piggin 		now = get_tb();
138ba33a96fSNicholas Piggin 	}
139ba33a96fSNicholas Piggin }
140ba33a96fSNicholas Piggin 
141ba33a96fSNicholas Piggin void usleep(uint64_t us)
142ba33a96fSNicholas Piggin {
143ba33a96fSNicholas Piggin 	sleep_tb((us * tb_hz) / 1000000);
144ba33a96fSNicholas Piggin }
145610c5a9cSNicholas Piggin 
146610c5a9cSNicholas Piggin static void rfid_msr(uint64_t msr)
147610c5a9cSNicholas Piggin {
148610c5a9cSNicholas Piggin 	uint64_t tmp;
149610c5a9cSNicholas Piggin 
150610c5a9cSNicholas Piggin 	asm volatile(
151610c5a9cSNicholas Piggin 		"mtsrr1	%1		\n\
152610c5a9cSNicholas Piggin 		 bl	0f		\n\
153610c5a9cSNicholas Piggin 		 0:			\n\
154610c5a9cSNicholas Piggin 		 mflr	%0		\n\
155610c5a9cSNicholas Piggin 		 addi	%0,%0,1f-0b	\n\
156610c5a9cSNicholas Piggin 		 mtsrr0	%0		\n\
157610c5a9cSNicholas Piggin 		 rfid			\n\
158610c5a9cSNicholas Piggin 		 1:			\n"
159610c5a9cSNicholas Piggin 		: "=r"(tmp) : "r"(msr) : "lr");
160610c5a9cSNicholas Piggin }
161610c5a9cSNicholas Piggin 
162610c5a9cSNicholas Piggin void enable_mcheck(void)
163610c5a9cSNicholas Piggin {
164610c5a9cSNicholas Piggin 	/* This is a no-op on pseries */
165610c5a9cSNicholas Piggin 	rfid_msr(mfmsr() | MSR_ME);
166610c5a9cSNicholas Piggin }
167610c5a9cSNicholas Piggin 
168610c5a9cSNicholas Piggin void disable_mcheck(void)
169610c5a9cSNicholas Piggin {
170610c5a9cSNicholas Piggin 	rfid_msr(mfmsr() & ~MSR_ME);
171610c5a9cSNicholas Piggin }
172