├── bsp └── fe310 │ ├── settings.mk │ ├── memory.lds │ ├── machine.h │ └── platform.h ├── .gitignore ├── LICENSE ├── src ├── openmz │ ├── include │ │ ├── sched.h │ │ ├── traps.h │ │ ├── const.h │ │ ├── macro.h │ │ ├── csr.h │ │ ├── config.h │ │ ├── config_macro.h │ │ └── kernel.h │ ├── Makefile │ ├── kernel.c │ ├── head.S │ ├── sched.c │ ├── default.lds │ ├── traps.c │ ├── traps.S │ └── ecall.c ├── zone2 │ ├── Makefile │ ├── head.S │ ├── main.c │ └── default.lds └── zone1 │ ├── Makefile │ ├── head.S │ ├── newlib.c │ ├── main.c │ └── default.lds ├── libhexfive ├── libhexfive.h └── libhexfive.S ├── LICENSE.HEXFIVE ├── scripts ├── COPYING ├── apply-format └── git-pre-commit-format ├── LICENSE.MIT ├── Makefile ├── README.md ├── .clang-format └── LICENSE.GPLv2 /bsp/fe310/settings.mk: -------------------------------------------------------------------------------- 1 | export ARCH = rv32imac 2 | export ABI = ilp32 3 | export CMODEL = medlow 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compile results 2 | *.elf 3 | *.map 4 | *.hex 5 | 6 | # Eclipse project 7 | .cproject 8 | .project 9 | .settings 10 | 11 | # ctags database 12 | tags 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This project is under three different copyright licenses: 2 | 3 | - HexFive's license (LICENSE.HEXFIVE) for the MultiZone API (libhexfive.h). 4 | - GPLv2 (LICENSE.GPLv2) for the kernel and drivers. 5 | - MIT (LICENSE.MIT) for the kernel configuration. 6 | 7 | The owner of the copyright of the source files are on the top of each file. 8 | -------------------------------------------------------------------------------- /src/openmz/include/sched.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | #ifndef SCHED_H 10 | #define SCHED_H 11 | #include "kernel.h" 12 | void sched_init(void); 13 | void sched_yield(void); 14 | void sched(void); 15 | void sched_intrp(zone_t* zone); 16 | #endif // SCHED_H 17 | -------------------------------------------------------------------------------- /bsp/fe310/memory.lds: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | rom = 0x20000000; 10 | ram = 0x80000000; 11 | itim = 0x8000000; 12 | 13 | CLIC = 0x02000000; 14 | PLIC = 0x0C000000; 15 | PRCI = 0x10008000; 16 | GPIO = 0x10012000; 17 | UART0 = 0x10013000; 18 | UART1 = 0x10023000; 19 | -------------------------------------------------------------------------------- /src/openmz/include/traps.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | #ifndef TRAPS_H 10 | #define TRAPS_H 11 | #include 12 | void handle_event(uintptr_t mcause, uintptr_t mtval); 13 | void handle_ecall(uintptr_t, uintptr_t); 14 | void handle_user_timer(uintptr_t, uintptr_t); 15 | void handle_illegal_instruction(uintptr_t, uintptr_t); 16 | void handle_user_intrp(uintptr_t, uintptr_t); 17 | void handle_user_excpt(uintptr_t, uintptr_t); 18 | 19 | #endif // TRAPS_H 20 | -------------------------------------------------------------------------------- /src/zone2/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Saab AB 3 | # 4 | # This software may be distributed and modified according to 5 | # the terms of the MIT License. 6 | # Note that NO WARRANTY is provided. 7 | # See "LICENSE.MIT" for details. 8 | # 9 | 10 | INCLUDES = include $(BSP_DIR) $(HEXFIVE_DIR) 11 | SOURCES = $(wildcard *.c *.S) $(HEXFIVE_DIR)/libhexfive.S ../zone1/counter.S 12 | HEADERS = $(wildcard *.h $(addsuffix /*.h, $(INCLUDES))) 13 | 14 | CFLAGS = -march=$(ARCH) -mabi=$(ABI) -mcmodel=$(CMODEL) 15 | CFLAGS += $(addprefix -I, $(INCLUDES)) -nostdlib 16 | CFLAGS += -T $(BSP_DIR)/memory.lds -T default.lds 17 | CFLAGS += -g -O3 18 | 19 | .PHONY: compile 20 | compile: $(PROGRAM_ELF) 21 | 22 | $(PROGRAM_ELF): $(SOURCES) $(HEADERS) 23 | $(CC) $(CFLAGS) -o $@ $(SOURCES) 24 | $(SIZE) $@ 25 | -------------------------------------------------------------------------------- /src/zone1/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Saab AB 3 | # 4 | # This software may be distributed and modified according to 5 | # the terms of the MIT License. 6 | # Note that NO WARRANTY is provided. 7 | # See "LICENSE.MIT" for details. 8 | # 9 | 10 | INCLUDES = include $(BSP_DIR) $(HEXFIVE_DIR) 11 | SOURCES = $(wildcard *.c *.S) $(HEXFIVE_DIR)/libhexfive.S 12 | HEADERS = $(wildcard *.h $(addsuffix /*.h, $(INCLUDES))) 13 | 14 | CFLAGS = -march=$(ARCH) -mabi=$(ABI) -mcmodel=$(CMODEL) 15 | CFLAGS += $(addprefix -I, $(INCLUDES)) --specs=nano.specs -nostartfiles 16 | CFLAGS += -T $(BSP_DIR)/memory.lds -T default.lds 17 | CFLAGS += -g -O3 18 | 19 | 20 | .PHONY: compile 21 | compile: $(PROGRAM_ELF) 22 | 23 | $(PROGRAM_ELF): $(SOURCES) $(HEADERS) 24 | $(CC) $(CFLAGS) -o $@ $(SOURCES) 25 | $(SIZE) $@ 26 | -------------------------------------------------------------------------------- /src/openmz/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Saab AB 3 | # 4 | # This software may be distributed and modified according to 5 | # the terms of the MIT License. 6 | # Note that NO WARRANTY is provided. 7 | # See "LICENSE.MIT" for details. 8 | # 9 | 10 | INCLUDES = include $(BSP_DIR) 11 | 12 | SOURCES = $(wildcard *.c *.S) 13 | HEADERS = $(wildcard *.h $(addsuffix /*.h, $(INCLUDES))) 14 | 15 | #CC = ccomp 16 | #CFLAGS = -finline-asm -fno-fpu -g 17 | 18 | CFLAGS = -march=$(ARCH) -mabi=$(ABI) -mcmodel=$(CMODEL) 19 | CFLAGS += -g -O2 20 | 21 | CFLAGS += $(addprefix -I, $(INCLUDES)) -nostdlib -static 22 | CFLAGS += -T $(BSP_DIR)/memory.lds -T default.lds 23 | 24 | .PHONY: compile 25 | compile: $(PROGRAM_ELF) 26 | 27 | $(PROGRAM_ELF): $(SOURCES) $(HEADERS) 28 | $(CC) $(CFLAGS) -o $@ $(SOURCES) 29 | $(SIZE) $@ 30 | -------------------------------------------------------------------------------- /libhexfive/libhexfive.h: -------------------------------------------------------------------------------- 1 | /* Copyright(C) 2018 Hex Five Security, Inc. - All Rights Reserved */ 2 | 3 | 4 | #ifndef LIBHEXFIVE_H_ 5 | #define LIBHEXFIVE_H_ 6 | #include 7 | 8 | void ECALL_YIELD(); 9 | void ECALL_WFI(); 10 | 11 | int ECALL_SEND(int, void *); 12 | int ECALL_RECV(int, void *); 13 | 14 | void ECALL_TRP_VECT(int, void *); 15 | void ECALL_IRQ_VECT(int, void *); 16 | 17 | void ECALL_CSRS_MIE(); 18 | void ECALL_CSRC_MIE(); 19 | 20 | void ECALL_CSRW_MTIMECMP(uint64_t); 21 | 22 | uint64_t ECALL_CSRR_MTIME(); 23 | uint64_t ECALL_CSRR_MCYCLE(); 24 | uint64_t ECALL_CSRR_MINSTR(); 25 | uint64_t ECALL_CSRR_MHPMC3(); 26 | uint64_t ECALL_CSRR_MHPMC4(); 27 | 28 | uint64_t ECALL_CSRR_MISA(); 29 | uint64_t ECALL_CSRR_MVENDID(); 30 | uint64_t ECALL_CSRR_MARCHID(); 31 | uint64_t ECALL_CSRR_MIMPID(); 32 | uint64_t ECALL_CSRR_MHARTID(); 33 | 34 | #endif /* LIBHEXFIVE_H_ */ 35 | -------------------------------------------------------------------------------- /LICENSE.HEXFIVE: -------------------------------------------------------------------------------- 1 | The file "libhexfive.h" falls under the following license. 2 | 3 | ------------------------------------------------------------------------------------------------------- 4 | 5 | Copyright (c) 2018, Hex Five Security, Inc. 6 | 7 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without 8 | fee is hereby granted, provided that the above copyright notice and this permission notice appear 9 | in all copies. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 12 | INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE 13 | FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 14 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 15 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /src/zone1/head.S: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | 10 | .section .text.init 11 | .globl _start 12 | _start: 13 | /* initialize global pointer */ 14 | .option push 15 | .option norelax 16 | la gp, __global_pointer$ 17 | .option pop 18 | la sp, _sp 19 | 20 | /* relocated data segment if required */ 21 | la t0, _data_lma 22 | la t1, _data 23 | la t2, _edata 24 | 25 | beq t0, t1, 2f 26 | 1: lw a0, 0(t0) 27 | sw a0, 0(t1) 28 | addi t0, t0, 4 29 | addi t1, t1, 4 30 | bltu t1, t2, 1b 31 | 2: 32 | 33 | // zero bss segment (i.e. uninitiated data) 34 | la t1, _bss 35 | la t2, _ebss 36 | beq t1, t2, 2f 37 | 1: sw x0, 0(t1) 38 | addi t1, t1, 4 39 | bltu t1, t2, 1b 40 | 2: 41 | 42 | /* start the program */ 43 | mv a0, x0 44 | mv a1, x0 45 | call main 46 | hang: 47 | j hang 48 | -------------------------------------------------------------------------------- /src/zone2/head.S: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | 10 | .section .text.init 11 | .globl _start 12 | _start: 13 | /* initialize global pointer */ 14 | .option push 15 | .option norelax 16 | la gp, __global_pointer$ 17 | .option pop 18 | la sp, _sp 19 | 20 | /* relocated data segment if required */ 21 | la t0, _data_lma 22 | la t1, _data 23 | la t2, _edata 24 | 25 | beq t0, t1, 2f 26 | 1: lw a0, 0(t0) 27 | sw a0, 0(t1) 28 | addi t0, t0, 4 29 | addi t1, t1, 4 30 | bltu t1, t2, 1b 31 | 2: 32 | 33 | // zero bss segment (i.e. uninitiated data) 34 | la t1, _bss 35 | la t2, _ebss 36 | beq t1, t2, 2f 37 | 1: sw x0, 0(t1) 38 | addi t1, t1, 4 39 | bltu t1, t2, 1b 40 | 2: 41 | 42 | /* start the program */ 43 | mv a0, x0 44 | mv a1, x0 45 | call main 46 | hang: 47 | j hang 48 | -------------------------------------------------------------------------------- /src/openmz/kernel.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | #include "kernel.h" 10 | 11 | #include "machine.h" 12 | #include "sched.h" 13 | 14 | #include "csr.h" 15 | 16 | kernel_t kernel = { .zones = { ZONE_CONFIG }, .intrp_handlers = { IRQ_CONFIG } }; 17 | 18 | extern void asm_restore_context(uintptr_t[32], uint32_t[2], uintptr_t[8]) __attribute__((noreturn)); 19 | void restore_context(void) 20 | { 21 | clear_cache(); 22 | asm_restore_context(CURRENT.regs, CURRENT.pmpcfg, CURRENT.pmpaddr); 23 | } 24 | 25 | extern void asm_trap_entry(void) __attribute__((noreturn)); 26 | void kmain(void) 27 | { 28 | // Kernel csr initialization. 29 | CSRW(mtvec, asm_trap_entry); 30 | CSRW(mstatus, 0); 31 | // set the zones' id 32 | for (int i = 0; i < N_ZONES; ++i) 33 | ZONES[i].id = i + 1; 34 | // initilize the hardware 35 | init_hardware(); 36 | // initialize the scheduler 37 | sched_init(); 38 | // Start zone context 39 | restore_context(); 40 | } 41 | -------------------------------------------------------------------------------- /src/zone2/main.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | #include "libhexfive.h" 10 | #include "platform.h" 11 | 12 | uint32_t vec32[4] = { 0, 0, 0, 0 }; 13 | uint64_t vec64[2] = { 0, 0 }; 14 | 15 | extern void asm_adder(uint32_t a0) __attribute__((noreturn)); 16 | void send_add_loop(uint32_t a0) 17 | { 18 | if (a0 != 0) { 19 | // send additions to zone 1 20 | vec32[0] = a0; 21 | while (!ECALL_SEND(1, vec32)) 22 | ECALL_YIELD(); 23 | } 24 | // enable interrupts 25 | ECALL_CSRS_MIE(); 26 | // get start and deadline 27 | while (!ECALL_RECV(1, vec64)) 28 | ECALL_YIELD(); 29 | uint64_t start_time = vec64[0]; 30 | uint64_t deadline = vec64[1]; 31 | // set deadline 32 | ECALL_CSRW_MTIMECMP(deadline); 33 | // wait for start time 34 | while (start_time > ECALL_CSRR_MTIME()) 35 | ; 36 | // start adding 37 | asm_adder(0); 38 | } 39 | void main(void) 40 | { 41 | ECALL_TRP_VECT(0x3, send_add_loop); 42 | send_add_loop(0); 43 | } 44 | -------------------------------------------------------------------------------- /scripts/COPYING: -------------------------------------------------------------------------------- 1 | This license applies to "git-pre-commit-format" and "apply-format." 2 | ---- 3 | Copyright 2017-2018 Marco Barisione 4 | Copyright 2018 Undo Ltd. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/openmz/include/const.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | #ifndef CONST_H_ 10 | #define CONST_H_ 11 | 12 | #define MIE_TIMER (1 << 7) 13 | 14 | #define INTRP_BIT (1UL << (__riscv_xlen - 1)) 15 | 16 | #define UMODE_SOFT_INTRP 0 17 | #define SMODE_SOFT_INTRP 1 18 | #define MMODE_SOFT_INTRP 3 19 | #define UMODE_TIMER_INTRP 4 20 | #define SMODE_TIMER_INTRP 5 21 | #define MMODE_TIMER_INTRP 7 22 | #define UMODE_EXTERN_INTRP 8 23 | #define SMODE_EXTERN_INTRP 9 24 | #define MMODE_EXTERN_INTRP 11 25 | 26 | #define INSTRUCTION_ADDRESS_MISALIGNED 0 27 | #define ILLEGAL_ACCESS_FAULT 1 28 | #define ILLEGAL_INSTRUCTION 2 29 | #define BREAKPOINT 3 30 | #define UMODE_SOFT_TIMER 3 31 | #define LOAD_ADDRESS_MISALIGNED 4 32 | #define LOAD_ACCESS_FAULT 5 33 | #define STORE_ADDRESS_MISALIGNED 6 34 | #define STORE_ACCESS_FAULT 7 35 | #define UMODE_ECALL 8 36 | #define SMODE_ECALL 9 37 | #define MMODE_ECALL 11 38 | #define INSTRUCTION_PAGE_FAULT 12 39 | #define LOAD_PAGE_FAULT 13 40 | #define STORE_PAGE_FAULT 15 41 | 42 | #define OP_URET 0x00200073UL 43 | #endif // CONST_H_ 44 | -------------------------------------------------------------------------------- /LICENSE.MIT: -------------------------------------------------------------------------------- 1 | Files described as being under the "MIT License" 2 | or simply the "MIT" fall under the license below. 3 | 4 | The copyrights of the MIT licensed files of the project are held by the 5 | respective owners indicated at the top of the file. 6 | 7 | --------------------------------------------------------------------- 8 | 9 | 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: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | 13 | 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. 14 | -------------------------------------------------------------------------------- /src/zone1/newlib.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | #include "platform.h" 10 | #include "string.h" 11 | #include 12 | 13 | int _fstat(int file, struct stat* st) 14 | { 15 | st->st_mode = S_IFCHR; 16 | return 0; 17 | } 18 | 19 | int _isatty(int file) 20 | { 21 | return 1; 22 | } 23 | 24 | int _lseek(int file, int ptr, int dir) 25 | { 26 | return 0; 27 | } 28 | 29 | int _open(const char* name, int flags, int mode) 30 | { 31 | return -1; 32 | } 33 | 34 | int _write(int file, char* c, int len) 35 | { 36 | for (int i = 0; i < len; ++i) { 37 | while (UART0.txdata < 0) 38 | ; 39 | UART0.txdata = c[i]; 40 | } 41 | return len; 42 | } 43 | 44 | int _read(int file, char* c, int len) 45 | { 46 | return -1; 47 | } 48 | 49 | char* _sbrk(int incr) 50 | { 51 | extern char _heap; /* Defined by the linker */ 52 | extern char _eheap; /* Defined by the linker */ 53 | static char* heap_ptr = &_heap; 54 | if (heap_ptr + incr <= &_eheap) { 55 | char* base = heap_ptr; 56 | heap_ptr += incr; 57 | return base; 58 | } 59 | return (char*)-1; 60 | } 61 | -------------------------------------------------------------------------------- /src/openmz/include/macro.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | #ifndef CONST_H 10 | #define CONST_H 11 | 12 | /* selection macro */ 13 | #if __riscv_xlen == 32 14 | #define SEL(a, b) a 15 | #else 16 | #define SEL(a, b) b 17 | #endif 18 | 19 | #define REG_S SEL(sw, sd) // register store 20 | #define REG_L SEL(lw, ld) // register load 21 | #define REGBYTES SEL(4, 8) // register size 22 | 23 | #define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0])) 24 | #define UNUSED(x) x __attribute__((unused)) 25 | 26 | #define STR(s) XSTR(s) 27 | #define XSTR(s) #s 28 | 29 | // Register index 30 | #define PC 0 31 | #define RA 1 32 | #define SP 2 33 | #define GP 3 34 | #define TP 4 35 | #define T0 5 36 | #define T1 6 37 | #define T2 7 38 | #define FP 8 39 | #define S0 8 40 | #define S1 9 41 | #define A0 10 42 | #define A1 11 43 | #define A2 12 44 | #define A3 13 45 | #define A4 14 46 | #define A5 15 47 | #define A6 16 48 | #define A7 17 49 | #define S2 18 50 | #define S3 19 51 | #define S4 20 52 | #define S5 21 53 | #define S6 22 54 | #define S7 23 55 | #define S8 24 56 | #define S9 25 57 | #define S10 26 58 | #define S11 27 59 | #define T3 28 60 | #define T4 29 61 | #define T5 30 62 | #define T6 31 63 | #endif // CONST_H 64 | -------------------------------------------------------------------------------- /src/openmz/head.S: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | 10 | .section .text.init 11 | .globl _start 12 | _start: 13 | /* initialize global pointer */ 14 | .option push 15 | .option norelax 16 | la gp, __global_pointer$ 17 | .option pop 18 | la sp, _sp 19 | 20 | la t0, hang 21 | csrw mtvec, t0 22 | 23 | // copy the ITIM section 24 | la t0, _itim_lma 25 | la t1, _itim 26 | la t2, _eitim 27 | 28 | beq t0, t1, 2f 29 | 1: lw a0, 0(t0) 30 | sw a0, 0(t1) 31 | addi t0, t0, 4 32 | addi t1, t1, 4 33 | bltu t1, t2, 1b 34 | 2: 35 | fence.i 36 | 37 | // copy the DATA section 38 | la t0, _data_lma 39 | la t1, _data 40 | la t2, _edata 41 | 42 | beq t0, t1, 2f 43 | 1: lw a0, 0(t0) 44 | sw a0, 0(t1) 45 | addi t0, t0, 4 46 | addi t1, t1, 4 47 | bltu t1, t2, 1b 48 | 2: 49 | 50 | // zero bss segment (i.e. uninitiated data) 51 | la t1, _bss 52 | la t2, _ebss 53 | beq t1, t2, 2f 54 | 1: sw x0, 0(t1) 55 | addi t1, t1, 4 56 | bltu t1, t2, 1b 57 | 2: 58 | 59 | /* start the kernel */ 60 | call kmain 61 | hang: 62 | ebreak 63 | j hang 64 | -------------------------------------------------------------------------------- /bsp/fe310/machine.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | #ifndef MACHINE_H 10 | #define MACHINE_H 11 | #include "csr.h" 12 | #include 13 | 14 | static inline uint64_t read_mtime(void) 15 | { 16 | register uint32_t lo, hi1, hi2; 17 | do { 18 | hi1 = CLIC.mtimeh; 19 | lo = CLIC.mtime; 20 | hi2 = CLIC.mtimeh; 21 | } while (hi1 != hi2); 22 | return (uint64_t)hi1 << 32 | lo; 23 | } 24 | 25 | static inline void write_mtimecmp(uint64_t val) 26 | { 27 | CLIC.mtimecmp = -1; 28 | CLIC.mtimecmph = val >> 32; 29 | CLIC.mtimecmp = val; 30 | } 31 | 32 | static inline void clear_cache(void) 33 | { 34 | // no cache clearing 35 | } 36 | 37 | static inline void init_hardware(void) 38 | { 39 | // Sets core clock frequency to 16 MHz 40 | uint32_t pllr = 0x1; 41 | uint32_t pllf = 0x2F; 42 | uint32_t pllq = 0x2; 43 | uint32_t pllsel = 0x1; 44 | uint32_t pllrefsel = 0x1; 45 | uint32_t pllbypass = 0x0; 46 | PRCI.pllcfg = pllr | (pllf << 4) | (pllq << 10) | (pllsel << 16) | (pllrefsel << 17) | (pllbypass << 18); 47 | while (!(PRCI.pllcfg >> 31)) 48 | ; // wait until configuration is locked 49 | 50 | CSRW(mcounteren, 0x1F); 51 | CSRW(mhpmevent3, 0x0102); 52 | } 53 | 54 | #endif // MACHINE_H 55 | -------------------------------------------------------------------------------- /src/openmz/include/csr.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | #ifndef CSR_H 10 | #define CSR_H 11 | 12 | #define CSRW(reg, in) __asm__ volatile("csrw " #reg ", %0" ::"r"(in) \ 13 | : "memory") 14 | #define CSRS(reg, in) __asm__ volatile("csrs " #reg ", %0" ::"r"(in) \ 15 | : "memory") 16 | #define CSRR(out, reg) __asm__ volatile("csrr %0, " #reg \ 17 | : "=r"(out)) 18 | 19 | #if __riscv_xlen == 32 20 | /* x5, x5, x7 = t0, t1, t2 */ 21 | #define CSRR64(out, reg) \ 22 | __asm__ volatile("csrr x5, " #reg ";" \ 23 | "sw x5, 0(%0);" \ 24 | "sw x0, 4(%0);" ::"r"(&out) \ 25 | : "x5", "memory") 26 | #define CSRR_COUNTER(out, reg) \ 27 | __asm__ volatile(" csrr x5, " #reg "h;" \ 28 | " csrr x6, " #reg ";" \ 29 | " csrr x7, " #reg "h;" \ 30 | " beq x5, x7, 1f;" \ 31 | " csrr x6, " #reg ";" \ 32 | "1:sw x6, 0(%0);" \ 33 | " sw x7, 4(%0);" ::"r"(&out) \ 34 | : "x5", "x6", "x7", "memory") 35 | #else 36 | #define CSRR64(out, reg) CSRR(out, reg) 37 | #define CSRR_COUNTER(out, reg) CSRR(out, reg) 38 | #endif 39 | 40 | #endif // CSR_H 41 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Saab AB 3 | # 4 | # This software may be distributed and modified according to 5 | # the terms of the MIT License. 6 | # Note that NO WARRANTY is provided. 7 | # See "LICENSE.MIT" for details. 8 | # 9 | 10 | PROGRAMS = openmz zone1 zone2 11 | 12 | BOARD ?= fe310 13 | BSP_DIR = $(abspath bsp/$(BOARD)) 14 | include $(BSP_DIR)/settings.mk 15 | 16 | HEXFIVE_DIR = $(abspath libhexfive) 17 | 18 | ELF_DIR = $(abspath elf) 19 | HEX_DIR = $(abspath hex) 20 | 21 | export CC=riscv64-unknown-elf-gcc 22 | export SIZE=riscv64-unknown-elf-size 23 | export OBJCOPY=riscv64-unknown-elf-objcopy 24 | export OBJDUMP=riscv64-unknown-elf-objdump 25 | 26 | .PHONY: all 27 | all: compile 28 | 29 | .PHONY: compile 30 | .PHONY: clean 31 | .PHONY: upload 32 | ifeq ($(PROGRAM),) 33 | compile: 34 | for file in $(PROGRAMS) ; do \ 35 | $(MAKE) -C . compile PROGRAM=$$file ; \ 36 | done 37 | clean: 38 | for file in $(PROGRAMS) ; do \ 39 | $(MAKE) -C . clean PROGRAM=$$file ; \ 40 | done 41 | upload: 42 | for file in $(PROGRAMS) ; do \ 43 | $(MAKE) -C . upload PROGRAM=$$file ; \ 44 | done 45 | else 46 | 47 | PROGRAM_ELF = $(ELF_DIR)/$(PROGRAM).elf 48 | PROGRAM_HEX = $(HEX_DIR)/$(PROGRAM).hex 49 | 50 | compile: $(PROGRAM_ELF) $(PROGRAM_HEX) 51 | 52 | .PHONY: $(PROGRAM_ELF) 53 | $(PROGRAM_ELF): 54 | mkdir -p $(ELF_DIR) 55 | $(MAKE) -C src/$(PROGRAM) compile \ 56 | PROGRAM_ELF=$(PROGRAM_ELF) \ 57 | BSP_DIR=$(BSP_DIR) \ 58 | HEXFIVE_DIR=$(HEXFIVE_DIR) 59 | 60 | $(PROGRAM_HEX): $(PROGRAM_ELF) 61 | mkdir -p $(HEX_DIR) 62 | $(OBJCOPY) -O ihex $(PROGRAM_ELF) $(PROGRAM_HEX) 63 | 64 | upload: $(PROGRAM_HEX) 65 | echo "loadfile $(PROGRAM_HEX)\nexit" \ 66 | | JLinkExe -device fe310 -if JTAG -speed 4000 -jtagconf -1,-1 -autoconnect 1 67 | 68 | clean: 69 | rm -f $(PROGRAM_ELF) 70 | endif 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/openmz/include/config.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the MIT License. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.MIT" for details. 8 | */ 9 | #ifndef CONFIG_H 10 | #define CONFIG_H 11 | #include "config_macro.h" 12 | 13 | // Number of zones 14 | #define N_ZONES 2 15 | 16 | // max trap code + 1 17 | #define N_TRAPS 12 18 | 19 | // max interrupt code + 1 20 | #define N_INTERRUPTS 12 21 | 22 | // time slice in ms 23 | #define QUANTUM 100 24 | 25 | /* 26 | * ZONE_N has N PMP regions. ZONE_N is defined for N = 2, 3, ..., 8. 27 | * ZONE_N's first argument is the program counter, the following 28 | * arguments are the PMP configurations. 29 | * 30 | * Example: 31 | * ZONE_2(0x20020000, NAPOT(RX, 0x20020000, 13), NAPOT(RW, 0x80001000, 12)) 32 | * pc: 0x20020000 33 | * region 1: read/execute, Base address 0x20020000, size 2^13 34 | * region 2: read/execute, Base address 0x80001000, size 2^12 35 | * 36 | * PMP configurations are: 37 | * - TOR(Permissions, address) 38 | * - NA4(Permissions, base address) 39 | * - NAPOT(Permissions, base address, log_2(size)) 40 | * The base address should be 2^size aligned. 41 | * 42 | * For all addresses, the two least significant bits will be zero since 43 | * PMP has the minimum granularity of 4 bytes. 44 | */ 45 | #define ZONE_CONFIG \ 46 | ZONE_4(0x20100000, \ 47 | NAPOT(RX, 0x20100000, 20), \ 48 | NAPOT(RW, 0x80001000, 12), \ 49 | NAPOT(RW, 0x10012000, 12), \ 50 | NAPOT(RW, 0x10013000, 12)) \ 51 | ZONE_2(0x20200000, \ 52 | NAPOT(RX, 0x20200000, 20), \ 53 | NAPOT(RW, 0x80002000, 12)) 54 | 55 | /* 56 | * Here we register hardware interrupts. 57 | * IRQ(Zone ID, Interrupt code) 58 | */ 59 | #define IRQ_CONFIG IRQ(1, 11) 60 | #endif // CONFIG_H 61 | -------------------------------------------------------------------------------- /src/zone1/main.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | #include "libhexfive.h" 10 | #include 11 | #include 12 | #include 13 | #define RR 1 14 | uint32_t vec32[4] = { 0, 0, 0, 0 }; 15 | uint64_t vec64[2] = { 0, 0 }; 16 | uint64_t prev_cache_misses; 17 | 18 | void init_uart(void) 19 | { 20 | UART0.div = 1666; 21 | UART0.txctrl = 0x1; 22 | UART0.rxctrl = 0x1; 23 | GPIO.iof_sel &= ~(3 << 16); 24 | GPIO.iof_en |= (3 << 16); 25 | } 26 | 27 | extern void asm_adder(int a0) __attribute__((noreturn)); 28 | 29 | void print_add_loop(uint32_t a0) 30 | { 31 | uint64_t cache_misses = ECALL_CSRR_MHPMC3(); 32 | if (a0 != 0) { 33 | #if RR 34 | while (!ECALL_RECV(2, vec32)) 35 | ECALL_YIELD(); 36 | // get the count of the other zone 37 | a0 += vec32[0]; 38 | #endif 39 | printf("%u %u\n\r", a0, cache_misses - prev_cache_misses); 40 | } 41 | prev_cache_misses = cache_misses; 42 | // set this as timer handler 43 | ECALL_TRP_VECT(0x3, print_add_loop); 44 | // enable interrupts 45 | ECALL_CSRS_MIE(); 46 | // calculate deadline 47 | uint64_t time = ECALL_CSRR_MTIME(); 48 | uint64_t start_time = time + RTCK_FREQ / 2; // start in half a second 49 | uint64_t deadline = start_time + 10 * RTCK_FREQ; // run for 10 seconds 50 | // send start and deadline to zone 2 51 | vec64[0] = start_time; 52 | vec64[1] = deadline; 53 | #if RR 54 | while (!ECALL_SEND(2, vec64)) 55 | ECALL_YIELD(); 56 | #endif 57 | // set deadline 58 | ECALL_CSRW_MTIMECMP(deadline); 59 | // wait for start time 60 | while (start_time > ECALL_CSRR_MTIME()) 61 | ; 62 | // start adding 63 | asm_adder(0); 64 | } 65 | 66 | void main(void) 67 | { 68 | init_uart(); 69 | printf("Test started\n\r"); 70 | print_add_loop(0); 71 | } 72 | -------------------------------------------------------------------------------- /src/zone1/default.lds: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | OUTPUT_ARCH("riscv") 10 | 11 | ENTRY(_start) 12 | 13 | MEMORY 14 | { 15 | /* 64 KiB rom */ 16 | rom (rxai!w) : ORIGIN = rom + 0x100000, LENGTH = 0x100000 17 | /* 6 KiB ram */ 18 | ram (wxa!ri) : ORIGIN = ram + 0x1000, LENGTH = 0x1000 19 | } 20 | 21 | SECTIONS 22 | { 23 | /* 1 KiB stack */ 24 | __stack_size = DEFINED(__stack_size) ? __stack_size : 0x400; 25 | PROVIDE(__stack_size = __stack_size); 26 | 27 | .text : { 28 | KEEP(*(.text.init)) 29 | *(.text) 30 | *(.text.*) 31 | . = ALIGN(8); 32 | } >rom AT>rom 33 | 34 | .rodata : ALIGN(8) { 35 | *(.rdata) 36 | *(.rodata) 37 | *(.rodata.*) 38 | } >rom AT>rom 39 | 40 | .data : ALIGN(8) { 41 | *(.data) 42 | *(.data.*) 43 | *(.sdata) 44 | *(.sdata.*) 45 | . = ALIGN(8); 46 | } >ram AT>rom 47 | PROVIDE(_data_lma = LOADADDR(.data)); 48 | PROVIDE(_data = ADDR(.data)); 49 | PROVIDE(_edata = ADDR(.data) + SIZEOF(.data)); 50 | PROVIDE(__global_pointer$ = ADDR(.data) + 0x800); 51 | 52 | .bss : ALIGN(8) { 53 | *(.bss) 54 | *(.bss.*) 55 | *(.sbss*) 56 | *(COMMON) 57 | . = ALIGN(8); 58 | } >ram AT>ram 59 | PROVIDE(_bss = ADDR(.bss)); 60 | PROVIDE(_ebss = ADDR(.bss) + SIZEOF(.bss)); 61 | PROVIDE(_heap = _ebss); 62 | 63 | .stack ORIGIN(ram) + LENGTH(ram) - __stack_size : { 64 | . += __stack_size; 65 | } >ram AT>ram 66 | PROVIDE(_eheap = ADDR(.stack)); 67 | PROVIDE(_sp = ADDR(.stack) + SIZEOF(.stack)); 68 | } 69 | -------------------------------------------------------------------------------- /src/zone2/default.lds: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | OUTPUT_ARCH("riscv") 10 | 11 | ENTRY(_start) 12 | 13 | MEMORY 14 | { 15 | /* 64 KiB rom */ 16 | rom (rxai!w) : ORIGIN = rom + 0x200000, LENGTH = 0x100000 17 | /* 6 KiB ram */ 18 | ram (wxa!ri) : ORIGIN = ram + 0x2000, LENGTH = 0x1000 19 | } 20 | 21 | SECTIONS 22 | { 23 | /* 1 KiB stack */ 24 | __stack_size = DEFINED(__stack_size) ? __stack_size : 0x400; 25 | PROVIDE(__stack_size = __stack_size); 26 | 27 | .text : { 28 | KEEP(*(.text.init)) 29 | *(.text) 30 | *(.text.*) 31 | . = ALIGN(8); 32 | } >rom AT>rom 33 | 34 | .rodata : ALIGN(8) { 35 | *(.rdata) 36 | *(.rodata) 37 | *(.rodata.*) 38 | } >rom AT>rom 39 | 40 | .data : ALIGN(8) { 41 | *(.data) 42 | *(.data.*) 43 | *(.sdata) 44 | *(.sdata.*) 45 | . = ALIGN(8); 46 | } >ram AT>rom 47 | PROVIDE(_data_lma = LOADADDR(.data)); 48 | PROVIDE(_data = ADDR(.data)); 49 | PROVIDE(_edata = ADDR(.data) + SIZEOF(.data)); 50 | PROVIDE(__global_pointer$ = ADDR(.data) + 0x800); 51 | 52 | .bss : ALIGN(8) { 53 | *(.bss) 54 | *(.bss.*) 55 | *(.sbss*) 56 | *(COMMON) 57 | . = ALIGN(8); 58 | } >ram AT>ram 59 | PROVIDE(_bss = ADDR(.bss)); 60 | PROVIDE(_ebss = ADDR(.bss) + SIZEOF(.bss)); 61 | PROVIDE(_heap = _ebss); 62 | 63 | .stack ORIGIN(ram) + LENGTH(ram) - __stack_size : { 64 | . += __stack_size; 65 | } >ram AT>ram 66 | PROVIDE(_eheap = ADDR(.stack)); 67 | PROVIDE(_sp = ADDR(.stack) + SIZEOF(.stack)); 68 | } 69 | -------------------------------------------------------------------------------- /bsp/fe310/platform.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | #ifndef PLATFORM_H 10 | #define PLATFORM_H 11 | #include 12 | 13 | #define RTCK_FREQ 32768 14 | #define CORECLK_FREQ 192000000 15 | 16 | // Padding so struct fields align correctly to memory map 17 | #define _PAD(name, start, end) char name[end - start] 18 | 19 | typedef volatile struct clic { 20 | uint32_t msip; 21 | _PAD(pad1, 0x4, 0x4000); 22 | uint32_t mtimecmp; 23 | uint32_t mtimecmph; 24 | _PAD(pad2, 0x4008, 0xbff8); 25 | uint32_t mtime; 26 | uint32_t mtimeh; 27 | } clic_t; 28 | 29 | typedef volatile struct plic { 30 | _PAD(pad1, 0x0, 0x4); 31 | uint32_t source_prio[52]; 32 | _PAD(pad2, 0xD4, 0x1000); 33 | uint32_t pending[2]; 34 | _PAD(pad3, 0x1008, 0x2000); 35 | uint32_t ie[2]; 36 | _PAD(pad4, 0x2008, 0x200000); 37 | uint32_t prio_thres; 38 | uint32_t claim_complete; 39 | } plic_t; 40 | 41 | typedef volatile struct gpio { 42 | uint32_t input_val; 43 | uint32_t input_en; 44 | uint32_t output_val; 45 | uint32_t output_en; 46 | uint32_t pue; 47 | uint32_t ds; 48 | uint32_t rise_ie; 49 | uint32_t rise_ip; 50 | uint32_t fall_ie; 51 | uint32_t fall_ip; 52 | uint32_t high_ie; 53 | uint32_t high_ip; 54 | uint32_t low_ie; 55 | uint32_t low_ip; 56 | uint32_t iof_en; 57 | uint32_t iof_sel; 58 | uint32_t out_xor; 59 | } gpio_t; 60 | 61 | typedef volatile struct uart { 62 | int32_t txdata; 63 | int32_t rxdata; 64 | uint32_t txctrl; 65 | uint32_t rxctrl; 66 | uint32_t ie; 67 | uint32_t ip; 68 | uint32_t div; 69 | } uart_t; 70 | 71 | typedef volatile struct prci { 72 | uint32_t hfrosccfg; 73 | uint32_t hfxosccfg; 74 | uint32_t pllcfg; 75 | uint32_t plloutdiv; 76 | uint32_t procmoncfg; 77 | } prci_t; 78 | 79 | extern clic_t CLIC; 80 | extern plic_t PLIC; 81 | extern prci_t PRCI; 82 | extern gpio_t GPIO; 83 | extern uart_t UART0; 84 | extern uart_t UART1; 85 | #endif // PLATFORM_H 86 | -------------------------------------------------------------------------------- /src/openmz/sched.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | #include "sched.h" 10 | 11 | #include "const.h" 12 | #include "csr.h" 13 | #include "kernel.h" 14 | #include "machine.h" 15 | 16 | #define QUANTUM_CYC (RTCK_FREQ * QUANTUM / 1000) 17 | 18 | void sched_yield(void) 19 | { 20 | KERNEL.intrp_mode = 0; 21 | KERNEL.current = KERNEL.next; 22 | KERNEL.next = (CURRENT.id == N_ZONES) ? &ZONES[0] : (KERNEL.current + 1); 23 | #if QUANTUM > 0 24 | KERNEL.deadline = KERNEL.deadline + KERNEL.next_quantum; 25 | KERNEL.next_quantum = QUANTUM_CYC; 26 | #endif 27 | } 28 | 29 | void sched_intrp(zone_t* zone) 30 | { 31 | KERNEL.intrp_mode = 1; 32 | KERNEL.next = KERNEL.current; 33 | KERNEL.current = zone; 34 | #if QUANTUM > 0 35 | uint64_t now = read_mtime(); 36 | if (now < KERNEL.deadline) { 37 | KERNEL.next_quantum = KERNEL.deadline - now; 38 | } else { 39 | KERNEL.next_quantum = 0; 40 | } 41 | KERNEL.deadline = read_mtime() + QUANTUM_CYC; 42 | #endif 43 | } 44 | 45 | void sched(void) 46 | { 47 | #if QUANTUM > 0 48 | if (KERNEL.deadline <= read_mtime()) { 49 | sched_yield(); 50 | } 51 | if ((CURRENT.ustatus & USTATUS_IE) && CURRENT.deadline && (CURRENT.deadline < KERNEL.deadline)) { 52 | write_mtimecmp(CURRENT.deadline); 53 | } else { 54 | write_mtimecmp(KERNEL.deadline); 55 | } 56 | if (KERNEL.intrp_mode) { 57 | CSRW(mie, MIE_TIMER); 58 | } else { 59 | CSRW(mie, KERNEL.mie); 60 | } 61 | #else 62 | uintptr_t mie = 0; 63 | if ((CURRENT.ustatus & USTATUS_IE) && CURRENT.deadline) { 64 | write_mtimecmp(CURRENT.deadline); 65 | mie |= MIE_TIMER; 66 | } 67 | if (!KERNEL.intrp_mode) { 68 | mie |= KERNEL.mie; 69 | } 70 | CSRW(mie, mie); 71 | #endif 72 | } 73 | 74 | void sched_init(void) 75 | { 76 | KERNEL.intrp_mode = 0; 77 | KERNEL.next = ZONES; 78 | #if QUANTUM > 0 79 | KERNEL.mie = MIE_TIMER; 80 | KERNEL.next_quantum = QUANTUM_CYC; 81 | #else 82 | KERNEL.mie = 0; 83 | #endif 84 | sched_yield(); 85 | sched(); 86 | } 87 | -------------------------------------------------------------------------------- /src/openmz/default.lds: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | OUTPUT_ARCH("riscv") 10 | 11 | ENTRY(_start) 12 | 13 | MEMORY 14 | { 15 | /* 64 KiB rom */ 16 | rom (rxai!w) : ORIGIN = rom + 0x10000, LENGTH = 0x2000 17 | itim (wx!rai) : ORIGIN = itim, LENGTH = 0x2000 18 | /* 4 KiB ram */ 19 | ram (wxa!ri) : ORIGIN = ram, LENGTH = 0x1000 20 | } 21 | 22 | SECTIONS 23 | { 24 | /* 1 KiB stack */ 25 | __stack_size = DEFINED(__stack_size) ? __stack_size : 0x200; 26 | PROVIDE(__stack_size = __stack_size); 27 | 28 | .text : { 29 | KEEP(*(.text.init)) 30 | . = ALIGN(8); 31 | } >rom AT>rom 32 | 33 | .data : ALIGN(8) { 34 | *(.data) 35 | *(.data.*) 36 | *(.sdata) 37 | *(.sdata.*) 38 | *(.rodata .rodata.*) 39 | *(.rdata .rdata.*) 40 | . = ALIGN(8); 41 | } >ram AT>rom 42 | 43 | PROVIDE(__global_pointer$ = ADDR(.data)); 44 | PROVIDE(_data_lma = LOADADDR(.data)); 45 | PROVIDE(_data = ADDR(.data)); 46 | PROVIDE(_edata = ADDR(.data) + SIZEOF(.data)); 47 | 48 | .itim : ALIGN(8) { 49 | *(.text) 50 | *(.text.*) 51 | *(.itim .itim.*) 52 | . = ALIGN(8); 53 | } >ram AT>rom 54 | 55 | PROVIDE(_itim_lma = LOADADDR(.itim)); 56 | PROVIDE(_itim = ADDR(.itim)); 57 | PROVIDE(_eitim = ADDR(.itim) + SIZEOF(.itim)); 58 | 59 | .bss : ALIGN(8) { 60 | *(.bss) 61 | *(.bss.*) 62 | *(.sbss*) 63 | *(COMMON) 64 | . = ALIGN(8); 65 | } >ram AT>ram 66 | PROVIDE(_bss = ADDR(.bss)); 67 | PROVIDE(_ebss = ADDR(.bss) + SIZEOF(.bss)); 68 | PROVIDE(_heap = _ebss); 69 | 70 | .stack ORIGIN(ram) + LENGTH(ram) - __stack_size : { 71 | . += __stack_size; 72 | } >ram AT>ram 73 | PROVIDE(_eheap = ADDR(.stack)); 74 | PROVIDE(_sp = ADDR(.stack) + SIZEOF(.stack)); 75 | } 76 | -------------------------------------------------------------------------------- /src/openmz/include/config_macro.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | #ifndef CONFIG_MACRO_H 10 | #define CONFIG_MACRO_H 11 | /* Macros used for zone configuration */ 12 | #define XZONE(pc, \ 13 | cfg0, addr0, cfg1, addr1, cfg2, addr2, cfg3, addr3, \ 14 | cfg4, addr4, cfg5, addr5, cfg6, addr6, cfg7, addr7) \ 15 | { \ 16 | .regs[PC] = pc, \ 17 | .pmpcfg = { \ 18 | cfg0 | cfg1 << 8 | cfg2 << 16 | cfg3 << 24, \ 19 | cfg4 | cfg5 << 8 | cfg6 << 16 | cfg7 << 24 }, \ 20 | .pmpaddr = { addr0, addr1, addr2, addr3, addr4, addr5, addr6, addr7 } \ 21 | }, 22 | 23 | #define ZONE_8(pc, pmp0, pmp1, pmp2, pmp3, pmp4, pmp5, pmp6, pmp7) \ 24 | XZONE(pc, pmp0, pmp1, pmp2, pmp3, pmp4, pmp5, pmp6, pmp7) 25 | #define ZONE_7(pc, pmp0, pmp1, pmp2, pmp3, pmp4, pmp5, pmp6) \ 26 | XZONE(pc, pmp0, pmp1, pmp2, pmp3, pmp4, pmp5, pmp6, 0, 0) 27 | #define ZONE_6(pc, pmp0, pmp1, pmp2, pmp3, pmp4, pmp5) \ 28 | XZONE(pc, pmp0, pmp1, pmp2, pmp3, pmp4, pmp5, 0, 0, 0, 0) 29 | #define ZONE_5(pc, pmp0, pmp1, pmp2, pmp3, pmp4) \ 30 | XZONE(pc, pmp0, pmp1, pmp2, pmp3, pmp4, 0, 0, 0, 0, 0, 0) 31 | #define ZONE_4(pc, pmp0, pmp1, pmp2, pmp3) \ 32 | XZONE(pc, pmp0, pmp1, pmp2, pmp3, 0, 0, 0, 0, 0, 0, 0, 0) 33 | #define ZONE_3(pc, pmp0, pmp1, pmp2) \ 34 | XZONE(pc, pmp0, pmp1, pmp2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 35 | #define ZONE_2(pc, pmp0, pmp1) \ 36 | XZONE(pc, pmp0, pmp1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 37 | 38 | #define IRQ(zone_id, irq_num) \ 39 | [irq_num] \ 40 | = { .zone = &kernel.zones[zone_id - 1], .handler = 0 }, 41 | 42 | #define W 2 43 | #define RW 3 44 | #define X 4 45 | #define RX 5 46 | #define WX 6 47 | #define RWX 7 48 | 49 | #define TOR(rwx, addr) \ 50 | (0x8 | rwx), (addr >> 2) 51 | #define NA4(rwx, addr) \ 52 | (0x10 | rwx), (addr >> 2) 53 | #define NAPOT(rwx, addr, size) \ 54 | (0x18 | rwx), (((addr >> 2) | ((1 << (size - 2)) - 1)) & ~(1 << (size - 2))) 55 | #endif // CONFIG_MACRO_H 56 | -------------------------------------------------------------------------------- /src/openmz/include/kernel.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | #ifndef KERNEL_H 10 | #define KERNEL_H 11 | #include "config.h" 12 | #include "macro.h" 13 | #include 14 | 15 | #define USTATUS_IE 1 16 | #define USTATUS_PIE (1 << 4) 17 | 18 | #define N_MSGS SEL(4, 2) 19 | 20 | /* inbox_t for inter-zone communication. */ 21 | typedef struct inbox { 22 | // if full != 0, then we have a message, else no message. 23 | uintptr_t full; 24 | // 128-bit message 25 | uintptr_t msgs[N_MSGS]; 26 | } inbox_t; 27 | 28 | /* zone_t data, e.g. Processor Control Block (PCB) */ 29 | typedef struct zone { 30 | uintptr_t id; 31 | // zone context, pc + x1-x31 32 | uintptr_t regs[32]; 33 | // pmp configuration registers 34 | uint32_t pmpcfg[2]; 35 | uintptr_t pmpaddr[8]; 36 | // trap handling regusters 37 | // ustatus[0] = interrupt enabled 38 | // ustatus[4] = prev. interrupt enabled */ 39 | uintptr_t ustatus; 40 | uintptr_t uie; 41 | uintptr_t utval; 42 | uintptr_t uepc; 43 | uintptr_t ucause; 44 | // user mtimecmp emulation 45 | uint64_t deadline; 46 | // exception handlers 47 | uintptr_t trap_handlers[N_TRAPS]; 48 | } zone_t; 49 | 50 | /* Interrupt handler. */ 51 | typedef struct intrp_handler { 52 | /* The zone handling the interrupt */ 53 | zone_t* zone; 54 | /* The pointer to the interrupt handler */ 55 | uintptr_t handler; 56 | } intrp_handler_t; 57 | 58 | /* Kernel data */ 59 | typedef struct kernel { 60 | /* Scheduler data */ 61 | zone_t* current; 62 | uint64_t deadline; 63 | zone_t* next; 64 | uint64_t next_quantum; 65 | uintptr_t mie; 66 | uintptr_t intrp_mode; 67 | /* zone_t data */ 68 | zone_t zones[N_ZONES]; 69 | /* inbox_tes[receiver][sender]*/ 70 | inbox_t inboxes[N_ZONES][N_ZONES]; 71 | /* irq_num => handler mapping */ 72 | intrp_handler_t intrp_handlers[N_INTERRUPTS]; 73 | } kernel_t; 74 | 75 | /* The ONLY global data */ 76 | extern kernel_t kernel; 77 | 78 | #define KERNEL kernel 79 | #define ZONES (kernel.zones) 80 | #define INTRP_HANDLERS (kernel.intrp_handlers) 81 | #define INBOXES (kernel.inboxes) 82 | #define CURRENT (*kernel.current) 83 | 84 | /* Load zone/user context */ 85 | void restore_context(void) __attribute__((noreturn)); 86 | 87 | #endif // KERNEL_H 88 | -------------------------------------------------------------------------------- /libhexfive/libhexfive.S: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | 10 | #define ENTRY(x) \ 11 | .globl x; \ 12 | x: 13 | 14 | .section .text.libhexfive 15 | ENTRY(ECALL_YIELD) 16 | li a7, 0 # sys call #0 17 | ecall 18 | ret 19 | 20 | ENTRY(ECALL_WFI) 21 | li a7, 1 # sys call #1 22 | ecall 23 | ret 24 | 25 | ENTRY(ECALL_SEND) 26 | #if __riscv_xlen == 32 27 | lw a4, 12(a1) # load msg[3] 28 | lw a3, 8(a1) # load msg[2] 29 | lw a2, 4(a1) # load msg[1] 30 | lw a1, 0(a1) # load msg[0] 31 | #else 32 | ld a2, 8(a1) # load msg[2-3] 33 | ld a1, 0(a1) # load msg[0-1] 34 | #endif 35 | li a7, 2 # sys call #2 36 | ecall 37 | ret 38 | 39 | ENTRY(ECALL_RECV) 40 | mv a6, a1 # save pointer 41 | li a7, 3 # sys call #3 42 | ecall 43 | beqz a0, 1f # status == 0, go to ret 44 | #if __riscv_xlen == 32 45 | sw a4, 12(a6) # save msg[3] 46 | sw a3, 8(a6) # save msg[2] 47 | sw a2, 4(a6) # save msg[1] 48 | sw a1, 0(a6) # save msg[0] 49 | #else 50 | sd a2, 8(a6) # save msg[2-3] 51 | sd a1, 0(a6) # save msg[0-1] 52 | #endif 53 | 1: ret 54 | 55 | ENTRY(ECALL_TRP_VECT) 56 | li a7, 4 # sys call #4 57 | ecall 58 | ret 59 | 60 | ENTRY(ECALL_IRQ_VECT) 61 | li a7, 5 # sys call #5 62 | ecall 63 | ret 64 | 65 | ENTRY(ECALL_CSRS_MIE) 66 | li a7, 6 # sys call #6 67 | ecall 68 | ret 69 | 70 | ENTRY(ECALL_CSRC_MIE) 71 | li a7, 7 # sys call #7 72 | ecall 73 | ret 74 | 75 | ENTRY(ECALL_CSRW_MTIMECMP) 76 | li a7, 8 # sys call #8 77 | ecall 78 | ret 79 | 80 | ENTRY(ECALL_CSRR_MTIME) 81 | li a7, 9 # sys call #9 82 | ecall 83 | ret 84 | 85 | ENTRY(ECALL_CSRR_MCYCLE) 86 | li a7, 10 # sys call #10 87 | ecall 88 | ret 89 | 90 | ENTRY(ECALL_CSRR_MINSTR) 91 | li a7, 11 # sys call #11 92 | ecall 93 | ret 94 | 95 | ENTRY(ECALL_CSRR_MHPMC3) 96 | li a7, 12 # sys call #12 97 | ecall 98 | ret 99 | 100 | ENTRY(ECALL_CSRR_MHPMC4) 101 | li a7, 13 # sys call #13 102 | ecall 103 | ret 104 | 105 | 106 | ENTRY(ECALL_CSRR_MISA) 107 | li a7, 14 # sys call #14 108 | ecall 109 | ret 110 | 111 | ENTRY(ECALL_CSRR_MVENDID) 112 | li a7, 15 # sys call #15 113 | ecall 114 | ret 115 | 116 | ENTRY(ECALL_CSRR_MARCHID) 117 | li a7, 16 # sys call #16 118 | ecall 119 | ret 120 | 121 | ENTRY(ECALL_CSRR_MIMPID) 122 | li a7, 17 # sys call #17 123 | ecall 124 | ret 125 | 126 | ENTRY(ECALL_CSRR_MHARTID) 127 | li a7, 18 # sys call #18 128 | ecall 129 | ret 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenMZ 2 | OpenMZ is an open-source implementation of [HexFive's MultiZone API](https://github.com/hex-five/multizone-api). 3 | 4 | OpenMZ is a security kernel for RISC-V processors with machine-mode and user-mode. OpenMZ partitions a system into an unlimited number of zones. Each zone has full access to eight regions of memory-mapped I/O (e.g., RAM, UART, GPIO), protected using RISC-V's physical memory protection (PMP) mechanism. 5 | 6 | ## Features 7 | - Preemptive round-robin scheduler with a configurable time slices. 8 | - Self-contained and open-source, written in C and assembly. 9 | - Theoretically unlimited number of *spatially* isolated zones. 10 | - Up to eight memory-mapped I/O regions per zone with protections defined by you. 11 | - Support for user-mode platform-level and core-local interrupts. 12 | - Support for user-mode exception handling. 13 | - A secure user-mode timer interrupts emulation. 14 | - Fast register-based inter-zone communication. 15 | 16 | ## Attacker model 17 | - **Data attack.** A zone tries to access or modify the memory in an unauthorized manner. 18 | - **Timing attack.** A zone tries to infer information from another zone or the kernel using timing side-channel attacks. 19 | - **Cache attack.** A zone tries to infer information from another zone or the kernel using cache side-channel attacks. 20 | 21 | ## Kernel configuration 22 | The kernel's configurations is in [config.h](openmz/config.h). The PMP fields `pmpcfg0` and `pmpaddr[0-8]` are configured as in RISC-V's PMP registers `pmpcfg0` and `pmpaddr0-7`. The initial program counter is stored in `regs[0]`. Interrupt mappings are stored in the `irq_handlers` field. All of these configurations options are set in `config.h`. 23 | ```C 24 | /* ... */ 25 | /* number of zone */ 26 | #define N_ZONES 3 27 | 28 | /* max trap code */ 29 | #define N_TRAPS 12 30 | 31 | /* max interrupt code */ 32 | #define N_INTERRUPTS 12 33 | 34 | /* time slice in timer cycles */ 35 | #define QUANTUM (32768 / 100) 36 | 37 | /* Zone configuration */ 38 | /* ZONE(program counter, pmpcfg0, {pmpaddr0, ..., pmpaddr7}) */ 39 | #define ZONE_CONFIG \ 40 | ZONE(0x20020000, ..., ...) \ 41 | ZONE(0x20030000, ..., ...) \ 42 | ZONE(0x20040000, ..., ...) 43 | 44 | /* Mapping interrupts to zones */ 45 | /* IRQ(zone id, interrupt exception code) */ 46 | #define IRQ_CONFIG IRQ(1, 11) IRQ(2, 18) 47 | /* ... */ 48 | ``` 49 | 50 | ## (Potential) Future Work 51 | - Complete formal verification - from the hardware level to source code. 52 | - Implement `ECALL_WFI`. 53 | - `YIELD_TO` call - allowing zones to yield their remaining time slice to a specific zone. 54 | - An optional *temporal* isolation of zones by disabling `YIELD/WFI` calls, and immediate context switch for interrupts. 55 | - More advanced round-robin scheduling with more configurable zone order and time slices. 56 | - Compatibility with a secure bootloader, or a new secure bootloader. 57 | - System call for supporting remote attestation. 58 | - RISC-V user-interrupt extension (N extension) compatibility. 59 | - Multicore support. 60 | - Supervisor support. 61 | - More memory-mapped I/O regions per zone. 62 | - Inter-processor communication (IPC) - allowing communication with a Linux companion on a different core. 63 | 64 | *The above list is mostly sorted by priority.* 65 | ## Example zone implementation 66 | 67 | ## Attribution 68 | 69 | ## Copyright 70 | 71 | This project is under three different copyright licenses. HexFive's license for the MultiZone API (`libhexfive.h`), GPLv2 for the kernel and drivers, and MIT for the kernel configuration. The owner of the copyright of a source file is on the top. 72 | -------------------------------------------------------------------------------- /src/openmz/traps.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | #include "traps.h" 10 | 11 | #include "machine.h" 12 | #include "sched.h" 13 | 14 | #include "const.h" 15 | #include "kernel.h" 16 | 17 | typedef void (*handler_t)(uintptr_t, uintptr_t); 18 | static const handler_t intrp_handlers[12] = { 19 | [0] = handle_user_intrp, 20 | [1] = handle_user_intrp, 21 | [2] = handle_user_intrp, 22 | [3] = handle_user_intrp, 23 | [4] = handle_user_intrp, 24 | [5] = handle_user_intrp, 25 | [6] = handle_user_intrp, 26 | [7] = handle_user_timer, 27 | [8] = handle_user_intrp, 28 | [9] = handle_user_intrp, 29 | [10] = handle_user_intrp, 30 | [11] = handle_user_intrp 31 | }; 32 | 33 | static const handler_t excpt_handlers[12] = { 34 | [0] = handle_user_excpt, 35 | [1] = handle_user_excpt, 36 | [2] = handle_illegal_instruction, 37 | [3] = handle_user_excpt, 38 | [4] = handle_user_excpt, 39 | [5] = handle_user_excpt, 40 | [6] = handle_user_excpt, 41 | [7] = handle_user_excpt, 42 | [8] = handle_ecall, 43 | [9] = handle_user_excpt, 44 | [10] = handle_user_excpt, 45 | [11] = handle_user_excpt 46 | }; 47 | 48 | void handle_event(uintptr_t mcause, uintptr_t mtval) 49 | { 50 | if ((intptr_t)mcause < 0) { 51 | intrp_handlers[mcause & ~INTRP_BIT](mcause, mtval); 52 | } else { 53 | excpt_handlers[mcause](mcause, mtval); 54 | } 55 | sched(); 56 | restore_context(); 57 | } 58 | 59 | void handle_user_timer(uintptr_t mcause, uintptr_t mtval) 60 | { 61 | #if QUANTUM 62 | if ((CURRENT.ustatus & USTATUS_IE) && CURRENT.deadline && CURRENT.deadline < KERNEL.deadline) { 63 | // user timer must have trigger interrupt 64 | handle_user_excpt(UMODE_SOFT_TIMER, 0); 65 | CURRENT.deadline = 0; 66 | } 67 | #else 68 | handle_user_exception(UMODE_SOFT_TIMER, 0); 69 | CURRENT.deadline = 0; 70 | #endif 71 | } 72 | 73 | void handle_user_intrp(uintptr_t mcause, uintptr_t mtval) 74 | { 75 | intrp_handler_t intrp_handler = INTRP_HANDLERS[mcause & ~INTRP_BIT]; 76 | zone_t* zone = intrp_handler.zone; 77 | zone->uepc = zone->regs[PC]; 78 | zone->ucause = mcause; 79 | zone->utval = 0; 80 | zone->regs[PC] = intrp_handler.handler; 81 | zone->ustatus = USTATUS_PIE; 82 | KERNEL.mie &= ~zone->uie; 83 | sched_intrp(zone); 84 | } 85 | 86 | void handle_user_excpt(uintptr_t mcause, uintptr_t mtval) 87 | { 88 | zone_t* zone = KERNEL.current; 89 | uintptr_t handler = zone->trap_handlers[mcause]; 90 | zone->uepc = zone->regs[PC]; 91 | zone->ucause = mcause; 92 | zone->utval = mtval; 93 | zone->regs[PC] = handler; 94 | if (zone->ustatus & USTATUS_IE) { 95 | zone->ustatus = USTATUS_PIE; 96 | KERNEL.mie &= ~zone->uie; 97 | } 98 | } 99 | 100 | static inline void handle_uret(void) 101 | { 102 | /* restore trap values and pc */ 103 | zone_t* zone = KERNEL.current; 104 | zone->regs[PC] = zone->uepc; 105 | zone->ucause = 0; 106 | zone->uepc = 0; 107 | zone->utval = 0; 108 | /* restore trap handling */ 109 | if (zone->ustatus & USTATUS_PIE) { 110 | zone->ustatus |= USTATUS_IE; 111 | } 112 | if (KERNEL.intrp_mode) { 113 | KERNEL.deadline = read_mtime(); 114 | sched_yield(); 115 | } 116 | } 117 | 118 | void handle_illegal_instruction(uintptr_t mcause, uintptr_t mtval) 119 | { 120 | // mtval is an opcode 121 | if (mtval == OP_URET) { 122 | handle_uret(); 123 | } else { 124 | handle_user_excpt(mcause, mtval); 125 | } 126 | // TODO: add CSR instruction emulation 127 | } 128 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: WebKit 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: DontAlign 6 | AlignConsecutiveMacros: false 7 | AlignConsecutiveAssignments: false 8 | AlignConsecutiveDeclarations: false 9 | AlignEscapedNewlines: Right 10 | AlignOperands: false 11 | AlignTrailingComments: false 12 | AllowAllArgumentsOnNextLine: true 13 | AllowAllConstructorInitializersOnNextLine: true 14 | AllowAllParametersOfDeclarationOnNextLine: true 15 | AllowShortBlocksOnASingleLine: false 16 | AllowShortCaseLabelsOnASingleLine: false 17 | AllowShortFunctionsOnASingleLine: None 18 | AllowShortLambdasOnASingleLine: All 19 | AllowShortIfStatementsOnASingleLine: Never 20 | AllowShortLoopsOnASingleLine: false 21 | AlwaysBreakAfterDefinitionReturnType: None 22 | AlwaysBreakAfterReturnType: None 23 | AlwaysBreakBeforeMultilineStrings: false 24 | AlwaysBreakTemplateDeclarations: MultiLine 25 | BinPackArguments: true 26 | BinPackParameters: true 27 | BraceWrapping: 28 | AfterCaseLabel: false 29 | AfterClass: false 30 | AfterControlStatement: false 31 | AfterEnum: false 32 | AfterFunction: true 33 | AfterNamespace: false 34 | AfterObjCDeclaration: false 35 | AfterStruct: false 36 | AfterUnion: false 37 | AfterExternBlock: false 38 | BeforeCatch: false 39 | BeforeElse: false 40 | IndentBraces: false 41 | SplitEmptyFunction: true 42 | SplitEmptyRecord: true 43 | SplitEmptyNamespace: true 44 | BreakBeforeBinaryOperators: All 45 | BreakBeforeBraces: WebKit 46 | BreakBeforeInheritanceComma: false 47 | BreakInheritanceList: BeforeColon 48 | BreakBeforeTernaryOperators: true 49 | BreakConstructorInitializersBeforeComma: false 50 | BreakConstructorInitializers: BeforeComma 51 | BreakAfterJavaFieldAnnotations: false 52 | BreakStringLiterals: true 53 | ColumnLimit: 0 54 | CommentPragmas: '^ IWYU pragma:' 55 | CompactNamespaces: false 56 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 57 | ConstructorInitializerIndentWidth: 4 58 | ContinuationIndentWidth: 4 59 | Cpp11BracedListStyle: false 60 | DerivePointerAlignment: false 61 | DisableFormat: false 62 | ExperimentalAutoDetectBinPacking: false 63 | FixNamespaceComments: false 64 | ForEachMacros: 65 | - foreach 66 | - Q_FOREACH 67 | - BOOST_FOREACH 68 | IncludeBlocks: Preserve 69 | IncludeCategories: 70 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 71 | Priority: 2 72 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 73 | Priority: 3 74 | - Regex: '.*' 75 | Priority: 1 76 | IncludeIsMainRegex: '(Test)?$' 77 | IndentCaseLabels: false 78 | IndentPPDirectives: None 79 | IndentWidth: 4 80 | IndentWrappedFunctionNames: false 81 | JavaScriptQuotes: Leave 82 | JavaScriptWrapImports: true 83 | KeepEmptyLinesAtTheStartOfBlocks: true 84 | MacroBlockBegin: '' 85 | MacroBlockEnd: '' 86 | MaxEmptyLinesToKeep: 1 87 | NamespaceIndentation: Inner 88 | ObjCBinPackProtocolList: Auto 89 | ObjCBlockIndentWidth: 4 90 | ObjCSpaceAfterProperty: true 91 | ObjCSpaceBeforeProtocolList: true 92 | PenaltyBreakAssignment: 2 93 | PenaltyBreakBeforeFirstCallParameter: 19 94 | PenaltyBreakComment: 300 95 | PenaltyBreakFirstLessLess: 120 96 | PenaltyBreakString: 1000 97 | PenaltyBreakTemplateDeclaration: 10 98 | PenaltyExcessCharacter: 1000000 99 | PenaltyReturnTypeOnItsOwnLine: 60 100 | PointerAlignment: Left 101 | ReflowComments: true 102 | SortIncludes: true 103 | SortUsingDeclarations: true 104 | SpaceAfterCStyleCast: false 105 | SpaceAfterLogicalNot: false 106 | SpaceAfterTemplateKeyword: true 107 | SpaceBeforeAssignmentOperators: true 108 | SpaceBeforeCpp11BracedList: true 109 | SpaceBeforeCtorInitializerColon: true 110 | SpaceBeforeInheritanceColon: true 111 | SpaceBeforeParens: ControlStatements 112 | SpaceBeforeRangeBasedForLoopColon: true 113 | SpaceInEmptyParentheses: false 114 | SpacesBeforeTrailingComments: 1 115 | SpacesInAngles: false 116 | SpacesInContainerLiterals: true 117 | SpacesInCStyleCastParentheses: false 118 | SpacesInParentheses: false 119 | SpacesInSquareBrackets: false 120 | Standard: Cpp11 121 | StatementMacros: 122 | - Q_UNUSED 123 | - QT_REQUIRE_VERSION 124 | TabWidth: 4 125 | UseTab: Never 126 | ... 127 | 128 | -------------------------------------------------------------------------------- /src/openmz/traps.S: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | #include "macro.h" 10 | 11 | .extern kernel_stack 12 | .extern __global_pointer$ 13 | .extern HandleEvent 14 | .extern Scheduler 15 | 16 | .globl asm_trap_entry 17 | .globl asm_restore_context 18 | 19 | .align 4 20 | // void asm_trap_entry(void) 21 | asm_trap_entry: 22 | // load regs, store user a0 23 | csrrw a0, mscratch, a0 24 | beqz a0, hang 25 | // save x1-x31 to regs 26 | REG_S ra, (REGBYTES * RA)(a0) 27 | REG_S sp, (REGBYTES * SP)(a0) 28 | REG_S gp, (REGBYTES * GP)(a0) 29 | REG_S tp, (REGBYTES * TP)(a0) 30 | REG_S t0, (REGBYTES * T0)(a0) 31 | REG_S t1, (REGBYTES * T1)(a0) 32 | REG_S t2, (REGBYTES * T2)(a0) 33 | REG_S s0, (REGBYTES * S0)(a0) 34 | REG_S s1, (REGBYTES * S1)(a0) 35 | REG_S a1, (REGBYTES * A1)(a0) 36 | REG_S a2, (REGBYTES * A2)(a0) 37 | REG_S a3, (REGBYTES * A3)(a0) 38 | REG_S a4, (REGBYTES * A4)(a0) 39 | REG_S a5, (REGBYTES * A5)(a0) 40 | REG_S a6, (REGBYTES * A6)(a0) 41 | REG_S a7, (REGBYTES * A7)(a0) 42 | REG_S s2, (REGBYTES * S2)(a0) 43 | REG_S s3, (REGBYTES * S3)(a0) 44 | REG_S s4, (REGBYTES * S4)(a0) 45 | REG_S s5, (REGBYTES * S5)(a0) 46 | REG_S s6, (REGBYTES * S6)(a0) 47 | REG_S s7, (REGBYTES * S7)(a0) 48 | REG_S s8, (REGBYTES * S8)(a0) 49 | REG_S s9, (REGBYTES * S9)(a0) 50 | REG_S s10, (REGBYTES * S10)(a0) 51 | REG_S s11, (REGBYTES * S11)(a0) 52 | REG_S t3, (REGBYTES * T3)(a0) 53 | REG_S t4, (REGBYTES * T4)(a0) 54 | REG_S t5, (REGBYTES * T5)(a0) 55 | REG_S t6, (REGBYTES * T6)(a0) 56 | csrrw t0, mscratch, x0 57 | REG_S t0, (REGBYTES * A0)(a0) 58 | // save pc to regs 59 | csrr t0, mepc 60 | REG_S t0, (REGBYTES * PC)(a0) 61 | 62 | // load kernel gp and sp 63 | .option push 64 | .option norelax 65 | la gp, __global_pointer$ 66 | .option pop 67 | la sp, _sp 68 | 69 | // get arguments mcause, mtval 70 | csrr a0, mcause 71 | csrr a1, mtval 72 | tail handle_event 73 | 74 | 75 | /** 76 | * void asm_restore_context(regs, pmpcfg, pmpaddr) 77 | * Restores the zone's context from its register `regs`. 78 | * Does not setup the pmp registers. 79 | */ 80 | asm_restore_context: 81 | mv s0, a0 82 | mv s1, a1 83 | mv s2, a2 84 | // load pmpaddr 85 | REG_L a0, (REGBYTES * 0)(s2) 86 | REG_L a1, (REGBYTES * 1)(s2) 87 | REG_L a2, (REGBYTES * 2)(s2) 88 | REG_L a3, (REGBYTES * 3)(s2) 89 | REG_L a4, (REGBYTES * 4)(s2) 90 | REG_L a5, (REGBYTES * 5)(s2) 91 | REG_L a6, (REGBYTES * 6)(s2) 92 | REG_L a7, (REGBYTES * 7)(s2) 93 | csrw pmpaddr0, a0 94 | csrw pmpaddr1, a1 95 | csrw pmpaddr2, a2 96 | csrw pmpaddr3, a3 97 | csrw pmpaddr4, a4 98 | csrw pmpaddr5, a5 99 | csrw pmpaddr6, a6 100 | csrw pmpaddr7, a7 101 | 102 | // load pmpcfg 103 | REG_L a0, 0(s1) 104 | csrw pmpcfg0, a0 105 | #if __riscv_xlen == 32 106 | REG_L a1, REGBYTES(s1) 107 | csrw pmpcfg1, a1 108 | #endif 109 | 110 | // save pointer to regs[32] 111 | csrw mscratch, s0 112 | // load pc from regs 113 | REG_L t0, (REGBYTES * PC)(s0) 114 | csrw mepc, t0 115 | // load x1-x31 from regs 116 | REG_L ra, (REGBYTES * RA)(s0) 117 | REG_L sp, (REGBYTES * SP)(s0) 118 | REG_L gp, (REGBYTES * GP)(s0) 119 | REG_L tp, (REGBYTES * TP)(s0) 120 | REG_L t0, (REGBYTES * T0)(s0) 121 | REG_L t1, (REGBYTES * T1)(s0) 122 | REG_L t2, (REGBYTES * T2)(s0) 123 | REG_L s1, (REGBYTES * S1)(s0) 124 | REG_L a0, (REGBYTES * A0)(s0) 125 | REG_L a1, (REGBYTES * A1)(s0) 126 | REG_L a2, (REGBYTES * A2)(s0) 127 | REG_L a3, (REGBYTES * A3)(s0) 128 | REG_L a4, (REGBYTES * A4)(s0) 129 | REG_L a5, (REGBYTES * A5)(s0) 130 | REG_L a6, (REGBYTES * A6)(s0) 131 | REG_L a7, (REGBYTES * A7)(s0) 132 | REG_L s2, (REGBYTES * S2)(s0) 133 | REG_L s3, (REGBYTES * S3)(s0) 134 | REG_L s4, (REGBYTES * S4)(s0) 135 | REG_L s5, (REGBYTES * S5)(s0) 136 | REG_L s6, (REGBYTES * S6)(s0) 137 | REG_L s7, (REGBYTES * S7)(s0) 138 | REG_L s8, (REGBYTES * S8)(s0) 139 | REG_L s9, (REGBYTES * S9)(s0) 140 | REG_L s10,(REGBYTES * S10)(s0) 141 | REG_L s11,(REGBYTES * S11)(s0) 142 | REG_L t3, (REGBYTES * T3)(s0) 143 | REG_L t4, (REGBYTES * T4)(s0) 144 | REG_L t5, (REGBYTES * T5)(s0) 145 | REG_L t6, (REGBYTES * T6)(s0) 146 | REG_L s0, (REGBYTES * S0)(s0) 147 | // go to user mode 148 | mret 149 | 150 | hang: 151 | ebreak 152 | j hang 153 | -------------------------------------------------------------------------------- /src/openmz/ecall.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020, Saab AB 3 | * 4 | * This software may be distributed and modified according to 5 | * the terms of the GNU General Public License version 2. 6 | * Note that NO WARRANTY is provided. 7 | * See "LICENSE.GPLv2" for details. 8 | */ 9 | 10 | #include "machine.h" 11 | #include "sched.h" 12 | 13 | #include "const.h" 14 | #include "csr.h" 15 | #include "kernel.h" 16 | #include "macro.h" 17 | #include "traps.h" 18 | 19 | /* handler takes a caller and its argument registers a0-a7 */ 20 | typedef void (*handler_t)(zone_t* caller, uintptr_t args[8]); 21 | 22 | /* ECALL numbers */ 23 | #define ECALL_YIELD 0 24 | #define ECALL_WFI 1 25 | #define ECALL_SEND 2 26 | #define ECALL_RECV 3 27 | #define ECALL_TRP_VECT 4 28 | #define ECALL_IRQ_VECT 5 29 | #define ECALL_CSRS_MIE 6 30 | #define ECALL_CSRC_MIE 7 31 | #define ECALL_CSRW_MTIMECMP 8 32 | #define ECALL_CSRR_MTIME 9 33 | #define ECALL_CSRR_MCYCLE 10 34 | #define ECALL_CSRR_MINSTR 11 35 | #define ECALL_CSRR_MHPMC3 12 36 | #define ECALL_CSRR_MHPMC4 13 37 | #define ECALL_CSRR_MISA 14 38 | #define ECALL_CSRR_MVENDID 15 39 | #define ECALL_CSRR_MARCHID 16 40 | #define ECALL_CSRR_MIMPID 17 41 | #define ECALL_CSRR_MHARTID 18 42 | 43 | void ecall_yield(zone_t* caller, uintptr_t args[8]) 44 | { 45 | KERNEL.deadline = read_mtime(); 46 | sched_yield(); 47 | } 48 | 49 | static void ecall_send(zone_t* caller, uintptr_t args[8]) 50 | { 51 | uintptr_t receiver = args[0] - 1; 52 | args[0] = 0; 53 | if (receiver >= N_ZONES) 54 | return; 55 | inbox_t* inbox = &INBOXES[receiver][caller->id - 1]; 56 | if (inbox->full) 57 | return; 58 | inbox->full = 1; 59 | for (int i = 0; i < N_MSGS; ++i) 60 | inbox->msgs[i] = args[1 + i]; 61 | args[0] = 1; 62 | } 63 | 64 | static void ecall_recv(zone_t* caller, uintptr_t args[8]) 65 | { 66 | uintptr_t sender = args[0] - 1; 67 | args[0] = 0; 68 | if (sender >= N_ZONES) 69 | return; 70 | inbox_t* inbox = &INBOXES[caller->id - 1][sender]; 71 | if (!inbox->full) 72 | return; 73 | inbox->full = 0; 74 | for (int i = 0; i < N_MSGS; ++i) 75 | args[i + 1] = inbox->msgs[i]; 76 | args[0] = 1; 77 | } 78 | 79 | static void ecall_trp_vect(zone_t* caller, uintptr_t args[8]) 80 | { 81 | uintptr_t code = args[0]; 82 | uintptr_t handler = args[1]; 83 | if (code >= N_TRAPS) 84 | return; 85 | caller->trap_handlers[code] = handler; 86 | if (code == UMODE_SOFT_TIMER) 87 | caller->deadline = 0; 88 | } 89 | 90 | static void ecall_irq_vect(zone_t* caller, uintptr_t args[8]) 91 | { 92 | uintptr_t code = args[0]; 93 | uintptr_t handler = args[1]; 94 | if ((code >= N_INTERRUPTS) || (INTRP_HANDLERS[code].zone != caller)) 95 | return; 96 | INTRP_HANDLERS[code].handler = handler; 97 | if (handler) { 98 | caller->uie |= (1 << code); 99 | if (caller->ustatus & USTATUS_IE) { 100 | KERNEL.mie |= (1 << code); 101 | } 102 | } else { 103 | caller->uie &= ~(1 << code); 104 | if (caller->ustatus & USTATUS_IE) { 105 | KERNEL.mie &= ~(1 << code); 106 | } 107 | } 108 | } 109 | 110 | static void ecall_csrs_mie(zone_t* caller, uintptr_t UNUSED(args[8])) 111 | { 112 | caller->ustatus |= USTATUS_IE; 113 | KERNEL.mie |= caller->uie; 114 | } 115 | 116 | static void ecall_csrc_mie(zone_t* caller, uintptr_t UNUSED(args[8])) 117 | { 118 | caller->ustatus &= ~USTATUS_IE; 119 | KERNEL.mie &= ~caller->uie; 120 | } 121 | 122 | static void ecall_csrw_mtimecmp(zone_t* caller, uintptr_t args[8]) 123 | { 124 | caller->deadline = *((uint64_t*)args); 125 | } 126 | 127 | static void ecall_csrr_mtime(zone_t* caller, uintptr_t args[8]) 128 | { 129 | *((uint64_t*)args) = read_mtime(); 130 | } 131 | 132 | static void ecall_csrr_mcycle(zone_t* caller, uintptr_t args[8]) 133 | { 134 | CSRR_COUNTER(args[0], mcycle); 135 | } 136 | 137 | static void ecall_csrr_minstr(zone_t* caller, uintptr_t args[8]) 138 | { 139 | CSRR_COUNTER(args[0], minstret); 140 | } 141 | 142 | static void ecall_csrr_mhpmc3(zone_t* caller, uintptr_t args[8]) 143 | { 144 | CSRR_COUNTER(args[0], mhpmcounter3); 145 | } 146 | 147 | static void ecall_csrr_mhpmc4(zone_t* caller, uintptr_t args[8]) 148 | { 149 | CSRR_COUNTER(args[0], mhpmcounter4); 150 | } 151 | 152 | static void ecall_csrr_misa(zone_t* caller, uintptr_t args[8]) 153 | { 154 | CSRR64(args[0], misa); 155 | } 156 | 157 | static void ecall_csrr_mvendid(zone_t* caller, uintptr_t args[8]) 158 | { 159 | CSRR64(args[0], mvendorid); 160 | } 161 | 162 | static void ecall_csrr_marchid(zone_t* caller, uintptr_t args[8]) 163 | { 164 | CSRR64(args[0], marchid); 165 | } 166 | 167 | static void ecall_csrr_mimpid(zone_t* caller, uintptr_t args[8]) 168 | { 169 | CSRR64(args[0], mimpid); 170 | } 171 | 172 | static void ecall_csrr_mhartid(zone_t* caller, uintptr_t args[8]) 173 | { 174 | CSRR64(args[0], mhartid); 175 | } 176 | 177 | static const handler_t ecall_handlers[] = { 178 | [ECALL_YIELD] = ecall_yield, 179 | [ECALL_WFI] = ecall_yield, 180 | [ECALL_SEND] = ecall_send, 181 | [ECALL_RECV] = ecall_recv, 182 | [ECALL_TRP_VECT] = ecall_trp_vect, 183 | [ECALL_IRQ_VECT] = ecall_irq_vect, 184 | [ECALL_CSRS_MIE] = ecall_csrs_mie, 185 | [ECALL_CSRC_MIE] = ecall_csrc_mie, 186 | [ECALL_CSRW_MTIMECMP] = ecall_csrw_mtimecmp, 187 | [ECALL_CSRR_MTIME] = ecall_csrr_mtime, 188 | [ECALL_CSRR_MCYCLE] = ecall_csrr_mcycle, 189 | [ECALL_CSRR_MINSTR] = ecall_csrr_minstr, 190 | [ECALL_CSRR_MHPMC3] = ecall_csrr_mhpmc3, 191 | [ECALL_CSRR_MHPMC4] = ecall_csrr_mhpmc4, 192 | [ECALL_CSRR_MISA] = ecall_csrr_misa, 193 | [ECALL_CSRR_MVENDID] = ecall_csrr_mvendid, 194 | [ECALL_CSRR_MARCHID] = ecall_csrr_marchid, 195 | [ECALL_CSRR_MIMPID] = ecall_csrr_mimpid, 196 | [ECALL_CSRR_MHARTID] = ecall_csrr_mhartid, 197 | }; 198 | 199 | void handle_ecall(uintptr_t mcause, uintptr_t mtval) 200 | { 201 | /* ecall table */ 202 | 203 | zone_t* caller = &CURRENT; 204 | /* always advance PC! */ 205 | caller->regs[PC] += 4; 206 | uintptr_t ecall = caller->regs[A7]; 207 | if (ecall < ARRAY_LEN(ecall_handlers)) 208 | ecall_handlers[ecall](caller, caller->regs + A0); 209 | } 210 | -------------------------------------------------------------------------------- /scripts/apply-format: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # 3 | # Copyright 2018 Undo Ltd. 4 | # 5 | # https://github.com/barisione/clang-format-hooks 6 | 7 | # Force variable declaration before access. 8 | set -u 9 | # Make any failure in piped commands be reflected in the exit code. 10 | set -o pipefail 11 | 12 | readonly bash_source="${BASH_SOURCE[0]:-$0}" 13 | 14 | ################## 15 | # Misc functions # 16 | ################## 17 | 18 | function error_exit() { 19 | for str in "$@"; do 20 | echo -n "$str" >&2 21 | done 22 | echo >&2 23 | 24 | exit 1 25 | } 26 | 27 | 28 | ######################## 29 | # Command line parsing # 30 | ######################## 31 | 32 | function show_help() { 33 | if [ -t 1 ] && hash tput 2> /dev/null; then 34 | local -r b=$(tput bold) 35 | local -r i=$(tput sitm) 36 | local -r n=$(tput sgr0) 37 | else 38 | local -r b= 39 | local -r i= 40 | local -r n= 41 | fi 42 | 43 | cat << EOF 44 | ${b}SYNOPSIS${n} 45 | 46 | To reformat git diffs: 47 | 48 | ${i}$bash_source [OPTIONS] [FILES-OR-GIT-DIFF-OPTIONS]${n} 49 | 50 | To reformat whole files, including unchanged parts: 51 | 52 | ${i}$bash_source [-f | --whole-file] FILES${n} 53 | 54 | ${b}DESCRIPTION${n} 55 | 56 | Reformat C or C++ code to match a specified formatting style. 57 | 58 | This command can either work on diffs, to reformat only changed parts of 59 | the code, or on whole files (if -f or --whole-file is used). 60 | 61 | ${b}FILES-OR-GIT-DIFF-OPTIONS${n} 62 | List of files to consider when applying clang-format to a diff. This is 63 | passed to "git diff" as is, so it can also include extra git options or 64 | revisions. 65 | For example, to apply clang-format on the changes made in the last few 66 | revisions you could use: 67 | ${i}\$ $bash_source HEAD~3${n} 68 | 69 | ${b}FILES${n} 70 | List of files to completely reformat. 71 | 72 | ${b}-f, --whole-file${n} 73 | Reformat the specified files completely (including parts you didn't 74 | change). 75 | The fix is printed on stdout by default. Use -i if you want to modify 76 | the files on disk. 77 | 78 | ${b}--staged, --cached${n} 79 | Reformat only code which is staged for commit. 80 | The fix is printed on stdout by default. Use -i if you want to modify 81 | the files on disk. 82 | 83 | ${b}-i${n} 84 | Reformat the code and apply the changes to the files on disk (instead 85 | of just printing the fix on stdout). 86 | 87 | ${b}--apply-to-staged${n} 88 | This is like specifying both --staged and -i, but the formatting 89 | changes are also staged for commit (so you can just use "git commit" 90 | to commit what you planned to, but formatted correctly). 91 | 92 | ${b}--style STYLE${n} 93 | The style to use for reformatting code. 94 | If no style is specified, then it's assumed there's a .clang-format 95 | file in the current directory or one of its parents. 96 | 97 | ${b}--help, -h, -?${n} 98 | Show this help. 99 | EOF 100 | } 101 | 102 | # getopts doesn't support long options. 103 | # getopt mangles stuff. 104 | # So we parse manually... 105 | declare positionals=() 106 | declare has_positionals=false 107 | declare whole_file=false 108 | declare apply_to_staged=false 109 | declare staged=false 110 | declare in_place=false 111 | declare style=file 112 | declare ignored=() 113 | while [ $# -gt 0 ]; do 114 | declare arg="$1" 115 | shift # Past option. 116 | case "$arg" in 117 | -h | -\? | --help ) 118 | show_help 119 | exit 0 120 | ;; 121 | -f | --whole-file ) 122 | whole_file=true 123 | ;; 124 | --apply-to-staged ) 125 | apply_to_staged=true 126 | ;; 127 | --cached | --staged ) 128 | staged=true 129 | ;; 130 | -i ) 131 | in_place=true 132 | ;; 133 | --style=* ) 134 | style="${arg//--style=/}" 135 | ;; 136 | --style ) 137 | [ $# -gt 0 ] || \ 138 | error_exit "No argument for --style option." 139 | style="$1" 140 | shift 141 | ;; 142 | --internal-opt-ignore-regex=* ) 143 | ignored+=("${arg//--internal-opt-ignore-regex=/}") 144 | ;; 145 | --internal-opt-ignore-regex ) 146 | ignored+=("${arg//--internal-opt-ignore-regex=/}") 147 | [ $# -gt 0 ] || \ 148 | error_exit "No argument for --internal-opt-ignore-regex option." 149 | ignored+=("$1") 150 | shift 151 | ;; 152 | -- ) 153 | # Stop processing further arguments. 154 | if [ $# -gt 0 ]; then 155 | positionals+=("$@") 156 | has_positionals=true 157 | fi 158 | break 159 | ;; 160 | -* ) 161 | error_exit "Unknown argument: $arg" 162 | ;; 163 | *) 164 | positionals+=("$arg") 165 | ;; 166 | esac 167 | done 168 | 169 | # Restore positional arguments, access them from "$@". 170 | if [ ${#positionals[@]} -gt 0 ]; then 171 | set -- "${positionals[@]}" 172 | has_positionals=true 173 | fi 174 | 175 | [ -n "$style" ] || \ 176 | error_exit "If you use --style you need to specify a valid style." 177 | 178 | ####################################### 179 | # Detection of clang-format & friends # 180 | ####################################### 181 | 182 | # clang-format. 183 | declare format="${CLANG_FORMAT:-}" 184 | if [ -z "$format" ]; then 185 | format=$(type -p clang-format) 186 | fi 187 | 188 | if [ -z "$format" ]; then 189 | error_exit \ 190 | $'You need to install clang-format.\n' \ 191 | $'\n' \ 192 | $'On Ubuntu/Debian this is available in the clang-format package or, in\n' \ 193 | $'older distro versions, clang-format-VERSION.\n' \ 194 | $'On Fedora it\'s available in the clang package.\n' \ 195 | $'You can also specify your own path for clang-format by setting the\n' \ 196 | $'$CLANG_FORMAT environment variable.' 197 | fi 198 | 199 | # clang-format-diff. 200 | if [ "$whole_file" = false ]; then 201 | invalid="/dev/null/invalid/path" 202 | if [ "${OSTYPE:-}" = "linux-gnu" ]; then 203 | readonly sort_version=-V 204 | else 205 | # On macOS, sort doesn't have -V. 206 | readonly sort_version=-n 207 | fi 208 | declare paths_to_try=() 209 | # .deb packages directly from upstream. 210 | # We try these first as they are probably newer than the system ones. 211 | while read -r f; do 212 | paths_to_try+=("$f") 213 | done < <(compgen -G "/usr/share/clang/clang-format-*/clang-format-diff.py" | sort "$sort_version" -r) 214 | # LLVM official releases (just untarred in /usr/local). 215 | while read -r f; do 216 | paths_to_try+=("$f") 217 | done < <(compgen -G "/usr/local/clang+llvm*/share/clang/clang-format-diff.py" | sort "$sort_version" -r) 218 | # Maybe it's in the $PATH already? This is true for Ubuntu and Debian. 219 | paths_to_try+=( \ 220 | "$(type -p clang-format-diff 2> /dev/null || echo "$invalid")" \ 221 | "$(type -p clang-format-diff.py 2> /dev/null || echo "$invalid")" \ 222 | ) 223 | # Fedora. 224 | paths_to_try+=( \ 225 | /usr/share/clang/clang-format-diff.py \ 226 | ) 227 | # Gentoo. 228 | while read -r f; do 229 | paths_to_try+=("$f") 230 | done < <(compgen -G "/usr/lib/llvm/*/share/clang/clang-format-diff.py" | sort -n -r) 231 | # Homebrew. 232 | while read -r f; do 233 | paths_to_try+=("$f") 234 | done < <(compgen -G "/usr/local/Cellar/clang-format/*/share/clang/clang-format-diff.py" | sort -n -r) 235 | 236 | declare format_diff= 237 | 238 | # Did the user specify a path? 239 | if [ -n "${CLANG_FORMAT_DIFF:-}" ]; then 240 | format_diff="$CLANG_FORMAT_DIFF" 241 | else 242 | for path in "${paths_to_try[@]}"; do 243 | if [ -e "$path" ]; then 244 | # Found! 245 | format_diff="$path" 246 | if [ ! -x "$format_diff" ]; then 247 | format_diff="python $format_diff" 248 | fi 249 | break 250 | fi 251 | done 252 | fi 253 | 254 | if [ -z "$format_diff" ]; then 255 | error_exit \ 256 | $'Cannot find clang-format-diff which should be shipped as part of the same\n' \ 257 | $'package where clang-format is.\n' \ 258 | $'\n' \ 259 | $'Please find out where clang-format-diff is in your distro and report an issue\n' \ 260 | $'at https://github.com/barisione/clang-format-hooks/issues with details about\n' \ 261 | $'your operating system and setup.\n' \ 262 | $'\n' \ 263 | $'You can also specify your own path for clang-format-diff by setting the\n' \ 264 | $'$CLANG_FORMAT_DIFF environment variable, for instance:\n' \ 265 | $'\n' \ 266 | $' CLANG_FORMAT_DIFF="python /.../clang-format-diff.py" \\\n' \ 267 | $' ' "$bash_source" 268 | fi 269 | 270 | readonly format_diff 271 | fi 272 | 273 | 274 | ############################ 275 | # Actually run the command # 276 | ############################ 277 | 278 | if [ "$whole_file" = true ]; then 279 | 280 | [ "$has_positionals" = true ] || \ 281 | error_exit "No files to reformat specified." 282 | [ "$staged" = false ] || \ 283 | error_exit "--staged/--cached only make sense when applying to a diff." 284 | 285 | read -r -a format_args <<< "$format" 286 | format_args+=("-style=file") 287 | [ "$in_place" = true ] && format_args+=("-i") 288 | 289 | "${format_args[@]}" "$@" 290 | 291 | else # Diff-only. 292 | 293 | if [ "$apply_to_staged" = true ]; then 294 | [ "$staged" = false ] || \ 295 | error_exit "You don't need --staged/--cached with --apply-to-staged." 296 | [ "$in_place" = false ] || \ 297 | error_exit "You don't need -i with --apply-to-staged." 298 | staged=true 299 | readonly patch_dest=$(mktemp) 300 | trap '{ rm -f "$patch_dest"; }' EXIT 301 | else 302 | readonly patch_dest=/dev/stdout 303 | fi 304 | 305 | declare git_args=(git diff -U0 --no-color) 306 | [ "$staged" = true ] && git_args+=("--staged") 307 | 308 | # $format_diff may contain a command ("python") and the script to excute, so we 309 | # need to split it. 310 | read -r -a format_diff_args <<< "$format_diff" 311 | [ "$in_place" = true ] && format_diff_args+=("-i") 312 | 313 | # Build the regex for paths to consider or ignore. 314 | # We use negative lookahead assertions which preceed the list of allowed patterns 315 | # (that is, the extensions we want). 316 | exclusions_regex= 317 | if [ "${#ignored[@]}" -gt 0 ]; then 318 | for pattern in "${ignored[@]}"; do 319 | exclusions_regex="$exclusions_regex(?!$pattern)" 320 | done 321 | fi 322 | 323 | "${git_args[@]}" "$@" \ 324 | | "${format_diff_args[@]}" \ 325 | -p1 \ 326 | -style="$style" \ 327 | -iregex="$exclusions_regex"'.*\.(c|cpp|cxx|cc|h|hpp|m|mm|js|java)' \ 328 | > "$patch_dest" \ 329 | || exit 1 330 | 331 | if [ "$apply_to_staged" = true ]; then 332 | if [ ! -s "$patch_dest" ]; then 333 | echo "No formatting changes to apply." 334 | exit 0 335 | fi 336 | patch -p0 < "$patch_dest" || \ 337 | error_exit "Cannot apply fix to local files." 338 | git apply -p0 --cached < "$patch_dest" || \ 339 | error_exit "Cannot apply fix to git staged changes." 340 | fi 341 | 342 | fi 343 | -------------------------------------------------------------------------------- /scripts/git-pre-commit-format: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # 3 | # Copyright 2018 Undo Ltd. 4 | # 5 | # https://github.com/barisione/clang-format-hooks 6 | 7 | # Force variable declaration before access. 8 | set -u 9 | # Make any failure in piped commands be reflected in the exit code. 10 | set -o pipefail 11 | 12 | readonly bash_source="${BASH_SOURCE[0]:-$0}" 13 | 14 | if [ -t 1 ] && hash tput 2> /dev/null; then 15 | readonly b=$(tput bold) 16 | readonly i=$(tput sitm) 17 | readonly n=$(tput sgr0) 18 | else 19 | readonly b= 20 | readonly i= 21 | readonly n= 22 | fi 23 | 24 | function error_exit() { 25 | for str in "$@"; do 26 | echo -n "$b$str$n" >&2 27 | done 28 | echo >&2 29 | 30 | exit 1 31 | } 32 | 33 | # realpath is not available everywhere. 34 | function realpath() { 35 | if [ "${OSTYPE:-}" = "linux-gnu" ]; then 36 | readlink -m "$@" 37 | else 38 | # Python should always be available on macOS. 39 | # We use sys.stdout.write instead of print so it's compatible with both Python 2 and 3. 40 | python -c "import sys; import os.path; sys.stdout.write(os.path.realpath('''$1''') + '\\n')" 41 | fi 42 | } 43 | 44 | # realpath --relative-to is only available on recent Linux distros. 45 | # This function behaves identical to Python's os.path.relpath() and doesn't need files to exist. 46 | function rel_realpath() { 47 | local -r path=$(realpath "$1") 48 | local -r rel_to=$(realpath "${2:-$PWD}") 49 | 50 | # Split the paths into components. 51 | IFS='/' read -r -a path_parts <<< "$path" 52 | IFS='/' read -r -a rel_to_parts <<< "$rel_to" 53 | 54 | # Search for the first different component. 55 | for ((idx=1; idx<${#path_parts[@]}; idx++)); do 56 | if [ "${path_parts[idx]}" != "${rel_to_parts[idx]:-}" ]; then 57 | break 58 | fi 59 | done 60 | 61 | result=() 62 | # Add the required ".." to the $result array. 63 | local -r first_different_idx="$idx" 64 | for ((idx=first_different_idx; idx<${#rel_to_parts[@]}; idx++)); do 65 | result+=("..") 66 | done 67 | # Add the required components from $path. 68 | for ((idx=first_different_idx; idx<${#path_parts[@]}; idx++)); do 69 | result+=("${path_parts[idx]}") 70 | done 71 | 72 | if [ "${#result[@]}" -gt 0 ]; then 73 | # Join the array with a "/" as separator. 74 | echo "$(export IFS='/'; echo "${result[*]}")" 75 | else 76 | echo . 77 | fi 78 | } 79 | 80 | # Find the top-level git directory (taking into account we could be in a submodule). 81 | declare git_test_dir=. 82 | declare top_dir 83 | 84 | while true; do 85 | top_dir=$(git -C "$git_test_dir" rev-parse --show-toplevel) || \ 86 | error_exit "You need to be in the git repository to run this script." 87 | 88 | # Try to handle git worktree. 89 | # The best way to deal both with git submodules and worktrees would be to 90 | # use --show-superproject-working-tree, but it's not supported in git 2.7.4 91 | # which is shipped in Ubuntu 16.04. 92 | declare git_common_dir 93 | if git_common_dir=$(git -C "$git_test_dir" rev-parse --git-common-dir 2>/dev/null); then 94 | # The common dir could be relative, so we make it absolute. 95 | git_common_dir=$(cd "$git_test_dir" && realpath "$git_common_dir") 96 | declare maybe_top_dir 97 | maybe_top_dir=$(realpath "$git_common_dir/..") 98 | if [ -e "$maybe_top_dir/.git" ]; then 99 | # We are not in a submodules, otherwise common dir would have been 100 | # something like PROJ/.git/modules/SUBMODULE and there would not be 101 | # a .git directory in PROJ/.git/modules/. 102 | top_dir="$maybe_top_dir" 103 | fi 104 | fi 105 | 106 | [ -e "$top_dir/.git" ] || \ 107 | error_exit "No .git directory in $top_dir." 108 | 109 | if [ -d "$top_dir/.git" ]; then 110 | # We are done! top_dir is the root git directory. 111 | break 112 | elif [ -f "$top_dir/.git" ]; then 113 | # We are in a submodule. 114 | git_test_dir="$git_test_dir/.." 115 | fi 116 | done 117 | 118 | readonly top_dir 119 | 120 | hook_path="$top_dir/.git/hooks/pre-commit" 121 | readonly hook_path 122 | 123 | me=$(realpath "$bash_source") || exit 1 124 | readonly me 125 | 126 | me_relative_to_hook=$(rel_realpath "$me" "$(dirname "$hook_path")") || exit 1 127 | readonly me_relative_to_hook 128 | 129 | my_dir=$(dirname "$me") || exit 1 130 | readonly my_dir 131 | 132 | apply_format="$my_dir/apply-format" 133 | readonly apply_format 134 | 135 | apply_format_relative_to_top_dir=$(rel_realpath "$apply_format" "$top_dir") || exit 1 136 | readonly apply_format_relative_to_top_dir 137 | 138 | function is_installed() { 139 | if [ ! -e "$hook_path" ]; then 140 | echo nothing 141 | else 142 | existing_hook_target=$(realpath "$hook_path") || exit 1 143 | readonly existing_hook_target 144 | 145 | if [ "$existing_hook_target" = "$me" ]; then 146 | # Already installed. 147 | echo installed 148 | else 149 | # There's a hook, but it's not us. 150 | echo different 151 | fi 152 | fi 153 | } 154 | 155 | function install() { 156 | if ln -s "$me_relative_to_hook" "$hook_path" 2> /dev/null; then 157 | echo "Pre-commit hook installed." 158 | else 159 | local -r res=$(is_installed) 160 | if [ "$res" = installed ]; then 161 | error_exit "The hook is already installed." 162 | elif [ "$res" = different ]; then 163 | error_exit "There's already an existing pre-commit hook, but for something else." 164 | elif [ "$res" = nothing ]; then 165 | error_exit "There's no pre-commit hook, but we couldn't create a symlink." 166 | else 167 | error_exit "Unexpected failure." 168 | fi 169 | fi 170 | } 171 | 172 | function uninstall() { 173 | local -r res=$(is_installed) 174 | if [ "$res" = installed ]; then 175 | rm "$hook_path" || \ 176 | error_exit "Couldn't remove the pre-commit hook." 177 | elif [ "$res" = different ]; then 178 | error_exit "There's a pre-commit hook installed, but for something else. Not removing." 179 | elif [ "$res" = nothing ]; then 180 | error_exit "There's no pre-commit hook, nothing to uninstall." 181 | else 182 | error_exit "Unexpected failure detecting the pre-commit hook status." 183 | fi 184 | } 185 | 186 | function show_help() { 187 | cat << EOF 188 | ${b}SYNOPSIS${n} 189 | 190 | $bash_source [install|uninstall] 191 | 192 | ${b}DESCRIPTION${n} 193 | 194 | Git hook to verify and fix formatting before committing. 195 | 196 | The script is invoked automatically when you commit, so you need to call it 197 | directly only to set up the hook or remove it. 198 | 199 | To setup the hook run this script passing "install" on the command line. 200 | To remove the hook run passing "uninstall". 201 | 202 | ${b}CONFIGURATION${n} 203 | 204 | You can configure the hook using the "git config" command. 205 | 206 | ${b}hooks.clangFormatDiffInteractive${n} (default: true) 207 | By default, the hook requires user input. If you don't run git from a 208 | terminal, you can disable the interactive prompt with: 209 | ${i}\$ git config hooks.clangFormatDiffInteractive false${n} 210 | 211 | ${b}hooks.clangFormatDiffStyle${n} (default: file) 212 | Unless a different style is specified, the hook expects a file named 213 | .clang-format to exist in the repository. This file should contain the 214 | configuration for clang-format. 215 | You can specify a different style (in this example, the WebKit one) 216 | with: 217 | ${i}\$ git config hooks.clangFormatDiffStyle WebKit${n} 218 | EOF 219 | } 220 | 221 | if [ $# = 1 ]; then 222 | case "$1" in 223 | -h | -\? | --help ) 224 | show_help 225 | exit 0 226 | ;; 227 | install ) 228 | install 229 | exit 0 230 | ;; 231 | uninstall ) 232 | uninstall 233 | exit 0 234 | ;; 235 | esac 236 | fi 237 | 238 | [ $# = 0 ] || error_exit "Invalid arguments: $*" 239 | 240 | 241 | # This is a real run of the hook, not a install/uninstall run. 242 | 243 | if [ -z "${GIT_DIR:-}" ] && [ -z "${GIT_INDEX_FILE:-}" ]; then 244 | error_exit \ 245 | $'It looks like you invoked this script directly, but it\'s supposed to be used\n' \ 246 | $'as a pre-commit git hook.\n' \ 247 | $'\n' \ 248 | $'To install the hook try:\n' \ 249 | $' ' "$bash_source" $' install\n' \ 250 | $'\n' \ 251 | $'For more details on this script try:\n' \ 252 | $' ' "$bash_source" $' --help\n' 253 | fi 254 | 255 | [ -x "$apply_format" ] || \ 256 | error_exit \ 257 | $'Cannot find the apply-format script.\n' \ 258 | $'I expected it here:\n' \ 259 | $' ' "$apply_format" 260 | 261 | readonly style=$(cd "$top_dir" && git config hooks.clangFormatDiffStyle || echo file) 262 | 263 | apply_format_opts=( 264 | "--style=$style" 265 | --cached 266 | ) 267 | 268 | readonly exclusions_file="$top_dir/.clang-format-hook-exclude" 269 | if [ -e "$exclusions_file" ]; then 270 | while IFS= read -r line; do 271 | if [[ "$line" && "$line" != "#"* ]]; then 272 | apply_format_opts+=("--internal-opt-ignore-regex=$line") 273 | fi 274 | done < "$exclusions_file" 275 | fi 276 | 277 | readonly patch=$(mktemp) 278 | trap '{ rm -f "$patch"; }' EXIT 279 | "$apply_format" --style="$style" --cached "${apply_format_opts[@]}" > "$patch" || \ 280 | error_exit $'\nThe apply-format script failed.' 281 | 282 | if [ "$(wc -l < "$patch")" -eq 0 ]; then 283 | echo "The staged content is formatted correctly." 284 | exit 0 285 | fi 286 | 287 | 288 | # The code is not formatted correctly. 289 | 290 | interactive=$(cd "$top_dir" && git config --bool hooks.clangFormatDiffInteractive) 291 | if [ "$interactive" != false ]; then 292 | # Interactive is the default, so anything that is not false is converted to 293 | # true, including possibly invalid values. 294 | interactive=true 295 | fi 296 | readonly interactive 297 | 298 | if [ "$interactive" = false ]; then 299 | echo "${b}The staged content is not formatted correctly.${n}" 300 | echo "You can fix the formatting with:" 301 | echo " ${i}\$ ./$apply_format_relative_to_top_dir --apply-to-staged${n}" 302 | echo 303 | echo "You can also make this script interactive (if you use git from a terminal) with:" 304 | echo " ${i}\$ git config hooks.clangFormatDiffInteractive true${n}" 305 | exit 1 306 | fi 307 | 308 | if hash colordiff 2> /dev/null; then 309 | colordiff < "$patch" 310 | else 311 | echo "${b}(Install colordiff to see this diff in color!)${n}" 312 | echo 313 | cat "$patch" 314 | fi 315 | 316 | # We don't want to suggest applying clang-format after merge resolution 317 | if git rev-parse MERGE_HEAD >/dev/null 2>&1; then 318 | readonly this_is_a_merge=true 319 | else 320 | readonly this_is_a_merge=false 321 | fi 322 | 323 | echo 324 | echo "${b}The staged content is not formatted correctly.${n}" 325 | echo "The fix shown above can be applied automatically to the commit." 326 | echo 327 | 328 | if $this_is_a_merge; then 329 | echo "${b}You appear to be committing the result of a merge. It is not${n}" 330 | echo "${b}recommended to apply the fix if it will reformat any code you${n}" 331 | echo "${b}did not modify in your branch.${n}" 332 | echo 333 | readonly recommend_apply=" (not recommended for merge!)" 334 | readonly recommend_force="" 335 | readonly bold_apply="" 336 | readonly bold_force="${b}" 337 | else 338 | readonly recommend_apply="" 339 | readonly recommend_force=" (not recommended!)" 340 | readonly bold_apply="${b}" 341 | readonly bold_force="" 342 | fi 343 | 344 | echo "You can:" 345 | echo " ${bold_apply}[a]: Apply the fix${recommend_apply}${n}" 346 | echo " ${bold_force}[f]: Force and commit anyway${recommend_force}${n}" 347 | echo " [c]: Cancel the commit" 348 | echo " [?]: Show help" 349 | echo 350 | 351 | readonly tty=${PRE_COMMIT_HOOK_TTY:-/dev/tty} 352 | 353 | while true; do 354 | echo -n "What would you like to do? [a/f/c/?] " 355 | read -r answer < "$tty" 356 | case "$answer" in 357 | 358 | [aA] ) 359 | patch -p0 < "$patch" || \ 360 | error_exit \ 361 | $'\n' \ 362 | $'Cannot apply fix to local files.\n' \ 363 | $'Have you modified the file locally after starting the commit?' 364 | git apply -p0 --cached < "$patch" || \ 365 | error_exit \ 366 | $'\n' \ 367 | $'Cannot apply fix to git staged changes.\n' \ 368 | $'This may happen if you have some overlapping unstaged changes. To solve\n' \ 369 | $'you need to stage or reset changes manually.' 370 | 371 | if $this_is_a_merge; then 372 | echo 373 | echo "Applied the fix to reformat the merge commit." 374 | echo "You can always abort by quitting your editor with no commit message." 375 | echo 376 | echo -n "Press return to continue." 377 | read -r < "$tty" 378 | fi 379 | ;; 380 | 381 | [fF] ) 382 | echo 383 | if ! $this_is_a_merge; then 384 | echo "Will commit anyway!" 385 | echo "You can always abort by quitting your editor with no commit message." 386 | echo 387 | echo -n "Press return to continue." 388 | read -r < "$tty" 389 | fi 390 | exit 0 391 | ;; 392 | 393 | [cC] ) 394 | error_exit "Commit aborted as requested." 395 | ;; 396 | 397 | \? ) 398 | echo 399 | show_help 400 | echo 401 | continue 402 | ;; 403 | 404 | * ) 405 | echo 'Invalid answer. Type "a", "f" or "c".' 406 | echo 407 | continue 408 | 409 | esac 410 | break 411 | done 412 | -------------------------------------------------------------------------------- /LICENSE.GPLv2: -------------------------------------------------------------------------------- 1 | Files described as being under the "GNU General Public License version 2" 2 | or simply the "GPLv2" fall under the license below. 3 | 4 | The copyrights of the GPLv2 licensed files of the project are held by the 5 | respective owners indicated at the top of the file. 6 | 7 | The Free Software Foundation owns the copyright to the license below. 8 | 9 | --------------------------------------------------------------------- 10 | 11 | GNU GENERAL PUBLIC LICENSE 12 | Version 2, June 1991 13 | 14 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 15 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 | Everyone is permitted to copy and distribute verbatim copies 17 | of this license document, but changing it is not allowed. 18 | 19 | Preamble 20 | 21 | The licenses for most software are designed to take away your 22 | freedom to share and change it. By contrast, the GNU General Public 23 | License is intended to guarantee your freedom to share and change free 24 | software--to make sure the software is free for all its users. This 25 | General Public License applies to most of the Free Software 26 | Foundation's software and to any other program whose authors commit to 27 | using it. (Some other Free Software Foundation software is covered by 28 | the GNU Lesser General Public License instead.) You can apply it to 29 | your programs, too. 30 | 31 | When we speak of free software, we are referring to freedom, not 32 | price. Our General Public Licenses are designed to make sure that you 33 | have the freedom to distribute copies of free software (and charge for 34 | this service if you wish), that you receive source code or can get it 35 | if you want it, that you can change the software or use pieces of it 36 | in new free programs; and that you know you can do these things. 37 | 38 | To protect your rights, we need to make restrictions that forbid 39 | anyone to deny you these rights or to ask you to surrender the rights. 40 | These restrictions translate to certain responsibilities for you if you 41 | distribute copies of the software, or if you modify it. 42 | 43 | For example, if you distribute copies of such a program, whether 44 | gratis or for a fee, you must give the recipients all the rights that 45 | you have. You must make sure that they, too, receive or can get the 46 | source code. And you must show them these terms so they know their 47 | rights. 48 | 49 | We protect your rights with two steps: (1) copyright the software, and 50 | (2) offer you this license which gives you legal permission to copy, 51 | distribute and/or modify the software. 52 | 53 | Also, for each author's protection and ours, we want to make certain 54 | that everyone understands that there is no warranty for this free 55 | software. If the software is modified by someone else and passed on, we 56 | want its recipients to know that what they have is not the original, so 57 | that any problems introduced by others will not reflect on the original 58 | authors' reputations. 59 | 60 | Finally, any free program is threatened constantly by software 61 | patents. We wish to avoid the danger that redistributors of a free 62 | program will individually obtain patent licenses, in effect making the 63 | program proprietary. To prevent this, we have made it clear that any 64 | patent must be licensed for everyone's free use or not licensed at all. 65 | 66 | The precise terms and conditions for copying, distribution and 67 | modification follow. 68 | 69 | GNU GENERAL PUBLIC LICENSE 70 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 71 | 72 | 0. This License applies to any program or other work which contains 73 | a notice placed by the copyright holder saying it may be distributed 74 | under the terms of this General Public License. The "Program", below, 75 | refers to any such program or work, and a "work based on the Program" 76 | means either the Program or any derivative work under copyright law: 77 | that is to say, a work containing the Program or a portion of it, 78 | either verbatim or with modifications and/or translated into another 79 | language. (Hereinafter, translation is included without limitation in 80 | the term "modification".) Each licensee is addressed as "you". 81 | 82 | Activities other than copying, distribution and modification are not 83 | covered by this License; they are outside its scope. The act of 84 | running the Program is not restricted, and the output from the Program 85 | is covered only if its contents constitute a work based on the 86 | Program (independent of having been made by running the Program). 87 | Whether that is true depends on what the Program does. 88 | 89 | 1. You may copy and distribute verbatim copies of the Program's 90 | source code as you receive it, in any medium, provided that you 91 | conspicuously and appropriately publish on each copy an appropriate 92 | copyright notice and disclaimer of warranty; keep intact all the 93 | notices that refer to this License and to the absence of any warranty; 94 | and give any other recipients of the Program a copy of this License 95 | along with the Program. 96 | 97 | You may charge a fee for the physical act of transferring a copy, and 98 | you may at your option offer warranty protection in exchange for a fee. 99 | 100 | 2. You may modify your copy or copies of the Program or any portion 101 | of it, thus forming a work based on the Program, and copy and 102 | distribute such modifications or work under the terms of Section 1 103 | above, provided that you also meet all of these conditions: 104 | 105 | a) You must cause the modified files to carry prominent notices 106 | stating that you changed the files and the date of any change. 107 | 108 | b) You must cause any work that you distribute or publish, that in 109 | whole or in part contains or is derived from the Program or any 110 | part thereof, to be licensed as a whole at no charge to all third 111 | parties under the terms of this License. 112 | 113 | c) If the modified program normally reads commands interactively 114 | when run, you must cause it, when started running for such 115 | interactive use in the most ordinary way, to print or display an 116 | announcement including an appropriate copyright notice and a 117 | notice that there is no warranty (or else, saying that you provide 118 | a warranty) and that users may redistribute the program under 119 | these conditions, and telling the user how to view a copy of this 120 | License. (Exception: if the Program itself is interactive but 121 | does not normally print such an announcement, your work based on 122 | the Program is not required to print an announcement.) 123 | 124 | These requirements apply to the modified work as a whole. If 125 | identifiable sections of that work are not derived from the Program, 126 | and can be reasonably considered independent and separate works in 127 | themselves, then this License, and its terms, do not apply to those 128 | sections when you distribute them as separate works. But when you 129 | distribute the same sections as part of a whole which is a work based 130 | on the Program, the distribution of the whole must be on the terms of 131 | this License, whose permissions for other licensees extend to the 132 | entire whole, and thus to each and every part regardless of who wrote it. 133 | 134 | Thus, it is not the intent of this section to claim rights or contest 135 | your rights to work written entirely by you; rather, the intent is to 136 | exercise the right to control the distribution of derivative or 137 | collective works based on the Program. 138 | 139 | In addition, mere aggregation of another work not based on the Program 140 | with the Program (or with a work based on the Program) on a volume of 141 | a storage or distribution medium does not bring the other work under 142 | the scope of this License. 143 | 144 | 3. You may copy and distribute the Program (or a work based on it, 145 | under Section 2) in object code or executable form under the terms of 146 | Sections 1 and 2 above provided that you also do one of the following: 147 | 148 | a) Accompany it with the complete corresponding machine-readable 149 | source code, which must be distributed under the terms of Sections 150 | 1 and 2 above on a medium customarily used for software interchange; or, 151 | 152 | b) Accompany it with a written offer, valid for at least three 153 | years, to give any third party, for a charge no more than your 154 | cost of physically performing source distribution, a complete 155 | machine-readable copy of the corresponding source code, to be 156 | distributed under the terms of Sections 1 and 2 above on a medium 157 | customarily used for software interchange; or, 158 | 159 | c) Accompany it with the information you received as to the offer 160 | to distribute corresponding source code. (This alternative is 161 | allowed only for noncommercial distribution and only if you 162 | received the program in object code or executable form with such 163 | an offer, in accord with Subsection b above.) 164 | 165 | The source code for a work means the preferred form of the work for 166 | making modifications to it. For an executable work, complete source 167 | code means all the source code for all modules it contains, plus any 168 | associated interface definition files, plus the scripts used to 169 | control compilation and installation of the executable. However, as a 170 | special exception, the source code distributed need not include 171 | anything that is normally distributed (in either source or binary 172 | form) with the major components (compiler, kernel, and so on) of the 173 | operating system on which the executable runs, unless that component 174 | itself accompanies the executable. 175 | 176 | If distribution of executable or object code is made by offering 177 | access to copy from a designated place, then offering equivalent 178 | access to copy the source code from the same place counts as 179 | distribution of the source code, even though third parties are not 180 | compelled to copy the source along with the object code. 181 | 182 | 4. You may not copy, modify, sublicense, or distribute the Program 183 | except as expressly provided under this License. Any attempt 184 | otherwise to copy, modify, sublicense or distribute the Program is 185 | void, and will automatically terminate your rights under this License. 186 | However, parties who have received copies, or rights, from you under 187 | this License will not have their licenses terminated so long as such 188 | parties remain in full compliance. 189 | 190 | 5. You are not required to accept this License, since you have not 191 | signed it. However, nothing else grants you permission to modify or 192 | distribute the Program or its derivative works. These actions are 193 | prohibited by law if you do not accept this License. Therefore, by 194 | modifying or distributing the Program (or any work based on the 195 | Program), you indicate your acceptance of this License to do so, and 196 | all its terms and conditions for copying, distributing or modifying 197 | the Program or works based on it. 198 | 199 | 6. Each time you redistribute the Program (or any work based on the 200 | Program), the recipient automatically receives a license from the 201 | original licensor to copy, distribute or modify the Program subject to 202 | these terms and conditions. You may not impose any further 203 | restrictions on the recipients' exercise of the rights granted herein. 204 | You are not responsible for enforcing compliance by third parties to 205 | this License. 206 | 207 | 7. If, as a consequence of a court judgment or allegation of patent 208 | infringement or for any other reason (not limited to patent issues), 209 | conditions are imposed on you (whether by court order, agreement or 210 | otherwise) that contradict the conditions of this License, they do not 211 | excuse you from the conditions of this License. If you cannot 212 | distribute so as to satisfy simultaneously your obligations under this 213 | License and any other pertinent obligations, then as a consequence you 214 | may not distribute the Program at all. For example, if a patent 215 | license would not permit royalty-free redistribution of the Program by 216 | all those who receive copies directly or indirectly through you, then 217 | the only way you could satisfy both it and this License would be to 218 | refrain entirely from distribution of the Program. 219 | 220 | If any portion of this section is held invalid or unenforceable under 221 | any particular circumstance, the balance of the section is intended to 222 | apply and the section as a whole is intended to apply in other 223 | circumstances. 224 | 225 | It is not the purpose of this section to induce you to infringe any 226 | patents or other property right claims or to contest validity of any 227 | such claims; this section has the sole purpose of protecting the 228 | integrity of the free software distribution system, which is 229 | implemented by public license practices. Many people have made 230 | generous contributions to the wide range of software distributed 231 | through that system in reliance on consistent application of that 232 | system; it is up to the author/donor to decide if he or she is willing 233 | to distribute software through any other system and a licensee cannot 234 | impose that choice. 235 | 236 | This section is intended to make thoroughly clear what is believed to 237 | be a consequence of the rest of this License. 238 | 239 | 8. If the distribution and/or use of the Program is restricted in 240 | certain countries either by patents or by copyrighted interfaces, the 241 | original copyright holder who places the Program under this License 242 | may add an explicit geographical distribution limitation excluding 243 | those countries, so that distribution is permitted only in or among 244 | countries not thus excluded. In such case, this License incorporates 245 | the limitation as if written in the body of this License. 246 | 247 | 9. The Free Software Foundation may publish revised and/or new versions 248 | of the General Public License from time to time. Such new versions will 249 | be similar in spirit to the present version, but may differ in detail to 250 | address new problems or concerns. 251 | 252 | Each version is given a distinguishing version number. If the Program 253 | specifies a version number of this License which applies to it and "any 254 | later version", you have the option of following the terms and conditions 255 | either of that version or of any later version published by the Free 256 | Software Foundation. If the Program does not specify a version number of 257 | this License, you may choose any version ever published by the Free Software 258 | Foundation. 259 | 260 | 10. If you wish to incorporate parts of the Program into other free 261 | programs whose distribution conditions are different, write to the author 262 | to ask for permission. For software which is copyrighted by the Free 263 | Software Foundation, write to the Free Software Foundation; we sometimes 264 | make exceptions for this. Our decision will be guided by the two goals 265 | of preserving the free status of all derivatives of our free software and 266 | of promoting the sharing and reuse of software generally. 267 | 268 | NO WARRANTY 269 | 270 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 271 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 272 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 273 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 274 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 275 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 276 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 277 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 278 | REPAIR OR CORRECTION. 279 | 280 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 281 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 282 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 283 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 284 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 285 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 286 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 287 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 288 | POSSIBILITY OF SUCH DAMAGES. 289 | 290 | END OF TERMS AND CONDITIONS 291 | 292 | How to Apply These Terms to Your New Programs 293 | 294 | If you develop a new program, and you want it to be of the greatest 295 | possible use to the public, the best way to achieve this is to make it 296 | free software which everyone can redistribute and change under these terms. 297 | 298 | To do so, attach the following notices to the program. It is safest 299 | to attach them to the start of each source file to most effectively 300 | convey the exclusion of warranty; and each file should have at least 301 | the "copyright" line and a pointer to where the full notice is found. 302 | 303 | 304 | Copyright (C) 305 | 306 | This program is free software; you can redistribute it and/or modify 307 | it under the terms of the GNU General Public License as published by 308 | the Free Software Foundation; either version 2 of the License, or 309 | (at your option) any later version. 310 | 311 | This program is distributed in the hope that it will be useful, 312 | but WITHOUT ANY WARRANTY; without even the implied warranty of 313 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 314 | GNU General Public License for more details. 315 | 316 | You should have received a copy of the GNU General Public License along 317 | with this program; if not, write to the Free Software Foundation, Inc., 318 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 319 | 320 | Also add information on how to contact you by electronic and paper mail. 321 | 322 | If the program is interactive, make it output a short notice like this 323 | when it starts in an interactive mode: 324 | 325 | Gnomovision version 69, Copyright (C) year name of author 326 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 327 | This is free software, and you are welcome to redistribute it 328 | under certain conditions; type `show c' for details. 329 | 330 | The hypothetical commands `show w' and `show c' should show the appropriate 331 | parts of the General Public License. Of course, the commands you use may 332 | be called something other than `show w' and `show c'; they could even be 333 | mouse-clicks or menu items--whatever suits your program. 334 | 335 | You should also get your employer (if you work as a programmer) or your 336 | school, if any, to sign a "copyright disclaimer" for the program, if 337 | necessary. Here is a sample; alter the names: 338 | 339 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 340 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 341 | 342 | , 1 April 1989 343 | Ty Coon, President of Vice 344 | 345 | This General Public License does not permit incorporating your program into 346 | proprietary programs. If your program is a subroutine library, you may 347 | consider it more useful to permit linking proprietary applications with the 348 | library. If this is what you want to do, use the GNU Lesser General 349 | Public License instead of this License. 350 | --------------------------------------------------------------------------------