├── .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 |
--------------------------------------------------------------------------------