diff --git a/software/example-privilege-level/LICENSE b/software/example-privilege-level/LICENSE new file mode 100644 index 00000000..201a5c0f --- /dev/null +++ b/software/example-privilege-level/LICENSE @@ -0,0 +1,3 @@ +This source repository is release under Apache2 and MIT licenses. + +See LICENSE.Apache2 and LICENSE.MIT for details. diff --git a/software/example-privilege-level/LICENSE.Apache2 b/software/example-privilege-level/LICENSE.Apache2 new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/software/example-privilege-level/LICENSE.Apache2 @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/software/example-privilege-level/LICENSE.MIT b/software/example-privilege-level/LICENSE.MIT new file mode 100644 index 00000000..06b9665d --- /dev/null +++ b/software/example-privilege-level/LICENSE.MIT @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2021 SiFive, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/software/example-privilege-level/Makefile b/software/example-privilege-level/Makefile new file mode 100644 index 00000000..0441936b --- /dev/null +++ b/software/example-privilege-level/Makefile @@ -0,0 +1,10 @@ +# Copyright 2021 SiFive, Inc # +# SPDX-License-Identifier: Apache-2.0 # + +PROGRAM ?= example-privilege-level + +$(PROGRAM): $(wildcard *.c) $(wildcard *.h) $(wildcard *.S) + $(CC) $(CFLAGS) $(LDFLAGS) $(filter %.c %.S,$^) $(LOADLIBES) $(LDLIBS) -o $@ + +clean: + rm -f $(PROGRAM) $(PROGRAM).hex diff --git a/software/example-privilege-level/README.md b/software/example-privilege-level/README.md new file mode 100644 index 00000000..11e4ecfc --- /dev/null +++ b/software/example-privilege-level/README.md @@ -0,0 +1,10 @@ +# example-privilege-level + +Demonstrates how to switch mode to supervisor mode from machine mode, +then switch mode to user mode from supervisor mode. + +This program shows what should be done before switching mode, and +uses ecall to test mode transfer. After switching mode, we call the +ecall and check if we get the correct corresponding exceptions. +- Call ecall in S-mode, get the exception code 9 (Environment call from S-mode) +- Call ecall in U-mode, get the exception code 8 (Environment call from U-mode) diff --git a/software/example-privilege-level/example-privilege-level.c b/software/example-privilege-level/example-privilege-level.c new file mode 100644 index 00000000..2cb01a3f --- /dev/null +++ b/software/example-privilege-level/example-privilege-level.c @@ -0,0 +1,257 @@ +/* Copyright 2021 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include + +#include +#include +#include +#include + +#include + +/* Enalbe / Disable print statment */ +#if 1 +#define PR_INFO(...) printf(__VA_ARGS__) +#else +#define PR_INFO(...) +#endif + +#define EXTRACT_FIELD(val, which) \ + (((val) & (which)) / ((which) & ~((which)-1))) + +#define INSERT_FIELD(val, which, fieldval) \ + (((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1)))) + +// TODO: Currently, METAL_R9_EXCEPTION_CODE is reserved in freedom-metal +#define METAL_ECALL_S_EXCEPTION_CODE METAL_R9_EXCEPTION_CODE + +/* + * Create a stack for user-mode execution. + * This size need to be big enough, otherwise, + * it would corrupt the freedom-metal content. + */ +/* Create a stack for supervisor-mode execution */ +uint8_t s_stack[1024] __attribute__((aligned(16))); +/* Create a stack for user-mode execution */ +uint8_t u_stack[1024] __attribute__((aligned(16))); + +/* Create the register file for user mode execution */ +struct metal_register_file s_regfile = { + .sp = (uintptr_t) (s_stack + sizeof(s_stack)), +}; + +struct metal_register_file u_regfile = { + .sp = (uintptr_t) (u_stack + sizeof(u_stack)), +}; + +/* TODO: Currently, metal_privilege_drop_to_mode only support M-mode */ +#define METAL_SSTATUS_SPP 0x00000100UL +#define METAL_SSTATUS_SPIE 0x00000020UL + +static void switch_mode(enum metal_privilege_mode next_mode, + struct metal_register_file regfile, + metal_privilege_entry_point_t next_addr) +{ + uintptr_t value; + + METAL_CPU_GET_CSR(sstatus, value); + + /* Set SPP to the requested privilege mode */ + value = INSERT_FIELD(value, METAL_SSTATUS_SPP, next_mode); + + /* Set SPIE bits by clearing value */ + value = INSERT_FIELD(value, METAL_SSTATUS_SPIE, 0); + + METAL_CPU_SET_CSR(sstatus, value); + + /* Set the entry point in SEPC */ + METAL_CPU_SET_CSR(sepc, next_addr); + + /* 'sp' can't be in clobber list, it is safe to simply drop + * 'sp' from the clobber list. + */ + __asm__ __volatile__( + "mv ra, %[regfile_ra] \n" + "mv sp, %[regfile_sp] \n" + "sret \n " + :: [regfile_ra]"r"(regfile.ra), [regfile_sp]"r"(regfile.sp) + : "ra"); +} + +static void supervisor_mode_trap_handler(struct metal_cpu *cpu, int cause) +{ + uintptr_t epc = metal_cpu_get_exception_pc(cpu); + int inst_len = metal_cpu_get_instruction_length(cpu, epc); + uintptr_t value; + + if (cause == METAL_ECALL_S_EXCEPTION_CODE) { + PR_INFO("Caught ecall from supervisor mode\n"); + METAL_CPU_GET_CSR(mstatus, value); + value = EXTRACT_FIELD(value, METAL_MSTATUS_MPP); + PR_INFO("mstatus.MPP is 0x%x\n", (unsigned int)value); + metal_cpu_set_exception_pc(cpu, epc + inst_len); + } else { + exit(7); + } +} + +static void user_mode_trap_handler(struct metal_cpu *cpu, int cause) +{ + uintptr_t epc = metal_cpu_get_exception_pc(cpu); + int inst_len = metal_cpu_get_instruction_length(cpu, epc); + uintptr_t value; + + if (cause == METAL_ECALL_U_EXCEPTION_CODE) { + PR_INFO("Caught ecall from user mode\n"); + METAL_CPU_GET_CSR(mstatus, value); + value = EXTRACT_FIELD(value, METAL_MSTATUS_MPP); + PR_INFO("mstatus.MPP is 0x%x\n", (unsigned int)value); + metal_cpu_set_exception_pc(cpu, epc + inst_len); + } else { + exit(8); + } +} + +static void supervisor_mode_entry_point(void) +{ + /* Perform a syscall in supervisor mode */ + __asm__ volatile("ecall"); + + return; +} + +static void user_mode_entry_point(void) +{ + /* Perform a syscall in user mode */ + __asm__ volatile("ecall"); + + return; +} + +static __attribute__((__noinline__)) void exit_point(void) +{ + exit(0); +} + +static __attribute__((__noinline__)) void start_transfer_umode(void) +{ + PR_INFO("= Transfer privilege to user mode =\n"); + + /* Normally, the original 'ra' register should be recovered by the + * lower-level trap handler. In this case, we set the return address + * where we want to return from user_mode_entry_point by hand, because + * the exit_point is not the caller of user_mode_entry_point, we enter + * user_mode_entry_point by setting sepc in the the lower-level trap + * handler. + */ + u_regfile.ra = (metal_xreg_t)exit_point; + + /* Use our own function to switch mode */ + switch_mode(METAL_PRIVILEGE_USER, + u_regfile, + user_mode_entry_point); +} + +static __attribute__((__noinline__)) void start_transfer_smode(void) +{ + PR_INFO("= Transfer privilege to supervisor mode =\n"); + + /* Normally, the original 'ra' register should be recovered by the + * lower-level trap handler. In this case, we set the return address + * where we want to return from supervisor_mode_entry_point by hand, + * because the start_transfer_umode is not the caller of + * supervisor_mode_entry_point, we enter supervisor_mode_entry_point by + * setting mepc in the lower-level trap handler. + */ + s_regfile.ra = (metal_xreg_t)start_transfer_umode; + + /* Use API of freedom-metal to switch mode */ + metal_privilege_drop_to_mode(METAL_PRIVILEGE_SUPERVISOR, + s_regfile, + supervisor_mode_entry_point); +} + +static void start_transfer_privilege(void) +{ + uintptr_t value; + + /* We are in machine mode at the beginning */ + PR_INFO("= Start privilege in machine mode =\n"); + + METAL_CPU_GET_CSR(mstatus, value); + value = EXTRACT_FIELD(value, METAL_MSTATUS_MPP); + PR_INFO("mstatus.MPP is 0x%x\n", (unsigned int)value); + + start_transfer_smode(); +} + +int main(void) +{ + int ret; + struct metal_cpu *cpu; + struct metal_interrupt *cpu_intr; +#ifdef __METAL_DT_PMP_HANDLE + struct metal_pmp *pmp; +#endif + + /* Initialize interrupt handling */ + cpu = metal_cpu_get(metal_cpu_get_current_hartid()); + if (!cpu) { + printf("Unable to get CPU handle\n"); + return 1; + } + + cpu_intr = metal_cpu_interrupt_controller(cpu); + if (!cpu_intr) { + printf("Unable to get CPU Interrupt handle\n"); + return 2; + } + + metal_interrupt_init(cpu_intr); + + /* Register our own handler for traps */ + ret = metal_cpu_exception_register(cpu, + METAL_ECALL_S_EXCEPTION_CODE, + supervisor_mode_trap_handler); + if (ret < 0) { + printf("Failed to register S-Mode exception handler\n"); + return 3; + } + + ret = metal_cpu_exception_register(cpu, + METAL_ECALL_U_EXCEPTION_CODE, + user_mode_trap_handler); + if (ret < 0) { + printf("Failed to register U-Mode exception handler\n"); + return 4; + } + +#ifdef __METAL_DT_PMP_HANDLE + /* Initialize PMPs */ + pmp = metal_pmp_get_device(); + if (!pmp) { + printf("Unable to get PMP Device\n"); + return 5; + } + metal_pmp_init(pmp); + + /* Configure PMP 0 to allow access to all memory */ + struct metal_pmp_config config = { + .L = METAL_PMP_UNLOCKED, + .A = METAL_PMP_TOR, + .X = 1, + .W = 1, + .R = 1, + }; + ret = metal_pmp_set_region(pmp, 0, config, -1); + if (ret != 0) { + return 6; + } +#endif + + start_transfer_privilege(); + + return 0; +}