tests: Add a test for privileged instruction interrupts
This adds a test that tries to execute various privileged instructions with MSR[PR] = 1. This also incidentally tests some of the MSR bit manipulations. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>pull/166/head
							parent
							
								
									041d6bef60
								
							
						
					
					
						commit
						10f4be4309
					
				| @ -0,0 +1,3 @@ | |||||||
|  | TEST=privileged | ||||||
|  |  | ||||||
|  | include ../Makefile.test | ||||||
| @ -0,0 +1,91 @@ | |||||||
|  | /* Copyright 2013-2014 IBM Corp. | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  * 	http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||||
|  |  * implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #define STACK_TOP 0x8000 | ||||||
|  |  | ||||||
|  | /* Load an immediate 64-bit value into a register */ | ||||||
|  | #define LOAD_IMM64(r, e)			\ | ||||||
|  | 	lis     r,(e)@highest;			\ | ||||||
|  | 	ori     r,r,(e)@higher;			\ | ||||||
|  | 	rldicr  r,r, 32, 31;			\ | ||||||
|  | 	oris    r,r, (e)@h;			\ | ||||||
|  | 	ori     r,r, (e)@l; | ||||||
|  |  | ||||||
|  | 	.section ".head","ax" | ||||||
|  |  | ||||||
|  | 	/* | ||||||
|  | 	 * Microwatt currently enters in LE mode at 0x0, so we don't need to | ||||||
|  | 	 * do any endian fix ups | ||||||
|  | 	 */ | ||||||
|  | 	. = 0 | ||||||
|  | .global _start | ||||||
|  | _start: | ||||||
|  | 	b	boot_entry | ||||||
|  |  | ||||||
|  | .global boot_entry | ||||||
|  | boot_entry: | ||||||
|  | 	/* setup stack */ | ||||||
|  | 	LOAD_IMM64(%r1, STACK_TOP - 0x100) | ||||||
|  | 	LOAD_IMM64(%r12, main) | ||||||
|  | 	mtctr	%r12 | ||||||
|  | 	bctrl | ||||||
|  | 	attn // terminate on exit | ||||||
|  | 	b . | ||||||
|  |  | ||||||
|  | 	/* Call a function with a specified MSR value */ | ||||||
|  | 	.global	call_with_msr | ||||||
|  | call_with_msr: | ||||||
|  | 	mtsrr0	%r4 | ||||||
|  | 	mr	%r12,%r4 | ||||||
|  | 	mtsrr1	%r5 | ||||||
|  | 	rfid | ||||||
|  |  | ||||||
|  | #define EXCEPTION(nr)		\ | ||||||
|  | 	.= nr			;\ | ||||||
|  | 	li	%r3,nr		;\ | ||||||
|  | 	blr | ||||||
|  |  | ||||||
|  | 	EXCEPTION(0x300) | ||||||
|  | 	EXCEPTION(0x380) | ||||||
|  | 	EXCEPTION(0x400) | ||||||
|  | 	EXCEPTION(0x480) | ||||||
|  | 	EXCEPTION(0x500) | ||||||
|  | 	EXCEPTION(0x600) | ||||||
|  | 	EXCEPTION(0x700) | ||||||
|  | 	EXCEPTION(0x800) | ||||||
|  | 	EXCEPTION(0x900) | ||||||
|  | 	EXCEPTION(0x980) | ||||||
|  | 	EXCEPTION(0xa00) | ||||||
|  | 	EXCEPTION(0xb00) | ||||||
|  |  | ||||||
|  | 	/* | ||||||
|  | 	 * System call - used to exit from tests where MSR[PR] | ||||||
|  | 	 * may have been set. | ||||||
|  | 	 */ | ||||||
|  | 	. = 0xc00 | ||||||
|  | 	blr | ||||||
|  |  | ||||||
|  | 	EXCEPTION(0xd00) | ||||||
|  | 	EXCEPTION(0xe00) | ||||||
|  | 	EXCEPTION(0xe20) | ||||||
|  | 	EXCEPTION(0xe40) | ||||||
|  | 	EXCEPTION(0xe60) | ||||||
|  | 	EXCEPTION(0xe80) | ||||||
|  | 	EXCEPTION(0xf00) | ||||||
|  | 	EXCEPTION(0xf20) | ||||||
|  | 	EXCEPTION(0xf40) | ||||||
|  | 	EXCEPTION(0xf60) | ||||||
|  | 	EXCEPTION(0xf80) | ||||||
| @ -0,0 +1,13 @@ | |||||||
|  | SECTIONS | ||||||
|  | { | ||||||
|  | 	_start = .; | ||||||
|  | 	. = 0; | ||||||
|  | 	.head : { | ||||||
|  | 		KEEP(*(.head)) | ||||||
|  |  	} | ||||||
|  | 	. = 0x2000; | ||||||
|  | 	.text : { *(.text) } | ||||||
|  | 	. = 0x4000; | ||||||
|  | 	.data : { *(.data) } | ||||||
|  | 	.bss : { *(.bss) } | ||||||
|  | } | ||||||
| @ -0,0 +1,152 @@ | |||||||
|  | #include <stddef.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  |  | ||||||
|  | #include "console.h" | ||||||
|  |  | ||||||
|  | #define MSR_EE	0x8000 | ||||||
|  | #define MSR_PR	0x4000 | ||||||
|  | #define MSR_IR	0x0020 | ||||||
|  | #define MSR_DR	0x0010 | ||||||
|  |  | ||||||
|  | extern int call_with_msr(unsigned long arg, int (*fn)(unsigned long), unsigned long msr); | ||||||
|  |  | ||||||
|  | #define SRR0	26 | ||||||
|  | #define SRR1	27 | ||||||
|  |  | ||||||
|  | static inline unsigned long mfspr(int sprnum) | ||||||
|  | { | ||||||
|  | 	long val; | ||||||
|  |  | ||||||
|  | 	__asm__ volatile("mfspr %0,%1" : "=r" (val) : "i" (sprnum)); | ||||||
|  | 	return val; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static inline void mtspr(int sprnum, unsigned long val) | ||||||
|  | { | ||||||
|  | 	__asm__ volatile("mtspr %0,%1" : : "i" (sprnum), "r" (val)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void print_string(const char *str) | ||||||
|  | { | ||||||
|  | 	for (; *str; ++str) | ||||||
|  | 		putchar(*str); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void print_hex(unsigned long val, int ndigits) | ||||||
|  | { | ||||||
|  | 	int i, x; | ||||||
|  |  | ||||||
|  | 	for (i = (ndigits - 1) * 4; i >= 0; i -= 4) { | ||||||
|  | 		x = (val >> i) & 0xf; | ||||||
|  | 		if (x >= 10) | ||||||
|  | 			putchar(x + 'a' - 10); | ||||||
|  | 		else | ||||||
|  | 			putchar(x + '0'); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // i < 100 | ||||||
|  | void print_test_number(int i) | ||||||
|  | { | ||||||
|  | 	print_string("test "); | ||||||
|  | 	putchar(48 + i/10); | ||||||
|  | 	putchar(48 + i%10); | ||||||
|  | 	putchar(':'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int priv_fn_1(unsigned long x) | ||||||
|  | { | ||||||
|  | 	__asm__ volatile("attn"); | ||||||
|  | 	__asm__ volatile("li 3,0; sc"); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int priv_fn_2(unsigned long x) | ||||||
|  | { | ||||||
|  | 	__asm__ volatile("mfmsr 3"); | ||||||
|  | 	__asm__ volatile("sc"); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int priv_fn_3(unsigned long x) | ||||||
|  | { | ||||||
|  | 	__asm__ volatile("mtmsrd 3"); | ||||||
|  | 	__asm__ volatile("li 3,0; sc"); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int priv_fn_4(unsigned long x) | ||||||
|  | { | ||||||
|  | 	__asm__ volatile("rfid"); | ||||||
|  | 	__asm__ volatile("li 3,0; sc"); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int priv_fn_5(unsigned long x) | ||||||
|  | { | ||||||
|  | 	__asm__ volatile("mfsrr0 3"); | ||||||
|  | 	__asm__ volatile("sc"); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int priv_fn_6(unsigned long x) | ||||||
|  | { | ||||||
|  | 	__asm__ volatile("mtsrr0 3"); | ||||||
|  | 	__asm__ volatile("sc"); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int priv_test(int (*fn)(unsigned long)) | ||||||
|  | { | ||||||
|  | 	unsigned long msr; | ||||||
|  | 	int vec; | ||||||
|  |  | ||||||
|  | 	__asm__ volatile ("mtdec %0" : : "r" (0x7fffffff)); | ||||||
|  | 	__asm__ volatile ("mfmsr %0" : "=r" (msr)); | ||||||
|  | 	/* this should fail */ | ||||||
|  | 	vec = call_with_msr(0, fn, msr | MSR_PR); | ||||||
|  | 	if (vec != 0x700) | ||||||
|  | 		return vec | 1; | ||||||
|  | 	/* SRR1 should be set correctly */ | ||||||
|  | 	msr |= MSR_PR | MSR_EE | MSR_IR | MSR_DR; | ||||||
|  | 	if (mfspr(SRR1) != (msr | 0x40000)) | ||||||
|  | 		return 2; | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int fail = 0; | ||||||
|  |  | ||||||
|  | void do_test(int num, int (*fn)(unsigned long)) | ||||||
|  | { | ||||||
|  | 	int ret; | ||||||
|  |  | ||||||
|  | 	print_test_number(num); | ||||||
|  | 	ret = priv_test(fn); | ||||||
|  | 	if (ret == 0) { | ||||||
|  | 		print_string("PASS\r\n"); | ||||||
|  | 	} else { | ||||||
|  | 		fail = 1; | ||||||
|  | 		print_string("FAIL "); | ||||||
|  | 		print_hex(ret, 4); | ||||||
|  | 		print_string(" SRR0="); | ||||||
|  | 		print_hex(mfspr(SRR0), 16); | ||||||
|  | 		print_string(" SRR1="); | ||||||
|  | 		print_hex(mfspr(SRR1), 16); | ||||||
|  | 		print_string("\r\n"); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int main(void) | ||||||
|  | { | ||||||
|  | 	potato_uart_init(); | ||||||
|  |  | ||||||
|  | 	do_test(1, priv_fn_1); | ||||||
|  | 	do_test(2, priv_fn_2); | ||||||
|  | 	do_test(3, priv_fn_3); | ||||||
|  | 	do_test(4, priv_fn_4); | ||||||
|  | 	do_test(5, priv_fn_5); | ||||||
|  | 	do_test(6, priv_fn_6); | ||||||
|  |  | ||||||
|  | 	return fail; | ||||||
|  | } | ||||||
											
												Binary file not shown.
											
										
									
								| @ -0,0 +1,6 @@ | |||||||
|  | test 01:PASS | ||||||
|  | test 02:PASS | ||||||
|  | test 03:PASS | ||||||
|  | test 04:PASS | ||||||
|  | test 05:PASS | ||||||
|  | test 06:PASS | ||||||
					Loading…
					
					
				
		Reference in New Issue