Compare commits
58 Commits
ch32v208br
...
dev13
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e37c12e91 | ||
|
|
17285e776f | ||
|
|
e7ad298ff3 | ||
|
|
49b20dfa6a | ||
|
|
0fdf4f2ace | ||
|
|
1c0edba5bd | ||
|
|
22b980cc08 | ||
|
|
64b2117012 | ||
|
|
16a31c6739 | ||
|
|
d664e2298e | ||
|
|
02c82025c8 | ||
|
|
dbaffab140 | ||
|
|
1e59fd2a8d | ||
|
|
3a99cc550c | ||
|
|
d05754a98e | ||
|
|
6d4cef4358 | ||
|
|
5a2c07e1a9 | ||
|
|
bd7966c5a3 | ||
|
|
6114b4618f | ||
|
|
71cf0c667c | ||
|
|
80f80b64f0 | ||
|
|
c1e99c449a | ||
|
|
ba54936940 | ||
|
|
0efbe375eb | ||
|
|
2e11a31da3 | ||
|
|
dd0c6c66ed | ||
|
|
446c3746a6 | ||
|
|
2c4fe30bd3 | ||
|
|
f7a232ed4f | ||
|
|
f4e193a738 | ||
|
|
29f1df2eea | ||
|
|
4803239498 | ||
|
|
736ba18769 | ||
|
|
0b858de120 | ||
|
|
56ec6edbe5 | ||
|
|
5a12635b85 | ||
|
|
c6de550e45 | ||
|
|
52387d47a7 | ||
|
|
48abec8a00 | ||
|
|
e62863bc22 | ||
|
|
a836b7f5c8 | ||
|
|
79d741e015 | ||
|
|
b6dd58c629 | ||
|
|
16a53d4e80 | ||
|
|
6d54c54bcc | ||
|
|
a19312df24 | ||
|
|
361ea2b53e | ||
|
|
6b91caac18 | ||
|
|
3b011500f1 | ||
|
|
18eff4334c | ||
|
|
50ecc1e520 | ||
|
|
7a296b2744 | ||
|
|
3a985252d9 | ||
|
|
9f9e25a98e | ||
|
|
baa04913bd | ||
|
|
3c6e8ce109 | ||
|
|
077dcd66ac | ||
|
|
293fd9fea9 |
@@ -1,3 +1,3 @@
|
||||
SRC_DIR := advantech beckhoff br delta mitsubishi omron schneider siemens ge xinje inovance keyence panasonic fatek ab abb
|
||||
SRC_DIR := advantech beckhoff br delta mitsubishi omron schneider siemens ge xinje inovance keyence panasonic fatek ab abb koyo
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
SRC_FILES := inovance_am401_cpu1608tn_ethernet.c inovance_am401_cpu1608tn_uart.c
|
||||
SRC_FILES := inovance_am401_cpu1608tn_ethernet.c inovance_am401_cpu1608tn_uart.c inovance_H3U_cpu3232MT_ethernet.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2024 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file inovance_H3U_cpu3232MT_ethernet.c
|
||||
* @brief PLC Inovance H3U-3232MT app
|
||||
* @version 3.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.08.06
|
||||
*/
|
||||
|
||||
#include <control.h>
|
||||
|
||||
void ControlInovanceH3UCPU3232MTTest(void)
|
||||
{
|
||||
int i, j = 0;
|
||||
int read_data_length = 0;
|
||||
uint8_t read_data[128] = {0};
|
||||
ControlProtocolType modbus_tcp_protocol = ControlProtocolFind();
|
||||
if (NULL == modbus_tcp_protocol) {
|
||||
printf("%s get modbus tcp protocol %p failed\n", __func__, modbus_tcp_protocol);
|
||||
return;
|
||||
}
|
||||
printf("%s get modbus tcp protocol %p successfull\n", __func__, modbus_tcp_protocol);
|
||||
|
||||
if (CONTROL_REGISTERED == modbus_tcp_protocol->protocol_status) {
|
||||
ControlProtocolOpen(modbus_tcp_protocol);
|
||||
for (;;) {
|
||||
read_data_length = ControlProtocolRead(modbus_tcp_protocol, read_data, sizeof(read_data));
|
||||
printf("%s read [%d] modbus tcp data %d using receipe file\n", __func__, i, read_data_length);
|
||||
if (read_data_length) {
|
||||
for (j = 0; j < read_data_length; j++) {
|
||||
printf("j %d data 0x%x\n", j, read_data[j]);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
memset(read_data, 0, sizeof(read_data));
|
||||
PrivTaskDelay(10000);
|
||||
}
|
||||
// ControlProtocolClose(modbus_tcp_protocol);
|
||||
}
|
||||
}
|
||||
PRIV_SHELL_CMD_FUNCTION(ControlInovanceH3UCPU3232MTTest, Inovance PLC N3UCPU3232MT Demo, PRIV_SHELL_CMD_MAIN_ATTR);
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"device_id": 1,
|
||||
"device_name": "Ino_H3U3232MT",
|
||||
"communication_type": 0,
|
||||
"socket_config": {
|
||||
"plc_ip": "192.168.250.55",
|
||||
"local_ip": "192.168.250.147",
|
||||
"gateway": "192.168.250.252",
|
||||
"netmask": "255.255.255.0",
|
||||
"port": 502
|
||||
},
|
||||
"protocol_type": 2,
|
||||
"read_period": 300,
|
||||
"read_item_list": [
|
||||
{
|
||||
"value_name": "M8000",
|
||||
"value_type": 1,
|
||||
"function_code": 1,
|
||||
"start_address": 8000,
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"value_name": "D120",
|
||||
"value_type": 3,
|
||||
"function_code": 3,
|
||||
"start_address": 120,
|
||||
"quantity": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
3
APP_Framework/Applications/control_app/plc_demo/koyo/Makefile
Executable file
3
APP_Framework/Applications/control_app/plc_demo/koyo/Makefile
Executable file
@@ -0,0 +1,3 @@
|
||||
SRC_FILES := koyo_nk1cpu40.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.7 MiB |
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2024 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file koyo_nk1cpu40.c
|
||||
* @brief PLC AB MICRO850 app
|
||||
* @version 3.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.07.03
|
||||
*/
|
||||
|
||||
#include <control.h>
|
||||
|
||||
void ControlKoyoNK1CPU40Test(void)
|
||||
{
|
||||
int i, j = 0;
|
||||
int read_data_length = 0;
|
||||
uint8_t read_data[128] = {0};
|
||||
ControlProtocolType modbus_tcp_protocol = ControlProtocolFind();
|
||||
if (NULL == modbus_tcp_protocol) {
|
||||
printf("%s get modbus tcp protocol %p failed\n", __func__, modbus_tcp_protocol);
|
||||
return;
|
||||
}
|
||||
printf("%s get modbus tcp protocol %p successfull\n", __func__, modbus_tcp_protocol);
|
||||
|
||||
if (CONTROL_REGISTERED == modbus_tcp_protocol->protocol_status) {
|
||||
ControlProtocolOpen(modbus_tcp_protocol);
|
||||
for (;;) {
|
||||
read_data_length = ControlProtocolRead(modbus_tcp_protocol, read_data, sizeof(read_data));
|
||||
printf("%s read [%d] modbus tcp data %d using receipe file\n", __func__, i, read_data_length);
|
||||
if (read_data_length) {
|
||||
for (j = 0; j < read_data_length; j++) {
|
||||
printf("j %d data 0x%x\n", j, read_data[j]);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
memset(read_data, 0, sizeof(read_data));
|
||||
PrivTaskDelay(10000);
|
||||
}
|
||||
// ControlProtocolClose(modbus_tcp_protocol);
|
||||
}
|
||||
}
|
||||
PRIV_SHELL_CMD_FUNCTION(ControlKoyoNK1CPU40Test, Koyo Plc NK1CPU40 Demo, PRIV_SHELL_CMD_MAIN_ATTR);
|
||||
@@ -977,7 +977,7 @@ int AdapterLoraTest(void)
|
||||
char task_name_2[] = "adapter_lora_gateway";
|
||||
args.pthread_name = task_name_2;
|
||||
args.arg = (void *)adapter;
|
||||
PrivTaskCreate(&lora_recv_data_task, &lora_gateway_attr, &LoraReceiveTask, (void *)&args);
|
||||
PrivTaskCreate(&lora_gateway_task, &lora_gateway_attr, &LoraGatewayTask, (void *)&args);
|
||||
#endif
|
||||
|
||||
PrivTaskStartup(&lora_gateway_task);
|
||||
|
||||
BIN
Black-Box Data Poisoning Attacks on Crowdsourcing.pdf
Normal file
BIN
Black-Box Data Poisoning Attacks on Crowdsourcing.pdf
Normal file
Binary file not shown.
BIN
Investigating_and_Detecting_Silent_Bugs_in_PyTorch_Programs.pdf
Normal file
BIN
Investigating_and_Detecting_Silent_Bugs_in_PyTorch_Programs.pdf
Normal file
Binary file not shown.
BIN
Learning from Noisy Crowd Labels with Logics.pdf
Normal file
BIN
Learning from Noisy Crowd Labels with Logics.pdf
Normal file
Binary file not shown.
@@ -4,7 +4,7 @@ MAKEFLAGS += --no-print-directory
|
||||
.PHONY:COMPILE_APP COMPILE_KERNEL
|
||||
|
||||
riscv_support :=
|
||||
arm_support += imx6q-sabrelite zynq7000-zc702
|
||||
arm_support += imx6q-sabrelite zynq7000-zc702 ok1028a-c
|
||||
emulator_support +=
|
||||
support := $(riscv_support) $(arm_support) $(emulator_support)
|
||||
SRC_DIR :=
|
||||
@@ -34,6 +34,9 @@ export UBIQUITOUS_ROOT ?= ..
|
||||
ifneq ($(findstring $(BOARD), imx6q-sabrelite zynq7000-zc702), )
|
||||
include $(KERNEL_ROOT)/hardkernel/arch/arm/armv7-a/cortex-a9/preboot_for_$(BOARD)/config.mk
|
||||
endif
|
||||
ifneq ($(findstring $(BOARD), ok1028a-c), )
|
||||
include $(KERNEL_ROOT)/hardkernel/arch/arm/armv8-a/cortex-a72/preboot_for_$(BOARD)/config.mk
|
||||
endif
|
||||
export BSP_BUILD_DIR := $(KERNEL_ROOT)
|
||||
export HOSTTOOLS_DIR ?= $(KERNEL_ROOT)/services/tools/hosttools
|
||||
export CONFIG2H_EXE ?= $(HOSTTOOLS_DIR)/xsconfig.sh
|
||||
@@ -126,6 +129,7 @@ clean:
|
||||
@rm -rf build
|
||||
@rm -rf temp.txt
|
||||
@rm -rf services/app/bin
|
||||
@rm -f services/app/*.o
|
||||
@rm -rf services/tools/mkfs/mkfs
|
||||
@rm -rf services/app/fs.img
|
||||
@rm -rf services/app/user.map
|
||||
|
||||
@@ -1,2 +1,22 @@
|
||||
# XIZI_AIOT
|
||||
### XiZi_AIoT Microkernel
|
||||
|
||||
XiZi_AIoT is a microkernel designed to facilitate task management, memory management, IPC, and various userland sample applications.
|
||||
|
||||
### Building Instructions
|
||||
|
||||
To build the XiZi_AIoT microkernel, navigate to the directory xiuos/Ubiquitous/XiZi_AIoT and run the command `make BOARD=$(BOARD)`. By default, running `make` is equivalent to `make BOARD=imx6q-sabrelite`. For building XiZi_AIoT specifically for the imx6q-sabrelite board, you'll need the gcc-arm-none-eabi toolchain. We recommend using version "arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors 6-2017-q1-update) 6.3.1 20170215 (release)", as this version was used during development. If the build process is successful, the generated files can be found in the "build" directory. Use either XiZi-$(BOARD).elf or XiZi-$(BOARD).bin as the image to run on the board or QEMU.
|
||||
|
||||
### Running on QEMU
|
||||
|
||||
QEMU is a useful tool for emulating boards while testing or developing XiZi_AIoT. Use the following command:
|
||||
|
||||
```
|
||||
qemu-system-arm -M sabrelite -m 1G -smp 4 -cpu cortex-a9 \
|
||||
-display none -serial null -serial stdio \
|
||||
-kernel xiuos/Ubiquitous/XiZi_AIoT/build/XiZi-imx6q-sabrelite.elf
|
||||
```
|
||||
Replace "xiuos/Ubiquitous/XiZi_AIoT/build/XiZi-imx6q-sabrelite.elf" with the appropriate path in your directory. We recommend using version "QEMU emulator version 7.2.0" for successful emulation of the sabrelite board.
|
||||
|
||||
### Makefile Usage
|
||||
|
||||
XiZi_AIoT utilizes a Makefile to build all its files, including .c and .S files. The compiler.mk file enables the make tool to iterate through all sub-directories defined by *SRC_DIR* and compile files defined by *SRC_FILES* using parameters defined in config.mk. Each board independently defines its config.mk file in hardkernel/arch/.../config.mk. Additionally, path_kernel.mk defines all include paths needed by XiZi_AIoT, and link.mk manages the linking process after all .c and .S files are compiled.
|
||||
@@ -1,4 +1,10 @@
|
||||
# The following three platforms support compatiable instructions.
|
||||
ifneq ($(findstring $(BOARD), ok1028a-c), )
|
||||
SRC_DIR := armv8-a
|
||||
endif
|
||||
ifneq ($(findstring $(BOARD), imx6q-sabrelite zynq7000-zc702), )
|
||||
SRC_DIR := armv7-a
|
||||
endif
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
||||
@@ -31,32 +31,14 @@ Modification:
|
||||
|
||||
context_switch:
|
||||
# store original context to stack
|
||||
str lr, [r13, #-4]!
|
||||
str r12, [r13, #-4]!
|
||||
str r11, [r13, #-4]!
|
||||
str r10, [r13, #-4]!
|
||||
str r9, [r13, #-4]!
|
||||
str r8, [r13, #-4]!
|
||||
str r7, [r13, #-4]!
|
||||
str r6, [r13, #-4]!
|
||||
str r5, [r13, #-4]!
|
||||
str r4, [r13, #-4]!
|
||||
stmfd r13!, {r4-r12, lr}
|
||||
|
||||
# switch the stack
|
||||
str r13, [r0] // save current sp to the old PCB (**old)
|
||||
mov r13, r1 // load the next stack
|
||||
|
||||
# restore context from stack
|
||||
ldr r4, [r13], #4
|
||||
ldr r5, [r13], #4
|
||||
ldr r6, [r13], #4
|
||||
ldr r7, [r13], #4
|
||||
ldr r8, [r13], #4
|
||||
ldr r9, [r13], #4
|
||||
ldr r10, [r13], #4
|
||||
ldr r11, [r13], #4
|
||||
ldr r12, [r13], #4
|
||||
ldr lr, [r13], #4
|
||||
ldmfd r13!, {r4-r12, lr}
|
||||
|
||||
# return to the caller
|
||||
bx lr
|
||||
|
||||
@@ -76,7 +76,7 @@ Modification:
|
||||
|
||||
#define NR_CPU 4
|
||||
|
||||
__attribute__((always_inline)) static inline uint32_t user_mode()
|
||||
__attribute__((always_inline, optimize("O0"))) static inline uint32_t user_mode()
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
@@ -92,6 +92,16 @@ __attribute__((always_inline)) static inline uint32_t user_mode()
|
||||
return val;
|
||||
}
|
||||
|
||||
__attribute__((always_inline, optimize("O0"))) static inline void cpu_into_low_power()
|
||||
{
|
||||
WFE();
|
||||
}
|
||||
|
||||
__attribute__((always_inline, optimize("O0"))) static inline void cpu_leave_low_power()
|
||||
{
|
||||
SEV();
|
||||
}
|
||||
|
||||
struct context {
|
||||
uint32_t r4;
|
||||
uint32_t r5;
|
||||
@@ -103,12 +113,12 @@ struct context {
|
||||
uint32_t r11;
|
||||
uint32_t r12;
|
||||
uint32_t lr;
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
/// @brief init task context, set return address to trap return
|
||||
/// @param
|
||||
extern void task_prepare_enter();
|
||||
__attribute__((__always_inline__)) static inline void arch_init_context(struct context* ctx)
|
||||
__attribute__((always_inline, optimize("O0"))) static inline void arch_init_context(struct context* ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->lr = (uint32_t)(task_prepare_enter + 4);
|
||||
@@ -133,13 +143,13 @@ struct trapframe {
|
||||
uint32_t r11;
|
||||
uint32_t r12;
|
||||
uint32_t pc;
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
/// @brief init task trapframe (*especially the user mode cpsr)
|
||||
/// @param tf
|
||||
/// @param sp
|
||||
/// @param pc
|
||||
__attribute__((__always_inline__)) static inline void arch_init_trapframe(struct trapframe* tf, uintptr_t sp, uintptr_t pc)
|
||||
__attribute__((always_inline, optimize("O0"))) static inline void arch_init_trapframe(struct trapframe* tf, uintptr_t sp, uintptr_t pc)
|
||||
{
|
||||
memset(tf, 0, sizeof(*tf));
|
||||
tf->spsr = user_mode();
|
||||
@@ -153,7 +163,7 @@ __attribute__((__always_inline__)) static inline void arch_init_trapframe(struct
|
||||
/// @param tf
|
||||
/// @param sp
|
||||
/// @param pc
|
||||
__attribute__((__always_inline__)) static inline void arch_trapframe_set_sp_pc(struct trapframe* tf, uintptr_t sp, uintptr_t pc)
|
||||
__attribute__((always_inline, optimize("O0"))) static inline void arch_trapframe_set_sp_pc(struct trapframe* tf, uintptr_t sp, uintptr_t pc)
|
||||
{
|
||||
tf->sp_usr = sp;
|
||||
tf->pc = pc;
|
||||
@@ -163,7 +173,7 @@ __attribute__((__always_inline__)) static inline void arch_trapframe_set_sp_pc(s
|
||||
/// @param tf
|
||||
/// @param argc
|
||||
/// @param argv
|
||||
__attribute__((__always_inline__)) static inline void arch_set_main_params(struct trapframe* tf, int argc, uintptr_t argv)
|
||||
__attribute__((always_inline, optimize("O0"))) static inline void arch_set_main_params(struct trapframe* tf, int argc, uintptr_t argv)
|
||||
{
|
||||
tf->r0 = (uint32_t)argc;
|
||||
tf->r1 = (uint32_t)argv;
|
||||
@@ -178,7 +188,7 @@ __attribute__((__always_inline__)) static inline void arch_set_main_params(struc
|
||||
/// @param param5
|
||||
/// @return
|
||||
extern int syscall(int sys_num, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4);
|
||||
__attribute__((__always_inline__)) static inline int arch_syscall(struct trapframe* tf, int* syscall_num)
|
||||
__attribute__((always_inline, optimize("O0"))) static inline int arch_syscall(struct trapframe* tf, int* syscall_num)
|
||||
{
|
||||
// call syscall
|
||||
*syscall_num = tf->r0;
|
||||
@@ -188,7 +198,7 @@ __attribute__((__always_inline__)) static inline int arch_syscall(struct trapfra
|
||||
/// @brief set return reg to trapframe
|
||||
/// @param tf
|
||||
/// @param ret
|
||||
__attribute__((__always_inline__)) static inline void arch_set_return(struct trapframe* tf, int ret)
|
||||
__attribute__((always_inline, optimize("O0"))) static inline void arch_set_return(struct trapframe* tf, int ret)
|
||||
{
|
||||
tf->r0 = (uint32_t)ret;
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ Modification:
|
||||
|
||||
.global _boot_start
|
||||
.global CpuInitCrit
|
||||
.global primary_cpu_init
|
||||
|
||||
.global primary_cpu_init
|
||||
_boot_start:
|
||||
@ save r0 for cores 1-3, r0 arg field passed by ROM
|
||||
@ r0 is a function pointer for secondary cpus
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export CROSS_COMPILE ?= arm-none-eabi-
|
||||
export DEVICE = -march=armv7-a -mtune=cortex-a9 -mfpu=vfpv3-d16 -ftree-vectorize -ffast-math -mfloat-abi=softfp
|
||||
export CFLAGS := $(DEVICE) -Wall -O0 -g -gdwarf-2
|
||||
# export CFLAGS := $(DEVICE) -std=c11 -Wall -O2 -g -gdwarf-2 -Wnull-dereference -Waddress -Warray-bounds -Wchar-subscripts -Wimplicit-int -Wimplicit-function-declaration -Wcomment -Wformat -Wmissing-braces -Wnonnull -Wparentheses -Wpointer-sign -Wreturn-type -Wsequence-point -Wstrict-aliasing -Wstrict-overflow=1 -Wswitch -Wtrigraphs -Wuninitialized -Wunknown-pragmas -Wunused-function -Wunused-label -Wunused-value -Wunused-variable -Wunused-function
|
||||
export CFLAGS := $(DEVICE) -std=c11 -Wall -O2 -g -gdwarf-2 -Waddress -Warray-bounds -Wchar-subscripts -Wimplicit-int -Wimplicit-function-declaration -Wcomment -Wformat -Wmissing-braces -Wnonnull -Wparentheses -Wpointer-sign -Wreturn-type -Wsequence-point -Wstrict-aliasing -Wstrict-overflow=1 -Wswitch -Wtrigraphs -Wuninitialized -Wunknown-pragmas -Wunused-function -Wunused-label -Wunused-value -Wunused-variable -Wunused-function
|
||||
export AFLAGS := -c $(DEVICE) -x assembler-with-cpp -D__ASSEMBLY__ -gdwarf-2
|
||||
# export LFLAGS := $(DEVICE) -Wl,-Map=XiZi-imx6q-sabrelite.map,-cref,-u,_boot_start -T $(KERNEL_ROOT)/hardkernel/arch/arm/armv7-a/cortex-a9/preboot_for_imx6q-sabrelite/nxp_imx6q_sabrelite.lds
|
||||
export LFLAGS := $(DEVICE) --specs=nosys.specs -Wl,-Map=XiZi-imx6q-sabrelite.map,-cref,-u,_boot_start -T $(KERNEL_ROOT)/hardkernel/arch/arm/armv7-a/cortex-a9/preboot_for_imx6q-sabrelite/nxp_imx6q_sabrelite.lds
|
||||
|
||||
@@ -70,10 +70,10 @@ Modification:
|
||||
#define ISB() __asm__ volatile("isb\n\t")
|
||||
|
||||
#define _ARM_MRC(coproc, opcode1, Rt, CRn, CRm, opcode2) \
|
||||
asm volatile("mrc p" #coproc ", " #opcode1 ", %[output], c" #CRn ", c" #CRm ", " #opcode2 "\n" : [output] "=r"(Rt))
|
||||
__asm__ volatile("mrc p" #coproc ", " #opcode1 ", %[output], c" #CRn ", c" #CRm ", " #opcode2 "\n" : [output] "=r"(Rt))
|
||||
|
||||
#define _ARM_MCR(coproc, opcode1, Rt, CRn, CRm, opcode2) \
|
||||
asm volatile("mcr p" #coproc ", " #opcode1 ", %[input], c" #CRn ", c" #CRm ", " #opcode2 "\n" ::[input] "r"(Rt))
|
||||
__asm__ volatile("mcr p" #coproc ", " #opcode1 ", %[input], c" #CRn ", c" #CRm ", " #opcode2 "\n" ::[input] "r"(Rt))
|
||||
|
||||
#define WriteReg(value, address) (*(volatile unsigned int*)(address) = (value))
|
||||
#define ReadReg(address) (*(volatile unsigned int*)(address))
|
||||
|
||||
@@ -56,7 +56,7 @@ typedef unsigned int reg32_t;
|
||||
#endif
|
||||
|
||||
//
|
||||
// Typecast macro for C or asm. In C, the cast is applied, while in asm it is excluded. This is
|
||||
// Typecast macro for C or __asm__. In C, the cast is applied, while in __asm__ it is excluded. This is
|
||||
// used to simplify macro definitions in the module register headers.
|
||||
//
|
||||
#ifndef __REG_VALUE_TYPE
|
||||
|
||||
@@ -18,14 +18,14 @@
|
||||
|
||||
/**
|
||||
* @file soc_memory_map.h
|
||||
* @brief support imx6q soc memory map define, reference from u-boot-2009-08/include/asm-arm/arch-mx6/mx6.h
|
||||
* @brief support imx6q soc memory map define, reference from u-boot-2009-08/include/__asm__-arm/arch-mx6/mx6.h
|
||||
* @version 3.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2023.09.08
|
||||
*/
|
||||
/*************************************************
|
||||
File name: soc_memory_map.h
|
||||
Description: support imx6q soc memory map define, reference from u-boot-2009-08/include/asm-arm/arch-mx6/mx6.h
|
||||
Description: support imx6q soc memory map define, reference from u-boot-2009-08/include/__asm__-arm/arch-mx6/mx6.h
|
||||
Others:
|
||||
History:
|
||||
1. Date: 2023-08-28
|
||||
|
||||
@@ -77,11 +77,15 @@ BOOT_STACK_SIZE = 0x4000;
|
||||
RAM_VECTORS_SIZE = 72;
|
||||
|
||||
/* Specify the memory areas */
|
||||
/*
|
||||
ddr3: physical area: [0x10000000, 0x50000000);
|
||||
virt_ddr3: virt area exclude boot(start_sec), that will be [0x90000000 + 0x11000, 0xD0000000)
|
||||
*/
|
||||
MEMORY
|
||||
{
|
||||
ocram (rwx) : ORIGIN = 0x00900000, LENGTH = 256K
|
||||
ddr3 (rwx) : ORIGIN = 0x10000000, LENGTH = 1024M
|
||||
virt_ddr3 (WRX) : ORIGIN = 0x90011000, LENGTH = 1024M
|
||||
virt_ddr3 (WRX) : ORIGIN = 0x90014000, LENGTH = 1024M
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -154,8 +158,8 @@ SECTIONS
|
||||
PROVIDE(boot_end_addr = .);
|
||||
} > ddr3
|
||||
|
||||
/* Other Kernel code is placed over 0x80000000 + 128KB. */
|
||||
.text : AT(0x10011000) {
|
||||
/* Other Kernel code is placed over 0x10011000(phy) and 0x90011000(virt). */
|
||||
.text : AT(0x10014000) {
|
||||
*(.vectors)
|
||||
. = ALIGN(0x1000);
|
||||
*(.text .text.* .gnu.linkonce.t.*)
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# The following three platforms support compatiable instructions.
|
||||
ifneq ($(findstring $(BOARD), ok1028a-c), )
|
||||
SRC_DIR := cortex-a72
|
||||
endif
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,4 @@
|
||||
SRC_DIR := preboot_for_$(BOARD)
|
||||
SRC_FILES := context_switch.S core.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
/**
|
||||
* @file context_switch.S
|
||||
* @brief task context switch functions
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.4.10
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: context_switch.S
|
||||
Description: task context switch functions
|
||||
Others:
|
||||
History:
|
||||
*************************************************/
|
||||
.global context_switch
|
||||
|
||||
context_switch:
|
||||
|
||||
mov x9, sp
|
||||
mov x10, sp
|
||||
|
||||
sub x9, x9, #16 * 7
|
||||
stp x10/*sp*/, x18, [x9, #16 * 0]
|
||||
stp x19, x20, [x9, #16 * 1]
|
||||
stp x21, x22, [x9, #16 * 2]
|
||||
stp x23, x24, [x9, #16 * 3]
|
||||
stp x25, x26, [x9, #16 * 4]
|
||||
stp x27, x28, [x9, #16 * 5]
|
||||
stp x29, x30, [x9, #16 * 6]
|
||||
|
||||
str x9, [x0]
|
||||
mov x9, x1
|
||||
|
||||
ldp x10/*sp*/, x18, [x9, #16 * 0]
|
||||
ldp x19, x20, [x9, #16 * 1]
|
||||
ldp x21, x22, [x9, #16 * 2]
|
||||
ldp x23, x24, [x9, #16 * 3]
|
||||
ldp x25, x26, [x9, #16 * 4]
|
||||
ldp x27, x28, [x9, #16 * 5]
|
||||
ldp x29, x30, [x9, #16 * 6]
|
||||
add x9, x9, #16 * 7
|
||||
|
||||
mov sp, x9
|
||||
|
||||
ret
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file core.c
|
||||
* @brief spl boot function
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.04.23
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: core.c
|
||||
Description: cortex-a9 core function, include cpu registers operations、core boot
|
||||
Others:
|
||||
History:
|
||||
1. Date: 2024-04-23
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. first version
|
||||
*************************************************/
|
||||
|
||||
/*********cortex-a72 general register************
|
||||
EL0 | EL1 | EL2 | EL3
|
||||
|
||||
x0;
|
||||
x1;
|
||||
x2;
|
||||
x3;
|
||||
x4;
|
||||
x5;
|
||||
x6;
|
||||
x7;
|
||||
x8;
|
||||
x9;
|
||||
x10;
|
||||
x11;
|
||||
x12;
|
||||
x13;
|
||||
x14;
|
||||
x15;
|
||||
x16;
|
||||
x17;
|
||||
x18;
|
||||
x19;
|
||||
x20;
|
||||
x21;
|
||||
x22;
|
||||
x23;
|
||||
x24;
|
||||
x25;
|
||||
x26;
|
||||
x27;
|
||||
x28;
|
||||
x29;
|
||||
x30;
|
||||
*********cortex-a72 special register************
|
||||
XZR
|
||||
PC
|
||||
SP_EL0 SP_EL1 SP_EL2 SP_EL3
|
||||
SPSR_EL1 SPSR_EL2 SPSR_EL3
|
||||
ELR_EL1 ELR_EL2 ELR_EL3
|
||||
************************************************/
|
||||
|
||||
#include "core.h"
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file core.h
|
||||
* @brief cortex-a72 core function
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.04.11
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: core.h
|
||||
Description: cortex-a72 core function
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
*************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Interrupt control bits
|
||||
#define NO_INT 0x80 // disable IRQ.
|
||||
#define DIS_INT 0xc0 // disable both IRQ and FIQ.
|
||||
|
||||
#define MODE_STACK_SIZE 0x1000
|
||||
|
||||
//! @name SPSR fields
|
||||
//@{
|
||||
#define SPSR_EL1_N (1 << 31) //!< Negative
|
||||
#define SPSR_EL1_Z (1 << 30) //!< Zero
|
||||
#define SPSR_EL1_C (1 << 29) //!< Carry
|
||||
#define SPSR_EL1_V (1 << 28) //!< Overflow
|
||||
#define SPSR_EL1_SS (1 << 21) //!< Software Step
|
||||
#define SPSR_EL1_IL (1 << 20) //!< Illegal Exception
|
||||
#define SPSR_EL1_D (1 << 9) //!< Debug mask
|
||||
#define SPSR_EL1_A (1 << 8) //!< SError mask
|
||||
#define SPSR_EL1_I (1 << 7) //!< IRQ mask
|
||||
#define SPSR_EL1_F (1 << 6) //!< FIQ mask
|
||||
#define SPSR_EL1_M (1 << 4) //!< Execution state 0=64-bit 1=32-bit
|
||||
#define SPSR_EL1_MODE (0x7) //!< Current processor mode
|
||||
//@}
|
||||
|
||||
//! @name Interrupt enable bits in SPSR
|
||||
//@{
|
||||
#define I_BIT 0x80 //!< When I bit is set, IRQ is disabled
|
||||
#define F_BIT 0x40 //!< When F bit is set, FIQ is disabled
|
||||
//@}
|
||||
|
||||
// ARM Modes t indicates selecting sp_el0 pointer, h indicates selecting sp_eln pointer
|
||||
#define SPSR_MODE_MASK 0x0f
|
||||
#define ARM_MODE_EL0_t 0x00
|
||||
#define ARM_MODE_EL1_t 0x04
|
||||
#define ARM_MODE_EL1_h 0x05
|
||||
#define ARM_MODE_EL2_t 0x08
|
||||
#define ARM_MODE_EL2_h 0x09
|
||||
#define ARM_MODE_EL3_t 0x0c
|
||||
#define ARM_MODE_EL3_h 0x0d
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cortex_a72.h"
|
||||
|
||||
#define NR_CPU 4 // maximum number of CPUs
|
||||
|
||||
__attribute__((always_inline)) static inline uint64_t EL0_mode() // Set ARM mode to EL0
|
||||
{
|
||||
uint64_t val = 0;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"mrs %0, spsr_el1"
|
||||
: "=r"(val)
|
||||
:
|
||||
:);
|
||||
val &= ~DIS_INT;
|
||||
val &= ~SPSR_MODE_MASK;
|
||||
val |= ARM_MODE_EL0_t;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
__attribute__((always_inline, optimize("O0"))) static inline void cpu_into_low_power()
|
||||
{
|
||||
WFE();
|
||||
}
|
||||
|
||||
__attribute__((always_inline, optimize("O0"))) static inline void cpu_leave_low_power()
|
||||
{
|
||||
SEV();
|
||||
}
|
||||
|
||||
struct context {
|
||||
uint64_t sp;
|
||||
|
||||
/* callee register */
|
||||
uint64_t x18;
|
||||
uint64_t x19;
|
||||
uint64_t x20;
|
||||
uint64_t x21;
|
||||
uint64_t x22;
|
||||
uint64_t x23;
|
||||
uint64_t x24;
|
||||
uint64_t x25;
|
||||
uint64_t x26;
|
||||
uint64_t x27;
|
||||
uint64_t x28;
|
||||
uint64_t x29;
|
||||
uint64_t x30;
|
||||
};
|
||||
|
||||
/// @brief init task context, set return address to trap return
|
||||
/// @param ctx
|
||||
extern void task_prepare_enter(void);
|
||||
__attribute__((__always_inline__)) static inline void arch_init_context(struct context* ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->x30 = (uintptr_t)(task_prepare_enter + 4);
|
||||
}
|
||||
|
||||
struct trapframe {
|
||||
uint64_t x0;
|
||||
uint64_t x1;
|
||||
uint64_t x2;
|
||||
uint64_t x3;
|
||||
uint64_t x4;
|
||||
uint64_t x5;
|
||||
uint64_t x6;
|
||||
uint64_t x7;
|
||||
uint64_t x8;
|
||||
uint64_t x9;
|
||||
uint64_t x10;
|
||||
uint64_t x11;
|
||||
uint64_t x12;
|
||||
uint64_t x13;
|
||||
uint64_t x14;
|
||||
uint64_t x15;
|
||||
uint64_t x16;
|
||||
uint64_t x17;
|
||||
uint64_t x18;
|
||||
uint64_t x19;
|
||||
uint64_t x20;
|
||||
uint64_t x21;
|
||||
uint64_t x22;
|
||||
uint64_t x23;
|
||||
uint64_t x24;
|
||||
uint64_t x25;
|
||||
uint64_t x26;
|
||||
uint64_t x27;
|
||||
uint64_t x28;
|
||||
uint64_t x29;
|
||||
uint64_t x30;
|
||||
uint64_t pc;
|
||||
uint64_t spsr;
|
||||
uint64_t sp;
|
||||
};
|
||||
|
||||
/// @brief init task trapframe
|
||||
/// @param tf
|
||||
/// @param sp
|
||||
/// @param pc
|
||||
__attribute__((__always_inline__)) static inline void arch_init_trapframe(struct trapframe* tf, uintptr_t sp, uintptr_t pc)
|
||||
{
|
||||
memset(tf, 0, sizeof(*tf));
|
||||
tf->sp = sp;
|
||||
tf->spsr = EL0_mode();
|
||||
tf->pc = pc;
|
||||
}
|
||||
|
||||
/// @brief set pc and sp to trapframe
|
||||
/// @param tf
|
||||
/// @param sp
|
||||
/// @param pc
|
||||
__attribute__((__always_inline__)) static inline void arch_trapframe_set_sp_pc(struct trapframe* tf, uintptr_t sp, uintptr_t pc)
|
||||
{
|
||||
tf->sp = sp;
|
||||
tf->pc = pc;
|
||||
}
|
||||
|
||||
/// @brief set params of main(int argc, char** argv) to trapframe (argc, argv)
|
||||
/// @param tf
|
||||
/// @param argc
|
||||
/// @param argv
|
||||
__attribute__((__always_inline__)) static inline void arch_set_main_params(struct trapframe* tf, int argc, uintptr_t argv)
|
||||
{
|
||||
tf->x0 = (uint64_t)argc;
|
||||
tf->x1 = (uint64_t)argv;
|
||||
}
|
||||
|
||||
/// @brief retrieve params to trapframe (up to max number of 6) and pass it to syscall()
|
||||
/// @param sys_num
|
||||
/// @param param1
|
||||
/// @param param2
|
||||
/// @param param3
|
||||
/// @param param4
|
||||
/// @param param5
|
||||
/// @return
|
||||
extern int syscall(int sys_num, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4);
|
||||
__attribute__((__always_inline__)) static inline int arch_syscall(struct trapframe* tf, int* syscall_num)
|
||||
{
|
||||
// call syscall
|
||||
*syscall_num = tf->x0;
|
||||
return syscall(*syscall_num, tf->x1, tf->x2, tf->x3, tf->x4);
|
||||
}
|
||||
|
||||
/// @brief set return reg to trapframe
|
||||
/// @param tf
|
||||
/// @param ret
|
||||
__attribute__((__always_inline__)) static inline void arch_set_return(struct trapframe* tf, int ret)
|
||||
{
|
||||
tf->x0 = (uint64_t)ret;
|
||||
}
|
||||
|
||||
void cpu_start_secondary(uint8_t cpu_id);
|
||||
void start_smp_cache_broadcast(int cpu_id);
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
SRC_FILES := boot.S \
|
||||
smp.c \
|
||||
cortexA72.S
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,81 @@
|
||||
// #include "memlayout.h"
|
||||
#include "core.h"
|
||||
// #include "registers.h"
|
||||
// #include "cortex_a72.h"
|
||||
// qemu -kernel loads the kernel at 0x40000000
|
||||
// and causes each CPU to jump there.
|
||||
// kernel.ld causes the following code to
|
||||
// be placed at 0x40000000.
|
||||
.section ".text"
|
||||
//.global _entry
|
||||
.global _boot_start
|
||||
.global primary_cpu_init
|
||||
|
||||
_boot_start:
|
||||
// set up a stack for C.
|
||||
// stack0 is declared in start.c,
|
||||
// with a 4096-byte stack per CPU.
|
||||
// sp = stack0 + ((cpuid+1) * 4096)
|
||||
// cpuid = mpidr_el1 & 0xff
|
||||
// save r0 for cores 1-3, r0 arg field passed by ROM
|
||||
// r0 is a function pointer for secondary cpus
|
||||
|
||||
// mov x4, x0
|
||||
|
||||
mrs x0, spsr_el1 /* Enter EL1 (Exception Level 1) */
|
||||
bic x0, x0, #0x1f
|
||||
MOV x1, #0xC5
|
||||
ORR x0, x0, x1
|
||||
msr spsr_el1, x0
|
||||
|
||||
|
||||
/* set NSACR, both Secure and Non-secure access are allowed to NEON */
|
||||
MRS X1, CPACR_EL1
|
||||
ORR X1, X1, #(0X3 << 20)
|
||||
MSR CPACR_EL1, X1
|
||||
ISB
|
||||
|
||||
// clear some registers
|
||||
msr elr_el1, XZR
|
||||
|
||||
ldr x0, =stacks_top
|
||||
mov x1, #MODE_STACK_SIZE
|
||||
|
||||
// get cpu id, and subtract the offset from the stacks base address
|
||||
mrs x2, mpidr_el1
|
||||
and x2, x2, #0x3
|
||||
mov x5, x2
|
||||
mul x3, x2, x1
|
||||
sub x0, x0, x3
|
||||
|
||||
MOV X2, #ARM_MODE_EL1_h | DIS_INT
|
||||
MSR SPSR_EL1, X2
|
||||
mov sp, x0
|
||||
SUB x0, x0,x1
|
||||
|
||||
// check cpu id - cpu0 is primary cpu
|
||||
cmp x5, #0
|
||||
beq primary_cpu_init
|
||||
bl bootmain // for secondary cpus, jump to argument function pointer passed in by ROM
|
||||
|
||||
bl .
|
||||
|
||||
primary_cpu_init:
|
||||
/* init .bss */
|
||||
/* clear the .bss section (zero init) */
|
||||
ldr x1, =boot_start_addr
|
||||
ldr x2, =boot_end_addr
|
||||
mov x3, #0
|
||||
1:
|
||||
cmp x1, x2
|
||||
stp x3, x3, [x1], #16
|
||||
b.lt 1b
|
||||
|
||||
// branch to c library entry point
|
||||
mov x0, #0 // argc
|
||||
mov x1, #0 // argv
|
||||
mov x2, #0 // env
|
||||
|
||||
bl bootmain
|
||||
|
||||
.end
|
||||
@@ -0,0 +1,11 @@
|
||||
export CROSS_COMPILE ?= aarch64-none-elf-
|
||||
export DEVICE = -mtune=cortex-a72 -ffreestanding -fno-common -fno-stack-protector -fno-pie -no-pie
|
||||
export CFLAGS := $(DEVICE) -Wall -Werror -O2 -g -fno-omit-frame-pointer -fPIC
|
||||
# export AFLAGS := -c $(DEVICE) -x assembler-with-cpp -D__ASSEMBLY__ -gdwarf-2
|
||||
export LFLAGS := $(DEVICE) -Wl,-T -Wl,$(KERNEL_ROOT)/hardkernel/arch/arm/armv8-a/cortex-a72/preboot_for_ok1028a-c/nxp_ls1028.lds -Wl,--start-group,-lgcc,-lc,--end-group
|
||||
export CXXFLAGS :=
|
||||
|
||||
export DEFINES := -DHAVE_CCONFIG_H -DCHIP_LS1028
|
||||
|
||||
export ARCH = arm
|
||||
export ARCH_ARMV = armv8-a
|
||||
@@ -0,0 +1,37 @@
|
||||
/*!
|
||||
* @file cortexA72.s
|
||||
* @brief This file contains cortexA72 functions
|
||||
*
|
||||
*/
|
||||
/*************************************************
|
||||
File name: cortexA72.S
|
||||
Description: This file contains cortexA9 functions
|
||||
Others:
|
||||
History:
|
||||
1. Date: 202-05-08
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. No modifications
|
||||
*************************************************/
|
||||
.section ".text","ax"
|
||||
|
||||
.global cpu_get_current
|
||||
# int cpu_get_current(void)@
|
||||
# get current CPU ID
|
||||
.func cpu_get_current
|
||||
cpu_get_current:
|
||||
mrs x0, mpidr_el1
|
||||
and x0, x0, #3
|
||||
ret
|
||||
.endfunc
|
||||
|
||||
.global psci_call
|
||||
psci_call:
|
||||
hvc #0
|
||||
ret
|
||||
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# End of cortexA72.s
|
||||
# ------------------------------------------------------------
|
||||
.end
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Freescale Semiconductor, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* o Redistributions of source code must retain the above copyright notice, this list
|
||||
* of conditions and the following disclaimer.
|
||||
*
|
||||
* o Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
* @file cortex_a72.h
|
||||
* @brief some cortex A72 core functions
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.04.24
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: cortex_a72.h
|
||||
Description: some cortex A72 core functions
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. No modifications
|
||||
*************************************************/
|
||||
|
||||
#if !defined(__CORTEX_A72_H__)
|
||||
#define __CORTEX_A72_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//! @name Instruction macros
|
||||
//@{
|
||||
#define NOP() __asm__ volatile("nop\n\t")
|
||||
#define WFI() __asm__ volatile("wfi\n\t")
|
||||
#define WFE() __asm__ volatile("wfe\n\t")
|
||||
#define SEV() __asm__ volatile("sev\n\t")
|
||||
#define DMB() __asm__ volatile("dmb ish\n\t")
|
||||
#define DSB() __asm__ volatile("dsb ish\n\t")
|
||||
#define ISB() __asm__ volatile("isb\n\t")
|
||||
|
||||
#define _ARM_MRS(coproc, opcode1, Rt, CRn, CRm, opcode2) \
|
||||
__asm__ volatile("mrc p" #coproc ", " #opcode1 ", %[output], c" #CRn ", c" #CRm ", " #opcode2 "\n" : [output] "=r"(Rt))
|
||||
|
||||
#define _ARM_MSR(coproc, opcode1, Rt, CRn, CRm, opcode2) \
|
||||
__asm__ volatile("mcr p" #coproc ", " #opcode1 ", %[input], c" #CRn ", c" #CRm ", " #opcode2 "\n" ::[input] "r"(Rt))
|
||||
|
||||
// #define WriteReg(value, address) (*(volatile unsigned int*)(address) = (value))
|
||||
// #define ReadReg(address) (*(volatile unsigned int*)(address))
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//! @name Misc
|
||||
//@{
|
||||
//! @brief Enable or disable the IRQ and FIQ state.
|
||||
bool arm_set_interrupt_state(bool enable);
|
||||
|
||||
//! @brief Get current CPU ID.
|
||||
int cpu_get_current(void);
|
||||
|
||||
//! @brief Enable the NEON MPE.
|
||||
void enable_neon_fpu(void);
|
||||
|
||||
//! @brief Disable aborts on unaligned accesses.
|
||||
void disable_strict_align_check(void);
|
||||
|
||||
//! @brief Get base address of private perpherial space.
|
||||
//!
|
||||
//! @return The address of the ARM CPU's private peripherals.
|
||||
// uint32_t get_arm_private_peripheral_base(void);
|
||||
//@}
|
||||
|
||||
//! @name Data cache operations
|
||||
//@{
|
||||
|
||||
//! @brief Check if dcache is enabled or disabled.
|
||||
int arm_dcache_state_query();
|
||||
|
||||
//! @brief Enables data cache at any available cache level.
|
||||
//!
|
||||
//! Works only if MMU is enabled!
|
||||
void arm_dcache_enable();
|
||||
|
||||
//! @brief Disables the data cache at any available cache level.
|
||||
void arm_dcache_disable();
|
||||
|
||||
//! @brief Invalidates the entire data cache.
|
||||
void arm_dcache_invalidate();
|
||||
|
||||
//! @brief Invalidate a line of data cache.
|
||||
void arm_dcache_invalidate_line(const void* addr);
|
||||
|
||||
//! @brief Invalidate a number of lines of data cache.
|
||||
//!
|
||||
//! Number of lines depends on length parameter and size of line.
|
||||
//! Size of line for A9 L1 cache is 32B.
|
||||
void arm_dcache_invalidate_mlines(const void* addr, size_t length);
|
||||
|
||||
//! @brief Flush (clean) all lines of cache (all sets in all ways).
|
||||
void arm_dcache_flush();
|
||||
|
||||
//! @brief Flush (clean) one line of cache.
|
||||
void arm_dcache_flush_line(const void* addr);
|
||||
|
||||
// @brief Flush (clean) multiple lines of cache.
|
||||
//!
|
||||
//! Number of lines depends on length parameter and size of line.
|
||||
void arm_dcache_flush_mlines(const void* addr, size_t length);
|
||||
//@}
|
||||
|
||||
//! @name Instrution cache operations
|
||||
//@{
|
||||
|
||||
//! @brief Check if icache is enabled or disabled.
|
||||
int arm_icache_state_query();
|
||||
|
||||
//! @brief Enables instruction cache at any available cache level.
|
||||
//!
|
||||
//! Works without enabled MMU too!
|
||||
void arm_icache_enable();
|
||||
|
||||
//! @brief Disables the instruction cache at any available cache level.
|
||||
void arm_icache_disable();
|
||||
|
||||
//! @brief Invalidates the entire instruction cache.
|
||||
void arm_icache_invalidate();
|
||||
|
||||
//! @brief Invalidates the entire instruction cache inner shareable.
|
||||
void arm_icache_invalidate_is();
|
||||
|
||||
//! @brief Invalidate a line of the instruction cache.
|
||||
void arm_icache_invalidate_line(const void* addr);
|
||||
|
||||
//! @brief Invalidate a number of lines of instruction cache.
|
||||
//!
|
||||
//! Number of lines depends on length parameter and size of line.
|
||||
void arm_icache_invalidate_mlines(const void* addr, size_t length);
|
||||
//@}
|
||||
|
||||
//! @name TLB operations
|
||||
//@{
|
||||
//! @brief Invalidate entire unified TLB.
|
||||
void arm_unified_tlb_invalidate(void);
|
||||
|
||||
//! @brief Invalidate entire unified TLB Inner Shareable.
|
||||
void arm_unified_tlb_invalidate_is(void);
|
||||
//@}
|
||||
|
||||
//! @name Branch predictor operations
|
||||
//@{
|
||||
//! @brief Enable branch prediction.
|
||||
void arm_branch_prediction_enable(void);
|
||||
|
||||
//! @brief Disable branch prediction.
|
||||
void arm_branch_prediction_disable(void);
|
||||
|
||||
//! @brief Invalidate entire branch predictor array.
|
||||
void arm_branch_target_cache_invalidate(void);
|
||||
|
||||
//! @brief Invalidate entire branch predictor array Inner Shareable
|
||||
void arm_branch_target_cache_invalidate_is(void);
|
||||
//@}
|
||||
|
||||
//! @name SCU
|
||||
//@{
|
||||
//! @brief Enables the SCU.
|
||||
void scu_enable(void);
|
||||
|
||||
//! @brief Set this CPU as participating in SMP.
|
||||
void scu_join_smp(void);
|
||||
|
||||
//! @brief Set this CPU as not participating in SMP.
|
||||
void scu_leave_smp(void);
|
||||
|
||||
//! @brief Determine which CPUs are participating in SMP.
|
||||
//!
|
||||
//! The return value is 1 bit per core:
|
||||
//! - bit 0 - CPU 0
|
||||
//! - bit 1 - CPU 1
|
||||
//! - etc...
|
||||
unsigned int scu_get_cpus_in_smp(void);
|
||||
|
||||
//! @brief Enable the broadcasting of cache & TLB maintenance operations.
|
||||
//!
|
||||
//! When enabled AND in SMP, broadcast all "inner sharable"
|
||||
//! cache and TLM maintenance operations to other SMP cores
|
||||
void scu_enable_maintenance_broadcast(void);
|
||||
|
||||
//! @brief Disable the broadcasting of cache & TLB maintenance operations.
|
||||
void scu_disable_maintenance_broadcast(void);
|
||||
|
||||
//! @brief Invalidates the SCU copy of the tag rams for the specified core.
|
||||
//!
|
||||
//! Typically only done at start-up.
|
||||
//! Possible flow:
|
||||
//! - Invalidate L1 caches
|
||||
//! - Invalidate SCU copy of TAG RAMs
|
||||
//! - Join SMP
|
||||
//!
|
||||
//! @param cpu 0x0=CPU 0, 0x1=CPU 1, etc...
|
||||
//! @param ways The ways to invalidate. Pass 0xf to invalidate all ways.
|
||||
void scu_secure_invalidate(unsigned int cpu, unsigned int ways);
|
||||
//@}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //__CORTEX_A72_H__
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
#ifndef INC_SYSREGS_H_
|
||||
#define INC_SYSREGS_H_
|
||||
|
||||
/* SCTLR_EL1, System Control Register (EL1). */
|
||||
#define SCTLR_RESERVED \
|
||||
((3 << 28) | (3 << 22) | (1 << 20) | (1 << 11) | (1 << 8) | (1 << 7))
|
||||
#define SCTLR_EE_LITTLE_ENDIAN (0 << 25)
|
||||
#define SCTLR_E0E_LITTLE_ENDIAN (0 << 24)
|
||||
#define SCTLR_I_CACHE (1 << 12)
|
||||
#define SCTLR_D_CACHE (1 << 2)
|
||||
#define SCTLR_MMU_DISABLED (0 << 0)
|
||||
#define SCTLR_MMU_ENABLED (1 << 0)
|
||||
|
||||
#define SCTLR_VALUE_MMU_DISABLED \
|
||||
(SCTLR_RESERVED | SCTLR_EE_LITTLE_ENDIAN | SCTLR_E0E_LITTLE_ENDIAN \
|
||||
| SCTLR_I_CACHE | SCTLR_D_CACHE | SCTLR_MMU_DISABLED)
|
||||
|
||||
/* HCR_EL2, Hypervisor Configuration Register (EL2). */
|
||||
#define HCR_RW (1 << 31)
|
||||
#define HCR_VALUE HCR_RW
|
||||
|
||||
/* CPACR_EL1, Architectural Feature Access Control Register. */
|
||||
#define CPACR_FP_EN (3 << 20)
|
||||
#define CPACR_TRACE_EN (0 << 28)
|
||||
#define CPACR_VALUE (CPACR_FP_EN | CPACR_TRACE_EN)
|
||||
|
||||
/* SCR_EL3, Secure Configuration Register (EL3). */
|
||||
#define SCR_RESERVED (3 << 4)
|
||||
#define SCR_RW (1 << 10)
|
||||
#define SCR_HCE (1 << 8)
|
||||
#define SCR_SMD (1 << 7)
|
||||
#define SCR_NS (1 << 0)
|
||||
#define SCR_VALUE (SCR_RESERVED | SCR_RW | SCR_HCE | SCR_SMD | SCR_NS)
|
||||
|
||||
/* SPSR_EL1/2/3, Saved Program Status Register. */
|
||||
#define SPSR_MASK_ALL (7 << 6)
|
||||
#define SPSR_EL1h (5 << 0)
|
||||
#define SPSR_EL2h (9 << 0)
|
||||
#define SPSR_EL3_VALUE (SPSR_MASK_ALL | SPSR_EL2h)
|
||||
#define SPSR_EL2_VALUE (SPSR_MASK_ALL | SPSR_EL1h)
|
||||
|
||||
/* Exception Class in ESR_EL1. */
|
||||
#define EC_SHIFT 26
|
||||
#define EC_UNKNOWN 0x00
|
||||
#define EC_SVC64 0x15
|
||||
#define EC_DABORT 0x24
|
||||
#define EC_IABORT 0x20
|
||||
|
||||
#define PTE_VALID 1 // level 0,1,2 descriptor: valid
|
||||
#define PTE_TABLE 2 // level 0,1,2 descriptor: table
|
||||
#define PTE_V 3 // level 3 descriptor: valid
|
||||
// PTE_AF(Access Flag)
|
||||
//
|
||||
// 0 -- this block entry has not yet.
|
||||
// 1 -- this block entry has been used.
|
||||
#define PTE_AF (1 << 10)
|
||||
// PTE_AP(Access Permission) is 2bit field.
|
||||
// EL0 EL1
|
||||
// 00 -- x RW
|
||||
// 01 -- RW RW
|
||||
// 10 -- x RO
|
||||
// 11 -- RO RO
|
||||
#define PTE_AP(ap) (((ap) & 3) << 6)
|
||||
#define PTE_U PTE_AP(1)
|
||||
#define PTE_RO PTE_AP(2)
|
||||
#define PTE_URO PTE_AP(3)
|
||||
#define PTE_PXN (1UL << 53) // Privileged eXecute Never
|
||||
#define PTE_UXN (1UL << 54) // Unprivileged(user) eXecute Never
|
||||
#define PTE_XN (PTE_PXN | PTE_UXN) // eXecute Never
|
||||
|
||||
// attribute index
|
||||
// index is set by mair_el1
|
||||
#define AI_DEVICE_nGnRnE_IDX 0x0
|
||||
#define AI_NORMAL_NC_IDX 0x1
|
||||
|
||||
// memory type
|
||||
#define MT_DEVICE_nGnRnE 0x0
|
||||
#define MT_NORMAL_NC 0x44
|
||||
|
||||
#define PTE_INDX(i) (((i) & 7) << 2)
|
||||
#define PTE_DEVICE PTE_INDX(AI_DEVICE_nGnRnE_IDX)
|
||||
#define PTE_NORMAL PTE_INDX(AI_NORMAL_NC_IDX)
|
||||
|
||||
// shift a physical address to the right place for a PTE.
|
||||
#define PA2PTE(pa) ((uint64_t)(pa) & 0xfffffffff000)
|
||||
#define PTE2PA(pte) ((uint64_t)(pte) & 0xfffffffff000)
|
||||
|
||||
#define PTE_FLAGS(pte) ((pte) & (0x600000000003ff))
|
||||
|
||||
// translation control register
|
||||
// #define TCR_T0SZ(n) ((n) & 0x3f)
|
||||
// #define TCR_TG0(n) (((n) & 0x3) << 14)
|
||||
// #define TCR_T1SZ(n) (((n) & 0x3f) << 16)
|
||||
// #define TCR_TG1(n) (((n) & 0x3) << 30)
|
||||
// #define TCR_IPS(n) (((n) & 0x7) << 32)
|
||||
|
||||
#define ISS_MASK 0xFFFFFF
|
||||
|
||||
#endif // INC_SYSREGS_H_
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2012, Freescale Semiconductor, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* o Redistributions of source code must retain the above copyright notice, this list
|
||||
* of conditions and the following disclaimer.
|
||||
*
|
||||
* o Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nxp_ls1028.lds
|
||||
* @brief nxp ls1028 lds function
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.04.10
|
||||
*/
|
||||
BOOT_STACK_SIZE = 0x4000;
|
||||
|
||||
OUTPUT_FORMAT("elf64-littleaarch64")
|
||||
OUTPUT_ARCH( "aarch64" )
|
||||
/**
|
||||
ENTRY( _ENTRY )
|
||||
*/
|
||||
ENTRY( _boot_start )
|
||||
|
||||
MEMORY {
|
||||
phy_ddr3 (rwx) : ORIGIN = 0x0000000040000000, LENGTH = 1024M
|
||||
vir_ddr3 (rwx) : ORIGIN = 0x0000006040635000, LENGTH = 1024M
|
||||
}
|
||||
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.start_sec : {
|
||||
. = ALIGN(0x1000);
|
||||
/* initialization start checkpoint. */
|
||||
|
||||
boot.o(.text)
|
||||
bootmmu.o(.text .text.*)
|
||||
|
||||
boot.o(.rodata .rodata.*)
|
||||
bootmmu.o(.rodata .rodata.*)
|
||||
|
||||
boot.o(.data .data.*)
|
||||
bootmmu.o(.data .data.*)
|
||||
|
||||
PROVIDE(boot_start_addr = .);
|
||||
|
||||
boot.o(.bss .bss.* COMMON)
|
||||
bootmmu.o(.bss .bss.* COMMON)
|
||||
|
||||
/* stack for booting code. */
|
||||
. = ALIGN(0x1000);
|
||||
PROVIDE(stacks_start = .);
|
||||
. += BOOT_STACK_SIZE;
|
||||
PROVIDE(stacks_end = .);
|
||||
PROVIDE(stacks_top = .);
|
||||
|
||||
/* initialization end checkpoint. */
|
||||
PROVIDE(boot_end_addr = .);
|
||||
} > phy_ddr3
|
||||
|
||||
.text : AT(0x40635000) {
|
||||
. = ALIGN(0x1000);
|
||||
*(.text .text.* .gnu.linkonce.t.*)
|
||||
} > vir_ddr3
|
||||
|
||||
. = ALIGN(0x1000);
|
||||
|
||||
.data : {
|
||||
*(.data .data.*)
|
||||
|
||||
. = ALIGN(0x1000);
|
||||
PROVIDE(_binary_fs_img_start = .);
|
||||
*(.rawdata_fs_img*)
|
||||
PROVIDE(_binary_fs_img_end = .);
|
||||
. = ALIGN(0x1000);
|
||||
PROVIDE(_binary_init_start = .);
|
||||
*(.rawdata_init*)
|
||||
PROVIDE(_binary_init_end = .);
|
||||
. = ALIGN(0x1000);
|
||||
PROVIDE(_binary_default_fs_start = .);
|
||||
*(.rawdata_memfs*)
|
||||
PROVIDE(_binary_default_fs_end = .);
|
||||
} > vir_ddr3
|
||||
|
||||
. = ALIGN(0x1000);
|
||||
PROVIDE(kernel_data_begin = .);
|
||||
|
||||
_image_size = . - 0x0000006040000000;
|
||||
.bss : {
|
||||
PROVIDE(__bss_start__ = .);
|
||||
*(.bss .bss.* COMMON)
|
||||
PROVIDE(__bss_end__ = .);
|
||||
} > vir_ddr3
|
||||
. = ALIGN(0x1000);
|
||||
PROVIDE(kernel_data_end = .);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2012, Freescale Semiconductor, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* o Redistributions of source code must retain the above copyright notice, this list
|
||||
* of conditions and the following disclaimer.
|
||||
*
|
||||
* o Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file smp.c
|
||||
* @brief start multicore
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.04.10
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: smp.c
|
||||
Description:
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. No modifications
|
||||
*************************************************/
|
||||
#include <stdint.h>
|
||||
|
||||
#define PSCI_CPUON 0xc4000003
|
||||
|
||||
extern void _boot_start();
|
||||
void psci_call(uint64_t fn, uint8_t cpuid, uint64_t entry, uint64_t ctxid);
|
||||
void cpu_start_secondary(uint8_t cpu_id)
|
||||
{
|
||||
psci_call(PSCI_CPUON, cpu_id, (uintptr_t)&_boot_start, 0);
|
||||
}
|
||||
|
||||
void start_smp_cache_broadcast(int cpu_id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1,3 +1,8 @@
|
||||
ifneq ($(findstring $(BOARD), imx6q-sabrelite zynq7000-zc702), )
|
||||
SRC_DIR := cortex-a9
|
||||
endif
|
||||
ifneq ($(findstring $(BOARD), ok1028a-c), )
|
||||
SRC_DIR := cortex-a72
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
3
Ubiquitous/XiZi_AIoT/hardkernel/cache/L1/arm/cortex-a72/Makefile
vendored
Normal file
3
Ubiquitous/XiZi_AIoT/hardkernel/cache/L1/arm/cortex-a72/Makefile
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
SRC_FILES := l1_cache.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
281
Ubiquitous/XiZi_AIoT/hardkernel/cache/L1/arm/cortex-a72/l1_cache.c
vendored
Normal file
281
Ubiquitous/XiZi_AIoT/hardkernel/cache/L1/arm/cortex-a72/l1_cache.c
vendored
Normal file
@@ -0,0 +1,281 @@
|
||||
/**
|
||||
* @file: l1_cache.c
|
||||
* @brief: the general management of L1 cache
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2024/04/23
|
||||
*
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: l1_cache.c
|
||||
Description: the general management of L1 cache
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. implement the l1 cache operations
|
||||
2. function names are modified to apply softkernel developement
|
||||
3. function implementations are from modifications of imx6 SDK package
|
||||
*************************************************/
|
||||
|
||||
#include "l1_cache.h"
|
||||
|
||||
void InvalidateL1Dcache(uintptr_t start, uintptr_t end)
|
||||
{
|
||||
uint64_t length = end - start;
|
||||
uint64_t addr = start;
|
||||
uint64_t ccsidr_el1;
|
||||
uint64_t line_size;
|
||||
uint64_t va;
|
||||
// get the cache line size
|
||||
|
||||
__asm__ __volatile__("mrs %0, ccsidr_el1" : "=r"(ccsidr_el1));
|
||||
line_size = 1 << ((ccsidr_el1 & 0x7) + 4);
|
||||
|
||||
// align the address with line
|
||||
const uintptr_t end_addr = (const uintptr_t)((uint64_t)addr + length);
|
||||
|
||||
do {
|
||||
va = (uint64_t)((uint64_t)addr & (~(line_size - 1)));
|
||||
|
||||
// Invalidate data cache line to PoC (Point of Coherence) by va.
|
||||
__asm__ __volatile__("dc ivac, %0 " : : "r"(va));
|
||||
|
||||
// increment addres to next line and decrement lenght
|
||||
addr = (uintptr_t)((uint64_t)addr + line_size);
|
||||
} while (addr < end_addr);
|
||||
|
||||
// All Cache, Branch predictor and TLB maintenance operations before followed instruction complete
|
||||
DSB();
|
||||
}
|
||||
|
||||
void InvalidateL1DcacheAll(void)
|
||||
{
|
||||
uint64_t ccsidr_el1; // Cache Size ID
|
||||
int num_sets; // number of sets
|
||||
int num_ways; // number of ways
|
||||
uint32_t wayset; // wayset parameter
|
||||
|
||||
__asm__ __volatile__("mrs %0, ccsidr_el1" : "=r"(ccsidr_el1)); // Read Cache Size ID
|
||||
|
||||
// Fill number of sets and number of ways from ccsidr_el1 register
|
||||
num_sets = ((ccsidr_el1 >> 32) & 0x7FFF) + 1;
|
||||
num_ways = ((ccsidr_el1 >> 0) & 0x7FFF) + 1;
|
||||
|
||||
// Invalidation all lines (all Sets in all ways)
|
||||
for (int way = 0; way < num_ways; way++) {
|
||||
for (int set = 0; set < num_sets; set++) {
|
||||
wayset = (way << 30) | (set << 5);
|
||||
__asm__ __volatile__("dc isw, %0" : : "r"(wayset));
|
||||
}
|
||||
}
|
||||
|
||||
// All Cache, Branch predictor and TLB maintenance operations before followed instruction complete
|
||||
DSB();
|
||||
}
|
||||
|
||||
void CleanL1Dcache(uintptr_t start, uintptr_t end)
|
||||
{
|
||||
void* addr = (void*)start;
|
||||
uintptr_t length = end - start;
|
||||
const void* end_addr = (const void*)((uint64_t)addr + length);
|
||||
uint64_t ccsidr_el1;
|
||||
uint64_t line_size;
|
||||
uint64_t va;
|
||||
|
||||
// get the cache line size
|
||||
__asm__ __volatile__("mrs %0, ccsidr_el1" : "=r"(ccsidr_el1));
|
||||
line_size = 1 << ((ccsidr_el1 & 0x7) + 4);
|
||||
|
||||
do {
|
||||
va = (uint64_t)addr & (~(line_size - 1));
|
||||
// Clean data cache line to PoC (Point of Coherence) by va.
|
||||
__asm__ __volatile__("dc cvac, %0" : : "r"(va));
|
||||
|
||||
// increment addres to next line and decrement lenght
|
||||
addr = (void*)((uint64_t)addr + line_size);
|
||||
} while (addr < end_addr);
|
||||
|
||||
// All Cache, Branch predictor and TLB maintenance operations before followed instruction complete
|
||||
DSB();
|
||||
}
|
||||
|
||||
void CleanL1DcacheAll(void)
|
||||
{
|
||||
uint64_t ccsidr_el1; // Cache Size ID
|
||||
int num_sets; // number of sets
|
||||
int num_ways; // number of ways
|
||||
uint32_t wayset; // wayset parameter
|
||||
|
||||
__asm__ __volatile__("mrs %0, ccsidr_el1" : "=r"(ccsidr_el1)); // Read Cache Size ID
|
||||
|
||||
// Fill number of sets and number of ways from ccsidr_el1 register This walues are decremented by 1
|
||||
num_sets = ((ccsidr_el1 >> 32) & 0x7FFF) + 1;
|
||||
num_ways = ((ccsidr_el1 >> 0) & 0x7FFF) + 1;
|
||||
|
||||
// clean all lines (all Sets in all ways)
|
||||
for (int way = 0; way < num_ways; way++) {
|
||||
for (int set = 0; set < num_sets; set++) {
|
||||
wayset = (way << 30) | (set << 5);
|
||||
__asm__ __volatile__("dc csw, %0" : : "r"(wayset));
|
||||
}
|
||||
}
|
||||
|
||||
// All Cache, Branch predictor and TLB maintenance operations before followed instruction complete
|
||||
DSB();
|
||||
}
|
||||
|
||||
void FlushL1Dcache(uintptr_t start, uintptr_t end)
|
||||
{
|
||||
void* addr = (void*)start;
|
||||
// size_t length=end-start;
|
||||
uint64_t va;
|
||||
uint64_t ccsidr_el1 = 0, line_size = 0;
|
||||
const void* end_addr = (const void*)((uint64_t)end);
|
||||
|
||||
// get the cache line size
|
||||
__asm__ __volatile__("mrs %0, ccsidr_el1" : "=r"(ccsidr_el1));
|
||||
line_size = 1 << ((ccsidr_el1 & 0x7) + 4);
|
||||
|
||||
do {
|
||||
// Clean data cache line to PoC (Point of Coherence) by va.
|
||||
va = (uint64_t)((uint64_t)addr & (~(line_size - 1))); // addr & va_VIRTUAL_ADDRESS_MASK
|
||||
__asm__ __volatile__("dc civac, %0" : : "r"(va));
|
||||
|
||||
// increment addres to next line and decrement lenght
|
||||
addr = (void*)((uint64_t)addr + line_size);
|
||||
} while (addr < end_addr);
|
||||
|
||||
// All Cache, Branch predictor and TLB maintenance operations before followed instruction complete
|
||||
DSB();
|
||||
}
|
||||
|
||||
void FlushL1DcacheAll(void)
|
||||
{
|
||||
uint64_t ccsidr_el1; // Cache Size ID
|
||||
int num_sets; // number of sets
|
||||
int num_ways; // number of ways
|
||||
uint32_t wayset; // wayset parameter
|
||||
|
||||
__asm__ __volatile__("mrs %0, ccsidr_el1" : "=r"(ccsidr_el1)); // Read Cache Size ID
|
||||
|
||||
// Fill number of sets and number of ways from ccsidr_el1 register This walues are decremented by 1
|
||||
num_sets = ((ccsidr_el1 >> 32) & 0x7FFF) + 1;
|
||||
num_ways = ((ccsidr_el1 >> 0) & 0x7FFF) + 1;
|
||||
|
||||
// clean and invalidate all lines (all Sets in all ways)
|
||||
for (int way = 0; way < num_ways; way++) {
|
||||
for (int set = 0; set < num_sets; set++) {
|
||||
wayset = (way << 30) | (set << 5);
|
||||
__asm__ __volatile__("dc cisw, %0" : : "r"(wayset));
|
||||
}
|
||||
}
|
||||
|
||||
// All Cache, Branch predictor and TLB maintenance operations before followed instruction complete
|
||||
DSB();
|
||||
}
|
||||
|
||||
void InvalidateL1IcacheAll()
|
||||
{
|
||||
__asm__ __volatile__("ic iallu\n\t");
|
||||
// synchronize context on this processor
|
||||
ISB();
|
||||
}
|
||||
|
||||
void InvalidateL1Icache(uintptr_t start, uintptr_t end)
|
||||
{
|
||||
// uintptr_t length = end - start;
|
||||
uintptr_t addr = start;
|
||||
uint64_t ccsidr_el1;
|
||||
uint64_t line_size;
|
||||
uint64_t va;
|
||||
const uintptr_t end_addr = (const uintptr_t)((uint64_t)end);
|
||||
// get the cache line size
|
||||
__asm__ __volatile__("mrs %0, ccsidr_el1" : "=r"(ccsidr_el1));
|
||||
line_size = 1 << ((ccsidr_el1 & 0x7) + 4);
|
||||
|
||||
do {
|
||||
va = (uint64_t)((uint64_t)addr & (~(line_size - 1)));
|
||||
|
||||
// Invalidate data cache line to PoC (Point of Coherence) by va.
|
||||
__asm__ __volatile__("ic ivau, %0 " : : "r"(va));
|
||||
// increment addres to next line and decrement lenght
|
||||
addr = (uintptr_t)((uint64_t)addr + line_size);
|
||||
} while (addr < end_addr);
|
||||
|
||||
// synchronize context on this processor
|
||||
ISB();
|
||||
}
|
||||
|
||||
void EnableL1Dcache()
|
||||
{
|
||||
uint64_t sctlr_el1; // System Control Register
|
||||
|
||||
// read sctlr_el1
|
||||
__asm__ __volatile__("mrs %0, sctlr_el1" : "=r"(sctlr_el1));
|
||||
|
||||
if (!(sctlr_el1 & SCTLR_EL1_DCACHE_ENABLE)) {
|
||||
// set C bit (data caching enable)
|
||||
sctlr_el1 |= SCTLR_EL1_DCACHE_ENABLE;
|
||||
|
||||
// write modified sctlr_el1
|
||||
__asm__ __volatile__("msr sctlr_el1, %0" : : "r"(sctlr_el1));
|
||||
|
||||
// data synchronization barrier
|
||||
DSB();
|
||||
}
|
||||
}
|
||||
|
||||
void DisableL1Dcache()
|
||||
{
|
||||
uint64_t sctlr_el1; // System Control Register
|
||||
|
||||
// read sctlr_el1
|
||||
__asm__ __volatile__("mrs %0, sctlr_el1" : "=r"(sctlr_el1));
|
||||
|
||||
// set C bit (data caching enable)
|
||||
sctlr_el1 &= ~SCTLR_EL1_DCACHE_ENABLE;
|
||||
|
||||
// write modified sctlr_el1
|
||||
__asm__ __volatile__("msr sctlr_el1, %0" : "=r"(sctlr_el1));
|
||||
|
||||
// data synchronization barrier
|
||||
DSB();
|
||||
}
|
||||
|
||||
void EnableL1Icache()
|
||||
{
|
||||
uint64_t sctlr_el1; // System Control Register
|
||||
|
||||
// read sctlr_el1
|
||||
__asm__ __volatile__("mrs %0, sctlr_el1" : "=r"(sctlr_el1));
|
||||
|
||||
if (!(sctlr_el1 & SCTLR_EL1_ICACHE_ENABLE)) {
|
||||
// set I bit (data caching enable)
|
||||
sctlr_el1 |= SCTLR_EL1_ICACHE_ENABLE;
|
||||
|
||||
// write modified sctlr_el1
|
||||
__asm__ __volatile__("msr sctlr_el1, %0" : "=r"(sctlr_el1));
|
||||
|
||||
// Instruction synchronization barrier
|
||||
ISB();
|
||||
}
|
||||
}
|
||||
|
||||
void DisableL1Icache()
|
||||
{
|
||||
uint64_t sctlr_el1; // System Control Register
|
||||
|
||||
// read sctlr_el1
|
||||
__asm__ __volatile__("mrs %0, sctlr_el1" : "=r"(sctlr_el1));
|
||||
|
||||
// set I bit (data caching enable)
|
||||
sctlr_el1 &= ~SCTLR_EL1_ICACHE_ENABLE;
|
||||
|
||||
// write modified sctlr_el1
|
||||
__asm__ __volatile__("msr sctlr_el1, %0" : : "r"(sctlr_el1));
|
||||
|
||||
// Instruction synchronization barrier
|
||||
ISB();
|
||||
}
|
||||
76
Ubiquitous/XiZi_AIoT/hardkernel/cache/L1/arm/cortex-a72/l1_cache.h
vendored
Normal file
76
Ubiquitous/XiZi_AIoT/hardkernel/cache/L1/arm/cortex-a72/l1_cache.h
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file: l1_cache.h
|
||||
* @brief: the general management of L1 cache
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2024/4/23
|
||||
*
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: l1_cache.h
|
||||
Description: the general management of L1 cache
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1、define the l1 cache operations
|
||||
*************************************************/
|
||||
#include "core.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* L1 Cache Operation:
|
||||
*
|
||||
* IVAC -Invalidate by Virtual Address, to Point of Coherency AArch32Equivalent :DCIMVAC
|
||||
*
|
||||
* ISW -Invalidate by Set/Way AArch32Equivalent :DCISW
|
||||
*
|
||||
*CVAC -Clean by Virtual Address to Point of Coherency AArch32Equivalent :DCCMVAC
|
||||
*
|
||||
*CSW -Clean by Set/Way AArch32Equivalent :DCCSW
|
||||
*
|
||||
*CVAU -Clean by Virtual Address to Point of Unification AArch32Equivalent :DCCMVAU
|
||||
*
|
||||
*CIVAC -Clean and invalidate data cache line by VA to PoC. AArch32Equivalent :DCCIMVAC
|
||||
*
|
||||
*ISW -Clean and invalidate data cache line by Set/Way. AArch32Equivalent :DCCISW
|
||||
*/
|
||||
|
||||
#define SCTLR_EL1_ICACHE_ENABLE (1 << 12) //!< Instruction cache enable
|
||||
#define SCTLR_EL1_DCACHE_ENABLE (1 << 2) //!< Data cache enable
|
||||
|
||||
void InvalidateL1Dcache(uintptr_t start, uintptr_t end);
|
||||
|
||||
void InvalidateL1DcacheAll(void);
|
||||
|
||||
void CleanL1Dcache(uintptr_t start, uintptr_t end);
|
||||
|
||||
void CleanL1DcacheAll(void);
|
||||
|
||||
void FlushL1Dcache(uintptr_t start, uintptr_t end);
|
||||
|
||||
void FlushL1DcacheAll(void);
|
||||
|
||||
void InvalidateL1IcacheAll(void);
|
||||
|
||||
void InvalidateL1Icache(uintptr_t start, uintptr_t end);
|
||||
|
||||
void EnableL1Icache(void);
|
||||
void DisableL1Icache();
|
||||
|
||||
void EnableL1Dcache();
|
||||
|
||||
void DisableL1Dcache();
|
||||
@@ -1,37 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file: cache_common_ope.c
|
||||
* @brief: the general management of cache
|
||||
* @version: 3.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2023/11/06
|
||||
*
|
||||
*/
|
||||
* @file: cache_common_ope.c
|
||||
* @brief: the general management of cache
|
||||
* @version: 3.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2023/11/06
|
||||
*
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: cache_common_ope.c
|
||||
Description: the general management of cache
|
||||
Others:
|
||||
History:
|
||||
Others:
|
||||
History:
|
||||
1. Date: 2023-11-06
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
Modification:
|
||||
1、implement xiuos cache operations
|
||||
*************************************************/
|
||||
#include "cache_common_ope.h"
|
||||
#include "l1_cache.h"
|
||||
#include "l2_cache.h"
|
||||
// #include "l2_cache.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
@@ -48,7 +48,7 @@ Modification:
|
||||
|
||||
static inline void invalidate_dcache(uintptr_t start, uintptr_t end)
|
||||
{
|
||||
InvalidateL1Dcache(start, end);
|
||||
// InvalidateL1Dcache(start, end);
|
||||
// InvalidateL2Cache(start, end);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ static inline void invalidate_dcache(uintptr_t start, uintptr_t end)
|
||||
|
||||
static inline void invalidate_dcache_all(void)
|
||||
{
|
||||
InvalidateL1DcacheAll();
|
||||
// InvalidateL1DcacheAll();
|
||||
// InvalidateL2CacheAll();
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ static inline void invalidate_dcache_all(void)
|
||||
****************************************************************************/
|
||||
static inline void invalidate_icache(uintptr_t start, uintptr_t end)
|
||||
{
|
||||
InvalidateL1Icache(start, end);
|
||||
// InvalidateL1Icache(start, end);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -92,7 +92,7 @@ static inline void invalidate_icache(uintptr_t start, uintptr_t end)
|
||||
|
||||
static inline void invalidate_icache_all(void)
|
||||
{
|
||||
InvalidateL1IcacheAll();
|
||||
// InvalidateL1IcacheAll();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -106,7 +106,7 @@ static inline void invalidate_icache_all(void)
|
||||
|
||||
static inline void clean_dcache(uintptr_t start, uintptr_t end)
|
||||
{
|
||||
CleanL1Dcache(start, end);
|
||||
// CleanL1Dcache(start, end);
|
||||
// CleanL2Cache(start, end);
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ static inline void clean_dcache(uintptr_t start, uintptr_t end)
|
||||
|
||||
static inline void clean_dcache_all(void)
|
||||
{
|
||||
CleanL1DcacheAll();
|
||||
// CleanL1DcacheAll();
|
||||
// CleanL2CacheAll();
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ static inline void clean_dcache_all(void)
|
||||
static inline void flush_dcache(uintptr_t start, uintptr_t end)
|
||||
{
|
||||
|
||||
FlushL1Dcache(start, end);
|
||||
// FlushL1Dcache(start, end);
|
||||
// FlushL2Cache(start, end);
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ static inline void flush_dcache(uintptr_t start, uintptr_t end)
|
||||
|
||||
static inline void flush_dcache_all(void)
|
||||
{
|
||||
FlushL1DcacheAll();
|
||||
// FlushL1DcacheAll();
|
||||
// FlushL2CacheAll();
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ static inline void flush_dcache_all(void)
|
||||
|
||||
static inline void enable_icache(void)
|
||||
{
|
||||
EnableL1Icache();
|
||||
// EnableL1Icache();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -178,7 +178,7 @@ static inline void enable_icache(void)
|
||||
|
||||
static inline void disable_icache(void)
|
||||
{
|
||||
DisableL1Icache();
|
||||
// DisableL1Icache();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -191,7 +191,7 @@ static inline void disable_icache(void)
|
||||
|
||||
static inline void enable_dcache(void)
|
||||
{
|
||||
EnableL1Dcache();
|
||||
// EnableL1Dcache();
|
||||
// EnableL2Cache();
|
||||
}
|
||||
|
||||
@@ -205,9 +205,9 @@ static inline void enable_dcache(void)
|
||||
|
||||
static inline void disable_dcache(void)
|
||||
{
|
||||
FlushL1DcacheAll();
|
||||
// FlushL1DcacheAll();
|
||||
// pl310_flush_all();
|
||||
DisableL1Dcache();
|
||||
// DisableL1Dcache();
|
||||
// DisableL2Cache();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
SRC_DIR:= arm/armv7-a/cortex-a9/$(BOARD)
|
||||
SRC_DIR:= arm
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
9
Ubiquitous/XiZi_AIoT/hardkernel/clock/arm/Makefile
Normal file
9
Ubiquitous/XiZi_AIoT/hardkernel/clock/arm/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
ifneq ($(findstring $(BOARD), ok1028a-c), )
|
||||
SRC_DIR := armv8-a
|
||||
endif
|
||||
ifneq ($(findstring $(BOARD), imx6q-sabrelite zynq7000-zc702), )
|
||||
SRC_DIR := armv7-a
|
||||
endif
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,6 @@
|
||||
ifneq ($(findstring $(BOARD), imx6q-sabrelite zynq7000-zc702), )
|
||||
SRC_DIR := cortex-a9
|
||||
endif
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,3 @@
|
||||
SRC_DIR := $(BOARD)
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -85,12 +85,13 @@ void ccm_init(void)
|
||||
#endif
|
||||
|
||||
// Ungate clocks that are not enabled in a driver - need to be updated
|
||||
|
||||
HW_CCM_CCGR0_WR(0xffffffff);
|
||||
HW_CCM_CCGR1_WR(0xFFCF0FFF); // EPIT, ESAI, GPT enabled by driver
|
||||
HW_CCM_CCGR2_WR(0xFFFFF03F); // I2C enabled by driver
|
||||
HW_CCM_CCGR3_WR(0xffffffff);
|
||||
HW_CCM_CCGR4_WR(0x00FFFF03); // GPMI, Perfmon enabled by driver
|
||||
HW_CCM_CCGR5_WR(0xF0FFFFCF); // UART, SATA enabled by driver
|
||||
// HW_CCM_CCGR5_WR(0xF0FFFFCF); // UART, SATA enabled by driver
|
||||
HW_CCM_CCGR6_WR(0xffffffff);
|
||||
|
||||
/*
|
||||
|
||||
@@ -39,6 +39,8 @@ Modification:
|
||||
static void _sys_clock_init()
|
||||
{
|
||||
uint32_t freq = get_main_clock(IPG_CLK);
|
||||
|
||||
ccm_init();
|
||||
gpt_init(CLKSRC_IPG_CLK, freq / 1000000, RESTART_MODE, WAIT_MODE_EN | STOP_MODE_EN);
|
||||
gpt_set_compare_event(kGPTOutputCompare1, OUTPUT_CMP_DISABLE, 1000);
|
||||
gpt_counter_enable(kGPTOutputCompare1);
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
ifneq ($(findstring $(BOARD), ok1028a-c), )
|
||||
SRC_DIR := cortex-a72
|
||||
endif
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,3 @@
|
||||
SRC_DIR := $(BOARD)
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,4 @@
|
||||
SRC_FILES := clock.c
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
#include "actracer.h"
|
||||
#include "core.h"
|
||||
#include "generic_timer.h"
|
||||
|
||||
#include "clock_common_op.h"
|
||||
|
||||
// armv8 generic timer driver
|
||||
#define CNTV_CTL_ENABLE (1 << 0)
|
||||
#define CNTV_CTL_IMASK (1 << 1)
|
||||
#define CNTV_CTL_ISTATUS (1 << 2)
|
||||
|
||||
static void enable_timer()
|
||||
{
|
||||
uint32_t c = r_cntv_ctl_el0();
|
||||
c |= CNTV_CTL_ENABLE;
|
||||
c &= ~CNTV_CTL_IMASK;
|
||||
w_cntv_ctl_el0(c);
|
||||
}
|
||||
|
||||
static void disable_timer()
|
||||
{
|
||||
uint32_t c = r_cntv_ctl_el0();
|
||||
c |= CNTV_CTL_IMASK;
|
||||
c &= ~CNTV_CTL_ENABLE;
|
||||
w_cntv_ctl_el0(c);
|
||||
}
|
||||
|
||||
static void reload_timer()
|
||||
{
|
||||
// interval 100ms
|
||||
static uint32_t ms = 10;
|
||||
uint32_t interval = ms * 1000;
|
||||
uint32_t interval_clk = interval * (r_cntfrq_el0() / 1000000);
|
||||
w_cntv_tval_el0(interval_clk);
|
||||
}
|
||||
|
||||
void _sys_clock_init()
|
||||
{
|
||||
disable_timer();
|
||||
reload_timer();
|
||||
enable_timer();
|
||||
}
|
||||
|
||||
static uint32_t _get_clock_int()
|
||||
{
|
||||
return 27;
|
||||
}
|
||||
|
||||
static uint64_t _get_tick()
|
||||
{
|
||||
return r_cntvct_el0();
|
||||
}
|
||||
|
||||
static uint64_t _get_second()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool _is_timer_expired()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void _clear_clock_intr()
|
||||
{
|
||||
disable_timer();
|
||||
reload_timer();
|
||||
enable_timer();
|
||||
}
|
||||
|
||||
static struct XiziClockDriver hardkernel_clock_driver = {
|
||||
.sys_clock_init = _sys_clock_init,
|
||||
.get_clock_int = _get_clock_int,
|
||||
.get_tick = _get_tick,
|
||||
.get_second = _get_second,
|
||||
.is_timer_expired = _is_timer_expired,
|
||||
.clear_clock_intr = _clear_clock_intr,
|
||||
};
|
||||
|
||||
struct XiziClockDriver* hardkernel_clock_init(struct TraceTag* hardkernel_tag)
|
||||
{
|
||||
hardkernel_clock_driver.sys_clock_init();
|
||||
return &hardkernel_clock_driver;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// armv8 generic timer
|
||||
static inline uint32_t r_cntv_ctl_el0()
|
||||
{
|
||||
uint32_t x;
|
||||
__asm__ volatile("mrs %0, cntv_ctl_el0" : "=r"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline void w_cntv_ctl_el0(uint32_t x)
|
||||
{
|
||||
__asm__ volatile("msr cntv_ctl_el0, %0" : : "r"(x));
|
||||
}
|
||||
|
||||
static inline uint32_t r_cntv_tval_el0()
|
||||
{
|
||||
uint32_t x;
|
||||
__asm__ volatile("mrs %0, cntv_tval_el0" : "=r"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline void w_cntv_tval_el0(uint32_t x)
|
||||
{
|
||||
__asm__ volatile("msr cntv_tval_el0, %0" : : "r"(x));
|
||||
}
|
||||
|
||||
static inline uint64_t r_cntvct_el0()
|
||||
{
|
||||
uint64_t x;
|
||||
__asm__ volatile("mrs %0, cntvct_el0" : "=r"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline uint32_t r_cntfrq_el0()
|
||||
{
|
||||
uint32_t x;
|
||||
__asm__ volatile("mrs %0, cntfrq_el0" : "=r"(x));
|
||||
return x;
|
||||
}
|
||||
@@ -37,6 +37,7 @@ Modification:
|
||||
|
||||
#include "assert.h"
|
||||
#include "pagetable.h"
|
||||
#include "spinlock.h"
|
||||
|
||||
#define KERN_BOOT_DRIVER(n, bi, f) \
|
||||
{ \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
SRC_DIR := arm/armv7-a/cortex-a9
|
||||
SRC_DIR := arm
|
||||
SRC_FILES := spinlock.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
9
Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/Makefile
Normal file
9
Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
ifneq ($(findstring $(BOARD), ok1028a-c), )
|
||||
SRC_DIR := armv8-a
|
||||
endif
|
||||
ifneq ($(findstring $(BOARD), imx6q-sabrelite zynq7000-zc702), )
|
||||
SRC_DIR := armv7-a
|
||||
endif
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,6 @@
|
||||
ifneq ($(findstring $(BOARD), imx6q-sabrelite zynq7000-zc702), )
|
||||
SRC_DIR := cortex-a9
|
||||
endif
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -125,20 +125,22 @@ void iabort_reason(struct trapframe* r)
|
||||
void handle_undefined_instruction(struct trapframe* tf)
|
||||
{
|
||||
// unimplemented trap handler
|
||||
xizi_enter_kernel();
|
||||
ERROR("undefined instruction at %x\n", tf->pc);
|
||||
xizi_enter_kernel();
|
||||
panic("");
|
||||
}
|
||||
|
||||
void handle_reserved(void)
|
||||
{
|
||||
// unimplemented trap handler
|
||||
ERROR("Unimplemented Reserved\n");
|
||||
xizi_enter_kernel();
|
||||
panic("Unimplemented Reserved\n");
|
||||
panic("");
|
||||
}
|
||||
|
||||
void handle_fiq(void)
|
||||
{
|
||||
ERROR("Unimplemented FIQ\n");
|
||||
xizi_enter_kernel();
|
||||
panic("Unimplemented FIQ\n");
|
||||
panic("");
|
||||
}
|
||||
@@ -45,6 +45,8 @@ Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. take only gicd part of functions
|
||||
*************************************************/
|
||||
#include "string.h"
|
||||
|
||||
#include "gicv2_common_opa.h"
|
||||
#include "gicv2_registers.h"
|
||||
|
||||
@@ -139,7 +141,7 @@ void gic_send_sgi(uint32_t irqID, uint32_t target_list, uint32_t filter_list)
|
||||
|
||||
void gic_init(void)
|
||||
{
|
||||
gicd_t* gicd = gic_get_gicd();
|
||||
volatile gicd_t* gicd = gic_get_gicd();
|
||||
|
||||
// First disable the distributor.
|
||||
gic_enable(false);
|
||||
@@ -150,7 +152,9 @@ void gic_init(void)
|
||||
|
||||
for (uint32_t i = 0; i < 255; i++) {
|
||||
*(uint32_t*)(&gicd->IPRIORITYRn[i * sizeof(uint32_t)]) = (uint32_t)0x80808080;
|
||||
// memset((void*)&gicd->IPRIORITYRn[i * sizeof(uint32_t)], 0x80, sizeof(uint32_t));
|
||||
*(uint32_t*)(&gicd->ITARGETSRn[i * sizeof(uint32_t)]) = (uint32_t)0x01010101;
|
||||
// memset((void*)&gicd->IPRIORITYRn[i * sizeof(uint32_t)], 0x01, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// Init the GIC CPU interface.
|
||||
|
||||
@@ -89,7 +89,7 @@ static void _sys_irq_init(int cpu_id)
|
||||
gic_init();
|
||||
}
|
||||
/* active hardware irq responser */
|
||||
xizi_trap_driver.switch_hw_irqtbl((uint32_t*)&_vector_jumper);
|
||||
xizi_trap_driver.switch_hw_irqtbl((uintptr_t*)&_vector_jumper);
|
||||
}
|
||||
|
||||
static void _cpu_irq_enable(void)
|
||||
@@ -117,7 +117,7 @@ static void _single_irq_disable(int irq, int cpu)
|
||||
}
|
||||
|
||||
#define VBAR
|
||||
static inline uint32_t* _switch_hw_irqtbl(uint32_t* new_tbl_base)
|
||||
static inline uintptr_t* _switch_hw_irqtbl(uintptr_t* new_tbl_base)
|
||||
{
|
||||
// get old irq table base addr
|
||||
uint32_t old_tbl_base = 0;
|
||||
@@ -132,7 +132,7 @@ static inline uint32_t* _switch_hw_irqtbl(uint32_t* new_tbl_base)
|
||||
sctlr &= ~(1 << 13);
|
||||
_ARM_MCR(15, 0, sctlr, 1, 0, 0);
|
||||
|
||||
return (uint32_t*)old_tbl_base;
|
||||
return (uintptr_t*)old_tbl_base;
|
||||
}
|
||||
|
||||
static void _bind_irq_handler(int irq, irq_handler_t handler)
|
||||
@@ -156,29 +156,11 @@ static uint32_t _hw_cur_int_num(uint32_t int_info)
|
||||
return int_info & 0x1FF;
|
||||
}
|
||||
|
||||
static uint32_t _hw_cur_int_cpu(uint32_t int_info)
|
||||
{
|
||||
return (int_info >> 10) & 0x7;
|
||||
}
|
||||
|
||||
static void _hw_after_irq(uint32_t int_info)
|
||||
{
|
||||
gic_write_end_of_irq(int_info);
|
||||
}
|
||||
|
||||
static int _is_interruptable(void)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"mrs %0, cpsr"
|
||||
: "=r"(val)
|
||||
:
|
||||
:);
|
||||
|
||||
return !(val & DIS_INT);
|
||||
}
|
||||
|
||||
int _cur_cpu_id()
|
||||
{
|
||||
return cpu_get_current();
|
||||
@@ -196,10 +178,8 @@ static struct XiziTrapDriver xizi_trap_driver = {
|
||||
|
||||
.bind_irq_handler = _bind_irq_handler,
|
||||
|
||||
.is_interruptable = _is_interruptable,
|
||||
.hw_before_irq = _hw_before_irq,
|
||||
.hw_cur_int_num = _hw_cur_int_num,
|
||||
.hw_cur_int_cpu = _hw_cur_int_cpu,
|
||||
.hw_after_irq = _hw_after_irq,
|
||||
};
|
||||
|
||||
|
||||
@@ -163,29 +163,11 @@ static uint32_t _hw_cur_int_num(uint32_t int_info)
|
||||
return int_info & XSCUGIC_ACK_INTID_MASK;
|
||||
}
|
||||
|
||||
static uint32_t _hw_cur_int_cpu(uint32_t int_info)
|
||||
{
|
||||
return (int_info >> 5) & 0x3;
|
||||
}
|
||||
|
||||
static void _hw_after_irq(uint32_t int_info)
|
||||
{
|
||||
XScuGic_CPUWriteReg(&IntcInstance, XSCUGIC_EOI_OFFSET, int_info);
|
||||
}
|
||||
|
||||
static int _is_interruptable(void)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"mrs %0, cpsr"
|
||||
: "=r"(val)
|
||||
:
|
||||
:);
|
||||
|
||||
return !(val & DIS_INT);
|
||||
}
|
||||
|
||||
int _cur_cpu_id()
|
||||
{
|
||||
return cpu_get_current();
|
||||
@@ -203,10 +185,8 @@ static struct XiziTrapDriver xizi_trap_driver = {
|
||||
|
||||
.bind_irq_handler = _bind_irq_handler,
|
||||
|
||||
.is_interruptable = _is_interruptable,
|
||||
.hw_before_irq = _hw_before_irq,
|
||||
.hw_cur_int_num = _hw_cur_int_num,
|
||||
.hw_cur_int_cpu = _hw_cur_int_cpu,
|
||||
.hw_after_irq = _hw_after_irq,
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
SRC_DIR := cortex-a72
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,9 @@
|
||||
SRC_FILES := trampoline.S $(BOARD)/trap_common.c $(BOARD)/trap.c error_debug.c hard_spinlock.S
|
||||
|
||||
ifeq ($(BOARD), ok1028a-c)
|
||||
SRC_DIR := gicv3
|
||||
SRC_FILES += $(BOARD)/
|
||||
endif
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,167 @@
|
||||
/* Copyright (c) 2006-2018 Frans Kaashoek, Robert Morris, Russ Cox,
|
||||
* Massachusetts Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* @file error_debug.c
|
||||
* @brief handle program abort
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.4.25
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: error_debug.c
|
||||
Description: handle program abort
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. Take only armv8 abort reason part(_abort_reason).
|
||||
2. Modify iabort and dabort handler(in dabort_handler() and iabort_handler())
|
||||
*************************************************/
|
||||
#include <stddef.h>
|
||||
|
||||
#include "assert.h"
|
||||
#include "core.h"
|
||||
#include "log.h"
|
||||
#include "multicores.h"
|
||||
#include "spinlock.h"
|
||||
#include "task.h"
|
||||
#include "trap_common.h"
|
||||
|
||||
void dump_tf(struct trapframe* tf)
|
||||
{
|
||||
KPrintf(" sp: 0x%x\n", tf->sp);
|
||||
KPrintf(" pc: 0x%x\n", tf->pc);
|
||||
KPrintf(" spsr: 0x%x\n", tf->spsr);
|
||||
KPrintf(" x0: 0x%x\n", tf->x0);
|
||||
KPrintf(" x1: 0x%x\n", tf->x1);
|
||||
KPrintf(" x2: 0x%x\n", tf->x2);
|
||||
KPrintf(" x3: 0x%x\n", tf->x3);
|
||||
KPrintf(" x4: 0x%x\n", tf->x4);
|
||||
KPrintf(" x5: 0x%x\n", tf->x5);
|
||||
KPrintf(" x6: 0x%x\n", tf->x6);
|
||||
KPrintf(" x7: 0x%x\n", tf->x7);
|
||||
KPrintf(" x8: 0x%x\n", tf->x8);
|
||||
KPrintf(" x9: 0x%x\n", tf->x9);
|
||||
KPrintf(" x10: 0x%x\n", tf->x10);
|
||||
KPrintf(" x11: 0x%x\n", tf->x11);
|
||||
KPrintf(" x12: 0x%x\n", tf->x12);
|
||||
KPrintf(" x13: 0x%x\n", tf->x13);
|
||||
KPrintf(" x14: 0x%x\n", tf->x14);
|
||||
KPrintf(" x15: 0x%x\n", tf->x15);
|
||||
KPrintf(" x16: 0x%x\n", tf->x16);
|
||||
KPrintf(" x17: 0x%x\n", tf->x17);
|
||||
KPrintf(" x18: 0x%x\n", tf->x18);
|
||||
KPrintf(" x19: 0x%x\n", tf->x19);
|
||||
KPrintf(" x20: 0x%x\n", tf->x20);
|
||||
KPrintf(" x21: 0x%x\n", tf->x21);
|
||||
KPrintf(" x22: 0x%x\n", tf->x22);
|
||||
KPrintf(" x23: 0x%x\n", tf->x23);
|
||||
KPrintf(" x24: 0x%x\n", tf->x24);
|
||||
KPrintf(" x25: 0x%x\n", tf->x25);
|
||||
KPrintf(" x26: 0x%x\n", tf->x26);
|
||||
KPrintf(" x27: 0x%x\n", tf->x27);
|
||||
KPrintf(" x28: 0x%x\n", tf->x28);
|
||||
KPrintf(" x29: 0x%x\n", tf->x29);
|
||||
KPrintf(" x30: 0x%x\n", tf->x30);
|
||||
}
|
||||
|
||||
void dabort_reason(struct trapframe* r)
|
||||
{
|
||||
uint32_t fault_status, fault_address;
|
||||
__asm__ __volatile__("mrs %0, esr_el1" : "=r"(fault_status));
|
||||
__asm__ __volatile__("mrs %0, far_el1" : "=r"(fault_address));
|
||||
LOG("program counter: 0x%x caused\n", r->pc);
|
||||
LOG("data abort at 0x%x, status 0x%x\n", fault_address, fault_status);
|
||||
if ((fault_status & 0x3f) == 0x21) // Alignment failure
|
||||
KPrintf("reason: alignment\n");
|
||||
else if ((fault_status & 0x3f) == 0x4) // Translation fault, level 0
|
||||
KPrintf("reason: sect. translation level 0\n");
|
||||
else if ((fault_status & 0x3f) == 0x5) // Translation fault, level 1
|
||||
KPrintf("reason: sect. translation level 1\n");
|
||||
else if ((fault_status & 0x3f) == 0x6) // Translation fault, level 2
|
||||
KPrintf("reason: sect. translation level 2\n");
|
||||
else if ((fault_status & 0x3f) == 0x7) // Translation fault, level 3
|
||||
KPrintf("reason: sect. translation level 3\n");
|
||||
else if ((fault_status & 0x3f) == 0x3d) // Section Domain fault
|
||||
KPrintf("reason: sect. domain\n");
|
||||
else if ((fault_status & 0x3f) == 0xd) // Permission level 1
|
||||
KPrintf("reason: sect. permission level 1\n");
|
||||
else if ((fault_status & 0x3f) == 0xe) // Permission level 2
|
||||
KPrintf("reason: sect. permission level 2\n");
|
||||
else if ((fault_status & 0x3f) == 0xf) // Permission level 3
|
||||
KPrintf("reason: sect. permission level 3\n");
|
||||
else if ((fault_status & 0x3f) == 0x14) // External abort
|
||||
KPrintf("reason: ext. abort\n");
|
||||
else if ((fault_status & 0x3f) == 0x9) // Access flag fault, level 1
|
||||
KPrintf("reason: sect. Access flag fault level 1\n");
|
||||
else if ((fault_status & 0x3f) == 0xa) // Access flag fault, level 2
|
||||
KPrintf("reason: sect. Access flag fault level 2\n");
|
||||
else if ((fault_status & 0x3f) == 0xb) // Access flag fault, level 3
|
||||
KPrintf("reason: sect. Access flag fault level 3\n");
|
||||
else
|
||||
KPrintf("reason: unknown???\n");
|
||||
|
||||
dump_tf(r);
|
||||
return;
|
||||
}
|
||||
|
||||
void iabort_reason(struct trapframe* r)
|
||||
{
|
||||
uint32_t fault_status, fault_address;
|
||||
__asm__ __volatile__("mrs %0, esr_el1" : "=r"(fault_status));
|
||||
__asm__ __volatile__("mrs %0, far_el1" : "=r"(fault_address));
|
||||
LOG("program counter: 0x%x caused\n", r->pc);
|
||||
LOG("data abort at 0x%x, status 0x%x\n", fault_address, fault_status);
|
||||
if ((fault_status & 0x3f) == 0x21) // Alignment failure
|
||||
KPrintf("reason: alignment\n");
|
||||
else if ((fault_status & 0x3f) == 0x4) // Translation fault, level 0
|
||||
KPrintf("reason: sect. translation level 0\n");
|
||||
else if ((fault_status & 0x3f) == 0x5) // Translation fault, level 1
|
||||
KPrintf("reason: sect. translation level 1\n");
|
||||
else if ((fault_status & 0x3f) == 0x6) // Translation fault, level 2
|
||||
KPrintf("reason: sect. translation level 2\n");
|
||||
else if ((fault_status & 0x3f) == 0x7) // Translation fault, level 3
|
||||
KPrintf("reason: sect. translation level 3\n");
|
||||
else if ((fault_status & 0x3f) == 0x3d) // Section Domain fault
|
||||
KPrintf("reason: sect. domain\n");
|
||||
else if ((fault_status & 0x3f) == 0xd) // Permission level 1
|
||||
KPrintf("reason: sect. permission level 1\n");
|
||||
else if ((fault_status & 0x3f) == 0xe) // Permission level 2
|
||||
KPrintf("reason: sect. permission level 2\n");
|
||||
else if ((fault_status & 0x3f) == 0xf) // Permission level 3
|
||||
KPrintf("reason: sect. permission level 3\n");
|
||||
else if ((fault_status & 0x3f) == 0x14) // External abort
|
||||
KPrintf("reason: ext. abort\n");
|
||||
else if ((fault_status & 0x3f) == 0x9) // Access flag fault, level 1
|
||||
KPrintf("reason: sect. Access flag fault level 1\n");
|
||||
else if ((fault_status & 0x3f) == 0xa) // Access flag fault, level 2
|
||||
KPrintf("reason: sect. Access flag fault level 2\n");
|
||||
else if ((fault_status & 0x3f) == 0xb) // Access flag fault, level 3
|
||||
KPrintf("reason: sect. Access flag fault level 3\n");
|
||||
else
|
||||
KPrintf("reason: unknown???\n");
|
||||
|
||||
dump_tf(r);
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
SRC_FILES := gicv3.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
/**
|
||||
* @file gicv3.c
|
||||
* @brief gicv3 operation
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.05.10
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: gicv3.c
|
||||
Description: gicv3 operation
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
*************************************************/
|
||||
#include <string.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "gicv3_common_opa.h"
|
||||
#include "gicv3_registers.h"
|
||||
|
||||
static struct {
|
||||
char* gicd;
|
||||
char* rdist_addrs[NR_CPU];
|
||||
} gicv3;
|
||||
|
||||
static inline uint32_t icc_igrpen1_el1()
|
||||
{
|
||||
uint32_t x;
|
||||
__asm__ volatile("mrs %0, S3_0_C12_C12_7" : "=r"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline void w_icc_igrpen1_el1(uint32_t x)
|
||||
{
|
||||
__asm__ volatile("msr S3_0_C12_C12_7, %0" : : "r"(x));
|
||||
}
|
||||
|
||||
static inline uint32_t icc_pmr_el1()
|
||||
{
|
||||
uint32_t x;
|
||||
__asm__ volatile("mrs %0, S3_0_C4_C6_0" : "=r"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline void w_icc_pmr_el1(uint32_t x)
|
||||
{
|
||||
__asm__ volatile("msr S3_0_C4_C6_0, %0" : : "r"(x));
|
||||
}
|
||||
|
||||
inline uint32_t gic_read_irq_ack()
|
||||
{
|
||||
uint32_t x;
|
||||
__asm__ volatile("mrs %0, S3_0_C12_C12_0" : "=r"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
inline void
|
||||
gic_write_end_of_irq(uint32_t x)
|
||||
{
|
||||
__asm__ volatile("msr S3_0_C12_C12_1, %0" : : "r"(x));
|
||||
}
|
||||
|
||||
static inline uint32_t icc_sre_el1()
|
||||
{
|
||||
uint32_t x;
|
||||
__asm__ volatile("mrs %0, S3_0_C12_C12_5" : "=r"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline void w_icc_sre_el1(uint32_t x)
|
||||
{
|
||||
__asm__ volatile("msr S3_0_C12_C12_5, %0" : : "r"(x));
|
||||
}
|
||||
|
||||
static void gicd_write(uint32_t off, uint32_t val)
|
||||
{
|
||||
*(volatile uint32_t*)(gicv3.gicd + off) = val;
|
||||
}
|
||||
|
||||
static uint32_t gicd_read(uint32_t off)
|
||||
{
|
||||
return *(volatile uint32_t*)(gicv3.gicd + off);
|
||||
}
|
||||
|
||||
static void gicr_write(uint32_t cpuid, uint32_t off, uint32_t val)
|
||||
{
|
||||
*(volatile uint32_t*)(gicv3.rdist_addrs[cpuid] + off) = val;
|
||||
}
|
||||
|
||||
static uint32_t gicr_read(uint32_t cpuid, uint32_t off)
|
||||
{
|
||||
return *(volatile uint32_t*)(gicv3.rdist_addrs[cpuid] + off);
|
||||
}
|
||||
|
||||
static void giccinit()
|
||||
{
|
||||
w_icc_igrpen1_el1(0);
|
||||
w_icc_pmr_el1(0xff);
|
||||
}
|
||||
|
||||
static void gicdinit()
|
||||
{
|
||||
gicd_write(D_CTLR, 0);
|
||||
|
||||
uint32_t typer = gicd_read(D_TYPER);
|
||||
uint32_t lines = typer & 0x1f;
|
||||
|
||||
for (int i = 0; i < lines; i++)
|
||||
gicd_write(D_IGROUPR(i), ~0);
|
||||
}
|
||||
|
||||
static void gicrinit(uint32_t cpuid)
|
||||
{
|
||||
gicr_write(cpuid, R_CTLR, 0);
|
||||
|
||||
w_icc_sre_el1(icc_sre_el1() | 1);
|
||||
|
||||
gicr_write(cpuid, R_IGROUPR0, ~0);
|
||||
gicr_write(cpuid, R_IGRPMODR0, 0);
|
||||
|
||||
uint32_t waker = gicr_read(cpuid, R_WAKER);
|
||||
gicr_write(cpuid, R_WAKER, waker & ~(1 << 1));
|
||||
while (gicr_read(cpuid, R_WAKER) & (1 << 2))
|
||||
;
|
||||
}
|
||||
|
||||
void gic_enable()
|
||||
{
|
||||
gicd_write(D_CTLR, (1 << 1));
|
||||
w_icc_igrpen1_el1(1);
|
||||
}
|
||||
|
||||
void gic_init()
|
||||
{
|
||||
gicv3.gicd = (char*)GICV3;
|
||||
for (int i = 0; i < NR_CPU; i++) {
|
||||
gicv3.rdist_addrs[i] = (char*)(GICV3_REDIST + (i) * 0x20000);
|
||||
}
|
||||
|
||||
gicdinit();
|
||||
}
|
||||
|
||||
void gicv3inithart(uint32_t cpu_id)
|
||||
{
|
||||
giccinit();
|
||||
gicrinit(cpu_id);
|
||||
|
||||
gic_enable();
|
||||
}
|
||||
|
||||
static void
|
||||
gic_enable_int(uint32_t intid)
|
||||
{
|
||||
uint32_t is = gicd_read(D_ISENABLER(intid / 32));
|
||||
is |= 1 << (intid % 32);
|
||||
gicd_write(D_ISENABLER(intid / 32), is);
|
||||
}
|
||||
|
||||
int gic_int_enabled(uint32_t intid)
|
||||
{
|
||||
uint32_t is = gicd_read(D_ISENABLER(intid / 32));
|
||||
return is & (1 << (intid % 32));
|
||||
}
|
||||
|
||||
static void
|
||||
gic_clear_pending(uint32_t intid)
|
||||
{
|
||||
uint32_t ic = gicd_read(D_ICPENDR(intid / 32));
|
||||
ic |= 1 << (intid % 32);
|
||||
gicd_write(D_ICPENDR(intid / 32), ic);
|
||||
}
|
||||
|
||||
static void
|
||||
gic_set_prio0(uint32_t intid)
|
||||
{
|
||||
// set priority to 0
|
||||
uint32_t p = gicd_read(D_IPRIORITYR(intid / 4));
|
||||
p &= ~((uint32_t)0xff << (intid % 4 * 8)); // set prio 0
|
||||
gicd_write(D_IPRIORITYR(intid / 4), p);
|
||||
}
|
||||
|
||||
static void gic_set_target(uint32_t intid, uint32_t cpuid)
|
||||
{
|
||||
uint32_t itargetsr = gicd_read(D_ITARGETSR(intid / 4));
|
||||
itargetsr &= ~((uint32_t)0xff << (intid % 4 * 8));
|
||||
gicd_write(D_ITARGETSR(intid / 4), itargetsr | ((uint32_t)(1 << cpuid) << (intid % 4 * 8)));
|
||||
}
|
||||
|
||||
static void
|
||||
gicr_enable_int(uint32_t cpuid, uint32_t intid)
|
||||
{
|
||||
uint32_t is = gicr_read(cpuid, R_ISENABLER0);
|
||||
is |= 1 << (intid % 32);
|
||||
gicr_write(cpuid, R_ISENABLER0, is);
|
||||
}
|
||||
|
||||
static void
|
||||
gicr_clear_pending(uint32_t cpuid, uint32_t intid)
|
||||
{
|
||||
uint32_t ic = gicr_read(cpuid, R_ICPENDR0);
|
||||
ic |= 1 << (intid % 32);
|
||||
gicr_write(cpuid, R_ICPENDR0, ic);
|
||||
}
|
||||
|
||||
static void
|
||||
gicr_set_prio0(uint32_t cpuid, uint32_t intid)
|
||||
{
|
||||
uint32_t p = gicr_read(cpuid, R_IPRIORITYR(intid / 4));
|
||||
p &= ~((uint32_t)0xff << (intid % 4 * 8)); // set prio 0
|
||||
gicr_write(cpuid, R_IPRIORITYR(intid / 4), p);
|
||||
}
|
||||
|
||||
void gic_setup_ppi(uint32_t cpuid, uint32_t intid)
|
||||
{
|
||||
gicr_set_prio0(cpuid, intid);
|
||||
gicr_clear_pending(cpuid, intid);
|
||||
gicr_enable_int(cpuid, intid);
|
||||
}
|
||||
|
||||
void gic_setup_spi(uint32_t cpuid, uint32_t intid)
|
||||
{
|
||||
gic_set_prio0(intid);
|
||||
gic_set_target(intid, cpuid);
|
||||
gic_clear_pending(intid);
|
||||
gic_enable_int(intid);
|
||||
}
|
||||
|
||||
// irq from iar
|
||||
int gic_iar_irq(uint32_t iar)
|
||||
{
|
||||
return iar & 0x3ff;
|
||||
}
|
||||
|
||||
// interrupt acknowledge register:
|
||||
// ask GIC what interrupt we should serve.
|
||||
uint32_t gic_iar()
|
||||
{
|
||||
return gic_read_irq_ack();
|
||||
}
|
||||
|
||||
// tell GIC we've served this IRQ.
|
||||
void gic_eoi(uint32_t iar)
|
||||
{
|
||||
gic_write_end_of_irq(iar);
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
/**
|
||||
* @file gicv3_common_opa.h
|
||||
* @brief gicv3 operation
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.05.07
|
||||
*/
|
||||
/*************************************************
|
||||
File name: gicv3_common_opa.h
|
||||
Description: gicv3 operation
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. Rename file
|
||||
*************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <mmio_access.h>
|
||||
|
||||
//! @name Initialization
|
||||
//@{
|
||||
//! @brief Init interrupt handling.
|
||||
//!
|
||||
//! This function is intended to be called only by the primary CPU init code, so it will
|
||||
//! only be called once during system bootup.
|
||||
//!
|
||||
//! Also inits the current CPU. You don't need to call gic_init_cpu() separately.
|
||||
//!
|
||||
//! @post The interrupt distributor and the current CPU interface are enabled. All interrupts
|
||||
//! that were pending are cleared, and all interrupts are made secure (group 0).
|
||||
void gic_init(void);
|
||||
|
||||
//! @name GIC Interrupt Distributor Functions
|
||||
//@{
|
||||
//! @brief Enable or disable the GIC Distributor.
|
||||
//!
|
||||
//! Enables or disables the GIC distributor passing both secure (group 0) and non-secure
|
||||
//! (group 1) interrupts to the CPU interfaces.
|
||||
//!
|
||||
//! @param enableIt Pass true to enable or false to disable.
|
||||
void gic_enable();
|
||||
|
||||
//! @brief Set the security mode for an interrupt.
|
||||
//!
|
||||
//! @param irqID The interrupt number.
|
||||
//! @param isSecure Whether the interrupt is taken to secure mode.
|
||||
void gic_set_irq_security(uint32_t irqID, bool isSecure);
|
||||
|
||||
//! @brief Enable or disable an interrupt.
|
||||
//!
|
||||
//! @param irqID The number of the interrupt to control.
|
||||
//! @param isEnabled Pass true to enable or false to disable.
|
||||
void gic_enable_irq(uint32_t irqID, bool isEnabled);
|
||||
|
||||
//! @brief Set whether a CPU will receive a particular interrupt.
|
||||
//!
|
||||
//! @param irqID The interrupt number.
|
||||
//! @param cpuNumber The CPU number. The first CPU core is 0.
|
||||
//! @param enableIt Whether to send the interrupt to the specified CPU. Pass true to enable
|
||||
//! or false to disable.
|
||||
void gic_set_cpu_target(uint32_t irqID, unsigned cpuNumber, bool enableIt);
|
||||
|
||||
//! @brief Set an interrupt's priority.
|
||||
//!
|
||||
//! @param irq_id The interrupt number.
|
||||
//! @param priority The priority for the interrupt. In the range of 0 through 0xff, with
|
||||
//! 0 being the highest priority.
|
||||
void gic_set_irq_priority(uint32_t irq_id, uint32_t priority);
|
||||
|
||||
void gic_setup_spi(uint32_t cpuid, uint32_t intid);
|
||||
void gic_setup_ppi(uint32_t cpuid, uint32_t intid);
|
||||
|
||||
void gicv3inithart(uint32_t cpu_id);
|
||||
//! @brief Send a software generated interrupt to a specific CPU.
|
||||
//!
|
||||
//! @param irq_id The interrupt number to send.
|
||||
//! @param target_list Each bit indicates a CPU to which the interrupt will be forwarded.
|
||||
//! Bit 0 is CPU 0, bit 1 is CPU 1, and so on. If the value is 0, then the interrupt
|
||||
//! will not be forwarded to any CPUs. This parameter is only used if @a filter_list
|
||||
//! is set to #kGicSgiFilter_UseTargetList.
|
||||
//! @param filter_list One of the enums of the #_gicd_sgi_filter enumeration. The selected
|
||||
//! option determines which CPUs the interrupt will be sent to. If the value
|
||||
//! is #kGicSgiFilter_UseTargetList, then the @a target_list parameter is used.
|
||||
void gic_send_sgi(uint32_t irq_id, uint32_t target_list, uint32_t filter_list);
|
||||
//@}
|
||||
|
||||
//! @name GIC CPU Interface Functions
|
||||
//@{
|
||||
//! @brief Enable or disable the interface to the GIC for the current CPU.
|
||||
//!
|
||||
//! @param enableIt Pass true to enable or false to disable.
|
||||
void gic_cpu_enable(bool enableIt);
|
||||
|
||||
//! @brief Set the mask of which interrupt priorities the CPU will receive.
|
||||
//!
|
||||
//! @param priority The lowest priority that will be passed to the current CPU. Pass 0xff to
|
||||
//! allow all priority interrupts to signal the CPU.
|
||||
void gic_set_cpu_priority_mask(uint32_t priority);
|
||||
|
||||
//! @brief Acknowledge starting of interrupt handling and get the interrupt number.
|
||||
//!
|
||||
//! Normally, this function is called at the beginning of the IRQ handler. It tells the GIC
|
||||
//! that you are starting to handle an interupt, and returns the number of the interrupt you
|
||||
//! need to handle. After the interrupt is handled, you should call gic_write_end_of_irq()
|
||||
//! to signal that the interrupt is completely handled.
|
||||
//!
|
||||
//! In some cases, a spurious interrupt might happen. One possibility is if another CPU handles
|
||||
//! the interrupt. When a spurious interrupt occurs, the end of the interrupt should be indicated
|
||||
//! but nothing else.
|
||||
//!
|
||||
//! @return The number for the highest priority interrupt available for the calling CPU. If
|
||||
//! the return value is 1022 or 1023, a spurious interrupt has occurred.
|
||||
uint32_t gic_read_irq_ack(void);
|
||||
|
||||
//! @brief Signal the end of handling an interrupt.
|
||||
//!
|
||||
//! @param irq_id The number of the interrupt for which handling has finished.
|
||||
void gic_write_end_of_irq(uint32_t irq_id);
|
||||
//@}
|
||||
|
||||
//! @}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// EOF
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2002 ARM Limited, All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
/**
|
||||
* @file gicv3_registers.h
|
||||
* @brief gicv3 registers
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.05.09
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: gicv3_registers.c
|
||||
Description: gicv3 registers
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. Rename the file
|
||||
*************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "memlayout.h"
|
||||
|
||||
// clang-format off
|
||||
// interrupt controller GICv3
|
||||
#define GICV3 MMIO_P2V_WO(0x08000000ULL)
|
||||
#define GICV3_REDIST MMIO_P2V_WO(0x080a0000ULL)
|
||||
|
||||
#define D_CTLR 0x0
|
||||
#define D_TYPER 0x4
|
||||
#define D_IGROUPR(n) (0x80 + (uint64_t)(n) * 4)
|
||||
#define D_ISENABLER(n) (0x100 + (uint64_t)(n) * 4)
|
||||
#define D_ICENABLER(n) (0x180 + (uint64_t)(n) * 4)
|
||||
#define D_ISPENDR(n) (0x200 + (uint64_t)(n) * 4)
|
||||
#define D_ICPENDR(n) (0x280 + (uint64_t)(n) * 4)
|
||||
#define D_IPRIORITYR(n) (0x400 + (uint64_t)(n) * 4)
|
||||
#define D_ITARGETSR(n) (0x800 + (uint64_t)(n) * 4)
|
||||
#define D_ICFGR(n) (0xc00 + (uint64_t)(n) * 4)
|
||||
|
||||
#define R_CTLR 0x0
|
||||
#define R_WAKER 0x14
|
||||
|
||||
#define SGI_BASE 0x10000
|
||||
#define R_IGROUPR0 (SGI_BASE + 0x80)
|
||||
#define R_ISENABLER0 (SGI_BASE + 0x100)
|
||||
#define R_ICENABLER0 (SGI_BASE + 0x180)
|
||||
#define R_ICPENDR0 (SGI_BASE + 0x280)
|
||||
#define R_IPRIORITYR(n) (SGI_BASE + 0x400 + (n) * 4)
|
||||
#define R_ICFGR0 (SGI_BASE + 0xc00)
|
||||
#define R_ICFGR1 (SGI_BASE + 0xc04)
|
||||
#define R_IGRPMODR0 (SGI_BASE + 0xd00)
|
||||
// clang-format on
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Freescale Semiconductor, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* o Redistributions of source code must retain the above copyright notice, this list
|
||||
* of conditions and the following disclaimer.
|
||||
*
|
||||
* o Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* Portions Copyright (c) 2011-2012 ARM Ltd. All rights reserved.
|
||||
*/
|
||||
/**
|
||||
* @file hard_spinlock.S
|
||||
* @brief spinlock implementation
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.04.11
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: hard_spinlock.S
|
||||
Description: spinlock implementation
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
*************************************************/
|
||||
|
||||
.arch armv8-a
|
||||
.section ".text","ax"
|
||||
|
||||
.global cpu_get_current
|
||||
|
||||
#define UNLOCKED 0xFF
|
||||
// int spinlock_lock(spinlock_t * lock, uint64_t timeout)
|
||||
.global _spinlock_lock
|
||||
.func _spinlock_lock
|
||||
_spinlock_lock:
|
||||
mov w2, #1
|
||||
|
||||
sevl
|
||||
wfe
|
||||
|
||||
ldaxrb w1, [x0] // check if the spinlock is currently unlocked
|
||||
cmp w1, #UNLOCKED
|
||||
bne _spinlock_lock
|
||||
|
||||
mrs x1, mpidr_el1 // get our CPU ID
|
||||
and x1, x1, #3
|
||||
stxrb w2, w1, [x0]
|
||||
cmp x2, #0
|
||||
bne _spinlock_lock // check if the write was successful, if the write failed, start over
|
||||
|
||||
dmb ish // Ensure that accesses to shared resource have completed
|
||||
|
||||
mov x0, #0
|
||||
ret
|
||||
|
||||
.endfunc
|
||||
|
||||
|
||||
// void spinlock_unlock(spinlock_t * lock)
|
||||
.global _spinlock_unlock
|
||||
.func _spinlock_unlock
|
||||
_spinlock_unlock:
|
||||
|
||||
mrs x1, mpidr_el1 // get our CPU ID
|
||||
and x1, x1, #3
|
||||
|
||||
ldr w2, [x0]
|
||||
cmp w1, w2
|
||||
bne 1f //doesn't match,jump to 1
|
||||
|
||||
|
||||
dmb ish
|
||||
|
||||
mov w1, #UNLOCKED
|
||||
str w1, [x0]
|
||||
|
||||
dsb ish //Ensure that no instructions following the barrier execute until
|
||||
// all memory accesses prior to the barrier have completed.
|
||||
|
||||
|
||||
sevl // send event to wake up other cores waiting on spinlock
|
||||
|
||||
mov x0, #0 // return success
|
||||
ret
|
||||
|
||||
1:
|
||||
mov x0, #1 //doesn't match, so exit with failure
|
||||
ret
|
||||
|
||||
.endfunc
|
||||
|
||||
.end
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
/**
|
||||
* @file exception_registers.h
|
||||
* @brief exception registers
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.05.09
|
||||
*/
|
||||
|
||||
static inline void w_vbar_el1(uint64_t x)
|
||||
{
|
||||
__asm__ volatile("msr vbar_el1, %0" : : "r"(x));
|
||||
}
|
||||
|
||||
static inline uint64_t r_esr_el1()
|
||||
{
|
||||
uint64_t x;
|
||||
__asm__ volatile("mrs %0, esr_el1" : "=r"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline void w_esr_el1(uint64_t x)
|
||||
{
|
||||
__asm__ volatile("msr esr_el1, %0" : : "r"(x));
|
||||
}
|
||||
|
||||
static inline uint64_t r_elr_el1()
|
||||
{
|
||||
uint64_t x;
|
||||
__asm__ volatile("mrs %0, elr_el1" : "=r"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline uint64_t r_far_el1()
|
||||
{
|
||||
uint64_t x;
|
||||
__asm__ volatile("mrs %0, far_el1" : "=r"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline uint64_t daif()
|
||||
{
|
||||
uint64_t x;
|
||||
__asm__ volatile("mrs %0, daif" : "=r"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
// enable interrupts(irq)
|
||||
static inline void intr_on()
|
||||
{
|
||||
__asm__ volatile("msr daifclr, #0xf" ::: "memory");
|
||||
}
|
||||
|
||||
// disable interrupts(irq)
|
||||
static inline void intr_off()
|
||||
{
|
||||
__asm__ volatile("msr daifset, #0xf" ::: "memory");
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* @file irq_numbers.c
|
||||
* @brief irq numbers
|
||||
* @version 3.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2023.08.25
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: irq_numbers.c
|
||||
Description: irq numbers
|
||||
Others:
|
||||
History:
|
||||
1. Date: 2023-08-28
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. Add HW_NR_IRQS
|
||||
*************************************************/
|
||||
#if !defined(__IRQ_NUMBERS_H__)
|
||||
#define __IRQ_NUMBERS_H__
|
||||
|
||||
#define HW_NR_IRQS NR_OK1028_INTRS
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Definitions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! @brief i.MX6 interrupt numbers.
|
||||
//!
|
||||
//! This enumeration lists the numbers for all of the interrupts available on the i.MX6 series.
|
||||
//! Use these numbers when specifying an interrupt to the GIC.
|
||||
//!
|
||||
//! The first 16 interrupts are special in that they are reserved for software interrupts generated
|
||||
//! by the SWI instruction.
|
||||
|
||||
enum _ls_interrupts {
|
||||
SW_INTERRUPT_0 = 0, //!< Software interrupt 0.
|
||||
SW_INTERRUPT_1 = 1, //!< Software interrupt 1.
|
||||
SW_INTERRUPT_2 = 2, //!< Software interrupt 2.
|
||||
SW_INTERRUPT_3 = 3, //!< Software interrupt 3.
|
||||
SW_INTERRUPT_4 = 4, //!< Software interrupt 4.
|
||||
SW_INTERRUPT_5 = 5, //!< Software interrupt 5.
|
||||
SW_INTERRUPT_6 = 6, //!< Software interrupt 6.
|
||||
SW_INTERRUPT_7 = 7, //!< Software interrupt 7.
|
||||
SW_INTERRUPT_8 = 8, //!< Software interrupt 8.
|
||||
SW_INTERRUPT_9 = 9, //!< Software interrupt 9.
|
||||
SW_INTERRUPT_10 = 10, //!< Software interrupt 10.
|
||||
SW_INTERRUPT_11 = 11, //!< Software interrupt 11.
|
||||
SW_INTERRUPT_12 = 12, //!< Software interrupt 12.
|
||||
SW_INTERRUPT_13 = 13, //!< Software interrupt 13.
|
||||
SW_INTERRUPT_14 = 14, //!< Software interrupt 14.
|
||||
SW_INTERRUPT_15 = 15, //!< Software interrupt 15.
|
||||
RSVD_INTERRUPT_16 = 16, //!< Reserved.
|
||||
RSVD_INTERRUPT_17 = 17, //!< Reserved.
|
||||
RSVD_INTERRUPT_18 = 18, //!< Reserved.
|
||||
RSVD_INTERRUPT_19 = 19, //!< Reserved.
|
||||
RSVD_INTERRUPT_20 = 20, //!< Reserved.
|
||||
RSVD_INTERRUPT_21 = 21, //!< Reserved.
|
||||
|
||||
LS_INT_DEBUG_CC = 22, //!<(cluster-internal) COMMIRQ - Debug communications channel
|
||||
LS_INT_PMU = 23, //!<(cluster-internal) PMUIRQ - Perfmon*
|
||||
LS_INT_CTI = 24, //!<(cluster-internal) CTIIRQ - Cross-trigger interface*
|
||||
LS_INT_VMI = 25, //!<(cluster-internal) VCPUMNTIRQ -Virtual maintenance interface*
|
||||
|
||||
LS_INT_WDOG = 28, //!< Watchdog timer
|
||||
LS_INT_SEC_PHY_TIMER = 29, //!<(cluster-internal) CNTPSIRQ - EL1 Secure physical timer event*
|
||||
LS_INT_NON_SEC_PHY_TIMER = 30, //!<(cluster-internal) CNTPNSIRQ - EL1 Non-secure physical timer event*
|
||||
RSVD_INTERRUPT_31 = 31, //!< Reserved.
|
||||
RSVD_INTERRUPT_32 = 32, //!< Reserved.
|
||||
RSVD_INTERRUPT_33 = 33, //!< Reserved.
|
||||
RSVD_INTERRUPT_34 = 34, //!< Reserved.
|
||||
RSVD_INTERRUPT_35 = 35, //!< Reserved.
|
||||
RSVD_INTERRUPT_36 = 36, //!< Reserved.
|
||||
RSVD_INTERRUPT_37 = 37, //!< Reserved.
|
||||
RSVD_INTERRUPT_38 = 38, //!< Reserved.
|
||||
RSVD_INTERRUPT_39 = 39, //!< Reserved.
|
||||
RSVD_INTERRUPT_40 = 40, //!< Reserved.
|
||||
RSVD_INTERRUPT_41 = 41, //!< Reserved.
|
||||
RSVD_INTERRUPT_42 = 42, //!< Reserved.
|
||||
|
||||
LS_INT_DUART1 = 64, // Logical OR of DUART1 interrupt requests.
|
||||
|
||||
LS_INT_I2C1_2 = 66, //!< I2C1 and I2C2 ORed
|
||||
LS_INT_I2C3_4 = 67, //!< I2C3 and I2C4 ORed
|
||||
LS_INT_GPIO1_2 = 68, //!< GPIO1 and GPIO2 ORed
|
||||
LS_INT_GPIO3 = 69, //!< GPIO3
|
||||
|
||||
LS_INT_FLETIMER1 = 76, //!< ORed all Flextimer 1 interrupt signals
|
||||
LS_INT_FLETIMER2 = 77, //!< ORed all Flextimer 2 interrupt signals
|
||||
LS_INT_FLETIMER3 = 78, //!< ORed all Flextimer 3 interrupt signals
|
||||
LS_INT_FLETIMER4 = 79, //!< ORed all Flextimer 4 interrupt signals
|
||||
|
||||
LS_INT_I2C5_6 = 106, //!< I2C5 and I2C6 ORed
|
||||
LS_INT_I2C7_8 = 107, //!< I2C7 and I2C8 ORed
|
||||
|
||||
LS_INT_USB3_1 = 112, //!< USB1 ORed INT
|
||||
LS_INT_USB3_2 = 113, //!< USB2 ORed INT
|
||||
|
||||
LS_INT_LPUART1 = 264, //!< LPUART1 interrupt request.
|
||||
LS_INT_LPUART2 = 265, //!< LPUART1 interrupt request.
|
||||
LS_INT_LPUART3 = 266, //!< LPUART1 interrupt request.
|
||||
LS_INT_LPUART4 = 267, //!< LPUART1 interrupt request.
|
||||
LS_INT_LPUART5 = 268, //!< LPUART1 interrupt request.
|
||||
LS_INT_LPUART6 = 269, //!< LPUART1 interrupt request.
|
||||
|
||||
NR_OK1028_INTRS,
|
||||
|
||||
};
|
||||
|
||||
#endif //__IRQ_NUMBERS_H__
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
/**
|
||||
* @file trap.c
|
||||
* @brief trap interface of hardkernel
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2023.05.06
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: trap.c
|
||||
Description: trap interface of hardkernel
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. first version
|
||||
*************************************************/
|
||||
#include <stdint.h>
|
||||
|
||||
#include "assert.h"
|
||||
#include "core.h"
|
||||
#include "exception_registers.h"
|
||||
#include "multicores.h"
|
||||
#include "syscall.h"
|
||||
#include "task.h"
|
||||
|
||||
extern void dabort_handler(struct trapframe* r);
|
||||
extern void iabort_handler(struct trapframe* r);
|
||||
|
||||
void kernel_abort_handler(struct trapframe* tf)
|
||||
{
|
||||
uint64_t esr = r_esr_el1();
|
||||
switch ((esr >> 0x1A) & 0x3F) {
|
||||
case 0b100100:
|
||||
case 0b100101:
|
||||
dabort_handler(tf);
|
||||
break;
|
||||
case 0b100000:
|
||||
case 0b100001:
|
||||
iabort_handler(tf);
|
||||
break;
|
||||
default: {
|
||||
uint64_t ec = (esr >> 26) & 0x3f;
|
||||
uint64_t iss = esr & 0x1ffffff;
|
||||
ERROR("esr: %016lx %016lx %016lx\n", esr, ec, iss);
|
||||
ERROR("elr = %016lx far = %016lx\n", r_elr_el1(), r_far_el1());
|
||||
ERROR("Current Task: %s.\n", cur_cpu()->task->name);
|
||||
panic("Unimplemented Error Occured.\n");
|
||||
}
|
||||
}
|
||||
panic("Return from abort handler.\n");
|
||||
}
|
||||
|
||||
void kernel_intr_handler(struct trapframe* tf)
|
||||
{
|
||||
panic("Intr at kernel mode should never happen by design.\n");
|
||||
}
|
||||
|
||||
extern void context_switch(struct context**, struct context*);
|
||||
void syscall_arch_handler(struct trapframe* tf)
|
||||
{
|
||||
|
||||
uint64_t esr = r_esr_el1();
|
||||
uint64_t ec = (esr >> 0x1A) & 0x3F;
|
||||
w_esr_el1(0);
|
||||
switch (ec) {
|
||||
case 0B010101:
|
||||
software_irq_dispatch(tf);
|
||||
break;
|
||||
case 0b100100:
|
||||
case 0b100101:
|
||||
dabort_handler(tf);
|
||||
break;
|
||||
case 0b100000:
|
||||
case 0b100001:
|
||||
iabort_handler(tf);
|
||||
break;
|
||||
default: {
|
||||
ERROR("USYSCALL: unexpected ec: %016lx", esr);
|
||||
ERROR(" elr = %016lx far = %016lx\n", r_elr_el1(), r_far_el1());
|
||||
// kill error task
|
||||
xizi_enter_kernel();
|
||||
assert(cur_cpu()->task != NULL);
|
||||
sys_exit(cur_cpu()->task);
|
||||
context_switch(&cur_cpu()->task->thread_context.context, cur_cpu()->scheduler);
|
||||
panic("dabort end should never be reashed.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
/**
|
||||
* @file trap_common.c
|
||||
* @brief trap interface of hardkernel
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2023.05.06
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: trap_common.c
|
||||
Description: trap interface of hardkernel
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. first version
|
||||
*************************************************/
|
||||
#include <string.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "cortex_a72.h"
|
||||
#include "exception_registers.h"
|
||||
#include "gicv3_common_opa.h"
|
||||
#include "trap_common.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "multicores.h"
|
||||
|
||||
static struct XiziTrapDriver xizi_trap_driver;
|
||||
|
||||
void panic(char* s)
|
||||
{
|
||||
KPrintf("panic: %s\n", s);
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
extern void alltraps();
|
||||
static void _sys_irq_init(int cpu_id)
|
||||
{
|
||||
// primary core init intr
|
||||
xizi_trap_driver.switch_hw_irqtbl((uintptr_t*)alltraps);
|
||||
|
||||
if (cpu_id == 0) {
|
||||
gic_init();
|
||||
}
|
||||
gicv3inithart(cpu_id);
|
||||
}
|
||||
|
||||
static void _cpu_irq_enable(void)
|
||||
{
|
||||
intr_on();
|
||||
}
|
||||
|
||||
static void _cpu_irq_disable(void)
|
||||
{
|
||||
intr_off();
|
||||
}
|
||||
|
||||
static void _single_irq_enable(int irq, int cpu, int prio)
|
||||
{
|
||||
gic_setup_ppi((uint32_t)cpu, (uint32_t)irq);
|
||||
}
|
||||
|
||||
static void _single_irq_disable(int irq, int cpu)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline uintptr_t* _switch_hw_irqtbl(uintptr_t* new_tbl_base)
|
||||
{
|
||||
w_vbar_el1((uint64_t)new_tbl_base);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _bind_irq_handler(int irq, irq_handler_t handler)
|
||||
{
|
||||
xizi_trap_driver.sw_irqtbl[irq].handler = handler;
|
||||
}
|
||||
|
||||
static uint32_t _hw_before_irq()
|
||||
{
|
||||
|
||||
uint32_t iar = gic_read_irq_ack();
|
||||
return iar;
|
||||
}
|
||||
|
||||
static uint32_t _hw_cur_int_num(uint32_t int_info)
|
||||
{
|
||||
return int_info & 0x3FF;
|
||||
}
|
||||
|
||||
static void _hw_after_irq(uint32_t int_info)
|
||||
{
|
||||
gic_write_end_of_irq(int_info);
|
||||
}
|
||||
|
||||
int _cur_cpu_id()
|
||||
{
|
||||
return cpu_get_current();
|
||||
}
|
||||
|
||||
static struct XiziTrapDriver xizi_trap_driver = {
|
||||
.sys_irq_init = _sys_irq_init,
|
||||
.cur_cpu_id = _cur_cpu_id,
|
||||
|
||||
.cpu_irq_enable = _cpu_irq_enable,
|
||||
.cpu_irq_disable = _cpu_irq_disable,
|
||||
.single_irq_enable = _single_irq_enable,
|
||||
.single_irq_disable = _single_irq_disable,
|
||||
.switch_hw_irqtbl = _switch_hw_irqtbl,
|
||||
|
||||
.bind_irq_handler = _bind_irq_handler,
|
||||
|
||||
.hw_before_irq = _hw_before_irq,
|
||||
.hw_cur_int_num = _hw_cur_int_num,
|
||||
.hw_after_irq = _hw_after_irq,
|
||||
};
|
||||
|
||||
struct XiziTrapDriver* hardkernel_intr_init(struct TraceTag* hardkernel_tag)
|
||||
{
|
||||
xizi_trap_driver.sys_irq_init(0);
|
||||
xizi_trap_driver.cpu_irq_disable();
|
||||
return &xizi_trap_driver;
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
/**
|
||||
* @file trampoline.S
|
||||
* @brief trap in and out code
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024-04-22
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: trampoline.S
|
||||
Description: trap in and out code
|
||||
Others:
|
||||
History:
|
||||
1. Date: 2024-04-22
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. first version
|
||||
*************************************************/
|
||||
|
||||
#include "memlayout.h"
|
||||
|
||||
#include "core.h"
|
||||
|
||||
.macro savereg
|
||||
// make room to save registers.
|
||||
sub sp, sp, #272
|
||||
|
||||
// save the registers.
|
||||
stp x0, x1, [sp, #16 * 0]
|
||||
stp x2, x3, [sp, #16 * 1]
|
||||
stp x4, x5, [sp, #16 * 2]
|
||||
stp x6, x7, [sp, #16 * 3]
|
||||
stp x8, x9, [sp, #16 * 4]
|
||||
stp x10, x11, [sp, #16 * 5]
|
||||
stp x12, x13, [sp, #16 * 6]
|
||||
stp x14, x15, [sp, #16 * 7]
|
||||
stp x16, x17, [sp, #16 * 8]
|
||||
stp x18, x19, [sp, #16 * 9]
|
||||
stp x20, x21, [sp, #16 * 10]
|
||||
stp x22, x23, [sp, #16 * 11]
|
||||
stp x24, x25, [sp, #16 * 12]
|
||||
stp x26, x27, [sp, #16 * 13]
|
||||
stp x28, x29, [sp, #16 * 14]
|
||||
mrs x9, elr_el1
|
||||
mrs x10, spsr_el1
|
||||
add x11, sp, #272
|
||||
stp x30, x9, [sp, #16 * 15]
|
||||
stp x10, x11, [sp, #16 * 16]
|
||||
.endm
|
||||
|
||||
.macro restorereg
|
||||
ldp x30, x9, [sp, #16 * 15]
|
||||
ldp x10, x11, [sp, #16 * 16]
|
||||
|
||||
msr elr_el1, x9
|
||||
msr spsr_el1, x10
|
||||
|
||||
ldp x0, x1, [sp, #16 * 0]
|
||||
ldp x2, x3, [sp, #16 * 1]
|
||||
ldp x4, x5, [sp, #16 * 2]
|
||||
ldp x6, x7, [sp, #16 * 3]
|
||||
ldp x8, x9, [sp, #16 * 4]
|
||||
ldp x10, x11, [sp, #16 * 5]
|
||||
ldp x12, x13, [sp, #16 * 6]
|
||||
ldp x14, x15, [sp, #16 * 7]
|
||||
ldp x16, x17, [sp, #16 * 8]
|
||||
ldp x18, x19, [sp, #16 * 9]
|
||||
ldp x20, x21, [sp, #16 * 10]
|
||||
ldp x22, x23, [sp, #16 * 11]
|
||||
ldp x24, x25, [sp, #16 * 12]
|
||||
ldp x26, x27, [sp, #16 * 13]
|
||||
ldp x28, x29, [sp, #16 * 14]
|
||||
add sp, sp, #272
|
||||
.endm
|
||||
|
||||
.macro usavereg
|
||||
sub sp, sp, #272
|
||||
|
||||
stp x0, x1, [sp, #16 * 0]
|
||||
stp x2, x3, [sp, #16 * 1]
|
||||
stp x4, x5, [sp, #16 * 2]
|
||||
stp x6, x7, [sp, #16 * 3]
|
||||
stp x8, x9, [sp, #16 * 4]
|
||||
stp x10, x11, [sp, #16 * 5]
|
||||
stp x12, x13, [sp, #16 * 6]
|
||||
stp x14, x15, [sp, #16 * 7]
|
||||
stp x16, x17, [sp, #16 * 8]
|
||||
stp x18, x19, [sp, #16 * 9]
|
||||
stp x20, x21, [sp, #16 * 10]
|
||||
stp x22, x23, [sp, #16 * 11]
|
||||
stp x24, x25, [sp, #16 * 12]
|
||||
stp x26, x27, [sp, #16 * 13]
|
||||
stp x28, x29, [sp, #16 * 14]
|
||||
|
||||
mrs x9, elr_el1
|
||||
mrs x10, spsr_el1
|
||||
mrs x11, sp_el0
|
||||
|
||||
stp x30, x9, [sp, #16 * 15]
|
||||
stp x10, x11, [sp, #16 * 16]
|
||||
.endm
|
||||
|
||||
.macro urestorereg
|
||||
ldp x30, x9, [sp, #16 * 15]
|
||||
ldp x10, x11, [sp, #16 * 16]
|
||||
|
||||
msr elr_el1, x9
|
||||
msr spsr_el1, x10
|
||||
msr sp_el0, x11
|
||||
|
||||
ldp x0, x1, [sp, #16 * 0]
|
||||
ldp x2, x3, [sp, #16 * 1]
|
||||
ldp x4, x5, [sp, #16 * 2]
|
||||
ldp x6, x7, [sp, #16 * 3]
|
||||
ldp x8, x9, [sp, #16 * 4]
|
||||
ldp x10, x11, [sp, #16 * 5]
|
||||
ldp x12, x13, [sp, #16 * 6]
|
||||
ldp x14, x15, [sp, #16 * 7]
|
||||
ldp x16, x17, [sp, #16 * 8]
|
||||
ldp x18, x19, [sp, #16 * 9]
|
||||
ldp x20, x21, [sp, #16 * 10]
|
||||
ldp x22, x23, [sp, #16 * 11]
|
||||
ldp x24, x25, [sp, #16 * 12]
|
||||
ldp x26, x27, [sp, #16 * 13]
|
||||
ldp x28, x29, [sp, #16 * 14]
|
||||
|
||||
add sp, sp, #272
|
||||
.endm
|
||||
|
||||
|
||||
.global alltraps
|
||||
.balign 0x800
|
||||
alltraps:
|
||||
// Current EL with sp0
|
||||
b .
|
||||
.balign 0x80
|
||||
b .
|
||||
.balign 0x80
|
||||
b .
|
||||
.balign 0x80
|
||||
b .
|
||||
|
||||
// Current EL with spx
|
||||
.balign 0x80
|
||||
b el1sync
|
||||
.balign 0x80
|
||||
b el1irq
|
||||
.balign 0x80
|
||||
b .
|
||||
.balign 0x80
|
||||
b .
|
||||
|
||||
// Lower EL using aarch64
|
||||
.balign 0x80
|
||||
b el0sync
|
||||
.balign 0x80
|
||||
b el0irq
|
||||
.balign 0x80
|
||||
b .
|
||||
.balign 0x80
|
||||
b .
|
||||
|
||||
// Lower EL using aarch32
|
||||
.balign 0x80
|
||||
b .
|
||||
.balign 0x80
|
||||
b .
|
||||
.balign 0x80
|
||||
b .
|
||||
.balign 0x80
|
||||
b .
|
||||
|
||||
el1sync:
|
||||
msr daifset, #0xf
|
||||
savereg
|
||||
|
||||
mov x0, sp
|
||||
bl kernel_abort_handler
|
||||
b .
|
||||
|
||||
el1irq:
|
||||
msr daifset, #0xf
|
||||
usavereg
|
||||
|
||||
mov x0, sp
|
||||
bl intr_irq_dispatch
|
||||
|
||||
urestorereg
|
||||
|
||||
eret
|
||||
|
||||
el0sync:
|
||||
msr daifset, #0xf
|
||||
usavereg
|
||||
|
||||
mov x0, sp
|
||||
bl syscall_arch_handler
|
||||
|
||||
urestorereg
|
||||
|
||||
eret
|
||||
|
||||
el0irq:
|
||||
msr daifset, #0xf
|
||||
usavereg
|
||||
|
||||
mov x0, sp
|
||||
bl intr_irq_dispatch
|
||||
|
||||
.global trap_return
|
||||
trap_return:
|
||||
urestorereg
|
||||
|
||||
eret
|
||||
@@ -52,16 +52,16 @@ enum {
|
||||
SPINLOCK_LOCK_WAITFOREVER = 0xFFFFFFFF,
|
||||
};
|
||||
|
||||
void spinlock_init(struct spinlock* lock, char* name)
|
||||
__attribute__((optimize("O0"))) void spinlock_init(struct spinlock* lock, char* name)
|
||||
{
|
||||
lock->owner_cpu = SPINLOCK_STATE_UNLOCK;
|
||||
strncpy(lock->name, name, 24);
|
||||
}
|
||||
|
||||
extern int _spinlock_lock(struct spinlock* lock, uint32_t timeout);
|
||||
void _spinlock_unlock(struct spinlock* lock);
|
||||
extern void _spinlock_unlock(struct spinlock* lock);
|
||||
|
||||
void spinlock_lock(struct spinlock* lock)
|
||||
__attribute__((optimize("O0"))) void spinlock_lock(struct spinlock* lock)
|
||||
{
|
||||
int cur_cpu_id = cur_cpuid();
|
||||
if (lock->owner_cpu != SPINLOCK_STATE_UNLOCK && lock->owner_cpu == cur_cpu_id) {
|
||||
@@ -80,7 +80,7 @@ void spinlock_lock(struct spinlock* lock)
|
||||
_spinlock_lock(lock, SPINLOCK_LOCK_WAITFOREVER);
|
||||
}
|
||||
|
||||
void spinlock_unlock(struct spinlock* lock)
|
||||
__attribute__((optimize("O0"))) void spinlock_unlock(struct spinlock* lock)
|
||||
{
|
||||
struct double_list_node* p_lock_node = &core_lock_request[cur_cpuid()].node;
|
||||
assert(lock_request_guard.next == p_lock_node);
|
||||
@@ -91,7 +91,7 @@ void spinlock_unlock(struct spinlock* lock)
|
||||
_spinlock_unlock(lock);
|
||||
}
|
||||
|
||||
bool spinlock_try_lock(struct spinlock* lock)
|
||||
__attribute__((optimize("O0"))) bool spinlock_try_lock(struct spinlock* lock)
|
||||
{
|
||||
int cur_cpu_id = cur_cpuid();
|
||||
if (lock->owner_cpu != SPINLOCK_STATE_UNLOCK && lock->owner_cpu == cur_cpu_id) {
|
||||
@@ -115,5 +115,5 @@ bool spinlock_try_lock(struct spinlock* lock)
|
||||
|
||||
bool is_spinlock_hold_by_current_cpu(struct spinlock* lock)
|
||||
{
|
||||
return lock->owner_cpu;
|
||||
return lock->owner_cpu == cur_cpuid();
|
||||
}
|
||||
@@ -32,12 +32,11 @@ Modification:
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "actracer.h"
|
||||
#include "core.h"
|
||||
#include "irq_numbers.h"
|
||||
#include "memlayout.h"
|
||||
|
||||
#include "actracer.h"
|
||||
|
||||
#define NR_IRQS HW_NR_IRQS
|
||||
#define NR_MODE_STACKS 4
|
||||
|
||||
@@ -56,8 +55,6 @@ struct irq_table_entry {
|
||||
struct XiziTrapDriver {
|
||||
/* irq number table*/
|
||||
struct irq_table_entry sw_irqtbl[NR_IRQS];
|
||||
/* current irq number happening in cpu*/
|
||||
uint32_t curr_int[NR_CPU];
|
||||
|
||||
void (*sys_irq_init)(int);
|
||||
int (*cur_cpu_id)();
|
||||
@@ -67,15 +64,13 @@ struct XiziTrapDriver {
|
||||
void (*single_irq_enable)(int irq, int cpu, int prio);
|
||||
void (*single_irq_disable)(int irq, int cpu);
|
||||
|
||||
uint32_t* (*switch_hw_irqtbl)(uint32_t*);
|
||||
uintptr_t* (*switch_hw_irqtbl)(uintptr_t*);
|
||||
void (*bind_irq_handler)(int, irq_handler_t);
|
||||
|
||||
/* check if no if interruptable */
|
||||
int (*is_interruptable)();
|
||||
/* code runs before irq handling */
|
||||
uint32_t (*hw_before_irq)();
|
||||
uint32_t (*hw_cur_int_num)(uint32_t int_info);
|
||||
uint32_t (*hw_cur_int_cpu)(uint32_t int_info);
|
||||
/* code runs after irq handling */
|
||||
void (*hw_after_irq)(uint32_t int_info);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
ifneq ($(findstring $(BOARD), ok1028a-c), )
|
||||
SRC_DIR := armv8-a
|
||||
endif
|
||||
ifneq ($(findstring $(BOARD), imx6q-sabrelite zynq7000-zc702), )
|
||||
SRC_DIR := armv7-a
|
||||
endif
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ static void build_boot_pgdir()
|
||||
|
||||
// kern mem
|
||||
uint32_t kern_mem_start_idx = KERN_MEM_BASE >> LEVEL3_PDE_SHIFT;
|
||||
uint32_t kern_mem_end_idx = (KERN_MEM_BASE + (PHY_MEM_STOP - PHY_MEM_BASE)) >> LEVEL3_PDE_SHIFT;
|
||||
uint32_t kern_mem_end_idx = (KERN_MEM_BASE + (PHY_USER_FREEMEM_BASE - PHY_MEM_BASE)) >> LEVEL3_PDE_SHIFT;
|
||||
for (uint32_t i = kern_mem_start_idx; i < kern_mem_end_idx; i++) {
|
||||
boot_pgdir[i] = V2P(i << LEVEL3_PDE_SHIFT) | L1_TYPE_SEC | L1_SECT_AP0;
|
||||
}
|
||||
|
||||
@@ -56,12 +56,13 @@ Modification:
|
||||
#define MAX_NR_FREE_PAGES ((PHY_MEM_STOP - PHY_MEM_BASE) >> LEVEL4_PTE_SHIFT)
|
||||
|
||||
/* User memory layout */
|
||||
#define NR_MAX_TREADS_PER_TASK 64
|
||||
#define USER_STACK_SIZE MODE_STACK_SIZE
|
||||
#define USER_MEM_BASE (0x00000000)
|
||||
#define USER_MEM_TOP DEV_VRTMEM_BASE
|
||||
#define USER_IPC_SPACE_BASE (0x70000000)
|
||||
#define USER_IPC_USE_ALLOCATOR_WATERMARK (0x70010000)
|
||||
#define USER_IPC_SPACE_TOP (USER_MEM_TOP - USER_STACK_SIZE)
|
||||
#define USER_IPC_SPACE_TOP (USER_MEM_TOP - (NR_MAX_TREADS_PER_TASK * USER_STACK_SIZE))
|
||||
|
||||
/* Deivce memory layout */
|
||||
#define DEV_PHYMEM_BASE (0x00000000)
|
||||
|
||||
@@ -38,24 +38,6 @@ Modification:
|
||||
// extern struct MmuCommonDone mmu_common_done;
|
||||
static struct MmuDriverRightGroup right_group;
|
||||
|
||||
void load_pgdir_critical(uintptr_t pgdir_paddr, struct TraceTag* intr_driver_tag)
|
||||
{
|
||||
|
||||
/* get cache driver */
|
||||
struct ICacheDone* p_icache_done = AchieveResource(&right_group.icache_driver_tag);
|
||||
struct DCacheDone* p_dcache_done = AchieveResource(&right_group.dcache_driver_tag);
|
||||
|
||||
/* get intr driver */
|
||||
struct XiziTrapDriver* p_intr_driver = AchieveResource(intr_driver_tag);
|
||||
|
||||
p_intr_driver->cpu_irq_disable();
|
||||
TTBR0_W((uint32_t)pgdir_paddr);
|
||||
CLEARTLB(0);
|
||||
p_icache_done->invalidateall();
|
||||
p_dcache_done->flushall();
|
||||
p_intr_driver->cpu_irq_enable();
|
||||
}
|
||||
|
||||
void load_pgdir(uintptr_t pgdir_paddr)
|
||||
{
|
||||
/* get cache driver */
|
||||
@@ -94,7 +76,6 @@ static struct MmuCommonDone mmu_common_done = {
|
||||
.MmuUsrDevPteAttr = GetUsrDevPteAttr,
|
||||
.MmuKernPteAttr = GetKernPteAttr,
|
||||
|
||||
.LoadPgdirCrit = load_pgdir_critical,
|
||||
.LoadPgdir = load_pgdir,
|
||||
.TlbFlushAll = tlb_flush_all,
|
||||
.TlbFlush = tlb_flush_range,
|
||||
|
||||
@@ -56,6 +56,9 @@ void GetUsrDevPteAttr(uintptr_t* attr)
|
||||
|
||||
usr_pte_attr.entry = 0;
|
||||
usr_pte_attr.desc_type = PAGE_4K;
|
||||
usr_pte_attr.TEX = 2;
|
||||
// usr_pte_attr.B = 1;
|
||||
usr_pte_attr.S = 1;
|
||||
usr_pte_attr.AP1_0 = AccessPermission_KernelUser;
|
||||
}
|
||||
*attr = usr_pte_attr.entry;
|
||||
@@ -87,6 +90,7 @@ void GetKernPteAttr(uintptr_t* attr)
|
||||
kern_pte_attr.B = 1;
|
||||
kern_pte_attr.C = 1;
|
||||
kern_pte_attr.S = 1;
|
||||
kern_pte_attr.TEX = 1;
|
||||
kern_pte_attr.AP1_0 = AccessPermission_KernelOnly;
|
||||
}
|
||||
*attr = kern_pte_attr.entry;
|
||||
@@ -94,5 +98,13 @@ void GetKernPteAttr(uintptr_t* attr)
|
||||
|
||||
void GetPdeAttr(uintptr_t* attr)
|
||||
{
|
||||
*attr = PAGE_DIR_COARSE;
|
||||
static char init = 0;
|
||||
static PageDirEntry pde_attr;
|
||||
if (init == 0) {
|
||||
init = 1;
|
||||
|
||||
pde_attr.entry = 0;
|
||||
pde_attr.desc_type = PAGE_DIR_COARSE;
|
||||
}
|
||||
*attr = pde_attr.entry;
|
||||
}
|
||||
3
Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv8-a/Makefile
Normal file
3
Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv8-a/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
SRC_DIR := cortex-a72
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,3 @@
|
||||
SRC_FILES := bootmmu.c mmu.c pagetable_attr.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
/**
|
||||
* @file bootmmu.c
|
||||
* @brief build pagetable and enable mmu in boot time
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.04.26
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: bootmmu.c
|
||||
Description: build pagetable and enable mmu in boot time
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. first version
|
||||
*************************************************/
|
||||
#include "core.h"
|
||||
#include "memlayout.h"
|
||||
#include "mmio_access.h"
|
||||
#include "mmu.h"
|
||||
#include "pagetable.h"
|
||||
#include "registers.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
extern uint64_t kernel_data_end[];
|
||||
extern uint64_t kernel_data_begin[];
|
||||
|
||||
// clang-format off
|
||||
#define L2_TYPE_TAB 2
|
||||
#define L2_PTE_VALID 1
|
||||
|
||||
#define L3_TYPE_TAB 2
|
||||
#define L3_PTE_VALID 1
|
||||
|
||||
#define L4_TYPE_PAGE (3 << 0)
|
||||
#define L4_PTE_DEV ((0b00) << 2) // Device memory
|
||||
#define L4_PTE_NORMAL ((0b01) << 2) // Device memory
|
||||
#define L4_PTE_AF (1 << 10) // Data Access Permissions
|
||||
|
||||
#define L4_PTE_PXN (1UL << 53) // Privileged eXecute Never
|
||||
#define L4_PTE_UXN (1UL << 54) // Unprivileged(user) eXecute Never
|
||||
#define L4_PTE_XN (PTE_PXN|PTE_UXN) // eXecute Never
|
||||
|
||||
#define IDX_MASK (0b111111111)
|
||||
#define L3_PDE_INDEX(idx) ((idx << LEVEL3_PDE_SHIFT) & L3_IDX_MASK)
|
||||
// clang-format on
|
||||
|
||||
uint64_t boot_l2pgdir[NUM_LEVEL2_PDE] __attribute__((aligned(0x1000))) = { 0 };
|
||||
|
||||
uint64_t boot_dev_l3pgdir[NUM_LEVEL3_PDE] __attribute__((aligned(0x1000))) = { 0 };
|
||||
uint64_t boot_virt_dev_l3pgdir[NUM_LEVEL3_PDE] __attribute__((aligned(0x1000))) = { 0 };
|
||||
uint64_t boot_kern_l3pgdir[NUM_LEVEL3_PDE] __attribute__((aligned(0x1000))) = { 0 };
|
||||
uint64_t boot_virt_kern_l3pgdir[NUM_LEVEL3_PDE] __attribute__((aligned(0x1000))) = { 0 };
|
||||
|
||||
uint64_t boot_dev_l4pgdirs[NUM_LEVEL3_PDE][NUM_LEVEL4_PTE] __attribute__((aligned(0x1000))) = { 0 };
|
||||
uint64_t boot_kern_l4pgdirs[NUM_LEVEL3_PDE][NUM_LEVEL4_PTE] __attribute__((aligned(0x1000))) = { 0 };
|
||||
|
||||
static void build_boot_pgdir()
|
||||
{
|
||||
uint64_t dev_phy_mem_base = DEV_PHYMEM_BASE;
|
||||
// dev mem
|
||||
boot_l2pgdir[(dev_phy_mem_base >> LEVEL2_PDE_SHIFT) & IDX_MASK] = (uint64_t)boot_dev_l3pgdir | L2_TYPE_TAB | L2_PTE_VALID;
|
||||
boot_l2pgdir[(MMIO_P2V_WO(dev_phy_mem_base) >> LEVEL2_PDE_SHIFT) & IDX_MASK] = (uint64_t)boot_dev_l3pgdir | L2_TYPE_TAB | L2_PTE_VALID;
|
||||
|
||||
uint64_t cur_mem_paddr = ALIGNDOWN((uint64_t)DEV_PHYMEM_BASE, PAGE_SIZE);
|
||||
for (size_t i = 0; i < NUM_LEVEL3_PDE; i++) {
|
||||
boot_dev_l3pgdir[i] = (uint64_t)boot_dev_l4pgdirs[i] | L3_TYPE_TAB | L3_PTE_VALID;
|
||||
|
||||
for (size_t j = 0; j < NUM_LEVEL4_PTE; j++) {
|
||||
boot_dev_l4pgdirs[i][j] = cur_mem_paddr | L4_TYPE_PAGE | L4_PTE_DEV | L4_PTE_AF | L4_PTE_XN;
|
||||
|
||||
cur_mem_paddr += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
// identical mem
|
||||
boot_l2pgdir[(PHY_MEM_BASE >> LEVEL2_PDE_SHIFT) & IDX_MASK] = (uint64_t)boot_kern_l3pgdir | L2_TYPE_TAB | L2_PTE_VALID;
|
||||
boot_l2pgdir[(P2V_WO(PHY_MEM_BASE) >> LEVEL2_PDE_SHIFT) & IDX_MASK] = (uint64_t)boot_kern_l3pgdir | L2_TYPE_TAB | L2_PTE_VALID;
|
||||
|
||||
cur_mem_paddr = ALIGNDOWN((uint64_t)PHY_MEM_BASE, PAGE_SIZE);
|
||||
for (size_t i = 0; i < NUM_LEVEL3_PDE; i++) {
|
||||
boot_kern_l3pgdir[i] = (uint64_t)boot_kern_l4pgdirs[i] | L3_TYPE_TAB | L3_PTE_VALID;
|
||||
|
||||
for (size_t j = 0; j < NUM_LEVEL4_PTE; j++) {
|
||||
boot_kern_l4pgdirs[i][j] = cur_mem_paddr | L4_TYPE_PAGE | L4_PTE_NORMAL | L4_PTE_AF;
|
||||
|
||||
cur_mem_paddr += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void load_boot_pgdir()
|
||||
{
|
||||
uint64_t val;
|
||||
|
||||
TTBR0_W((uintptr_t)boot_l2pgdir);
|
||||
TTBR1_W(0);
|
||||
|
||||
TCR_W(TCR_VALUE);
|
||||
MAIR_W((MT_DEVICE_nGnRnE << (8 * AI_DEVICE_nGnRnE_IDX)) | (MT_NORMAL_NC << (8 * AI_NORMAL_NC_IDX)));
|
||||
|
||||
// Enable paging using read/modify/write
|
||||
SCTLR_R(val);
|
||||
val |= (1 << 0); // EL1 and EL0 stage 1 address translation enabled.
|
||||
SCTLR_W(val);
|
||||
|
||||
// flush all TLB
|
||||
DSB();
|
||||
CLEARTLB(0);
|
||||
ISB();
|
||||
}
|
||||
|
||||
extern void main(void);
|
||||
static bool _bss_inited = false;
|
||||
void bootmain()
|
||||
{
|
||||
build_boot_pgdir();
|
||||
load_boot_pgdir();
|
||||
__asm__ __volatile__("add sp, sp, %0" ::"r"(KERN_MEM_BASE - PHY_MEM_BASE));
|
||||
if (!_bss_inited) {
|
||||
memset(&kernel_data_begin, 0x00, (size_t)((uint64_t)kernel_data_end - (uint64_t)kernel_data_begin));
|
||||
_bss_inited = true;
|
||||
}
|
||||
main();
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file mmu.h
|
||||
* @brief mmu related configure and registers
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024-04-26
|
||||
*/
|
||||
/*************************************************
|
||||
File name: mmu.h
|
||||
Description: mmu related configure and registers
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. first version
|
||||
*************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "memlayout.h"
|
||||
|
||||
// #define TCR_SH1_INNER (0b11 << 28)
|
||||
// #define TCR_ORGN1_IRGN1_WRITEBACK_WRITEALLOC ((0b01 << 26) | (0b01 << 24))
|
||||
// #define TCR_SH0_INNER (0b11 << 12)
|
||||
// #define TCR_ORGN0_IRGN0_WRITEBACK_WRITEALLOC ((0b01 << 10) | (0b01 << 8))
|
||||
#define TCR_IPS (0 << 0)
|
||||
#define TCR_TG1_4K (0b10 << 30)
|
||||
#define TCR_TOSZ (0b11001 << 0)
|
||||
#define TCR_T1SZ (0b11001 << 16)
|
||||
#define TCR_TG0_4K (0 << 14)
|
||||
|
||||
#define TCR_VALUE \
|
||||
(TCR_IPS | TCR_TG1_4K | TCR_TG0_4K | TCR_TOSZ | TCR_T1SZ)
|
||||
|
||||
enum AccessPermission {
|
||||
AccessPermission_NoAccess = 0,
|
||||
AccessPermission_KernelOnly = 1, // EL1
|
||||
AccessPermission_Reserved = 2,
|
||||
AccessPermission_KernelUser = 3, // EL1&EL0
|
||||
};
|
||||
|
||||
void GetDevPteAttr(uintptr_t* attr);
|
||||
void GetUsrPteAttr(uintptr_t* attr);
|
||||
void GetUsrDevPteAttr(uintptr_t* attr);
|
||||
void GetKernPteAttr(uintptr_t* attr);
|
||||
void GetPdeAttr(uintptr_t* attr);
|
||||
|
||||
/*
|
||||
Enable MMU, cache, write buffer, etc.
|
||||
*/
|
||||
#define SCTLR_R(val) __asm__ volatile("mrs %0, sctlr_el1" : "=r"(val))
|
||||
#define SCTLR_W(val) __asm__ volatile("msr sctlr_el1, %0" ::"r"(val))
|
||||
|
||||
/*
|
||||
Read and write mmu pagetable register base addr
|
||||
*/
|
||||
#define TTBR0_R(val) __asm__ volatile("mrs %0, ttbr0_el1" : "=r"(val))
|
||||
#define TTBR0_W(val) __asm__ volatile("msr ttbr0_el1, %0" ::"r"(val))
|
||||
|
||||
/*
|
||||
Read and write mmu pagetable register base addr
|
||||
*/
|
||||
#define TTBR1_R(val) __asm__ volatile("mrs %0, ttbr1_el1" : "=r"(val))
|
||||
#define TTBR1_W(val) __asm__ volatile("msr ttbr1_el1, %0" ::"r"(val))
|
||||
|
||||
/*
|
||||
Translation Control Register(TCR)
|
||||
*/
|
||||
#define TCR_R(val) __asm__ volatile("mrs %0, tcr_el1" : "=r"(val))
|
||||
#define TCR_W(val) __asm__ volatile("msr tcr_el1, %0" ::"r"(val))
|
||||
|
||||
#define MAIR_R(val) __asm__ volatile("mrs %0, mair_el1" : "=r"(val))
|
||||
#define MAIR_W(val) __asm__ volatile("msr mair_el1, %0" ::"r"(val))
|
||||
|
||||
/*
|
||||
Flush TLB when loading a new page table.
|
||||
@note If nG is not set in the pte attribute, process switching need flush tlb.
|
||||
*/
|
||||
#define CLEARTLB(val) __asm__ volatile("tlbi vmalle1")
|
||||
|
||||
/*
|
||||
When nG is set in the pte attribute, the process is assigned an ASID, which is stored in the lower 8 bits of the CONTEXTIDR register.
|
||||
When the process switches, the flush TLB is no longer required anymore.
|
||||
*/
|
||||
#define CONTEXTIDR_R(val) __asm__ volatile("mrs %0, contextidr_el1" : "=r"(val))
|
||||
#define CONTEXTIDR_W(val) __asm__ volatile("msr contextidr_el1, %0" ::"r"(val))
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
#include <stdint.h>
|
||||
__attribute__((always_inline)) static inline uint64_t v2p(void* a) { return ((uint64_t)(a)) - KERN_MEM_BASE; }
|
||||
__attribute__((always_inline)) static inline void* p2v(uint64_t a) { return (void*)((a) + KERN_MEM_BASE); }
|
||||
#endif
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
/**
|
||||
* @file mmu.c
|
||||
* @brief mmu operations
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024.04.26
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: mmu.c
|
||||
Description: mmu operations
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. first version
|
||||
*************************************************/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "mmu.h"
|
||||
|
||||
#include "cache_common_ope.h"
|
||||
#include "mmu_common.h"
|
||||
#include "trap_common.h"
|
||||
|
||||
// extern struct MmuCommonDone mmu_common_done;
|
||||
static struct MmuDriverRightGroup right_group;
|
||||
|
||||
void load_pgdir(uintptr_t pgdir_paddr)
|
||||
{
|
||||
/* get cache driver */
|
||||
struct ICacheDone* p_icache_done = AchieveResource(&right_group.icache_driver_tag);
|
||||
struct DCacheDone* p_dcache_done = AchieveResource(&right_group.dcache_driver_tag);
|
||||
|
||||
TTBR0_W((uint64_t)pgdir_paddr);
|
||||
CLEARTLB(0);
|
||||
p_icache_done->invalidateall();
|
||||
p_dcache_done->flushall();
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) inline static void _tlb_flush(uintptr_t va)
|
||||
{
|
||||
__asm__ volatile("tlbi vae1is, %0" ::"r"(va));
|
||||
}
|
||||
|
||||
static void tlb_flush_range(uintptr_t vstart, int len)
|
||||
{
|
||||
uintptr_t vaddr = vstart;
|
||||
uintptr_t vend = vaddr + len;
|
||||
for (; vaddr < vend; vaddr += PAGE_SIZE) {
|
||||
_tlb_flush(vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
static void tlb_flush_all()
|
||||
{
|
||||
CLEARTLB(0);
|
||||
}
|
||||
|
||||
static struct MmuCommonDone mmu_common_done = {
|
||||
.MmuDevPteAttr = GetDevPteAttr,
|
||||
.MmuPdeAttr = GetPdeAttr,
|
||||
.MmuUsrPteAttr = GetUsrPteAttr,
|
||||
.MmuUsrDevPteAttr = GetUsrDevPteAttr,
|
||||
.MmuKernPteAttr = GetKernPteAttr,
|
||||
|
||||
.LoadPgdir = load_pgdir,
|
||||
.TlbFlushAll = tlb_flush_all,
|
||||
.TlbFlush = tlb_flush_range,
|
||||
};
|
||||
|
||||
struct MmuCommonDone* hardkernel_mmu_init(struct TraceTag* hardkernel_tag, char* icache_name, char* dcache_name)
|
||||
{
|
||||
/* init right group for mmu driver */
|
||||
AchieveResourceTag(&right_group.icache_driver_tag, hardkernel_tag, icache_name);
|
||||
AchieveResourceTag(&right_group.dcache_driver_tag, hardkernel_tag, dcache_name);
|
||||
|
||||
return &mmu_common_done;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file memlayout.h
|
||||
* @brief virtual memory and physical memory layout
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024-04-25
|
||||
*/
|
||||
/*************************************************
|
||||
File name: memlayout.h
|
||||
Description: virtual memory and physical memory layout
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. first version
|
||||
*************************************************/
|
||||
#pragma once
|
||||
|
||||
// Memory layout
|
||||
// clang-format off
|
||||
|
||||
#define ARCH_BIT 64
|
||||
|
||||
/* A72 physical memory layout */
|
||||
#define PHY_MEM_BASE (0x0000000040000000ULL)
|
||||
#define PHY_USER_FREEMEM_BASE (0x0000000046000000ULL)
|
||||
#define PHY_USER_FREEMEM_TOP (0x0000000048000000ULL)
|
||||
#define PHY_MEM_STOP (0x0000000048000000ULL)
|
||||
|
||||
/* PTE-PAGE_SIZE */
|
||||
#define LEVEL4_PTE_SHIFT 12
|
||||
#define LEVEL4_PTE_SIZE (1 << LEVEL4_PTE_SHIFT)
|
||||
|
||||
/* PDE-SECTION_SIZE */
|
||||
#define LEVEL3_PDE_SHIFT 21
|
||||
#define LEVEL3_PDE_SIZE (1 << LEVEL3_PDE_SHIFT)
|
||||
|
||||
#define LEVEL2_PDE_SHIFT 30
|
||||
#define LEVEL2_PDE_SIZE (1 << LEVEL2_PDE_SHIFT)
|
||||
|
||||
#define LEVEL1_PTE_SHIFT 39
|
||||
|
||||
#define NUM_LEVEL2_PDE (1 << (LEVEL1_PTE_SHIFT - LEVEL2_PDE_SHIFT))
|
||||
#define NUM_LEVEL3_PDE (1 << (LEVEL2_PDE_SHIFT - LEVEL3_PDE_SHIFT)) // how many PDE in a PT
|
||||
#define NUM_LEVEL4_PTE (1 << (LEVEL3_PDE_SHIFT - LEVEL4_PTE_SHIFT)) // how many PTE in a PT
|
||||
#define NUM_TOPLEVEL_PDE NUM_LEVEL2_PDE
|
||||
|
||||
#define PAGE_SIZE LEVEL4_PTE_SIZE
|
||||
#define MAX_NR_FREE_PAGES ((PHY_MEM_STOP - PHY_MEM_BASE) >> LEVEL4_PTE_SHIFT)
|
||||
|
||||
/* Deivce memory layout */
|
||||
#define DEV_PHYMEM_BASE (0x0000000000000000ULL)
|
||||
#define DEV_VRTMEM_BASE (0x0000004000000000ULL)
|
||||
#define DEV_MEM_SZ (0x0000000010000000ULL)
|
||||
|
||||
/* User memory layout */
|
||||
#define USER_STACK_SIZE PAGE_SIZE
|
||||
#define USER_MEM_BASE (0x0000000000000000ULL)
|
||||
#define USER_MEM_TOP DEV_VRTMEM_BASE
|
||||
#define USER_IPC_SPACE_BASE (0x0000003000000000ULL)
|
||||
#define USER_IPC_USE_ALLOCATOR_WATERMARK (0x0000003000010000ULL)
|
||||
#define USER_IPC_SPACE_TOP (USER_IPC_SPACE_BASE + 0x10000000ULL)
|
||||
|
||||
/* Kernel memory layout */
|
||||
#define KERN_MEM_BASE (0x0000006040000000ULL) // First kernel virtual address
|
||||
#define KERN_OFFSET (KERN_MEM_BASE - PHY_MEM_BASE)
|
||||
|
||||
#define V2P(a) (((uint64_t)(a)) - KERN_OFFSET)
|
||||
#define P2V(a) ((void *)(((char *)(a)) + KERN_OFFSET))
|
||||
|
||||
#define V2P_WO(x) ((x) - KERN_OFFSET) // same as V2P, but without casts
|
||||
#define P2V_WO(x) ((x) + KERN_OFFSET) // same as P2V, but without casts
|
||||
// clang-format on
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
/**
|
||||
* @file pagetable_attr.c
|
||||
* @brief mmu entry attributes
|
||||
* @version 1.
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2023.04.26
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: pagetable_attr.c
|
||||
Description: mmu entry attributes
|
||||
Others:
|
||||
History:
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. first version
|
||||
*************************************************/
|
||||
#include "mmu.h"
|
||||
#include "mmu_common.h"
|
||||
|
||||
// clang-format off
|
||||
#define ARMV8_PTE_ATTR_MASK(attr) (((attr) & 0b111) << 2)
|
||||
#define ARMV8_PTE_DEVICE ARMV8_PTE_ATTR_MASK(0x0)
|
||||
#define ARMV8_PTE_NORMAL ARMV8_PTE_ATTR_MASK(0x1)
|
||||
|
||||
#define ARMV8_PTE_AP(ap) (((ap) & 0b11) << 6)
|
||||
#define ARMV8_PTE_AP_U ARMV8_PTE_AP(0x01)
|
||||
#define ARMV8_PTE_AP_K ARMV8_PTE_AP(0x00)
|
||||
#define ARMV8_PTE_AP_RO ARMV8_PTE_AP(0b10)
|
||||
#define ARMV8_PTE_AP_RW ARMV8_PTE_AP(0b00)
|
||||
|
||||
#define ARMV8_PTE_AF (0x1 << 10)
|
||||
#define ARMV8_PTE_PXN (1ULL << 53) // Privileged eXecute Never
|
||||
#define ARMV8_PTE_UXN (1ULL << 54) // Unprivileged(user) eXecute Never
|
||||
#define ARMV8_PTE_XN (ARMV8_PTE_PXN | ARMV8_PTE_UXN)
|
||||
|
||||
#define ARMV8_PTE_VALID (0b11 << 0)
|
||||
#define ARMV8_PDE_VALID (0b11 << 0)
|
||||
|
||||
// clang-format on
|
||||
|
||||
void GetUsrPteAttr(uintptr_t* attr)
|
||||
{
|
||||
*attr = ARMV8_PTE_AP_U | ARMV8_PTE_AP_RW | ARMV8_PTE_AF | ARMV8_PTE_NORMAL | ARMV8_PTE_VALID;
|
||||
}
|
||||
|
||||
void GetUsrDevPteAttr(uintptr_t* attr)
|
||||
{
|
||||
*attr = ARMV8_PTE_AP_U | ARMV8_PTE_AP_RW | ARMV8_PTE_AF | ARMV8_PTE_DEVICE | ARMV8_PTE_XN | ARMV8_PTE_VALID;
|
||||
}
|
||||
|
||||
void GetDevPteAttr(uintptr_t* attr)
|
||||
{
|
||||
*attr = ARMV8_PTE_AP_K | ARMV8_PTE_AP_RW | ARMV8_PTE_AF | ARMV8_PTE_DEVICE | ARMV8_PTE_XN | ARMV8_PTE_VALID;
|
||||
}
|
||||
|
||||
void GetKernPteAttr(uintptr_t* attr)
|
||||
{
|
||||
*attr = ARMV8_PTE_AP_K | ARMV8_PTE_AP_RW | ARMV8_PTE_AF | ARMV8_PTE_NORMAL | ARMV8_PTE_VALID;
|
||||
}
|
||||
|
||||
void GetPdeAttr(uintptr_t* attr)
|
||||
{
|
||||
*attr = ARMV8_PDE_VALID;
|
||||
}
|
||||
@@ -19,15 +19,13 @@ struct MmuDriverRightGroup {
|
||||
struct TraceTag intr_driver_tag;
|
||||
};
|
||||
|
||||
struct MmuCommonDone
|
||||
{
|
||||
struct MmuCommonDone {
|
||||
void (*MmuDevPteAttr)(uintptr_t* attr);
|
||||
void (*MmuPdeAttr)(uintptr_t* attr);
|
||||
void (*MmuUsrPteAttr)(uintptr_t* attr);
|
||||
void (*MmuUsrDevPteAttr)(uintptr_t* attr);
|
||||
void (*MmuKernPteAttr)(uintptr_t* attr);
|
||||
|
||||
void (*LoadPgdirCrit)(uintptr_t pgdir_paddr, struct TraceTag*);
|
||||
void (*LoadPgdir)(uintptr_t pgdir_paddr);
|
||||
void (*TlbFlushAll)();
|
||||
void (*TlbFlush)(uintptr_t vaddr, int len);
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
# The following three platforms support compatiable instructions.
|
||||
ifneq ($(findstring $(BOARD), ok1028a-c), )
|
||||
SRC_DIR := armv8-a
|
||||
endif
|
||||
ifneq ($(findstring $(BOARD), imx6q-sabrelite zynq7000-zc702), )
|
||||
SRC_DIR := armv7-a
|
||||
endif
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
|
||||
/**
|
||||
* @file iomux_v3.h
|
||||
* @brief support imx6q iomux function define, reference from u-boot-2009-08/include/asm-arm/arch-mx6/iomux_v3.h
|
||||
* @brief support imx6q iomux function define, reference from u-boot-2009-08/include/__asm__-arm/arch-mx6/iomux_v3.h
|
||||
* @version 3.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2023.09.08
|
||||
*/
|
||||
/*************************************************
|
||||
File name: iomux_v3.h
|
||||
Description: support imx6q iomux function define, reference from u-boot-2009-08/include/asm-arm/arch-mx6/iomux_v3.h
|
||||
Description: support imx6q iomux function define, reference from u-boot-2009-08/include/__asm__-arm/arch-mx6/iomux_v3.h
|
||||
Others:
|
||||
History:
|
||||
1. Date: 2023-09-08
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
|
||||
/**
|
||||
* @file regs_pins.h
|
||||
* @brief support imx6q pin map define, reference from u-boot-2009-08/include/asm-arm/arch-mx6/mx6_pins.h
|
||||
* @brief support imx6q pin map define, reference from u-boot-2009-08/include/__asm__-arm/arch-mx6/mx6_pins.h
|
||||
* @version 3.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2023.09.08
|
||||
*/
|
||||
/*************************************************
|
||||
File name: regs_pins.h
|
||||
Description: support imx6q pin map define, reference from u-boot-2009-08/include/asm-arm/arch-mx6/mx6_pins.h
|
||||
Description: support imx6q pin map define, reference from u-boot-2009-08/include/__asm__-arm/arch-mx6/mx6_pins.h
|
||||
Others:
|
||||
History:
|
||||
1. Date: 2023-09-08
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# The following three platforms support compatiable instructions.
|
||||
SRC_DIR := cortex-a72
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,3 @@
|
||||
SRC_DIR := uart_io_for_$(BOARD)
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,3 @@
|
||||
SRC_FILES := uart.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "memlayout.h"
|
||||
#include "mmio_access.h"
|
||||
|
||||
#define UART0_BASE (0x09000000ULL)
|
||||
#define UART0_REG(reg) ((volatile uint32_t*)(MMIO_P2V_WO(UART0_BASE + reg)))
|
||||
|
||||
// the UART control registers.
|
||||
// pl011
|
||||
#define DR 0x00
|
||||
#define FR 0x18
|
||||
#define FR_RXFE (1 << 4) // recieve fifo empty
|
||||
#define FR_TXFF (1 << 5) // transmit fifo full
|
||||
#define FR_RXFF (1 << 6) // recieve fifo full
|
||||
#define FR_TXFE (1 << 7) // transmit fifo empty
|
||||
#define IBRD 0x24
|
||||
#define FBRD 0x28
|
||||
#define LCRH 0x2c
|
||||
#define LCRH_FEN (1 << 4)
|
||||
#define LCRH_WLEN_8BIT (3 << 5)
|
||||
#define CR 0x30
|
||||
#define IMSC 0x38
|
||||
#define INT_RX_ENABLE (1 << 4)
|
||||
#define INT_TX_ENABLE (1 << 5)
|
||||
#define ICR 0x44
|
||||
|
||||
#define UART_READ_REG(reg) (*(UART0_REG(reg)))
|
||||
#define UART_WRITE_REG(reg, v) (*(UART0_REG(reg)) = (v))
|
||||
@@ -0,0 +1,128 @@
|
||||
//
|
||||
// low-level driver routines for pl011 UART.
|
||||
//
|
||||
|
||||
#include "uart.h"
|
||||
#include "actracer.h"
|
||||
#include "uart_common_ope.h"
|
||||
|
||||
// the UART control registers are memory-mapped
|
||||
// at address UART0. this macro returns the
|
||||
// address of one of the registers.
|
||||
|
||||
// the transmit output buffer.
|
||||
#define UART_TX_BUF_SIZE 32
|
||||
static char uart_tx_buf[UART_TX_BUF_SIZE];
|
||||
uint64_t uart_tx_w; // write next to uart_tx_buf[uart_tx_w % UART_TX_BUF_SIZE]
|
||||
uint64_t uart_tx_r; // read next from uart_tx_buf[uart_tx_r % UART_TX_BUF_SIZE]
|
||||
|
||||
void uartinit(void)
|
||||
{
|
||||
// disable uart
|
||||
UART_WRITE_REG(CR, 0);
|
||||
|
||||
// disable interrupts.
|
||||
UART_WRITE_REG(IMSC, 0);
|
||||
|
||||
// in qemu, it is not necessary to set baudrate.
|
||||
// enable FIFOs.
|
||||
// set word length to 8 bits, no parity.
|
||||
UART_WRITE_REG(LCRH, LCRH_FEN | LCRH_WLEN_8BIT);
|
||||
|
||||
// enable RXE, TXE and enable uart.
|
||||
UART_WRITE_REG(CR, 0x301);
|
||||
|
||||
// enable transmit and receive interrupts.
|
||||
UART_WRITE_REG(IMSC, INT_RX_ENABLE | INT_TX_ENABLE);
|
||||
}
|
||||
|
||||
// if the UART is idle, and a character is waiting
|
||||
// in the transmit buffer, send it.
|
||||
// caller must hold uart_tx_lock.
|
||||
// called from both the top- and bottom-half.
|
||||
void uartstart()
|
||||
{
|
||||
while (1) {
|
||||
if (uart_tx_w == uart_tx_r) {
|
||||
// transmit buffer is empty.
|
||||
return;
|
||||
}
|
||||
|
||||
if (UART_READ_REG(FR) & FR_TXFF) {
|
||||
// the UART transmit holding register is full,
|
||||
// so we cannot give it another byte.
|
||||
// it will interrupt when it's ready for a new byte.
|
||||
return;
|
||||
}
|
||||
|
||||
int c = uart_tx_buf[uart_tx_r % UART_TX_BUF_SIZE];
|
||||
uart_tx_r += 1;
|
||||
|
||||
// maybe uartputc() is waiting for space in the buffer.
|
||||
|
||||
UART_WRITE_REG(DR, c);
|
||||
}
|
||||
}
|
||||
|
||||
// add a character to the output buffer and tell the
|
||||
// UART to start sending if it isn't already.
|
||||
// blocks if the output buffer is full.
|
||||
// because it may block, it can't be called
|
||||
// from interrupts; it's only suitable for use
|
||||
// by write().
|
||||
void uartputc(uint8_t c)
|
||||
{
|
||||
while (uart_tx_w == uart_tx_r + UART_TX_BUF_SIZE)
|
||||
;
|
||||
uart_tx_buf[uart_tx_w % UART_TX_BUF_SIZE] = c;
|
||||
uart_tx_w += 1;
|
||||
uartstart();
|
||||
return;
|
||||
}
|
||||
|
||||
// read one input character from the UART.
|
||||
// return -1 if none is waiting.
|
||||
static uint8_t uartgetc(void)
|
||||
{
|
||||
if (UART_READ_REG(FR) & FR_RXFE)
|
||||
return 0xFF;
|
||||
else
|
||||
return UART_READ_REG(DR);
|
||||
}
|
||||
|
||||
// handle a uart interrupt, raised because input has
|
||||
// arrived, or the uart is ready for more output, or
|
||||
// both. called from trap.c.
|
||||
void uartintr(void)
|
||||
{
|
||||
// read and process incoming characters.
|
||||
while (1) {
|
||||
int c = uartgetc();
|
||||
if (c == 0xFF)
|
||||
break;
|
||||
}
|
||||
|
||||
// send buffered characters.
|
||||
uartstart();
|
||||
|
||||
// clear transmit and receive interrupts.
|
||||
UART_WRITE_REG(ICR, INT_RX_ENABLE | INT_TX_ENABLE);
|
||||
}
|
||||
|
||||
static uint32_t UartGetIrqnum()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct XiziSerialDriver hardkernel_serial_driver = {
|
||||
.sys_serial_init = uartinit,
|
||||
.get_serial_irqnum = UartGetIrqnum,
|
||||
.putc = uartputc,
|
||||
.getc = uartgetc,
|
||||
};
|
||||
|
||||
struct XiziSerialDriver* hardkernel_uart_init(struct TraceTag* hardkernel_tag)
|
||||
{
|
||||
hardkernel_serial_driver.sys_serial_init();
|
||||
return &hardkernel_serial_driver;
|
||||
}
|
||||
102
Ubiquitous/XiZi_AIoT/hardkernel/uart/printf.h
Normal file
102
Ubiquitous/XiZi_AIoT/hardkernel/uart/printf.h
Normal file
@@ -0,0 +1,102 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// \author (c) Marco Paland (info@paland.com)
|
||||
// 2014-2019, PALANDesign Hannover, Germany
|
||||
//
|
||||
// \license The MIT License (MIT)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
|
||||
// embedded systems with a very limited resources.
|
||||
// Use this instead of bloated standard/newlib printf.
|
||||
// These routines are thread safe and reentrant.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _PRINTF_H_
|
||||
#define _PRINTF_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Tiny printf implementation
|
||||
* You have to implement _putchar if you use printf()
|
||||
* To avoid conflicts with the regular printf() API it is overridden by macro defines
|
||||
* and internal underscore-appended functions like printf_() are used
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are written into the array, not counting the terminating null character
|
||||
*/
|
||||
#define KPrintf printf_
|
||||
#define printf printf_
|
||||
int printf_(const char* format, ...);
|
||||
|
||||
/**
|
||||
* Tiny sprintf implementation
|
||||
* Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD!
|
||||
* \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output!
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
||||
*/
|
||||
#define sprintf sprintf_
|
||||
int sprintf_(char* buffer, const char* format, ...);
|
||||
|
||||
/**
|
||||
* Tiny snprintf/vsnprintf implementation
|
||||
* \param buffer A pointer to the buffer where to store the formatted string
|
||||
* \param count The maximum number of characters to store in the buffer, including a terminating null character
|
||||
* \param format A string that specifies the format of the output
|
||||
* \param va A value identifying a variable arguments list
|
||||
* \return The number of characters that COULD have been written into the buffer, not counting the terminating
|
||||
* null character. A value equal or larger than count indicates truncation. Only when the returned value
|
||||
* is non-negative and less than count, the string has been completely written.
|
||||
*/
|
||||
#define snprintf snprintf_
|
||||
#define vsnprintf vsnprintf_
|
||||
int snprintf_(char* buffer, size_t count, const char* format, ...);
|
||||
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va);
|
||||
|
||||
/**
|
||||
* Tiny vprintf implementation
|
||||
* \param format A string that specifies the format of the output
|
||||
* \param va A value identifying a variable arguments list
|
||||
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
||||
*/
|
||||
#define vprintf vprintf_
|
||||
int vprintf_(const char* format, va_list va);
|
||||
|
||||
/**
|
||||
* printf with output function
|
||||
* You may use this as dynamic alternative to printf() with its fixed _putchar() output
|
||||
* \param out An output function which takes one character and an argument pointer
|
||||
* \param arg An argument pointer for user data passed to output function
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are sent to the output function, not counting the terminating null character
|
||||
*/
|
||||
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _PRINTF_H_
|
||||
@@ -1,15 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// \author (c) Marco Paland (info@paland.com)
|
||||
// 2014-2019, PALANDesign Hannover, Germany
|
||||
//
|
||||
// \license The MIT License (MIT)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
|
||||
// embedded systems with a very limited resources. These routines are thread
|
||||
// safe and reentrant!
|
||||
// Use this instead of the bloated standard/newlib printf cause these use
|
||||
// malloc for printf (and may not be thread safe).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* @file uart_common_ope.c
|
||||
* @brief support uart common operation
|
||||
@@ -17,8 +36,10 @@
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2023.11.20
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "uart_common_ope.h"
|
||||
#include "assert.h"
|
||||
|
||||
struct PrintProxy {
|
||||
struct TraceTag uart_driver_tag;
|
||||
@@ -38,85 +59,840 @@ int serial_init(struct TraceTag* uart_driver_tag)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void PrintInt(int xx, int base, int sign)
|
||||
// 'ntoa' conversion buffer size, this must be big enough to hold one converted
|
||||
// numeric number including padded zeros (dynamically created on stack)
|
||||
// default: 32 byte
|
||||
#define PRINTF_NTOA_BUFFER_SIZE 32U
|
||||
|
||||
#define PRINTF_FTOA_BUFFER_SIZE 32U
|
||||
|
||||
// support for the floating point type (%f)
|
||||
// default: activated
|
||||
#define PRINTF_SUPPORT_FLOAT
|
||||
|
||||
// support for exponential floating point notation (%e/%g)
|
||||
// default: activated
|
||||
#define PRINTF_SUPPORT_EXPONENTIAL
|
||||
|
||||
// define the default floating point precision
|
||||
// default: 6 digits
|
||||
#define PRINTF_DEFAULT_FLOAT_PRECISION 6U
|
||||
|
||||
// define the largest float suitable to print with %f
|
||||
// default: 1e9
|
||||
#define PRINTF_MAX_FLOAT 1e9
|
||||
|
||||
// support for the long long types (%llu or %p)
|
||||
// default: activated
|
||||
#define PRINTF_SUPPORT_LONG_LONG
|
||||
|
||||
// support for the ptrdiff_t type (%t)
|
||||
// ptrdiff_t is normally defined in <stddef.h> as long or long long type
|
||||
// default: activated
|
||||
#define PRINTF_SUPPORT_PTRDIFF_T
|
||||
|
||||
#define _putchar proxy()->serial->putc
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// internal flag definitions
|
||||
#define FLAGS_ZEROPAD (1U << 0U)
|
||||
#define FLAGS_LEFT (1U << 1U)
|
||||
#define FLAGS_PLUS (1U << 2U)
|
||||
#define FLAGS_SPACE (1U << 3U)
|
||||
#define FLAGS_HASH (1U << 4U)
|
||||
#define FLAGS_UPPERCASE (1U << 5U)
|
||||
#define FLAGS_CHAR (1U << 6U)
|
||||
#define FLAGS_SHORT (1U << 7U)
|
||||
#define FLAGS_LONG (1U << 8U)
|
||||
#define FLAGS_LONG_LONG (1U << 9U)
|
||||
#define FLAGS_PRECISION (1U << 10U)
|
||||
#define FLAGS_ADAPT_EXP (1U << 11U)
|
||||
|
||||
// import float.h for DBL_MAX
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
#include <float.h>
|
||||
#endif
|
||||
|
||||
// output function type
|
||||
typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen);
|
||||
|
||||
// wrapper (used as buffer) for output function type
|
||||
typedef struct {
|
||||
void (*fct)(char character, void* arg);
|
||||
void* arg;
|
||||
} out_fct_wrap_type;
|
||||
|
||||
// internal buffer output
|
||||
static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
static char digits[] = "0123456789ABCDEF";
|
||||
char buf[16];
|
||||
int i;
|
||||
uint32_t x;
|
||||
|
||||
if (sign && (sign = xx < 0)) {
|
||||
x = -xx;
|
||||
} else {
|
||||
x = xx;
|
||||
if (idx < maxlen) {
|
||||
((char*)buffer)[idx] = character;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
|
||||
do {
|
||||
buf[i++] = digits[x % base];
|
||||
} while ((x /= base) != 0);
|
||||
|
||||
if (sign)
|
||||
buf[i++] = '-';
|
||||
|
||||
while (--i >= 0)
|
||||
proxy()->serial->putc(buf[i]);
|
||||
}
|
||||
|
||||
void KPrintf(char* fmt, ...)
|
||||
// internal null output
|
||||
static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
int i, c;
|
||||
uint32_t* argp;
|
||||
char* s;
|
||||
(void)character;
|
||||
(void)buffer;
|
||||
(void)idx;
|
||||
(void)maxlen;
|
||||
}
|
||||
|
||||
if (fmt == 0) {
|
||||
KPrintf("null fmt");
|
||||
return;
|
||||
// internal _putchar wrapper
|
||||
static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
(void)buffer;
|
||||
(void)idx;
|
||||
(void)maxlen;
|
||||
if (character) {
|
||||
_putchar(character);
|
||||
}
|
||||
}
|
||||
|
||||
// internal output function wrapper
|
||||
static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
(void)idx;
|
||||
(void)maxlen;
|
||||
if (character) {
|
||||
// buffer is the output fct pointer
|
||||
((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg);
|
||||
}
|
||||
}
|
||||
|
||||
// internal secure strlen
|
||||
// \return The length of the string (excluding the terminating 0) limited by 'maxsize'
|
||||
static inline unsigned int _strnlen_s(const char* str, size_t maxsize)
|
||||
{
|
||||
const char* s;
|
||||
for (s = str; *s && maxsize--; ++s)
|
||||
;
|
||||
return (unsigned int)(s - str);
|
||||
}
|
||||
|
||||
// internal test if char is a digit (0-9)
|
||||
// \return true if char is a digit
|
||||
static inline bool _is_digit(char ch)
|
||||
{
|
||||
return (ch >= '0') && (ch <= '9');
|
||||
}
|
||||
|
||||
// internal ASCII string to unsigned int conversion
|
||||
static unsigned int _atoi(const char** str)
|
||||
{
|
||||
unsigned int i = 0U;
|
||||
while (_is_digit(**str)) {
|
||||
i = i * 10U + (unsigned int)(*((*str)++) - '0');
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
// output the specified string in reverse, taking care of any zero-padding
|
||||
static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags)
|
||||
{
|
||||
const size_t start_idx = idx;
|
||||
|
||||
// pad spaces up to given width
|
||||
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
|
||||
for (size_t i = len; i < width; i++) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
|
||||
argp = (uint32_t*)(void*)(&fmt + 1);
|
||||
// reverse string
|
||||
while (len) {
|
||||
out(buf[--len], buffer, idx++, maxlen);
|
||||
}
|
||||
|
||||
for (i = 0; (c = fmt[i] & 0xff) != 0; i++) {
|
||||
if (c != '%') {
|
||||
proxy()->serial->putc(c);
|
||||
// append pad spaces up to given width
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (idx - start_idx < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
// internal itoa format
|
||||
static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
// pad leading zeros
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
// handle hash
|
||||
if (flags & FLAGS_HASH) {
|
||||
if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
|
||||
len--;
|
||||
if (len && (base == 16U)) {
|
||||
len--;
|
||||
}
|
||||
}
|
||||
if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'x';
|
||||
} else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'X';
|
||||
} else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'b';
|
||||
}
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
} else if (flags & FLAGS_PLUS) {
|
||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||
} else if (flags & FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||
}
|
||||
|
||||
// internal itoa for 'long' type
|
||||
static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
|
||||
// no hash for 0 values
|
||||
if (!value) {
|
||||
flags &= ~FLAGS_HASH;
|
||||
}
|
||||
|
||||
// write if precision != 0 and value is != 0
|
||||
if (!(flags & FLAGS_PRECISION) || value) {
|
||||
do {
|
||||
const char digit = (char)(value % base);
|
||||
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
value /= base;
|
||||
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||
}
|
||||
|
||||
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
||||
}
|
||||
|
||||
// internal itoa for 'long long' type
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
|
||||
// no hash for 0 values
|
||||
if (!value) {
|
||||
flags &= ~FLAGS_HASH;
|
||||
}
|
||||
|
||||
// write if precision != 0 and value is != 0
|
||||
if (!(flags & FLAGS_PRECISION) || value) {
|
||||
do {
|
||||
const char digit = (char)(value % base);
|
||||
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
value /= base;
|
||||
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||
}
|
||||
|
||||
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
||||
}
|
||||
#endif // PRINTF_SUPPORT_LONG_LONG
|
||||
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT
|
||||
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags);
|
||||
#endif
|
||||
|
||||
// internal ftoa for fixed decimal floating point
|
||||
static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
char buf[PRINTF_FTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
double diff = 0.0;
|
||||
|
||||
// powers of 10
|
||||
static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||
|
||||
// test for special values
|
||||
if (value != value)
|
||||
return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags);
|
||||
if (value < -DBL_MAX)
|
||||
return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags);
|
||||
if (value > DBL_MAX)
|
||||
return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
|
||||
|
||||
// test for very large values
|
||||
// standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad
|
||||
if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) {
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
return _etoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||
#else
|
||||
return 0U;
|
||||
#endif
|
||||
}
|
||||
|
||||
// test for negative
|
||||
bool negative = false;
|
||||
if (value < 0) {
|
||||
negative = true;
|
||||
value = 0 - value;
|
||||
}
|
||||
|
||||
// set default precision, if not set explicitly
|
||||
if (!(flags & FLAGS_PRECISION)) {
|
||||
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||
}
|
||||
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
|
||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
|
||||
buf[len++] = '0';
|
||||
prec--;
|
||||
}
|
||||
|
||||
int whole = (int)value;
|
||||
double tmp = (value - whole) * pow10[prec];
|
||||
unsigned long frac = (unsigned long)tmp;
|
||||
diff = tmp - frac;
|
||||
|
||||
if (diff > 0.5) {
|
||||
++frac;
|
||||
// handle rollover, e.g. case 0.99 with prec 1 is 1.0
|
||||
if (frac >= pow10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
} else if (diff < 0.5) {
|
||||
} else if ((frac == 0U) || (frac & 1U)) {
|
||||
// if halfway, round up if odd OR if last digit is 0
|
||||
++frac;
|
||||
}
|
||||
|
||||
if (prec == 0U) {
|
||||
diff = value - (double)whole;
|
||||
if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
|
||||
// exactly 0.5 and ODD, then round up
|
||||
// 1.5 -> 2, but 2.5 -> 2
|
||||
++whole;
|
||||
}
|
||||
} else {
|
||||
unsigned int count = prec;
|
||||
// now do fractional part, as an unsigned number
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
--count;
|
||||
buf[len++] = (char)(48U + (frac % 10U));
|
||||
if (!(frac /= 10U)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// add extra 0s
|
||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
// add decimal
|
||||
buf[len++] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
// do whole part, number is reversed
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
buf[len++] = (char)(48 + (whole % 10));
|
||||
if (!(whole /= 10)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// pad leading zeros
|
||||
if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
|
||||
if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
} else if (flags & FLAGS_PLUS) {
|
||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||
} else if (flags & FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||
}
|
||||
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com>
|
||||
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
// check for NaN and special values
|
||||
if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) {
|
||||
return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||
}
|
||||
|
||||
// determine the sign
|
||||
const bool negative = value < 0;
|
||||
if (negative) {
|
||||
value = -value;
|
||||
}
|
||||
|
||||
// default precision
|
||||
if (!(flags & FLAGS_PRECISION)) {
|
||||
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||
}
|
||||
|
||||
// determine the decimal exponent
|
||||
// based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
|
||||
union {
|
||||
uint64_t U;
|
||||
double F;
|
||||
} conv;
|
||||
|
||||
conv.F = value;
|
||||
int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2
|
||||
conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
|
||||
// now approximate log10 from the log2 integer part and an expansion of ln around 1.5
|
||||
int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168);
|
||||
// now we want to compute 10^expval but we want to be sure it won't overflow
|
||||
exp2 = (int)(expval * 3.321928094887362 + 0.5);
|
||||
const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
|
||||
const double z2 = z * z;
|
||||
conv.U = (uint64_t)(exp2 + 1023) << 52U;
|
||||
// compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
|
||||
conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
|
||||
// correct for rounding errors
|
||||
if (value < conv.F) {
|
||||
expval--;
|
||||
conv.F /= 10;
|
||||
}
|
||||
|
||||
// the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
|
||||
unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U;
|
||||
|
||||
// in "%g" mode, "prec" is the number of *significant figures* not decimals
|
||||
if (flags & FLAGS_ADAPT_EXP) {
|
||||
// do we want to fall-back to "%f" mode?
|
||||
if ((value >= 1e-4) && (value < 1e6)) {
|
||||
if ((int)prec > expval) {
|
||||
prec = (unsigned)((int)prec - expval - 1);
|
||||
} else {
|
||||
prec = 0;
|
||||
}
|
||||
flags |= FLAGS_PRECISION; // make sure _ftoa respects precision
|
||||
// no characters in exponent
|
||||
minwidth = 0U;
|
||||
expval = 0;
|
||||
} else {
|
||||
// we use one sigfig for the whole part
|
||||
if ((prec > 0) && (flags & FLAGS_PRECISION)) {
|
||||
--prec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// will everything fit?
|
||||
unsigned int fwidth = width;
|
||||
if (width > minwidth) {
|
||||
// we didn't fall-back so subtract the characters required for the exponent
|
||||
fwidth -= minwidth;
|
||||
} else {
|
||||
// not enough characters, so go back to default sizing
|
||||
fwidth = 0U;
|
||||
}
|
||||
if ((flags & FLAGS_LEFT) && minwidth) {
|
||||
// if we're padding on the right, DON'T pad the floating part
|
||||
fwidth = 0U;
|
||||
}
|
||||
|
||||
// rescale the float value
|
||||
if (expval) {
|
||||
value /= conv.F;
|
||||
}
|
||||
|
||||
// output the floating part
|
||||
const size_t start_idx = idx;
|
||||
idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP);
|
||||
|
||||
// output the exponent part
|
||||
if (minwidth) {
|
||||
// output the exponential symbol
|
||||
out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen);
|
||||
// output the exponent value
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth - 1, FLAGS_ZEROPAD | FLAGS_PLUS);
|
||||
// might need to right-pad spaces
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (idx - start_idx < width)
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif // PRINTF_SUPPORT_FLOAT
|
||||
|
||||
// internal vsnprintf
|
||||
static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va)
|
||||
{
|
||||
unsigned int flags, width, precision, n;
|
||||
size_t idx = 0U;
|
||||
|
||||
if (!buffer) {
|
||||
// use null output function
|
||||
out = _out_null;
|
||||
}
|
||||
|
||||
while (*format) {
|
||||
// format specifier? %[flags][width][.precision][length]
|
||||
if (*format != '%') {
|
||||
// no
|
||||
out(*format, buffer, idx++, maxlen);
|
||||
format++;
|
||||
continue;
|
||||
} else {
|
||||
// yes, evaluate it
|
||||
format++;
|
||||
}
|
||||
|
||||
c = fmt[++i] & 0xff;
|
||||
// evaluate flags
|
||||
flags = 0U;
|
||||
do {
|
||||
switch (*format) {
|
||||
case '0':
|
||||
flags |= FLAGS_ZEROPAD;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
case '-':
|
||||
flags |= FLAGS_LEFT;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
case '+':
|
||||
flags |= FLAGS_PLUS;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
case ' ':
|
||||
flags |= FLAGS_SPACE;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
case '#':
|
||||
flags |= FLAGS_HASH;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
default:
|
||||
n = 0U;
|
||||
break;
|
||||
}
|
||||
} while (n);
|
||||
|
||||
if (!c)
|
||||
// evaluate width field
|
||||
width = 0U;
|
||||
if (_is_digit(*format)) {
|
||||
width = _atoi(&format);
|
||||
} else if (*format == '*') {
|
||||
const int w = va_arg(va, int);
|
||||
if (w < 0) {
|
||||
flags |= FLAGS_LEFT; // reverse padding
|
||||
width = (unsigned int)-w;
|
||||
} else {
|
||||
width = (unsigned int)w;
|
||||
}
|
||||
format++;
|
||||
}
|
||||
|
||||
// evaluate precision field
|
||||
precision = 0U;
|
||||
if (*format == '.') {
|
||||
flags |= FLAGS_PRECISION;
|
||||
format++;
|
||||
if (_is_digit(*format)) {
|
||||
precision = _atoi(&format);
|
||||
} else if (*format == '*') {
|
||||
const int prec = (int)va_arg(va, int);
|
||||
precision = prec > 0 ? (unsigned int)prec : 0U;
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate length field
|
||||
switch (*format) {
|
||||
case 'l':
|
||||
flags |= FLAGS_LONG;
|
||||
format++;
|
||||
if (*format == 'l') {
|
||||
flags |= FLAGS_LONG_LONG;
|
||||
format++;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
flags |= FLAGS_SHORT;
|
||||
format++;
|
||||
if (*format == 'h') {
|
||||
flags |= FLAGS_CHAR;
|
||||
format++;
|
||||
}
|
||||
break;
|
||||
#if defined(PRINTF_SUPPORT_PTRDIFF_T)
|
||||
case 't':
|
||||
flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
#endif
|
||||
case 'j':
|
||||
flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
case 'z':
|
||||
flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
// evaluate specifier
|
||||
switch (*format) {
|
||||
case 'd':
|
||||
PrintInt(*argp++, 10, 1);
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'p':
|
||||
PrintInt(*argp++, 16, 0);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if ((s = (char*)*argp++) == 0) {
|
||||
s = "(null)";
|
||||
case 'X':
|
||||
case 'o':
|
||||
case 'b': {
|
||||
// set the base
|
||||
unsigned int base;
|
||||
if (*format == 'x' || *format == 'X') {
|
||||
base = 16U;
|
||||
} else if (*format == 'o') {
|
||||
base = 8U;
|
||||
} else if (*format == 'b') {
|
||||
base = 2U;
|
||||
} else {
|
||||
base = 10U;
|
||||
flags &= ~FLAGS_HASH; // no hash for dec format
|
||||
}
|
||||
// uppercase
|
||||
if (*format == 'X') {
|
||||
flags |= FLAGS_UPPERCASE;
|
||||
}
|
||||
|
||||
for (; *s; s++) {
|
||||
proxy()->serial->putc(*s);
|
||||
// no plus or space flag for u, x, X, o, b
|
||||
if ((*format != 'i') && (*format != 'd')) {
|
||||
flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
|
||||
}
|
||||
|
||||
// ignore '0' flag when precision is given
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
flags &= ~FLAGS_ZEROPAD;
|
||||
}
|
||||
|
||||
// convert the integer
|
||||
if ((*format == 'i') || (*format == 'd')) {
|
||||
// signed
|
||||
if (flags & FLAGS_LONG_LONG) {
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
const long long value = va_arg(va, long long);
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
#endif
|
||||
} else if (flags & FLAGS_LONG) {
|
||||
const long value = va_arg(va, long);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
} else {
|
||||
const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int)
|
||||
: va_arg(va, int);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
}
|
||||
} else {
|
||||
// unsigned
|
||||
if (flags & FLAGS_LONG_LONG) {
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags);
|
||||
#endif
|
||||
} else if (flags & FLAGS_LONG) {
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags);
|
||||
} else {
|
||||
const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int)
|
||||
: va_arg(va, unsigned int);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
case 'f':
|
||||
case 'F':
|
||||
if (*format == 'F')
|
||||
flags |= FLAGS_UPPERCASE;
|
||||
idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
|
||||
format++;
|
||||
break;
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'g':
|
||||
case 'G':
|
||||
if ((*format == 'g') || (*format == 'G'))
|
||||
flags |= FLAGS_ADAPT_EXP;
|
||||
if ((*format == 'E') || (*format == 'G'))
|
||||
flags |= FLAGS_UPPERCASE;
|
||||
idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
|
||||
format++;
|
||||
break;
|
||||
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif // PRINTF_SUPPORT_FLOAT
|
||||
case 'c': {
|
||||
unsigned int l = 1U;
|
||||
// pre padding
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
// char output
|
||||
out((char)va_arg(va, int), buffer, idx++, maxlen);
|
||||
// post padding
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 's': {
|
||||
const char* p = va_arg(va, char*);
|
||||
unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1);
|
||||
// pre padding
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
l = (l < precision ? l : precision);
|
||||
}
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
// string output
|
||||
while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
|
||||
out(*(p++), buffer, idx++, maxlen);
|
||||
}
|
||||
// post padding
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p': {
|
||||
width = sizeof(void*) * 2U;
|
||||
flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
|
||||
if (is_ll) {
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags);
|
||||
} else {
|
||||
#endif
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags);
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
}
|
||||
#endif
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case '%':
|
||||
proxy()->serial->putc('%');
|
||||
out('%', buffer, idx++, maxlen);
|
||||
format++;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Print unknown % sequence to draw attention.
|
||||
proxy()->serial->putc('%');
|
||||
proxy()->serial->putc(c);
|
||||
out(*format, buffer, idx++, maxlen);
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// termination
|
||||
out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
|
||||
|
||||
// return written chars without terminating \0
|
||||
return (int)idx;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int printf_(const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
char buffer[1];
|
||||
const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sprintf_(char* buffer, const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int snprintf_(char* buffer, size_t count, const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const int ret = _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vprintf_(const char* format, va_list va)
|
||||
{
|
||||
char buffer[1];
|
||||
return _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
|
||||
}
|
||||
|
||||
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va)
|
||||
{
|
||||
return _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||
}
|
||||
|
||||
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const out_fct_wrap_type out_fct_wrap = { out, arg };
|
||||
const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "actracer.h"
|
||||
#include "printf.h"
|
||||
|
||||
struct XiziSerialDriver {
|
||||
void (*sys_serial_init)();
|
||||
@@ -33,8 +34,6 @@ struct XiziSerialDriver {
|
||||
void (*putc)(uint8_t);
|
||||
};
|
||||
|
||||
void KPrintf(char* fmt, ...);
|
||||
|
||||
struct XiziSerialDriver* hardkernel_uart_init(struct TraceTag* hardkernel_tag);
|
||||
|
||||
int serial_init(struct TraceTag* uart_driver_tag);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
SRC_DIR :=
|
||||
SRC_FILES := actracer.c actracer_mem_chunk.c
|
||||
SRC_FILES := actracer.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
||||
@@ -29,267 +29,43 @@ Modification:
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "trap_common.h"
|
||||
|
||||
#include "assert.h"
|
||||
#include "multicores.h"
|
||||
#include "spinlock.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "actracer.h"
|
||||
#include "assert.h"
|
||||
|
||||
#ifndef min
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
static struct SysTracer sys_tracer;
|
||||
static char root_name[TRACER_NODE_NAME_LEN] = "ROOT\0";
|
||||
|
||||
struct SysTracer sys_tracer;
|
||||
char* tracer_space[TRACER_MEM_CHUNK_SIZE * NR_TRACER_MEM_CHUNKS];
|
||||
|
||||
struct TraceTag* const RequireRootTag()
|
||||
static void tracer_init_node(TracerNode* node, char* name, tracemeta_ac_type type, void* p_resource)
|
||||
{
|
||||
static struct TraceTag root_trace_tag = { NULL };
|
||||
return &root_trace_tag;
|
||||
}
|
||||
|
||||
static inline int namecmp(const char* s, const char* t)
|
||||
{
|
||||
return strncmp(s, t, RESOURCE_NAME_SIZE);
|
||||
}
|
||||
|
||||
/// @brief alloc a trace meta to trace resource
|
||||
static struct TraceMeta* alloc_trace_meta()
|
||||
{
|
||||
int index = -1;
|
||||
for (uint32_t idx = 0; idx < BITS_TRACEMETA_BITMAP; idx++) {
|
||||
if (sys_tracer.trace_meta_bit_map[idx] == 0xFFFFFFFF) {
|
||||
continue;
|
||||
}
|
||||
uint32_t position = __builtin_ffs(~sys_tracer.trace_meta_bit_map[idx]) - 1;
|
||||
if (position != 31) {
|
||||
// found a free bit
|
||||
sys_tracer.trace_meta_bit_map[idx] |= (1 << (position));
|
||||
index = idx * 32 + position;
|
||||
break;
|
||||
}
|
||||
node->type = type;
|
||||
node->parent = NULL;
|
||||
if (name != NULL) {
|
||||
char* p_name = (char*)slab_alloc(&sys_tracer.node_name_allocator);
|
||||
strcpy(p_name, name);
|
||||
p_name[TRACER_NODE_NAME_LEN - 1] = '\0';
|
||||
node->name = p_name;
|
||||
}
|
||||
|
||||
if (index == -1) {
|
||||
panic("Tracer no enough TracerMeta.");
|
||||
}
|
||||
|
||||
sys_tracer.trace_meta_poll[index].index = index;
|
||||
return &sys_tracer.trace_meta_poll[index];
|
||||
}
|
||||
|
||||
static bool dealloc_trace_meta(struct TraceMeta* meta)
|
||||
{
|
||||
int index = meta->index;
|
||||
// clear bitmap
|
||||
uint32_t outer_index = index / 32;
|
||||
uint32_t inner_index = index % 32;
|
||||
sys_tracer.trace_meta_bit_map[outer_index] &= (uint32_t)(~(1 << inner_index));
|
||||
// clear meta
|
||||
sys_tracer.trace_meta_poll[index].type = TRACER_INVALID;
|
||||
|
||||
if (index == -1) {
|
||||
panic("Tracer no enough TracerMeta.");
|
||||
}
|
||||
|
||||
sys_tracer.trace_meta_poll[index].index = index;
|
||||
return &sys_tracer.trace_meta_poll[index];
|
||||
}
|
||||
|
||||
static tracer_mem_chunk_idx_t trace_meta_map_mem_chunk(struct TraceMeta* const p_trace_meta, tracer_mem_chunk_idx_t mem_chunk_num)
|
||||
{
|
||||
tracer_mem_chunk_idx_t addr;
|
||||
/* direct mapping */
|
||||
if (mem_chunk_num < TRACEMETA_NR_DIRECT) {
|
||||
if ((addr = p_trace_meta->addr[mem_chunk_num]) == 0) {
|
||||
p_trace_meta->addr[mem_chunk_num] = addr = tracer_mem_chunk_alloc();
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
/* indirect mapping */
|
||||
mem_chunk_num -= TRACEMETA_NR_DIRECT;
|
||||
int indirect_mem_chunk_id = mem_chunk_num / NR_ADDR_PER_MEM_CHUNK;
|
||||
if (indirect_mem_chunk_id < TRACEMETA_NR_INDIRECT) {
|
||||
if ((addr = p_trace_meta->addr[TRACEMETA_NR_DIRECT + indirect_mem_chunk_id]) == 0) {
|
||||
p_trace_meta->addr[TRACEMETA_NR_DIRECT + indirect_mem_chunk_id] = addr = tracer_mem_chunk_alloc();
|
||||
}
|
||||
mem_chunk_num -= indirect_mem_chunk_id * NR_ADDR_PER_MEM_CHUNK;
|
||||
if (node->type == TRACER_OWNER) {
|
||||
doubleListNodeInit(&node->children_guard);
|
||||
} else {
|
||||
panic("tracer inode, bmap out of range");
|
||||
// no return
|
||||
node->p_resource = p_resource;
|
||||
}
|
||||
|
||||
// index mem_chunk
|
||||
struct tracer_mem_chunk* tracer_mem_chunk = tracer_mem_chunk_read(addr);
|
||||
tracer_mem_chunk_idx_t* indirect_list = (tracer_mem_chunk_idx_t*)tracer_mem_chunk->data;
|
||||
|
||||
if ((addr = indirect_list[mem_chunk_num]) == 0) {
|
||||
indirect_list[mem_chunk_num] = addr = tracer_mem_chunk_alloc();
|
||||
tracer_mem_chunk_write(tracer_mem_chunk);
|
||||
}
|
||||
|
||||
tracer_mem_chunk_release(tracer_mem_chunk);
|
||||
return addr;
|
||||
doubleListNodeInit(&node->list_node);
|
||||
}
|
||||
|
||||
/// @brief write trace info by trace meta
|
||||
static int trace_write_info(struct TraceMeta* const p_trace_meta, char* src, uint32_t off, uint32_t n)
|
||||
void sys_tracer_init()
|
||||
{
|
||||
if (p_trace_meta->type == TRACER_INVALID) {
|
||||
return -1;
|
||||
}
|
||||
// set sys_tracer resource identity
|
||||
tracer_init_node(&sys_tracer.root_node, NULL, TRACER_OWNER, NULL);
|
||||
sys_tracer.root_node.name = root_name;
|
||||
sys_tracer.sys_tracer_tag.meta = &sys_tracer.root_node;
|
||||
|
||||
// fast path
|
||||
if (off == 0 && n <= sizeof(uintptr_t)) {
|
||||
p_trace_meta->reserved = *(uintptr_t*)src;
|
||||
return n;
|
||||
}
|
||||
|
||||
if (UNLIKELY(off > p_trace_meta->size || off + n > VFS_FILE_MAXSIZE * TRACER_MEM_CHUNK_SIZE || off + n < off)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct tracer_mem_chunk* tracer_mem_chunk;
|
||||
uint32_t m;
|
||||
for (uint32_t tot = 0; tot < n; tot += m, off += m, src += m) {
|
||||
tracer_mem_chunk = tracer_mem_chunk_read(trace_meta_map_mem_chunk(p_trace_meta, off / TRACER_MEM_CHUNK_SIZE));
|
||||
m = min(n - tot, TRACER_MEM_CHUNK_SIZE - off % TRACER_MEM_CHUNK_SIZE);
|
||||
memmove(tracer_mem_chunk->data + off % TRACER_MEM_CHUNK_SIZE, src, m);
|
||||
tracer_mem_chunk_write(tracer_mem_chunk);
|
||||
tracer_mem_chunk_release(tracer_mem_chunk);
|
||||
}
|
||||
|
||||
if (n > 0 && off > p_trace_meta->size) {
|
||||
p_trace_meta->size = off;
|
||||
}
|
||||
|
||||
return n;
|
||||
// init memory allocator
|
||||
slab_init(&sys_tracer.node_allocator, sizeof(TracerNode));
|
||||
slab_init(&sys_tracer.node_name_allocator, sizeof(char[TRACER_NODE_NAME_LEN]));
|
||||
}
|
||||
|
||||
/// @brief read trace info by trace meta
|
||||
static int trace_read_info(struct TraceMeta* const p_trace_meta, char* dst, uint32_t off, uint32_t n)
|
||||
{
|
||||
if (p_trace_meta->type == TRACER_INVALID) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (off == 0 && n <= sizeof(uintptr_t)) {
|
||||
*(uintptr_t*)dst = p_trace_meta->reserved;
|
||||
return n;
|
||||
}
|
||||
|
||||
if (UNLIKELY(off > p_trace_meta->size || off + n < off)) {
|
||||
return -1;
|
||||
}
|
||||
if (UNLIKELY(off + n > p_trace_meta->size)) {
|
||||
n = p_trace_meta->size - off;
|
||||
}
|
||||
|
||||
static struct tracer_mem_chunk* tracer_mem_chunk;
|
||||
uint32_t m;
|
||||
for (uint32_t tot = 0; tot < n; tot += m, off += m, dst += m) {
|
||||
tracer_mem_chunk = tracer_mem_chunk_read(trace_meta_map_mem_chunk(p_trace_meta, off / TRACER_MEM_CHUNK_SIZE));
|
||||
m = min(n - tot, TRACER_MEM_CHUNK_SIZE - off % TRACER_MEM_CHUNK_SIZE);
|
||||
memmove(dst, tracer_mem_chunk->data + off % TRACER_MEM_CHUNK_SIZE, m);
|
||||
tracer_mem_chunk_release(tracer_mem_chunk);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static struct TraceMeta* tracer_find_meta_onestep(struct TraceMeta* const p_owner, char* name, uint32_t* poff)
|
||||
{
|
||||
struct TraceResourceEntry resource_entry;
|
||||
|
||||
if (p_owner->type != TRACER_OWNER) {
|
||||
ERROR("tracer_find_meta_onestep, not a dir, index: %d\n", p_owner->index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (uint32_t off = 0; off < p_owner->size; off += sizeof(resource_entry)) {
|
||||
if (trace_read_info(p_owner, (char*)&resource_entry, off, sizeof(resource_entry)) != sizeof(resource_entry)) {
|
||||
panic("tracer_find_meta_onestep: read trace owner's resources failed\n");
|
||||
}
|
||||
|
||||
if (resource_entry.index == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (namecmp(name, resource_entry.name) == 0) {
|
||||
if (poff) {
|
||||
*poff = off;
|
||||
}
|
||||
uint32_t vindex = resource_entry.index;
|
||||
assert(vindex >= 0 && vindex < NR_MAX_TRACEMETA);
|
||||
return &sys_tracer.trace_meta_poll[vindex];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Write a new vdirectory entry (name, index) into the vdirectory dp.
|
||||
static int tracer_append_meta(struct TraceMeta* p_owner, char* name, uint32_t index)
|
||||
{
|
||||
struct TraceResourceEntry resource_entry;
|
||||
|
||||
int offset = 0;
|
||||
for (offset = 0; offset < p_owner->size; offset += sizeof(resource_entry)) {
|
||||
if (trace_read_info(p_owner, (char*)&resource_entry, offset, sizeof(resource_entry)) != sizeof(resource_entry)) {
|
||||
ERROR("tracer_append_meta failed, read owner's resources failed.\n");
|
||||
return -1;
|
||||
}
|
||||
if (resource_entry.index == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
strncpy(resource_entry.name, name, RESOURCE_NAME_SIZE);
|
||||
resource_entry.index = index;
|
||||
if (trace_write_info(p_owner, (char*)&resource_entry, offset, sizeof(resource_entry)) != sizeof(resource_entry)) {
|
||||
ERROR("tracer_append_meta failed, append resource to owner failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct TraceMeta* tracer_new_meta(struct TraceMeta* p_owner, char* name, short type)
|
||||
{
|
||||
struct TraceMeta* p_trace_meta;
|
||||
|
||||
// check if owner entry exists
|
||||
uint32_t offset;
|
||||
if ((p_trace_meta = tracer_find_meta_onestep(p_owner, name, &offset)) != 0) {
|
||||
LOG("create resource(trace meta) failed, %s is existed\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((p_trace_meta = alloc_trace_meta()) == 0) {
|
||||
ERROR("create resource(trace meta) failed, cache is no free\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p_trace_meta->type = type;
|
||||
p_trace_meta->size = 0;
|
||||
|
||||
// update parent directory
|
||||
tracer_append_meta(p_owner, name, p_trace_meta->index);
|
||||
|
||||
// update "." and ".." for vfs inode
|
||||
if (p_trace_meta->type == TRACER_OWNER) {
|
||||
tracer_append_meta(p_trace_meta, ".", p_trace_meta->index);
|
||||
tracer_append_meta(p_trace_meta, "..", p_owner->index);
|
||||
}
|
||||
|
||||
return p_trace_meta;
|
||||
}
|
||||
|
||||
static char* parse_path(char* path, char* name)
|
||||
static char* parse_path(char* path, char* const name)
|
||||
{
|
||||
// skip extra '/'
|
||||
while (*path == '/') {
|
||||
@@ -307,8 +83,9 @@ static char* parse_path(char* path, char* name)
|
||||
|
||||
// handle current name
|
||||
int len = path - cur_start;
|
||||
if (len >= RESOURCE_NAME_SIZE) {
|
||||
strncpy(name, cur_start, RESOURCE_NAME_SIZE);
|
||||
if (len >= TRACER_NODE_NAME_LEN) {
|
||||
strncpy(name, cur_start, TRACER_NODE_NAME_LEN);
|
||||
name[TRACER_NODE_NAME_LEN - 1] = '\0';
|
||||
} else {
|
||||
strncpy(name, cur_start, len);
|
||||
name[len] = '\0';
|
||||
@@ -317,215 +94,105 @@ static char* parse_path(char* path, char* name)
|
||||
return path;
|
||||
}
|
||||
|
||||
static struct TraceMeta* tracer_find_meta(struct TraceMeta* const p_owner, char* path, int nameiparent, char* name)
|
||||
static TracerNode* tracer_find_node_onestep(TracerNode* const owner, const char* const name)
|
||||
{
|
||||
struct TraceMeta* p_owner_inside = p_owner;
|
||||
struct TraceMeta* vnp;
|
||||
|
||||
/* traverse TRACER_OWNER */
|
||||
while ((path = parse_path(path, name)) != 0) {
|
||||
if (p_owner_inside->type != TRACER_OWNER) {
|
||||
return NULL;
|
||||
}
|
||||
if (nameiparent && *path == '\0') {
|
||||
return p_owner_inside;
|
||||
}
|
||||
if ((vnp = tracer_find_meta_onestep(p_owner_inside, name, NULL)) == 0) {
|
||||
DEBUG("Not such object: %s\n", path);
|
||||
return NULL;
|
||||
}
|
||||
p_owner_inside = vnp;
|
||||
}
|
||||
|
||||
if (nameiparent) {
|
||||
return NULL;
|
||||
}
|
||||
return p_owner_inside;
|
||||
}
|
||||
|
||||
int tracer_write_trace(struct TraceTag* const p_trace_tag, char* src, uint32_t off, uint32_t n)
|
||||
{
|
||||
if (src == NULL || p_trace_tag == NULL || p_trace_tag->meta == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return trace_write_info(p_trace_tag->meta, src, off, n);
|
||||
}
|
||||
|
||||
int tracer_read_trace(struct TraceTag* const p_trace_tag, char* dst, uint32_t off, uint32_t n)
|
||||
{
|
||||
if (dst == NULL || p_trace_tag == NULL || p_trace_tag->meta == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return trace_read_info(p_trace_tag->meta, dst, off, n);
|
||||
}
|
||||
|
||||
/// @brief
|
||||
static void trace_locate_inner(struct TraceTag* target, struct TraceTag* const p_trace_tag, char* path, bool parent)
|
||||
{
|
||||
char name[RESOURCE_NAME_SIZE];
|
||||
struct TraceMeta* p_trace_meta = tracer_find_meta(p_trace_tag->meta, path, parent, name);
|
||||
// p_trace_meta: TRACER_OWNER, VT_FS or other.
|
||||
// TRACER_OWNER: path: "", name: "dir name"
|
||||
// other: path: "", name: "file name"
|
||||
if (!p_trace_meta) {
|
||||
DEBUG("trace_locate, not found\n");
|
||||
}
|
||||
target->type = p_trace_meta->type;
|
||||
target->meta = p_trace_meta;
|
||||
}
|
||||
|
||||
static inline void trace_locate(struct TraceTag* target, struct TraceTag* const p_trace_tag, char* path)
|
||||
{
|
||||
trace_locate_inner(target, p_trace_tag, path, 0);
|
||||
}
|
||||
|
||||
static inline void trace_locate_parent(struct TraceTag* target, struct TraceTag* const p_trace_tag, char* path)
|
||||
{
|
||||
trace_locate_inner(target, p_trace_tag, path, 1);
|
||||
}
|
||||
|
||||
bool tracer_create_trace(struct TraceTag* target, struct TraceTag* p_trace_tag, char* path, short type)
|
||||
{
|
||||
struct TraceMeta *p_trace_meta, *p_owner;
|
||||
|
||||
// find parent vfs inode
|
||||
if ((p_owner = p_trace_tag->meta) == 0) {
|
||||
LOG("create tracemeta failed, parent is null\n");
|
||||
target->meta = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
p_trace_meta = tracer_new_meta(p_owner, path, type);
|
||||
target->meta = p_trace_meta;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tracer_delete_trace(struct TraceTag* target, struct TraceTag* owner)
|
||||
{
|
||||
if (target->meta == NULL || owner->type != TRACER_OWNER) {
|
||||
return false;
|
||||
}
|
||||
struct TraceMeta* p_trace_meta = target->meta;
|
||||
struct TraceMeta* p_owner_meta = owner->meta;
|
||||
assert(p_trace_meta->type != TRACER_INVALID);
|
||||
|
||||
if (p_trace_meta->type == TRACER_OWNER) {
|
||||
/// @todo support recursive delete
|
||||
}
|
||||
|
||||
struct TraceResourceEntry resource_entry;
|
||||
bool is_owned = false;
|
||||
for (uint32_t off = 0; off < p_owner_meta->size; off += sizeof(resource_entry)) {
|
||||
if (trace_read_info(p_owner_meta, (char*)&resource_entry, off, sizeof(resource_entry)) != sizeof(resource_entry)) {
|
||||
panic("tracer_find_meta_onestep: read trace owner's resources failed\n");
|
||||
}
|
||||
|
||||
if (resource_entry.index == 0) {
|
||||
TracerNode* iter = NULL;
|
||||
assert(owner->type == TRACER_OWNER);
|
||||
DOUBLE_LIST_FOR_EACH_ENTRY(iter, &owner->children_guard, list_node)
|
||||
{
|
||||
if (iter->name == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (resource_entry.index == p_trace_meta->index) {
|
||||
resource_entry.index = 0;
|
||||
trace_write_info(owner->meta, (char*)&resource_entry, off, sizeof(resource_entry));
|
||||
is_owned = true;
|
||||
break;
|
||||
if (strcmp(name, iter->name) == 0) {
|
||||
return iter;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_owned) {
|
||||
ERROR("delete trace(%d) not owned by given owner(%d).\n", target->meta->index, owner->meta->index);
|
||||
return false;
|
||||
}
|
||||
dealloc_trace_meta(p_trace_meta);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TraceTag* const RequireRootTag()
|
||||
{
|
||||
return &sys_tracer.sys_tracer_tag;
|
||||
}
|
||||
|
||||
bool AchieveResourceTag(TraceTag* target, TraceTag* owner, char* name)
|
||||
{
|
||||
static char name_buffer[TRACER_NODE_NAME_LEN];
|
||||
|
||||
TracerNode* inner_node = owner->meta;
|
||||
assert(inner_node != NULL && inner_node->type == TRACER_OWNER);
|
||||
while ((name = parse_path(name, name_buffer)) != NULL) {
|
||||
if ((inner_node = tracer_find_node_onestep(inner_node, name_buffer)) == NULL) {
|
||||
DEBUG("Tracer: No such object, owner: %s, child: %s\n", //
|
||||
owner->meta->name == NULL ? "NULL" : owner->meta->name, name == NULL ? "NULL" : name_buffer);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
target->meta = inner_node;
|
||||
return true;
|
||||
}
|
||||
|
||||
void tracer_init(void)
|
||||
void* AchieveResource(TraceTag* tag)
|
||||
{
|
||||
/* init sys_tracer, the manager */
|
||||
spinlock_init(&sys_tracer.mem_chunk_bitmap_lock, "tracer_mem_chunk_bitmap");
|
||||
spinlock_init(&sys_tracer.trace_meta_bitmap_lock, "tracer_meta_bitmap");
|
||||
memset(sys_tracer.mem_chunks_bit_map, 0, sizeof(sys_tracer.mem_chunk_bitmap_lock));
|
||||
memset(sys_tracer.trace_meta_bit_map, 0, sizeof(sys_tracer.trace_meta_bit_map));
|
||||
|
||||
assert((TRACER_MEM_CHUNK_SIZE % sizeof(struct TraceMeta)) == 0);
|
||||
assert((TRACER_MEM_CHUNK_SIZE % sizeof(struct TraceResourceEntry)) == 0);
|
||||
// mem_chunk space, fit with mem_chunk_bit_map
|
||||
mem_chunk_synchronizer_init((uintptr_t)tracer_space, TRACER_MEM_CHUNK_SIZE, NR_TRACER_MEM_CHUNKS);
|
||||
|
||||
/* build root inode */
|
||||
alloc_trace_meta(); // inode as guard.
|
||||
|
||||
/* build root trace_meta */
|
||||
struct TraceMeta* root_tracemeta = alloc_trace_meta();
|
||||
assert(root_tracemeta->index == 1);
|
||||
root_tracemeta->type = TRACER_OWNER;
|
||||
root_tracemeta->size = 0;
|
||||
|
||||
tracer_append_meta(root_tracemeta, ".", root_tracemeta->index);
|
||||
tracer_append_meta(root_tracemeta, "..", root_tracemeta->index);
|
||||
|
||||
RequireRootTag()->meta = root_tracemeta;
|
||||
}
|
||||
|
||||
/// @brief find resource tag
|
||||
void tracer_find_tag(struct TraceTag* target, struct TraceTag* const source, char* path)
|
||||
{
|
||||
target->meta = NULL;
|
||||
struct TraceTag* p_trace_tag;
|
||||
|
||||
if (*path == '/' || source == NULL) {
|
||||
p_trace_tag = RequireRootTag();
|
||||
} else {
|
||||
p_trace_tag = source;
|
||||
}
|
||||
if (p_trace_tag == NULL || p_trace_tag->meta == NULL) {
|
||||
return;
|
||||
}
|
||||
trace_locate(target, p_trace_tag, path);
|
||||
}
|
||||
|
||||
bool AchieveResourceTag(struct TraceTag* target, struct TraceTag* owner, char* name)
|
||||
{
|
||||
tracer_find_tag(target, owner, name);
|
||||
if (target->meta == NULL) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void* AchieveResource(struct TraceTag* target)
|
||||
{
|
||||
if (target->type == TRACER_OWNER) {
|
||||
assert(tag != NULL);
|
||||
if (tag->meta == NULL || tag->meta->type == TRACER_OWNER) {
|
||||
return NULL;
|
||||
}
|
||||
void* p_resource = NULL;
|
||||
tracer_read_trace(target, (char*)&p_resource, 0, sizeof(void*));
|
||||
assert(p_resource != NULL);
|
||||
return p_resource;
|
||||
|
||||
return tag->meta->p_resource;
|
||||
}
|
||||
|
||||
bool CreateResourceTag(struct TraceTag* new_tag, struct TraceTag* owner, char* name, tracemeta_ac_type type, void* p_resource)
|
||||
bool CreateResourceTag(TraceTag* new_tag, TraceTag* owner, char* name, tracemeta_ac_type type, void* p_resource)
|
||||
{
|
||||
new_tag->type = type;
|
||||
if (type == TRACER_OWNER) {
|
||||
return tracer_create_trace(new_tag, owner, name, type);
|
||||
assert(new_tag != NULL && owner != NULL);
|
||||
if (owner->meta == NULL) {
|
||||
ERROR("Tracer: Empty owner\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// handle ac resource types
|
||||
if (p_resource == NULL) {
|
||||
assert(owner->meta->type == TRACER_OWNER);
|
||||
if (tracer_find_node_onestep(owner->meta, name) != NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tracer_create_trace(new_tag, owner, name, type)) {
|
||||
TracerNode* new_node = (TracerNode*)slab_alloc(&sys_tracer.node_allocator);
|
||||
if (new_node == NULL) {
|
||||
ERROR("Tracer: No memory for new node\n");
|
||||
return false;
|
||||
}
|
||||
bool ret = tracer_write_trace(new_tag, (char*)&p_resource, 0, sizeof(void*)) == sizeof(void*);
|
||||
return ret;
|
||||
tracer_init_node(new_node, name, type, p_resource);
|
||||
|
||||
// new node add to owner's children list
|
||||
doubleListAddOnHead(&new_node->list_node, &owner->meta->children_guard);
|
||||
new_node->parent = owner->meta;
|
||||
|
||||
new_tag->meta = new_node;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeleteResource(struct TraceTag* target, struct TraceTag* owner)
|
||||
bool DeleteResource(TraceTag* target, TraceTag* owner)
|
||||
{
|
||||
return tracer_delete_trace(target, owner);
|
||||
assert(target != NULL && owner != NULL);
|
||||
assert(owner->meta != NULL && owner->meta->type == TRACER_OWNER);
|
||||
if (target->meta == NULL) {
|
||||
ERROR("Tracer: Delete a empty resource\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(target->meta->parent == owner->meta);
|
||||
doubleListDel(&target->meta->list_node);
|
||||
// delete name
|
||||
if (target->meta->name != NULL) {
|
||||
slab_free(&sys_tracer.node_name_allocator, target->meta->name);
|
||||
}
|
||||
// delete all children
|
||||
/// @attention currently donot allow multilevel resource deletion
|
||||
if (target->meta->type == TRACER_OWNER) {
|
||||
assert(IS_DOUBLE_LIST_EMPTY(&target->meta->children_guard));
|
||||
}
|
||||
slab_free(&sys_tracer.node_allocator, target->meta);
|
||||
target->meta = NULL;
|
||||
return true;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user