diff --git a/tests/privileged/Makefile b/tests/privileged/Makefile new file mode 100644 index 0000000..7c24998 --- /dev/null +++ b/tests/privileged/Makefile @@ -0,0 +1,3 @@ +TEST=privileged + +include ../Makefile.test diff --git a/tests/privileged/head.S b/tests/privileged/head.S new file mode 100644 index 0000000..9b76234 --- /dev/null +++ b/tests/privileged/head.S @@ -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) diff --git a/tests/privileged/powerpc.lds b/tests/privileged/powerpc.lds new file mode 100644 index 0000000..8c8c65b --- /dev/null +++ b/tests/privileged/powerpc.lds @@ -0,0 +1,13 @@ +SECTIONS +{ + _start = .; + . = 0; + .head : { + KEEP(*(.head)) + } + . = 0x2000; + .text : { *(.text) } + . = 0x4000; + .data : { *(.data) } + .bss : { *(.bss) } +} diff --git a/tests/privileged/privileged.c b/tests/privileged/privileged.c new file mode 100644 index 0000000..073dc07 --- /dev/null +++ b/tests/privileged/privileged.c @@ -0,0 +1,152 @@ +#include +#include +#include + +#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; +} diff --git a/tests/test_privileged.bin b/tests/test_privileged.bin new file mode 100755 index 0000000..5b8ce63 Binary files /dev/null and b/tests/test_privileged.bin differ diff --git a/tests/test_privileged.console_out b/tests/test_privileged.console_out new file mode 100644 index 0000000..a49bb9b --- /dev/null +++ b/tests/test_privileged.console_out @@ -0,0 +1,6 @@ +test 01:PASS +test 02:PASS +test 03:PASS +test 04:PASS +test 05:PASS +test 06:PASS diff --git a/tests/update_console_tests b/tests/update_console_tests index c17c12b..bd012d9 100755 --- a/tests/update_console_tests +++ b/tests/update_console_tests @@ -3,7 +3,7 @@ # Script to update console related tests from source # -for i in sc illegal decrementer ; do +for i in sc illegal decrementer privileged ; do cd $i make cd -