├── .clang-format ├── COPYING ├── Makefile ├── README.md ├── README.zh-CN.md ├── guests ├── echo │ ├── Makefile │ ├── include │ │ ├── arm │ │ │ └── sysregs.h │ │ ├── mini_uart.h │ │ ├── mm.h │ │ ├── peripherals │ │ │ ├── base.h │ │ │ ├── gpio.h │ │ │ └── mini_uart.h │ │ ├── printf.h │ │ └── utils.h │ └── src │ │ ├── boot.S │ │ ├── config.txt │ │ ├── kernel.c │ │ ├── linker.ld │ │ ├── mini_uart.c │ │ ├── mm.S │ │ ├── printf.c │ │ └── utils.S ├── freertos │ └── freertos.bin ├── lrtos │ ├── Makefile │ ├── include │ │ ├── arm │ │ │ ├── mmu.h │ │ │ └── sysregs.h │ │ ├── entry.h │ │ ├── fork.h │ │ ├── irq.h │ │ ├── mini_uart.h │ │ ├── mm.h │ │ ├── peripherals │ │ │ ├── base.h │ │ │ ├── gpio.h │ │ │ ├── irq.h │ │ │ ├── mini_uart.h │ │ │ └── timer.h │ │ ├── printf.h │ │ ├── sched.h │ │ ├── sys.h │ │ ├── timer.h │ │ ├── user.h │ │ ├── user_sys.h │ │ └── utils.h │ └── src │ │ ├── boot.S │ │ ├── config.txt │ │ ├── entry.S │ │ ├── fork.c │ │ ├── irq.S │ │ ├── irq.c │ │ ├── kernel.c │ │ ├── linker.ld │ │ ├── mini_uart.c │ │ ├── mm.S │ │ ├── mm.c │ │ ├── printf.c │ │ ├── sched.S │ │ ├── sched.c │ │ ├── sys.c │ │ ├── timer.c │ │ ├── user.c │ │ ├── user_sys.S │ │ └── utils.S └── uboot │ └── uboot.bin ├── hypervisor ├── Makefile ├── arch │ └── aarch64 │ │ ├── boot.S │ │ ├── entry.S │ │ ├── irq.S │ │ ├── sched.S │ │ ├── sync_exc.c │ │ ├── task.c │ │ └── utils.S ├── boards │ └── raspi │ │ ├── config.txt │ │ ├── irq.c │ │ ├── linker.ld │ │ ├── linker_qemu.ld │ │ ├── mini_uart.c │ │ ├── phys2bus.c │ │ ├── raspi3b.c │ │ ├── sd.c │ │ └── timer.c ├── common │ ├── delays.c │ ├── fifo.c │ ├── loader.c │ ├── main.c │ ├── mm.c │ ├── printf.c │ ├── sched.c │ ├── shell.c │ ├── shell_priv.h │ └── utils.c ├── emulator │ └── raspi │ │ ├── bcm2837.c │ │ └── vmbox.c └── fs │ ├── diskio.c │ └── ff.c ├── include ├── arch │ └── aarch64 │ │ ├── mmu.h │ │ ├── page.h │ │ ├── sysregs.h │ │ └── timer.h ├── boards │ └── raspi │ │ ├── base.h │ │ ├── gpio.h │ │ ├── irq.h │ │ ├── mini_uart.h │ │ ├── phys2bus.h │ │ ├── pl011.h │ │ ├── raspi3b.h │ │ └── timer.h ├── common │ ├── board.h │ ├── debug.h │ ├── delays.h │ ├── entry.h │ ├── errno.h │ ├── fifo.h │ ├── irq.h │ ├── loader.h │ ├── mini_uart.h │ ├── mm.h │ ├── printf.h │ ├── sched.h │ ├── sd.h │ ├── shell.h │ ├── sync_exc.h │ ├── task.h │ ├── timer.h │ ├── types.h │ └── utils.h ├── emulator │ └── raspi │ │ ├── bcm2837.h │ │ └── vmbox.h └── fs │ ├── diskio.h │ ├── ff.h │ └── ffconf.h ├── misc ├── bootcode.bin └── start.elf └── scripts ├── clean.sh ├── create_sd.sh └── demo.sh /COPYING: -------------------------------------------------------------------------------- 1 | The aVisor is provided under: 2 | 3 | SPDX-License-Identifier: GPL-2.0-or-later 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #// SPDX-License-Identifier: GPL-2.0-or-later 2 | #/* 3 | # * aVisor Hypervisor 4 | # * 5 | # * A Tiny Hypervisor for IoT Development 6 | # * 7 | # * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | # */ 9 | 10 | GNU_TOOLS ?= aarch64-linux-gnu 11 | GNU_GCC = $(GNU_TOOLS)-gcc 12 | GNU_LD = $(GNU_TOOLS)-ld 13 | GNU_OBJCOPY = $(GNU_TOOLS)-objcopy 14 | GNU_OBJDUMP = $(GNU_TOOLS)-objdump 15 | 16 | INC_DIR = include 17 | C_OPS = -Wall -nostdlib -nostartfiles -ffreestanding -I$(INC_DIR) -mgeneral-regs-only 18 | ASM_OPS = -I$(INC_DIR) 19 | 20 | BUILD_DIR = build 21 | OUTDIR = bin 22 | 23 | SRC_DIR += hypervisor/arch/aarch64 24 | SRC_DIR += hypervisor/boards/raspi 25 | SRC_DIR += hypervisor/common 26 | SRC_DIR += hypervisor/fs 27 | SRC_DIR += hypervisor/emulator/raspi 28 | 29 | HV_DIR = hypervisor 30 | 31 | .PHONY: all 32 | all: kernel8.img 33 | 34 | .PHONY: qemu 35 | qemu: qemu.img 36 | 37 | C_FILES = $(wildcard *.c $(foreach fd, $(SRC_DIR), $(fd)/*.c)) 38 | ASM_FILES =$(wildcard *.S $(foreach fd, $(SRC_DIR), $(fd)/*.S)) 39 | 40 | $(BUILD_DIR)/%_c.o: %.c 41 | mkdir -p $(dir $@) 42 | $(GNU_GCC) $(C_OPS) -MMD -c $< -o $@ 43 | 44 | $(BUILD_DIR)/%_s.o: %.S 45 | mkdir -p $(dir $@) 46 | $(GNU_GCC) $(ASM_OPS) -MMD -c $< -o $@ 47 | 48 | OBJ_FILES = $(C_FILES:%.c=$(BUILD_DIR)/%_c.o) 49 | OBJ_FILES += $(ASM_FILES:%.S=$(BUILD_DIR)/%_s.o) 50 | 51 | DEP_FILES = $(OBJ_FILES:%.o=%.d) 52 | -include $(DEP_FILES) 53 | 54 | LINKER_FILE = $(HV_DIR)/boards/raspi/linker.ld 55 | LINKER_FILE_QEMU = $(HV_DIR)/boards/raspi/linker_qemu.ld 56 | 57 | kernel8.img: $(LINKER_FILE) $(OBJ_FILES) 58 | $(GNU_LD) -T $(LINKER_FILE) -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) 59 | $(GNU_OBJCOPY) $(BUILD_DIR)/kernel8.elf -O binary $(BUILD_DIR)/kernel8.img 60 | mkdir -p ./bin 61 | cp $(BUILD_DIR)/kernel8.img $(OUTDIR)/kernel8.img 62 | 63 | qemu.img: $(LINKER_FILE_QEMU) $(OBJ_FILES) 64 | $(GNU_LD) -T $(LINKER_FILE_QEMU) -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) 65 | $(GNU_OBJCOPY) $(BUILD_DIR)/kernel8.elf -O binary $(BUILD_DIR)/kernel8.img 66 | mkdir -p ./bin 67 | cp $(BUILD_DIR)/kernel8.img $(OUTDIR)/kernel8.img 68 | $(GNU_OBJDUMP) -D $(BUILD_DIR)/kernel8.elf > $(BUILD_DIR)/kernel8.list 69 | 70 | .PHONY: clean 71 | clean: 72 | rm -rf $(BUILD_DIR) $(OUTDIR) 73 | 74 | .PHONY: echoes 75 | echoes: 76 | @echo "C_FILES: $(C_FILES)" 77 | @echo "ASM_FILES: $(ASM_FILES)" 78 | @echo "OBJ_FILES: $(OBJ_FILES)" 79 | @echo "SRC_DIR: $(SRC_DIR)" 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # aVisor Hypervisor 2 | 3 | **[aVisor](https://calinyara.github.io/technology/2023/02/25/aVisor-en.html)** is a bare-metal hypervisor that runs on the Raspberry Pi 3. It can be used to learn about the basic concepts of ARM virtualization and the principles of hypervisors and operating systems. 4 | 5 |
6 | 7 | **Compilation and QEMU Simulation** 8 | 9 | ``` 10 | ./scripts/demo.sh // Compile and run the demo 11 | ./scripts/clean.sh // Clean the project 12 | ``` 13 | 14 | **Operation In the Console** 15 | 16 | The above demo will run 4 Guest VMs on the Hypervisor. After startup, press ***Enter*** to go to the hypervisor's console. 17 | 18 | - **[echo](https://github.com/calinyara/avisor/tree/main/guests/echo)**: A baremetal binary that echoes keyboard input. 19 | - **[lrtos](https://github.com/calinyara/avisor/tree/main/guests/lrtos)**: A miniature operating system that runs two user mode processes after startup, one prints "12345" and the other prints "abcde". The lrtos kernel supports the process scheduling. 20 | - **[uboot](https://github.com/u-boot/u-boot)**: The standard Das U-Boot Bootloader. 21 | - **[FreeRTOS](https://github.com/hacker-jie/freertos-raspi3)**: The FreeRTOS VM runs two tasks, one prints "12345" and the other prints "ABCDE". The tasks are scheduled by FreeRTOS. 22 | 23 |
24 | 25 | ``` 26 | help // Print the help 27 | vml // Display the current Guest VMs info 28 | vmc // Switch from the hypervisor's console to a Guest VM's console 29 | @+0 // Switch back to the hypervisor's console from a Guest VM's console 30 | ls // List all files (VM images) 31 | vmld // Load a VM image and run it 32 | ``` 33 | 34 | -------------------------------------------------------------------------------- /README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # aVisor Hypervisor 2 | 3 | **[aVisor](https://calinyara.github.io/technology/2023/02/25/aVisor.html)** 是一个可运行在树莓派3上的Hypervisor。用以帮助理解ARM虚拟化的基本概念,学习Hypervisor和操作系统的实现原理。 4 | 5 | 参考 [**Armv8架构虚拟化介绍**](https://calinyara.github.io/technology/2019/11/03/armv8-virtualization.html) 6 | 7 | **编译及运行** 8 | 9 | ``` 10 | ./scripts/demo.sh // 编译并运行demo 11 | ./scripts/clean.sh // 清理 12 | ``` 13 | 14 | **控制台操作** 15 | 16 | 运行上述demo,将在aVisor运行4个虚拟机 17 | - **[echo](https://github.com/calinyara/avisor/tree/main/guests/echo)**: 一个baremetal二进制程序,用以回显键盘输入 18 | - **[lrtos](https://github.com/calinyara/avisor/tree/main/guests/lrtos)**: 一个微型操作系统,启动后运行两个用户态程序,一个打印“12345”, 另一个打印"abcde", 其内核支持简单调度 19 | - **uboot**: 标准的 Das U-Boot Bootloader 20 | - **[FreeRTOS](https://github.com/hacker-jie/freertos-raspi3)**: 该DEMO运行两个Task, 一个打印“12345”, 另一个打印"ABCDE",由FreeRTOS调度运行 21 | 22 | 启动后按回车进入aVisor控制台 23 | 24 | ``` 25 | help // 打印帮助 26 | vml // 显示当前虚拟机信息 27 | vmc // 从Hypervisor控制台切换到VM控制台,例如:vmc 3,切换到uboot控制台 28 | @+0 // 从VM控制台切换回Hypervisor控制台 29 | ls // 显示当前目录下文件(虚拟机镜像文件) 30 | vmld // 加载一个虚拟机镜像文件并运行 31 | ``` 32 | 33 | -------------------------------------------------------------------------------- /guests/echo/Makefile: -------------------------------------------------------------------------------- 1 | ARMGNU ?= aarch64-linux-gnu 2 | 3 | COPS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude -mgeneral-regs-only 4 | ASMOPS = -Iinclude 5 | 6 | BUILD_DIR = build 7 | SRC_DIR = src 8 | 9 | all : echo.bin 10 | 11 | clean : 12 | rm -rf $(BUILD_DIR) *.img *.bin 13 | 14 | $(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c 15 | mkdir -p $(@D) 16 | $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ 17 | 18 | $(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S 19 | $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ 20 | 21 | C_FILES = $(wildcard $(SRC_DIR)/*.c) 22 | ASM_FILES = $(wildcard $(SRC_DIR)/*.S) 23 | OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) 24 | OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) 25 | 26 | DEP_FILES = $(OBJ_FILES:%.o=%.d) 27 | -include $(DEP_FILES) 28 | 29 | echo.bin: $(SRC_DIR)/linker.ld $(OBJ_FILES) 30 | $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) 31 | $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary echo.bin 32 | -------------------------------------------------------------------------------- /guests/echo/include/arm/sysregs.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYSREGS_H 2 | #define _SYSREGS_H 3 | 4 | // *************************************** 5 | // SCTLR_EL1, System Control Register (EL1), Page 2654 of AArch64-Reference-Manual. 6 | // *************************************** 7 | 8 | #define SCTLR_RESERVED (3 << 28) | (3 << 22) | (1 << 20) | (1 << 11) 9 | #define SCTLR_EE_LITTLE_ENDIAN (0 << 25) 10 | #define SCTLR_EOE_LITTLE_ENDIAN (0 << 24) 11 | #define SCTLR_I_CACHE_DISABLED (0 << 12) 12 | #define SCTLR_D_CACHE_DISABLED (0 << 2) 13 | #define SCTLR_MMU_DISABLED (0 << 0) 14 | #define SCTLR_MMU_ENABLED (1 << 0) 15 | 16 | #define SCTLR_VALUE_MMU_DISABLED \ 17 | (SCTLR_RESERVED | SCTLR_EE_LITTLE_ENDIAN | SCTLR_I_CACHE_DISABLED | \ 18 | SCTLR_D_CACHE_DISABLED | SCTLR_MMU_DISABLED) 19 | 20 | // *************************************** 21 | // HCR_EL2, Hypervisor Configuration Register (EL2), Page 2487 of AArch64-Reference-Manual. 22 | // *************************************** 23 | 24 | #define HCR_RW (1 << 31) 25 | #define HCR_VALUE HCR_RW 26 | 27 | // *************************************** 28 | // SCR_EL3, Secure Configuration Register (EL3), Page 2648 of AArch64-Reference-Manual. 29 | // *************************************** 30 | 31 | #define SCR_RESERVED (3 << 4) 32 | #define SCR_RW (1 << 10) 33 | #define SCR_NS (1 << 0) 34 | #define SCR_VALUE (SCR_RESERVED | SCR_RW | SCR_NS) 35 | 36 | // *************************************** 37 | // SPSR_EL3, Saved Program Status Register (EL3) Page 389 of AArch64-Reference-Manual. 38 | // *************************************** 39 | 40 | #define SPSR_MASK_ALL (7 << 6) 41 | #define SPSR_EL1h (5 << 0) 42 | #define SPSR_VALUE (SPSR_MASK_ALL | SPSR_EL1h) 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /guests/echo/include/mini_uart.h: -------------------------------------------------------------------------------- 1 | #ifndef _MINI_UART_H 2 | #define _MINI_UART_H 3 | 4 | void uart_init(void); 5 | char uart_recv(void); 6 | void uart_send(char c); 7 | void uart_hex(unsigned int d); 8 | void putc(void *p, char c); 9 | 10 | #endif /*_MINI_UART_H */ 11 | -------------------------------------------------------------------------------- /guests/echo/include/mm.h: -------------------------------------------------------------------------------- 1 | #ifndef _MM_H 2 | #define _MM_H 3 | 4 | #define PAGE_SHIFT 12 5 | #define TABLE_SHIFT 9 6 | #define SECTION_SHIFT (PAGE_SHIFT + TABLE_SHIFT) 7 | 8 | #define PAGE_SIZE (1 << PAGE_SHIFT) 9 | #define SECTION_SIZE (1 << SECTION_SHIFT) 10 | 11 | #define LOW_MEMORY (2 * SECTION_SIZE) 12 | 13 | #ifndef __ASSEMBLER__ 14 | 15 | void memzero(unsigned long src, unsigned long n); 16 | 17 | #endif 18 | 19 | #endif /*_MM_H */ 20 | -------------------------------------------------------------------------------- /guests/echo/include/peripherals/base.h: -------------------------------------------------------------------------------- 1 | #ifndef _P_BASE_H 2 | #define _P_BASE_H 3 | 4 | #define PBASE 0x3F000000 5 | 6 | #endif /*_P_BASE_H */ 7 | -------------------------------------------------------------------------------- /guests/echo/include/peripherals/gpio.h: -------------------------------------------------------------------------------- 1 | #ifndef _P_GPIO_H 2 | #define _P_GPIO_H 3 | 4 | #include "peripherals/base.h" 5 | 6 | #define GPFSEL1 (PBASE + 0x00200004) 7 | #define GPSET0 (PBASE + 0x0020001C) 8 | #define GPCLR0 (PBASE + 0x00200028) 9 | #define GPPUD (PBASE + 0x00200094) 10 | #define GPPUDCLK0 (PBASE + 0x00200098) 11 | 12 | #endif /*_P_GPIO_H */ 13 | -------------------------------------------------------------------------------- /guests/echo/include/peripherals/mini_uart.h: -------------------------------------------------------------------------------- 1 | #ifndef _P_MINI_UART_H 2 | #define _P_MINI_UART_H 3 | 4 | #include "peripherals/base.h" 5 | 6 | #define AUX_ENABLES (PBASE + 0x00215004) 7 | #define AUX_MU_IO_REG (PBASE + 0x00215040) 8 | #define AUX_MU_IER_REG (PBASE + 0x00215044) 9 | #define AUX_MU_IIR_REG (PBASE + 0x00215048) 10 | #define AUX_MU_LCR_REG (PBASE + 0x0021504C) 11 | #define AUX_MU_MCR_REG (PBASE + 0x00215050) 12 | #define AUX_MU_LSR_REG (PBASE + 0x00215054) 13 | #define AUX_MU_MSR_REG (PBASE + 0x00215058) 14 | #define AUX_MU_SCRATCH (PBASE + 0x0021505C) 15 | #define AUX_MU_CNTL_REG (PBASE + 0x00215060) 16 | #define AUX_MU_STAT_REG (PBASE + 0x00215064) 17 | #define AUX_MU_BAUD_REG (PBASE + 0x00215068) 18 | 19 | #endif /*_P_MINI_UART_H */ 20 | -------------------------------------------------------------------------------- /guests/echo/include/printf.h: -------------------------------------------------------------------------------- 1 | /* 2 | File: printf.h 3 | 4 | Copyright (C) 2004 Kustaa Nyholm 5 | 6 | This library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | This library is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | See the GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public 17 | License along with this library; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | 20 | This library is realy just two files: 'printf.h' and 'printf.c'. 21 | 22 | They provide a simple and small (+200 loc) printf functionality to 23 | be used in embedded systems. 24 | 25 | I've found them so usefull in debugging that I do not bother with a 26 | debugger at all. 27 | 28 | They are distributed in source form, so to use them, just compile them 29 | into your project. 30 | 31 | Two printf variants are provided: printf and sprintf. 32 | 33 | The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'. 34 | 35 | Zero padding and field width are also supported. 36 | 37 | If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the 38 | long specifier is also 39 | supported. Note that this will pull in some long math routines (pun intended!) 40 | and thus make your executable noticably longer. 41 | 42 | The memory foot print of course depends on the target cpu, compiler and 43 | compiler options, but a rough guestimate (based on a H8S target) is about 44 | 1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space. 45 | Not too bad. Your milage may vary. By hacking the source code you can 46 | get rid of some hunred bytes, I'm sure, but personally I feel the balance of 47 | functionality and flexibility versus code size is close to optimal for 48 | many embedded systems. 49 | 50 | To use the printf you need to supply your own character output function, 51 | something like : 52 | 53 | void putc ( void* p, char c) 54 | { 55 | while (!SERIAL_PORT_EMPTY) ; 56 | SERIAL_PORT_TX_REGISTER = c; 57 | } 58 | 59 | Before you can call printf you need to initialize it to use your 60 | character output function with something like: 61 | 62 | init_printf(NULL,putc); 63 | 64 | Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc', 65 | the NULL (or any pointer) you pass into the 'init_printf' will eventually be 66 | passed to your 'putc' routine. This allows you to pass some storage space (or 67 | anything realy) to the character output function, if necessary. 68 | This is not often needed but it was implemented like that because it made 69 | implementing the sprintf function so neat (look at the source code). 70 | 71 | The code is re-entrant, except for the 'init_printf' function, so it 72 | is safe to call it from interupts too, although this may result in mixed output. 73 | If you rely on re-entrancy, take care that your 'putc' function is re-entrant! 74 | 75 | The printf and sprintf functions are actually macros that translate to 76 | 'tfp_printf' and 'tfp_sprintf'. This makes it possible 77 | to use them along with 'stdio.h' printf's in a single source file. 78 | You just need to undef the names before you include the 'stdio.h'. 79 | Note that these are not function like macros, so if you have variables 80 | or struct members with these names, things will explode in your face. 81 | Without variadic macros this is the best we can do to wrap these 82 | fucnction. If it is a problem just give up the macros and use the 83 | functions directly or rename them. 84 | 85 | For further details see source code. 86 | 87 | regs Kusti, 23.10.2004 88 | */ 89 | 90 | #ifndef __TFP_PRINTF__ 91 | #define __TFP_PRINTF__ 92 | 93 | #include 94 | 95 | void init_printf(void *putp, void (*putf)(void *, char)); 96 | 97 | void tfp_printf(char *fmt, ...); 98 | void tfp_sprintf(char *s, char *fmt, ...); 99 | 100 | void tfp_format(void *putp, void (*putf)(void *, char), char *fmt, va_list va); 101 | 102 | #define printf tfp_printf 103 | #define sprintf tfp_sprintf 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /guests/echo/include/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef _BOOT_H 2 | #define _BOOT_H 3 | 4 | extern void delay(unsigned long); 5 | extern void put32(unsigned long, unsigned int); 6 | extern unsigned int get32(unsigned long); 7 | extern int get_el(void); 8 | 9 | #endif /*_BOOT_H */ 10 | -------------------------------------------------------------------------------- /guests/echo/src/boot.S: -------------------------------------------------------------------------------- 1 | #include "arm/sysregs.h" 2 | 3 | #include "mm.h" 4 | 5 | .section ".text.boot" 6 | 7 | .globl _start 8 | _start: 9 | mrs x0, mpidr_el1 10 | and x0, x0,#0xFF // Check processor id 11 | cbz x0, master // Hang for all non-primary CPU 12 | b proc_hang 13 | 14 | proc_hang: 15 | b proc_hang 16 | 17 | master: 18 | ldr x0, =SCTLR_VALUE_MMU_DISABLED 19 | msr sctlr_el1, x0 20 | isb 21 | 22 | el1_entry: 23 | adr x0, bss_begin 24 | adr x1, bss_end 25 | sub x1, x1, x0 26 | bl memzero 27 | 28 | mov sp, #LOW_MEMORY 29 | bl kernel_main 30 | b proc_hang // should never come here 31 | -------------------------------------------------------------------------------- /guests/echo/src/config.txt: -------------------------------------------------------------------------------- 1 | kernel_old=1 2 | disable_commandline_tags=1 3 | -------------------------------------------------------------------------------- /guests/echo/src/kernel.c: -------------------------------------------------------------------------------- 1 | #include "mini_uart.h" 2 | #include "printf.h" 3 | #include "utils.h" 4 | 5 | void kernel_main(void) 6 | { 7 | uart_init(); 8 | init_printf(0, putc); 9 | 10 | printf("ECHO OS: echo your input...\n"); 11 | 12 | while (1) { 13 | char c = uart_recv(); 14 | if (c == '\n' || c == '\r') { 15 | uart_send('\r'); 16 | uart_send('\n'); 17 | } else { 18 | uart_send(c); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /guests/echo/src/linker.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | .text.boot : { *(.text.boot) } 4 | .text : { *(.text) } 5 | .rodata : { *(.rodata) } 6 | .data : { *(.data) } 7 | . = ALIGN(0x8); 8 | bss_begin = .; 9 | .bss : { *(.bss*) } 10 | bss_end = .; 11 | } 12 | -------------------------------------------------------------------------------- /guests/echo/src/mini_uart.c: -------------------------------------------------------------------------------- 1 | #include "peripherals/mini_uart.h" 2 | #include "peripherals/gpio.h" 3 | #include "utils.h" 4 | 5 | void uart_send(char c) 6 | { 7 | while (1) { 8 | if (get32(AUX_MU_LSR_REG) & 0x20) 9 | break; 10 | } 11 | put32(AUX_MU_IO_REG, c); 12 | } 13 | 14 | void uart_hex(unsigned int d) 15 | { 16 | unsigned int n; 17 | int c; 18 | for (c = 28; c >= 0; c -= 4) { 19 | // get highest tetrad 20 | n = (d >> c) & 0xF; 21 | // 0-9 => '0'-'9', 10-15 => 'A'-'F' 22 | n += n > 9 ? 0x37 : 0x30; 23 | uart_send(n); 24 | } 25 | } 26 | 27 | char uart_recv(void) 28 | { 29 | while (1) { 30 | if (get32(AUX_MU_LSR_REG) & 0x01) 31 | break; 32 | } 33 | return (get32(AUX_MU_IO_REG) & 0xFF); 34 | } 35 | 36 | void uart_send_string(char *str) 37 | { 38 | for (int i = 0; str[i] != '\0'; i++) { 39 | uart_send((char)str[i]); 40 | } 41 | } 42 | 43 | void uart_init(void) 44 | { 45 | unsigned int selector; 46 | 47 | selector = get32(GPFSEL1); 48 | selector &= ~(7 << 12); // clean gpio14 49 | selector |= 2 << 12; // set alt5 for gpio14 50 | selector &= ~(7 << 15); // clean gpio15 51 | selector |= 2 << 15; // set alt5 for gpio15 52 | put32(GPFSEL1, selector); 53 | 54 | put32(GPPUD, 0); 55 | delay(150); 56 | put32(GPPUDCLK0, (1 << 14) | (1 << 15)); 57 | delay(150); 58 | put32(GPPUDCLK0, 0); 59 | 60 | put32(AUX_ENABLES, 61 | 1); //Enable mini uart (this also enables access to it registers) 62 | put32(AUX_MU_CNTL_REG, 63 | 0); //Disable auto flow control and disable receiver and transmitter (for now) 64 | put32(AUX_MU_IER_REG, 0); //Disable receive and transmit interrupts 65 | put32(AUX_MU_LCR_REG, 3); //Enable 8 bit mode 66 | put32(AUX_MU_MCR_REG, 0); //Set RTS line to be always high 67 | put32(AUX_MU_BAUD_REG, 270); //Set baud rate to 115200 68 | 69 | put32(AUX_MU_CNTL_REG, 3); //Finally, enable transmitter and receiver 70 | } 71 | 72 | // This function is required by printf function 73 | void putc(void *p, char c) 74 | { 75 | uart_send(c); 76 | } 77 | -------------------------------------------------------------------------------- /guests/echo/src/mm.S: -------------------------------------------------------------------------------- 1 | .globl memzero 2 | memzero: 3 | str xzr, [x0], #8 4 | subs x1, x1, #8 5 | b.gt memzero 6 | ret 7 | -------------------------------------------------------------------------------- /guests/echo/src/printf.c: -------------------------------------------------------------------------------- 1 | /* 2 | File: printf.c 3 | 4 | Copyright (C) 2004 Kustaa Nyholm 5 | 6 | This library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | This library is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public 17 | License along with this library; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | 20 | */ 21 | 22 | #include "printf.h" 23 | 24 | typedef void (*putcf)(void *, char); 25 | static putcf stdout_putf; 26 | static void *stdout_putp; 27 | 28 | #ifdef PRINTF_LONG_SUPPORT 29 | 30 | static void uli2a(unsigned long int num, unsigned int base, int uc, char *bf) 31 | { 32 | int n = 0; 33 | unsigned int d = 1; 34 | while (num / d >= base) 35 | d *= base; 36 | while (d != 0) { 37 | int dgt = num / d; 38 | num %= d; 39 | d /= base; 40 | if (n || dgt > 0 || d == 0) { 41 | *bf++ = dgt + (dgt < 10 ? '0' : (uc ? 'A' : 'a') - 10); 42 | ++n; 43 | } 44 | } 45 | *bf = 0; 46 | } 47 | 48 | static void li2a(long num, char *bf) 49 | { 50 | if (num < 0) { 51 | num = -num; 52 | *bf++ = '-'; 53 | } 54 | uli2a(num, 10, 0, bf); 55 | } 56 | 57 | #endif 58 | 59 | static void ui2a(unsigned int num, unsigned int base, int uc, char *bf) 60 | { 61 | int n = 0; 62 | unsigned int d = 1; 63 | while (num / d >= base) 64 | d *= base; 65 | while (d != 0) { 66 | int dgt = num / d; 67 | num %= d; 68 | d /= base; 69 | if (n || dgt > 0 || d == 0) { 70 | *bf++ = dgt + (dgt < 10 ? '0' : (uc ? 'A' : 'a') - 10); 71 | ++n; 72 | } 73 | } 74 | *bf = 0; 75 | } 76 | 77 | static void i2a(int num, char *bf) 78 | { 79 | if (num < 0) { 80 | num = -num; 81 | *bf++ = '-'; 82 | } 83 | ui2a(num, 10, 0, bf); 84 | } 85 | 86 | static int a2d(char ch) 87 | { 88 | if (ch >= '0' && ch <= '9') 89 | return ch - '0'; 90 | else if (ch >= 'a' && ch <= 'f') 91 | return ch - 'a' + 10; 92 | else if (ch >= 'A' && ch <= 'F') 93 | return ch - 'A' + 10; 94 | else 95 | return -1; 96 | } 97 | 98 | static char a2i(char ch, char **src, int base, int *nump) 99 | { 100 | char *p = *src; 101 | int num = 0; 102 | int digit; 103 | while ((digit = a2d(ch)) >= 0) { 104 | if (digit > base) 105 | break; 106 | num = num * base + digit; 107 | ch = *p++; 108 | } 109 | *src = p; 110 | *nump = num; 111 | return ch; 112 | } 113 | 114 | static void putchw(void *putp, putcf putf, int n, char z, char *bf) 115 | { 116 | char fc = z ? '0' : ' '; 117 | char ch; 118 | char *p = bf; 119 | while (*p++ && n > 0) 120 | n--; 121 | while (n-- > 0) 122 | putf(putp, fc); 123 | while ((ch = *bf++)) 124 | putf(putp, ch); 125 | } 126 | 127 | void tfp_format(void *putp, putcf putf, char *fmt, va_list va) 128 | { 129 | char bf[12]; 130 | 131 | char ch; 132 | 133 | while ((ch = *(fmt++))) { 134 | if (ch != '%') 135 | putf(putp, ch); 136 | else { 137 | char lz = 0; 138 | #ifdef PRINTF_LONG_SUPPORT 139 | char lng = 0; 140 | #endif 141 | int w = 0; 142 | ch = *(fmt++); 143 | if (ch == '0') { 144 | ch = *(fmt++); 145 | lz = 1; 146 | } 147 | if (ch >= '0' && ch <= '9') { 148 | ch = a2i(ch, &fmt, 10, &w); 149 | } 150 | #ifdef PRINTF_LONG_SUPPORT 151 | if (ch == 'l') { 152 | ch = *(fmt++); 153 | lng = 1; 154 | } 155 | #endif 156 | switch (ch) { 157 | case 0: 158 | goto abort; 159 | case 'u': { 160 | #ifdef PRINTF_LONG_SUPPORT 161 | if (lng) 162 | uli2a(va_arg(va, unsigned long int), 10, 163 | 0, bf); 164 | else 165 | #endif 166 | ui2a(va_arg(va, unsigned int), 10, 0, 167 | bf); 168 | putchw(putp, putf, w, lz, bf); 169 | break; 170 | } 171 | case 'd': { 172 | #ifdef PRINTF_LONG_SUPPORT 173 | if (lng) 174 | li2a(va_arg(va, unsigned long int), bf); 175 | else 176 | #endif 177 | i2a(va_arg(va, int), bf); 178 | putchw(putp, putf, w, lz, bf); 179 | break; 180 | } 181 | case 'x': 182 | case 'X': 183 | #ifdef PRINTF_LONG_SUPPORT 184 | if (lng) 185 | uli2a(va_arg(va, unsigned long int), 16, 186 | (ch == 'X'), bf); 187 | else 188 | #endif 189 | ui2a(va_arg(va, unsigned int), 16, 190 | (ch == 'X'), bf); 191 | putchw(putp, putf, w, lz, bf); 192 | break; 193 | case 'c': 194 | putf(putp, (char)(va_arg(va, int))); 195 | break; 196 | case 's': 197 | putchw(putp, putf, w, 0, va_arg(va, char *)); 198 | break; 199 | case '%': 200 | putf(putp, ch); 201 | default: 202 | break; 203 | } 204 | } 205 | } 206 | abort:; 207 | } 208 | 209 | void init_printf(void *putp, void (*putf)(void *, char)) 210 | { 211 | stdout_putf = putf; 212 | stdout_putp = putp; 213 | } 214 | 215 | void tfp_printf(char *fmt, ...) 216 | { 217 | va_list va; 218 | va_start(va, fmt); 219 | tfp_format(stdout_putp, stdout_putf, fmt, va); 220 | va_end(va); 221 | } 222 | 223 | static void putcp(void *p, char c) 224 | { 225 | *(*((char **)p))++ = c; 226 | } 227 | 228 | void tfp_sprintf(char *s, char *fmt, ...) 229 | { 230 | va_list va; 231 | va_start(va, fmt); 232 | tfp_format(&s, putcp, fmt, va); 233 | putcp(&s, 0); 234 | va_end(va); 235 | } 236 | -------------------------------------------------------------------------------- /guests/echo/src/utils.S: -------------------------------------------------------------------------------- 1 | .globl get_el 2 | get_el: 3 | mrs x0, CurrentEL 4 | lsr x0, x0, #2 5 | ret 6 | 7 | .globl put32 8 | put32: 9 | str w1,[x0] 10 | ret 11 | 12 | .globl get32 13 | get32: 14 | ldr w0,[x0] 15 | ret 16 | 17 | .globl delay 18 | delay: 19 | subs x0, x0, #1 20 | bne delay 21 | ret 22 | -------------------------------------------------------------------------------- /guests/freertos/freertos.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calinyara/avisor/ebde0d4dbf95f7ed9a20baf1e2c71b7ca0e8bed5/guests/freertos/freertos.bin -------------------------------------------------------------------------------- /guests/lrtos/Makefile: -------------------------------------------------------------------------------- 1 | ARMGNU ?= aarch64-linux-gnu 2 | 3 | COPS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude -mgeneral-regs-only 4 | ASMOPS = -Iinclude 5 | 6 | BUILD_DIR = build 7 | SRC_DIR = src 8 | 9 | all : lrtos.bin 10 | 11 | clean : 12 | rm -rf $(BUILD_DIR) *.img *.bin 13 | 14 | $(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c 15 | mkdir -p $(@D) 16 | $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ 17 | 18 | $(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S 19 | $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ 20 | 21 | C_FILES = $(wildcard $(SRC_DIR)/*.c) 22 | ASM_FILES = $(wildcard $(SRC_DIR)/*.S) 23 | OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) 24 | OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) 25 | 26 | DEP_FILES = $(OBJ_FILES:%.o=%.d) 27 | -include $(DEP_FILES) 28 | 29 | lrtos.bin: $(SRC_DIR)/linker.ld $(OBJ_FILES) 30 | $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) 31 | $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary lrtos.bin 32 | -------------------------------------------------------------------------------- /guests/lrtos/include/arm/mmu.h: -------------------------------------------------------------------------------- 1 | #ifndef _MMU_H 2 | #define _MMU_H 3 | 4 | #define MM_TYPE_PAGE_TABLE 0x3 5 | #define MM_TYPE_PAGE 0x3 6 | #define MM_TYPE_BLOCK 0x1 7 | #define MM_ACCESS (0x1 << 10) 8 | #define MM_ACCESS_PERMISSION (0x01 << 6) 9 | 10 | /* 11 | * Memory region attributes: 12 | * 13 | * n = AttrIndx[2:0] 14 | * n MAIR 15 | * DEVICE_nGnRnE 000 00000000 16 | * NORMAL_NC 001 01000100 17 | */ 18 | #define MT_DEVICE_nGnRnE 0x0 19 | #define MT_NORMAL_NC 0x1 20 | #define MT_DEVICE_nGnRnE_FLAGS 0x00 21 | #define MT_NORMAL_NC_FLAGS 0x44 22 | #define MAIR_VALUE \ 23 | (MT_DEVICE_nGnRnE_FLAGS << (8 * MT_DEVICE_nGnRnE)) | \ 24 | (MT_NORMAL_NC_FLAGS << (8 * MT_NORMAL_NC)) 25 | 26 | #define MMU_FLAGS (MM_TYPE_BLOCK | (MT_NORMAL_NC << 2) | MM_ACCESS) 27 | #define MMU_DEVICE_FLAGS (MM_TYPE_BLOCK | (MT_DEVICE_nGnRnE << 2) | MM_ACCESS) 28 | #define MMU_PTE_FLAGS \ 29 | (MM_TYPE_PAGE | (MT_NORMAL_NC << 2) | MM_ACCESS | MM_ACCESS_PERMISSION) 30 | 31 | #define TCR_T0SZ (64 - 48) 32 | #define TCR_T1SZ ((64 - 48) << 16) 33 | #define TCR_TG0_4K (0 << 14) 34 | #define TCR_TG1_4K (2 << 30) 35 | #define TCR_VALUE (TCR_T0SZ | TCR_T1SZ | TCR_TG0_4K | TCR_TG1_4K) 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /guests/lrtos/include/arm/sysregs.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYSREGS_H 2 | #define _SYSREGS_H 3 | 4 | // *************************************** 5 | // SCTLR_EL1, System Control Register (EL1), Page 2025 of AArch64-Reference-Manual. 6 | // *************************************** 7 | 8 | #define SCTLR_RESERVED (3 << 28) | (3 << 22) | (1 << 20) | (1 << 11) 9 | #define SCTLR_EE_LITTLE_ENDIAN (0 << 25) 10 | #define SCTLR_EOE_LITTLE_ENDIAN (0 << 24) 11 | #define SCTLR_I_CACHE_DISABLED (0 << 12) 12 | #define SCTLR_D_CACHE_DISABLED (0 << 2) 13 | #define SCTLR_MMU_DISABLED (0 << 0) 14 | #define SCTLR_MMU_ENABLED (1 << 0) 15 | 16 | #define SCTLR_VALUE_MMU_DISABLED \ 17 | (SCTLR_RESERVED | SCTLR_EE_LITTLE_ENDIAN | SCTLR_I_CACHE_DISABLED | \ 18 | SCTLR_D_CACHE_DISABLED | SCTLR_MMU_DISABLED) 19 | 20 | // *************************************** 21 | // HCR_EL2, Hypervisor Configuration Register (EL2), Page 1923 of AArch64-Reference-Manual. 22 | // *************************************** 23 | 24 | #define HCR_RW (1 << 31) 25 | #define HCR_VALUE HCR_RW 26 | 27 | // *************************************** 28 | // SCR_EL3, Secure Configuration Register (EL3), Page 2022 of AArch64-Reference-Manual. 29 | // *************************************** 30 | 31 | #define SCR_RESERVED (3 << 4) 32 | #define SCR_RW (1 << 10) 33 | #define SCR_NS (1 << 0) 34 | #define SCR_VALUE (SCR_RESERVED | SCR_RW | SCR_NS) 35 | 36 | // *************************************** 37 | // SPSR_EL3, Saved Program Status Register (EL3) Page 288 of AArch64-Reference-Manual. 38 | // *************************************** 39 | 40 | #define SPSR_MASK_ALL (7 << 6) 41 | #define SPSR_EL1h (5 << 0) 42 | #define SPSR_VALUE (SPSR_MASK_ALL | SPSR_EL1h) 43 | 44 | // *************************************** 45 | // ESR_EL1, Exception Syndrome Register (EL1). Page 1899 of AArch64-Reference-Manual. 46 | // *************************************** 47 | 48 | #define ESR_ELx_EC_SHIFT 26 49 | #define ESR_ELx_EC_SVC64 0x15 50 | #define ESR_ELx_EC_DABT_LOW 0x24 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /guests/lrtos/include/entry.h: -------------------------------------------------------------------------------- 1 | #ifndef _ENTRY_H 2 | #define _ENTRY_H 3 | 4 | #define S_FRAME_SIZE 272 // size of all saved registers 5 | #define S_X0 0 // offset of x0 register in saved stack frame 6 | 7 | #define SYNC_INVALID_EL1t 0 8 | #define IRQ_INVALID_EL1t 1 9 | #define FIQ_INVALID_EL1t 2 10 | #define ERROR_INVALID_EL1t 3 11 | 12 | #define SYNC_INVALID_EL1h 4 13 | #define FIQ_INVALID_EL1h 5 14 | #define ERROR_INVALID_EL1h 6 15 | 16 | #define FIQ_INVALID_EL0_64 7 17 | #define ERROR_INVALID_EL0_64 8 18 | 19 | #define SYNC_INVALID_EL0_32 9 20 | #define IRQ_INVALID_EL0_32 10 21 | #define FIQ_INVALID_EL0_32 11 22 | #define ERROR_INVALID_EL0_32 12 23 | 24 | #define SYNC_ERROR 13 25 | #define SYSCALL_ERROR 14 26 | #define DATA_ABORT_ERROR 15 27 | 28 | #ifndef __ASSEMBLER__ 29 | 30 | void ret_from_fork(void); 31 | 32 | #endif 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /guests/lrtos/include/fork.h: -------------------------------------------------------------------------------- 1 | #ifndef _FORK_H 2 | #define _FORK_H 3 | 4 | #include "sched.h" 5 | 6 | /* 7 | * PSR bits 8 | */ 9 | #define PSR_MODE_EL0t 0x00000000 10 | #define PSR_MODE_EL1t 0x00000004 11 | #define PSR_MODE_EL1h 0x00000005 12 | #define PSR_MODE_EL2t 0x00000008 13 | #define PSR_MODE_EL2h 0x00000009 14 | #define PSR_MODE_EL3t 0x0000000c 15 | #define PSR_MODE_EL3h 0x0000000d 16 | 17 | int copy_process(unsigned long clone_flags, unsigned long fn, 18 | unsigned long arg); 19 | int move_to_user_mode(unsigned long start, unsigned long size, 20 | unsigned long pc); 21 | struct pt_regs *task_pt_regs(struct task_struct *tsk); 22 | 23 | struct pt_regs { 24 | unsigned long regs[31]; 25 | unsigned long sp; 26 | unsigned long pc; 27 | unsigned long pstate; 28 | }; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /guests/lrtos/include/irq.h: -------------------------------------------------------------------------------- 1 | #ifndef _IRQ_H 2 | #define _IRQ_H 3 | 4 | void enable_interrupt_controller(void); 5 | 6 | void irq_vector_init(void); 7 | void enable_irq(void); 8 | void disable_irq(void); 9 | 10 | #endif /*_IRQ_H */ 11 | -------------------------------------------------------------------------------- /guests/lrtos/include/mini_uart.h: -------------------------------------------------------------------------------- 1 | #ifndef _MINI_UART_H 2 | #define _MINI_UART_H 3 | 4 | void uart_init(void); 5 | char uart_recv(void); 6 | void uart_send(char c); 7 | void putc(void *p, char c); 8 | 9 | #endif /*_MINI_UART_H */ 10 | -------------------------------------------------------------------------------- /guests/lrtos/include/mm.h: -------------------------------------------------------------------------------- 1 | #ifndef _MM_H 2 | #define _MM_H 3 | 4 | #include "peripherals/base.h" 5 | 6 | #define VA_START 0xffff000000000000 7 | 8 | #define PHYS_MEMORY_SIZE 0x40000000 9 | 10 | #define PAGE_MASK 0xfffffffffffff000 11 | #define PAGE_SHIFT 12 12 | #define TABLE_SHIFT 9 13 | #define SECTION_SHIFT (PAGE_SHIFT + TABLE_SHIFT) 14 | 15 | #define PAGE_SIZE (1 << PAGE_SHIFT) 16 | #define SECTION_SIZE (1 << SECTION_SHIFT) 17 | 18 | #define LOW_MEMORY (2 * SECTION_SIZE) 19 | #define HIGH_MEMORY DEVICE_BASE 20 | 21 | #define PAGING_MEMORY (HIGH_MEMORY - LOW_MEMORY) 22 | #define PAGING_PAGES (PAGING_MEMORY / PAGE_SIZE) 23 | 24 | #define PTRS_PER_TABLE (1 << TABLE_SHIFT) 25 | 26 | #define PGD_SHIFT PAGE_SHIFT + 3 * TABLE_SHIFT 27 | #define PUD_SHIFT PAGE_SHIFT + 2 * TABLE_SHIFT 28 | #define PMD_SHIFT PAGE_SHIFT + TABLE_SHIFT 29 | 30 | #define PG_DIR_SIZE (3 * PAGE_SIZE) 31 | 32 | #ifndef __ASSEMBLER__ 33 | 34 | #include "sched.h" 35 | 36 | unsigned long get_free_page(); 37 | void free_page(unsigned long p); 38 | void map_page(struct task_struct *task, unsigned long va, unsigned long page); 39 | void memzero(unsigned long src, unsigned long n); 40 | void memcpy(unsigned long dst, unsigned long src, unsigned long n); 41 | 42 | int copy_virt_memory(struct task_struct *dst); 43 | unsigned long allocate_kernel_page(); 44 | unsigned long allocate_user_page(struct task_struct *task, unsigned long va); 45 | 46 | extern unsigned long pg_dir; 47 | 48 | #endif 49 | 50 | #endif /*_MM_H */ 51 | -------------------------------------------------------------------------------- /guests/lrtos/include/peripherals/base.h: -------------------------------------------------------------------------------- 1 | #ifndef _P_BASE_H 2 | #define _P_BASE_H 3 | 4 | #include "mm.h" 5 | 6 | #define DEVICE_BASE 0x3F000000 7 | #define PBASE (VA_START + DEVICE_BASE) 8 | 9 | #endif /*_P_BASE_H */ 10 | -------------------------------------------------------------------------------- /guests/lrtos/include/peripherals/gpio.h: -------------------------------------------------------------------------------- 1 | #ifndef _P_GPIO_H 2 | #define _P_GPIO_H 3 | 4 | #include "peripherals/base.h" 5 | 6 | #define GPFSEL1 (PBASE + 0x00200004) 7 | #define GPSET0 (PBASE + 0x0020001C) 8 | #define GPCLR0 (PBASE + 0x00200028) 9 | #define GPPUD (PBASE + 0x00200094) 10 | #define GPPUDCLK0 (PBASE + 0x00200098) 11 | 12 | #endif /*_P_GPIO_H */ 13 | -------------------------------------------------------------------------------- /guests/lrtos/include/peripherals/irq.h: -------------------------------------------------------------------------------- 1 | #ifndef _P_IRQ_H 2 | #define _P_IRQ_H 3 | 4 | #include "peripherals/base.h" 5 | 6 | #define IRQ_BASIC_PENDING (PBASE + 0x0000B200) 7 | #define IRQ_PENDING_1 (PBASE + 0x0000B204) 8 | #define IRQ_PENDING_2 (PBASE + 0x0000B208) 9 | #define FIQ_CONTROL (PBASE + 0x0000B20C) 10 | #define ENABLE_IRQS_1 (PBASE + 0x0000B210) 11 | #define ENABLE_IRQS_2 (PBASE + 0x0000B214) 12 | #define ENABLE_BASIC_IRQS (PBASE + 0x0000B218) 13 | #define DISABLE_IRQS_1 (PBASE + 0x0000B21C) 14 | #define DISABLE_IRQS_2 (PBASE + 0x0000B220) 15 | #define DISABLE_BASIC_IRQS (PBASE + 0x0000B224) 16 | 17 | #define SYSTEM_TIMER_IRQ_0 (1 << 0) 18 | #define SYSTEM_TIMER_IRQ_1 (1 << 1) 19 | #define SYSTEM_TIMER_IRQ_2 (1 << 2) 20 | #define SYSTEM_TIMER_IRQ_3 (1 << 3) 21 | 22 | #endif /*_P_IRQ_H */ 23 | -------------------------------------------------------------------------------- /guests/lrtos/include/peripherals/mini_uart.h: -------------------------------------------------------------------------------- 1 | #ifndef _P_MINI_UART_H 2 | #define _P_MINI_UART_H 3 | 4 | #include "peripherals/base.h" 5 | 6 | #define AUX_ENABLES (PBASE + 0x00215004) 7 | #define AUX_MU_IO_REG (PBASE + 0x00215040) 8 | #define AUX_MU_IER_REG (PBASE + 0x00215044) 9 | #define AUX_MU_IIR_REG (PBASE + 0x00215048) 10 | #define AUX_MU_LCR_REG (PBASE + 0x0021504C) 11 | #define AUX_MU_MCR_REG (PBASE + 0x00215050) 12 | #define AUX_MU_LSR_REG (PBASE + 0x00215054) 13 | #define AUX_MU_MSR_REG (PBASE + 0x00215058) 14 | #define AUX_MU_SCRATCH (PBASE + 0x0021505C) 15 | #define AUX_MU_CNTL_REG (PBASE + 0x00215060) 16 | #define AUX_MU_STAT_REG (PBASE + 0x00215064) 17 | #define AUX_MU_BAUD_REG (PBASE + 0x00215068) 18 | 19 | #endif /*_P_MINI_UART_H */ 20 | -------------------------------------------------------------------------------- /guests/lrtos/include/peripherals/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef _P_TIMER_H 2 | #define _P_TIMER_H 3 | 4 | #include "peripherals/base.h" 5 | 6 | #define TIMER_CS (PBASE + 0x00003000) 7 | #define TIMER_CLO (PBASE + 0x00003004) 8 | #define TIMER_CHI (PBASE + 0x00003008) 9 | #define TIMER_C0 (PBASE + 0x0000300C) 10 | #define TIMER_C1 (PBASE + 0x00003010) 11 | #define TIMER_C2 (PBASE + 0x00003014) 12 | #define TIMER_C3 (PBASE + 0x00003018) 13 | 14 | #define TIMER_CS_M0 (1 << 0) 15 | #define TIMER_CS_M1 (1 << 1) 16 | #define TIMER_CS_M2 (1 << 2) 17 | #define TIMER_CS_M3 (1 << 3) 18 | 19 | #endif /*_P_TIMER_H */ 20 | -------------------------------------------------------------------------------- /guests/lrtos/include/printf.h: -------------------------------------------------------------------------------- 1 | /* 2 | File: printf.h 3 | 4 | Copyright (C) 2004 Kustaa Nyholm 5 | 6 | This library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | This library is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | See the GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public 17 | License along with this library; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | 20 | This library is realy just two files: 'printf.h' and 'printf.c'. 21 | 22 | They provide a simple and small (+200 loc) printf functionality to 23 | be used in embedded systems. 24 | 25 | I've found them so usefull in debugging that I do not bother with a 26 | debugger at all. 27 | 28 | They are distributed in source form, so to use them, just compile them 29 | into your project. 30 | 31 | Two printf variants are provided: printf and sprintf. 32 | 33 | The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'. 34 | 35 | Zero padding and field width are also supported. 36 | 37 | If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the 38 | long specifier is also 39 | supported. Note that this will pull in some long math routines (pun intended!) 40 | and thus make your executable noticably longer. 41 | 42 | The memory foot print of course depends on the target cpu, compiler and 43 | compiler options, but a rough guestimate (based on a H8S target) is about 44 | 1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space. 45 | Not too bad. Your milage may vary. By hacking the source code you can 46 | get rid of some hunred bytes, I'm sure, but personally I feel the balance of 47 | functionality and flexibility versus code size is close to optimal for 48 | many embedded systems. 49 | 50 | To use the printf you need to supply your own character output function, 51 | something like : 52 | 53 | void putc ( void* p, char c) 54 | { 55 | while (!SERIAL_PORT_EMPTY) ; 56 | SERIAL_PORT_TX_REGISTER = c; 57 | } 58 | 59 | Before you can call printf you need to initialize it to use your 60 | character output function with something like: 61 | 62 | init_printf(NULL,putc); 63 | 64 | Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc', 65 | the NULL (or any pointer) you pass into the 'init_printf' will eventually be 66 | passed to your 'putc' routine. This allows you to pass some storage space (or 67 | anything realy) to the character output function, if necessary. 68 | This is not often needed but it was implemented like that because it made 69 | implementing the sprintf function so neat (look at the source code). 70 | 71 | The code is re-entrant, except for the 'init_printf' function, so it 72 | is safe to call it from interupts too, although this may result in mixed output. 73 | If you rely on re-entrancy, take care that your 'putc' function is re-entrant! 74 | 75 | The printf and sprintf functions are actually macros that translate to 76 | 'tfp_printf' and 'tfp_sprintf'. This makes it possible 77 | to use them along with 'stdio.h' printf's in a single source file. 78 | You just need to undef the names before you include the 'stdio.h'. 79 | Note that these are not function like macros, so if you have variables 80 | or struct members with these names, things will explode in your face. 81 | Without variadic macros this is the best we can do to wrap these 82 | fucnction. If it is a problem just give up the macros and use the 83 | functions directly or rename them. 84 | 85 | For further details see source code. 86 | 87 | regs Kusti, 23.10.2004 88 | */ 89 | 90 | #ifndef __TFP_PRINTF__ 91 | #define __TFP_PRINTF__ 92 | 93 | #include 94 | 95 | void init_printf(void *putp, void (*putf)(void *, char)); 96 | 97 | void tfp_printf(char *fmt, ...); 98 | void tfp_sprintf(char *s, char *fmt, ...); 99 | 100 | void tfp_format(void *putp, void (*putf)(void *, char), char *fmt, va_list va); 101 | 102 | #define printf tfp_printf 103 | #define sprintf tfp_sprintf 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /guests/lrtos/include/sched.h: -------------------------------------------------------------------------------- 1 | #ifndef _SCHED_H 2 | #define _SCHED_H 3 | 4 | #define THREAD_CPU_CONTEXT 0 // offset of cpu_context in task_struct 5 | 6 | #ifndef __ASSEMBLER__ 7 | 8 | #define THREAD_SIZE 4096 9 | 10 | #define NR_TASKS 64 11 | 12 | #define FIRST_TASK task[0] 13 | #define LAST_TASK task[NR_TASKS - 1] 14 | 15 | #define TASK_RUNNING 0 16 | #define TASK_ZOMBIE 1 17 | 18 | #define PF_KTHREAD 0x00000002 19 | 20 | extern struct task_struct *current; 21 | extern struct task_struct *task[NR_TASKS]; 22 | extern int nr_tasks; 23 | 24 | struct cpu_context { 25 | unsigned long x19; 26 | unsigned long x20; 27 | unsigned long x21; 28 | unsigned long x22; 29 | unsigned long x23; 30 | unsigned long x24; 31 | unsigned long x25; 32 | unsigned long x26; 33 | unsigned long x27; 34 | unsigned long x28; 35 | unsigned long fp; 36 | unsigned long sp; 37 | unsigned long pc; 38 | }; 39 | 40 | #define MAX_PROCESS_PAGES 16 41 | 42 | struct user_page { 43 | unsigned long phys_addr; 44 | unsigned long virt_addr; 45 | }; 46 | 47 | struct mm_struct { 48 | unsigned long pgd; 49 | int user_pages_count; 50 | struct user_page user_pages[MAX_PROCESS_PAGES]; 51 | int kernel_pages_count; 52 | unsigned long kernel_pages[MAX_PROCESS_PAGES]; 53 | }; 54 | 55 | struct task_struct { 56 | struct cpu_context cpu_context; 57 | long state; 58 | long counter; 59 | long priority; 60 | long preempt_count; 61 | unsigned long flags; 62 | struct mm_struct mm; 63 | }; 64 | 65 | extern void sched_init(void); 66 | extern void schedule(void); 67 | extern void timer_tick(void); 68 | extern void preempt_disable(void); 69 | extern void preempt_enable(void); 70 | extern void switch_to(struct task_struct *next); 71 | extern void cpu_switch_to(struct task_struct *prev, struct task_struct *next); 72 | extern void exit_process(void); 73 | 74 | #define INIT_TASK \ 75 | /*cpu_context*/ { \ 76 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* state etc */ 0, \ 77 | 0, 5, 0, PF_KTHREAD, \ 78 | /* mm */ { \ 79 | 0, 0, { { 0 } }, 0, \ 80 | { \ 81 | 0 \ 82 | } \ 83 | } \ 84 | } 85 | #endif 86 | #endif 87 | -------------------------------------------------------------------------------- /guests/lrtos/include/sys.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_H 2 | #define _SYS_H 3 | 4 | #define __NR_syscalls 3 5 | 6 | #ifndef __ASSEMBLER__ 7 | 8 | void sys_write(char *buf); 9 | int sys_fork(); 10 | 11 | #endif 12 | 13 | #endif /*_SYS_H */ 14 | -------------------------------------------------------------------------------- /guests/lrtos/include/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef _TIMER_H 2 | #define _TIMER_H 3 | 4 | void timer_init(void); 5 | void handle_timer_irq(void); 6 | 7 | #endif /*_TIMER_H */ 8 | -------------------------------------------------------------------------------- /guests/lrtos/include/user.h: -------------------------------------------------------------------------------- 1 | #ifndef _USER_H 2 | #define _USER_H 3 | 4 | void user_process1(char *array); 5 | void user_process(); 6 | extern unsigned long user_begin; 7 | extern unsigned long user_end; 8 | 9 | #endif /*_USER_H */ 10 | -------------------------------------------------------------------------------- /guests/lrtos/include/user_sys.h: -------------------------------------------------------------------------------- 1 | #ifndef _USER_SYS_H 2 | #define _USER_SYS_H 3 | 4 | void call_sys_write(char *buf); 5 | int call_sys_fork(); 6 | void call_sys_exit(); 7 | 8 | extern void user_delay(unsigned long); 9 | extern unsigned long get_sp(void); 10 | extern unsigned long get_pc(void); 11 | 12 | #endif /*_USER_SYS_H */ 13 | -------------------------------------------------------------------------------- /guests/lrtos/include/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTILS_H 2 | #define _UTILS_H 3 | 4 | extern void delay(unsigned long); 5 | extern void put32(unsigned long, unsigned int); 6 | extern unsigned int get32(unsigned long); 7 | extern unsigned long get_el(void); 8 | extern void set_pgd(unsigned long pgd); 9 | extern unsigned long get_pgd(); 10 | 11 | #endif /*_UTILS_H */ 12 | -------------------------------------------------------------------------------- /guests/lrtos/src/boot.S: -------------------------------------------------------------------------------- 1 | #include "arm/mmu.h" 2 | #include "arm/sysregs.h" 3 | #include "mm.h" 4 | #include "peripherals/base.h" 5 | 6 | .section ".text.boot" 7 | 8 | .globl _start 9 | _start: 10 | mrs x0, mpidr_el1 11 | and x0, x0,#0xFF // Check processor id 12 | cbz x0, master // Hang for all non-primary CPU 13 | b proc_hang 14 | 15 | proc_hang: 16 | b proc_hang 17 | 18 | master: 19 | ldr x0, =SCTLR_VALUE_MMU_DISABLED 20 | msr sctlr_el1, x0 21 | isb 22 | 23 | el1_entry: 24 | adr x0, bss_begin 25 | adr x1, bss_end 26 | sub x1, x1, x0 27 | bl memzero 28 | 29 | bl __create_idmap 30 | adrp x0, idmap_dir 31 | msr ttbr0_el1, x0 32 | 33 | bl __create_page_tables 34 | 35 | mov x0, #VA_START 36 | add sp, x0, #LOW_MEMORY 37 | 38 | adrp x0, pg_dir 39 | msr ttbr1_el1, x0 40 | 41 | ldr x0, =(TCR_VALUE) 42 | msr tcr_el1, x0 43 | 44 | ldr x0, =(MAIR_VALUE) 45 | msr mair_el1, x0 46 | 47 | ldr x2, =kernel_main 48 | 49 | mov x0, #SCTLR_MMU_ENABLED 50 | dsb ish 51 | isb 52 | msr sctlr_el1, x0 53 | isb 54 | 55 | br x2 56 | 57 | .macro create_pgd_entry, tbl, virt, tmp1, tmp2 58 | create_table_entry \tbl, \virt, PGD_SHIFT, \tmp1, \tmp2 59 | create_table_entry \tbl, \virt, PUD_SHIFT, \tmp1, \tmp2 60 | .endm 61 | 62 | .macro create_table_entry, tbl, virt, shift, tmp1, tmp2 63 | lsr \tmp1, \virt, #\shift 64 | and \tmp1, \tmp1, #PTRS_PER_TABLE - 1 // table index 65 | add \tmp2, \tbl, #PAGE_SIZE 66 | orr \tmp2, \tmp2, #MM_TYPE_PAGE_TABLE 67 | str \tmp2, [\tbl, \tmp1, lsl #3] 68 | add \tbl, \tbl, #PAGE_SIZE // next level table page 69 | .endm 70 | 71 | .macro create_block_map, tbl, phys, start, end, flags, tmp1 72 | lsr \start, \start, #SECTION_SHIFT 73 | and \start, \start, #PTRS_PER_TABLE - 1 // table index 74 | lsr \end, \end, #SECTION_SHIFT 75 | and \end, \end, #PTRS_PER_TABLE - 1 // table end index 76 | lsr \phys, \phys, #SECTION_SHIFT 77 | mov \tmp1, #\flags 78 | orr \phys, \tmp1, \phys, lsl #SECTION_SHIFT // table entry 79 | 9999: str \phys, [\tbl, \start, lsl #3] // store the entry 80 | add \start, \start, #1 // next entry 81 | add \phys, \phys, #SECTION_SIZE // next block 82 | cmp \start, \end 83 | b.ls 9999b 84 | .endm 85 | 86 | __create_idmap: 87 | mov x29, x30 88 | 89 | adrp x0, idmap_dir 90 | mov x1, #PG_DIR_SIZE 91 | bl memzero 92 | 93 | adrp x0, idmap_dir 94 | mov x1, xzr 95 | create_pgd_entry x0, x1, x2, x3 96 | 97 | mov x1, xzr 98 | mov x2, xzr 99 | ldr x3, =(PHYS_MEMORY_SIZE) 100 | create_block_map x0, x1, x2, x3, MMU_FLAGS, x4 101 | 102 | mov x30, x29 103 | ret 104 | 105 | __create_page_tables: 106 | mov x29, x30 // save return address 107 | 108 | adrp x0, pg_dir 109 | mov x1, #PG_DIR_SIZE 110 | bl memzero 111 | 112 | adrp x0, pg_dir 113 | mov x1, #VA_START 114 | create_pgd_entry x0, x1, x2, x3 115 | 116 | /* Mapping kernel and init stack*/ 117 | mov x1, xzr // start mapping from physical offset 0 118 | mov x2, #VA_START // first virtual address 119 | ldr x3, =(VA_START + DEVICE_BASE - SECTION_SIZE) // last virtual address 120 | create_block_map x0, x1, x2, x3, MMU_FLAGS, x4 121 | 122 | /* Mapping device memory*/ 123 | mov x1, #DEVICE_BASE // start mapping from device base address 124 | ldr x2, =(VA_START + DEVICE_BASE) // first virtual address 125 | ldr x3, =(VA_START + PHYS_MEMORY_SIZE - SECTION_SIZE) // last virtual address 126 | create_block_map x0, x1, x2, x3, MMU_DEVICE_FLAGS, x4 127 | 128 | mov x30, x29 // restore return address 129 | ret 130 | -------------------------------------------------------------------------------- /guests/lrtos/src/config.txt: -------------------------------------------------------------------------------- 1 | kernel_old=1 2 | disable_commandline_tags=1 3 | -------------------------------------------------------------------------------- /guests/lrtos/src/entry.S: -------------------------------------------------------------------------------- 1 | #include "arm/sysregs.h" 2 | #include "entry.h" 3 | #include "sys.h" 4 | 5 | .macro handle_invalid_entry el, type 6 | kernel_entry \el 7 | mov x0, #\type 8 | mrs x1, esr_el1 9 | mrs x2, elr_el1 10 | bl show_invalid_entry_message 11 | b err_hang 12 | .endm 13 | 14 | .macro ventry label 15 | .align 7 16 | b \label 17 | .endm 18 | 19 | .macro kernel_entry, el 20 | sub sp, sp, #S_FRAME_SIZE 21 | stp x0, x1, [sp, #16 * 0] 22 | stp x2, x3, [sp, #16 * 1] 23 | stp x4, x5, [sp, #16 * 2] 24 | stp x6, x7, [sp, #16 * 3] 25 | stp x8, x9, [sp, #16 * 4] 26 | stp x10, x11, [sp, #16 * 5] 27 | stp x12, x13, [sp, #16 * 6] 28 | stp x14, x15, [sp, #16 * 7] 29 | stp x16, x17, [sp, #16 * 8] 30 | stp x18, x19, [sp, #16 * 9] 31 | stp x20, x21, [sp, #16 * 10] 32 | stp x22, x23, [sp, #16 * 11] 33 | stp x24, x25, [sp, #16 * 12] 34 | stp x26, x27, [sp, #16 * 13] 35 | stp x28, x29, [sp, #16 * 14] 36 | 37 | .if \el == 0 38 | mrs x21, sp_el0 39 | .else 40 | add x21, sp, #S_FRAME_SIZE 41 | .endif /* \el == 0 */ 42 | 43 | mrs x22, elr_el1 44 | mrs x23, spsr_el1 45 | 46 | stp x30, x21, [sp, #16 * 15] 47 | stp x22, x23, [sp, #16 * 16] 48 | .endm 49 | 50 | .macro kernel_exit, el 51 | ldp x22, x23, [sp, #16 * 16] 52 | ldp x30, x21, [sp, #16 * 15] 53 | 54 | .if \el == 0 55 | msr sp_el0, x21 56 | .endif /* \el == 0 */ 57 | 58 | msr elr_el1, x22 59 | msr spsr_el1, x23 60 | 61 | 62 | ldp x0, x1, [sp, #16 * 0] 63 | ldp x2, x3, [sp, #16 * 1] 64 | ldp x4, x5, [sp, #16 * 2] 65 | ldp x6, x7, [sp, #16 * 3] 66 | ldp x8, x9, [sp, #16 * 4] 67 | ldp x10, x11, [sp, #16 * 5] 68 | ldp x12, x13, [sp, #16 * 6] 69 | ldp x14, x15, [sp, #16 * 7] 70 | ldp x16, x17, [sp, #16 * 8] 71 | ldp x18, x19, [sp, #16 * 9] 72 | ldp x20, x21, [sp, #16 * 10] 73 | ldp x22, x23, [sp, #16 * 11] 74 | ldp x24, x25, [sp, #16 * 12] 75 | ldp x26, x27, [sp, #16 * 13] 76 | ldp x28, x29, [sp, #16 * 14] 77 | add sp, sp, #S_FRAME_SIZE 78 | eret 79 | .endm 80 | 81 | 82 | /* 83 | * Exception vectors. 84 | */ 85 | .align 11 86 | .globl vectors 87 | vectors: 88 | ventry sync_invalid_el1t // Synchronous EL1t 89 | ventry irq_invalid_el1t // IRQ EL1t 90 | ventry fiq_invalid_el1t // FIQ EL1t 91 | ventry error_invalid_el1t // Error EL1t 92 | 93 | ventry sync_invalid_el1h // Synchronous EL1h 94 | ventry el1_irq // IRQ EL1h 95 | ventry fiq_invalid_el1h // FIQ EL1h 96 | ventry error_invalid_el1h // Error EL1h 97 | 98 | ventry el0_sync // Synchronous 64-bit EL0 99 | ventry el0_irq // IRQ 64-bit EL0 100 | ventry fiq_invalid_el0_64 // FIQ 64-bit EL0 101 | ventry error_invalid_el0_64 // Error 64-bit EL0 102 | 103 | ventry sync_invalid_el0_32 // Synchronous 32-bit EL0 104 | ventry irq_invalid_el0_32 // IRQ 32-bit EL0 105 | ventry fiq_invalid_el0_32 // FIQ 32-bit EL0 106 | ventry error_invalid_el0_32 // Error 32-bit EL0 107 | 108 | sync_invalid_el1t: 109 | handle_invalid_entry 1, SYNC_INVALID_EL1t 110 | 111 | irq_invalid_el1t: 112 | handle_invalid_entry 1, IRQ_INVALID_EL1t 113 | 114 | fiq_invalid_el1t: 115 | handle_invalid_entry 1, FIQ_INVALID_EL1t 116 | 117 | error_invalid_el1t: 118 | handle_invalid_entry 1, ERROR_INVALID_EL1t 119 | 120 | sync_invalid_el1h: 121 | handle_invalid_entry 1, SYNC_INVALID_EL1h 122 | 123 | fiq_invalid_el1h: 124 | handle_invalid_entry 1, FIQ_INVALID_EL1h 125 | 126 | error_invalid_el1h: 127 | handle_invalid_entry 1, ERROR_INVALID_EL1h 128 | 129 | fiq_invalid_el0_64: 130 | handle_invalid_entry 0, FIQ_INVALID_EL0_64 131 | 132 | error_invalid_el0_64: 133 | handle_invalid_entry 0, ERROR_INVALID_EL0_64 134 | 135 | sync_invalid_el0_32: 136 | handle_invalid_entry 0, SYNC_INVALID_EL0_32 137 | 138 | irq_invalid_el0_32: 139 | handle_invalid_entry 0, IRQ_INVALID_EL0_32 140 | 141 | fiq_invalid_el0_32: 142 | handle_invalid_entry 0, FIQ_INVALID_EL0_32 143 | 144 | error_invalid_el0_32: 145 | handle_invalid_entry 0, ERROR_INVALID_EL0_32 146 | 147 | 148 | el1_irq: 149 | kernel_entry 1 150 | bl handle_irq 151 | kernel_exit 1 152 | 153 | el0_irq: 154 | kernel_entry 0 155 | bl handle_irq 156 | kernel_exit 0 157 | 158 | el0_sync: 159 | kernel_entry 0 160 | mrs x25, esr_el1 // read the syndrome register 161 | lsr x24, x25, #ESR_ELx_EC_SHIFT // exception class 162 | cmp x24, #ESR_ELx_EC_SVC64 // SVC in 64-bit state 163 | b.eq el0_svc 164 | cmp x24, #ESR_ELx_EC_DABT_LOW // data abort in EL0 165 | b.eq el0_da 166 | handle_invalid_entry 0, SYNC_ERROR 167 | 168 | sc_nr .req x25 // number of system calls 169 | scno .req x26 // syscall number 170 | stbl .req x27 // syscall table pointer 171 | 172 | el0_svc: 173 | adr stbl, sys_call_table // load syscall table pointer 174 | uxtw scno, w8 // syscall number in w8 175 | mov sc_nr, #__NR_syscalls 176 | bl enable_irq 177 | cmp scno, sc_nr // check upper syscall limit 178 | b.hs ni_sys 179 | 180 | ldr x16, [stbl, scno, lsl #3] // address in the syscall table 181 | blr x16 // call sys_* routine 182 | b ret_from_syscall 183 | ni_sys: 184 | handle_invalid_entry 0, SYSCALL_ERROR 185 | ret_from_syscall: 186 | bl disable_irq 187 | str x0, [sp, #S_X0] // returned x0 188 | kernel_exit 0 189 | 190 | el0_da: 191 | bl enable_irq 192 | mrs x0, far_el1 193 | mrs x1, esr_el1 194 | bl do_mem_abort 195 | cmp x0, 0 196 | b.eq 1f 197 | handle_invalid_entry 0, DATA_ABORT_ERROR 198 | 1: 199 | bl disable_irq 200 | kernel_exit 0 201 | 202 | .globl ret_from_fork 203 | ret_from_fork: 204 | bl schedule_tail 205 | cbz x19, ret_to_user // not a kernel thread 206 | mov x0, x20 207 | blr x19 208 | ret_to_user: 209 | bl disable_irq 210 | kernel_exit 0 211 | 212 | 213 | .globl err_hang 214 | err_hang: b err_hang 215 | -------------------------------------------------------------------------------- /guests/lrtos/src/fork.c: -------------------------------------------------------------------------------- 1 | #include "fork.h" 2 | #include "entry.h" 3 | #include "mm.h" 4 | #include "sched.h" 5 | #include "utils.h" 6 | 7 | int copy_process(unsigned long clone_flags, unsigned long fn, unsigned long arg) 8 | { 9 | preempt_disable(); 10 | struct task_struct *p; 11 | 12 | unsigned long page = allocate_kernel_page(); 13 | p = (struct task_struct *)page; 14 | struct pt_regs *childregs = task_pt_regs(p); 15 | 16 | if (!p) 17 | return -1; 18 | 19 | if (clone_flags & PF_KTHREAD) { 20 | p->cpu_context.x19 = fn; 21 | p->cpu_context.x20 = arg; 22 | } else { 23 | struct pt_regs *cur_regs = task_pt_regs(current); 24 | *childregs = *cur_regs; 25 | childregs->regs[0] = 0; 26 | copy_virt_memory(p); 27 | } 28 | p->flags = clone_flags; 29 | p->priority = current->priority; 30 | p->state = TASK_RUNNING; 31 | p->counter = p->priority; 32 | p->preempt_count = 1; //disable preemtion until schedule_tail 33 | 34 | p->cpu_context.pc = (unsigned long)ret_from_fork; 35 | p->cpu_context.sp = (unsigned long)childregs; 36 | int pid = nr_tasks++; 37 | task[pid] = p; 38 | 39 | preempt_enable(); 40 | return pid; 41 | } 42 | 43 | int move_to_user_mode(unsigned long start, unsigned long size, unsigned long pc) 44 | { 45 | struct pt_regs *regs = task_pt_regs(current); 46 | regs->pstate = PSR_MODE_EL0t; 47 | regs->pc = pc; 48 | regs->sp = 2 * PAGE_SIZE; 49 | unsigned long code_page = allocate_user_page(current, 0); 50 | if (code_page == 0) { 51 | return -1; 52 | } 53 | memcpy(code_page, start, size); 54 | set_pgd(current->mm.pgd); 55 | return 0; 56 | } 57 | 58 | struct pt_regs *task_pt_regs(struct task_struct *tsk) 59 | { 60 | unsigned long p = 61 | (unsigned long)tsk + THREAD_SIZE - sizeof(struct pt_regs); 62 | return (struct pt_regs *)p; 63 | } 64 | -------------------------------------------------------------------------------- /guests/lrtos/src/irq.S: -------------------------------------------------------------------------------- 1 | .globl irq_vector_init 2 | irq_vector_init: 3 | adr x0, vectors // load VBAR_EL1 with virtual 4 | msr vbar_el1, x0 // vector table address 5 | ret 6 | 7 | .globl enable_irq 8 | enable_irq: 9 | msr daifclr, #2 10 | ret 11 | 12 | .globl disable_irq 13 | disable_irq: 14 | msr daifset, #2 15 | ret 16 | -------------------------------------------------------------------------------- /guests/lrtos/src/irq.c: -------------------------------------------------------------------------------- 1 | #include "peripherals/irq.h" 2 | #include "entry.h" 3 | #include "printf.h" 4 | #include "timer.h" 5 | #include "utils.h" 6 | 7 | const char *entry_error_messages[] = { 8 | "SYNC_INVALID_EL1t", "IRQ_INVALID_EL1t", 9 | "FIQ_INVALID_EL1t", "ERROR_INVALID_EL1T", 10 | 11 | "SYNC_INVALID_EL1h", "IRQ_INVALID_EL1h", 12 | "FIQ_INVALID_EL1h", "ERROR_INVALID_EL1h", 13 | 14 | "SYNC_INVALID_EL0_64", "IRQ_INVALID_EL0_64", 15 | "FIQ_INVALID_EL0_64", "ERROR_INVALID_EL0_64", 16 | 17 | "SYNC_INVALID_EL0_32", "IRQ_INVALID_EL0_32", 18 | "FIQ_INVALID_EL0_32", "ERROR_INVALID_EL0_32", 19 | 20 | "SYNC_ERROR", "SYSCALL_ERROR" 21 | }; 22 | 23 | void enable_interrupt_controller() 24 | { 25 | put32(ENABLE_IRQS_1, SYSTEM_TIMER_IRQ_1); 26 | } 27 | 28 | void show_invalid_entry_message(int type, unsigned long esr, 29 | unsigned long address) 30 | { 31 | printf("%s, ESR: %x, address: %x\r\n", entry_error_messages[type], esr, 32 | address); 33 | } 34 | 35 | void handle_irq(void) 36 | { 37 | unsigned int irq = get32(IRQ_PENDING_1); 38 | switch (irq) { 39 | case (SYSTEM_TIMER_IRQ_1): 40 | handle_timer_irq(); 41 | break; 42 | default: 43 | printf("Inknown pending irq: %x\r\n", irq); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /guests/lrtos/src/kernel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "fork.h" 5 | #include "irq.h" 6 | #include "mini_uart.h" 7 | #include "printf.h" 8 | #include "sched.h" 9 | #include "sys.h" 10 | #include "timer.h" 11 | #include "user.h" 12 | #include "utils.h" 13 | 14 | void kernel_process() 15 | { 16 | printf("Kernel process started. EL %d\r\n", get_el()); 17 | unsigned long begin = (unsigned long)&user_begin; 18 | unsigned long end = (unsigned long)&user_end; 19 | unsigned long process = (unsigned long)&user_process; 20 | int err = move_to_user_mode(begin, end - begin, process - begin); 21 | if (err < 0) { 22 | printf("Error while moving process to user mode\n\r"); 23 | } 24 | } 25 | 26 | void kernel_main() 27 | { 28 | uart_init(); 29 | init_printf(NULL, putc); 30 | irq_vector_init(); 31 | timer_init(); 32 | enable_interrupt_controller(); 33 | enable_irq(); 34 | 35 | int res = copy_process(PF_KTHREAD, (unsigned long)&kernel_process, 0); 36 | if (res < 0) { 37 | printf("error while starting kernel process"); 38 | return; 39 | } 40 | 41 | while (1) { 42 | schedule(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /guests/lrtos/src/linker.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0xffff000000000000; 4 | .text.boot : { *(.text.boot) } 5 | . = ALIGN(0x00001000); 6 | user_begin = .; 7 | .text.user : { build/user* (.text) } 8 | .rodata.user : { build/user* (.rodata) } 9 | .data.user : { build/user* (.data) } 10 | .bss.user : { build/user* (.bss) } 11 | user_end = .; 12 | .text : { *(.text) } 13 | .rodata : { *(.rodata) } 14 | .data : { *(.data) } 15 | . = ALIGN(0x8); 16 | bss_begin = .; 17 | .bss : { *(.bss*) } 18 | bss_end = .; 19 | . = ALIGN(0x00001000); 20 | idmap_dir = .; 21 | .data.idmapd : { . += (3 * (1 << 12)); } 22 | . = ALIGN(0x00001000); 23 | pg_dir = .; 24 | .data.pgd : { . += (3 * (1 << 12)); } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /guests/lrtos/src/mini_uart.c: -------------------------------------------------------------------------------- 1 | #include "peripherals/mini_uart.h" 2 | #include "peripherals/gpio.h" 3 | #include "utils.h" 4 | 5 | void uart_send(char c) 6 | { 7 | while (1) { 8 | if (get32(AUX_MU_LSR_REG) & 0x20) 9 | break; 10 | } 11 | put32(AUX_MU_IO_REG, c); 12 | } 13 | 14 | char uart_recv(void) 15 | { 16 | while (1) { 17 | if (get32(AUX_MU_LSR_REG) & 0x01) 18 | break; 19 | } 20 | return (get32(AUX_MU_IO_REG) & 0xFF); 21 | } 22 | 23 | void uart_send_string(char *str) 24 | { 25 | for (int i = 0; str[i] != '\0'; i++) { 26 | uart_send((char)str[i]); 27 | } 28 | } 29 | 30 | void uart_init(void) 31 | { 32 | unsigned int selector; 33 | 34 | selector = get32(GPFSEL1); 35 | selector &= ~(7 << 12); // clean gpio14 36 | selector |= 2 << 12; // set alt5 for gpio14 37 | selector &= ~(7 << 15); // clean gpio15 38 | selector |= 2 << 15; // set alt5 for gpio15 39 | put32(GPFSEL1, selector); 40 | 41 | put32(GPPUD, 0); 42 | delay(150); 43 | put32(GPPUDCLK0, (1 << 14) | (1 << 15)); 44 | delay(150); 45 | put32(GPPUDCLK0, 0); 46 | 47 | put32(AUX_ENABLES, 48 | 1); //Enable mini uart (this also enables access to it registers) 49 | put32(AUX_MU_CNTL_REG, 50 | 0); //Disable auto flow control and disable receiver and transmitter (for now) 51 | put32(AUX_MU_IER_REG, 0); //Disable receive and transmit interrupts 52 | put32(AUX_MU_LCR_REG, 3); //Enable 8 bit mode 53 | put32(AUX_MU_MCR_REG, 0); //Set RTS line to be always high 54 | put32(AUX_MU_BAUD_REG, 270); //Set baud rate to 115200 55 | 56 | put32(AUX_MU_CNTL_REG, 3); //Finally, enable transmitter and receiver 57 | } 58 | 59 | // This function is required by printf function 60 | void putc(void *p, char c) 61 | { 62 | uart_send(c); 63 | } 64 | -------------------------------------------------------------------------------- /guests/lrtos/src/mm.S: -------------------------------------------------------------------------------- 1 | .globl memcpy 2 | memcpy: 3 | ldr x3, [x1], #8 4 | str x3, [x0], #8 5 | subs x2, x2, #8 6 | b.gt memcpy 7 | ret 8 | 9 | .globl memzero 10 | memzero: 11 | str xzr, [x0], #8 12 | subs x1, x1, #8 13 | b.gt memzero 14 | ret 15 | -------------------------------------------------------------------------------- /guests/lrtos/src/mm.c: -------------------------------------------------------------------------------- 1 | #include "mm.h" 2 | #include "arm/mmu.h" 3 | 4 | static unsigned short mem_map[PAGING_PAGES] = { 5 | 0, 6 | }; 7 | 8 | unsigned long allocate_kernel_page() 9 | { 10 | unsigned long page = get_free_page(); 11 | if (page == 0) { 12 | return 0; 13 | } 14 | return page + VA_START; 15 | } 16 | 17 | unsigned long allocate_user_page(struct task_struct *task, unsigned long va) 18 | { 19 | unsigned long page = get_free_page(); 20 | if (page == 0) { 21 | return 0; 22 | } 23 | map_page(task, va, page); 24 | return page + VA_START; 25 | } 26 | 27 | unsigned long get_free_page() 28 | { 29 | for (int i = 0; i < PAGING_PAGES; i++) { 30 | if (mem_map[i] == 0) { 31 | mem_map[i] = 1; 32 | unsigned long page = LOW_MEMORY + i * PAGE_SIZE; 33 | memzero(page + VA_START, PAGE_SIZE); 34 | return page; 35 | } 36 | } 37 | return 0; 38 | } 39 | 40 | void free_page(unsigned long p) 41 | { 42 | mem_map[(p - LOW_MEMORY) / PAGE_SIZE] = 0; 43 | } 44 | 45 | void map_table_entry(unsigned long *pte, unsigned long va, unsigned long pa) 46 | { 47 | unsigned long index = va >> PAGE_SHIFT; 48 | index = index & (PTRS_PER_TABLE - 1); 49 | unsigned long entry = pa | MMU_PTE_FLAGS; 50 | pte[index] = entry; 51 | } 52 | 53 | unsigned long map_table(unsigned long *table, unsigned long shift, 54 | unsigned long va, int *new_table) 55 | { 56 | unsigned long index = va >> shift; 57 | index = index & (PTRS_PER_TABLE - 1); 58 | if (!table[index]) { 59 | *new_table = 1; 60 | unsigned long next_level_table = get_free_page(); 61 | unsigned long entry = next_level_table | MM_TYPE_PAGE_TABLE; 62 | table[index] = entry; 63 | return next_level_table; 64 | } else { 65 | *new_table = 0; 66 | } 67 | return table[index] & PAGE_MASK; 68 | } 69 | 70 | void map_page(struct task_struct *task, unsigned long va, unsigned long page) 71 | { 72 | unsigned long pgd; 73 | if (!task->mm.pgd) { 74 | task->mm.pgd = get_free_page(); 75 | task->mm.kernel_pages[++task->mm.kernel_pages_count] = 76 | task->mm.pgd; 77 | } 78 | pgd = task->mm.pgd; 79 | int new_table; 80 | unsigned long pud = map_table((unsigned long *)(pgd + VA_START), 81 | PGD_SHIFT, va, &new_table); 82 | if (new_table) { 83 | task->mm.kernel_pages[++task->mm.kernel_pages_count] = pud; 84 | } 85 | unsigned long pmd = map_table((unsigned long *)(pud + VA_START), 86 | PUD_SHIFT, va, &new_table); 87 | if (new_table) { 88 | task->mm.kernel_pages[++task->mm.kernel_pages_count] = pmd; 89 | } 90 | unsigned long pte = map_table((unsigned long *)(pmd + VA_START), 91 | PMD_SHIFT, va, &new_table); 92 | if (new_table) { 93 | task->mm.kernel_pages[++task->mm.kernel_pages_count] = pte; 94 | } 95 | map_table_entry((unsigned long *)(pte + VA_START), va, page); 96 | struct user_page p = { page, va }; 97 | task->mm.user_pages[task->mm.user_pages_count++] = p; 98 | } 99 | 100 | int copy_virt_memory(struct task_struct *dst) 101 | { 102 | struct task_struct *src = current; 103 | for (int i = 0; i < src->mm.user_pages_count; i++) { 104 | unsigned long kernel_va = allocate_user_page( 105 | dst, src->mm.user_pages[i].virt_addr); 106 | if (kernel_va == 0) { 107 | return -1; 108 | } 109 | memcpy(kernel_va, src->mm.user_pages[i].virt_addr, PAGE_SIZE); 110 | } 111 | return 0; 112 | } 113 | 114 | static int ind = 1; 115 | 116 | int do_mem_abort(unsigned long addr, unsigned long esr) 117 | { 118 | unsigned long dfs = (esr & 0b111111); 119 | if ((dfs & 0b111100) == 0b100) { 120 | unsigned long page = get_free_page(); 121 | if (page == 0) { 122 | return -1; 123 | } 124 | map_page(current, addr & PAGE_MASK, page); 125 | ind++; 126 | if (ind > 2) { 127 | return -1; 128 | } 129 | return 0; 130 | } 131 | return -1; 132 | } 133 | -------------------------------------------------------------------------------- /guests/lrtos/src/printf.c: -------------------------------------------------------------------------------- 1 | /* 2 | File: printf.c 3 | 4 | Copyright (C) 2004 Kustaa Nyholm 5 | 6 | This library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | This library is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public 17 | License along with this library; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | 20 | */ 21 | 22 | #include "printf.h" 23 | 24 | typedef void (*putcf)(void *, char); 25 | static putcf stdout_putf; 26 | static void *stdout_putp; 27 | 28 | #ifdef PRINTF_LONG_SUPPORT 29 | 30 | static void uli2a(unsigned long int num, unsigned int base, int uc, char *bf) 31 | { 32 | int n = 0; 33 | unsigned int d = 1; 34 | while (num / d >= base) 35 | d *= base; 36 | while (d != 0) { 37 | int dgt = num / d; 38 | num %= d; 39 | d /= base; 40 | if (n || dgt > 0 || d == 0) { 41 | *bf++ = dgt + (dgt < 10 ? '0' : (uc ? 'A' : 'a') - 10); 42 | ++n; 43 | } 44 | } 45 | *bf = 0; 46 | } 47 | 48 | static void li2a(long num, char *bf) 49 | { 50 | if (num < 0) { 51 | num = -num; 52 | *bf++ = '-'; 53 | } 54 | uli2a(num, 10, 0, bf); 55 | } 56 | 57 | #endif 58 | 59 | static void ui2a(unsigned int num, unsigned int base, int uc, char *bf) 60 | { 61 | int n = 0; 62 | unsigned int d = 1; 63 | while (num / d >= base) 64 | d *= base; 65 | while (d != 0) { 66 | int dgt = num / d; 67 | num %= d; 68 | d /= base; 69 | if (n || dgt > 0 || d == 0) { 70 | *bf++ = dgt + (dgt < 10 ? '0' : (uc ? 'A' : 'a') - 10); 71 | ++n; 72 | } 73 | } 74 | *bf = 0; 75 | } 76 | 77 | static void i2a(int num, char *bf) 78 | { 79 | if (num < 0) { 80 | num = -num; 81 | *bf++ = '-'; 82 | } 83 | ui2a(num, 10, 0, bf); 84 | } 85 | 86 | static int a2d(char ch) 87 | { 88 | if (ch >= '0' && ch <= '9') 89 | return ch - '0'; 90 | else if (ch >= 'a' && ch <= 'f') 91 | return ch - 'a' + 10; 92 | else if (ch >= 'A' && ch <= 'F') 93 | return ch - 'A' + 10; 94 | else 95 | return -1; 96 | } 97 | 98 | static char a2i(char ch, char **src, int base, int *nump) 99 | { 100 | char *p = *src; 101 | int num = 0; 102 | int digit; 103 | while ((digit = a2d(ch)) >= 0) { 104 | if (digit > base) 105 | break; 106 | num = num * base + digit; 107 | ch = *p++; 108 | } 109 | *src = p; 110 | *nump = num; 111 | return ch; 112 | } 113 | 114 | static void putchw(void *putp, putcf putf, int n, char z, char *bf) 115 | { 116 | char fc = z ? '0' : ' '; 117 | char ch; 118 | char *p = bf; 119 | while (*p++ && n > 0) 120 | n--; 121 | while (n-- > 0) 122 | putf(putp, fc); 123 | while ((ch = *bf++)) 124 | putf(putp, ch); 125 | } 126 | 127 | void tfp_format(void *putp, putcf putf, char *fmt, va_list va) 128 | { 129 | char bf[12]; 130 | 131 | char ch; 132 | 133 | while ((ch = *(fmt++))) { 134 | if (ch != '%') 135 | putf(putp, ch); 136 | else { 137 | char lz = 0; 138 | #ifdef PRINTF_LONG_SUPPORT 139 | char lng = 0; 140 | #endif 141 | int w = 0; 142 | ch = *(fmt++); 143 | if (ch == '0') { 144 | ch = *(fmt++); 145 | lz = 1; 146 | } 147 | if (ch >= '0' && ch <= '9') { 148 | ch = a2i(ch, &fmt, 10, &w); 149 | } 150 | #ifdef PRINTF_LONG_SUPPORT 151 | if (ch == 'l') { 152 | ch = *(fmt++); 153 | lng = 1; 154 | } 155 | #endif 156 | switch (ch) { 157 | case 0: 158 | goto abort; 159 | case 'u': { 160 | #ifdef PRINTF_LONG_SUPPORT 161 | if (lng) 162 | uli2a(va_arg(va, unsigned long int), 10, 163 | 0, bf); 164 | else 165 | #endif 166 | ui2a(va_arg(va, unsigned int), 10, 0, 167 | bf); 168 | putchw(putp, putf, w, lz, bf); 169 | break; 170 | } 171 | case 'd': { 172 | #ifdef PRINTF_LONG_SUPPORT 173 | if (lng) 174 | li2a(va_arg(va, unsigned long int), bf); 175 | else 176 | #endif 177 | i2a(va_arg(va, int), bf); 178 | putchw(putp, putf, w, lz, bf); 179 | break; 180 | } 181 | case 'x': 182 | case 'X': 183 | #ifdef PRINTF_LONG_SUPPORT 184 | if (lng) 185 | uli2a(va_arg(va, unsigned long int), 16, 186 | (ch == 'X'), bf); 187 | else 188 | #endif 189 | ui2a(va_arg(va, unsigned int), 16, 190 | (ch == 'X'), bf); 191 | putchw(putp, putf, w, lz, bf); 192 | break; 193 | case 'c': 194 | putf(putp, (char)(va_arg(va, int))); 195 | break; 196 | case 's': 197 | putchw(putp, putf, w, 0, va_arg(va, char *)); 198 | break; 199 | case '%': 200 | putf(putp, ch); 201 | default: 202 | break; 203 | } 204 | } 205 | } 206 | abort:; 207 | } 208 | 209 | void init_printf(void *putp, void (*putf)(void *, char)) 210 | { 211 | stdout_putf = putf; 212 | stdout_putp = putp; 213 | } 214 | 215 | void tfp_printf(char *fmt, ...) 216 | { 217 | va_list va; 218 | va_start(va, fmt); 219 | tfp_format(stdout_putp, stdout_putf, fmt, va); 220 | va_end(va); 221 | } 222 | 223 | static void putcp(void *p, char c) 224 | { 225 | *(*((char **)p))++ = c; 226 | } 227 | 228 | void tfp_sprintf(char *s, char *fmt, ...) 229 | { 230 | va_list va; 231 | va_start(va, fmt); 232 | tfp_format(&s, putcp, fmt, va); 233 | putcp(&s, 0); 234 | va_end(va); 235 | } 236 | -------------------------------------------------------------------------------- /guests/lrtos/src/sched.S: -------------------------------------------------------------------------------- 1 | #include "sched.h" 2 | 3 | .globl cpu_switch_to 4 | cpu_switch_to: 5 | mov x10, #THREAD_CPU_CONTEXT 6 | add x8, x0, x10 7 | mov x9, sp 8 | stp x19, x20, [x8], #16 // store callee-saved registers 9 | stp x21, x22, [x8], #16 10 | stp x23, x24, [x8], #16 11 | stp x25, x26, [x8], #16 12 | stp x27, x28, [x8], #16 13 | stp x29, x9, [x8], #16 14 | str x30, [x8] 15 | add x8, x1, x10 16 | ldp x19, x20, [x8], #16 // restore callee-saved registers 17 | ldp x21, x22, [x8], #16 18 | ldp x23, x24, [x8], #16 19 | ldp x25, x26, [x8], #16 20 | ldp x27, x28, [x8], #16 21 | ldp x29, x9, [x8], #16 22 | ldr x30, [x8] 23 | mov sp, x9 24 | ret 25 | 26 | 27 | -------------------------------------------------------------------------------- /guests/lrtos/src/sched.c: -------------------------------------------------------------------------------- 1 | #include "sched.h" 2 | #include "irq.h" 3 | #include "mm.h" 4 | #include "printf.h" 5 | #include "utils.h" 6 | 7 | static struct task_struct init_task = INIT_TASK; 8 | struct task_struct *current = &(init_task); 9 | struct task_struct *task[NR_TASKS] = { 10 | &(init_task), 11 | }; 12 | int nr_tasks = 1; 13 | 14 | void preempt_disable(void) 15 | { 16 | current->preempt_count++; 17 | } 18 | 19 | void preempt_enable(void) 20 | { 21 | current->preempt_count--; 22 | } 23 | 24 | void _schedule(void) 25 | { 26 | preempt_disable(); 27 | int next, c; 28 | struct task_struct *p; 29 | while (1) { 30 | c = -1; 31 | next = 0; 32 | for (int i = 0; i < NR_TASKS; i++) { 33 | p = task[i]; 34 | if (p && p->state == TASK_RUNNING && p->counter > c) { 35 | c = p->counter; 36 | next = i; 37 | } 38 | } 39 | if (c) { 40 | break; 41 | } 42 | for (int i = 0; i < NR_TASKS; i++) { 43 | p = task[i]; 44 | if (p) { 45 | p->counter = (p->counter >> 1) + p->priority; 46 | } 47 | } 48 | } 49 | switch_to(task[next]); 50 | preempt_enable(); 51 | } 52 | 53 | void schedule(void) 54 | { 55 | current->counter = 0; 56 | _schedule(); 57 | } 58 | 59 | void switch_to(struct task_struct *next) 60 | { 61 | if (current == next) 62 | return; 63 | struct task_struct *prev = current; 64 | current = next; 65 | set_pgd(next->mm.pgd); 66 | cpu_switch_to(prev, next); 67 | } 68 | 69 | void schedule_tail(void) 70 | { 71 | preempt_enable(); 72 | } 73 | 74 | void timer_tick() 75 | { 76 | --current->counter; 77 | if (current->counter > 0 || current->preempt_count > 0) { 78 | return; 79 | } 80 | current->counter = 0; 81 | enable_irq(); 82 | _schedule(); 83 | disable_irq(); 84 | } 85 | 86 | void exit_process() 87 | { 88 | preempt_disable(); 89 | for (int i = 0; i < NR_TASKS; i++) { 90 | if (task[i] == current) { 91 | task[i]->state = TASK_ZOMBIE; 92 | break; 93 | } 94 | } 95 | preempt_enable(); 96 | schedule(); 97 | } 98 | -------------------------------------------------------------------------------- /guests/lrtos/src/sys.c: -------------------------------------------------------------------------------- 1 | #include "fork.h" 2 | #include "mm.h" 3 | #include "printf.h" 4 | #include "sched.h" 5 | #include "utils.h" 6 | 7 | void sys_write(char *buf) 8 | { 9 | printf(buf); 10 | } 11 | 12 | int sys_fork() 13 | { 14 | return copy_process(0, 0, 0); 15 | } 16 | 17 | void sys_exit() 18 | { 19 | exit_process(); 20 | } 21 | 22 | void *const sys_call_table[] = { sys_write, sys_fork, sys_exit }; 23 | -------------------------------------------------------------------------------- /guests/lrtos/src/timer.c: -------------------------------------------------------------------------------- 1 | #include "peripherals/timer.h" 2 | #include "printf.h" 3 | #include "sched.h" 4 | #include "utils.h" 5 | 6 | const unsigned int interval = 60000; 7 | unsigned int curVal = 0; 8 | 9 | void timer_init(void) 10 | { 11 | curVal = get32(TIMER_CLO); 12 | curVal += interval; 13 | put32(TIMER_C1, curVal); 14 | } 15 | 16 | void handle_timer_irq(void) 17 | { 18 | curVal += interval; 19 | put32(TIMER_C1, curVal); 20 | put32(TIMER_CS, TIMER_CS_M1); 21 | timer_tick(); 22 | } 23 | -------------------------------------------------------------------------------- /guests/lrtos/src/user.c: -------------------------------------------------------------------------------- 1 | #include "user.h" 2 | #include "printf.h" 3 | #include "user_sys.h" 4 | 5 | void loop(char *str) 6 | { 7 | char buf[2] = { "" }; 8 | while (1) { 9 | for (int i = 0; i < 5; i++) { 10 | buf[0] = str[i]; 11 | call_sys_write(buf); 12 | user_delay(10000000); 13 | } 14 | } 15 | } 16 | 17 | void user_process() 18 | { 19 | call_sys_write("User process\n\r"); 20 | int pid = call_sys_fork(); 21 | if (pid < 0) { 22 | call_sys_write("Error during fork\n\r"); 23 | call_sys_exit(); 24 | return; 25 | } 26 | if (pid == 0) { 27 | loop("12345"); 28 | } else { 29 | loop("abcde"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /guests/lrtos/src/user_sys.S: -------------------------------------------------------------------------------- 1 | .section ".text.user" 2 | 3 | .set SYS_WRITE_NUMBER, 0 // syscal numbers 4 | .set SYS_FORK_NUMBER, 1 5 | .set SYS_EXIT_NUMBER, 2 6 | 7 | .globl user_delay 8 | user_delay: 9 | subs x0, x0, #1 10 | bne user_delay 11 | ret 12 | 13 | .globl call_sys_write 14 | call_sys_write: 15 | mov w8, #SYS_WRITE_NUMBER 16 | svc #0 17 | ret 18 | 19 | .globl call_sys_exit 20 | call_sys_exit: 21 | mov w8, #SYS_EXIT_NUMBER 22 | svc #0 23 | ret 24 | 25 | .globl call_sys_fork 26 | call_sys_fork: 27 | mov w8, #SYS_FORK_NUMBER 28 | svc #0 29 | ret 30 | -------------------------------------------------------------------------------- /guests/lrtos/src/utils.S: -------------------------------------------------------------------------------- 1 | .globl get_el 2 | get_el: 3 | mrs x0, CurrentEL 4 | lsr x0, x0, #2 5 | ret 6 | 7 | .globl put32 8 | put32: 9 | str w1,[x0] 10 | ret 11 | 12 | .globl get32 13 | get32: 14 | ldr w0,[x0] 15 | ret 16 | 17 | .globl delay 18 | delay: 19 | subs x0, x0, #1 20 | bne delay 21 | ret 22 | 23 | .globl set_pgd 24 | set_pgd: 25 | msr ttbr0_el1, x0 26 | tlbi vmalle1is 27 | DSB ISH // ensure completion of TLB invalidation 28 | isb 29 | ret 30 | 31 | .globl get_pgd 32 | get_pgd: 33 | mov x1, 0 34 | ldr x0, [x1] 35 | mov x0, 0x1000 36 | msr ttbr0_el1, x0 37 | ldr x0, [x1] 38 | ret 39 | 40 | -------------------------------------------------------------------------------- /guests/uboot/uboot.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calinyara/avisor/ebde0d4dbf95f7ed9a20baf1e2c71b7ca0e8bed5/guests/uboot/uboot.bin -------------------------------------------------------------------------------- /hypervisor/Makefile: -------------------------------------------------------------------------------- 1 | #// SPDX-License-Identifier: GPL-2.0-or-later 2 | #/* 3 | # * aVisor Hypervisor 4 | # * 5 | # * A Tiny Hypervisor for IoT Development 6 | # * 7 | # * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | # */ 9 | 10 | GNU_TOOLS ?= aarch64-linux-gnu 11 | GNU_GCC = $(GNU_TOOLS)-gcc 12 | GNU_LD = $(GNU_TOOLS)-ld 13 | GNU_OBJCOPY = $(GNU_TOOLS)-objcopy 14 | 15 | INC_DIR = ../include 16 | C_OPS = -Wall -nostdlib -nostartfiles -ffreestanding -I$(INC_DIR) -mgeneral-regs-only 17 | ASM_OPS = -I$(INC_DIR) 18 | 19 | BUILD_DIR = build 20 | 21 | SRC_DIR += arch/aarch64 22 | SRC_DIR += boards/raspi 23 | SRC_DIR += common 24 | SRC_DIR += fs 25 | SRC_DIR += emulator/raspi 26 | 27 | HV_DIR = ./ 28 | 29 | .PHONY: all 30 | all: kernel8.img 31 | 32 | .PHONY: qemu 33 | qemu: qemu.img 34 | 35 | C_FILES = $(wildcard *.c $(foreach fd, $(SRC_DIR), $(fd)/*.c)) 36 | ASM_FILES =$(wildcard *.S $(foreach fd, $(SRC_DIR), $(fd)/*.S)) 37 | 38 | $(BUILD_DIR)/%_c.o: %.c 39 | mkdir -p $(dir $@) 40 | $(GNU_GCC) $(C_OPS) -MMD -c $< -o $@ 41 | 42 | $(BUILD_DIR)/%_s.o: %.S 43 | mkdir -p $(dir $@) 44 | $(GNU_GCC) $(ASM_OPS) -MMD -c $< -o $@ 45 | 46 | OBJ_FILES = $(C_FILES:%.c=$(BUILD_DIR)/%_c.o) 47 | OBJ_FILES += $(ASM_FILES:%.S=$(BUILD_DIR)/%_s.o) 48 | 49 | DEP_FILES = $(OBJ_FILES:%.o=%.d) 50 | -include $(DEP_FILES) 51 | 52 | LINKER_FILE = $(HV_DIR)/boards/raspi/linker.ld 53 | LINKER_FILE_QEMU = $(HV_DIR)/boards/raspi/linker_qemu.ld 54 | 55 | kernel8.img: $(LINKER_FILE) $(OBJ_FILES) 56 | $(GNU_LD) -T $(LINKER_FILE) -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) 57 | $(GNU_OBJCOPY) $(BUILD_DIR)/kernel8.elf -O binary $(BUILD_DIR)/kernel8.img 58 | 59 | qemu.img: $(LINKER_FILE_QEMU) $(OBJ_FILES) 60 | $(GNU_LD) -T $(LINKER_FILE_QEMU) -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) 61 | $(GNU_OBJCOPY) $(BUILD_DIR)/kernel8.elf -O binary $(BUILD_DIR)/kernel8.img 62 | 63 | .PHONY: clean 64 | clean: 65 | rm -rf $(BUILD_DIR) 66 | 67 | .PHONY: echoes 68 | echoes: 69 | @echo "C_FILES: $(C_FILES)" 70 | @echo "ASM_FILES: $(ASM_FILES)" 71 | @echo "OBJ_FILES: $(OBJ_FILES)" 72 | @echo "SRC_DIR: $(SRC_DIR)" 73 | -------------------------------------------------------------------------------- /hypervisor/arch/aarch64/boot.S: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #include "arch/aarch64/mmu.h" 11 | #include "arch/aarch64/sysregs.h" 12 | #include "boards/raspi/base.h" 13 | #include "common/mm.h" 14 | 15 | .section ".text.boot" 16 | 17 | .globl _start 18 | _start: 19 | mrs x0, mpidr_el1 20 | /* Check processor id */ 21 | and x0, x0,#0xFF 22 | /* Hang for all non-primary CPU */ 23 | cbz x0, master 24 | b proc_hang 25 | 26 | proc_hang: 27 | b proc_hang 28 | 29 | master: 30 | ldr x0, =SCTLR_VALUE_MMU_DISABLED 31 | msr sctlr_el2, x0 32 | 33 | /* 34 | * Initial EL for Real HW is 3, for QEMU is 2 35 | * Change EL from 3 to 2 36 | */ 37 | mrs x0, CurrentEL 38 | lsr x0, x0, #2 39 | cmp x0, #3 40 | beq el3 41 | 42 | ldr x0, =HCR_VALUE 43 | msr hcr_el2, x0 44 | 45 | ldr x0, =SPSR_VALUE 46 | msr spsr_el2, x0 47 | 48 | adr x0, el2_entry 49 | msr elr_el2, x0 50 | eret 51 | 52 | el3: 53 | ldr x0, =HCR_VALUE 54 | msr hcr_el2, x0 55 | 56 | ldr x0, =SCR_VALUE 57 | msr scr_el3, x0 58 | 59 | ldr x0, =SPSR_VALUE 60 | msr spsr_el3, x0 61 | 62 | adr x0, el2_entry 63 | msr elr_el3, x0 64 | 65 | eret 66 | 67 | el2_entry: 68 | adr x0, bss_begin 69 | adr x1, bss_end 70 | sub x1, x1, x0 71 | bl memzero 72 | 73 | bl __create_page_tables 74 | 75 | mov x0, #VA_START 76 | add sp, x0, #LOW_MEMORY 77 | 78 | adrp x0, pg_dir 79 | msr ttbr0_el2, x0 80 | 81 | ldr x0, =(TCR_VALUE) 82 | msr tcr_el2, x0 83 | 84 | ldr x0, =(VTCR_VALUE) 85 | msr vtcr_el2, x0 86 | 87 | ldr x0, =(MAIR_VALUE) 88 | msr mair_el2, x0 89 | 90 | /* clear TLB */ 91 | tlbi alle1 92 | 93 | ldr x2, =hypervisor_main 94 | 95 | mov x0, #SCTLR_MMU_ENABLED 96 | dsb ish 97 | isb 98 | msr sctlr_el2, x0 99 | isb 100 | 101 | br x2 102 | 103 | .macro create_pgd_entry, tbl, virt, tmp1, tmp2 104 | create_table_entry \tbl, \virt, PGD_SHIFT, \tmp1, \tmp2 105 | create_table_entry \tbl, \virt, PUD_SHIFT, \tmp1, \tmp2 106 | .endm 107 | 108 | .macro create_table_entry, tbl, virt, shift, tmp1, tmp2 109 | lsr \tmp1, \virt, #\shift 110 | and \tmp1, \tmp1, #PTRS_PER_TABLE - 1 /* table index */ 111 | add \tmp2, \tbl, #PAGE_SIZE 112 | orr \tmp2, \tmp2, #MM_TYPE_PAGE_TABLE 113 | str \tmp2, [\tbl, \tmp1, lsl #3] 114 | add \tbl, \tbl, #PAGE_SIZE /* next level table page */ 115 | .endm 116 | 117 | .macro create_block_map, tbl, phys, start, end, flags, tmp1 118 | lsr \start, \start, #SECTION_SHIFT 119 | and \start, \start, #PTRS_PER_TABLE - 1 /* table index */ 120 | lsr \end, \end, #SECTION_SHIFT 121 | and \end, \end, #PTRS_PER_TABLE - 1 /* table end index */ 122 | lsr \phys, \phys, #SECTION_SHIFT 123 | mov \tmp1, #\flags 124 | orr \phys, \tmp1, \phys, lsl #SECTION_SHIFT /* table entry */ 125 | 1: str \phys, [\tbl, \start, lsl #3] /* store the entry */ 126 | add \start, \start, #1 /* next entry */ 127 | add \phys, \phys, #SECTION_SIZE /* next block */ 128 | cmp \start, \end 129 | b.ls 1b 130 | .endm 131 | 132 | __create_page_tables: 133 | /* save return address */ 134 | mov x29, x30 135 | 136 | adrp x0, pg_dir 137 | mov x1, #PG_DIR_SIZE 138 | bl memzero 139 | 140 | adrp x0, pg_dir 141 | mov x1, #VA_START 142 | create_pgd_entry x0, x1, x2, x3 143 | 144 | /* Mapping kernel and init stack */ 145 | mov x1, xzr /* start mapping from physical offset 0 */ 146 | mov x2, #VA_START /* first virtual address */ 147 | ldr x3, =(VA_START + DEVICE_BASE - SECTION_SIZE) /* last virtual address */ 148 | create_block_map x0, x1, x2, x3, MMU_FLAGS, x4 149 | 150 | /* Mapping device memory */ 151 | mov x1, #DEVICE_BASE /* start mapping from device base address */ 152 | ldr x2, =(VA_START + DEVICE_BASE) /* first virtual address */ 153 | ldr x3, =(VA_START + PHYS_MEMORY_SIZE - SECTION_SIZE) /* last virtual address */ 154 | create_block_map x0, x1, x2, x3, MMU_DEVICE_FLAGS, x4 155 | 156 | /* restore return address */ 157 | mov x30, x29 158 | ret 159 | -------------------------------------------------------------------------------- /hypervisor/arch/aarch64/entry.S: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #include "arch/aarch64/sysregs.h" 11 | #include "common/entry.h" 12 | 13 | .macro handle_invalid_entry type 14 | kernel_entry 15 | mov x0, #\type 16 | mrs x1, esr_el2 17 | mrs x2, elr_el2 18 | mrs x3, far_el2 19 | bl show_invalid_entry_message 20 | b err_hang 21 | .endm 22 | 23 | .macro ventry label 24 | .align 7 25 | b \label 26 | .endm 27 | 28 | .macro kernel_entry 29 | sub sp, sp, #S_FRAME_SIZE 30 | stp x0, x1, [sp, #16 * 0] 31 | stp x2, x3, [sp, #16 * 1] 32 | stp x4, x5, [sp, #16 * 2] 33 | stp x6, x7, [sp, #16 * 3] 34 | stp x8, x9, [sp, #16 * 4] 35 | stp x10, x11, [sp, #16 * 5] 36 | stp x12, x13, [sp, #16 * 6] 37 | stp x14, x15, [sp, #16 * 7] 38 | stp x16, x17, [sp, #16 * 8] 39 | stp x18, x19, [sp, #16 * 9] 40 | stp x20, x21, [sp, #16 * 10] 41 | stp x22, x23, [sp, #16 * 11] 42 | stp x24, x25, [sp, #16 * 12] 43 | stp x26, x27, [sp, #16 * 13] 44 | stp x28, x29, [sp, #16 * 14] 45 | 46 | add x21, sp, #S_FRAME_SIZE 47 | 48 | mrs x22, elr_el2 49 | mrs x23, spsr_el2 50 | 51 | stp x30, x21, [sp, #16 * 15] 52 | stp x22, x23, [sp, #16 * 16] 53 | 54 | bl vm_leaving_work 55 | .endm 56 | 57 | .macro kernel_exit 58 | bl vm_entering_work 59 | 60 | ldp x30, x21, [sp, #16 * 15] 61 | ldp x22, x23, [sp, #16 * 16] 62 | 63 | msr elr_el2, x22 64 | msr spsr_el2, x23 65 | 66 | ldp x0, x1, [sp, #16 * 0] 67 | ldp x2, x3, [sp, #16 * 1] 68 | ldp x4, x5, [sp, #16 * 2] 69 | ldp x6, x7, [sp, #16 * 3] 70 | ldp x8, x9, [sp, #16 * 4] 71 | ldp x10, x11, [sp, #16 * 5] 72 | ldp x12, x13, [sp, #16 * 6] 73 | ldp x14, x15, [sp, #16 * 7] 74 | ldp x16, x17, [sp, #16 * 8] 75 | ldp x18, x19, [sp, #16 * 9] 76 | ldp x20, x21, [sp, #16 * 10] 77 | ldp x22, x23, [sp, #16 * 11] 78 | ldp x24, x25, [sp, #16 * 12] 79 | ldp x26, x27, [sp, #16 * 13] 80 | ldp x28, x29, [sp, #16 * 14] 81 | add sp, sp, #S_FRAME_SIZE 82 | eret 83 | .endm 84 | 85 | 86 | /* 87 | * Exception Vectors. 88 | */ 89 | .align 11 90 | .globl vectors 91 | vectors: 92 | ventry sync_invalid_el2 // Synchronous EL2 93 | ventry irq_invalid_el2 // IRQ EL2 94 | ventry fiq_invalid_el2 // FIQ EL2 95 | ventry error_invalid_el2 // Error EL2 96 | 97 | ventry sync_invalid_el2 // Synchronous EL2 98 | ventry el2_irq // IRQ EL2 99 | ventry fiq_invalid_el2 // FIQ EL2 100 | ventry error_invalid_el2 // Error EL2 101 | 102 | ventry el01_sync // Synchronous 64-bit EL0 or 1 103 | ventry el01_irq // IRQ 64-bit EL0 or 1 104 | ventry fiq_invalid_el01_64 // FIQ 64-bit EL0 or 1 105 | ventry error_invalid_el01_64 // Error 64-bit EL0 or 1 106 | 107 | ventry sync_invalid_el01_32 // Synchronous 32-bit EL0 or 1 108 | ventry irq_invalid_el01_32 // IRQ 32-bit EL0 or 1 109 | ventry fiq_invalid_el01_32 // FIQ 32-bit EL0 or 1 110 | ventry error_invalid_el01_32 // Error 32-bit EL0 or 1 111 | 112 | sync_invalid_el2: 113 | handle_invalid_entry SYNC_INVALID_EL2 114 | 115 | irq_invalid_el2: 116 | handle_invalid_entry IRQ_INVALID_EL2 117 | 118 | fiq_invalid_el2: 119 | handle_invalid_entry FIQ_INVALID_EL2 120 | 121 | error_invalid_el2: 122 | handle_invalid_entry ERROR_INVALID_EL2 123 | 124 | fiq_invalid_el01_64: 125 | handle_invalid_entry FIQ_INVALID_EL01_64 126 | 127 | error_invalid_el01_64: 128 | handle_invalid_entry ERROR_INVALID_EL01_64 129 | 130 | sync_invalid_el01_32: 131 | handle_invalid_entry SYNC_INVALID_EL01_32 132 | 133 | irq_invalid_el01_32: 134 | handle_invalid_entry IRQ_INVALID_EL01_32 135 | 136 | fiq_invalid_el01_32: 137 | handle_invalid_entry FIQ_INVALID_EL01_32 138 | 139 | error_invalid_el01_32: 140 | handle_invalid_entry ERROR_INVALID_EL01_32 141 | 142 | 143 | el2_irq: 144 | kernel_entry 145 | bl handle_irq 146 | kernel_exit 147 | 148 | el01_irq: 149 | kernel_entry 150 | bl handle_irq 151 | kernel_exit 152 | 153 | el01_sync: 154 | kernel_entry 155 | mrs x0, esr_el2 156 | mrs x1, elr_el2 157 | mrs x2, far_el2 158 | /* hvc number in x8 */ 159 | mov x3, x8 160 | bl handle_sync_exception 161 | kernel_exit 162 | 163 | .globl switch_from_kthread 164 | switch_from_kthread: 165 | mov x0, x20 166 | mov x1, x21 167 | mov x3, x22 168 | mov x4, x23 169 | blr x19 170 | kernel_exit 171 | 172 | .globl err_hang 173 | err_hang: b err_hang 174 | -------------------------------------------------------------------------------- /hypervisor/arch/aarch64/irq.S: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | .globl irq_vector_init 11 | irq_vector_init: 12 | adr x0, vectors /* load VBAR_EL2 with virtual address */ 13 | msr vbar_el2, x0 /* vector table address */ 14 | ret 15 | 16 | .globl enable_irq 17 | enable_irq: 18 | msr daifclr, #2 19 | ret 20 | 21 | .globl disable_irq 22 | disable_irq: 23 | msr daifset, #2 24 | ret 25 | -------------------------------------------------------------------------------- /hypervisor/arch/aarch64/sched.S: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #include "common/sched.h" 11 | 12 | .globl cpu_switch_to 13 | cpu_switch_to: 14 | mov x10, #THREAD_CPU_CONTEXT 15 | add x8, x0, x10 16 | mov x9, sp 17 | stp x19, x20, [x8], #16 /* store callee-saved registers */ 18 | stp x21, x22, [x8], #16 19 | stp x23, x24, [x8], #16 20 | stp x25, x26, [x8], #16 21 | stp x27, x28, [x8], #16 22 | stp x29, x9, [x8], #16 23 | str x30, [x8] 24 | add x8, x1, x10 25 | ldp x19, x20, [x8], #16 /* restore callee-saved registers */ 26 | ldp x21, x22, [x8], #16 27 | ldp x23, x24, [x8], #16 28 | ldp x25, x26, [x8], #16 29 | ldp x27, x28, [x8], #16 30 | ldp x29, x9, [x8], #16 31 | ldr x30, [x8] 32 | mov sp, x9 33 | ret 34 | -------------------------------------------------------------------------------- /hypervisor/arch/aarch64/sync_exc.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #include "common/sync_exc.h" 11 | #include "arch/aarch64/sysregs.h" 12 | #include "common/debug.h" 13 | #include "common/irq.h" 14 | #include "common/mm.h" 15 | #include "common/sched.h" 16 | #include "common/task.h" 17 | 18 | const char *sync_error_reasons[] = { 19 | "Unknown reason.", 20 | "Trapped WFI or WFE instruction execution.", 21 | "(unknown)", 22 | "Trapped MCR or MRC access with (coproc==0b1111).", 23 | "Trapped MCRR or MRRC access with (coproc==0b1111).", 24 | "Trapped MCR or MRC access with (coproc==0b1110).", 25 | "Trapped LDC or STC access.", 26 | "Access to SVE, Advanced SIMD, or floating-point functionality trapped by CPACR_EL1.FPEN, CPTR_EL2.FPEN, CPTR_EL2.TFP, or CPTR_EL3.TFP control.", 27 | "Trapped VMRS access, from ID group trap.", 28 | "Trapped use of a Pointer authentication instruction because HCR_EL2.API == 0 || SCR_EL3.API == 0.", 29 | "(unknown)", 30 | "(unknown)", 31 | "Trapped MRRC access with (coproc==0b1110).", 32 | "Branch Target Exception.", 33 | "Illegal Execution state.", 34 | "(unknown)", 35 | "(unknown)", 36 | "SVC instruction execution in AArch32 state.", 37 | "HVC instruction execution in AArch32 state.", 38 | "SMC instruction execution in AArch32 state.", 39 | "(unknown)", 40 | "SVC instruction execution in AArch64 state.", 41 | "HVC instruction execution in AArch64 state.", 42 | "SMC instruction execution in AArch64 state.", 43 | "Trapped MSR, MRS or System instruction execution in AArch64 state.", 44 | "Access to SVE functionality trapped as a result of CPACR_EL1.ZEN, CPTR_EL2.ZEN, CPTR_EL2.TZ, or CPTR_EL3.EZ.", 45 | "Trapped ERET, ERETAA, or ERETAB instruction execution.", 46 | "(unknown)", 47 | "Exception from a Pointer Authentication instruction authentication failure.", 48 | "(unknown)", 49 | "(unknown)", 50 | "(unknown)", 51 | "Instruction Abort from a lower Exception level.", 52 | "Instruction Abort taken without a change in Exception level.", 53 | "PC alignment fault exception.", 54 | "(unknown)", 55 | "Data Abort from a lower Exception level.", 56 | "Data Abort without a change in Exception level, or Data Aborts taken to EL2 as a result of accesses generated associated with VNCR_EL2 as part of nested virtualization support.", 57 | "SP alignment fault exception.", 58 | "(unknown)", 59 | "Trapped floating-point exception taken from AArch32 state.", 60 | "(unknown)", 61 | "(unknown)", 62 | "(unknown)", 63 | "Trapped floating-point exception taken from AArch64 state.", 64 | "(unknown)", 65 | "(unknown)", 66 | "SError interrupt.", 67 | "Breakpoint exception from a lower Exception level.", 68 | "Breakpoint exception taken without a change in Exception level.", 69 | "Software Step exception from a lower Exception level.", 70 | "Software Step exception taken without a change in Exception level.", 71 | "Watchpoint from a lower Exception level.", 72 | "Watchpoint exceptions without a change in Exception level, or Watchpoint exceptions taken to EL2 as a result of accesses generated associated with VNCR_EL2 as part of nested virtualization support.", 73 | "(unknown)", 74 | "(unknown)", 75 | "BKPT instruction execution in AArch32 state.", 76 | "(unknown)", 77 | "Vector Catch exception from AArch32 state.", 78 | "(unknown)", 79 | "BRK instruction execution in AArch64 state.", 80 | }; 81 | 82 | void handle_trap_wfx() 83 | { 84 | schedule(); 85 | increment_current_pc(4); 86 | } 87 | 88 | void handle_hvc64(unsigned long hvc_nr) 89 | { 90 | WARN("HVC #%d", hvc_nr); 91 | } 92 | 93 | void handle_trap_system(unsigned long esr) 94 | { 95 | /* msr(reg) */ 96 | #define DEFINE_SYSREG_MSR(name, _op1, _crn, _crm, _op2) \ 97 | do { \ 98 | if (op1 == (_op1) && crn == (_crn) && crm == (_crm) && \ 99 | op2 == (_op2)) { \ 100 | current->cpu_sysregs.name = regs->regs[rt]; \ 101 | goto sys_fin; \ 102 | } \ 103 | } while (0) 104 | 105 | /* mrs */ 106 | #define DEFINE_SYSREG_MRS(name, _op1, _crn, _crm, _op2) \ 107 | do { \ 108 | if (op1 == (_op1) && crn == (_crn) && crm == (_crm) && \ 109 | op2 == (_op2)) { \ 110 | regs->regs[rt] = current->cpu_sysregs.name; \ 111 | goto sys_fin; \ 112 | } \ 113 | } while (0) 114 | 115 | struct pt_regs *regs = task_pt_regs(current); 116 | 117 | unsigned int op0 = (esr >> 20) & 0x3; 118 | unsigned int op2 = (esr >> 17) & 0x7; 119 | unsigned int op1 = (esr >> 14) & 0x7; 120 | unsigned int crn = (esr >> 10) & 0xf; 121 | unsigned int rt = (esr >> 5) & 0x1f; 122 | unsigned int crm = (esr >> 1) & 0xf; 123 | unsigned int dir = esr & 0x1; 124 | 125 | // INFO("trap_system: op0=%u,op2=%u,op1=%u,crn=%u,rt=%u,crm=%u,dir=%u", 126 | // op0, op2, op1, crn, rt, crm, dir); 127 | 128 | if ((op0 & 2) && dir == 0) { 129 | DEFINE_SYSREG_MSR(actlr_el1, 0, 1, 0, 1); 130 | DEFINE_SYSREG_MSR(csselr_el1, 1, 0, 0, 0); 131 | } else if ((op0 & 2) && dir == 1) { 132 | DEFINE_SYSREG_MRS(actlr_el1, 0, 1, 0, 1); 133 | DEFINE_SYSREG_MRS(id_pfr0_el1, 0, 0, 1, 0); 134 | DEFINE_SYSREG_MRS(id_pfr1_el1, 0, 0, 1, 1); 135 | DEFINE_SYSREG_MRS(id_mmfr0_el1, 0, 0, 1, 4); 136 | DEFINE_SYSREG_MRS(id_mmfr1_el1, 0, 0, 1, 5); 137 | DEFINE_SYSREG_MRS(id_mmfr2_el1, 0, 0, 1, 6); 138 | DEFINE_SYSREG_MRS(id_mmfr3_el1, 0, 0, 1, 7); 139 | DEFINE_SYSREG_MRS(id_isar0_el1, 0, 0, 2, 0); 140 | DEFINE_SYSREG_MRS(id_isar1_el1, 0, 0, 2, 1); 141 | DEFINE_SYSREG_MRS(id_isar2_el1, 0, 0, 2, 2); 142 | DEFINE_SYSREG_MRS(id_isar3_el1, 0, 0, 2, 3); 143 | DEFINE_SYSREG_MRS(id_isar4_el1, 0, 0, 2, 4); 144 | DEFINE_SYSREG_MRS(id_isar5_el1, 0, 0, 2, 5); 145 | DEFINE_SYSREG_MRS(mvfr0_el1, 0, 0, 3, 0); 146 | DEFINE_SYSREG_MRS(mvfr1_el1, 0, 0, 3, 1); 147 | DEFINE_SYSREG_MRS(mvfr2_el1, 0, 0, 3, 2); 148 | DEFINE_SYSREG_MRS(id_aa64pfr0_el1, 0, 0, 4, 0); 149 | DEFINE_SYSREG_MRS(id_aa64pfr1_el1, 0, 0, 4, 1); 150 | DEFINE_SYSREG_MRS(id_aa64dfr0_el1, 0, 0, 5, 0); 151 | DEFINE_SYSREG_MRS(id_aa64dfr1_el1, 0, 0, 5, 1); 152 | DEFINE_SYSREG_MRS(id_aa64isar0_el1, 0, 0, 6, 0); 153 | DEFINE_SYSREG_MRS(id_aa64isar1_el1, 0, 0, 6, 1); 154 | DEFINE_SYSREG_MRS(id_aa64mmfr0_el1, 0, 0, 7, 0); 155 | DEFINE_SYSREG_MRS(id_aa64mmfr1_el1, 0, 0, 7, 1); 156 | DEFINE_SYSREG_MRS(id_aa64afr0_el1, 0, 0, 5, 4); 157 | DEFINE_SYSREG_MRS(id_aa64afr1_el1, 0, 0, 5, 5); 158 | DEFINE_SYSREG_MRS(ctr_el0, 3, 0, 0, 1); 159 | DEFINE_SYSREG_MRS(ccsidr_el1, 1, 0, 0, 0); 160 | DEFINE_SYSREG_MRS(clidr_el1, 1, 0, 0, 1); 161 | DEFINE_SYSREG_MRS(csselr_el1, 2, 0, 0, 0); 162 | DEFINE_SYSREG_MRS(aidr_el1, 1, 0, 0, 7); 163 | DEFINE_SYSREG_MRS(revidr_el1, 0, 0, 0, 6); 164 | } 165 | 166 | WARN("system register access is not handled."); 167 | sys_fin: 168 | increment_current_pc(4); 169 | return; 170 | } 171 | 172 | #define ESR_EL2_EC_SHIFT 26 173 | 174 | #define ESR_EL2_EC_TRAP_WFX 1 175 | #define ESR_EL2_EC_TRAP_FP_REG 7 176 | #define ESR_EL2_EC_HVC64 22 177 | #define ESR_EL2_EC_TRAP_SYSTEM 24 178 | #define ESR_EL2_EC_TRAP_SVE 25 179 | #define ESR_EL2_EC_DABT_LOW 36 180 | 181 | void handle_sync_exception(unsigned long esr, unsigned long elr, 182 | unsigned long far, unsigned long hvc_nr) 183 | { 184 | int eclass = (esr >> ESR_EL2_EC_SHIFT) & 0x3f; 185 | 186 | switch (eclass) { 187 | case ESR_EL2_EC_TRAP_WFX: 188 | current->stat.wfx_trap_count++; 189 | handle_trap_wfx(); 190 | break; 191 | case ESR_EL2_EC_TRAP_FP_REG: 192 | WARN("TRAP_FP_REG is not implemented."); 193 | break; 194 | case ESR_EL2_EC_HVC64: 195 | current->stat.hvc_trap_count++; 196 | handle_hvc64(hvc_nr); 197 | break; 198 | case ESR_EL2_EC_TRAP_SYSTEM: 199 | current->stat.sysreg_trap_count++; 200 | handle_trap_system(esr); 201 | break; 202 | case ESR_EL2_EC_TRAP_SVE: 203 | WARN("TRAP_SVE is not implemented."); 204 | break; 205 | case ESR_EL2_EC_DABT_LOW: 206 | if (handle_mem_abort(far, esr) < 0) 207 | PANIC("handle_mem_abort() failed."); 208 | break; 209 | default: 210 | PANIC("uncaught synchronous exception:\n%s\nesr: %x, address: %x", 211 | sync_error_reasons[eclass], esr, elr); 212 | break; 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /hypervisor/arch/aarch64/task.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #include "common/task.h" 11 | #include "common/board.h" 12 | #include "common/debug.h" 13 | #include "common/entry.h" 14 | #include "common/fifo.h" 15 | #include "common/mm.h" 16 | #include "common/sched.h" 17 | #include "common/utils.h" 18 | #include "emulator/raspi/bcm2837.h" 19 | 20 | int uart_forwarded_task = 0; 21 | 22 | struct pt_regs *task_pt_regs(struct task_struct *tsk) 23 | { 24 | unsigned long p = 25 | (unsigned long)tsk + THREAD_SIZE - sizeof(struct pt_regs); 26 | return (struct pt_regs *)p; 27 | } 28 | 29 | static void prepare_task(loader_func_t loader, void *arg) 30 | { 31 | INFO("loading..."); 32 | 33 | struct pt_regs *regs = task_pt_regs(current); 34 | regs->pstate = PSR_MODE_EL1h; 35 | /* interrupt mask */ 36 | regs->pstate |= (0xf << 6); 37 | 38 | if (loader(arg, regs) < 0) 39 | PANIC("failed to load"); 40 | 41 | set_cpu_sysregs(current); 42 | 43 | INFO("loaded"); 44 | } 45 | 46 | static struct cpu_sysregs initial_sysregs; 47 | 48 | static void prepare_initial_sysregs(void) 49 | { 50 | static int is_first_call = 1; 51 | 52 | if (!is_first_call) 53 | return; 54 | 55 | get_all_sysregs(&initial_sysregs); 56 | 57 | /* Disable MMU */ 58 | initial_sysregs.sctlr_el1 &= ~1; 59 | 60 | is_first_call = 0; 61 | } 62 | 63 | void increment_current_pc(int ilen) 64 | { 65 | struct pt_regs *regs = task_pt_regs(current); 66 | regs->pc += ilen; 67 | } 68 | 69 | int create_task(loader_func_t loader, void *arg) 70 | { 71 | struct task_struct *p; 72 | 73 | p = (struct task_struct *)allocate_page(); 74 | struct pt_regs *childregs = task_pt_regs(p); 75 | 76 | if (!p) 77 | return -1; 78 | 79 | p->cpu_context.x19 = (unsigned long)prepare_task; 80 | p->cpu_context.x20 = (unsigned long)loader; 81 | p->cpu_context.x21 = (unsigned long)arg; 82 | p->flags = 0; 83 | p->priority = current->priority; 84 | p->state = TASK_RUNNING; 85 | p->counter = p->priority; 86 | (void)strncpy(p->name, "VM", 36); 87 | 88 | p->board_ops = &bcm2837_board_ops; 89 | if (HAVE_FUNC(p->board_ops, initialize)) 90 | p->board_ops->initialize(p); 91 | 92 | prepare_initial_sysregs(); 93 | memcpy(&p->cpu_sysregs, &initial_sysregs, sizeof(struct cpu_sysregs)); 94 | 95 | p->cpu_context.pc = (unsigned long)switch_from_kthread; 96 | p->cpu_context.sp = (unsigned long)childregs; 97 | int pid = nr_tasks++; 98 | task[pid] = p; 99 | p->pid = pid; 100 | 101 | init_task_console(p); 102 | 103 | return pid; 104 | } 105 | 106 | void init_task_console(struct task_struct *tsk) 107 | { 108 | tsk->console.in_fifo = create_fifo(); 109 | tsk->console.out_fifo = create_fifo(); 110 | } 111 | 112 | void flush_task_console(struct task_struct *tsk) 113 | { 114 | struct fifo *outfifo = tsk->console.out_fifo; 115 | unsigned long val; 116 | 117 | while (dequeue_fifo(outfifo, &val) == 0) 118 | printf("%c", val & 0xff); 119 | } 120 | 121 | void init_initial_task() 122 | { 123 | (void)strncpy(task[0]->name, "HV", 36); 124 | } 125 | -------------------------------------------------------------------------------- /hypervisor/arch/aarch64/utils.S: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | .globl memcpy 11 | memcpy: 12 | ldr x3, [x1], #8 13 | str x3, [x0], #8 14 | subs x2, x2, #8 15 | b.gt memcpy 16 | ret 17 | 18 | .globl memzero 19 | memzero: 20 | str xzr, [x0], #8 21 | subs x1, x1, #8 22 | b.gt memzero 23 | ret 24 | 25 | .globl get_el 26 | get_el: 27 | mrs x0, CurrentEL 28 | lsr x0, x0, #2 29 | ret 30 | 31 | .globl put32 32 | put32: 33 | str w1,[x0] 34 | ret 35 | 36 | .globl get32 37 | get32: 38 | ldr w0,[x0] 39 | ret 40 | 41 | .globl delay 42 | delay: 43 | subs x0, x0, #1 44 | bne delay 45 | ret 46 | 47 | .globl set_stage2_pgd 48 | set_stage2_pgd: 49 | /* prepare VMID */ 50 | and x1, x1, #0xff 51 | lsl x1, x1, #48 52 | /* set VMID */ 53 | orr x0, x0, x1 54 | /* set address of PGD */ 55 | msr vttbr_el2, x0 56 | dsb ish 57 | isb 58 | ret 59 | 60 | .globl restore_sysregs 61 | restore_sysregs: 62 | ldp x1, x2, [x0], #16 63 | msr sctlr_el1, x1 64 | msr ttbr0_el1, x2 65 | ldp x1, x2, [x0], #16 66 | msr ttbr1_el1, x1 67 | msr tcr_el1, x2 68 | ldp x1, x2, [x0], #16 69 | msr esr_el1, x1 70 | msr far_el1, x2 71 | ldp x1, x2, [x0], #16 72 | msr afsr0_el1, x1 73 | msr afsr1_el1, x2 74 | ldp x1, x2, [x0], #16 75 | msr mair_el1, x1 76 | msr amair_el1, x2 77 | ldp x1, x2, [x0], #16 78 | msr contextidr_el1, x1 79 | msr cpacr_el1, x2 80 | ldp x1, x2, [x0], #16 81 | msr elr_el1, x1 82 | msr fpcr, x2 83 | ldp x1, x2, [x0], #16 84 | msr fpsr, x1 85 | msr vpidr_el2, x2 /* for virtualization */ 86 | ldp x1, x2, [x0], #16 87 | msr vmpidr_el2, x1 /* for virtualization */ 88 | msr par_el1, x2 89 | ldp x1, x2, [x0], #16 90 | msr sp_el0, x1 91 | msr sp_el1, x2 92 | ldp x1, x2, [x0], #16 93 | msr spsr_el1, x1 94 | msr tpidr_el0, x2 95 | ldp x1, x2, [x0], #16 96 | msr tpidr_el1, x1 97 | msr tpidrro_el0, x2 98 | ldr x1, [x0] 99 | msr vbar_el1, x1 100 | dsb ish 101 | isb 102 | ret 103 | 104 | .globl save_sysregs 105 | save_sysregs: 106 | dsb ish 107 | isb 108 | mrs x1, sctlr_el1 109 | mrs x2, ttbr0_el1 110 | stp x1, x2, [x0], #16 111 | mrs x1, ttbr1_el1 112 | mrs x2, tcr_el1 113 | stp x1, x2, [x0], #16 114 | mrs x1, esr_el1 115 | mrs x2, far_el1 116 | stp x1, x2, [x0], #16 117 | mrs x1, afsr0_el1 118 | mrs x2, afsr1_el1 119 | stp x1, x2, [x0], #16 120 | mrs x1, mair_el1 121 | mrs x2, amair_el1 122 | stp x1, x2, [x0], #16 123 | mrs x1, contextidr_el1 124 | mrs x2, cpacr_el1 125 | stp x1, x2, [x0], #16 126 | mrs x1, elr_el1 127 | mrs x2, fpcr 128 | stp x1, x2, [x0], #16 129 | mrs x1, fpsr 130 | mrs x2, midr_el1 131 | stp x1, x2, [x0], #16 132 | mrs x1, mpidr_el1 133 | mrs x2, par_el1 134 | stp x1, x2, [x0], #16 135 | mrs x1, sp_el0 136 | mrs x2, sp_el1 137 | stp x1, x2, [x0], #16 138 | mrs x1, spsr_el1 139 | mrs x2, tpidr_el0 140 | stp x1, x2, [x0], #16 141 | mrs x1, tpidr_el1 142 | mrs x2, tpidrro_el0 143 | stp x1, x2, [x0], #16 144 | mrs x1, vbar_el1 145 | str x1, [x0] 146 | ret 147 | 148 | .globl get_all_sysregs 149 | get_all_sysregs: 150 | mrs x1, sctlr_el1 151 | mrs x2, ttbr0_el1 152 | stp x1, x2, [x0], #16 153 | mrs x1, ttbr1_el1 154 | mrs x2, tcr_el1 155 | stp x1, x2, [x0], #16 156 | mrs x1, esr_el1 157 | mrs x2, far_el1 158 | stp x1, x2, [x0], #16 159 | mrs x1, afsr0_el1 160 | mrs x2, afsr1_el1 161 | stp x1, x2, [x0], #16 162 | mrs x1, mair_el1 163 | mrs x2, amair_el1 164 | stp x1, x2, [x0], #16 165 | mrs x1, contextidr_el1 166 | mrs x2, cpacr_el1 167 | stp x1, x2, [x0], #16 168 | mrs x1, elr_el1 169 | mrs x2, fpcr 170 | stp x1, x2, [x0], #16 171 | mrs x1, fpsr 172 | mrs x2, midr_el1 173 | stp x1, x2, [x0], #16 174 | mrs x1, mpidr_el1 175 | mrs x2, par_el1 176 | stp x1, x2, [x0], #16 177 | mrs x1, sp_el0 178 | mrs x2, sp_el1 179 | stp x1, x2, [x0], #16 180 | mrs x1, spsr_el1 181 | mrs x2, tpidr_el0 182 | stp x1, x2, [x0], #16 183 | mrs x1, tpidr_el1 184 | mrs x2, tpidrro_el0 185 | stp x1, x2, [x0], #16 186 | mrs x1, vbar_el1 187 | mrs x2, actlr_el1 188 | stp x1, x2, [x0], #16 189 | mrs x1, id_pfr0_el1 190 | mrs x2, id_pfr1_el1 191 | stp x1, x2, [x0], #16 192 | mrs x1, id_mmfr0_el1 193 | mrs x2, id_mmfr1_el1 194 | stp x1, x2, [x0], #16 195 | mrs x1, id_mmfr2_el1 196 | mrs x2, id_mmfr3_el1 197 | stp x1, x2, [x0], #16 198 | mrs x1, id_isar0_el1 199 | mrs x2, id_isar1_el1 200 | stp x1, x2, [x0], #16 201 | mrs x1, id_isar2_el1 202 | mrs x2, id_isar3_el1 203 | stp x1, x2, [x0], #16 204 | mrs x1, id_isar4_el1 205 | mrs x2, id_isar5_el1 206 | stp x1, x2, [x0], #16 207 | mrs x1, mvfr0_el1 208 | mrs x2, mvfr1_el1 209 | stp x1, x2, [x0], #16 210 | mrs x1, mvfr2_el1 211 | mrs x2, id_aa64pfr0_el1 212 | stp x1, x2, [x0], #16 213 | mrs x1, id_aa64pfr1_el1 214 | mrs x2, id_aa64dfr0_el1 215 | stp x1, x2, [x0], #16 216 | mrs x1, id_aa64dfr1_el1 217 | mrs x2, id_aa64isar0_el1 218 | stp x1, x2, [x0], #16 219 | mrs x1, id_aa64isar1_el1 220 | mrs x2, id_aa64mmfr0_el1 221 | stp x1, x2, [x0], #16 222 | mrs x1, id_aa64mmfr1_el1 223 | mrs x2, id_aa64afr0_el1 224 | stp x1, x2, [x0], #16 225 | mrs x1, id_aa64afr1_el1 226 | mrs x2, ctr_el0 227 | stp x1, x2, [x0], #16 228 | mrs x1, ccsidr_el1 229 | mrs x2, clidr_el1 230 | stp x1, x2, [x0], #16 231 | mrs x1, csselr_el1 232 | mrs x2, aidr_el1 233 | stp x1, x2, [x0], #16 234 | mrs x1, revidr_el1 235 | mrs x2, cntkctl_el1 236 | stp x1, x2, [x0], #16 237 | mrs x1, cntp_ctl_el0 238 | mrs x2, cntp_cval_el0 239 | stp x1, x2, [x0], #16 240 | mrs x1, cntp_tval_el0 241 | mrs x2, cntv_ctl_el0 242 | stp x1, x2, [x0], #16 243 | mrs x1, cntv_cval_el0 244 | mrs x2, cntv_tval_el0 245 | stp x1, x2, [x0], #16 246 | ret 247 | 248 | .globl assert_vfiq 249 | assert_vfiq: 250 | mrs x0, hcr_el2 251 | orr x1, x0, #0x40 252 | msr hcr_el2, x1 253 | ret 254 | 255 | .globl assert_virq 256 | assert_virq: 257 | mrs x0, hcr_el2 258 | orr x1, x0, #0x80 259 | msr hcr_el2, x1 260 | ret 261 | 262 | .globl assert_vserror 263 | assert_vserror: 264 | mrs x0, hcr_el2 265 | orr x1, x0, #0x100 266 | msr hcr_el2, x1 267 | ret 268 | 269 | .globl clear_vfiq 270 | clear_vfiq: 271 | mrs x0, hcr_el2 272 | bic x1, x0, #0x40 273 | msr hcr_el2, x1 274 | ret 275 | 276 | .globl clear_virq 277 | clear_virq: 278 | mrs x0, hcr_el2 279 | bic x1, x0, #0x80 280 | msr hcr_el2, x1 281 | ret 282 | 283 | .globl clear_vserror 284 | clear_vserror: 285 | mrs x0, hcr_el2 286 | bic x1, x0, #0x100 287 | msr hcr_el2, x1 288 | ret 289 | 290 | .globl translate_el1 291 | translate_el1: 292 | at s1e1r, x0 293 | mrs x0, par_el1 294 | ret 295 | -------------------------------------------------------------------------------- /hypervisor/boards/raspi/config.txt: -------------------------------------------------------------------------------- 1 | kernel_old=1 2 | disable_commandline_tags=1 3 | -------------------------------------------------------------------------------- /hypervisor/boards/raspi/irq.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #include "boards/raspi/irq.h" 11 | #include "arch/aarch64/sysregs.h" 12 | #include "common/debug.h" 13 | #include "common/entry.h" 14 | #include "common/mini_uart.h" 15 | #include "common/sched.h" 16 | #include "common/timer.h" 17 | #include "common/utils.h" 18 | 19 | const char *entry_error_messages[] = { 20 | "SYNC_INVALID_EL2", 21 | "IRQ_INVALID_EL2", 22 | "FIQ_INVALID_EL2", 23 | "ERROR_INVALID_EL2", 24 | 25 | "SYNC_INVALID_EL01_64", 26 | "IRQ_INVALID_EL01_64", 27 | "FIQ_INVALID_EL01_64", 28 | "ERROR_INVALID_EL01_64", 29 | 30 | "SYNC_INVALID_EL01_32", 31 | "IRQ_INVALID_EL01_32", 32 | "FIQ_INVALID_EL01_32", 33 | "ERROR_INVALID_EL01_32", 34 | }; 35 | 36 | void enable_interrupt_controller() 37 | { 38 | put32(ENABLE_IRQS_1, SYSTEM_TIMER_IRQ_1_BIT); 39 | put32(ENABLE_IRQS_1, SYSTEM_TIMER_IRQ_3_BIT); 40 | put32(ENABLE_IRQS_1, AUX_IRQ_BIT); 41 | } 42 | 43 | void show_invalid_entry_message(int type, unsigned long esr, unsigned long elr, 44 | unsigned long far) 45 | { 46 | PANIC("uncaught exception(%s) esr: %x, elr: %x, far: %x", 47 | entry_error_messages[type], esr, elr, far); 48 | } 49 | 50 | void handle_irq(void) 51 | { 52 | unsigned int irq = get32(IRQ_PENDING_1); 53 | if (irq & SYSTEM_TIMER_IRQ_1_BIT) { 54 | irq &= ~SYSTEM_TIMER_IRQ_1_BIT; 55 | handle_timer1_irq(); 56 | } 57 | 58 | if (irq & SYSTEM_TIMER_IRQ_3_BIT) { 59 | irq &= ~SYSTEM_TIMER_IRQ_3_BIT; 60 | handle_timer3_irq(); 61 | } 62 | 63 | if (irq & AUX_IRQ_BIT) { 64 | irq &= ~AUX_IRQ_BIT; 65 | handle_uart_irq(); 66 | } 67 | 68 | if (irq) 69 | WARN("unknown pending irq: %x", irq); 70 | } 71 | -------------------------------------------------------------------------------- /hypervisor/boards/raspi/linker.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0000000000000000; 4 | .text.boot : { *(.text.boot) } 5 | . = ALIGN(0x00001000); 6 | el1_test_begin = .; 7 | .text.user : { build/el1_* (.text) } 8 | .rodata.user : { build/el1_* (.rodata) } 9 | .data.user : { build/el1_* (.data) } 10 | .bss.user : { build/el1_* (.bss) } 11 | el1_test_end = .; 12 | .text : { *(.text) } 13 | .rodata : { *(.rodata) } 14 | .data : { *(.data) } 15 | . = ALIGN(0x8); 16 | bss_begin = .; 17 | .bss : { *(.bss*) } 18 | bss_end = .; 19 | . = ALIGN(0x00001000); 20 | pg_dir = .; 21 | .data.pgd : { . += (3 * (1 << 12)); } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /hypervisor/boards/raspi/linker_qemu.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x0000000000080000; 4 | .text.boot : { *(.text.boot) } 5 | . = ALIGN(0x00001000); 6 | el1_test_begin = .; 7 | .text.user : { build/el1_* (.text) } 8 | .rodata.user : { build/el1_* (.rodata) } 9 | .data.user : { build/el1_* (.data) } 10 | .bss.user : { build/el1_* (.bss) } 11 | el1_test_end = .; 12 | .text : { *(.text) } 13 | .rodata : { *(.rodata) } 14 | .data : { *(.data) } 15 | . = ALIGN(0x8); 16 | bss_begin = .; 17 | .bss : { *(.bss*) } 18 | bss_end = .; 19 | . = ALIGN(0x00001000); 20 | pg_dir = .; 21 | .data.pgd : { . += (3 * (1 << 12)); } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /hypervisor/boards/raspi/mini_uart.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #include "boards/raspi/mini_uart.h" 11 | #include "boards/raspi/gpio.h" 12 | #include "common/fifo.h" 13 | #include "common/printf.h" 14 | #include "common/sched.h" 15 | #include "common/shell.h" 16 | #include "common/task.h" 17 | #include "common/utils.h" 18 | 19 | void uart_send(char c) 20 | { 21 | while (1) { 22 | if (get32(AUX_MU_LSR_REG) & 0x20) 23 | break; 24 | } 25 | put32(AUX_MU_IO_REG, c); 26 | } 27 | 28 | char uart_recv(void) 29 | { 30 | while (1) { 31 | if (get32(AUX_MU_LSR_REG) & 0x01) 32 | break; 33 | } 34 | 35 | char c = get32(AUX_MU_IO_REG) & 0xFF; 36 | 37 | return c; 38 | } 39 | 40 | int is_uart_forwarded_task(struct task_struct *tsk) 41 | { 42 | return tsk->pid == uart_forwarded_task; 43 | } 44 | 45 | #define ESCAPE_CHAR '@' 46 | 47 | void handle_uart_irq(void) 48 | { 49 | int tsk_id; 50 | /* 0 is the hypervisor */ 51 | if (uart_forwarded_task == 0) { 52 | shell_kick(); 53 | } else { 54 | static int is_escaped = 0; 55 | 56 | char received = get32(AUX_MU_IO_REG) & 0xff; 57 | 58 | struct task_struct *tsk; 59 | if (is_escaped) { 60 | is_escaped = 0; 61 | if (isdigit(received)) { 62 | tsk_id = received - '0'; 63 | if (tsk_id > nr_tasks - 1) 64 | goto clear_int; 65 | uart_forwarded_task = tsk_id; 66 | printf("\nSwitched to console: %d\n", 67 | uart_forwarded_task); 68 | tsk = task[uart_forwarded_task]; 69 | if (tsk->state == TASK_RUNNING) 70 | flush_task_console(tsk); 71 | } else if (received == 'l') { 72 | show_task_list(); 73 | } else if (received == ESCAPE_CHAR) { 74 | goto enqueue_char; 75 | } 76 | } else if (received == ESCAPE_CHAR) { 77 | is_escaped = 1; 78 | } else { 79 | enqueue_char: 80 | tsk = task[uart_forwarded_task]; 81 | if (tsk->state == TASK_RUNNING) 82 | enqueue_fifo(tsk->console.in_fifo, received); 83 | } 84 | } 85 | 86 | clear_int: 87 | /* clear interrupt */ 88 | put32(AUX_MU_IIR_REG, 0x2); 89 | } 90 | 91 | void uart_init(void) 92 | { 93 | unsigned int selector; 94 | 95 | selector = get32(GPFSEL1); 96 | selector &= ~(7 << 12); /* clean gpio14 */ 97 | selector |= 2 << 12; /* set alt5 for gpio14 */ 98 | selector &= ~(7 << 15); /* clean gpio15 */ 99 | selector |= 2 << 15; /* set alt5 for gpio15 */ 100 | put32(GPFSEL1, selector); 101 | 102 | put32(GPPUD, 0); 103 | delay(150); 104 | put32(GPPUDCLK0, (1 << 14) | (1 << 15)); 105 | delay(150); 106 | put32(GPPUDCLK0, 0); 107 | 108 | put32(AUX_ENABLES, 109 | 1); /* Enable mini uart (this also enables access to it registers) */ 110 | put32(AUX_MU_CNTL_REG, 111 | 0); /* Disable auto flow control and disable receiver */ 112 | /* and transmitter (for now) */ 113 | put32(AUX_MU_IER_REG, 1); /* Enable receive interrupt */ 114 | put32(AUX_MU_LCR_REG, 3); /* Enable 8 bit mode */ 115 | put32(AUX_MU_MCR_REG, 0); /* Set RTS line to be always high */ 116 | put32(AUX_MU_BAUD_REG, 270); /* Set baud rate to 115200 */ 117 | 118 | put32(AUX_MU_CNTL_REG, 119 | 3); /* Finally, enable transmitter and receiver */ 120 | } 121 | 122 | /* This function is required by printf function */ 123 | void _putchar(char c) 124 | { 125 | uart_send(c); 126 | } 127 | -------------------------------------------------------------------------------- /hypervisor/boards/raspi/phys2bus.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #include "boards/raspi/phys2bus.h" 11 | 12 | unsigned long phys_to_bus(unsigned long phys) 13 | { 14 | return 0xc0000000 | phys; 15 | } 16 | 17 | unsigned long bus_to_phys(unsigned long bus) 18 | { 19 | return bus & ~0xc0000000; 20 | } 21 | -------------------------------------------------------------------------------- /hypervisor/boards/raspi/raspi3b.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #include "boards/raspi/raspi3b.h" 11 | #include "common/mm.h" 12 | #include "common/types.h" 13 | 14 | static uint8_t rasp3b_page_memap[PAGING_PAGES] = { 0 }; 15 | 16 | static struct page_pool rasp3b_page_pool = { 17 | .start_addr = LOW_MEMORY, 18 | .page_nr = PAGING_PAGES, 19 | .memap = rasp3b_page_memap, 20 | .last_page_id = 0, 21 | }; 22 | 23 | struct page_pool *get_rasp3b_page_pool(void) 24 | { 25 | return &rasp3b_page_pool; 26 | } 27 | -------------------------------------------------------------------------------- /hypervisor/boards/raspi/timer.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #include "boards/raspi/timer.h" 11 | #include "common/board.h" 12 | #include "common/debug.h" 13 | #include "common/sched.h" 14 | #include "common/utils.h" 15 | 16 | const unsigned int interval = 400000; 17 | 18 | void timer_init(void) 19 | { 20 | put32(TIMER_C1, get32(TIMER_CLO) + interval); 21 | } 22 | 23 | /* for task switch */ 24 | void handle_timer1_irq(void) 25 | { 26 | put32(TIMER_C1, get32(TIMER_CLO) + interval); 27 | put32(TIMER_CS, TIMER_CS_M1); 28 | timer_tick(); 29 | } 30 | 31 | /* for vm's interrupt */ 32 | void handle_timer3_irq(void) 33 | { 34 | put32(TIMER_CS, TIMER_CS_M3); 35 | } 36 | 37 | unsigned long get_physical_timer_count(void) 38 | { 39 | unsigned long clo = get32(TIMER_CLO); 40 | unsigned long chi = get32(TIMER_CHI); 41 | return clo | (chi << 32); 42 | } 43 | 44 | unsigned long get_system_timer(void) 45 | { 46 | unsigned int h = -1, l; 47 | 48 | // we must read MMIO area as two separate 32 bit reads 49 | h = get32(TIMER_CHI); 50 | l = get32(TIMER_CLO); 51 | 52 | // we have to repeat it if high word changed during read 53 | if (h != get32(TIMER_CHI)) { 54 | h = get32(TIMER_CHI); 55 | l = get32(TIMER_CLO); 56 | } 57 | 58 | // compose long int value 59 | return ((unsigned long)h << 32) | l; 60 | } 61 | 62 | void show_systimer_info(void) 63 | { 64 | printf("HI: %x\nLO: %x\nCS:%x\nC1: %x\nC3: %x\n", get32(TIMER_CHI), 65 | get32(TIMER_CLO), get32(TIMER_CS), get32(TIMER_C1), 66 | get32(TIMER_C3)); 67 | } 68 | -------------------------------------------------------------------------------- /hypervisor/common/delays.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | * 9 | * Copyright (C) 2018 bzt (bztsrc@github) 10 | * 11 | * Permission is hereby granted, free of charge, to any person 12 | * obtaining a copy of this software and associated documentation 13 | * files (the "Software"), to deal in the Software without 14 | * restriction, including without limitation the rights to use, copy, 15 | * modify, merge, publish, distribute, sublicense, and/or sell copies 16 | * of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be 20 | * included in all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 26 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 27 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 29 | * DEALINGS IN THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #include "boards/raspi/timer.h" 34 | #include "common/timer.h" 35 | #include "common/utils.h" 36 | 37 | /** 38 | * Wait N CPU cycles (ARM CPU only) 39 | */ 40 | void wait_cycles(unsigned int n) 41 | { 42 | if (n) 43 | while (n--) { 44 | asm volatile("nop"); 45 | } 46 | } 47 | 48 | /** 49 | * Wait N microsec (ARM CPU only) 50 | */ 51 | void wait_msec(unsigned int n) 52 | { 53 | register unsigned long f, t, r; 54 | 55 | // get the current counter frequency 56 | asm volatile("mrs %0, cntfrq_el0" : "=r"(f)); 57 | 58 | // read the current counter 59 | asm volatile("mrs %0, cntpct_el0" : "=r"(t)); 60 | 61 | // calculate expire value for counter 62 | t += ((f / 1000) * n) / 1000; 63 | 64 | do { 65 | asm volatile("mrs %0, cntpct_el0" : "=r"(r)); 66 | } while (r < t); 67 | } 68 | 69 | /** 70 | * Wait N microsec (with BCM System Timer) 71 | */ 72 | void wait_msec_st(unsigned int n) 73 | { 74 | unsigned long t = get_system_timer(); 75 | 76 | // we must check if it's non-zero, because qemu does not emulate 77 | // system timer, and returning constant zero would mean infinite loop 78 | if (t) 79 | while (get_system_timer() < t + n) 80 | ; 81 | } 82 | -------------------------------------------------------------------------------- /hypervisor/common/fifo.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #include "common/fifo.h" 11 | #include "common/mm.h" 12 | 13 | #define FIFO_SIZE 256 // warning: DO NOT exceed page size 14 | 15 | struct fifo { 16 | unsigned int head; 17 | unsigned int tail; 18 | unsigned int used; 19 | unsigned long buf[FIFO_SIZE]; 20 | }; 21 | 22 | #define NEXT_INDEX(i) (((i) + 1) == FIFO_SIZE ? 0 : ((i) + 1)) 23 | 24 | int is_empty_fifo(struct fifo *fifo) 25 | { 26 | return fifo->used == 0; 27 | } 28 | 29 | int is_full_fifo(struct fifo *fifo) 30 | { 31 | return fifo->used == FIFO_SIZE; 32 | } 33 | 34 | struct fifo *create_fifo() 35 | { 36 | struct fifo *fifo = (struct fifo *)allocate_page(); 37 | fifo->head = 0; 38 | fifo->tail = 0; 39 | fifo->used = 0; 40 | 41 | return fifo; 42 | } 43 | 44 | void clear_fifo(struct fifo *fifo) 45 | { 46 | fifo->head = 0; 47 | fifo->tail = 0; 48 | fifo->used = 0; 49 | } 50 | 51 | int enqueue_fifo(struct fifo *fifo, unsigned long val) 52 | { 53 | if (is_full_fifo(fifo)) 54 | return -1; 55 | 56 | fifo->buf[fifo->head] = val; 57 | fifo->head = NEXT_INDEX(fifo->head); 58 | fifo->used++; 59 | 60 | return 0; 61 | } 62 | 63 | int dequeue_fifo(struct fifo *fifo, unsigned long *val) 64 | { 65 | if (is_empty_fifo(fifo)) 66 | return -1; 67 | 68 | if (val) 69 | *val = fifo->buf[fifo->tail]; 70 | 71 | fifo->tail = NEXT_INDEX(fifo->tail); 72 | fifo->used--; 73 | 74 | return 0; 75 | } 76 | 77 | int used_of_fifo(struct fifo *fifo) 78 | { 79 | return fifo->used; 80 | } 81 | -------------------------------------------------------------------------------- /hypervisor/common/loader.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #include 11 | 12 | #include "common/debug.h" 13 | #include "common/loader.h" 14 | #include "common/mm.h" 15 | #include "common/sched.h" 16 | #include "common/utils.h" 17 | #include "fs/ff.h" 18 | 19 | // va should be page-aligned. 20 | int load_file_to_memory(struct task_struct *tsk, const char *name, 21 | unsigned long va) 22 | { 23 | unsigned long gva = va & PAGE_MASK; 24 | uint8_t *buf; 25 | FRESULT r; 26 | UINT br; 27 | FIL f; 28 | 29 | r = f_open(&f, name, FA_READ); 30 | if (r) { 31 | PANIC("Can't open the file: %s, err=%d\n", name, r); 32 | return -r; 33 | } 34 | 35 | for (;;) { 36 | buf = allocate_task_page(tsk, gva); 37 | r = f_read(&f, buf, PAGE_SIZE, &br); 38 | if (br == 0) { /* error or eof */ 39 | deallocate_page(buf); 40 | break; 41 | } 42 | gva += PAGE_SIZE; 43 | } 44 | 45 | f_close(&f); 46 | INFO("file: %s loaded", name); 47 | 48 | return -r; 49 | } 50 | 51 | int raw_binary_loader(void *arg, struct pt_regs *regs) 52 | { 53 | struct raw_binary_loader_args *loader_args = arg; 54 | 55 | if (load_file_to_memory(current, loader_args->filename, 56 | loader_args->load_addr) < 0) 57 | return -1; 58 | (void)strncpy(current->name, loader_args->filename, 36); 59 | 60 | regs->pc = loader_args->entry_point; 61 | regs->sp = loader_args->sp; 62 | regs->regs[0] = 0; 63 | regs->regs[1] = 0; 64 | regs->regs[2] = 0; 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /hypervisor/common/main.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | #include "common/debug.h" 14 | #include "common/irq.h" 15 | #include "common/loader.h" 16 | #include "common/mini_uart.h" 17 | #include "common/mm.h" 18 | #include "common/printf.h" 19 | #include "common/sched.h" 20 | #include "common/sd.h" 21 | #include "common/shell.h" 22 | #include "common/task.h" 23 | #include "common/timer.h" 24 | #include "common/utils.h" 25 | #include "fs/diskio.h" 26 | #include "fs/ff.h" 27 | 28 | FATFS fatfs; 29 | 30 | void hypervisor_main() 31 | { 32 | uart_init(); 33 | shell_init(); 34 | printf("=== aVisor Hypervisor ===\n"); 35 | 36 | init_task_console(current); 37 | init_initial_task(); 38 | irq_vector_init(); 39 | timer_init(); 40 | disable_irq(); 41 | enable_interrupt_controller(); 42 | 43 | f_mount(&fatfs, "/", 0); 44 | 45 | struct raw_binary_loader_args bl_args1 = { 46 | .load_addr = 0x0, 47 | .entry_point = 0x0, 48 | .sp = 0x100000, 49 | .filename = "lrtos.bin", 50 | }; 51 | 52 | if (create_task(raw_binary_loader, &bl_args1) < 0) { 53 | printf("error while starting task\n"); 54 | return; 55 | } 56 | 57 | struct raw_binary_loader_args bl_args2 = { 58 | .load_addr = 0x0, 59 | .entry_point = 0x0, 60 | .sp = 0x100000, 61 | .filename = "echo.bin", 62 | }; 63 | 64 | if (create_task(raw_binary_loader, &bl_args2) < 0) { 65 | printf("error while starting task\n"); 66 | return; 67 | } 68 | 69 | struct raw_binary_loader_args bl_args3 = { 70 | .load_addr = 0x80000, 71 | .entry_point = 0x80000, 72 | .sp = 0x0, 73 | .filename = "uboot.bin", 74 | }; 75 | 76 | if (create_task(raw_binary_loader, &bl_args3) < 0) { 77 | printf("error while starting task\n"); 78 | return; 79 | } 80 | 81 | struct raw_binary_loader_args bl_args4 = { 82 | .load_addr = 0x80000, 83 | .entry_point = 0x80000, 84 | .sp = 0x0, 85 | .filename = "freertos.bin", 86 | }; 87 | 88 | if (create_task(raw_binary_loader, &bl_args4) < 0) { 89 | printf("error while starting task\n"); 90 | return; 91 | } 92 | 93 | while (1) { 94 | disable_irq(); 95 | schedule(); 96 | enable_irq(); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /hypervisor/common/mm.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #include "common/mm.h" 11 | #include "arch/aarch64/mmu.h" 12 | #include "boards/raspi/raspi3b.h" 13 | #include "common/board.h" 14 | #include "common/debug.h" 15 | #include "common/task.h" 16 | #include "common/utils.h" 17 | 18 | paddr_t get_free_page(struct page_pool *pool); 19 | void free_page(struct page_pool *pool, paddr_t p); 20 | 21 | void *allocate_page() 22 | { 23 | paddr_t page = get_free_page(get_rasp3b_page_pool()); 24 | 25 | if (page == 0) { 26 | return 0; 27 | } 28 | 29 | return (void *)TO_VADDR(page); 30 | } 31 | 32 | void deallocate_page(void *page) 33 | { 34 | free_page(get_rasp3b_page_pool(), TO_PADDR(page)); 35 | } 36 | 37 | void *allocate_task_page(struct task_struct *task, vaddr_t va) 38 | { 39 | paddr_t page = get_free_page(get_rasp3b_page_pool()); 40 | 41 | if (page == 0) { 42 | return 0; 43 | } 44 | 45 | map_stage2_page(task, va, page, MMU_STAGE2_PAGE_FLAGS); 46 | return (void *)TO_VADDR(page); 47 | } 48 | 49 | void set_task_page_notaccessable(struct task_struct *task, vaddr_t va) 50 | { 51 | map_stage2_page(task, va, 0, MMU_STAGE2_MMIO_PAGE_FLAGS); 52 | } 53 | 54 | paddr_t get_free_page(struct page_pool *pool) 55 | { 56 | uint64_t i, index; 57 | paddr_t page; 58 | 59 | for (i = pool->last_page_id; i < (pool->last_page_id + pool->page_nr); 60 | i++) { 61 | index = i % pool->page_nr; 62 | if (pool->memap[index] == 0) { 63 | pool->memap[index] = 1; 64 | page = pool->start_addr + index * PAGE_SIZE; 65 | memzero((void *)TO_VADDR(page), PAGE_SIZE); 66 | pool->last_page_id = index; 67 | return page; 68 | } 69 | } 70 | 71 | PANIC("no free pages!\n"); 72 | return 0; 73 | } 74 | 75 | void free_page(struct page_pool *pool, paddr_t p) 76 | { 77 | pool->memap[(p - pool->start_addr) / PAGE_SIZE] = 0; 78 | } 79 | 80 | void map_stage2_table_entry(vaddr_t pte, vaddr_t va, paddr_t pa, uint64_t flags) 81 | { 82 | uint64_t index = va >> PAGE_SHIFT; 83 | 84 | index = index & (PTRS_PER_TABLE - 1); 85 | uint64_t entry = pa | flags; 86 | 87 | ((uint64_t *)pte)[index] = entry; 88 | } 89 | 90 | static paddr_t map_stage2_table(vaddr_t table, uint64_t shift, vaddr_t va, 91 | int *new_table) 92 | { 93 | uint64_t index = va >> shift; 94 | 95 | index = index & (PTRS_PER_TABLE - 1); 96 | 97 | if (!((uint64_t *)table)[index]) { 98 | *new_table = 1; 99 | paddr_t next_level_table = 100 | get_free_page(get_rasp3b_page_pool()); 101 | uint64_t entry = next_level_table | MM_TYPE_PAGE_TABLE; 102 | 103 | ((uint64_t *)table)[index] = entry; 104 | return next_level_table; 105 | } else { 106 | *new_table = 0; 107 | } 108 | 109 | return ((uint64_t *)table)[index] & PAGE_MASK; 110 | } 111 | 112 | bool check_task_page_mapped(struct task_struct *task, vaddr_t va) 113 | { 114 | paddr_t lv1_table; 115 | 116 | if (!task->mm.first_table) { 117 | task->mm.first_table = get_free_page(get_rasp3b_page_pool()); 118 | task->mm.kernel_pages_count++; 119 | } 120 | 121 | lv1_table = task->mm.first_table; 122 | int new_table; 123 | paddr_t lv2_table = map_stage2_table(TO_VADDR(lv1_table), LV1_SHIFT, va, 124 | &new_table); 125 | 126 | if (new_table) { 127 | task->mm.kernel_pages_count++; 128 | return false; 129 | } 130 | 131 | map_stage2_table(TO_VADDR(lv2_table), LV2_SHIFT, va, &new_table); 132 | 133 | if (new_table) { 134 | task->mm.kernel_pages_count++; 135 | return false; 136 | } 137 | 138 | return true; 139 | } 140 | 141 | void map_stage2_page(struct task_struct *task, vaddr_t va, paddr_t page, 142 | uint64_t flags) 143 | { 144 | paddr_t lv1_table; 145 | 146 | if (!task->mm.first_table) { 147 | task->mm.first_table = get_free_page(get_rasp3b_page_pool()); 148 | task->mm.kernel_pages_count++; 149 | } 150 | 151 | lv1_table = task->mm.first_table; 152 | int new_table; 153 | paddr_t lv2_table = map_stage2_table(TO_VADDR(lv1_table), LV1_SHIFT, va, 154 | &new_table); 155 | 156 | if (new_table) { 157 | task->mm.kernel_pages_count++; 158 | } 159 | 160 | paddr_t lv3_table = map_stage2_table(TO_VADDR(lv2_table), LV2_SHIFT, va, 161 | &new_table); 162 | 163 | if (new_table) { 164 | task->mm.kernel_pages_count++; 165 | } 166 | 167 | map_stage2_table_entry(TO_VADDR(lv3_table), va, page, flags); 168 | task->mm.user_pages_count++; 169 | } 170 | 171 | paddr_t get_ipa(vaddr_t va) 172 | { 173 | paddr_t ipa = translate_el1(va); 174 | 175 | ipa &= 0xFFFFFFFFF000; 176 | ipa |= va & 0xFFF; 177 | return ipa; 178 | } 179 | 180 | #define ISS_ABORT_DFSC_MASK 0x3f 181 | 182 | int handle_mem_abort(vaddr_t addr, uint64_t esr) 183 | { 184 | struct pt_regs *regs = task_pt_regs(current); 185 | uint64_t dfsc = esr & ISS_ABORT_DFSC_MASK; 186 | 187 | if (dfsc >> 2 == 0x1) { 188 | // translation fault 189 | paddr_t page = get_free_page(get_rasp3b_page_pool()); 190 | 191 | if (page == 0) { 192 | return -1; 193 | } 194 | 195 | map_stage2_page(current, get_ipa(addr) & PAGE_MASK, page, 196 | MMU_STAGE2_PAGE_FLAGS); 197 | current->stat.pf_count++; 198 | return 0; 199 | } else if (dfsc >> 2 == 0x3) { 200 | // permission fault (mmio) 201 | const struct board_ops *ops = current->board_ops; 202 | 203 | //int sas = (esr >> 22) & 0x3; 204 | unsigned int srt = (esr >> 16) & 0x1f; 205 | unsigned int wnr = (esr >> 6) & 0x1; 206 | 207 | if (wnr == 0) { 208 | if (HAVE_FUNC(ops, mmio_read)) 209 | regs->regs[srt] = 210 | ops->mmio_read(current, get_ipa(addr)); 211 | } else { 212 | if (HAVE_FUNC(ops, mmio_write)) 213 | ops->mmio_write(current, get_ipa(addr), 214 | regs->regs[srt]); 215 | } 216 | 217 | increment_current_pc(4); 218 | current->stat.mmio_count++; 219 | return 0; 220 | } 221 | 222 | return -1; 223 | } 224 | -------------------------------------------------------------------------------- /hypervisor/common/sched.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #include "common/sched.h" 11 | #include "common/board.h" 12 | #include "common/debug.h" 13 | #include "common/irq.h" 14 | #include "common/mm.h" 15 | #include "common/task.h" 16 | #include "common/utils.h" 17 | 18 | static struct task_struct init_task = INIT_TASK; 19 | struct task_struct *current = &(init_task); 20 | 21 | struct task_struct *task[NR_TASKS] = { 22 | &(init_task), 23 | }; 24 | 25 | int nr_tasks = 1; 26 | 27 | void _schedule(void) 28 | { 29 | int next, c; 30 | 31 | struct task_struct *p; 32 | 33 | while (1) { 34 | c = -1; 35 | next = 0; 36 | 37 | for (int i = 0; i < NR_TASKS; i++) { 38 | p = task[i]; 39 | 40 | if (p && p->state == TASK_RUNNING && p->counter > c) { 41 | c = p->counter; 42 | next = i; 43 | } 44 | } 45 | 46 | if (c) 47 | break; 48 | 49 | for (int i = 0; i < NR_TASKS; i++) { 50 | p = task[i]; 51 | 52 | if (p) 53 | p->counter = (p->counter >> 1) + p->priority; 54 | } 55 | } 56 | 57 | switch_to(task[next]); 58 | } 59 | 60 | void schedule(void) 61 | { 62 | current->counter = 0; 63 | _schedule(); 64 | } 65 | 66 | void set_cpu_virtual_interrupt(struct task_struct *tsk) 67 | { 68 | if (HAVE_FUNC(tsk->board_ops, is_irq_asserted) && 69 | tsk->board_ops->is_irq_asserted(tsk)) 70 | assert_virq(); 71 | else 72 | clear_virq(); 73 | 74 | if (HAVE_FUNC(tsk->board_ops, is_fiq_asserted) && 75 | tsk->board_ops->is_fiq_asserted(tsk)) 76 | assert_vfiq(); 77 | else 78 | clear_vfiq(); 79 | } 80 | 81 | void switch_to(struct task_struct *next) 82 | { 83 | if (current == next) 84 | return; 85 | 86 | struct task_struct *prev = current; 87 | current = next; 88 | 89 | cpu_switch_to(prev, next); 90 | } 91 | 92 | void timer_tick() 93 | { 94 | --current->counter; 95 | 96 | if (current->counter > 0) 97 | return; 98 | 99 | current->counter = 0; 100 | _schedule(); 101 | } 102 | 103 | void exit_task() 104 | { 105 | for (int i = 0; i < NR_TASKS; i++) { 106 | if (task[i] == current) { 107 | task[i]->state = TASK_ZOMBIE; 108 | break; 109 | } 110 | } 111 | 112 | schedule(); 113 | } 114 | 115 | void set_cpu_sysregs(struct task_struct *tsk) 116 | { 117 | set_stage2_pgd(tsk->mm.first_table, tsk->pid); 118 | restore_sysregs(&tsk->cpu_sysregs); 119 | } 120 | 121 | void vm_entering_work() 122 | { 123 | if (HAVE_FUNC(current->board_ops, entering_vm)) 124 | current->board_ops->entering_vm(current); 125 | 126 | if (is_uart_forwarded_task(current)) 127 | flush_task_console(current); 128 | 129 | set_cpu_sysregs(current); 130 | set_cpu_virtual_interrupt(current); 131 | } 132 | 133 | void vm_leaving_work() 134 | { 135 | save_sysregs(¤t->cpu_sysregs); 136 | 137 | if (HAVE_FUNC(current->board_ops, leaving_vm)) 138 | current->board_ops->leaving_vm(current); 139 | 140 | if (is_uart_forwarded_task(current)) 141 | flush_task_console(current); 142 | } 143 | 144 | const char *task_state_str[] = { 145 | "RUNNING", 146 | "ZOMBIE", 147 | }; 148 | 149 | void show_task_list(void) 150 | { 151 | printf("%3s %12s %8s %7s %8s %7s %7s %7s %7s %7s\n", "id", "name", 152 | "state", "pages", "saved-pc", "wfx", "hvc", "sysreg", "pf", 153 | "mmio"); 154 | 155 | for (int i = 0; i < nr_tasks; i++) { 156 | struct task_struct *tsk = task[i]; 157 | printf("%3d %12s %8s %7d %8x %7d %7d %7d %7d %7d\n", tsk->pid, 158 | tsk->name ? tsk->name : "", task_state_str[tsk->state], 159 | tsk->mm.user_pages_count, task_pt_regs(tsk)->pc, 160 | tsk->stat.wfx_trap_count, tsk->stat.hvc_trap_count, 161 | tsk->stat.sysreg_trap_count, tsk->stat.pf_count, 162 | tsk->stat.mmio_count); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /hypervisor/common/shell_priv.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "common/types.h" 13 | 14 | #define SHELL_CMD_MAX_LEN 100U 15 | #define SHELL_STRING_MAX_LEN (PAGE_SIZE << 2U) 16 | 17 | /* Shell Command Function */ 18 | typedef int32_t (*shell_cmd_fn_t)(int32_t argc, char **argv); 19 | 20 | /* Shell Command */ 21 | struct shell_cmd { 22 | char *str; /* Command string */ 23 | char *cmd_param; /* Command parameter string */ 24 | char *help_str; /* Help text associated with the command */ 25 | shell_cmd_fn_t fcn; /* Command call-back function */ 26 | }; 27 | 28 | /* Shell Control Block */ 29 | struct shell { 30 | char input_line[2][SHELL_CMD_MAX_LEN + 1U]; /* current & last */ 31 | uint32_t input_line_len; /* Length of current input line */ 32 | uint32_t input_line_active; /* Active input line index */ 33 | struct shell_cmd *cmds; /* cmds supported */ 34 | uint32_t cmd_count; /* Count of cmds supported */ 35 | }; 36 | 37 | /* Shell Command list with parameters and help description */ 38 | #define SHELL_CMD_HELP "help" 39 | #define SHELL_CMD_HELP_PARAM NULL 40 | #define SHELL_CMD_HELP_HELP "Supported hypervisor shell commands" 41 | 42 | #define SHELL_CMD_VML "vml" 43 | #define SHELL_CMD_VML_PARAM NULL 44 | #define SHELL_CMD_VML_HELP "List all VMs" 45 | 46 | #define SHELL_CMD_VMC "vmc" 47 | #define SHELL_CMD_VMC_PARAM "" 48 | #define SHELL_CMD_VMC_HELP \ 49 | "Switch to the VM's console. Use [@0] to return to the aVisor console" 50 | 51 | #define SHELL_CMD_VMLD "vmld" 52 | #define SHELL_CMD_VMLD_PARAM " " 53 | #define SHELL_CMD_VMLD_HELP "Load the VM image and run it" 54 | 55 | #define SHELL_CMD_LS "ls" 56 | #define SHELL_CMD_LS_PARAM NULL 57 | #define SHELL_CMD_LS_HELP "List files in current folder" 58 | 59 | -------------------------------------------------------------------------------- /hypervisor/common/utils.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | #include "common/types.h" 14 | #include "common/utils.h" 15 | 16 | int abs(int n) 17 | { 18 | return n < 0 ? -n : n; 19 | } 20 | 21 | char *strncpy(char *dest, const char *src, size_t n) 22 | { 23 | size_t i; 24 | 25 | for (i = 0; i < n && src[i] != '\0'; i++) { 26 | dest[i] = src[i]; 27 | } 28 | 29 | for (; i < n; i++) 30 | dest[i] = '\0'; 31 | 32 | return dest; 33 | } 34 | 35 | size_t strlen(const char *s) 36 | { 37 | size_t i; 38 | 39 | for (i = 0; *s != '\0'; i++, s++) 40 | ; 41 | 42 | return i; 43 | } 44 | 45 | size_t strnlen(const char *s, size_t n) 46 | { 47 | size_t i; 48 | 49 | for (i = 0; i < n && *s != '\0'; i++, s++) 50 | ; 51 | 52 | return i; 53 | } 54 | 55 | int strcmp(const char *s1, const char *s2) 56 | { 57 | while (*s1 && *s1 == *s2) { 58 | s1++; 59 | s2++; 60 | } 61 | 62 | return *s1 - *s2; 63 | } 64 | 65 | int strncmp(const char *s1, const char *s2, size_t n) 66 | { 67 | size_t i; 68 | 69 | for (i = 0; i < n && *s1 && (*s1 == *s2); i++, s1++, s2++) 70 | ; 71 | 72 | return (i != n) ? (*s1 - *s2) : 0; 73 | } 74 | 75 | void *memset(void *s, int c, size_t n) 76 | { 77 | for (size_t i = 0; i < n; i++) 78 | *(uint8_t *)s++ = (uint8_t)c; 79 | 80 | return s; 81 | } 82 | 83 | int memcmp(const void *s1, const void *s2, size_t n) 84 | { 85 | size_t i; 86 | uint8_t *p1 = (uint8_t *)s1; 87 | uint8_t *p2 = (uint8_t *)s2; 88 | 89 | for (i = 0; i < n; i++, p1++, p2++) { 90 | if (*p1 != *p2) 91 | break; 92 | } 93 | 94 | if (i == n) 95 | return 0; 96 | 97 | else 98 | return *p1 - *p2; 99 | } 100 | 101 | void *memmove(void *dest, const void *src, size_t n) 102 | { 103 | if (src + n > dest) { 104 | src += n - 1; 105 | dest += n - 1; 106 | 107 | for (size_t i = 0; i < n; i++) 108 | *(uint8_t *)dest-- = *(uint8_t *)src--; 109 | } else { 110 | memcpy(dest, src, n); 111 | } 112 | 113 | return dest; 114 | } 115 | 116 | void *memchr(const void *s, int c, size_t n) 117 | { 118 | uint8_t *p = (uint8_t *)s; 119 | 120 | for (size_t i = 0; i < n; i++, p++) { 121 | if (*p == c) 122 | return p; 123 | } 124 | 125 | return NULL; 126 | } 127 | 128 | char *strchr(const char *s, int c) 129 | { 130 | char *p = (char *)s; 131 | 132 | while (*p != '\0' && *p != c) 133 | p++; 134 | 135 | if (*p == '\0') 136 | return NULL; 137 | 138 | else 139 | return p; 140 | } 141 | 142 | char *strcpy(char *dest, const char *src) 143 | { 144 | do { 145 | *dest++ = *src; 146 | } while (*src++ != '\0'); 147 | 148 | return dest; 149 | } 150 | 151 | char *strncat(char *dest, const char *src, size_t n) 152 | { 153 | size_t destlen = strlen(dest); 154 | size_t i; 155 | 156 | for (i = 0; i < n; i++) { 157 | dest[destlen + i] = src[i]; 158 | } 159 | 160 | dest[destlen + i] = '\0'; 161 | return dest; 162 | } 163 | 164 | char *strcat(char *dest, const char *src) 165 | { 166 | size_t destlen = strlen(dest); 167 | 168 | strcpy(dest + destlen, src); 169 | return dest; 170 | } 171 | 172 | int isdigit(int c) 173 | { 174 | return (c >= '0' && c <= '9'); 175 | } 176 | 177 | int isspace(int c) 178 | { 179 | return (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || 180 | c == '\v'); 181 | } 182 | 183 | int toupper(int c) 184 | { 185 | if (c >= 'a' && c <= 'z') 186 | return c - ('a' - 'A'); 187 | 188 | else 189 | return c; 190 | } 191 | 192 | int tolower(int c) 193 | { 194 | if (c >= 'A' && c <= 'Z') 195 | return c + ('a' - 'A'); 196 | 197 | else 198 | return c; 199 | } 200 | 201 | int strcasecmp(const char *s1, const char *s2) 202 | { 203 | int c1, c2; 204 | 205 | do { 206 | c1 = tolower(*s1++); 207 | c2 = tolower(*s2++); 208 | } while (c1 == c2 && c1 != 0); 209 | 210 | return c1 - c2; 211 | } 212 | 213 | /** 214 | * strncasecmp - Case insensitive, length-limited string comparison 215 | */ 216 | int strncasecmp(const char *s1, const char *s2, size_t len) 217 | { 218 | unsigned char c1, c2; 219 | 220 | if (!len) 221 | return 0; 222 | 223 | do { 224 | c1 = *s1++; 225 | c2 = *s2++; 226 | 227 | if (!c1 || !c2) 228 | break; 229 | 230 | if (c1 == c2) 231 | continue; 232 | 233 | c1 = tolower(c1); 234 | c2 = tolower(c2); 235 | 236 | if (c1 != c2) 237 | break; 238 | } while (--len); 239 | 240 | return (int)c1 - (int)c2; 241 | } 242 | 243 | /* 244 | * Convert a string to a long integer - decimal support only. 245 | */ 246 | int64_t strtol_deci(const char *nptr) 247 | { 248 | const char *s = nptr; 249 | uint64_t acc, cutoff, cutlim; 250 | int32_t neg = 0, any; 251 | uint64_t base = 10UL; 252 | char c; 253 | 254 | /* 255 | * Skip white space and pick up leading +/- sign if any. 256 | */ 257 | do { 258 | c = *s; 259 | s++; 260 | } while (isspace(c)); 261 | 262 | if (c == '-') { 263 | neg = 1; 264 | c = *s; 265 | s++; 266 | } else if (c == '+') { 267 | c = *s; 268 | s++; 269 | } else { 270 | /* No sign character. */ 271 | } 272 | 273 | /* 274 | * Compute the cutoff value between legal numbers and illegal 275 | * numbers. That is the largest legal value, divided by the 276 | * base. An input number that is greater than this value, if 277 | * followed by a legal input character, is too big. One that 278 | * is equal to this value may be valid or not; the limit 279 | * between valid and invalid numbers is then based on the last 280 | * digit. For instance, if the range for longs is 281 | * [-2147483648..2147483647] and the input base is 10, 282 | * cutoff will be set to 214748364 and cutlim to either 283 | * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated 284 | * a value > 214748364, or equal but the next digit is > 7 (or 8), 285 | * the number is too big, and we will return a range error. 286 | * 287 | * Set any if any `digits' consumed; make it negative to indicate 288 | * overflow. 289 | */ 290 | cutoff = (neg != 0) ? LONG_MIN : LONG_MAX; 291 | cutlim = cutoff % base; 292 | cutoff /= base; 293 | acc = 0UL; 294 | any = 0; 295 | 296 | while ((c >= '0') && (c <= '9')) { 297 | c -= '0'; 298 | if ((acc > cutoff) || 299 | ((acc == cutoff) && ((uint64_t)c > cutlim))) { 300 | any = -1; 301 | break; 302 | } else { 303 | acc *= base; 304 | acc += (uint64_t)c; 305 | } 306 | 307 | c = *s; 308 | s++; 309 | } 310 | 311 | if (any < 0) { 312 | acc = (neg != 0) ? LONG_MIN : LONG_MAX; 313 | } else if (neg != 0) { 314 | acc = ~acc + 1UL; 315 | } else { 316 | /* There is no overflow and no leading '-' exists. In such case 317 | * acc already holds the right number. No action required. */ 318 | } 319 | return (long)acc; 320 | } 321 | 322 | unsigned long strtoul(const char *str, char **endptr, int base) 323 | { 324 | int auto_detect = 0; 325 | if (base == 0 || base == 16) { 326 | if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { 327 | str += 2; 328 | auto_detect = 1; 329 | } 330 | } 331 | 332 | if (auto_detect) { 333 | base = 16; 334 | } 335 | 336 | unsigned long result = 0; 337 | int sign = 1; 338 | 339 | if (str[0] == '+') { 340 | str++; 341 | } else if (str[0] == '-') { 342 | sign = -1; 343 | str++; 344 | } 345 | 346 | while (*str) { 347 | unsigned int digit; 348 | char c = *str++; 349 | 350 | if (c >= '0' && c <= '9') { 351 | digit = c - '0'; 352 | } else if (c >= 'a' && c <= 'z') { 353 | digit = c - 'a' + 10; 354 | } else if (c >= 'A' && c <= 'Z') { 355 | digit = c - 'A' + 10; 356 | } else { 357 | break; 358 | } 359 | 360 | if (digit >= base) { 361 | break; 362 | } 363 | 364 | unsigned long next = result * base + digit; 365 | if (next < result) { 366 | return ULONG_MAX; 367 | } 368 | 369 | result = next; 370 | } 371 | 372 | if (endptr) { 373 | *endptr = (char *)str; 374 | } 375 | 376 | return sign * result; 377 | } 378 | 379 | -------------------------------------------------------------------------------- /hypervisor/emulator/raspi/vmbox.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #include "emulator/raspi/vmbox.h" 11 | #include "arch/aarch64/page.h" 12 | #include "arch/aarch64/sysregs.h" 13 | #include "boards/raspi/base.h" 14 | #include "boards/raspi/phys2bus.h" 15 | #include "common/errno.h" 16 | #include "common/debug.h" 17 | 18 | /* 19 | * TODO: 20 | * 1. mbox emulation should be per VM 21 | * 2. mbox emulation 22 | * step 1: read from the real hardware 23 | * step 2: return the info to the virtualized machine 24 | */ 25 | 26 | // The buffer must be 16-byte aligned as only the upper 28 bits of the address can be passed via the mailbox 27 | // volatile uint32_t __attribute__((aligned(16))) mbox[36]; 28 | static volatile uint32_t *mbox; 29 | static uint32_t mbox_val = 0; 30 | 31 | enum { 32 | VIDEOCORE_MBOX = (DEVICE_BASE + 0x0000B880), 33 | MBOX_READ = (VIDEOCORE_MBOX + 0x0), 34 | MBOX_POLL = (VIDEOCORE_MBOX + 0x10), 35 | MBOX_SENDER = (VIDEOCORE_MBOX + 0x14), 36 | MBOX_STATUS = (VIDEOCORE_MBOX + 0x18), 37 | MBOX_CONFIG = (VIDEOCORE_MBOX + 0x1C), 38 | MBOX_WRITE = (VIDEOCORE_MBOX + 0x20), 39 | MBOX_RESPONSE = 0x80000000, 40 | MBOX_FULL = 0x80000000, 41 | MBOX_EMPTY = 0x40000000 42 | }; 43 | 44 | static uint64_t emulate_mbox_read(struct task_struct *tsk) 45 | { 46 | /* 47 | * Prepare the mbox[] and waiting for the read. 48 | * mbox[0] is the buffer size in bytes (including the header values, 49 | * the end tag and padding) 50 | * mbox[1] is the type, request or response. 51 | * mbox[2] is the tag. 52 | * mbox[3] is the val buf size. 53 | * mbox[4] MSB indicate the type, remaining bits indicate buf size 54 | * mbox[5] and mbox[6] are val. 55 | * mbox[7] is end tag (= 0). 56 | */ 57 | if ((mbox_val & 0xF) == MBOX_CHAN_TAGS && mbox[1] == MBOX_REQUEST) { 58 | switch (mbox[2]) { 59 | case MBOX_TAG_GET_ARM_MEMORY: 60 | mbox[1] = MBOX_RESPONSE; 61 | mbox[4] = MBOX_RESPONSE | mbox[3]; 62 | mbox[5] = 0x0; /* RAM start addr */ 63 | mbox[6] = 0x3c000000; /* RAM Length */ 64 | break; 65 | case MBOX_TAG_GET_BOARD_SERIAL: 66 | mbox[1] = MBOX_RESPONSE; 67 | mbox[4] = MBOX_RESPONSE | mbox[3]; 68 | mbox[5] = 0x0; /* serial number 0 */ 69 | mbox[6] = 0x0; /* serial number 1 */ 70 | break; 71 | case MBOX_TAG_SET_POWER_STATE: 72 | mbox[1] = MBOX_RESPONSE; 73 | mbox[4] = MBOX_RESPONSE | mbox[3]; 74 | /* mbox[5] is the device id, keep the same */ 75 | mbox[6] = 0x1; /* state bits */ 76 | break; 77 | default: 78 | WARN("Unsupported mbox TAG:%x\n", mbox[2]); 79 | } 80 | } 81 | 82 | return mbox_val; 83 | } 84 | 85 | static uint64_t emulate_mbox_write(struct task_struct *tsk, uint64_t val) 86 | { 87 | vaddr_t gva = (bus_to_phys(val) & ~0xF); 88 | paddr_t maddr = 0; 89 | uint64_t err; 90 | mbox_val = (uint32_t)val; 91 | 92 | /* 93 | * Check if the gva mapped or not. It should always be mapped. 94 | */ 95 | if (!check_task_page_mapped(tsk, gva)) { 96 | PANIC("mbox buf not mapped!!!\n"); 97 | return -EFAULT; 98 | } 99 | 100 | err = gvirt_to_maddr(gva, &maddr, GV2M_WRITE); 101 | mbox = (uint32_t *)maddr; 102 | 103 | return 0; 104 | } 105 | 106 | bool is_mbox_addr(uint64_t addr) 107 | { 108 | return (addr >= VIDEOCORE_MBOX && addr <= MBOX_WRITE); 109 | } 110 | 111 | uint64_t handle_mbox_read(struct task_struct *tsk, uint64_t addr) 112 | { 113 | uint64_t ret = 0; 114 | static uint64_t empty = MBOX_EMPTY; 115 | 116 | switch (addr) { 117 | case MBOX_STATUS: 118 | /* 119 | * TODO 120 | * This emulation is currently not accuracy. 121 | * uboot will drain the the stale responses. 122 | * check: https://elixir.bootlin.com/u-boot/v2022.10/source/arch/arm/mach-bcm283x/mbox.c#L31 123 | */ 124 | ret = empty; 125 | 126 | if (empty & MBOX_EMPTY) 127 | empty = 0; 128 | else 129 | empty = MBOX_EMPTY; 130 | 131 | break; 132 | case MBOX_READ: 133 | ret = emulate_mbox_read(tsk); 134 | break; 135 | default: 136 | WARN("Unsupported MBOX Read\n"); 137 | } 138 | return ret; 139 | } 140 | 141 | uint64_t handle_mbox_write(struct task_struct *tsk, uint64_t addr, uint64_t val) 142 | { 143 | uint64_t ret = 0; 144 | switch (addr) { 145 | case MBOX_WRITE: 146 | ret = emulate_mbox_write(tsk, val); 147 | break; 148 | default: 149 | WARN("Unsupported MBOX Write\n"); 150 | } 151 | return ret; 152 | } 153 | -------------------------------------------------------------------------------- /hypervisor/fs/diskio.c: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------*/ 2 | /* Low level disk I/O module SKELETON for FatFs (C)ChaN, 2019 */ 3 | /*-----------------------------------------------------------------------*/ 4 | /* If a working storage control module is available, it should be */ 5 | /* attached to the FatFs via a glue function rather than modifying it. */ 6 | /* This is an example of glue functions to attach various exsisting */ 7 | /* storage control modules to the FatFs module with a defined API. */ 8 | /*-----------------------------------------------------------------------*/ 9 | 10 | #include "fs/diskio.h" /* Declarations of disk functions */ 11 | #include "common/sd.h" 12 | #include "fs/ff.h" /* Obtains integer types */ 13 | 14 | /* Definitions of physical drive number for each drive */ 15 | #define DEV_RAM 0 /* Example: Map Ramdisk to physical drive 0 */ 16 | #define DEV_MMC 1 /* Example: Map MMC/SD card to physical drive 1 */ 17 | #define DEV_USB 2 /* Example: Map USB MSD to physical drive 2 */ 18 | 19 | static DSTATUS stat = STA_NOINIT; 20 | 21 | /*-----------------------------------------------------------------------*/ 22 | /* Get Drive Status */ 23 | /*-----------------------------------------------------------------------*/ 24 | 25 | DSTATUS disk_status(BYTE pdrv) 26 | { 27 | return stat; 28 | } 29 | 30 | /*-----------------------------------------------------------------------*/ 31 | /* Inidialize a Drive */ 32 | /*-----------------------------------------------------------------------*/ 33 | 34 | DSTATUS disk_initialize(BYTE pdrv) 35 | { 36 | if (sd_init() < 0) 37 | return RES_ERROR; 38 | stat = STA_OK; 39 | 40 | return RES_OK; 41 | } 42 | 43 | /*-----------------------------------------------------------------------*/ 44 | /* Read Sector(s) */ 45 | /*-----------------------------------------------------------------------*/ 46 | 47 | DRESULT disk_read(BYTE pdrv, /* Physical drive nmuber to identify the drive */ 48 | BYTE *buff, /* Data buffer to store read data */ 49 | LBA_t sector, /* Start sector in LBA */ 50 | UINT count /* Number of sectors to read */ 51 | ) 52 | { 53 | if (sd_readblock(sector, buff, count) < 0) 54 | return RES_ERROR; 55 | 56 | return RES_OK; 57 | } 58 | 59 | /*-----------------------------------------------------------------------*/ 60 | /* Write Sector(s) */ 61 | /*-----------------------------------------------------------------------*/ 62 | 63 | #if FF_FS_READONLY == 0 64 | 65 | DRESULT disk_write(BYTE pdrv, /* Physical drive nmuber to identify the drive */ 66 | const BYTE *buff, /* Data to be written */ 67 | LBA_t sector, /* Start sector in LBA */ 68 | UINT count /* Number of sectors to write */ 69 | ) 70 | { 71 | return RES_NOTSUP; 72 | } 73 | 74 | #endif 75 | 76 | /*-----------------------------------------------------------------------*/ 77 | /* Miscellaneous Functions */ 78 | /*-----------------------------------------------------------------------*/ 79 | 80 | DRESULT disk_ioctl(BYTE pdrv, /* Physical drive nmuber (0..) */ 81 | BYTE cmd, /* Control code */ 82 | void *buff /* Buffer to send/receive control data */ 83 | ) 84 | { 85 | return RES_NOTSUP; 86 | } 87 | -------------------------------------------------------------------------------- /include/arch/aarch64/mmu.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #define MM_TYPE_PAGE_TABLE 0x3 13 | #define MM_TYPE_PAGE 0x3 14 | #define MM_TYPE_BLOCK 0x1 15 | 16 | #define MM_ACCESS (1 << 10) 17 | #define MM_nG (0 << 11) 18 | #define MM_SH (3 << 8) 19 | 20 | /* 21 | * Memory region attributes: 22 | * 23 | * n = AttrIndx[2:0] 24 | * n MAIR 25 | * DEVICE_nGnRnE 000 00000000 26 | * NORMAL_CACHEABLE 001 11111111 27 | */ 28 | #define MT_DEVICE_nGnRnE 0x0 29 | #define MT_NORMAL_CACHEABLE 0x1 30 | 31 | #define MT_DEVICE_nGnRnE_FLAGS 0x00 32 | #define MT_NORMAL_CACHEABLE_FLAGS 0x44 //TODO: temp. non-cacheable 33 | 34 | #define MAIR_VALUE \ 35 | (MT_DEVICE_nGnRnE_FLAGS << (8 * MT_DEVICE_nGnRnE)) | \ 36 | (MT_NORMAL_CACHEABLE_FLAGS << (8 * MT_NORMAL_CACHEABLE)) 37 | 38 | #define MMU_FLAGS \ 39 | (MM_TYPE_BLOCK | (MT_NORMAL_CACHEABLE << 2) | MM_nG | MM_SH | MM_ACCESS) 40 | #define MMU_DEVICE_FLAGS \ 41 | (MM_TYPE_BLOCK | (MT_DEVICE_nGnRnE << 2) | MM_nG | MM_SH | MM_ACCESS) 42 | 43 | #define MM_STAGE2_ACCESS (1 << 10) 44 | #define MM_STAGE2_SH (3 << 8) 45 | #define MM_STAGE2_AP (3 << 6) 46 | #define MM_STAGE2_MEMATTR (0x5 << 2) //TODO: temp. non-cacheable 47 | 48 | #define MMU_STAGE2_PAGE_FLAGS \ 49 | (MM_TYPE_PAGE | MM_STAGE2_ACCESS | MM_STAGE2_SH | MM_STAGE2_AP | \ 50 | MM_STAGE2_MEMATTR) 51 | 52 | #define MM_STAGE2_AP_NONE (0 << 6) 53 | #define MM_STAGE2_DEVICE_MEMATTR (0x0 << 2) 54 | #define MMU_STAGE2_MMIO_PAGE_FLAGS \ 55 | (MM_TYPE_PAGE | MM_STAGE2_ACCESS | MM_STAGE2_SH | MM_STAGE2_AP_NONE | \ 56 | MM_STAGE2_DEVICE_MEMATTR) 57 | 58 | #define TCR_T0SZ (64 - 48) 59 | #define TCR_TG0_4K (0 << 14) 60 | #define TCR_VALUE (TCR_T0SZ | TCR_TG0_4K) 61 | -------------------------------------------------------------------------------- /include/arch/aarch64/page.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "common/types.h" 13 | #include "common/mm.h" 14 | #include "arch/aarch64/sysregs.h" 15 | 16 | #define PADDR_MASK (((1ULL) << 52) - 1) 17 | 18 | static inline uint64_t gva_to_ma_par(vaddr_t va, unsigned int flags) 19 | { 20 | uint64_t par, tmp = READ_SYSREG64(PAR_EL1); 21 | 22 | if ((flags & GV2M_WRITE) == GV2M_WRITE) 23 | asm volatile("at s12e1w, %0;" : : "r"(va)); 24 | else 25 | asm volatile("at s12e1r, %0;" : : "r"(va)); 26 | 27 | asm volatile("isb" : : : "memory"); 28 | par = READ_SYSREG64(PAR_EL1); 29 | WRITE_SYSREG64(tmp, PAR_EL1); 30 | return par; 31 | } 32 | 33 | static inline uint64_t gvirt_to_maddr(vaddr_t va, paddr_t *pa, 34 | unsigned int flags) 35 | { 36 | uint64_t par = gva_to_ma_par(va, flags); 37 | if ( par & 0x1 ) 38 | return par; 39 | *pa = (par & PADDR_MASK & PAGE_MASK) | ((unsigned long) va & ~PAGE_MASK); 40 | return 0; 41 | } 42 | 43 | -------------------------------------------------------------------------------- /include/arch/aarch64/sysregs.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | // *************************************** 13 | // SCTLR_EL2, System Control Register (EL2) 14 | // *************************************** 15 | 16 | #define SCTLR_EE (0 << 25) 17 | #define SCTLR_I_CACHE_DISABLED (0 << 12) 18 | #define SCTLR_D_CACHE_DISABLED (0 << 2) 19 | #define SCTLR_MMU_DISABLED (0 << 0) 20 | #define SCTLR_MMU_ENABLED (1 << 0) 21 | 22 | #define SCTLR_VALUE_MMU_DISABLED \ 23 | (SCTLR_EE | SCTLR_I_CACHE_DISABLED | SCTLR_D_CACHE_DISABLED | \ 24 | SCTLR_MMU_DISABLED) 25 | 26 | // *************************************** 27 | // HCR_EL2, Hypervisor Configuration Register (EL2) 28 | // *************************************** 29 | 30 | // trap related 31 | #define HCR_TACR (1 << 21) 32 | #define HCR_TID3 (1 << 18) 33 | #define HCR_TID2 (1 << 17) 34 | #define HCR_TID1 (1 << 16) 35 | #define HCR_TWE (1 << 14) 36 | #define HCR_TWI (1 << 13) 37 | // others 38 | #define HCR_E2H (0 << 34) 39 | #define HCR_RW (1 << 31) 40 | #define HCR_TGE (0 << 27) 41 | #define HCR_AMO (1 << 5) // routing to EL2 42 | #define HCR_IMO (1 << 4) // routing to EL2 43 | #define HCR_FMO (1 << 3) // routing to EL2 44 | #define HCR_SWIO (1 << 1) 45 | #define HCR_VM (1 << 0) // stage 2 translation enable 46 | 47 | #define HCR_VALUE \ 48 | (HCR_TACR | HCR_TID3 | HCR_TID2 | HCR_TID1 | HCR_TWE | HCR_TWI | \ 49 | HCR_E2H | HCR_RW | HCR_TGE | HCR_AMO | HCR_IMO | HCR_FMO | HCR_SWIO | \ 50 | HCR_VM) 51 | 52 | // SCR_EL3, Secure Configuration Register (EL3) 53 | // *************************************** 54 | 55 | #define SCR_RESERVED (3 << 4) 56 | #define SCR_RW (1 << 10) 57 | #define SCR_HCE (1 << 8) 58 | #define SCR_NS (1 << 0) 59 | 60 | #define SCR_VALUE (SCR_RESERVED | SCR_RW | SCR_HCE | SCR_NS) 61 | 62 | // *************************************** 63 | // SPSR_EL3, Saved Program Status Register (EL3) 64 | // *************************************** 65 | 66 | #define SPSR_MASK_ALL (7 << 6) 67 | #define SPSR_EL2h (9 << 0) 68 | 69 | #define SPSR_VALUE (SPSR_MASK_ALL | SPSR_EL2h) 70 | 71 | // *************************************** 72 | // VTCR_EL2, Virtualization Translation Control Register (EL2) 73 | // *************************************** 74 | 75 | #define VTCR_NSA (1 << 30) 76 | #define VTCR_NSW (1 << 29) 77 | #define VTCR_VS (0 << 19) 78 | #define VTCR_PS (2 << 16) 79 | #define VTCR_TG0 (0 << 14) // 4KB 80 | #define VTCR_SH0 (3 << 12) 81 | #define VTCR_ORGN0 (0 << 10) 82 | #define VTCR_IRGN0 (0 << 8) 83 | #define VTCR_SL0 (1 << 6) 84 | #define VTCR_T0SZ (64 - 38) 85 | 86 | #define VTCR_VALUE \ 87 | (VTCR_NSA | VTCR_NSW | VTCR_VS | VTCR_PS | VTCR_TG0 | VTCR_SH0 | \ 88 | VTCR_ORGN0 | VTCR_IRGN0 | VTCR_SL0 | VTCR_T0SZ) 89 | 90 | /* Flags for get_page_from_gva, gvirt_to_maddr etc */ 91 | #define GV2M_READ (0u<<0) 92 | #define GV2M_WRITE (1u<<0) 93 | #define GV2M_EXEC (1u<<1) 94 | 95 | /* Indirect stringification. Doing two levels allows the parameter to be a 96 | * macro itself. For example, compile with -DFOO=bar, __stringify(FOO) 97 | * converts to "bar". 98 | */ 99 | #define __stringify_1(x...) #x 100 | #define __stringify(x...) __stringify_1(x) 101 | 102 | /* Access to system registers */ 103 | #define READ_SYSREG32(name) ((uint32_t)READ_SYSREG64(name)) 104 | 105 | #define WRITE_SYSREG32(v, name) WRITE_SYSREG64((uint64_t)v, name) 106 | 107 | #define WRITE_SYSREG64(v, name) do { \ 108 | uint64_t _r = v; \ 109 | asm volatile("msr "__stringify(name)", %0" : : "r" (_r)); \ 110 | } while (0) 111 | #define READ_SYSREG64(name) ({ \ 112 | uint64_t _r; \ 113 | asm volatile("mrs %0, "__stringify(name) : "=r" (_r)); \ 114 | _r; }) 115 | 116 | #define READ_SYSREG(name) READ_SYSREG64(name) 117 | #define WRITE_SYSREG(v, name) WRITE_SYSREG64(v, name) 118 | 119 | -------------------------------------------------------------------------------- /include/arch/aarch64/timer.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | * 9 | * rdtsc: is using System counter 10 | * 11 | * usage: 12 | * t0 = rdtsc(); 13 | * ... 14 | * t1 = rdtsc(); 15 | * time = t1 - t0; 16 | * 17 | * rdtsc0: is useing Performance Monitors registers, which provide better precision 18 | * than rdtsc. 19 | * 20 | * usage: 21 | * call enable_pmu_pmccntr() once to enable the timer. 22 | * t0 = rdtsc0(); 23 | * ... 24 | * t1 = rdtsc0(); 25 | * time = t1 - t0; 26 | */ 27 | 28 | #pragma once 29 | 30 | #include "common/types.h" 31 | 32 | static inline uint64_t arm64_cntvct(void) 33 | { 34 | uint64_t tsc; 35 | asm volatile("mrs %0, cntvct_el0" : "=r"(tsc)); 36 | return tsc; 37 | } 38 | 39 | static inline uint64_t arm64_cntfrq(void) 40 | { 41 | uint64_t freq; 42 | asm volatile("mrs %0, cntfrq_el0" : "=r"(freq)); 43 | return freq; 44 | } 45 | 46 | static inline uint64_t rdtsc(void) 47 | { 48 | return arm64_cntvct(); 49 | } 50 | 51 | static inline uint64_t arm64_pmccntr(void) 52 | { 53 | uint64_t tsc; 54 | asm volatile("mrs %0, pmccntr_el0" : "=r"(tsc)); 55 | return tsc; 56 | } 57 | 58 | static inline uint64_t rdtsc0(void) 59 | { 60 | return arm64_pmccntr(); 61 | } 62 | 63 | static inline void enable_pmu_pmccntr(void) 64 | { 65 | uint64_t val = 0; 66 | /* Disable cycle counter overflow interrupt */ 67 | asm volatile("msr pmintenset_el1, %0" : : "r"((uint64_t)(0 << 31))); 68 | /* Enable cycle counter */ 69 | asm volatile("msr pmcntenset_el0, %0" ::"r"((uint64_t)(1 << 31))); 70 | /* Enable user-mode access to cycle counters. */ 71 | asm volatile("msr pmuserenr_el0, %0" 72 | : 73 | : "r"((uint64_t)(1 << 0) | (uint64_t)(1 << 2))); 74 | /* Clear cycle counter and start */ 75 | asm volatile("mrs %0, pmcr_el0" : "=r"(val)); 76 | val |= ((uint64_t)(1 << 0) | (uint64_t)(1 << 2)); 77 | asm volatile("isb"); 78 | asm volatile("msr pmcr_el0, %0" : : "r"(val)); 79 | val = (1 << 27); 80 | asm volatile("msr pmccfiltr_el0, %0" ::"r"(val)); 81 | } 82 | 83 | static inline uint64_t tsc_2_microsec(uint64_t tsc) 84 | { 85 | register uint64_t f; 86 | asm volatile("mrs %0, cntfrq_el0" : "=r"(f)); 87 | return (tsc * 1000000 / f); 88 | } 89 | -------------------------------------------------------------------------------- /include/boards/raspi/base.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "common/mm.h" 13 | 14 | #define DEVICE_BASE 0x3F000000 15 | #define PBASE (VA_START + DEVICE_BASE) 16 | -------------------------------------------------------------------------------- /include/boards/raspi/gpio.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "boards/raspi/base.h" 13 | 14 | #define GPFSEL0 (PBASE + 0x00200000) 15 | #define GPFSEL1 (PBASE + 0x00200004) 16 | #define GPFSEL2 (PBASE + 0x00200008) 17 | #define GPFSEL3 (PBASE + 0x0020000C) 18 | #define GPFSEL4 (PBASE + 0x00200010) 19 | #define GPFSEL5 (PBASE + 0x00200014) 20 | #define GPSET0 (PBASE + 0x0020001C) 21 | #define GPSET1 (PBASE + 0x00200020) 22 | #define GPCLR0 (PBASE + 0x00200028) 23 | #define GPLEV0 (PBASE + 0x00200034) 24 | #define GPLEV1 (PBASE + 0x00200038) 25 | #define GPEDS0 (PBASE + 0x00200040) 26 | #define GPEDS1 (PBASE + 0x00200044) 27 | #define GPHEN0 (PBASE + 0x00200064) 28 | #define GPHEN1 (PBASE + 0x00200068) 29 | #define GPPUD (PBASE + 0x00200094) 30 | #define GPPUDCLK0 (PBASE + 0x00200098) 31 | #define GPPUDCLK1 (PBASE + 0x0020009C) 32 | -------------------------------------------------------------------------------- /include/boards/raspi/irq.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "boards/raspi/base.h" 13 | 14 | #define IRQ_BASIC_PENDING (PBASE + 0x0000B200) 15 | #define IRQ_PENDING_1 (PBASE + 0x0000B204) 16 | #define IRQ_PENDING_2 (PBASE + 0x0000B208) 17 | #define FIQ_CONTROL (PBASE + 0x0000B20C) 18 | #define ENABLE_IRQS_1 (PBASE + 0x0000B210) 19 | #define ENABLE_IRQS_2 (PBASE + 0x0000B214) 20 | #define ENABLE_BASIC_IRQS (PBASE + 0x0000B218) 21 | #define DISABLE_IRQS_1 (PBASE + 0x0000B21C) 22 | #define DISABLE_IRQS_2 (PBASE + 0x0000B220) 23 | #define DISABLE_BASIC_IRQS (PBASE + 0x0000B224) 24 | 25 | #define SYSTEM_TIMER_IRQ_0_BIT (1 << 0) 26 | #define SYSTEM_TIMER_IRQ_1_BIT (1 << 1) 27 | #define SYSTEM_TIMER_IRQ_2_BIT (1 << 2) 28 | #define SYSTEM_TIMER_IRQ_3_BIT (1 << 3) 29 | #define AUX_IRQ_BIT (1 << 29) 30 | -------------------------------------------------------------------------------- /include/boards/raspi/mini_uart.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "boards/raspi/base.h" 13 | 14 | #define AUX_IRQ (PBASE + 0x00215000) 15 | #define AUX_ENABLES (PBASE + 0x00215004) 16 | #define AUX_MU_IO_REG (PBASE + 0x00215040) 17 | #define AUX_MU_IER_REG (PBASE + 0x00215044) 18 | #define AUX_MU_IIR_REG (PBASE + 0x00215048) 19 | #define AUX_MU_LCR_REG (PBASE + 0x0021504C) 20 | #define AUX_MU_MCR_REG (PBASE + 0x00215050) 21 | #define AUX_MU_LSR_REG (PBASE + 0x00215054) 22 | #define AUX_MU_MSR_REG (PBASE + 0x00215058) 23 | #define AUX_MU_SCRATCH (PBASE + 0x0021505C) 24 | #define AUX_MU_CNTL_REG (PBASE + 0x00215060) 25 | #define AUX_MU_STAT_REG (PBASE + 0x00215064) 26 | #define AUX_MU_BAUD_REG (PBASE + 0x00215068) 27 | -------------------------------------------------------------------------------- /include/boards/raspi/phys2bus.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | unsigned long phys_to_bus(unsigned long phys); 13 | unsigned long bus_to_phys(unsigned long bus); 14 | -------------------------------------------------------------------------------- /include/boards/raspi/pl011.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "boards/raspi/base.h" 13 | 14 | #define PL011_DR (PBASE + 0x201000) 15 | #define PL011_RSRECR (PBASE + 0x201004) 16 | #define PL011_FR (PBASE + 0x201018) 17 | #define PL011_ILPR (PBASE + 0x201020) 18 | #define PL011_IBRD (PBASE + 0x201024) 19 | #define PL011_FBRD (PBASE + 0x201028) 20 | #define PL011_LCRH (PBASE + 0x20102c) 21 | #define PL011_CR (PBASE + 0x201030) 22 | #define PL011_IFLS (PBASE + 0x201034) 23 | #define PL011_IMSC (PBASE + 0x201038) 24 | #define PL011_RIS (PBASE + 0x20103c) 25 | #define PL011_MIS (PBASE + 0x201040) 26 | #define PL011_ICR (PBASE + 0x201044) 27 | #define PL011_DMACR (PBASE + 0x201048) 28 | #define PL011_ITCR (PBASE + 0x201080) 29 | #define PL011_ITIP (PBASE + 0x201084) 30 | #define PL011_ITOP (PBASE + 0x201088) 31 | #define PL011_IDR (PBASE + 0x20108c) 32 | -------------------------------------------------------------------------------- /include/boards/raspi/raspi3b.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "common/mm.h" 13 | #include "common/types.h" 14 | 15 | struct page_pool { 16 | paddr_t start_addr; 17 | // spinlock_t lock; // TODO: need a lock 18 | uint64_t page_nr; 19 | uint8_t *memap; 20 | uint64_t last_page_id; 21 | }; 22 | 23 | struct page_pool *get_rasp3b_page_pool(void); 24 | -------------------------------------------------------------------------------- /include/boards/raspi/timer.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "boards/raspi/base.h" 13 | 14 | #define TIMER_CS (PBASE + 0x00003000) 15 | #define TIMER_CLO (PBASE + 0x00003004) 16 | #define TIMER_CHI (PBASE + 0x00003008) 17 | #define TIMER_C0 (PBASE + 0x0000300C) 18 | #define TIMER_C1 (PBASE + 0x00003010) 19 | #define TIMER_C2 (PBASE + 0x00003014) 20 | #define TIMER_C3 (PBASE + 0x00003018) 21 | 22 | #define TIMER_CS_M0 (1 << 0) 23 | #define TIMER_CS_M1 (1 << 1) 24 | #define TIMER_CS_M2 (1 << 2) 25 | #define TIMER_CS_M3 (1 << 3) 26 | -------------------------------------------------------------------------------- /include/common/board.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "common/sched.h" 13 | 14 | #define HAVE_FUNC(ops, func, ...) ((ops) && ((ops)->func)) 15 | 16 | struct board_ops { 17 | void (*initialize)(struct task_struct *); 18 | unsigned long (*mmio_read)(struct task_struct *, unsigned long); 19 | void (*mmio_write)(struct task_struct *, unsigned long, unsigned long); 20 | void (*entering_vm)(struct task_struct *); 21 | void (*leaving_vm)(struct task_struct *); 22 | int (*is_irq_asserted)(struct task_struct *); 23 | int (*is_fiq_asserted)(struct task_struct *); 24 | void (*debug)(struct task_struct *); 25 | }; 26 | -------------------------------------------------------------------------------- /include/common/debug.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "common/entry.h" 13 | #include "common/printf.h" 14 | #include "common/sched.h" 15 | 16 | #define _LOG_COMMON(level, fmt, ...) \ 17 | do { \ 18 | if (current) { \ 19 | printf("%s[%d]: ", (level), current->pid); \ 20 | } else { \ 21 | printf("%s[?]: ", (level)); \ 22 | } \ 23 | printf(fmt "\n", ##__VA_ARGS__); \ 24 | } while (0) 25 | 26 | #define INFO(fmt, ...) _LOG_COMMON("INFO", fmt, ##__VA_ARGS__) 27 | #define WARN(fmt, ...) _LOG_COMMON("WARN", fmt, ##__VA_ARGS__) 28 | 29 | #define PANIC(fmt, ...) \ 30 | do { \ 31 | _LOG_COMMON("!!! PANIC", fmt, ##__VA_ARGS__); \ 32 | if (current) \ 33 | exit_task(); \ 34 | else \ 35 | err_hang(); \ 36 | } while (0) 37 | -------------------------------------------------------------------------------- /include/common/delays.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | * 9 | * Copyright (C) 2018 bzt (bztsrc@github) 10 | * 11 | * Permission is hereby granted, free of charge, to any person 12 | * obtaining a copy of this software and associated documentation 13 | * files (the "Software"), to deal in the Software without 14 | * restriction, including without limitation the rights to use, copy, 15 | * modify, merge, publish, distribute, sublicense, and/or sell copies 16 | * of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be 20 | * included in all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 26 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 27 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 29 | * DEALINGS IN THE SOFTWARE. 30 | * 31 | */ 32 | 33 | void wait_cycles(unsigned int n); 34 | void wait_msec(unsigned int n); 35 | void wait_msec_st(unsigned int n); 36 | -------------------------------------------------------------------------------- /include/common/entry.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #define S_FRAME_SIZE 272 // size of all saved registers 13 | #define S_X0 0 // offset of x0 register in saved stack frame 14 | 15 | #define SYNC_INVALID_EL2 0 16 | #define IRQ_INVALID_EL2 1 17 | #define FIQ_INVALID_EL2 2 18 | #define ERROR_INVALID_EL2 3 19 | 20 | #define SYNC_INVALID_EL01_64 4 21 | #define IRQ_INVALID_EL01_64 5 22 | #define FIQ_INVALID_EL01_64 6 23 | #define ERROR_INVALID_EL01_64 7 24 | 25 | #define SYNC_INVALID_EL01_32 8 26 | #define IRQ_INVALID_EL01_32 9 27 | #define FIQ_INVALID_EL01_32 10 28 | #define ERROR_INVALID_EL01_32 11 29 | 30 | #ifndef __ASSEMBLER__ 31 | 32 | void switch_from_kthread(void); 33 | void err_hang(void); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/common/errno.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | /** Indicates that operation not permitted. */ 13 | #define EPERM 1 14 | /** Indicates that there is IO error. */ 15 | #define EIO 5 16 | /** Indicates that not enough memory. */ 17 | #define ENOMEM 12 18 | /** Indicates Permission denied */ 19 | #define EACCES 13 20 | /** Indicates there is fault. */ 21 | #define EFAULT 14 22 | /** Indicates that target is busy. */ 23 | #define EBUSY 16 24 | /** Indicates that no such dev. */ 25 | #define ENODEV 19 26 | /** Indicates that argument is not valid. */ 27 | #define EINVAL 22 28 | /** Indicates that timeout occurs. */ 29 | #define ETIMEDOUT 110 30 | -------------------------------------------------------------------------------- /include/common/fifo.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | struct fifo; 13 | 14 | int is_empty_fifo(struct fifo *); 15 | int is_full_fifo(struct fifo *); 16 | struct fifo *create_fifo(void); 17 | void clear_fifo(struct fifo *fifo); 18 | int enqueue_fifo(struct fifo *, unsigned long); 19 | int dequeue_fifo(struct fifo *, unsigned long *); 20 | int used_of_fifo(struct fifo *fifo); 21 | -------------------------------------------------------------------------------- /include/common/irq.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | void enable_interrupt_controller(void); 13 | 14 | void irq_vector_init(void); 15 | void enable_irq(void); 16 | void disable_irq(void); 17 | -------------------------------------------------------------------------------- /include/common/loader.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "common/sched.h" 13 | #include "common/task.h" 14 | 15 | struct raw_binary_loader_args { 16 | unsigned long load_addr; 17 | unsigned long entry_point; 18 | unsigned long sp; 19 | char filename[36]; 20 | }; 21 | 22 | int raw_binary_loader(void *, struct pt_regs *regs); 23 | -------------------------------------------------------------------------------- /include/common/mini_uart.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | void uart_init(void); 13 | void handle_uart_irq(void); 14 | char uart_recv(void); 15 | void uart_send(char c); 16 | void putc(void *p, char c); 17 | -------------------------------------------------------------------------------- /include/common/mm.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "boards/raspi/base.h" 13 | 14 | #define VA_START 0x0000000000000000 15 | 16 | #define PHYS_MEMORY_SIZE 0x40000000 17 | 18 | #define PAGE_MASK 0xfffffffffffff000 19 | #define PAGE_SHIFT 12 20 | #define TABLE_SHIFT 9 21 | #define SECTION_SHIFT (PAGE_SHIFT + TABLE_SHIFT) 22 | 23 | #define PAGE_SIZE (1 << PAGE_SHIFT) 24 | #define SECTION_SIZE (1 << SECTION_SHIFT) 25 | 26 | #define LOW_MEMORY (2 * SECTION_SIZE) 27 | #define HIGH_MEMORY DEVICE_BASE 28 | 29 | #define PAGING_MEMORY (HIGH_MEMORY - LOW_MEMORY) 30 | #define PAGING_PAGES (PAGING_MEMORY / PAGE_SIZE) 31 | 32 | #define PTRS_PER_TABLE (1 << TABLE_SHIFT) 33 | 34 | #define PGD_SHIFT PAGE_SHIFT + 3 * TABLE_SHIFT 35 | #define PUD_SHIFT PAGE_SHIFT + 2 * TABLE_SHIFT 36 | #define PMD_SHIFT PAGE_SHIFT + TABLE_SHIFT 37 | 38 | #define LV1_SHIFT PAGE_SHIFT + 2 * TABLE_SHIFT 39 | #define LV2_SHIFT PAGE_SHIFT + TABLE_SHIFT 40 | 41 | #define PG_DIR_SIZE (3 * PAGE_SIZE) 42 | 43 | #ifndef __ASSEMBLER__ 44 | #include "sched.h" 45 | #include "types.h" 46 | #include 47 | 48 | typedef uint64_t paddr_t; 49 | typedef uint64_t vaddr_t; 50 | 51 | #define TO_VADDR(pa) ((vaddr_t)pa + VA_START) 52 | #define TO_PADDR(pa) ((paddr_t)pa - VA_START) 53 | 54 | void map_stage2_page(struct task_struct *task, vaddr_t va, paddr_t page, 55 | uint64_t flags); 56 | void *allocate_page(void); 57 | void deallocate_page(void *); 58 | void *allocate_task_page(struct task_struct *task, vaddr_t va); 59 | bool check_task_page_mapped(struct task_struct *task, vaddr_t va); 60 | void set_task_page_notaccessable(struct task_struct *task, vaddr_t va); 61 | int handle_mem_abort(vaddr_t addr, uint64_t esr); 62 | 63 | extern paddr_t pg_dir; 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /include/common/printf.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // \author (c) Marco Paland (info@paland.com) 3 | // 2014-2019, PALANDesign Hannover, Germany 4 | // 5 | // \license The MIT License (MIT) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | // \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on 26 | // embedded systems with a very limited resources. 27 | // Use this instead of bloated standard/newlib printf. 28 | // These routines are thread safe and reentrant. 29 | // 30 | /////////////////////////////////////////////////////////////////////////////// 31 | 32 | #ifndef _PRINTF_H_ 33 | #define _PRINTF_H_ 34 | 35 | #include 36 | #include 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | /** 43 | * Output a character to a custom device like UART, used by the printf() function 44 | * This function is declared here only. You have to write your custom implementation somewhere 45 | * \param character Character to output 46 | */ 47 | void _putchar(char character); 48 | 49 | /** 50 | * Tiny printf implementation 51 | * You have to implement _putchar if you use printf() 52 | * To avoid conflicts with the regular printf() API it is overridden by macro defines 53 | * and internal underscore-appended functions like printf_() are used 54 | * \param format A string that specifies the format of the output 55 | * \return The number of characters that are written into the array, not counting the terminating null character 56 | */ 57 | #define printf printf_ 58 | int printf_(const char *format, ...); 59 | 60 | /** 61 | * Tiny sprintf implementation 62 | * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! 63 | * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! 64 | * \param format A string that specifies the format of the output 65 | * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character 66 | */ 67 | #define sprintf sprintf_ 68 | int sprintf_(char *buffer, const char *format, ...); 69 | 70 | /** 71 | * Tiny snprintf/vsnprintf implementation 72 | * \param buffer A pointer to the buffer where to store the formatted string 73 | * \param count The maximum number of characters to store in the buffer, including a terminating null character 74 | * \param format A string that specifies the format of the output 75 | * \param va A value identifying a variable arguments list 76 | * \return The number of characters that COULD have been written into the buffer, not counting the terminating 77 | * null character. A value equal or larger than count indicates truncation. Only when the returned value 78 | * is non-negative and less than count, the string has been completely written. 79 | */ 80 | #define snprintf snprintf_ 81 | #define vsnprintf vsnprintf_ 82 | int snprintf_(char *buffer, size_t count, const char *format, ...); 83 | int vsnprintf_(char *buffer, size_t count, const char *format, va_list va); 84 | 85 | /** 86 | * Tiny vprintf implementation 87 | * \param format A string that specifies the format of the output 88 | * \param va A value identifying a variable arguments list 89 | * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character 90 | */ 91 | #define vprintf vprintf_ 92 | int vprintf_(const char *format, va_list va); 93 | 94 | /** 95 | * printf with output function 96 | * You may use this as dynamic alternative to printf() with its fixed _putchar() output 97 | * \param out An output function which takes one character and an argument pointer 98 | * \param arg An argument pointer for user data passed to output function 99 | * \param format A string that specifies the format of the output 100 | * \return The number of characters that are sent to the output function, not counting the terminating null character 101 | */ 102 | int fctprintf(void (*out)(char character, void *arg), void *arg, 103 | const char *format, ...); 104 | 105 | #ifdef __cplusplus 106 | } 107 | #endif 108 | 109 | #endif // _PRINTF_H_ 110 | -------------------------------------------------------------------------------- /include/common/sched.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #define THREAD_CPU_CONTEXT 0 // offset of cpu_context in task_struct 13 | 14 | #ifndef __ASSEMBLER__ 15 | #define THREAD_SIZE 4096 16 | 17 | #define NR_TASKS 64 18 | 19 | #define FIRST_TASK task[0] 20 | #define LAST_TASK task[NR_TASKS - 1] 21 | 22 | #define TASK_RUNNING 0 23 | #define TASK_ZOMBIE 1 24 | 25 | struct board_ops; 26 | extern struct task_struct *current; 27 | extern struct task_struct *task[NR_TASKS]; 28 | extern int nr_tasks; 29 | 30 | struct cpu_context { 31 | unsigned long x19; 32 | unsigned long x20; 33 | unsigned long x21; 34 | unsigned long x22; 35 | unsigned long x23; 36 | unsigned long x24; 37 | unsigned long x25; 38 | unsigned long x26; 39 | unsigned long x27; 40 | unsigned long x28; 41 | unsigned long fp; 42 | unsigned long sp; 43 | unsigned long pc; 44 | }; 45 | 46 | struct cpu_sysregs { 47 | // not trapped (save & restore performed) 48 | unsigned long sctlr_el1; 49 | unsigned long ttbr0_el1; 50 | unsigned long ttbr1_el1; 51 | unsigned long tcr_el1; 52 | unsigned long esr_el1; 53 | unsigned long far_el1; 54 | unsigned long afsr0_el1; 55 | unsigned long afsr1_el1; 56 | unsigned long mair_el1; 57 | unsigned long amair_el1; 58 | unsigned long contextidr_el1; 59 | 60 | unsigned long cpacr_el1; 61 | unsigned long elr_el1; 62 | unsigned long fpcr; 63 | unsigned long fpsr; 64 | unsigned long midr_el1; // ro 65 | unsigned long mpidr_el1; // ro 66 | unsigned long par_el1; 67 | unsigned long sp_el0; 68 | unsigned long sp_el1; 69 | unsigned long spsr_el1; 70 | unsigned long tpidr_el0; 71 | unsigned long tpidr_el1; 72 | unsigned long tpidrro_el0; 73 | unsigned long vbar_el1; 74 | 75 | // trapped by TACR 76 | unsigned long actlr_el1; // rw 77 | 78 | // trapped by TID3 79 | unsigned long id_pfr0_el1; // ro 80 | unsigned long id_pfr1_el1; // ro 81 | unsigned long id_mmfr0_el1; // ro 82 | unsigned long id_mmfr1_el1; // ro 83 | unsigned long id_mmfr2_el1; // ro 84 | unsigned long id_mmfr3_el1; // ro 85 | unsigned long id_isar0_el1; // ro 86 | unsigned long id_isar1_el1; // ro 87 | unsigned long id_isar2_el1; // ro 88 | unsigned long id_isar3_el1; // ro 89 | unsigned long id_isar4_el1; // ro 90 | unsigned long id_isar5_el1; // ro 91 | unsigned long mvfr0_el1; // ro 92 | unsigned long mvfr1_el1; // ro 93 | unsigned long mvfr2_el1; // ro 94 | unsigned long id_aa64pfr0_el1; // ro 95 | unsigned long id_aa64pfr1_el1; // ro 96 | unsigned long id_aa64dfr0_el1; // ro 97 | unsigned long id_aa64dfr1_el1; // ro 98 | unsigned long id_aa64isar0_el1; // ro 99 | unsigned long id_aa64isar1_el1; // ro 100 | unsigned long id_aa64mmfr0_el1; // ro 101 | unsigned long id_aa64mmfr1_el1; // ro 102 | unsigned long id_aa64afr0_el1; // ro 103 | unsigned long id_aa64afr1_el1; // ro 104 | 105 | // trapped by TID2 106 | unsigned long ctr_el0; // ro 107 | unsigned long ccsidr_el1; // ro 108 | unsigned long clidr_el1; // ro 109 | unsigned long csselr_el1; // rw 110 | 111 | // trapped by TID1 112 | unsigned long aidr_el1; // ro 113 | unsigned long revidr_el1; // ro 114 | 115 | // system timer 116 | unsigned long cntkctl_el1; 117 | unsigned long cntp_ctl_el0; 118 | unsigned long cntp_cval_el0; 119 | unsigned long cntp_tval_el0; 120 | unsigned long cntv_ctl_el0; 121 | unsigned long cntv_cval_el0; 122 | unsigned long cntv_tval_el0; 123 | }; 124 | 125 | struct mm_struct { 126 | unsigned long first_table; 127 | int user_pages_count; 128 | int kernel_pages_count; 129 | }; 130 | 131 | struct task_stat { 132 | long wfx_trap_count; 133 | long hvc_trap_count; 134 | long sysreg_trap_count; 135 | long pf_count; 136 | long mmio_count; 137 | }; 138 | 139 | struct task_console { 140 | struct fifo *in_fifo; 141 | struct fifo *out_fifo; 142 | }; 143 | 144 | struct task_struct { 145 | struct cpu_context cpu_context; 146 | long state; 147 | long counter; 148 | long priority; 149 | long preempt_count; 150 | long pid; // used as VMID 151 | unsigned long flags; 152 | char name[36]; 153 | const struct board_ops *board_ops; 154 | void *board_data; 155 | struct mm_struct mm; 156 | struct cpu_sysregs cpu_sysregs; 157 | struct task_stat stat; 158 | struct task_console console; 159 | }; 160 | 161 | extern void sched_init(void); 162 | extern void schedule(void); 163 | extern void timer_tick(void); 164 | extern void preempt_disable(void); 165 | extern void preempt_enable(void); 166 | extern void set_cpu_virtual_interrupt(struct task_struct *); 167 | void set_cpu_sysregs(struct task_struct *); 168 | extern void switch_to(struct task_struct *); 169 | extern void cpu_switch_to(struct task_struct *, struct task_struct *); 170 | extern void exit_task(void); 171 | extern void show_task_list(void); 172 | 173 | #define INIT_TASK \ 174 | { \ 175 | /* cpu_context */ { 0 }, /* state etc */ 0, 0, 1, 0, 0, 0, "", \ 176 | 0, 0, /* mm */ { 0 }, /* cpu_sysregs */ { 0 }, \ 177 | /* stat */ { 0 }, /* console */ { 0 }, \ 178 | } 179 | 180 | #endif 181 | -------------------------------------------------------------------------------- /include/common/sd.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | * 9 | * Copyright (C) 2018 bzt (bztsrc@github) 10 | * 11 | * Permission is hereby granted, free of charge, to any person 12 | * obtaining a copy of this software and associated documentation 13 | * files (the "Software"), to deal in the Software without 14 | * restriction, including without limitation the rights to use, copy, 15 | * modify, merge, publish, distribute, sublicense, and/or sell copies 16 | * of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be 20 | * included in all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 26 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 27 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 29 | * DEALINGS IN THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #pragma once 34 | 35 | #define SD_OK 0 36 | #define SD_TIMEOUT -1 37 | #define SD_ERROR -2 38 | 39 | int sd_init(); 40 | int sd_readblock(unsigned int lba, unsigned char *buffer, unsigned int num); 41 | -------------------------------------------------------------------------------- /include/common/shell.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | void shell_init(void); 13 | void shell_kick(void); 14 | -------------------------------------------------------------------------------- /include/common/sync_exc.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | void show_uncaught_sync_exception_message(int, unsigned long, unsigned long); 13 | -------------------------------------------------------------------------------- /include/common/task.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "common/sched.h" 13 | 14 | /* 15 | * PSR bits 16 | */ 17 | #define PSR_MODE_EL0t 0x00000000 18 | #define PSR_MODE_EL1t 0x00000004 19 | #define PSR_MODE_EL1h 0x00000005 20 | #define PSR_MODE_EL2t 0x00000008 21 | #define PSR_MODE_EL2h 0x00000009 22 | #define PSR_MODE_EL3t 0x0000000c 23 | #define PSR_MODE_EL3h 0x0000000d 24 | 25 | extern int uart_forwarded_task; 26 | 27 | struct pt_regs { 28 | unsigned long regs[31]; 29 | unsigned long sp; 30 | unsigned long pc; 31 | unsigned long pstate; 32 | }; 33 | 34 | typedef int (*loader_func_t)(void *, struct pt_regs *regs); 35 | 36 | struct pt_regs *task_pt_regs(struct task_struct *); 37 | int create_task(loader_func_t, void *); 38 | void init_task_console(struct task_struct *); 39 | int is_uart_forwarded_task(struct task_struct *); 40 | void flush_task_console(struct task_struct *); 41 | void increment_current_pc(int); 42 | void init_initial_task(void); 43 | 44 | -------------------------------------------------------------------------------- /include/common/timer.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | void timer_init(void); 13 | void handle_timer1_irq(void); 14 | void handle_timer3_irq(void); 15 | unsigned long get_physical_timer_count(void); 16 | unsigned long get_system_timer(void); 17 | -------------------------------------------------------------------------------- /include/common/types.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 13 | #define __aligned(x) __attribute__((aligned(x))) 14 | #define __packed __attribute__((packed)) 15 | #define __unused __attribute__((unused)) 16 | 17 | #ifndef ASSEMBLER 18 | 19 | /* Define standard data types. These definitions allow software components 20 | * to perform in the same manner on different target platforms. 21 | */ 22 | typedef signed char int8_t; 23 | typedef unsigned char uint8_t; 24 | typedef signed short int16_t; 25 | typedef unsigned short uint16_t; 26 | typedef signed int int32_t; 27 | typedef unsigned int uint32_t; 28 | typedef unsigned long uint64_t; 29 | typedef signed long int64_t; 30 | // NOW #include 31 | // typedef unsigned int size_t; 32 | typedef __builtin_va_list va_list; 33 | 34 | typedef _Bool bool; 35 | 36 | #ifndef NULL 37 | #define NULL ((void *)0) 38 | #endif 39 | 40 | #ifndef true 41 | #define true ((_Bool)1) 42 | #define false ((_Bool)0) 43 | #endif 44 | 45 | #ifndef UINT64_MAX 46 | #define UINT64_MAX (0xffffffffffffffffUL) 47 | #endif 48 | 49 | #ifndef UINT32_MAX 50 | #define UINT32_MAX (0xffffffffU) 51 | #endif 52 | 53 | #endif /* ASSEMBLER */ 54 | -------------------------------------------------------------------------------- /include/common/utils.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "common/types.h" 13 | #include 14 | 15 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) 16 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) 17 | 18 | /* MACRO related to string */ 19 | #define ULONG_MAX ((uint64_t)(~0UL)) /* 0xFFFFFFFF */ 20 | #define LONG_MAX (ULONG_MAX >> 1U) /* 0x7FFFFFFF */ 21 | #define LONG_MIN (~LONG_MAX) /* 0x80000000 */ 22 | 23 | struct cpu_sysregs; 24 | 25 | void memzero(void *, size_t); 26 | void memcpy(void *, const void *, size_t); 27 | 28 | extern void delay(unsigned long); 29 | extern void put32(unsigned long, unsigned int); 30 | extern unsigned int get32(unsigned long); 31 | extern unsigned long get_el(void); 32 | extern void set_stage2_pgd(unsigned long, unsigned long); 33 | extern void restore_sysregs(struct cpu_sysregs *); 34 | extern void save_sysregs(struct cpu_sysregs *); 35 | extern void get_all_sysregs(struct cpu_sysregs *); 36 | extern void assert_vfiq(void); 37 | extern void assert_virq(void); 38 | extern void assert_vserror(void); 39 | extern void clear_vfiq(void); 40 | extern void clear_virq(void); 41 | extern void clear_vserror(void); 42 | extern unsigned long translate_el1(unsigned long); 43 | 44 | int abs(int); 45 | char *strncpy(char *, const char *, size_t); 46 | size_t strnlen(const char *, size_t); 47 | int strcmp(const char *, const char *); 48 | int strncmp(const char *, const char *, size_t); 49 | int strcasecmp(const char *s1, const char *s2); 50 | int strncasecmp(const char *s1, const char *s2, size_t len); 51 | char *strdup(const char *); 52 | void *memset(void *, int, size_t); 53 | int memcmp(const void *, const void *, size_t); 54 | void *memmove(void *, const void *, size_t); 55 | void *memchr(const void *, int, size_t); 56 | char *strchr(const char *, int); 57 | char *strcpy(char *, const char *); 58 | char *strncat(char *, const char *, size_t); 59 | char *strcat(char *, const char *); 60 | int isdigit(int); 61 | int isspace(int); 62 | int toupper(int); 63 | int tolower(int); 64 | int64_t strtol_deci(const char *nptr); 65 | unsigned long strtoul(const char *str, char **endptr, int base); 66 | 67 | -------------------------------------------------------------------------------- /include/emulator/raspi/bcm2837.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | extern const struct board_ops bcm2837_board_ops; 13 | -------------------------------------------------------------------------------- /include/emulator/raspi/vmbox.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * aVisor Hypervisor 4 | * 5 | * A Tiny Hypervisor for IoT Development 6 | * 7 | * Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "common/sched.h" 13 | #include "common/types.h" 14 | #include 15 | 16 | #define MBOX_REQUEST 0 17 | 18 | typedef enum { 19 | CLK_EMMC_ID = 0x1, // Mailbox Tag Channel EMMC clock ID 20 | CLK_UART_ID = 0x2, // Mailbox Tag Channel uart clock ID 21 | CLK_ARM_ID = 0x3, // Mailbox Tag Channel ARM clock ID 22 | CLK_CORE_ID = 0x4, // Mailbox Tag Channel SOC core clock ID 23 | CLK_V3D_ID = 0x5, // Mailbox Tag Channel V3D clock ID 24 | CLK_H264_ID = 0x6, // Mailbox Tag Channel H264 clock ID 25 | CLK_ISP_ID = 0x7, // Mailbox Tag Channel ISP clock ID 26 | CLK_SDRAM_ID = 0x8, // Mailbox Tag Channel SDRAM clock ID 27 | CLK_PIXEL_ID = 0x9, // Mailbox Tag Channel PIXEL clock ID 28 | CLK_PWM_ID = 0xA, // Mailbox Tag Channel PWM clock ID 29 | } MB_CLOCK_ID; 30 | 31 | typedef enum { 32 | MBOX_CHAN_POWER = 0x0, // Mailbox Channel 0: Power Management Interface 33 | MBOX_CHAN_FB = 0x1, // Mailbox Channel 1: Frame Buffer 34 | MBOX_CHAN_VUART = 0x2, // Mailbox Channel 2: Virtual UART 35 | MBOX_CHAN_VCHIQ = 0x3, // Mailbox Channel 3: VCHIQ Interface 36 | MBOX_CHAN_LEDS = 0x4, // Mailbox Channel 4: LEDs Interface 37 | MBOX_CHAN_BUTTONS = 0x5, // Mailbox Channel 5: Buttons Interface 38 | MBOX_CHAN_TOUCH = 0x6, // Mailbox Channel 6: Touchscreen Interface 39 | MBOX_CHAN_COUNT = 0x7, // Mailbox Channel 7: Counter 40 | MBOX_CHAN_TAGS = 0x8, // Mailbox Channel 8: Tags (ARM to VC) 41 | MBOX_CHAN_GPU = 0x9, // Mailbox Channel 9: GPU (VC to ARM) 42 | } MBOX_CHAN; 43 | 44 | typedef enum { 45 | /* Videocore info commands */ 46 | MBOX_TAG_GET_VERSION = 0x00000001, // Get firmware revision 47 | 48 | /* Hardware info commands */ 49 | MBOX_TAG_GET_BOARD_MODEL = 0x00010001, // Get board model 50 | MBOX_TAG_GET_BOARD_REVISION = 0x00010002, // Get board revision 51 | MBOX_TAG_GET_BOARD_MAC_ADDRESS = 0x00010003, // Get board MAC address 52 | MBOX_TAG_GET_BOARD_SERIAL = 0x00010004, // Get board serial 53 | MBOX_TAG_GET_ARM_MEMORY = 0x00010005, // Get ARM memory 54 | MBOX_TAG_GET_VC_MEMORY = 0x00010006, // Get VC memory 55 | MBOX_TAG_GET_CLOCKS = 0x00010007, // Get clocks 56 | 57 | /* Power commands */ 58 | MBOX_TAG_GET_POWER_STATE = 0x00020001, // Get power state 59 | MBOX_TAG_GET_TIMING = 0x00020002, // Get timing 60 | MBOX_TAG_SET_POWER_STATE = 0x00028001, // Set power state 61 | 62 | /* GPIO commands */ 63 | MBOX_TAG_GET_GET_GPIO_STATE = 0x00030041, // Get GPIO state 64 | MBOX_TAG_SET_GPIO_STATE = 0x00038041, // Set GPIO state 65 | 66 | /* Clock commands */ 67 | MBOX_TAG_GET_CLOCK_STATE = 0x00030001, // Get clock state 68 | MBOX_TAG_GET_CLOCK_RATE = 0x00030002, // Get clock rate 69 | MBOX_TAG_GET_MAX_CLOCK_RATE = 0x00030004, // Get max clock rate 70 | MBOX_TAG_GET_MIN_CLOCK_RATE = 0x00030007, // Get min clock rate 71 | MBOX_TAG_GET_TURBO = 0x00030009, // Get turbo 72 | 73 | MBOX_TAG_SET_CLOCK_STATE = 0x00038001, // Set clock state 74 | MBOX_TAG_SET_CLOCK_RATE = 0x00038002, // Set clock rate 75 | MBOX_TAG_SET_TURBO = 0x00038009, // Set turbo 76 | 77 | /* Voltage commands */ 78 | MBOX_TAG_GET_VOLTAGE = 0x00030003, // Get voltage 79 | MBOX_TAG_GET_MAX_VOLTAGE = 0x00030005, // Get max voltage 80 | MBOX_TAG_GET_MIN_VOLTAGE = 0x00030008, // Get min voltage 81 | 82 | MBOX_TAG_SET_VOLTAGE = 0x00038003, // Set voltage 83 | 84 | /* Temperature commands */ 85 | MBOX_TAG_GET_TEMPERATURE = 0x00030006, // Get temperature 86 | MBOX_TAG_GET_MAX_TEMPERATURE = 0x0003000A, // Get max temperature 87 | 88 | /* Memory commands */ 89 | MBOX_TAG_ALLOCATE_MEMORY = 0x0003000C, // Allocate Memory 90 | MBOX_TAG_LOCK_MEMORY = 0x0003000D, // Lock memory 91 | MBOX_TAG_UNLOCK_MEMORY = 0x0003000E, // Unlock memory 92 | MBOX_TAG_RELEASE_MEMORY = 0x0003000F, // Release Memory 93 | 94 | /* Execute code commands */ 95 | MBOX_TAG_EXECUTE_CODE = 0x00030010, // Execute code 96 | 97 | /* QPU control commands */ 98 | MBOX_TAG_EXECUTE_QPU = 0x00030011, // Execute code on QPU 99 | MBOX_TAG_ENABLE_QPU = 0x00030012, // QPU enable 100 | 101 | /* Displaymax commands */ 102 | MBOX_TAG_GET_DISPMANX_HANDLE = 0x00030014, // Get displaymax handle 103 | MBOX_TAG_GET_EDID_BLOCK = 0x00030020, // Get HDMI EDID block 104 | 105 | /* SD Card commands */ 106 | MBOX_GET_SDHOST_CLOCK = 0x00030042, // Get SD Card EMCC clock 107 | MBOX_SET_SDHOST_CLOCK = 0x00038042, // Set SD Card EMCC clock 108 | 109 | /* Framebuffer commands */ 110 | MBOX_TAG_ALLOCATE_FRAMEBUFFER = 111 | 0x00040001, // Allocate Framebuffer address 112 | MBOX_TAG_BLANK_SCREEN = 0x00040002, // Blank screen 113 | MBOX_TAG_GET_PHYSICAL_WIDTH_HEIGHT = 114 | 0x00040003, // Get physical screen width/height 115 | MBOX_TAG_GET_VIRTUAL_WIDTH_HEIGHT = 116 | 0x00040004, // Get virtual screen width/height 117 | MBOX_TAG_GET_COLOUR_DEPTH = 0x00040005, // Get screen colour depth 118 | MBOX_TAG_GET_PIXEL_ORDER = 0x00040006, // Get screen pixel order 119 | MBOX_TAG_GET_ALPHA_MODE = 0x00040007, // Get screen alpha mode 120 | MBOX_TAG_GET_PITCH = 0x00040008, // Get screen line to line pitch 121 | MBOX_TAG_GET_VIRTUAL_OFFSET = 0x00040009, // Get screen virtual offset 122 | MBOX_TAG_GET_OVERSCAN = 0x0004000A, // Get screen overscan value 123 | MBOX_TAG_GET_PALETTE = 0x0004000B, // Get screen palette 124 | 125 | MBOX_TAG_RELEASE_FRAMEBUFFER = 126 | 0x00048001, // Release Framebuffer address 127 | MBOX_TAG_SET_PHYSICAL_WIDTH_HEIGHT = 128 | 0x00048003, // Set physical screen width/heigh 129 | MBOX_TAG_SET_VIRTUAL_WIDTH_HEIGHT = 130 | 0x00048004, // Set virtual screen width/height 131 | MBOX_TAG_SET_COLOUR_DEPTH = 0x00048005, // Set screen colour depth 132 | MBOX_TAG_SET_PIXEL_ORDER = 0x00048006, // Set screen pixel order 133 | MBOX_TAG_SET_ALPHA_MODE = 0x00048007, // Set screen alpha mode 134 | MBOX_TAG_SET_VIRTUAL_OFFSET = 0x00048009, // Set screen virtual offset 135 | MBOX_TAG_SET_OVERSCAN = 0x0004800A, // Set screen overscan value 136 | MBOX_TAG_SET_PALETTE = 0x0004800B, // Set screen palette 137 | MBOX_TAG_SET_VSYNC = 0x0004800E, // Set screen VSync 138 | MBOX_TAG_SET_BACKLIGHT = 0x0004800F, // Set screen backlight 139 | 140 | /* VCHIQ commands */ 141 | MBOX_TAG_VCHIQ_INIT = 0x00048010, // Enable VCHIQ 142 | 143 | /* Config commands */ 144 | MBOX_TAG_GET_COMMAND_LINE = 0x00050001, // Get command line 145 | 146 | /* Shared resource management commands */ 147 | MBOX_TAG_GET_DMA_CHANNELS = 0x00060001, // Get DMA channels 148 | 149 | /* Cursor commands */ 150 | MBOX_TAG_SET_CURSOR_INFO = 0x00008010, // Set cursor info 151 | MBOX_TAG_SET_CURSOR_STATE = 0x00008011, // Set cursor state 152 | 153 | MBOX_TAG_LAST = 0x0, // Tag for the end 154 | } MBOX_TAG; 155 | 156 | bool is_mbox_addr(uint64_t addr); 157 | uint64_t handle_mbox_read(struct task_struct *tsk, uint64_t addr); 158 | uint64_t handle_mbox_write(struct task_struct *tsk, uint64_t addr, uint64_t val); 159 | 160 | -------------------------------------------------------------------------------- /include/fs/diskio.h: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------/ 2 | / Low level disk interface modlue include file (C)ChaN, 2019 / 3 | /-----------------------------------------------------------------------*/ 4 | 5 | #ifndef _DISKIO_DEFINED 6 | #define _DISKIO_DEFINED 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #include "fs/ff.h" 13 | 14 | /* Status of Disk Functions */ 15 | typedef BYTE DSTATUS; 16 | 17 | /* Results of Disk Functions */ 18 | typedef enum { 19 | RES_OK = 0, /* 0: Successful */ 20 | RES_ERROR, /* 1: R/W Error */ 21 | RES_WRPRT, /* 2: Write Protected */ 22 | RES_NOTRDY, /* 3: Not Ready */ 23 | RES_PARERR, /* 4: Invalid Parameter */ 24 | RES_NOTSUP /*5: Not Support */ 25 | } DRESULT; 26 | 27 | /*---------------------------------------*/ 28 | /* Prototypes for disk control functions */ 29 | 30 | DSTATUS disk_initialize(BYTE pdrv); 31 | DSTATUS disk_status(BYTE pdrv); 32 | DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count); 33 | DRESULT disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count); 34 | DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff); 35 | 36 | /* Disk Status Bits (DSTATUS) */ 37 | #define STA_OK 0x00 /* Status OK */ 38 | #define STA_NOINIT 0x01 /* Drive not initialized */ 39 | #define STA_NODISK 0x02 /* No medium in the drive */ 40 | #define STA_PROTECT 0x04 /* Write protected */ 41 | 42 | /* Command code for disk_ioctrl fucntion */ 43 | 44 | /* Generic command (Used by FatFs) */ 45 | #define CTRL_SYNC \ 46 | 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ 47 | #define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ 48 | #define GET_SECTOR_SIZE \ 49 | 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ 50 | #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ 51 | #define CTRL_TRIM \ 52 | 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ 53 | 54 | /* Generic command (Not used by FatFs) */ 55 | #define CTRL_POWER 5 /* Get/Set power status */ 56 | #define CTRL_LOCK 6 /* Lock/Unlock media removal */ 57 | #define CTRL_EJECT 7 /* Eject media */ 58 | #define CTRL_FORMAT 8 /* Create physical format on the media */ 59 | 60 | /* MMC/SDC specific ioctl command */ 61 | #define MMC_GET_TYPE 10 /* Get card type */ 62 | #define MMC_GET_CSD 11 /* Get CSD */ 63 | #define MMC_GET_CID 12 /* Get CID */ 64 | #define MMC_GET_OCR 13 /* Get OCR */ 65 | #define MMC_GET_SDSTAT 14 /* Get SD status */ 66 | #define ISDIO_READ 55 /* Read data form SD iSDIO register */ 67 | #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ 68 | #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ 69 | 70 | /* ATA/CF specific ioctl command */ 71 | #define ATA_GET_REV 20 /* Get F/W revision */ 72 | #define ATA_GET_MODEL 21 /* Get model name */ 73 | #define ATA_GET_SN 22 /* Get serial number */ 74 | 75 | #ifdef __cplusplus 76 | } 77 | #endif 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /misc/bootcode.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calinyara/avisor/ebde0d4dbf95f7ed9a20baf1e2c71b7ca0e8bed5/misc/bootcode.bin -------------------------------------------------------------------------------- /misc/start.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calinyara/avisor/ebde0d4dbf95f7ed9a20baf1e2c71b7ca0e8bed5/misc/start.elf -------------------------------------------------------------------------------- /scripts/clean.sh: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # SPDX-License-Identifier: GPL-2.0-or-later 3 | # 4 | # aVisor Hypervisor 5 | # 6 | # A Tiny Hypervisor for IoT Development 7 | # 8 | # Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 9 | ############################################################# 10 | 11 | #!/bin/bash 12 | 13 | make clean 14 | 15 | cd guests/lrtos 16 | make clean 17 | 18 | cd ../echo 19 | make clean 20 | -------------------------------------------------------------------------------- /scripts/create_sd.sh: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # SPDX-License-Identifier: GPL-2.0-or-later 3 | # 4 | # aVisor Hypervisor 5 | # 6 | # A Tiny Hypervisor for IoT Development 7 | # 8 | # Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 9 | ############################################################# 10 | 11 | #!/bin/bash 12 | 13 | # sdcard img name, hv (not needed for qemu) and one VM at least 14 | if [ "$#" -lt 2 ]; then 15 | echo "Usage: "$0" sdimage [hv] guest0, guest1 ..." 16 | exit 1 17 | fi 18 | 19 | SDNAME="$1" 20 | shift 21 | PAYLOAD="$@" 22 | 23 | command -v qemu-img >/dev/null || { echo "qemu-img not installed"; exit 1; } 24 | command -v qemu-nbd >/dev/null || { echo "qemu-nbd not installed"; exit 1; } 25 | 26 | qemu-img create "$SDNAME" 64M 27 | sudo qemu-nbd -c /dev/nbd0 "$SDNAME" 28 | 29 | (echo o; 30 | echo n; echo p 31 | echo 1 32 | echo ; echo 33 | echo w; echo q) | sudo fdisk /dev/nbd0 34 | sudo mkfs.fat -F32 /dev/nbd0p1 35 | 36 | mkdir tmp || true 37 | sudo mount -o user /dev/nbd0p1 tmp/ 38 | sudo cp $PAYLOAD tmp/ 39 | sleep 1s 40 | sudo umount tmp/ 41 | rmdir tmp || true 42 | 43 | sudo qemu-nbd -d /dev/nbd0 44 | 45 | (echo t; echo c 46 | echo w; echo q) | sudo fdisk "$SDNAME" 47 | -------------------------------------------------------------------------------- /scripts/demo.sh: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # SPDX-License-Identifier: GPL-2.0-or-later 3 | # 4 | # aVisor Hypervisor 5 | # 6 | # A Tiny Hypervisor for IoT Development 7 | # 8 | # Copyright (c) 2022 Deng Jie (mr.dengjie@gmail.com). 9 | ############################################################# 10 | 11 | #!/bin/bash 12 | 13 | # build the aVisor hpervisor 14 | make clean 15 | make qemu 16 | 17 | # build the lrtos 18 | cd guests/lrtos 19 | make clean 20 | make 21 | 22 | # build the echo 23 | cd ../echo 24 | make clean 25 | make 26 | 27 | # build the Qemu boot img 28 | cd ../../ 29 | cp guests/lrtos/lrtos.bin ./bin 30 | cp guests/echo/echo.bin ./bin 31 | cp guests/uboot/uboot.bin ./bin 32 | cp guests/freertos/freertos.bin ./bin 33 | sudo modprobe nbd max_part=8 34 | ./scripts/create_sd.sh ./bin/avisor.img ./bin/lrtos.bin ./bin/echo.bin ./bin/uboot.bin ./bin/freertos.bin 35 | 36 | # Run the Demo 37 | qemu-system-aarch64 -M raspi3b -nographic -serial null -serial mon:stdio -m 1024 -kernel ./bin/kernel8.img -drive file=./bin/avisor.img,if=sd,format=raw 38 | 39 | --------------------------------------------------------------------------------