finish lab1 & init lab2
This commit is contained in:
commit
87322288a2
3
lab1/.gdbinit
Normal file
3
lab1/.gdbinit
Normal file
@ -0,0 +1,3 @@
|
||||
set architecture aarch64
|
||||
target remote localhost:1234
|
||||
file ./build/kernel.img
|
16
lab1/.gitignore
vendored
Normal file
16
lab1/.gitignore
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
*.o
|
||||
*.elf
|
||||
*.img
|
||||
*.bin
|
||||
*.pyc
|
||||
*.swp
|
||||
|
||||
cscope.*
|
||||
.vscode
|
||||
|
||||
asm
|
||||
tags
|
||||
build
|
||||
*.out
|
||||
*.pyc
|
||||
chcore.out
|
85
lab1/CMakeLists.txt
Normal file
85
lab1/CMakeLists.txt
Normal file
@ -0,0 +1,85 @@
|
||||
cmake_minimum_required (VERSION 3.14)
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE on)
|
||||
|
||||
set(CMAKE_BUILD_TYPE "Release") # "Release" or "Debug"
|
||||
set(CHCORE_PLAT "raspi3")
|
||||
set(CHCORE_ARCH "aarch64")
|
||||
|
||||
mark_as_advanced(CMAKE_INSTALL_PREFIX)
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_definitions("-DLOG_LEVEL=2")
|
||||
else ()
|
||||
add_definitions("-DLOG_LEVEL=1")
|
||||
endif ()
|
||||
|
||||
set(CROSS_COMPILE "${CHCORE_ARCH}-linux-gnu-")
|
||||
|
||||
set(CMAKE_C_COMPILER "${CROSS_COMPILE}gcc")
|
||||
set(CMAKE_ASM_COMPILER "${CROSS_COMPILE}gcc")
|
||||
execute_process (
|
||||
COMMAND ${CMAKE_C_COMPILER} -print-file-name=include
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
OUTPUT_VARIABLE C_COMPILER_INCLUDE
|
||||
)
|
||||
|
||||
|
||||
set(CMAKE_C_FLAGS
|
||||
"-Wall -fPIC -nostdlib -nostartfiles -ffreestanding \
|
||||
-DCHCORE -nostdinc ")
|
||||
|
||||
project (chos C ASM)
|
||||
|
||||
set(BOOTLOADER_PATH "boot")
|
||||
set(KERNEL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/kernel")
|
||||
|
||||
|
||||
set(KERNEL_ARCH_PATH "${KERNEL_PATH}")
|
||||
|
||||
include_directories(".")
|
||||
include_directories("${KERNEL_PATH}")
|
||||
|
||||
add_subdirectory("${KERNEL_ARCH_PATH}")
|
||||
|
||||
set(BINARY_KERNEL_IMG_PATH "CMakeFiles/kernel.img.dir")
|
||||
set(init_object
|
||||
"${BINARY_KERNEL_IMG_PATH}/${BOOTLOADER_PATH}/start.S.o
|
||||
${BINARY_KERNEL_IMG_PATH}/${BOOTLOADER_PATH}/mmu.c.o
|
||||
${BINARY_KERNEL_IMG_PATH}/${BOOTLOADER_PATH}/tools.S.o
|
||||
${BINARY_KERNEL_IMG_PATH}/${BOOTLOADER_PATH}/init_c.c.o
|
||||
${BINARY_KERNEL_IMG_PATH}/${BOOTLOADER_PATH}/uart.c.o"
|
||||
)
|
||||
|
||||
set(link_script "linker.lds")
|
||||
configure_file("./scripts/linker-aarch64.lds.in" "linker.lds.S")
|
||||
|
||||
set(files "")
|
||||
include("${BOOTLOADER_PATH}/config.cmake")
|
||||
|
||||
add_executable(kernel.img ${files}
|
||||
$<TARGET_OBJECTS:${PROJECT_NAME}-arch>
|
||||
)
|
||||
|
||||
set_property(
|
||||
TARGET kernel.img
|
||||
APPEND_STRING
|
||||
PROPERTY
|
||||
LINK_FLAGS
|
||||
"-T ${CMAKE_CURRENT_BINARY_DIR}/${link_script} -e _start"
|
||||
)
|
||||
|
||||
set_property(
|
||||
TARGET kernel.img
|
||||
APPEND_STRING
|
||||
PROPERTY
|
||||
DEPENDS
|
||||
"${link_script}"
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
TARGET kernel.img
|
||||
PRE_LINK
|
||||
COMMAND ${CMAKE_C_COMPILER} -E -x c
|
||||
-I${CMAKE_SOURCE_DIR}/${BOOTLOADER_PATH}/include ./linker.lds.S | grep -v "^#" > linker.lds
|
||||
)
|
121
lab1/LICENSE
Normal file
121
lab1/LICENSE
Normal file
@ -0,0 +1,121 @@
|
||||
木兰宽松许可证, 第1版
|
||||
|
||||
木兰宽松许可证, 第1版
|
||||
2019年8月 http://license.coscl.org.cn/MulanPSL
|
||||
|
||||
您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第1版(“本许可证”)的如下条款的约束:
|
||||
|
||||
0. 定义
|
||||
|
||||
“软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。
|
||||
|
||||
“贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。
|
||||
|
||||
“法人实体”是指提交贡献的机构及其“关联实体”。
|
||||
|
||||
“关联实体”是指,对“本许可证”下的一方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。
|
||||
|
||||
“贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。
|
||||
|
||||
1. 授予版权许可
|
||||
|
||||
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。
|
||||
|
||||
2. 授予专利许可
|
||||
|
||||
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括仅因您或他人修改“贡献”或其他结合而将必然会侵犯到的专利权利要求。如您或您的“关联实体”直接或间接地(包括通过代理、专利被许可人或受让人),就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。
|
||||
|
||||
3. 无商标许可
|
||||
|
||||
“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。
|
||||
|
||||
4. 分发限制
|
||||
|
||||
您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。
|
||||
|
||||
5. 免责声明与责任限制
|
||||
|
||||
“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。
|
||||
|
||||
条款结束。
|
||||
|
||||
如何将木兰宽松许可证,第1版,应用到您的软件
|
||||
|
||||
如果您希望将木兰宽松许可证,第1版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步:
|
||||
|
||||
1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字;
|
||||
|
||||
2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中;
|
||||
|
||||
3, 请将如下声明文本放入每个源文件的头部注释中。
|
||||
|
||||
Copyright (c) [2019] [name of copyright holder]
|
||||
[Software Name] is licensed under the Mulan PSL v1.
|
||||
You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
You may obtain a copy of Mulan PSL v1 at:
|
||||
http://license.coscl.org.cn/MulanPSL
|
||||
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 v1 for more details.
|
||||
|
||||
|
||||
Mulan Permissive Software License,Version 1
|
||||
|
||||
Mulan Permissive Software License,Version 1 (Mulan PSL v1)
|
||||
August 2019 http://license.coscl.org.cn/MulanPSL
|
||||
|
||||
Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v1 (this License) with following terms and conditions:
|
||||
|
||||
0. Definition
|
||||
|
||||
Software means the program and related documents which are comprised of those Contribution and licensed under this License.
|
||||
|
||||
Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License.
|
||||
|
||||
Legal Entity means the entity making a Contribution and all its Affiliates.
|
||||
|
||||
Affiliates means entities that control, or are controlled by, or are under common control with a party to this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity.
|
||||
|
||||
Contribution means the copyrightable work licensed by a particular Contributor under this License.
|
||||
|
||||
1. Grant of Copyright License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not.
|
||||
|
||||
2. Grant of Patent License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed, excluding of any patent claims solely be infringed by your or others’ modification or other combinations. If you or your Affiliates directly or indirectly (including through an agent, patent licensee or assignee), institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken.
|
||||
|
||||
3. No Trademark License
|
||||
|
||||
No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in section 4.
|
||||
|
||||
4. Distribution Restriction
|
||||
|
||||
You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software.
|
||||
|
||||
5. Disclaimer of Warranty and Limitation of Liability
|
||||
|
||||
The Software and Contribution in it are provided without warranties of any kind, either express or implied. In no event shall any Contributor or copyright holder be liable to you for any damages, including, but not limited to any direct, or indirect, special or consequential damages arising from your use or inability to use the Software or the Contribution in it, no matter how it’s caused or based on which legal theory, even if advised of the possibility of such damages.
|
||||
|
||||
End of the Terms and Conditions
|
||||
|
||||
How to apply the Mulan Permissive Software License,Version 1 (Mulan PSL v1) to your software
|
||||
|
||||
To apply the Mulan PSL v1 to your work, for easy identification by recipients, you are suggested to complete following three steps:
|
||||
|
||||
i. Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner;
|
||||
ii. Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package;
|
||||
iii. Attach the statement to the appropriate annotated syntax at the beginning of each source file.
|
||||
|
||||
Copyright (c) [2019] [name of copyright holder]
|
||||
[Software Name] is licensed under the Mulan PSL v1.
|
||||
You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
You may obtain a copy of Mulan PSL v1 at:
|
||||
http://license.coscl.org.cn/MulanPSL
|
||||
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 v1 for more details.
|
50
lab1/Makefile
Normal file
50
lab1/Makefile
Normal file
@ -0,0 +1,50 @@
|
||||
BUILD_DIR := ./build
|
||||
ifndef QEMU
|
||||
QEMU := qemu-system-aarch64
|
||||
endif
|
||||
|
||||
LAB := 1
|
||||
# try to generate a unique GDB port
|
||||
GDBPORT := 1234
|
||||
QEMUOPTS = -machine raspi3 -serial null -serial mon:stdio -m size=1G -kernel $(BUILD_DIR)/kernel.img -gdb tcp::1234
|
||||
IMAGES = $(BUILD_DIR)/kernel.img
|
||||
|
||||
all: build
|
||||
|
||||
gdb:
|
||||
gdb-multiarch -n -x .gdbinit
|
||||
|
||||
build: FORCE
|
||||
./scripts/docker_build.sh
|
||||
|
||||
qemu: $(IMAGES)
|
||||
$(QEMU) $(QEMUOPTS)
|
||||
|
||||
qemu-gdb: $(IMAGES)
|
||||
@echo "***"
|
||||
@echo "*** make qemu-gdb'." 1>&2
|
||||
@echo "***"
|
||||
$(QEMU) -nographic $(QEMUOPTS) -S
|
||||
|
||||
|
||||
gdbport:
|
||||
@echo $(GDBPORT)
|
||||
|
||||
docker: FORCE
|
||||
./scripts/run_docker.sh
|
||||
|
||||
grade: build FORCE
|
||||
@echo "make grade"
|
||||
@echo "LAB"$(LAB)": test >>>>>>>>>>>>>>>>>"
|
||||
ifeq ($(LAB), 2)
|
||||
./scripts/run_mm_test.sh
|
||||
endif
|
||||
./scripts/grade-lab$(LAB)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm -rf build
|
||||
@rm -rf chcore.out
|
||||
|
||||
.PHONY: FORCE
|
||||
FORCE:
|
32
lab1/README.md
Normal file
32
lab1/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# ChCore
|
||||
|
||||
This is the repository of ChCore labs in SE315, 2020 Spring.
|
||||
|
||||
## build
|
||||
- `make` or `make build`
|
||||
- The project will be built in `build` directory.
|
||||
|
||||
## Emulate
|
||||
- `make qemu`
|
||||
|
||||
Emulate ChCore in QEMU
|
||||
|
||||
## Debug with GBD
|
||||
|
||||
- `make qemu-gdb`
|
||||
|
||||
Start a GDB server running ChCore
|
||||
|
||||
- `make gdb`
|
||||
|
||||
Start a GDB (gdb-multiarch) client
|
||||
|
||||
## Grade
|
||||
- `make grade`
|
||||
|
||||
Show your grade of labs in the current branch
|
||||
|
||||
## Other
|
||||
- type `Ctrl+a x` to quit QEMU
|
||||
- type `Ctrl+d` to quit GDB
|
||||
|
13
lab1/boot/boot.h
Normal file
13
lab1/boot/boot.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
extern void el1_mmu_activate(void);
|
||||
extern void init_boot_pt(void);
|
||||
|
||||
extern void start_kernel(void *boot_flag);
|
||||
|
||||
extern char _bss_start;
|
||||
extern char _bss_end;
|
||||
|
||||
#define PLAT_CPU_NUMBER 4
|
||||
|
||||
#define ALIGN(n) __attribute__((__aligned__(n)))
|
12
lab1/boot/config.cmake
Normal file
12
lab1/boot/config.cmake
Normal file
@ -0,0 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
set(INIT_PATH "${BOOTLOADER_PATH}")
|
||||
|
||||
file(
|
||||
GLOB
|
||||
tmpfiles
|
||||
"${INIT_PATH}/*.c"
|
||||
"${INIT_PATH}/*.S"
|
||||
)
|
||||
|
||||
list(APPEND files ${tmpfiles})
|
7
lab1/boot/image.h
Normal file
7
lab1/boot/image.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define SZ_16K 0x4000
|
||||
#define SZ_64K 0x10000
|
||||
|
||||
#define KERNEL_VADDR 0xffffff0000000000
|
||||
#define TEXT_OFFSET 0x80000
|
64
lab1/boot/init_c.c
Normal file
64
lab1/boot/init_c.c
Normal file
@ -0,0 +1,64 @@
|
||||
#include "boot.h"
|
||||
#include "image.h"
|
||||
|
||||
typedef unsigned long u64;
|
||||
|
||||
#define INIT_STACK_SIZE 0x1000
|
||||
char boot_cpu_stack[PLAT_CPU_NUMBER][INIT_STACK_SIZE] ALIGN(16);
|
||||
|
||||
/*
|
||||
* Initialize these varibles in order to make them not in .bss section.
|
||||
* So, they will have concrete initial value even on real machine.
|
||||
*
|
||||
* Non-primary CPUs will spin until they see the secondary_boot_flag becomes
|
||||
* non-zero which is set in kernel (see enable_smp_cores).
|
||||
*
|
||||
* The secondary_boot_flag is initilized as {NOT_BSS, 0, 0, ...}.
|
||||
*/
|
||||
#define NOT_BSS (0xBEEFUL)
|
||||
long secondary_boot_flag[PLAT_CPU_NUMBER] = { NOT_BSS };
|
||||
|
||||
volatile u64 clear_bss_flag = NOT_BSS;
|
||||
|
||||
/* Uart */
|
||||
void early_uart_init(void);
|
||||
void uart_send_string(char *);
|
||||
|
||||
static void clear_bss(void)
|
||||
{
|
||||
u64 bss_start_addr;
|
||||
u64 bss_end_addr;
|
||||
u64 i;
|
||||
|
||||
bss_start_addr = (u64) & _bss_start;
|
||||
bss_end_addr = (u64) & _bss_end;
|
||||
|
||||
for (i = bss_start_addr; i < bss_end_addr; ++i)
|
||||
*(char *)i = 0;
|
||||
|
||||
clear_bss_flag = 0;
|
||||
}
|
||||
|
||||
void init_c(void)
|
||||
{
|
||||
/* Clear the bss area for the kernel image */
|
||||
clear_bss();
|
||||
|
||||
/* Initialize UART before enabling MMU. */
|
||||
early_uart_init();
|
||||
uart_send_string("boot: init_c\r\n");
|
||||
|
||||
/* Initialize Boot Page Table. */
|
||||
uart_send_string("[BOOT] Install boot page table\r\n");
|
||||
init_boot_pt();
|
||||
|
||||
/* Enable MMU. */
|
||||
el1_mmu_activate();
|
||||
uart_send_string("[BOOT] Enable el1 MMU\r\n");
|
||||
|
||||
/* Call Kernel Main. */
|
||||
uart_send_string("[BOOT] Jump to kernel main\r\n");
|
||||
start_kernel(secondary_boot_flag);
|
||||
|
||||
/* Never reach here */
|
||||
}
|
131
lab1/boot/mmu.c
Normal file
131
lab1/boot/mmu.c
Normal file
@ -0,0 +1,131 @@
|
||||
#include "image.h"
|
||||
|
||||
typedef unsigned long u64;
|
||||
typedef unsigned int u32;
|
||||
|
||||
/* Physical memory address space: 0-1G */
|
||||
#define PHYSMEM_START (0x0UL)
|
||||
#define PERIPHERAL_BASE (0x3F000000UL)
|
||||
#define PHYSMEM_END (0x40000000UL)
|
||||
|
||||
/* The number of entries in one page table page */
|
||||
#define PTP_ENTRIES 512
|
||||
/* The size of one page table page */
|
||||
#define PTP_SIZE 4096
|
||||
#define ALIGN(n) __attribute__((__aligned__(n)))
|
||||
u64 boot_ttbr0_l0[PTP_ENTRIES] ALIGN(PTP_SIZE);
|
||||
u64 boot_ttbr0_l1[PTP_ENTRIES] ALIGN(PTP_SIZE);
|
||||
u64 boot_ttbr0_l2[PTP_ENTRIES] ALIGN(PTP_SIZE);
|
||||
|
||||
u64 boot_ttbr1_l0[PTP_ENTRIES] ALIGN(PTP_SIZE);
|
||||
u64 boot_ttbr1_l1[PTP_ENTRIES] ALIGN(PTP_SIZE);
|
||||
u64 boot_ttbr1_l2[PTP_ENTRIES] ALIGN(PTP_SIZE);
|
||||
|
||||
#define IS_VALID (1UL << 0)
|
||||
#define IS_TABLE (1UL << 1)
|
||||
|
||||
#define UXN (0x1UL << 54)
|
||||
#define ACCESSED (0x1UL << 10)
|
||||
#define INNER_SHARABLE (0x3UL << 8)
|
||||
#define NORMAL_MEMORY (0x4UL << 2)
|
||||
#define DEVICE_MEMORY (0x0UL << 2)
|
||||
|
||||
#define SIZE_2M (2UL*1024*1024)
|
||||
|
||||
#define GET_L0_INDEX(x) (((x) >> (12 + 9 + 9 + 9)) & 0x1ff)
|
||||
#define GET_L1_INDEX(x) (((x) >> (12 + 9 + 9)) & 0x1ff)
|
||||
#define GET_L2_INDEX(x) (((x) >> (12 + 9)) & 0x1ff)
|
||||
|
||||
void init_boot_pt(void)
|
||||
{
|
||||
u32 start_entry_idx;
|
||||
u32 end_entry_idx;
|
||||
u32 idx;
|
||||
u64 kva;
|
||||
|
||||
/* TTBR0_EL1 0-1G */
|
||||
boot_ttbr0_l0[0] = ((u64) boot_ttbr0_l1) | IS_TABLE | IS_VALID;
|
||||
boot_ttbr0_l1[0] = ((u64) boot_ttbr0_l2) | IS_TABLE | IS_VALID;
|
||||
|
||||
/* Usuable memory: PHYSMEM_START ~ PERIPHERAL_BASE */
|
||||
start_entry_idx = PHYSMEM_START / SIZE_2M;
|
||||
end_entry_idx = PERIPHERAL_BASE / SIZE_2M;
|
||||
|
||||
/* Map each 2M page */
|
||||
for (idx = start_entry_idx; idx < end_entry_idx; ++idx) {
|
||||
boot_ttbr0_l2[idx] = (PHYSMEM_START + idx * SIZE_2M)
|
||||
| UXN /* Unprivileged execute never */
|
||||
| ACCESSED /* Set access flag */
|
||||
| INNER_SHARABLE /* Sharebility */
|
||||
| NORMAL_MEMORY /* Normal memory */
|
||||
| IS_VALID;
|
||||
}
|
||||
|
||||
/* Peripheral memory: PERIPHERAL_BASE ~ PHYSMEM_END */
|
||||
|
||||
/* Raspi3b/3b+ Peripherals: 0x3f 00 00 00 - 0x3f ff ff ff */
|
||||
start_entry_idx = end_entry_idx;
|
||||
end_entry_idx = PHYSMEM_END / SIZE_2M;
|
||||
|
||||
/* Map each 2M page */
|
||||
for (idx = start_entry_idx; idx < end_entry_idx; ++idx) {
|
||||
boot_ttbr0_l2[idx] = (PHYSMEM_START + idx * SIZE_2M)
|
||||
| UXN /* Unprivileged execute never */
|
||||
| ACCESSED /* Set access flag */
|
||||
| DEVICE_MEMORY /* Device memory */
|
||||
| IS_VALID;
|
||||
}
|
||||
|
||||
/*
|
||||
* TTBR1_EL1 0-1G
|
||||
* KERNEL_VADDR: L0 pte index: 510; L1 pte index: 0; L2 pte index: 0.
|
||||
*/
|
||||
kva = KERNEL_VADDR;
|
||||
boot_ttbr1_l0[GET_L0_INDEX(kva)] = ((u64) boot_ttbr1_l1)
|
||||
| IS_TABLE | IS_VALID;
|
||||
boot_ttbr1_l1[GET_L1_INDEX(kva)] = ((u64) boot_ttbr1_l2)
|
||||
| IS_TABLE | IS_VALID;
|
||||
|
||||
start_entry_idx = GET_L2_INDEX(kva);
|
||||
/* Note: assert(start_entry_idx == 0) */
|
||||
end_entry_idx = start_entry_idx + PERIPHERAL_BASE / SIZE_2M;
|
||||
/* Note: assert(end_entry_idx < PTP_ENTIRES) */
|
||||
|
||||
/*
|
||||
* Map each 2M page
|
||||
* Usuable memory: PHYSMEM_START ~ PERIPHERAL_BASE
|
||||
*/
|
||||
for (idx = start_entry_idx; idx < end_entry_idx; ++idx) {
|
||||
boot_ttbr1_l2[idx] = (PHYSMEM_START + idx * SIZE_2M)
|
||||
| UXN /* Unprivileged execute never */
|
||||
| ACCESSED /* Set access flag */
|
||||
| INNER_SHARABLE /* Sharebility */
|
||||
| NORMAL_MEMORY /* Normal memory */
|
||||
| IS_VALID;
|
||||
}
|
||||
|
||||
/* Peripheral memory: PERIPHERAL_BASE ~ PHYSMEM_END */
|
||||
start_entry_idx = end_entry_idx;
|
||||
end_entry_idx = PHYSMEM_END / SIZE_2M;
|
||||
|
||||
/* Map each 2M page */
|
||||
for (idx = start_entry_idx; idx < end_entry_idx; ++idx) {
|
||||
boot_ttbr1_l2[idx] = (PHYSMEM_START + idx * SIZE_2M)
|
||||
| UXN /* Unprivileged execute never */
|
||||
| ACCESSED /* Set access flag */
|
||||
| DEVICE_MEMORY /* Device memory */
|
||||
| IS_VALID;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local peripherals, e.g., ARM timer, IRQs, and mailboxes
|
||||
*
|
||||
* 0x4000_0000 .. 0xFFFF_FFFF
|
||||
* 1G is enough. Map 1G page here.
|
||||
*/
|
||||
kva = KERNEL_VADDR + PHYSMEM_END;
|
||||
boot_ttbr1_l1[GET_L1_INDEX(kva)] = PHYSMEM_END | UXN /* Unprivileged execute never */
|
||||
| ACCESSED /* Set access flag */
|
||||
| DEVICE_MEMORY /* Device memory */
|
||||
| IS_VALID;
|
||||
}
|
32
lab1/boot/start.S
Normal file
32
lab1/boot/start.S
Normal file
@ -0,0 +1,32 @@
|
||||
#include <common/asm.h>
|
||||
|
||||
.extern arm64_elX_to_el1
|
||||
.extern boot_cpu_stack
|
||||
.extern secondary_boot_flag
|
||||
.extern clear_bss_flag
|
||||
.extern init_c
|
||||
|
||||
BEGIN_FUNC(_start)
|
||||
mrs x8, mpidr_el1
|
||||
and x8, x8, #0xFF
|
||||
cbz x8, primary
|
||||
|
||||
/* hang all secondary processors before we intorduce multi-processors */
|
||||
secondary_hang:
|
||||
bl secondary_hang
|
||||
|
||||
primary:
|
||||
|
||||
/* Turn to el1 from other exception levels. */
|
||||
bl arm64_elX_to_el1
|
||||
|
||||
/* Prepare stack pointer and jump to C. */
|
||||
adr x0, boot_cpu_stack
|
||||
add x0, x0, #0x1000
|
||||
mov sp, x0
|
||||
|
||||
bl init_c
|
||||
|
||||
/* Should never be here */
|
||||
b .
|
||||
END_FUNC(_start)
|
288
lab1/boot/tools.S
Normal file
288
lab1/boot/tools.S
Normal file
@ -0,0 +1,288 @@
|
||||
// Copyright 2016 The Fuchsia Authors
|
||||
// Copyright (c) 2014, Google Inc. All rights reserved
|
||||
//
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Sergey Matyukevich
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ChCore refers to both
|
||||
* https://github.com/s-matyukevich/raspberry-pi-os/blob/master/docs/lesson01/rpi-os.md
|
||||
* and Google Zircon for implementing the boot helper functions.
|
||||
*/
|
||||
|
||||
#include <common/asm.h>
|
||||
#include <common/registers.h>
|
||||
|
||||
|
||||
#define CURRENTEL_EL1 (0b01 << 2)
|
||||
#define CURRENTEL_EL2 (0b10 << 2)
|
||||
|
||||
#define CPACR_EL1_FPEN (0b11 << 20)
|
||||
#define ID_AA64PFR0_EL1_GIC (0b1111 << 24)
|
||||
|
||||
#define CNTHCTL_EL2_EL1PCEN (1 << 1)
|
||||
#define CNTHCTL_EL2_EL1PCTEN (1 << 0)
|
||||
#define CPTR_EL2_RES1 0x33ff
|
||||
#define HCR_EL2_RW (1 << 31)
|
||||
#define ICC_SRE_EL2_SRE (1 << 0)
|
||||
#define ICC_SRE_EL2_ENABLE (1 << 3)
|
||||
|
||||
#define SCR_EL3_HCE (1 << 8)
|
||||
#define SCR_EL3_NS (1 << 0)
|
||||
#define SCR_EL3_RW (1 << 10)
|
||||
|
||||
#define SPSR_ELX_DAIF (0b1111 << 6)
|
||||
#define SPSR_ELX_EL1H (0b0101)
|
||||
|
||||
#define ICH_HCR_EL2 S3_4_C12_C11_0
|
||||
#define ICC_SRE_EL2 S3_4_C12_C9_5
|
||||
|
||||
BEGIN_FUNC(arm64_elX_to_el1)
|
||||
mrs x9, CurrentEL
|
||||
|
||||
// Check the current exception level.
|
||||
cmp x9, CURRENTEL_EL1
|
||||
beq .Ltarget
|
||||
cmp x9, CURRENTEL_EL2
|
||||
beq .Lin_el2
|
||||
// Otherwise, we are in EL3.
|
||||
|
||||
// Set EL2 to 64bit and enable the HVC instruction.
|
||||
mrs x9, scr_el3
|
||||
mov x10, SCR_EL3_NS | SCR_EL3_HCE | SCR_EL3_RW
|
||||
orr x9, x9, x10
|
||||
msr scr_el3, x9
|
||||
|
||||
// Set the return address and exception level.
|
||||
adr x9, .Ltarget
|
||||
msr elr_el3, x9
|
||||
mov x9, SPSR_ELX_DAIF | SPSR_ELX_EL1H
|
||||
msr spsr_el3, x9
|
||||
|
||||
.Lin_el2:
|
||||
// Disable EL1 timer traps and the timer offset.
|
||||
mrs x9, cnthctl_el2
|
||||
orr x9, x9, CNTHCTL_EL2_EL1PCEN | CNTHCTL_EL2_EL1PCTEN
|
||||
msr cnthctl_el2, x9
|
||||
msr cntvoff_el2, xzr
|
||||
|
||||
// Disable stage 2 translations.
|
||||
msr vttbr_el2, xzr
|
||||
|
||||
// Disable EL2 coprocessor traps.
|
||||
mov x9, CPTR_EL2_RES1
|
||||
msr cptr_el2, x9
|
||||
|
||||
// Disable EL1 FPU traps.
|
||||
mov x9, CPACR_EL1_FPEN
|
||||
msr cpacr_el1, x9
|
||||
|
||||
// Check whether the GIC system registers are supported.
|
||||
mrs x9, id_aa64pfr0_el1
|
||||
and x9, x9, ID_AA64PFR0_EL1_GIC
|
||||
cbz x9, .Lno_gic_sr
|
||||
|
||||
// Enable the GIC system registers in EL2, and allow their use in EL1.
|
||||
mrs x9, ICC_SRE_EL2
|
||||
mov x10, ICC_SRE_EL2_ENABLE | ICC_SRE_EL2_SRE
|
||||
orr x9, x9, x10
|
||||
msr ICC_SRE_EL2, x9
|
||||
|
||||
// Disable the GIC virtual CPU interface.
|
||||
msr ICH_HCR_EL2, xzr
|
||||
|
||||
.Lno_gic_sr:
|
||||
// Set EL1 to 64bit.
|
||||
mov x9, HCR_EL2_RW
|
||||
msr hcr_el2, x9
|
||||
|
||||
// Set the return address and exception level.
|
||||
adr x9, .Ltarget
|
||||
msr elr_el2, x9
|
||||
mov x9, SPSR_ELX_DAIF | SPSR_ELX_EL1H
|
||||
msr spsr_el2, x9
|
||||
|
||||
isb
|
||||
eret
|
||||
|
||||
.Ltarget:
|
||||
ret
|
||||
END_FUNC(arm64_elX_to_el1)
|
||||
|
||||
BEGIN_FUNC(invalidate_cache_all)
|
||||
mrs x0, clidr_el1
|
||||
and w3, w0, #0x07000000 // get 2x level of coherence
|
||||
lsr w3, w3, #23
|
||||
cbz w3, .Lfinished_inv_cache
|
||||
mov w10, #0 // w10 = 2x cache level
|
||||
mov w8, #1 // w8 = constant 1
|
||||
.Lloop1_inv_cache:
|
||||
add w2, w10, w10, lsr #1 // calculate 3x cache level
|
||||
lsr w1, w0, w2 // extract 3 bit cache type for this level
|
||||
and w1, w1, #0x7
|
||||
cmp w1, #2
|
||||
b.lt .Lskip_inv_cache // no data or unified cache at this level
|
||||
msr csselr_el1, x10 // select this cache level
|
||||
isb // synchronize change to csselr
|
||||
mrs x1, ccsidr_el1 // w1 = ccsidr
|
||||
and w2, w1, #7 // w2 = log2(line len) - 4
|
||||
add w2, w2, #4 // w2 = log2(line len)
|
||||
ubfx w4, w1, #3, #10 // w4 = max way number, right aligned
|
||||
clz w5, w4 // w5 = 32 - log2(ways), bit position of way in DC operand
|
||||
lsl w9, w4, w5 // w9 = max way number, aligned to position in DC operand
|
||||
lsl w12, w8, w5 // w12 = amount to decrement way number per iteration
|
||||
|
||||
.Lloop2_inv_cache:
|
||||
ubfx w7, w1, #13, #15 // w7 = max set number, right aligned
|
||||
lsl w7, w7, w2 // w7 = max set number, aligned to position in DC operand
|
||||
lsl w13, w8, w2 // w13 = amount to decrement set number per iteration
|
||||
.Lloop3_inv_cache:
|
||||
orr w11, w10, w9 // w11 = combine way number and cache number
|
||||
orr w11, w11, w7 // and set number for DC operand
|
||||
dc isw, x11 // data cache op
|
||||
subs w7, w7, w13 // decrement set number
|
||||
b.ge .Lloop3_inv_cache
|
||||
|
||||
subs w9, w9, w12 // decrement way number
|
||||
b.ge .Lloop2_inv_cache
|
||||
.Lskip_inv_cache:
|
||||
add w10, w10, #2 // increment 2x cache level
|
||||
cmp w3, w10
|
||||
dsb sy // ensure completetion of previous cache maintainance instructions
|
||||
b.gt .Lloop1_inv_cache
|
||||
.Lfinished_inv_cache:
|
||||
|
||||
// dump the instruction cache as well
|
||||
ic iallu
|
||||
isb
|
||||
ret
|
||||
END_FUNC(invalidate_cache_all)
|
||||
|
||||
.extern boot_ttbr0_l0
|
||||
.extern boot_ttbr1_l0
|
||||
|
||||
|
||||
/* Device-nGnRE memory */
|
||||
#define MMU_MAIR_ATTR1 (0x04 << (8 * 1))
|
||||
|
||||
/* Normal Memory, Outer Write-back non-transient Read/Write allocate,
|
||||
* Inner Write-back non-transient Read/Write allocate
|
||||
*/
|
||||
#define MMU_MAIR_ATTR2 (0xff << (8 * 2))
|
||||
|
||||
/* Normal Memory, Inner/Outer uncached, Write Combined */
|
||||
#define MMU_MAIR_ATTR3 (0x44 << (8 * 3))
|
||||
|
||||
|
||||
/*
|
||||
* Enable cached page table walks:
|
||||
* inner/outer (IRGN/ORGN): write-back + write-allocate
|
||||
*/
|
||||
#define MMU_TCR_TG1_4k (0 << 14)
|
||||
#define MMU_TCR_SH1_INNER_SH (3 << 28)
|
||||
#define MMU_TCR_ORGN1_WBA (1 << 26)
|
||||
#define MMU_TCR_IRGN1_WBA (1 << 24)
|
||||
#define MMU_TCR_T1SZ ((64 - 48) << 16) /* 48-bit */
|
||||
#define MMU_TCR_FLAGS1 (MMU_TCR_TG1_4k | MMU_TCR_SH1_INNER_SH | \
|
||||
MMU_TCR_ORGN1_WBA | MMU_TCR_IRGN1_WBA | MMU_TCR_T1SZ)
|
||||
|
||||
#define MMU_TCR_TG0_4k (0 << 30)
|
||||
#define MMU_TCR_SH0_INNER_SH (3 << 12)
|
||||
#define MMU_TCR_ORGN0_WBA (1 << 10)
|
||||
#define MMU_TCR_IRGN0_WBA (1 << 8)
|
||||
#define MMU_TCR_T0SZ ((64 - 48) << 0) /* 48-bit */
|
||||
#define MMU_TCR_FLAGS0 (MMU_TCR_TG0_4k | MMU_TCR_SH0_INNER_SH | \
|
||||
MMU_TCR_ORGN0_WBA | MMU_TCR_IRGN0_WBA | MMU_TCR_T0SZ)
|
||||
#define MMU_TCR_IPS (0b101 << 32) /* 48-bit */
|
||||
#define MMU_TCR_AS (1 << 36)
|
||||
|
||||
|
||||
BEGIN_FUNC(el1_mmu_activate)
|
||||
stp x29, x30, [sp, #-16]!
|
||||
mov x29, sp
|
||||
|
||||
bl invalidate_cache_all
|
||||
|
||||
/* Invalidate TLB */
|
||||
tlbi vmalle1is
|
||||
isb
|
||||
dsb sy
|
||||
|
||||
/* Initialize Memory Attribute Indirection Register */
|
||||
ldr x8, =MMU_MAIR_ATTR1 | MMU_MAIR_ATTR2 | MMU_MAIR_ATTR3
|
||||
msr mair_el1, x8
|
||||
|
||||
/* Initialize TCR_EL1 */
|
||||
/* set cacheable attributes on translation walk */
|
||||
/* (SMP extensions) non-shareable, inner write-back write-allocate */
|
||||
ldr x8, =MMU_TCR_FLAGS1 | MMU_TCR_FLAGS0 | MMU_TCR_IPS | MMU_TCR_AS
|
||||
msr tcr_el1, x8
|
||||
isb
|
||||
|
||||
/* Write ttbr with phys addr of the translation table */
|
||||
adrp x8, boot_ttbr0_l0
|
||||
msr ttbr0_el1, x8
|
||||
adrp x8, boot_ttbr1_l0
|
||||
msr ttbr1_el1, x8
|
||||
isb
|
||||
|
||||
mrs x8, sctlr_el1
|
||||
/* Enable MMU */
|
||||
orr x8, x8, #SCTLR_EL1_M
|
||||
/* Disable alignment checking */
|
||||
bic x8, x8, #SCTLR_EL1_A
|
||||
bic x8, x8, #SCTLR_EL1_SA0
|
||||
bic x8, x8, #SCTLR_EL1_SA
|
||||
orr x8, x8, #SCTLR_EL1_nAA
|
||||
/* Data accesses Cacheable */
|
||||
orr x8, x8, #SCTLR_EL1_C
|
||||
/* Instruction access Cacheable */
|
||||
orr x8, x8, #SCTLR_EL1_I
|
||||
msr sctlr_el1, x8
|
||||
|
||||
ldp x29, x30, [sp], #16
|
||||
ret
|
||||
END_FUNC(el1_mmu_activate)
|
||||
|
||||
|
||||
/* These simple function is written by ChCorers */
|
||||
BEGIN_FUNC(early_put32)
|
||||
str w1, [x0]
|
||||
ret
|
||||
END_FUNC(early_put32)
|
||||
|
||||
BEGIN_FUNC(early_get32)
|
||||
ldr w0, [x0]
|
||||
ret
|
||||
END_FUNC(early_get32)
|
||||
|
||||
BEGIN_FUNC(delay)
|
||||
subs x0, x0, #1
|
||||
bne delay
|
||||
ret
|
||||
END_FUNC(delay)
|
79
lab1/boot/uart.c
Normal file
79
lab1/boot/uart.c
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Sergey Matyukevich
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ChCore refers to
|
||||
* https://github.com/s-matyukevich/raspberry-pi-os/blob/master/docs/lesson01/rpi-os.md
|
||||
* for the min-uart init process.
|
||||
*/
|
||||
|
||||
#include "uart.h"
|
||||
|
||||
void early_uart_init(void)
|
||||
{
|
||||
unsigned int ra;
|
||||
|
||||
ra = early_get32(GPFSEL1);
|
||||
ra &= ~(7 << 12);
|
||||
ra |= 2 << 12;
|
||||
ra &= ~(7 << 15);
|
||||
ra |= 2 << 15;
|
||||
early_put32(GPFSEL1, ra);
|
||||
|
||||
early_put32(GPPUD, 0);
|
||||
delay(150);
|
||||
early_put32(GPPUDCLK0, (1 << 14) | (1 << 15));
|
||||
delay(150);
|
||||
early_put32(GPPUDCLK0, 0);
|
||||
|
||||
early_put32(AUX_ENABLES, 1);
|
||||
early_put32(AUX_MU_IER_REG, 0);
|
||||
early_put32(AUX_MU_CNTL_REG, 0);
|
||||
early_put32(AUX_MU_IER_REG, 0);
|
||||
early_put32(AUX_MU_LCR_REG, 3);
|
||||
early_put32(AUX_MU_MCR_REG, 0);
|
||||
early_put32(AUX_MU_BAUD_REG, 270);
|
||||
|
||||
early_put32(AUX_MU_CNTL_REG, 3);
|
||||
}
|
||||
|
||||
unsigned int early_uart_lsr(void)
|
||||
{
|
||||
return early_get32(AUX_MU_LSR_REG);
|
||||
}
|
||||
|
||||
static void early_uart_send(unsigned int c)
|
||||
{
|
||||
while (1) {
|
||||
if (early_uart_lsr() & 0x20)
|
||||
break;
|
||||
}
|
||||
early_put32(AUX_MU_IO_REG, c);
|
||||
}
|
||||
|
||||
void uart_send_string(char *str)
|
||||
{
|
||||
for (int i = 0; str[i] != '\0'; i++)
|
||||
early_uart_send((char)str[i]);
|
||||
}
|
58
lab1/boot/uart.h
Normal file
58
lab1/boot/uart.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Sergey Matyukevich
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ChCore refers to
|
||||
* https://github.com/s-matyukevich/raspberry-pi-os/blob/master/docs/lesson01/rpi-os.md
|
||||
* for the min-uart init process.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* This peripheral mapped offset is specific to BCM2837 */
|
||||
#define PHYSADDR_OFFSET 0x3F000000UL
|
||||
|
||||
/* BCM2835 and BCM2837 define the same offsets */
|
||||
#define GPFSEL1 (PHYSADDR_OFFSET + 0x00200004)
|
||||
#define GPSET0 (PHYSADDR_OFFSET + 0x0020001C)
|
||||
#define GPCLR0 (PHYSADDR_OFFSET + 0x00200028)
|
||||
#define GPPUD (PHYSADDR_OFFSET + 0x00200094)
|
||||
#define GPPUDCLK0 (PHYSADDR_OFFSET + 0x00200098)
|
||||
|
||||
#define AUX_ENABLES (PHYSADDR_OFFSET + 0x00215004)
|
||||
#define AUX_MU_IO_REG (PHYSADDR_OFFSET + 0x00215040)
|
||||
#define AUX_MU_IER_REG (PHYSADDR_OFFSET + 0x00215044)
|
||||
#define AUX_MU_IIR_REG (PHYSADDR_OFFSET + 0x00215048)
|
||||
#define AUX_MU_LCR_REG (PHYSADDR_OFFSET + 0x0021504C)
|
||||
#define AUX_MU_MCR_REG (PHYSADDR_OFFSET + 0x00215050)
|
||||
#define AUX_MU_LSR_REG (PHYSADDR_OFFSET + 0x00215054)
|
||||
#define AUX_MU_MSR_REG (PHYSADDR_OFFSET + 0x00215058)
|
||||
#define AUX_MU_SCRATCH (PHYSADDR_OFFSET + 0x0021505C)
|
||||
#define AUX_MU_CNTL_REG (PHYSADDR_OFFSET + 0x00215060)
|
||||
#define AUX_MU_STAT_REG (PHYSADDR_OFFSET + 0x00215064)
|
||||
#define AUX_MU_BAUD_REG (PHYSADDR_OFFSET + 0x00215068)
|
||||
|
||||
void early_put32(unsigned long int addr, unsigned int ch);
|
||||
unsigned int early_get32(unsigned long int addr);
|
||||
void delay(unsigned long time);
|
10
lab1/kernel/CMakeLists.txt
Normal file
10
lab1/kernel/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
add_library(${PROJECT_NAME}-arch OBJECT
|
||||
head.S
|
||||
main.c
|
||||
monitor.c
|
||||
common/tools.S
|
||||
common/uart.c
|
||||
common/printk.c
|
||||
)
|
39
lab1/kernel/common/asm.h
Normal file
39
lab1/kernel/common/asm.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define __ASM__
|
||||
|
||||
#define BEGIN_FUNC(_name) \
|
||||
.global _name; \
|
||||
.type _name, %function; \
|
||||
_name:
|
||||
|
||||
#define END_FUNC(_name) \
|
||||
.size _name, .-_name
|
||||
|
||||
#define EXPORT(symbol) \
|
||||
.globl symbol; \
|
||||
symbol:
|
||||
|
||||
#define LOCAL_DATA(x) \
|
||||
.type x,1; \
|
||||
x:
|
||||
|
||||
#define DATA(x) \
|
||||
.global x; \
|
||||
.hidden x; \
|
||||
LOCAL_DATA(x)
|
||||
|
||||
#define END_DATA(x) \
|
||||
.size x, .-x
|
39
lab1/kernel/common/kprint.h
Normal file
39
lab1/kernel/common/kprint.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "printk.h"
|
||||
|
||||
#define WARNING 0
|
||||
#define INFO 1
|
||||
#define DEBUG 2
|
||||
|
||||
/* LOG_LEVEL is INFO by default */
|
||||
|
||||
#if LOG_LEVEL >= WARNING
|
||||
#define kwarn(fmt, ...) printk("[WARN] "fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define kwarn(fmt, ...)
|
||||
#endif
|
||||
|
||||
#if LOG_LEVEL >= INFO
|
||||
#define kinfo(fmt, ...) printk("[INFO] "fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define kinfo(fmt, ...)
|
||||
#endif
|
||||
|
||||
#if LOG_LEVEL >= DEBUG
|
||||
#define kdebug(fmt, ...) printk("[DEBUG] "fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define kdebug(fmt, ...)
|
||||
#endif
|
33
lab1/kernel/common/machine.h
Normal file
33
lab1/kernel/common/machine.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/vars.h>
|
||||
|
||||
/* raspi3 config */
|
||||
#define PLAT_CPU_NUM 4
|
||||
|
||||
// Timers interrupt control registers
|
||||
#define IMER_IRQCNTL_BASE (KBASE + 0x40000040)
|
||||
#define CORE0_TIMER_IRQCNTL (IMER_IRQCNTL_BASE + 0x0)
|
||||
#define CORE1_TIMER_IRQCNTL (IMER_IRQCNTL_BASE + 0x4)
|
||||
#define CORE2_TIMER_IRQCNTL (IMER_IRQCNTL_BASE + 0x8)
|
||||
#define CORE3_TIMER_IRQCNTL (IMER_IRQCNTL_BASE + 0xc)
|
||||
#define INT_SRC_TIMER3 0x008
|
||||
|
||||
// IRQ & FIQ source registers
|
||||
#define IRQ_BASE (KBASE + 0x40000060)
|
||||
#define CORE0_IRQ (IRQ_BASE + 0x0)
|
||||
#define CORE1_IRQ (IRQ_BASE + 0x4)
|
||||
#define CORE2_IRQ (IRQ_BASE + 0x8)
|
||||
#define CORE3_IRQ (IRQ_BASE + 0xc)
|
71
lab1/kernel/common/macro.h
Normal file
71
lab1/kernel/common/macro.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define ALIGN(n) __attribute__((__aligned__(n)))
|
||||
|
||||
#define ROUND_UP(x, n) (((x) + (n) - 1) & ~((n) - 1))
|
||||
#define ROUND_DOWN(x, n) ((x) & ~((n) - 1))
|
||||
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
|
||||
|
||||
#define BUG_ON(expr) \
|
||||
do { \
|
||||
if ((expr)) { \
|
||||
printk("BUG: %s:%d %s\n", __func__, __LINE__, #expr); \
|
||||
for (;;) { \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BUG(str) \
|
||||
do { \
|
||||
printk("BUG: %s:%d %s\n", __func__, __LINE__, str); \
|
||||
for (;;) { \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define WARN(msg) \
|
||||
printk("WARN: %s:%d %s\n", __func__, __LINE__, msg)
|
||||
|
||||
#define WARN_ON(cond, msg) \
|
||||
do { \
|
||||
if ((cond)) { \
|
||||
printk("WARN: %s:%d %s on " #cond "\n", \
|
||||
__func__, __LINE__, msg); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define likely(x) (!!(x))
|
||||
#define unlikely(x) (!!(x))
|
||||
#endif // __GNUC__
|
||||
|
||||
#define BIT(x) (1UL << (x))
|
||||
|
||||
#define offsetof(TYPE, MEMBER) ((u64)&((TYPE *)0)->MEMBER)
|
||||
#define container_of(ptr, type, field) \
|
||||
((type *)((void *)(ptr) - (u64)(&(((type *)(0))->field))))
|
||||
|
||||
#define container_of_safe(ptr, type, field) ({ \
|
||||
typeof (ptr) __ptr = (ptr); \
|
||||
type *__obj = container_of(__ptr, type, field); \
|
||||
(__ptr ? __obj : NULL); \
|
||||
})
|
||||
|
||||
#define MAX(x, y) ((x) < (y) ? (y) : (x))
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0)
|
56
lab1/kernel/common/peripherals.h
Normal file
56
lab1/kernel/common/peripherals.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Sergey Matyukevich
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ChCore refers to
|
||||
* https://github.com/s-matyukevich/raspberry-pi-os/blob/master/docs/lesson01/rpi-os.md
|
||||
* for the min-uart init process.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/vars.h>
|
||||
|
||||
/* This peripheral mapped offset is specific to BCM2837 */
|
||||
#define PHYSADDR_OFFSET (KBASE + 0x3F000000UL)
|
||||
|
||||
/* BCM2835 and BCM2837 define the same offsets */
|
||||
#define GPFSEL1 (PHYSADDR_OFFSET + 0x00200004)
|
||||
#define GPSET0 (PHYSADDR_OFFSET + 0x0020001C)
|
||||
#define GPCLR0 (PHYSADDR_OFFSET + 0x00200028)
|
||||
#define GPPUD (PHYSADDR_OFFSET + 0x00200094)
|
||||
#define GPPUDCLK0 (PHYSADDR_OFFSET + 0x00200098)
|
||||
|
||||
#define AUX_ENABLES (PHYSADDR_OFFSET + 0x00215004)
|
||||
#define AUX_MU_IO_REG (PHYSADDR_OFFSET + 0x00215040)
|
||||
#define AUX_MU_IER_REG (PHYSADDR_OFFSET + 0x00215044)
|
||||
#define AUX_MU_IIR_REG (PHYSADDR_OFFSET + 0x00215048)
|
||||
#define AUX_MU_LCR_REG (PHYSADDR_OFFSET + 0x0021504C)
|
||||
#define AUX_MU_MCR_REG (PHYSADDR_OFFSET + 0x00215050)
|
||||
#define AUX_MU_LSR_REG (PHYSADDR_OFFSET + 0x00215054)
|
||||
#define AUX_MU_MSR_REG (PHYSADDR_OFFSET + 0x00215058)
|
||||
#define AUX_MU_SCRATCH (PHYSADDR_OFFSET + 0x0021505C)
|
||||
#define AUX_MU_CNTL_REG (PHYSADDR_OFFSET + 0x00215060)
|
||||
#define AUX_MU_STAT_REG (PHYSADDR_OFFSET + 0x00215064)
|
||||
#define AUX_MU_BAUD_REG (PHYSADDR_OFFSET + 0x00215068)
|
493
lab1/kernel/common/printk.c
Normal file
493
lab1/kernel/common/printk.c
Normal file
@ -0,0 +1,493 @@
|
||||
/*
|
||||
* BSD-3-Clause License
|
||||
*
|
||||
* Copyright (c) 2016, Matt Redfearn
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. 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.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder 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.
|
||||
*/
|
||||
#include <common/uart.h>
|
||||
|
||||
#define PRINT_BUF_LEN 64
|
||||
|
||||
typedef __builtin_va_list va_list;
|
||||
#define va_start(v,l) __builtin_va_start(v,l)
|
||||
#define va_end(v) __builtin_va_end(v)
|
||||
#define va_arg(v,l) __builtin_va_arg(v,l)
|
||||
#define va_copy(d,s) __builtin_va_copy(d,s)
|
||||
|
||||
static void simple_outputchar(char **str, char c)
|
||||
{
|
||||
if (str) {
|
||||
**str = c;
|
||||
++(*str);
|
||||
} else {
|
||||
uart_send(c);
|
||||
}
|
||||
}
|
||||
|
||||
enum flags {
|
||||
PAD_ZERO = 1,
|
||||
PAD_RIGHT = 2
|
||||
};
|
||||
|
||||
static int prints(char **out, const char *string, int width, int flags)
|
||||
{
|
||||
int pc = 0, padchar = ' ';
|
||||
|
||||
if (width > 0) {
|
||||
int len = 0;
|
||||
const char *ptr;
|
||||
for (ptr = string; *ptr; ++ptr)
|
||||
++len;
|
||||
if (len >= width)
|
||||
width = 0;
|
||||
else
|
||||
width -= len;
|
||||
if (flags & PAD_ZERO)
|
||||
padchar = '0';
|
||||
}
|
||||
if (!(flags & PAD_RIGHT)) {
|
||||
for (; width > 0; --width) {
|
||||
simple_outputchar(out, padchar);
|
||||
++pc;
|
||||
}
|
||||
}
|
||||
for (; *string; ++string) {
|
||||
simple_outputchar(out, *string);
|
||||
++pc;
|
||||
}
|
||||
for (; width > 0; --width) {
|
||||
simple_outputchar(out, padchar);
|
||||
++pc;
|
||||
}
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
// this function print number `i` in the base of `base` (base > 1)
|
||||
// `sign` is the flag of print signed number or unsigned number
|
||||
// `width` and `flags` mean the length of printed number at least `width`,
|
||||
// if the length of number is less than `width`, choose PAD_ZERO or PAD_RIGHT
|
||||
// `letbase` means uppercase('A') or lowercase('a') when using hex
|
||||
// you may need to call `prints`
|
||||
// you do not need to print prefix like "0x", "0"...
|
||||
// Remember the most significant digit is printed first.
|
||||
static int printk_write_num(char **out, long long i, int base, int sign,
|
||||
int width, int flags, int letbase)
|
||||
{
|
||||
char print_buf[PRINT_BUF_LEN];
|
||||
char *s;
|
||||
int t, neg = 0, pc = 0;
|
||||
unsigned long long u = i;
|
||||
|
||||
if (i == 0) {
|
||||
print_buf[0] = '0';
|
||||
print_buf[1] = '\0';
|
||||
return prints(out, print_buf, width, flags);
|
||||
}
|
||||
|
||||
if (sign && base == 10 && i < 0) {
|
||||
neg = 1;
|
||||
u = -i;
|
||||
}
|
||||
// TODO: fill your code here
|
||||
// store the digitals in the buffer `print_buf`:
|
||||
// 1. the last postion of this buffer must be '\0'
|
||||
// 2. the format is only decided by `base` and `letbase` here
|
||||
int len = 0;
|
||||
s = print_buf + 1;
|
||||
while (u > 0) {
|
||||
t = u % base;
|
||||
u /= base;
|
||||
if (t <= 9)
|
||||
s[len++] = t + '0';
|
||||
else
|
||||
s[len++] = t - 10 + (letbase ? 'a': 'A');
|
||||
}
|
||||
s[len] = '\0';
|
||||
// swap print_buf
|
||||
char ch;
|
||||
for (int i = 0; i < len / 2; i++) {
|
||||
ch = s[i];
|
||||
s[i] = s[len - 1 - i];
|
||||
s[len - 1 - i] = ch;
|
||||
}
|
||||
|
||||
if (neg) {
|
||||
if (width && (flags & PAD_ZERO)) {
|
||||
simple_outputchar(out, '-');
|
||||
++pc;
|
||||
--width;
|
||||
} else {
|
||||
*--s = '-';
|
||||
}
|
||||
}
|
||||
|
||||
return pc + prints(out, s, width, flags);
|
||||
}
|
||||
|
||||
static int simple_vsprintf(char **out, const char *format, va_list ap)
|
||||
{
|
||||
int width, flags;
|
||||
int pc = 0;
|
||||
char scr[2];
|
||||
union {
|
||||
char c;
|
||||
char *s;
|
||||
int i;
|
||||
unsigned int u;
|
||||
long li;
|
||||
unsigned long lu;
|
||||
long long lli;
|
||||
unsigned long long llu;
|
||||
short hi;
|
||||
unsigned short hu;
|
||||
signed char hhi;
|
||||
unsigned char hhu;
|
||||
void *p;
|
||||
} u;
|
||||
|
||||
for (; *format != 0; ++format) {
|
||||
if (*format == '%') {
|
||||
++format;
|
||||
width = flags = 0;
|
||||
if (*format == '\0')
|
||||
break;
|
||||
if (*format == '%')
|
||||
goto out;
|
||||
if (*format == '-') {
|
||||
++format;
|
||||
flags = PAD_RIGHT;
|
||||
}
|
||||
while (*format == '0') {
|
||||
++format;
|
||||
flags |= PAD_ZERO;
|
||||
}
|
||||
if (*format == '*') {
|
||||
width = va_arg(ap, int);
|
||||
format++;
|
||||
} else {
|
||||
for (; *format >= '0' && *format <= '9';
|
||||
++format) {
|
||||
width *= 10;
|
||||
width += *format - '0';
|
||||
}
|
||||
}
|
||||
switch (*format) {
|
||||
case ('d'):
|
||||
u.i = va_arg(ap, int);
|
||||
pc +=
|
||||
printk_write_num(out, u.i, 10, 1, width,
|
||||
flags, 'a');
|
||||
break;
|
||||
|
||||
case ('u'):
|
||||
u.u = va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.u, 10, 0, width,
|
||||
flags, 'a');
|
||||
break;
|
||||
|
||||
case ('o'):
|
||||
u.u = va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.u, 8, 0, width,
|
||||
flags, 'a');
|
||||
break;
|
||||
|
||||
case ('x'):
|
||||
u.u = va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.u, 16, 0, width,
|
||||
flags, 'a');
|
||||
break;
|
||||
|
||||
case ('X'):
|
||||
u.u = va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.u, 16, 0, width,
|
||||
flags, 'A');
|
||||
break;
|
||||
|
||||
case ('p'):
|
||||
u.lu = va_arg(ap, unsigned long);
|
||||
pc +=
|
||||
printk_write_num(out, u.lu, 16, 0, width,
|
||||
flags, 'a');
|
||||
break;
|
||||
|
||||
case ('c'):
|
||||
u.c = va_arg(ap, int);
|
||||
scr[0] = u.c;
|
||||
scr[1] = '\0';
|
||||
pc += prints(out, scr, width, flags);
|
||||
break;
|
||||
|
||||
case ('s'):
|
||||
u.s = va_arg(ap, char *);
|
||||
pc +=
|
||||
prints(out, u.s ? u.s : "(null)", width,
|
||||
flags);
|
||||
break;
|
||||
case ('l'):
|
||||
++format;
|
||||
switch (*format) {
|
||||
case ('d'):
|
||||
u.li = va_arg(ap, long);
|
||||
pc +=
|
||||
printk_write_num(out, u.li, 10, 1,
|
||||
width, flags, 'a');
|
||||
break;
|
||||
|
||||
case ('u'):
|
||||
u.lu = va_arg(ap, unsigned long);
|
||||
pc +=
|
||||
printk_write_num(out, u.lu, 10, 0,
|
||||
width, flags, 'a');
|
||||
break;
|
||||
|
||||
case ('o'):
|
||||
u.lu = va_arg(ap, unsigned long);
|
||||
pc +=
|
||||
printk_write_num(out, u.lu, 8, 0,
|
||||
width, flags, 'a');
|
||||
break;
|
||||
|
||||
case ('x'):
|
||||
u.lu = va_arg(ap, unsigned long);
|
||||
pc +=
|
||||
printk_write_num(out, u.lu, 16, 0,
|
||||
width, flags, 'a');
|
||||
break;
|
||||
|
||||
case ('X'):
|
||||
u.lu = va_arg(ap, unsigned long);
|
||||
pc +=
|
||||
printk_write_num(out, u.lu, 16, 0,
|
||||
width, flags, 'A');
|
||||
break;
|
||||
|
||||
case ('l'):
|
||||
++format;
|
||||
switch (*format) {
|
||||
case ('d'):
|
||||
u.lli = va_arg(ap, long long);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli,
|
||||
10, 1,
|
||||
width,
|
||||
flags,
|
||||
'a');
|
||||
break;
|
||||
|
||||
case ('u'):
|
||||
u.llu =
|
||||
va_arg(ap,
|
||||
unsigned long long);
|
||||
pc +=
|
||||
printk_write_num(out, u.llu,
|
||||
10, 0,
|
||||
width,
|
||||
flags,
|
||||
'a');
|
||||
break;
|
||||
|
||||
case ('o'):
|
||||
u.llu =
|
||||
va_arg(ap,
|
||||
unsigned long long);
|
||||
pc +=
|
||||
printk_write_num(out, u.llu,
|
||||
8, 0,
|
||||
width,
|
||||
flags,
|
||||
'a');
|
||||
break;
|
||||
|
||||
case ('x'):
|
||||
u.llu =
|
||||
va_arg(ap,
|
||||
unsigned long long);
|
||||
pc +=
|
||||
printk_write_num(out, u.llu,
|
||||
16, 0,
|
||||
width,
|
||||
flags,
|
||||
'a');
|
||||
break;
|
||||
|
||||
case ('X'):
|
||||
u.llu =
|
||||
va_arg(ap,
|
||||
unsigned long long);
|
||||
pc +=
|
||||
printk_write_num(out, u.llu,
|
||||
16, 0,
|
||||
width,
|
||||
flags,
|
||||
'A');
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ('h'):
|
||||
++format;
|
||||
switch (*format) {
|
||||
case ('d'):
|
||||
u.hi = va_arg(ap, int);
|
||||
pc +=
|
||||
printk_write_num(out, u.hi, 10, 1,
|
||||
width, flags, 'a');
|
||||
break;
|
||||
|
||||
case ('u'):
|
||||
u.hu = va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli, 10, 0,
|
||||
width, flags, 'a');
|
||||
break;
|
||||
|
||||
case ('o'):
|
||||
u.hu = va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli, 8, 0,
|
||||
width, flags, 'a');
|
||||
break;
|
||||
|
||||
case ('x'):
|
||||
u.hu = va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli, 16, 0,
|
||||
width, flags, 'a');
|
||||
break;
|
||||
|
||||
case ('X'):
|
||||
u.hu = va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli, 16, 0,
|
||||
width, flags, 'A');
|
||||
break;
|
||||
|
||||
case ('h'):
|
||||
++format;
|
||||
switch (*format) {
|
||||
case ('d'):
|
||||
u.hhi = va_arg(ap, int);
|
||||
pc +=
|
||||
printk_write_num(out, u.hhi,
|
||||
10, 1,
|
||||
width,
|
||||
flags,
|
||||
'a');
|
||||
break;
|
||||
|
||||
case ('u'):
|
||||
u.hhu =
|
||||
va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli,
|
||||
10, 0,
|
||||
width,
|
||||
flags,
|
||||
'a');
|
||||
break;
|
||||
|
||||
case ('o'):
|
||||
u.hhu =
|
||||
va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli,
|
||||
8, 0,
|
||||
width,
|
||||
flags,
|
||||
'a');
|
||||
break;
|
||||
|
||||
case ('x'):
|
||||
u.hhu =
|
||||
va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli,
|
||||
16, 0,
|
||||
width,
|
||||
flags,
|
||||
'a');
|
||||
break;
|
||||
|
||||
case ('X'):
|
||||
u.hhu =
|
||||
va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli,
|
||||
16, 0,
|
||||
width,
|
||||
flags,
|
||||
'A');
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
out:
|
||||
simple_outputchar(out, *format);
|
||||
++pc;
|
||||
}
|
||||
}
|
||||
if (out)
|
||||
**out = '\0';
|
||||
return pc;
|
||||
}
|
||||
|
||||
void printk(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
simple_vsprintf(NULL, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void break_point()
|
||||
{
|
||||
printk("[ChCore] Lab stalling ... \n");
|
||||
}
|
16
lab1/kernel/common/printk.h
Normal file
16
lab1/kernel/common/printk.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
void printk(const char *fmt, ...);
|
||||
void break_point();
|
117
lab1/kernel/common/registers.h
Normal file
117
lab1/kernel/common/registers.h
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/macro.h>
|
||||
|
||||
/* ARMv8 AA64 REGISTERS */
|
||||
|
||||
/* SPSR_EL1 Register aarch64 (FROM ARM-ARM C5-395) */
|
||||
/* Holds the saved process state when an exception is taken to EL1 */
|
||||
#define SPSR_EL1_N BIT(31) /* N condition flag */
|
||||
#define SPSR_EL1_Z BIT(30) /* Z condition flag */
|
||||
#define SPSR_EL1_C BIT(29) /* C condition flag */
|
||||
#define SPSR_EL1_V BIT(28) /* V condition flag */
|
||||
#define SPSR_EL1_DIT BIT(24) /* Data Independent Timing PSTATE.DIT ARMv8.4 */
|
||||
#define SPSR_EL1_UAO BIT(23) /* User Access Override PSTATE.UAO ARMv8.2 */
|
||||
#define SPSR_EL1_PAN BIT(22) /* Privileged Access Never PSTATE.PAN ARMv8.1 */
|
||||
#define SPSR_EL1_SS BIT(21) /* Software Step PSTATE.SS */
|
||||
#define SPSR_EL1_IL BIT(20) /* Illegal Execution state PSTATE.IL */
|
||||
#define SPSR_EL1_DEBUG BIT(9) /* Debug mask */
|
||||
#define SPSR_EL1_SERROR BIT(8) /* SERROR mask */
|
||||
#define SPSR_EL1_IRQ BIT(7) /* IRQ mask */
|
||||
#define SPSR_EL1_FIQ BIT(6) /* FIQ mask */
|
||||
#define SPSR_EL1_M BIT(4) /* Exception taken from AArch64 */
|
||||
#define SPSR_EL1_EL0t 0b0000
|
||||
#define SPSR_EL1_EL1t 0b0100
|
||||
#define SPSR_EL1_EL1h 0b0101
|
||||
|
||||
/* SPSR_EL1 DEFAULT */
|
||||
#define SPSR_EL1_KERNEL SPSR_EL1_EL1h
|
||||
#define SPSR_EL1_USER SPSR_EL1_EL0t
|
||||
|
||||
/* SCTLR_EL1 System Control Register aarch64 (FROM ARM-ARM D12-3081) */
|
||||
|
||||
#define SCTLR_EL1_EnIA BIT(31) /* Controls enabling of pointer authentication */
|
||||
#define SCTLR_EL1_EnIB BIT(30) /* Controls enabling of pointer authentication */
|
||||
#define SCTLR_EL1_LSMAOE BIT(29) /* Load Multiple and Store Multiple Atomicity and Ordering Enable */
|
||||
#define SCTLR_EL1_nTLSMD BIT(28) /* No Trap Load Multiple and Store Multiple to Device-nGRE/Device-nGnRE/Device-nGnRnE memory */
|
||||
#define SCTLR_EL1_EnDA BIT(27) /* Controls enabling of pointer authentication */
|
||||
#define SCTLR_EL1_UCI BIT(26) /* Traps EL0 execution of cache maintenance instructions to EL1, from AArch64 state only */
|
||||
#define SCTLR_EL1_EE BIT(25) /* Endianness of data accesses at EL1, and stage 1 translation table walks in the EL1&0 translation regime */
|
||||
#define SCTLR_EL1_E0E BIT(24) /* Endianness of data accesses at EL0 */
|
||||
#define SCTLR_EL1_SPAN BIT(23) /* Set Privileged Access Never, on taking an exception to EL1 */
|
||||
#define SCTLR_EL1_IESB BIT(21) /* Implicit error synchronization event enable */
|
||||
#define SCTLR_EL1_WXN BIT(19) /* Write permission implies XN (Execute-never) */
|
||||
#define SCTLR_EL1_nTWE BIT(18) /* Traps EL0 execution of WFE instructions to EL1, from both Execution states */
|
||||
#define SCTLR_EL1_nTWI BIT(16) /* Traps EL0 execution of WFI instructions to EL1, from both Execution states */
|
||||
#define SCTLR_EL1_UCT BIT(15) /* Traps EL0 accesses to the CTR_EL0 to EL1, from AArch64 state only */
|
||||
#define SCTLR_EL1_DZE BIT(14) /* Traps EL0 execution of DC ZVA instructions to EL1, from AArch64 state only */
|
||||
#define SCTLR_EL1_EnDB BIT(13) /* Controls enabling of pointer authentication */
|
||||
#define SCTLR_EL1_I BIT(12) /* Instruction access Cacheability control, for accesses at EL0 and EL1 */
|
||||
#define SCTLR_EL1_UMA BIT(9) /* User Mask Access: Traps EL0 execution of MSR and MRS instructions that access the PSTATE.{D, A, I, F} */
|
||||
#define SCTLR_EL1_SED BIT(8) /* SETEND instruction disable. Disables SETEND instructions at EL0 using AArch32 */
|
||||
#define SCTLR_EL1_ITD BIT(7) /* IT Disable. Disables some uses of IT instructions at EL0 using AArch32 */
|
||||
#define SCTLR_EL1_nAA BIT(6) /* Non-aligned access. This bit controls generation of Alignment faults at EL1 and EL0 under certain conditions */
|
||||
#define SCTLR_EL1_CP15BEN BIT(5) /* System instruction memory barrier enable (AArch32) */
|
||||
#define SCTLR_EL1_SA0 BIT(4) /* SP Alignment check enable for EL0 */
|
||||
#define SCTLR_EL1_SA BIT(3) /* SP Alignment check */
|
||||
#define SCTLR_EL1_C BIT(2) /* Cacheability control for data accesses */
|
||||
#define SCTLR_EL1_A BIT(1) /* Alignment check enable */
|
||||
#define SCTLR_EL1_M BIT(0) /* MMU enable for EL1 and EL0 stage 1 address translation */
|
||||
|
||||
#ifndef __ASM__
|
||||
/* Types of the registers */
|
||||
enum reg_type {
|
||||
X0 = 0, /* 0x00 */
|
||||
X1 = 1, /* 0x08 */
|
||||
X2 = 2, /* 0x10 */
|
||||
X3 = 3, /* 0x18 */
|
||||
X4 = 4, /* 0x20 */
|
||||
X5 = 5, /* 0x28 */
|
||||
X6 = 6, /* 0x30 */
|
||||
X7 = 7, /* 0x38 */
|
||||
X8 = 8, /* 0x40 */
|
||||
X9 = 9, /* 0x48 */
|
||||
X10 = 10, /* 0x50 */
|
||||
X11 = 11, /* 0x58 */
|
||||
X12 = 12, /* 0x60 */
|
||||
X13 = 13, /* 0x68 */
|
||||
X14 = 14, /* 0x70 */
|
||||
X15 = 15, /* 0x78 */
|
||||
X16 = 16, /* 0x80 */
|
||||
X17 = 17, /* 0x88 */
|
||||
X18 = 18, /* 0x90 */
|
||||
X19 = 19, /* 0x98 */
|
||||
X20 = 20, /* 0xa0 */
|
||||
X21 = 21, /* 0xa8 */
|
||||
X22 = 22, /* 0xb0 */
|
||||
X23 = 23, /* 0xb8 */
|
||||
X24 = 24, /* 0xc0 */
|
||||
X25 = 25, /* 0xc8 */
|
||||
X26 = 26, /* 0xd0 */
|
||||
X27 = 27, /* 0xd8 */
|
||||
X28 = 28, /* 0xe0 */
|
||||
X29 = 29, /* 0xe8 */
|
||||
X30 = 30, /* 0xf0 */
|
||||
SP_EL0 = 31, /* 0xf8 */
|
||||
ELR_EL1 = 32, /* 0x100 NEXT PC */
|
||||
SPSR_EL1 = 33, /* 0x108 */
|
||||
TPIDR_EL0 = 34
|
||||
};
|
||||
#endif /* ASMCODE */
|
||||
|
||||
#define REG_NUM 35
|
||||
|
||||
#define SZ_U64 8
|
||||
#define ARCH_EXEC_CONT_SIZE REG_NUM*SZ_U64 /* Cannot use sizeof in asm */
|
33
lab1/kernel/common/tools.S
Normal file
33
lab1/kernel/common/tools.S
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#include <common/asm.h>
|
||||
|
||||
BEGIN_FUNC(put32)
|
||||
str w1,[x0]
|
||||
ret
|
||||
END_FUNC(put32)
|
||||
|
||||
BEGIN_FUNC(get32)
|
||||
ldr w0,[x0]
|
||||
ret
|
||||
END_FUNC(put32)
|
||||
|
||||
BEGIN_FUNC(put64)
|
||||
str x1,[x0]
|
||||
ret
|
||||
END_FUNC(put32)
|
||||
|
||||
BEGIN_FUNC(get64)
|
||||
ldr x0,[x0]
|
||||
ret
|
||||
END_FUNC(put32)
|
17
lab1/kernel/common/tools.h
Normal file
17
lab1/kernel/common/tools.h
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern void put32(u64 addr, u32 data);
|
||||
extern unsigned int get32(u64 addr);
|
||||
extern void delay(u32 time);
|
162
lab1/kernel/common/types.h
Normal file
162
lab1/kernel/common/types.h
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/macro.h>
|
||||
|
||||
typedef unsigned long long u64;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned char u8;
|
||||
#ifdef CHCORE
|
||||
typedef long long s64;
|
||||
typedef int s32;
|
||||
typedef short s16;
|
||||
typedef signed char s8;
|
||||
|
||||
/* According to `https://pubs.opengroup.org/onlinepubs/9699919799/`. */
|
||||
|
||||
/* Used for file block counts. */
|
||||
typedef s64 blkcnt_t;
|
||||
|
||||
/* Used for block sizes. */
|
||||
typedef s64 blksize_t;
|
||||
|
||||
/* Used for system times in clock ticks or CLOCKS_PER_SEC; see <time.h>. */
|
||||
typedef u64 clock_t;
|
||||
|
||||
/* Used for clock ID type in the clock and timer functions.*/
|
||||
typedef u64 clockid_t;
|
||||
|
||||
/* Used for device IDs. */
|
||||
typedef u64 dev_t;
|
||||
|
||||
/* Used for file system block counts. */
|
||||
typedef u64 fsblkcnt_t;
|
||||
|
||||
/* Used for file system file counts. */
|
||||
typedef u64 fsfilcnt_t;
|
||||
|
||||
/* Used for group IDs. */
|
||||
typedef u64 gid_t;
|
||||
|
||||
/*
|
||||
* Used as a general identifier; can be used to contain at least a pid_t,
|
||||
* uid_t, or gid_t.
|
||||
*/
|
||||
typedef u64 id_t;
|
||||
|
||||
/* Used for file serial numbers. */
|
||||
typedef u64 ino_t;
|
||||
|
||||
/* Used for XSI interprocess communication. */
|
||||
typedef u64 key_t;
|
||||
|
||||
/* Used for some file attributes. */
|
||||
typedef u64 mode_t;
|
||||
|
||||
/* Used for link counts. */
|
||||
typedef u64 nlink_t;
|
||||
|
||||
/* Used for file sizes. */
|
||||
typedef s64 off_t;
|
||||
|
||||
/* Used for process IDs and process group IDs. */
|
||||
typedef s64 pid_t;
|
||||
|
||||
/* Used to identify a thread attribute object. */
|
||||
typedef u64 pthread_attr_t;
|
||||
|
||||
/* Used to identify a barrier. */
|
||||
typedef u64 pthread_barrier_t;
|
||||
|
||||
/* Used to define a barrier attributes object. */
|
||||
typedef u64 pthread_barrierattr_t;
|
||||
|
||||
/* Used for condition variables. */
|
||||
typedef u64 pthread_cond_t;
|
||||
|
||||
/* Used to identify a condition attribute object. */
|
||||
typedef u64 pthread_condattr_t;
|
||||
|
||||
/* Used for thread-specific data keys. */
|
||||
typedef u64 pthread_key_t;
|
||||
|
||||
/* Used for mutexes. */
|
||||
typedef u64 pthread_mutex_t;
|
||||
|
||||
/* Used to identify a mutex attribute object. */
|
||||
typedef u64 pthread_mutexattr_t;
|
||||
|
||||
/* Used for dynamic package initialization. */
|
||||
typedef u64 pthread_once_t;
|
||||
|
||||
/* Used for read-write locks. */
|
||||
typedef u64 pthread_rwlock_t;
|
||||
|
||||
/* Used for read-write lock attributes. */
|
||||
typedef u64 pthread_rwlockattr_t;
|
||||
|
||||
/* Used to identify a spin lock. */
|
||||
typedef u64 pthread_spinlock_t;
|
||||
|
||||
/* Used to identify a thread. */
|
||||
typedef u64 pthread_t;
|
||||
|
||||
/* Used for sizes of objects. */
|
||||
typedef u64 size_t;
|
||||
|
||||
/* Used for a count of bytes or an error indication. */
|
||||
typedef s64 ssize_t;
|
||||
|
||||
/* Used for time in microseconds. */
|
||||
typedef s64 suseconds_t;
|
||||
|
||||
/* Used for time in seconds. */
|
||||
typedef u64 time_t;
|
||||
|
||||
/* Used for timer ID returned by timer_create(). */
|
||||
typedef u64 timer_t;
|
||||
|
||||
/* Used to identify a trace stream attributes object. */
|
||||
typedef u64 trace_attr_t;
|
||||
|
||||
/* Used to identify a trace event type. */
|
||||
typedef u64 trace_event_id_t;
|
||||
|
||||
/* Used to identify a trace event type set. */
|
||||
typedef u64 trace_event_set_t;
|
||||
|
||||
/* Used to identify a trace stream. */
|
||||
typedef u64 trace_id_t;
|
||||
|
||||
/* Used for user IDs. */
|
||||
typedef u64 uid_t;
|
||||
|
||||
#define NULL ((void *)0)
|
||||
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
typedef char bool;
|
||||
#define true (1)
|
||||
#define false (0)
|
||||
typedef u64 paddr_t;
|
||||
typedef u64 vaddr_t;
|
||||
|
||||
typedef u64 atomic_cnt;
|
||||
|
||||
/* Different platform may have different cacheline size and may have some features like prefetch */
|
||||
#define CACHELINE_SZ 64
|
||||
#define pad_to_cache_line(n) (ROUND_UP(n, CACHELINE_SZ) - (n))
|
101
lab1/kernel/common/uart.c
Normal file
101
lab1/kernel/common/uart.c
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Sergey Matyukevich
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ChCore refers to
|
||||
* https://github.com/s-matyukevich/raspberry-pi-os/blob/master/docs/lesson01/rpi-os.md
|
||||
* for the min-uart init process.
|
||||
*/
|
||||
#include <common/machine.h>
|
||||
#include <common/types.h>
|
||||
#include <common/tools.h>
|
||||
#include <common/uart.h>
|
||||
#include <common/peripherals.h>
|
||||
|
||||
void uart_init(void)
|
||||
{
|
||||
unsigned int ra;
|
||||
|
||||
ra = get32(GPFSEL1);
|
||||
ra &= ~(7 << 12);
|
||||
ra |= 2 << 12;
|
||||
ra &= ~(7 << 15);
|
||||
ra |= 2 << 15;
|
||||
put32(GPFSEL1, ra);
|
||||
|
||||
put32(GPPUD, 0);
|
||||
// delay(150);
|
||||
put32(GPPUDCLK0, (1 << 14) | (1 << 15));
|
||||
// delay(150);
|
||||
put32(GPPUDCLK0, 0);
|
||||
|
||||
put32(AUX_ENABLES, 1);
|
||||
put32(AUX_MU_IER_REG, 0);
|
||||
put32(AUX_MU_CNTL_REG, 0);
|
||||
put32(AUX_MU_IER_REG, 0);
|
||||
put32(AUX_MU_LCR_REG, 3);
|
||||
put32(AUX_MU_MCR_REG, 0);
|
||||
put32(AUX_MU_BAUD_REG, 270);
|
||||
|
||||
put32(AUX_MU_CNTL_REG, 3);
|
||||
|
||||
/* Clear the screen */
|
||||
uart_send(12);
|
||||
uart_send(27);
|
||||
uart_send('[');
|
||||
uart_send('2');
|
||||
uart_send('J');
|
||||
}
|
||||
|
||||
u32 uart_lsr(void)
|
||||
{
|
||||
return get32(AUX_MU_LSR_REG);
|
||||
}
|
||||
|
||||
u32 uart_recv(void)
|
||||
{
|
||||
while (1) {
|
||||
if (uart_lsr() & 0x01)
|
||||
break;
|
||||
}
|
||||
|
||||
return (get32(AUX_MU_IO_REG) & 0xFF);
|
||||
}
|
||||
|
||||
u32 nb_uart_recv(void)
|
||||
{
|
||||
if (uart_lsr() & 0x01)
|
||||
return (get32(AUX_MU_IO_REG) & 0xFF);
|
||||
else
|
||||
return NB_UART_NRET;
|
||||
}
|
||||
|
||||
void uart_send(u32 c)
|
||||
{
|
||||
while (1) {
|
||||
if (uart_lsr() & 0x20)
|
||||
break;
|
||||
}
|
||||
put32(AUX_MU_IO_REG, c);
|
||||
}
|
41
lab1/kernel/common/uart.h
Normal file
41
lab1/kernel/common/uart.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Sergey Matyukevich
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ChCore refers to
|
||||
* https://github.com/s-matyukevich/raspberry-pi-os/blob/master/docs/lesson01/rpi-os.md
|
||||
* for the min-uart init process.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/types.h>
|
||||
|
||||
void uart_init(void);
|
||||
u32 uart_recv(void);
|
||||
void uart_send(u32 c);
|
||||
|
||||
#define NB_UART_NRET 0xffffff
|
||||
/* Non-blocking receive */
|
||||
u32 nb_uart_recv(void);
|
23
lab1/kernel/common/vars.h
Normal file
23
lab1/kernel/common/vars.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Leave 8K space to kernel stack */
|
||||
#define KERNEL_STACK_SIZE (8192)
|
||||
#define IDLE_STACK_SIZE (8192)
|
||||
#define STACK_ALIGNMENT 16
|
||||
|
||||
/* can be different in different architectures */
|
||||
#ifndef KBASE
|
||||
#define KBASE 0xffffff0000000000
|
||||
#endif
|
30
lab1/kernel/head.S
Normal file
30
lab1/kernel/head.S
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#include <common/asm.h>
|
||||
#include <common/vars.h>
|
||||
|
||||
BEGIN_FUNC(start_kernel)
|
||||
/*
|
||||
* Code in bootloader specified only the primary
|
||||
* cpu with MPIDR = 0 can be boot here. So we directly
|
||||
* set the TPIDR_EL1 to 0, which represent the logical
|
||||
* cpuid in the kernel
|
||||
*/
|
||||
mov x3, #0
|
||||
msr TPIDR_EL1, x3
|
||||
|
||||
ldr x2, =kernel_stack
|
||||
add x2, x2, KERNEL_STACK_SIZE
|
||||
mov sp, x2
|
||||
bl main
|
||||
END_FUNC(start_kernel)
|
51
lab1/kernel/main.c
Normal file
51
lab1/kernel/main.c
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#include <common/kprint.h>
|
||||
#include <common/macro.h>
|
||||
#include <common/uart.h>
|
||||
#include <common/machine.h>
|
||||
|
||||
ALIGN(STACK_ALIGNMENT)
|
||||
char kernel_stack[PLAT_CPU_NUM][KERNEL_STACK_SIZE];
|
||||
|
||||
int stack_backtrace();
|
||||
|
||||
// Test the stack backtrace function (lab 1 only)
|
||||
__attribute__ ((optimize("O1")))
|
||||
void stack_test(long x)
|
||||
{
|
||||
kinfo("entering stack_test %d\n", x);
|
||||
if (x > 0)
|
||||
stack_test(x - 1);
|
||||
else
|
||||
stack_backtrace();
|
||||
kinfo("leaving stack_test %d\n", x);
|
||||
}
|
||||
|
||||
void main(void *addr)
|
||||
{
|
||||
/* Init uart */
|
||||
uart_init();
|
||||
kinfo("[ChCore] uart init finished\n");
|
||||
|
||||
kinfo("Address of main() is 0x%lx\n", main);
|
||||
kinfo("123456 decimal is 0%o octal\n", 123456);
|
||||
|
||||
stack_test(5);
|
||||
|
||||
break_point();
|
||||
return;
|
||||
|
||||
/* Should provide panic and use here */
|
||||
BUG("[FATAL] Should never be here!\n");
|
||||
}
|
53
lab1/kernel/monitor.c
Normal file
53
lab1/kernel/monitor.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
// Simple command-line kernel monitor useful for
|
||||
// controlling the kernel and exploring the system interactively.
|
||||
|
||||
#include <common/printk.h>
|
||||
#include <common/types.h>
|
||||
#include <common/machine.h>
|
||||
|
||||
extern char kernel_stack[PLAT_CPU_NUM][KERNEL_STACK_SIZE];
|
||||
|
||||
static inline __attribute__ ((always_inline))
|
||||
u64 read_fp()
|
||||
{
|
||||
u64 fp;
|
||||
__asm __volatile("mov %0, x29":"=r"(fp));
|
||||
return fp;
|
||||
}
|
||||
|
||||
__attribute__ ((optimize("O1")))
|
||||
int stack_backtrace()
|
||||
{
|
||||
printk("Stack backtrace:\n");
|
||||
|
||||
// Your code here.
|
||||
u64 *fp, *preFp;
|
||||
fp = read_fp();
|
||||
// until stack end
|
||||
while (true) {
|
||||
preFp = *fp;
|
||||
// entry frame
|
||||
if (preFp == 0)
|
||||
break;
|
||||
printk("LR %lx FP %lx Args", *(preFp + 1), preFp);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
printk(" %lx", *(fp + 2 + i));
|
||||
}
|
||||
printk("\n");
|
||||
fp = preFp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
33
lab1/scripts/build.sh
Executable file
33
lab1/scripts/build.sh
Executable file
@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ ! -d "build" ]; then
|
||||
mkdir build
|
||||
cd build
|
||||
cat > simulate.sh <<EOF
|
||||
#!/bin/bash
|
||||
|
||||
basedir=\$(dirname "\$0")
|
||||
if [[ \$@ == *"gdb"* ]]; then
|
||||
qemu-system-aarch64 -machine raspi3 -nographic -serial null -serial mon:stdio -m size=1G -kernel \$basedir/kernel.img -S -gdb tcp::1234
|
||||
else
|
||||
qemu-system-aarch64 -machine raspi3 -nographic -serial null -serial mon:stdio -m size=1G -kernel \$basedir/kernel.img
|
||||
fi
|
||||
EOF
|
||||
chmod +x simulate.sh
|
||||
cd ..
|
||||
fi
|
||||
|
||||
# compile kernel
|
||||
echo "compiling kernel ..."
|
||||
cd build
|
||||
|
||||
cmake -DCMAKE_LINKER=aarch64-linux-gnu-ld -DCMAKE_C_LINK_EXECUTABLE="<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>" .. -G Ninja "$@"
|
||||
echo "before ninja"
|
||||
ninja
|
||||
echo "after ninja"
|
||||
if [ ! -f "kernel.img" ]; then
|
||||
echo "kernel.img is not exist"
|
||||
fi
|
||||
aarch64-linux-gnu-nm -n kernel.img > kernel.sym
|
||||
# print the compile logs
|
||||
#ninja -v
|
4
lab1/scripts/docker_build.sh
Executable file
4
lab1/scripts/docker_build.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
rm -rf ./build
|
||||
|
||||
docker run -it --rm -u $(id -u ${USER}):$(id -g ${USER}) -v $(pwd):/chos -w /chos ipads/chcore_builder:v1.0 ./scripts/build.sh "$@"
|
45
lab1/scripts/grade-lab1
Executable file
45
lab1/scripts/grade-lab1
Executable file
@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import re
|
||||
from gradelib import *
|
||||
|
||||
r = Runner(save("chcore.out"),
|
||||
stop_breakpoint("break_point"))
|
||||
|
||||
@test(0, "running ChCore")
|
||||
def test_chcore():
|
||||
r.run_qemu(30)
|
||||
|
||||
@test(15, parent=test_chcore)
|
||||
def test_print_hex():
|
||||
addrs = [int(sym[:16], 16) for sym in open("./build/kernel.sym")
|
||||
if sym[19:].strip() == "main"]
|
||||
r.match("\[INFO\] Address of main\(\) is 0x%x" % addrs[0])
|
||||
|
||||
@test(15, parent=test_chcore)
|
||||
def test_print_oct():
|
||||
r.match("\[INFO\] 123456 decimal is 0361100 octal")
|
||||
|
||||
BACKTRACE_RE = r" *LR *ffffff00000[0-9a-z]{5} *FP *ffffff0000[0-9a-z]{6} *Args *([0-9a-z]+)"
|
||||
BACKTRACE_LR = r" *LR *(ffffff00000[0-9a-z]{5}) *FP *ffffff0000[0-9a-z]{6} *Args *[0-9a-z]+"
|
||||
|
||||
@test(15, parent=test_chcore)
|
||||
def test_stack_count():
|
||||
matches = re.findall(BACKTRACE_RE, r.qemu.output, re.MULTILINE)
|
||||
assert_equal(len(matches), 7)
|
||||
|
||||
@test(15, parent=test_chcore)
|
||||
def test_stack_arguments():
|
||||
matches = re.findall(BACKTRACE_RE, r.qemu.output, re.MULTILINE)
|
||||
assert_equal("\n".join(matches[:6]),
|
||||
"\n".join("%01x" % n for n in [0,1,2,3,4,5]))
|
||||
|
||||
@test(20, parent=test_chcore)
|
||||
def test_stack_lr():
|
||||
matches = re.findall(BACKTRACE_LR, r.qemu.output, re.MULTILINE)
|
||||
addrs = [int(sym[:16], 16) for sym in open("./build/kernel.sym")
|
||||
if sym[19:].strip() == "stack_test"][0] + 80
|
||||
for i in range(5):
|
||||
assert_equal(int(matches[i], 16), addrs)
|
||||
|
||||
run_tests()
|
693
lab1/scripts/gradelib.py
Normal file
693
lab1/scripts/gradelib.py
Normal file
@ -0,0 +1,693 @@
|
||||
# The gradelib.py is:
|
||||
#
|
||||
# Copyright (c) 2006-2019 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.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys, os, re, time, socket, select, subprocess, errno, shutil, random, string
|
||||
from subprocess import check_call, Popen
|
||||
from optparse import OptionParser
|
||||
|
||||
__all__ = []
|
||||
|
||||
##################################################################
|
||||
# Test structure
|
||||
#
|
||||
|
||||
__all__ += ["test", "end_part", "run_tests", "get_current_test"]
|
||||
|
||||
TESTS = []
|
||||
TOTAL = POSSIBLE = 0
|
||||
PART_TOTAL = PART_POSSIBLE = 0
|
||||
CURRENT_TEST = None
|
||||
|
||||
def test(points, title=None, parent=None):
|
||||
"""Decorator for declaring test functions. If title is None, the
|
||||
title of the test will be derived from the function name by
|
||||
stripping the leading "test_" and replacing underscores with
|
||||
spaces."""
|
||||
|
||||
def register_test(fn, title=title):
|
||||
if not title:
|
||||
assert fn.__name__.startswith("test_")
|
||||
title = fn.__name__[5:].replace("_", " ")
|
||||
if parent:
|
||||
title = " " + title
|
||||
|
||||
def run_test():
|
||||
global TOTAL, POSSIBLE, CURRENT_TEST
|
||||
|
||||
# Handle test dependencies
|
||||
if run_test.complete:
|
||||
return run_test.ok
|
||||
run_test.complete = True
|
||||
parent_failed = False
|
||||
if parent:
|
||||
parent_failed = not parent()
|
||||
|
||||
# Run the test
|
||||
fail = None
|
||||
start = time.time()
|
||||
CURRENT_TEST = run_test
|
||||
sys.stdout.write("%s: " % title)
|
||||
sys.stdout.flush()
|
||||
try:
|
||||
if parent_failed:
|
||||
raise AssertionError('Parent failed: %s' % parent.__name__)
|
||||
fn()
|
||||
except AssertionError as e:
|
||||
fail = str(e)
|
||||
|
||||
# Display and handle test result
|
||||
POSSIBLE += points
|
||||
if points:
|
||||
print("%s" % \
|
||||
(color("red", "FAIL") if fail else color("green", "OK")), end=' ')
|
||||
if time.time() - start > 0.1:
|
||||
print("(%.1fs)" % (time.time() - start), end=' ')
|
||||
print()
|
||||
if fail:
|
||||
print(" %s" % fail.replace("\n", "\n "))
|
||||
else:
|
||||
TOTAL += points
|
||||
for callback in run_test.on_finish:
|
||||
callback(fail)
|
||||
CURRENT_TEST = None
|
||||
|
||||
run_test.ok = not fail
|
||||
return run_test.ok
|
||||
|
||||
# Record test metadata on the test wrapper function
|
||||
run_test.__name__ = fn.__name__
|
||||
run_test.title = title
|
||||
run_test.complete = False
|
||||
run_test.ok = False
|
||||
run_test.on_finish = []
|
||||
TESTS.append(run_test)
|
||||
return run_test
|
||||
return register_test
|
||||
|
||||
def end_part(name):
|
||||
def show_part():
|
||||
global PART_TOTAL, PART_POSSIBLE
|
||||
print("Part %s score: %d/%d" % \
|
||||
(name, TOTAL - PART_TOTAL, POSSIBLE - PART_POSSIBLE))
|
||||
print()
|
||||
PART_TOTAL, PART_POSSIBLE = TOTAL, POSSIBLE
|
||||
show_part.title = ""
|
||||
TESTS.append(show_part)
|
||||
|
||||
def run_tests():
|
||||
"""Set up for testing and run the registered test functions."""
|
||||
|
||||
# Handle command line
|
||||
global options
|
||||
parser = OptionParser(usage="usage: %prog [-v] [filters...]")
|
||||
parser.add_option("-v", "--verbose", action="store_true",
|
||||
help="print commands")
|
||||
parser.add_option("--color", choices=["never", "always", "auto"],
|
||||
default="auto", help="never, always, or auto")
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
# Start with a full build to catch build errors
|
||||
make()
|
||||
|
||||
# Clean the file system if there is one
|
||||
# reset_fs()
|
||||
|
||||
# Run tests
|
||||
limit = list(map(str.lower, args))
|
||||
try:
|
||||
for test in TESTS:
|
||||
if not limit or any(l in test.title.lower() for l in limit):
|
||||
test()
|
||||
if not limit:
|
||||
print("Score: %d/%d" % (TOTAL, POSSIBLE))
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
if TOTAL < POSSIBLE:
|
||||
sys.exit(1)
|
||||
|
||||
def get_current_test():
|
||||
if not CURRENT_TEST:
|
||||
raise RuntimeError("No test is running")
|
||||
return CURRENT_TEST
|
||||
|
||||
##################################################################
|
||||
# Assertions
|
||||
#
|
||||
|
||||
__all__ += ["assert_equal", "assert_lines_match"]
|
||||
|
||||
def assert_equal(got, expect, msg=""):
|
||||
if got == expect:
|
||||
return
|
||||
if msg:
|
||||
msg += "\n"
|
||||
raise AssertionError("%sgot:\n %s\nexpected:\n %s" %
|
||||
(msg, str(got).replace("\n", "\n "),
|
||||
str(expect).replace("\n", "\n ")))
|
||||
|
||||
def assert_lines_match(text, *regexps, **kw):
|
||||
"""Assert that all of regexps match some line in text. If a 'no'
|
||||
keyword argument is given, it must be a list of regexps that must
|
||||
*not* match any line in text."""
|
||||
|
||||
def assert_lines_match_kw(no=[]):
|
||||
return no
|
||||
no = assert_lines_match_kw(**kw)
|
||||
|
||||
# Check text against regexps
|
||||
lines = text.splitlines()
|
||||
good = set()
|
||||
bad = set()
|
||||
first_line = 0
|
||||
for i, line in enumerate(lines):
|
||||
if any(re.match(r, line) for r in regexps):
|
||||
if (first_line == 0):
|
||||
first_line = i
|
||||
good.add(i)
|
||||
regexps = [r for r in regexps if not re.match(r, line)]
|
||||
if any(re.match(r, line) for r in no):
|
||||
bad.add(i)
|
||||
|
||||
if not regexps and not bad:
|
||||
return first_line
|
||||
|
||||
# We failed; construct an informative failure message
|
||||
show = set()
|
||||
for lineno in good.union(bad):
|
||||
for offset in range(-2, 3):
|
||||
show.add(lineno + offset)
|
||||
if regexps:
|
||||
show.update(n for n in range(len(lines) - 5, len(lines)))
|
||||
|
||||
msg = []
|
||||
last = -1
|
||||
for lineno in sorted(show):
|
||||
if 0 <= lineno < len(lines):
|
||||
if lineno != last + 1:
|
||||
msg.append("...")
|
||||
last = lineno
|
||||
msg.append("%s %s" % (color("red", "BAD ") if lineno in bad else
|
||||
color("green", "GOOD") if lineno in good
|
||||
else " ",
|
||||
lines[lineno]))
|
||||
if last != len(lines) - 1:
|
||||
msg.append("...")
|
||||
if bad:
|
||||
msg.append("unexpected lines in output")
|
||||
for r in regexps:
|
||||
msg.append(color("red", "MISSING") + " '%s'" % r)
|
||||
raise AssertionError("\n".join(msg))
|
||||
return 0
|
||||
|
||||
def assert_lines_match_line(line_num, text, *regexps, **kw):
|
||||
"""Assert that all of regexps match some line in text. If a 'no'
|
||||
keyword argument is given, it must be a list of regexps that must
|
||||
*not* match any line in text."""
|
||||
|
||||
def assert_lines_match_kw(no=[]):
|
||||
return no
|
||||
no = assert_lines_match_kw(**kw)
|
||||
|
||||
# Check text against regexps
|
||||
lines = text.splitlines()
|
||||
good = set()
|
||||
bad = set()
|
||||
first_line = 0
|
||||
for i, line in enumerate(lines):
|
||||
if (i >=line_num):
|
||||
if any(re.match(r, line) for r in regexps):
|
||||
if (first_line == 0 ):
|
||||
first_line = i
|
||||
good.add(i)
|
||||
regexps = [r for r in regexps if not re.match(r, line)]
|
||||
if any(re.match(r, line) for r in no):
|
||||
bad.add(i)
|
||||
|
||||
if not regexps and not bad:
|
||||
return first_line
|
||||
|
||||
# We failed; construct an informative failure message
|
||||
show = set()
|
||||
for lineno in good.union(bad):
|
||||
for offset in range(-2, 3):
|
||||
show.add(lineno + offset)
|
||||
if regexps:
|
||||
show.update(n for n in range(len(lines) - 5, len(lines)))
|
||||
|
||||
msg = []
|
||||
last = -1
|
||||
for lineno in sorted(show):
|
||||
if 0 <= lineno < len(lines):
|
||||
if lineno != last + 1:
|
||||
msg.append("...")
|
||||
last = lineno
|
||||
msg.append("%s %s" % (color("red", "BAD ") if lineno in bad else
|
||||
color("green", "GOOD") if lineno in good
|
||||
else " ",
|
||||
lines[lineno]))
|
||||
if last != len(lines) - 1:
|
||||
msg.append("...")
|
||||
if bad:
|
||||
msg.append("unexpected lines in output")
|
||||
for r in regexps:
|
||||
msg.append(color("red", "MISSING or WRONG ORDER") + " '%s'" % r)
|
||||
raise AssertionError("\n".join(msg))
|
||||
return 0
|
||||
|
||||
##################################################################
|
||||
# Utilities
|
||||
#
|
||||
|
||||
__all__ += ["make", "maybe_unlink", "reset_fs", "color", "random_str"]
|
||||
|
||||
MAKE_TIMESTAMP = 0
|
||||
|
||||
def pre_make():
|
||||
"""Delay prior to running make to ensure file mtimes change."""
|
||||
while int(time.time()) == MAKE_TIMESTAMP:
|
||||
time.sleep(0.1)
|
||||
|
||||
def post_make():
|
||||
"""Record the time after make completes so that the next run of
|
||||
make can be delayed if needed."""
|
||||
global MAKE_TIMESTAMP
|
||||
MAKE_TIMESTAMP = int(time.time())
|
||||
|
||||
def make(*target):
|
||||
pre_make()
|
||||
#print(target)
|
||||
if Popen(("make",) + target).wait():
|
||||
sys.exit(1)
|
||||
post_make()
|
||||
|
||||
def show_command(cmd):
|
||||
from pipes import quote
|
||||
print("\n$", " ".join(map(quote, cmd)))
|
||||
|
||||
def maybe_unlink(*paths):
|
||||
for path in paths:
|
||||
try:
|
||||
os.unlink(path)
|
||||
except EnvironmentError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
raise
|
||||
|
||||
COLORS = {"default": "\033[0m", "red": "\033[31m", "green": "\033[32m"}
|
||||
|
||||
def color(name, text):
|
||||
if options.color == "always" or (options.color == "auto" and os.isatty(1)):
|
||||
return COLORS[name] + text + COLORS["default"]
|
||||
return text
|
||||
|
||||
def reset_fs():
|
||||
if os.path.exists("obj/fs/clean-fs.img"):
|
||||
shutil.copyfile("obj/fs/clean-fs.img", "obj/fs/fs.img")
|
||||
|
||||
def random_str(n=8):
|
||||
letters = string.ascii_letters + string.digits
|
||||
return ''.join(random.choice(letters) for _ in range(n))
|
||||
|
||||
##################################################################
|
||||
# Controllers
|
||||
#
|
||||
|
||||
__all__ += ["QEMU", "GDBClient"]
|
||||
|
||||
class QEMU(object):
|
||||
_GDBPORT = None
|
||||
|
||||
def __init__(self, *make_args):
|
||||
# Check that QEMU is not currently running
|
||||
try:
|
||||
GDBClient(self.get_gdb_port(), timeout=0).close()
|
||||
except socket.error:
|
||||
pass
|
||||
else:
|
||||
print("""\
|
||||
GDB stub found on port %d.
|
||||
QEMU appears to already be running. Please exit it if possible or use
|
||||
'killall qemu' or 'killall qemu.real'.""" % self.get_gdb_port(), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if options.verbose:
|
||||
show_command(("make",) + make_args)
|
||||
cmd = ("make", "-s", "--no-print-directory") + make_args
|
||||
self.proc = Popen(cmd, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
stdin=subprocess.PIPE)
|
||||
# Accumulated output as a string
|
||||
self.output = ""
|
||||
# Accumulated output as a bytearray
|
||||
self.outbytes = bytearray()
|
||||
self.on_output = []
|
||||
|
||||
@staticmethod
|
||||
def get_gdb_port():
|
||||
if QEMU._GDBPORT is None:
|
||||
p = Popen(["make", "-s", "--no-print-directory", "gdbport"],
|
||||
stdout=subprocess.PIPE)
|
||||
(out, _) = p.communicate()
|
||||
if p.returncode:
|
||||
raise RuntimeError(
|
||||
"Failed to get gdbport: make exited with %d" %
|
||||
p.returncode)
|
||||
QEMU._GDBPORT = int(out)
|
||||
return QEMU._GDBPORT
|
||||
|
||||
def fileno(self):
|
||||
if self.proc:
|
||||
return self.proc.stdout.fileno()
|
||||
|
||||
def handle_read(self):
|
||||
buf = os.read(self.proc.stdout.fileno(), 4096)
|
||||
self.outbytes.extend(buf)
|
||||
self.output = self.outbytes.decode("utf-8", "replace")
|
||||
for callback in self.on_output:
|
||||
callback(buf)
|
||||
if buf == b"":
|
||||
self.wait()
|
||||
return
|
||||
|
||||
def write(self, buf):
|
||||
if isinstance(buf, str):
|
||||
buf = buf.encode('utf-8')
|
||||
self.proc.stdin.write(buf)
|
||||
self.proc.stdin.flush()
|
||||
|
||||
def wait(self):
|
||||
if self.proc:
|
||||
self.proc.wait()
|
||||
self.proc = None
|
||||
|
||||
def kill(self):
|
||||
if self.proc:
|
||||
self.proc.terminate()
|
||||
|
||||
class GDBClient(object):
|
||||
def __init__(self, port, timeout=15):
|
||||
start = time.time()
|
||||
while True:
|
||||
self.sock = socket.socket()
|
||||
try:
|
||||
self.sock.settimeout(1)
|
||||
self.sock.connect(("localhost", port))
|
||||
break
|
||||
except socket.error:
|
||||
if time.time() >= start + timeout:
|
||||
raise
|
||||
self.__buf = ""
|
||||
|
||||
def fileno(self):
|
||||
if self.sock:
|
||||
return self.sock.fileno()
|
||||
|
||||
def handle_read(self):
|
||||
try:
|
||||
data = self.sock.recv(4096).decode("ascii", "replace")
|
||||
except socket.error:
|
||||
data = ""
|
||||
if data == "":
|
||||
self.sock.close()
|
||||
self.sock = None
|
||||
return
|
||||
self.__buf += data
|
||||
|
||||
while True:
|
||||
m = re.search(r"\$([^#]*)#[0-9a-zA-Z]{2}", self.__buf)
|
||||
if not m:
|
||||
break
|
||||
pkt = m.group(1)
|
||||
self.__buf = self.__buf[m.end():]
|
||||
|
||||
if pkt.startswith("T05"):
|
||||
# Breakpoint
|
||||
raise TerminateTest
|
||||
|
||||
def __send(self, cmd):
|
||||
packet = "$%s#%02x" % (cmd, sum(map(ord, cmd)) % 256)
|
||||
self.sock.sendall(packet.encode("ascii"))
|
||||
|
||||
def __send_break(self):
|
||||
self.sock.sendall(b"\x03")
|
||||
|
||||
def close(self):
|
||||
if self.sock:
|
||||
self.sock.close()
|
||||
self.sock = None
|
||||
|
||||
def cont(self):
|
||||
self.__send("c")
|
||||
|
||||
def breakpoint(self, addr):
|
||||
self.__send("Z1,%x,1" % addr)
|
||||
|
||||
|
||||
##################################################################
|
||||
# QEMU test runner
|
||||
#
|
||||
|
||||
__all__ += ["TerminateTest", "Runner"]
|
||||
|
||||
class TerminateTest(Exception):
|
||||
pass
|
||||
|
||||
class Runner():
|
||||
def __init__(self, *default_monitors):
|
||||
self.__default_monitors = default_monitors
|
||||
|
||||
def run_qemu(self, lab_timeout, *monitors, **kw):
|
||||
"""Run a QEMU-based test. monitors should functions that will
|
||||
be called with this Runner instance once QEMU and GDB are
|
||||
started. Typically, they should register callbacks that throw
|
||||
TerminateTest when stop events occur. The target_base
|
||||
argument gives the make target to run. The make_args argument
|
||||
should be a list of additional arguments to pass to make. The
|
||||
timeout argument bounds how long to run before returning."""
|
||||
|
||||
def run_qemu_kw(target_base="qemu", make_args=[], timeout=lab_timeout):
|
||||
return target_base, make_args, timeout
|
||||
target_base, make_args, timeout = run_qemu_kw(**kw)
|
||||
|
||||
# Start QEMU
|
||||
pre_make()
|
||||
self.qemu = QEMU(target_base + "-gdb", *make_args)
|
||||
self.gdb = None
|
||||
|
||||
try:
|
||||
# Wait for QEMU to start or make to fail. This will set
|
||||
# self.gdb if QEMU starts.
|
||||
self.qemu.on_output = [self.__monitor_start]
|
||||
self.__react([self.qemu], timeout=30)
|
||||
self.qemu.on_output = []
|
||||
if self.gdb is None:
|
||||
print("Failed to connect to QEMU; output:")
|
||||
print(self.qemu.output)
|
||||
sys.exit(1)
|
||||
post_make()
|
||||
|
||||
# QEMU and GDB are up
|
||||
self.reactors = [self.qemu, self.gdb]
|
||||
|
||||
# Start monitoring
|
||||
for m in self.__default_monitors + monitors:
|
||||
m(self)
|
||||
|
||||
# Run and react
|
||||
self.gdb.cont()
|
||||
self.__react(self.reactors, timeout)
|
||||
finally:
|
||||
# Shutdown QEMU
|
||||
try:
|
||||
if self.gdb is None:
|
||||
sys.exit(1)
|
||||
self.qemu.kill()
|
||||
self.__react(self.reactors, 5)
|
||||
self.gdb.close()
|
||||
self.qemu.wait()
|
||||
except:
|
||||
print("""\
|
||||
Failed to shutdown QEMU. You might need to 'killall qemu' or
|
||||
'killall qemu.real'.
|
||||
""")
|
||||
raise
|
||||
|
||||
def __monitor_start(self, output):
|
||||
if b"\n" in output:
|
||||
try:
|
||||
self.gdb = GDBClient(self.qemu.get_gdb_port(), timeout=30)
|
||||
raise TerminateTest
|
||||
except socket.error:
|
||||
pass
|
||||
if not len(output):
|
||||
raise TerminateTest
|
||||
|
||||
def __react(self, reactors, timeout):
|
||||
deadline = time.time() + timeout
|
||||
try:
|
||||
while True:
|
||||
timeleft = deadline - time.time()
|
||||
if timeleft < 0:
|
||||
# sys.stdout.write("Timeout! ")
|
||||
sys.stdout.flush()
|
||||
return
|
||||
|
||||
rset = [r for r in reactors if r.fileno() is not None]
|
||||
if not rset:
|
||||
return
|
||||
|
||||
rset, _, _ = select.select(rset, [], [], timeleft)
|
||||
for reactor in rset:
|
||||
reactor.handle_read()
|
||||
except TerminateTest:
|
||||
pass
|
||||
|
||||
def user_test(self, binary, *monitors, **kw):
|
||||
"""Run a user test using the specified binary. Monitors and
|
||||
keyword arguments are as for run_qemu. This runs on a disk
|
||||
snapshot unless the keyword argument 'snapshot' is False."""
|
||||
|
||||
maybe_unlink("obj/kern/init.o", "obj/kern/kernel")
|
||||
if kw.pop("snapshot", True):
|
||||
kw.setdefault("make_args", []).append("QEMUEXTRA+=-snapshot")
|
||||
self.run_qemu(target_base="run-%s" % binary, *monitors, **kw)
|
||||
|
||||
def match(self, *args, **kwargs):
|
||||
"""Shortcut to call assert_lines_match on the most recent QEMU
|
||||
output."""
|
||||
|
||||
return assert_lines_match(self.qemu.output, *args, **kwargs)
|
||||
|
||||
def match_line(self, line_num, *args, **kwargs):
|
||||
"""Shortcut to call assert_lines_match on the most recent QEMU
|
||||
output."""
|
||||
return assert_lines_match_line(line_num, self.qemu.output, *args, **kwargs)
|
||||
|
||||
def make_kernel(self, binary):
|
||||
os.system("./scripts/docker_build.sh %s > tmp.out" % binary)
|
||||
|
||||
def file_match(self, file_name, r):
|
||||
f = open(file_name, 'r')
|
||||
file_text = f.read()
|
||||
lines = file_text.splitlines()
|
||||
good = set()
|
||||
bad = set()
|
||||
isMatch = 0
|
||||
for i, line in enumerate(lines):
|
||||
if r in line:
|
||||
isMatch = 1
|
||||
good.add(i)
|
||||
if isMatch:
|
||||
return
|
||||
# We failed; construct an informative failure message
|
||||
show = set()
|
||||
for lineno in good.union(bad):
|
||||
for offset in range(-2, 3):
|
||||
show.add(lineno + offset)
|
||||
show.update(n for n in range(len(lines) - 1, len(lines)))
|
||||
msg = []
|
||||
last = -1
|
||||
for lineno in sorted(show):
|
||||
if 0 <= lineno < len(lines):
|
||||
if lineno != last + 1:
|
||||
msg.append("...")
|
||||
last = lineno
|
||||
msg.append("%s %s" % (color("red", "BAD ") if lineno in bad else
|
||||
color("green", "GOOD") if lineno in good
|
||||
else " ",
|
||||
lines[lineno]))
|
||||
if last != len(lines) - 1:
|
||||
msg.append("...")
|
||||
if bad:
|
||||
msg.append("unexpected lines in output")
|
||||
msg.append(color("red", "MISSING") + " '%s'" % r)
|
||||
raise AssertionError("\n".join(msg))
|
||||
|
||||
##################################################################
|
||||
# Monitors
|
||||
#
|
||||
|
||||
__all__ += ["save", "stop_breakpoint", "call_on_line", "stop_on_line"]
|
||||
|
||||
def save(path):
|
||||
"""Return a monitor that writes QEMU's output to path. If the
|
||||
test fails, copy the output to path.test-name."""
|
||||
|
||||
def setup_save(runner):
|
||||
f.seek(0)
|
||||
f.truncate()
|
||||
runner.qemu.on_output.append(f.write)
|
||||
get_current_test().on_finish.append(save_on_finish)
|
||||
|
||||
def save_on_finish(fail):
|
||||
f.flush()
|
||||
save_path = path + "." + get_current_test().__name__[5:]
|
||||
if fail:
|
||||
shutil.copyfile(path, save_path)
|
||||
print(" QEMU output saved to %s" % save_path)
|
||||
elif os.path.exists(save_path):
|
||||
os.unlink(save_path)
|
||||
print(" (Old %s failure log removed)" % save_path)
|
||||
|
||||
f = open(path, "wb")
|
||||
return setup_save
|
||||
|
||||
def stop_breakpoint(addr):
|
||||
"""Returns a monitor that stops when addr is reached. addr may be
|
||||
a number or the name of a symbol."""
|
||||
|
||||
def setup_breakpoint(runner):
|
||||
if isinstance(addr, str):
|
||||
addrs = [int(sym[:16], 16) for sym in open("./build/kernel.sym")
|
||||
if sym[19:].strip() == addr]
|
||||
assert len(addrs), "Symbol %s not found" % addr
|
||||
runner.gdb.breakpoint(addrs[0])
|
||||
else:
|
||||
runner.gdb.breakpoint(addr)
|
||||
return setup_breakpoint
|
||||
|
||||
def call_on_line(regexp, callback):
|
||||
"""Returns a monitor that calls 'callback' when QEMU prints a line
|
||||
matching 'regexp'."""
|
||||
|
||||
def setup_call_on_line(runner):
|
||||
buf = bytearray()
|
||||
def handle_output(output):
|
||||
buf.extend(output)
|
||||
while b"\n" in buf:
|
||||
line, buf[:] = buf.split(b"\n", 1)
|
||||
line = line.decode("utf-8", "replace")
|
||||
if re.match(regexp, line):
|
||||
callback(line)
|
||||
runner.qemu.on_output.append(handle_output)
|
||||
return setup_call_on_line
|
||||
|
||||
def stop_on_line(regexp):
|
||||
"""Returns a monitor that stops when QEMU prints a line matching
|
||||
'regexp'."""
|
||||
|
||||
def stop(line):
|
||||
raise TerminateTest
|
||||
return call_on_line(regexp, stop)
|
37
lab1/scripts/linker-aarch64.lds.in
Normal file
37
lab1/scripts/linker-aarch64.lds.in
Normal file
@ -0,0 +1,37 @@
|
||||
#include "../boot/image.h"
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = TEXT_OFFSET;
|
||||
img_start = .;
|
||||
init : {
|
||||
${init_object}
|
||||
}
|
||||
|
||||
. = ALIGN(SZ_16K);
|
||||
|
||||
init_end = ABSOLUTE(.);
|
||||
|
||||
.text KERNEL_VADDR + init_end : AT(init_end) {
|
||||
*(.text*)
|
||||
}
|
||||
|
||||
. = ALIGN(SZ_64K);
|
||||
.data : {
|
||||
*(.data*)
|
||||
}
|
||||
. = ALIGN(SZ_64K);
|
||||
|
||||
.rodata : {
|
||||
*(.rodata*)
|
||||
}
|
||||
_edata = . - KERNEL_VADDR;
|
||||
|
||||
_bss_start = . - KERNEL_VADDR;
|
||||
.bss : {
|
||||
*(.bss*)
|
||||
}
|
||||
_bss_end = . - KERNEL_VADDR;
|
||||
. = ALIGN(SZ_64K);
|
||||
img_end = . - KERNEL_VADDR;
|
||||
}
|
2
lab1/scripts/run_docker.sh
Executable file
2
lab1/scripts/run_docker.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
docker run -it --rm -u $(id -u ${USER}):$(id -g ${USER}) -v $(pwd):/chos -w /chos ipads/chcore_builder:v1.0
|
3
lab2/.gdbinit
Normal file
3
lab2/.gdbinit
Normal file
@ -0,0 +1,3 @@
|
||||
set architecture aarch64
|
||||
target remote localhost:1234
|
||||
file ./build/kernel.img
|
16
lab2/.gitignore
vendored
Normal file
16
lab2/.gitignore
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
*.o
|
||||
*.elf
|
||||
*.img
|
||||
*.bin
|
||||
*.pyc
|
||||
*.swp
|
||||
|
||||
cscope.*
|
||||
.vscode
|
||||
|
||||
asm
|
||||
tags
|
||||
build
|
||||
*.out
|
||||
*.pyc
|
||||
chcore.out
|
8
lab2/.idea/.gitignore
generated
vendored
Normal file
8
lab2/.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
13
lab2/.idea/misc.xml
generated
Normal file
13
lab2/.idea/misc.xml
generated
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="MakefileSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<MakefileProjectSettings>
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="version" value="2" />
|
||||
</MakefileProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
<component name="MakefileWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
</project>
|
88
lab2/CMakeLists.txt
Normal file
88
lab2/CMakeLists.txt
Normal file
@ -0,0 +1,88 @@
|
||||
cmake_minimum_required (VERSION 3.14)
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE on)
|
||||
|
||||
set(CMAKE_BUILD_TYPE "Release") # "Release" or "Debug"
|
||||
set(CHCORE_PLAT "raspi3")
|
||||
set(CHCORE_ARCH "aarch64")
|
||||
|
||||
mark_as_advanced(CMAKE_INSTALL_PREFIX)
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_definitions("-DLOG_LEVEL=2")
|
||||
else ()
|
||||
add_definitions("-DLOG_LEVEL=1")
|
||||
endif ()
|
||||
|
||||
set(CROSS_COMPILE "${CHCORE_ARCH}-linux-gnu-")
|
||||
|
||||
set(CMAKE_C_COMPILER "${CROSS_COMPILE}gcc")
|
||||
set(CMAKE_ASM_COMPILER "${CROSS_COMPILE}gcc")
|
||||
execute_process (
|
||||
COMMAND ${CMAKE_C_COMPILER} -print-file-name=include
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
OUTPUT_VARIABLE C_COMPILER_INCLUDE
|
||||
)
|
||||
|
||||
|
||||
set(CMAKE_C_FLAGS
|
||||
"-Wall -fPIC -nostdlib -nostartfiles -ffreestanding \
|
||||
-DCHCORE -nostdinc ")
|
||||
|
||||
project (chos C ASM)
|
||||
|
||||
set(BOOTLOADER_PATH "boot")
|
||||
set(KERNEL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/kernel")
|
||||
|
||||
|
||||
set(KERNEL_ARCH_PATH "${KERNEL_PATH}")
|
||||
set(KERNEL_MM_PATH "${KERNEL_PATH}/mm")
|
||||
|
||||
include_directories(".")
|
||||
include_directories("${KERNEL_PATH}")
|
||||
|
||||
add_subdirectory("${KERNEL_ARCH_PATH}")
|
||||
add_subdirectory("${KERNEL_MM_PATH}")
|
||||
|
||||
set(BINARY_KERNEL_IMG_PATH "CMakeFiles/kernel.img.dir")
|
||||
set(init_object
|
||||
"${BINARY_KERNEL_IMG_PATH}/${BOOTLOADER_PATH}/start.S.o
|
||||
${BINARY_KERNEL_IMG_PATH}/${BOOTLOADER_PATH}/mmu.c.o
|
||||
${BINARY_KERNEL_IMG_PATH}/${BOOTLOADER_PATH}/tools.S.o
|
||||
${BINARY_KERNEL_IMG_PATH}/${BOOTLOADER_PATH}/init_c.c.o
|
||||
${BINARY_KERNEL_IMG_PATH}/${BOOTLOADER_PATH}/uart.c.o"
|
||||
)
|
||||
|
||||
set(link_script "linker.lds")
|
||||
configure_file("./scripts/linker-aarch64.lds.in" "linker.lds.S")
|
||||
|
||||
set(files "")
|
||||
include("${BOOTLOADER_PATH}/config.cmake")
|
||||
|
||||
add_executable(kernel.img ${files}
|
||||
$<TARGET_OBJECTS:${PROJECT_NAME}-arch>
|
||||
$<TARGET_OBJECTS:${PROJECT_NAME}-mm>
|
||||
)
|
||||
|
||||
set_property(
|
||||
TARGET kernel.img
|
||||
APPEND_STRING
|
||||
PROPERTY
|
||||
LINK_FLAGS
|
||||
"-T ${CMAKE_CURRENT_BINARY_DIR}/${link_script} -e _start"
|
||||
)
|
||||
|
||||
set_property(
|
||||
TARGET kernel.img
|
||||
APPEND_STRING
|
||||
PROPERTY
|
||||
DEPENDS
|
||||
"${link_script}"
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
TARGET kernel.img
|
||||
PRE_LINK
|
||||
COMMAND ${CMAKE_C_COMPILER} -E -x c
|
||||
-I${CMAKE_SOURCE_DIR}/${BOOTLOADER_PATH}/include ./linker.lds.S | grep -v "^#" > linker.lds
|
||||
)
|
121
lab2/LICENSE
Normal file
121
lab2/LICENSE
Normal file
@ -0,0 +1,121 @@
|
||||
木兰宽松许可证, 第1版
|
||||
|
||||
木兰宽松许可证, 第1版
|
||||
2019年8月 http://license.coscl.org.cn/MulanPSL
|
||||
|
||||
您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第1版(“本许可证”)的如下条款的约束:
|
||||
|
||||
0. 定义
|
||||
|
||||
“软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。
|
||||
|
||||
“贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。
|
||||
|
||||
“法人实体”是指提交贡献的机构及其“关联实体”。
|
||||
|
||||
“关联实体”是指,对“本许可证”下的一方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。
|
||||
|
||||
“贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。
|
||||
|
||||
1. 授予版权许可
|
||||
|
||||
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。
|
||||
|
||||
2. 授予专利许可
|
||||
|
||||
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括仅因您或他人修改“贡献”或其他结合而将必然会侵犯到的专利权利要求。如您或您的“关联实体”直接或间接地(包括通过代理、专利被许可人或受让人),就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。
|
||||
|
||||
3. 无商标许可
|
||||
|
||||
“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。
|
||||
|
||||
4. 分发限制
|
||||
|
||||
您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。
|
||||
|
||||
5. 免责声明与责任限制
|
||||
|
||||
“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。
|
||||
|
||||
条款结束。
|
||||
|
||||
如何将木兰宽松许可证,第1版,应用到您的软件
|
||||
|
||||
如果您希望将木兰宽松许可证,第1版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步:
|
||||
|
||||
1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字;
|
||||
|
||||
2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中;
|
||||
|
||||
3, 请将如下声明文本放入每个源文件的头部注释中。
|
||||
|
||||
Copyright (c) [2019] [name of copyright holder]
|
||||
[Software Name] is licensed under the Mulan PSL v1.
|
||||
You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
You may obtain a copy of Mulan PSL v1 at:
|
||||
http://license.coscl.org.cn/MulanPSL
|
||||
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 v1 for more details.
|
||||
|
||||
|
||||
Mulan Permissive Software License,Version 1
|
||||
|
||||
Mulan Permissive Software License,Version 1 (Mulan PSL v1)
|
||||
August 2019 http://license.coscl.org.cn/MulanPSL
|
||||
|
||||
Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v1 (this License) with following terms and conditions:
|
||||
|
||||
0. Definition
|
||||
|
||||
Software means the program and related documents which are comprised of those Contribution and licensed under this License.
|
||||
|
||||
Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License.
|
||||
|
||||
Legal Entity means the entity making a Contribution and all its Affiliates.
|
||||
|
||||
Affiliates means entities that control, or are controlled by, or are under common control with a party to this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity.
|
||||
|
||||
Contribution means the copyrightable work licensed by a particular Contributor under this License.
|
||||
|
||||
1. Grant of Copyright License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not.
|
||||
|
||||
2. Grant of Patent License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed, excluding of any patent claims solely be infringed by your or others’ modification or other combinations. If you or your Affiliates directly or indirectly (including through an agent, patent licensee or assignee), institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken.
|
||||
|
||||
3. No Trademark License
|
||||
|
||||
No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in section 4.
|
||||
|
||||
4. Distribution Restriction
|
||||
|
||||
You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software.
|
||||
|
||||
5. Disclaimer of Warranty and Limitation of Liability
|
||||
|
||||
The Software and Contribution in it are provided without warranties of any kind, either express or implied. In no event shall any Contributor or copyright holder be liable to you for any damages, including, but not limited to any direct, or indirect, special or consequential damages arising from your use or inability to use the Software or the Contribution in it, no matter how it’s caused or based on which legal theory, even if advised of the possibility of such damages.
|
||||
|
||||
End of the Terms and Conditions
|
||||
|
||||
How to apply the Mulan Permissive Software License,Version 1 (Mulan PSL v1) to your software
|
||||
|
||||
To apply the Mulan PSL v1 to your work, for easy identification by recipients, you are suggested to complete following three steps:
|
||||
|
||||
i. Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner;
|
||||
ii. Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package;
|
||||
iii. Attach the statement to the appropriate annotated syntax at the beginning of each source file.
|
||||
|
||||
Copyright (c) [2019] [name of copyright holder]
|
||||
[Software Name] is licensed under the Mulan PSL v1.
|
||||
You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
You may obtain a copy of Mulan PSL v1 at:
|
||||
http://license.coscl.org.cn/MulanPSL
|
||||
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 v1 for more details.
|
50
lab2/Makefile
Normal file
50
lab2/Makefile
Normal file
@ -0,0 +1,50 @@
|
||||
BUILD_DIR := ./build
|
||||
ifndef QEMU
|
||||
QEMU := qemu-system-aarch64
|
||||
endif
|
||||
|
||||
LAB := 2
|
||||
# try to generate a unique GDB port
|
||||
GDBPORT := 1234
|
||||
QEMUOPTS = -machine raspi3 -serial null -serial mon:stdio -m size=1G -kernel $(BUILD_DIR)/kernel.img -gdb tcp::1234
|
||||
IMAGES = $(BUILD_DIR)/kernel.img
|
||||
|
||||
all: build
|
||||
|
||||
gdb:
|
||||
gdb-multiarch -n -x .gdbinit
|
||||
|
||||
build: FORCE
|
||||
./scripts/docker_build.sh
|
||||
|
||||
qemu: $(IMAGES)
|
||||
$(QEMU) $(QEMUOPTS)
|
||||
|
||||
qemu-gdb: $(IMAGES)
|
||||
@echo "***"
|
||||
@echo "*** make qemu-gdb'." 1>&2
|
||||
@echo "***"
|
||||
$(QEMU) -nographic $(QEMUOPTS) -S
|
||||
|
||||
|
||||
gdbport:
|
||||
@echo $(GDBPORT)
|
||||
|
||||
docker: FORCE
|
||||
./scripts/run_docker.sh
|
||||
|
||||
grade: build FORCE
|
||||
@echo "make grade"
|
||||
@echo "LAB"$(LAB)": test >>>>>>>>>>>>>>>>>"
|
||||
ifeq ($(LAB), 2)
|
||||
./scripts/run_mm_test.sh
|
||||
endif
|
||||
./scripts/grade-lab$(LAB)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm -rf build
|
||||
@rm -rf chcore.out
|
||||
|
||||
.PHONY: FORCE
|
||||
FORCE:
|
32
lab2/README.md
Normal file
32
lab2/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# ChCore
|
||||
|
||||
This is the repository of ChCore labs in SE315, 2020 Spring.
|
||||
|
||||
## build
|
||||
- `make` or `make build`
|
||||
- The project will be built in `build` directory.
|
||||
|
||||
## Emulate
|
||||
- `make qemu`
|
||||
|
||||
Emulate ChCore in QEMU
|
||||
|
||||
## Debug with GBD
|
||||
|
||||
- `make qemu-gdb`
|
||||
|
||||
Start a GDB server running ChCore
|
||||
|
||||
- `make gdb`
|
||||
|
||||
Start a GDB (gdb-multiarch) client
|
||||
|
||||
## Grade
|
||||
- `make grade`
|
||||
|
||||
Show your grade of labs in the current branch
|
||||
|
||||
## Other
|
||||
- type `Ctrl+a x` to quit QEMU
|
||||
- type `Ctrl+d` to quit GDB
|
||||
|
13
lab2/boot/boot.h
Normal file
13
lab2/boot/boot.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
extern void el1_mmu_activate(void);
|
||||
extern void init_boot_pt(void);
|
||||
|
||||
extern void start_kernel(void *boot_flag);
|
||||
|
||||
extern char _bss_start;
|
||||
extern char _bss_end;
|
||||
|
||||
#define PLAT_CPU_NUMBER 4
|
||||
|
||||
#define ALIGN(n) __attribute__((__aligned__(n)))
|
12
lab2/boot/config.cmake
Normal file
12
lab2/boot/config.cmake
Normal file
@ -0,0 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
set(INIT_PATH "${BOOTLOADER_PATH}")
|
||||
|
||||
file(
|
||||
GLOB
|
||||
tmpfiles
|
||||
"${INIT_PATH}/*.c"
|
||||
"${INIT_PATH}/*.S"
|
||||
)
|
||||
|
||||
list(APPEND files ${tmpfiles})
|
7
lab2/boot/image.h
Normal file
7
lab2/boot/image.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define SZ_16K 0x4000
|
||||
#define SZ_64K 0x10000
|
||||
|
||||
#define KERNEL_VADDR 0xffffff0000000000
|
||||
#define TEXT_OFFSET 0x80000
|
64
lab2/boot/init_c.c
Normal file
64
lab2/boot/init_c.c
Normal file
@ -0,0 +1,64 @@
|
||||
#include "boot.h"
|
||||
#include "image.h"
|
||||
|
||||
typedef unsigned long u64;
|
||||
|
||||
#define INIT_STACK_SIZE 0x1000
|
||||
char boot_cpu_stack[PLAT_CPU_NUMBER][INIT_STACK_SIZE] ALIGN(16);
|
||||
|
||||
/*
|
||||
* Initialize these varibles in order to make them not in .bss section.
|
||||
* So, they will have concrete initial value even on real machine.
|
||||
*
|
||||
* Non-primary CPUs will spin until they see the secondary_boot_flag becomes
|
||||
* non-zero which is set in kernel (see enable_smp_cores).
|
||||
*
|
||||
* The secondary_boot_flag is initilized as {NOT_BSS, 0, 0, ...}.
|
||||
*/
|
||||
#define NOT_BSS (0xBEEFUL)
|
||||
long secondary_boot_flag[PLAT_CPU_NUMBER] = { NOT_BSS };
|
||||
|
||||
volatile u64 clear_bss_flag = NOT_BSS;
|
||||
|
||||
/* Uart */
|
||||
void early_uart_init(void);
|
||||
void uart_send_string(char *);
|
||||
|
||||
static void clear_bss(void)
|
||||
{
|
||||
u64 bss_start_addr;
|
||||
u64 bss_end_addr;
|
||||
u64 i;
|
||||
|
||||
bss_start_addr = (u64) & _bss_start;
|
||||
bss_end_addr = (u64) & _bss_end;
|
||||
|
||||
for (i = bss_start_addr; i < bss_end_addr; ++i)
|
||||
*(char *)i = 0;
|
||||
|
||||
clear_bss_flag = 0;
|
||||
}
|
||||
|
||||
void init_c(void)
|
||||
{
|
||||
/* Clear the bss area for the kernel image */
|
||||
clear_bss();
|
||||
|
||||
/* Initialize UART before enabling MMU. */
|
||||
early_uart_init();
|
||||
uart_send_string("boot: init_c\r\n");
|
||||
|
||||
/* Initialize Boot Page Table. */
|
||||
uart_send_string("[BOOT] Install boot page table\r\n");
|
||||
init_boot_pt();
|
||||
|
||||
/* Enable MMU. */
|
||||
el1_mmu_activate();
|
||||
uart_send_string("[BOOT] Enable el1 MMU\r\n");
|
||||
|
||||
/* Call Kernel Main. */
|
||||
uart_send_string("[BOOT] Jump to kernel main\r\n");
|
||||
start_kernel(secondary_boot_flag);
|
||||
|
||||
/* Never reach here */
|
||||
}
|
132
lab2/boot/mmu.c
Normal file
132
lab2/boot/mmu.c
Normal file
@ -0,0 +1,132 @@
|
||||
#include "image.h"
|
||||
|
||||
typedef unsigned long u64;
|
||||
typedef unsigned int u32;
|
||||
|
||||
/* Physical memory address space: 0-1G */
|
||||
#define PHYSMEM_START (0x0UL)
|
||||
#define PHYSMEM_BOOT_END (0x10000000UL)
|
||||
#define PERIPHERAL_BASE (0x20000000UL)
|
||||
#define PHYSMEM_END (0x40000000UL)
|
||||
|
||||
/* The number of entries in one page table page */
|
||||
#define PTP_ENTRIES 512
|
||||
/* The size of one page table page */
|
||||
#define PTP_SIZE 4096
|
||||
#define ALIGN(n) __attribute__((__aligned__(n)))
|
||||
u64 boot_ttbr0_l0[PTP_ENTRIES] ALIGN(PTP_SIZE);
|
||||
u64 boot_ttbr0_l1[PTP_ENTRIES] ALIGN(PTP_SIZE);
|
||||
u64 boot_ttbr0_l2[PTP_ENTRIES] ALIGN(PTP_SIZE);
|
||||
|
||||
u64 boot_ttbr1_l0[PTP_ENTRIES] ALIGN(PTP_SIZE);
|
||||
u64 boot_ttbr1_l1[PTP_ENTRIES] ALIGN(PTP_SIZE);
|
||||
u64 boot_ttbr1_l2[PTP_ENTRIES] ALIGN(PTP_SIZE);
|
||||
|
||||
#define IS_VALID (1UL << 0)
|
||||
#define IS_TABLE (1UL << 1)
|
||||
|
||||
#define UXN (0x1UL << 54)
|
||||
#define ACCESSED (0x1UL << 10)
|
||||
#define INNER_SHARABLE (0x3UL << 8)
|
||||
#define NORMAL_MEMORY (0x4UL << 2)
|
||||
#define DEVICE_MEMORY (0x0UL << 2)
|
||||
|
||||
#define SIZE_2M (2UL*1024*1024)
|
||||
|
||||
#define GET_L0_INDEX(x) (((x) >> (12 + 9 + 9 + 9)) & 0x1ff)
|
||||
#define GET_L1_INDEX(x) (((x) >> (12 + 9 + 9)) & 0x1ff)
|
||||
#define GET_L2_INDEX(x) (((x) >> (12 + 9)) & 0x1ff)
|
||||
|
||||
void init_boot_pt(void)
|
||||
{
|
||||
u32 start_entry_idx;
|
||||
u32 end_entry_idx;
|
||||
u32 idx;
|
||||
u64 kva;
|
||||
|
||||
/* TTBR0_EL1 0-1G */
|
||||
boot_ttbr0_l0[0] = ((u64) boot_ttbr0_l1) | IS_TABLE | IS_VALID;
|
||||
boot_ttbr0_l1[0] = ((u64) boot_ttbr0_l2) | IS_TABLE | IS_VALID;
|
||||
|
||||
/* Usuable memory: PHYSMEM_START ~ PERIPHERAL_BASE */
|
||||
start_entry_idx = PHYSMEM_START / SIZE_2M;
|
||||
end_entry_idx = PERIPHERAL_BASE / SIZE_2M;
|
||||
|
||||
/* Map each 2M page */
|
||||
for (idx = start_entry_idx; idx < end_entry_idx; ++idx) {
|
||||
boot_ttbr0_l2[idx] = (PHYSMEM_START + idx * SIZE_2M)
|
||||
| UXN /* Unprivileged execute never */
|
||||
| ACCESSED /* Set access flag */
|
||||
| INNER_SHARABLE /* Sharebility */
|
||||
| NORMAL_MEMORY /* Normal memory */
|
||||
| IS_VALID;
|
||||
}
|
||||
|
||||
/* Peripheral memory: PERIPHERAL_BASE ~ PHYSMEM_END */
|
||||
|
||||
/* Raspi3b/3b+ Peripherals: 0x3f 00 00 00 - 0x3f ff ff ff */
|
||||
start_entry_idx = end_entry_idx;
|
||||
end_entry_idx = PHYSMEM_END / SIZE_2M;
|
||||
|
||||
/* Map each 2M page */
|
||||
for (idx = start_entry_idx; idx < end_entry_idx; ++idx) {
|
||||
boot_ttbr0_l2[idx] = (PHYSMEM_START + idx * SIZE_2M)
|
||||
| UXN /* Unprivileged execute never */
|
||||
| ACCESSED /* Set access flag */
|
||||
| DEVICE_MEMORY /* Device memory */
|
||||
| IS_VALID;
|
||||
}
|
||||
|
||||
/*
|
||||
* TTBR1_EL1 0-1G
|
||||
* KERNEL_VADDR: L0 pte index: 510; L1 pte index: 0; L2 pte index: 0.
|
||||
*/
|
||||
kva = KERNEL_VADDR;
|
||||
boot_ttbr1_l0[GET_L0_INDEX(kva)] = ((u64) boot_ttbr1_l1)
|
||||
| IS_TABLE | IS_VALID;
|
||||
boot_ttbr1_l1[GET_L1_INDEX(kva)] = ((u64) boot_ttbr1_l2)
|
||||
| IS_TABLE | IS_VALID;
|
||||
|
||||
start_entry_idx = GET_L2_INDEX(kva);
|
||||
/* Note: assert(start_entry_idx == 0) */
|
||||
end_entry_idx = start_entry_idx + PHYSMEM_BOOT_END / SIZE_2M;
|
||||
/* Note: assert(end_entry_idx < PTP_ENTIRES) */
|
||||
|
||||
/*
|
||||
* Map each 2M page
|
||||
* Usuable memory: PHYSMEM_START ~ PERIPHERAL_BASE
|
||||
*/
|
||||
for (idx = start_entry_idx; idx < end_entry_idx; ++idx) {
|
||||
boot_ttbr1_l2[idx] = (PHYSMEM_START + idx * SIZE_2M)
|
||||
| UXN /* Unprivileged execute never */
|
||||
| ACCESSED /* Set access flag */
|
||||
| INNER_SHARABLE /* Sharebility */
|
||||
| NORMAL_MEMORY /* Normal memory */
|
||||
| IS_VALID;
|
||||
}
|
||||
|
||||
/* Peripheral memory: PERIPHERAL_BASE ~ PHYSMEM_END */
|
||||
start_entry_idx = start_entry_idx + PERIPHERAL_BASE / SIZE_2M;
|
||||
end_entry_idx = PHYSMEM_END / SIZE_2M;
|
||||
|
||||
/* Map each 2M page */
|
||||
for (idx = start_entry_idx; idx < end_entry_idx; ++idx) {
|
||||
boot_ttbr1_l2[idx] = (PHYSMEM_START + idx * SIZE_2M)
|
||||
| UXN /* Unprivileged execute never */
|
||||
| ACCESSED /* Set access flag */
|
||||
| DEVICE_MEMORY /* Device memory */
|
||||
| IS_VALID;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local peripherals, e.g., ARM timer, IRQs, and mailboxes
|
||||
*
|
||||
* 0x4000_0000 .. 0xFFFF_FFFF
|
||||
* 1G is enough. Map 1G page here.
|
||||
*/
|
||||
kva = KERNEL_VADDR + PHYSMEM_END;
|
||||
boot_ttbr1_l1[GET_L1_INDEX(kva)] = PHYSMEM_END | UXN /* Unprivileged execute never */
|
||||
| ACCESSED /* Set access flag */
|
||||
| DEVICE_MEMORY /* Device memory */
|
||||
| IS_VALID;
|
||||
}
|
32
lab2/boot/start.S
Normal file
32
lab2/boot/start.S
Normal file
@ -0,0 +1,32 @@
|
||||
#include <common/asm.h>
|
||||
|
||||
.extern arm64_elX_to_el1
|
||||
.extern boot_cpu_stack
|
||||
.extern secondary_boot_flag
|
||||
.extern clear_bss_flag
|
||||
.extern init_c
|
||||
|
||||
BEGIN_FUNC(_start)
|
||||
mrs x8, mpidr_el1
|
||||
and x8, x8, #0xFF
|
||||
cbz x8, primary
|
||||
|
||||
/* hang all secondary processors before we intorduce multi-processors */
|
||||
secondary_hang:
|
||||
bl secondary_hang
|
||||
|
||||
primary:
|
||||
|
||||
/* Turn to el1 from other exception levels. */
|
||||
bl arm64_elX_to_el1
|
||||
|
||||
/* Prepare stack pointer and jump to C. */
|
||||
adr x0, boot_cpu_stack
|
||||
add x0, x0, #0x1000
|
||||
mov sp, x0
|
||||
|
||||
bl init_c
|
||||
|
||||
/* Should never be here */
|
||||
b .
|
||||
END_FUNC(_start)
|
288
lab2/boot/tools.S
Normal file
288
lab2/boot/tools.S
Normal file
@ -0,0 +1,288 @@
|
||||
// Copyright 2016 The Fuchsia Authors
|
||||
// Copyright (c) 2014, Google Inc. All rights reserved
|
||||
//
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Sergey Matyukevich
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ChCore refers to both
|
||||
* https://github.com/s-matyukevich/raspberry-pi-os/blob/master/docs/lesson01/rpi-os.md
|
||||
* and Google Zircon for implementing the boot helper functions.
|
||||
*/
|
||||
|
||||
#include <common/asm.h>
|
||||
#include <common/registers.h>
|
||||
|
||||
|
||||
#define CURRENTEL_EL1 (0b01 << 2)
|
||||
#define CURRENTEL_EL2 (0b10 << 2)
|
||||
|
||||
#define CPACR_EL1_FPEN (0b11 << 20)
|
||||
#define ID_AA64PFR0_EL1_GIC (0b1111 << 24)
|
||||
|
||||
#define CNTHCTL_EL2_EL1PCEN (1 << 1)
|
||||
#define CNTHCTL_EL2_EL1PCTEN (1 << 0)
|
||||
#define CPTR_EL2_RES1 0x33ff
|
||||
#define HCR_EL2_RW (1 << 31)
|
||||
#define ICC_SRE_EL2_SRE (1 << 0)
|
||||
#define ICC_SRE_EL2_ENABLE (1 << 3)
|
||||
|
||||
#define SCR_EL3_HCE (1 << 8)
|
||||
#define SCR_EL3_NS (1 << 0)
|
||||
#define SCR_EL3_RW (1 << 10)
|
||||
|
||||
#define SPSR_ELX_DAIF (0b1111 << 6)
|
||||
#define SPSR_ELX_EL1H (0b0101)
|
||||
|
||||
#define ICH_HCR_EL2 S3_4_C12_C11_0
|
||||
#define ICC_SRE_EL2 S3_4_C12_C9_5
|
||||
|
||||
BEGIN_FUNC(arm64_elX_to_el1)
|
||||
mrs x9, CurrentEL
|
||||
|
||||
// Check the current exception level.
|
||||
cmp x9, CURRENTEL_EL1
|
||||
beq .Ltarget
|
||||
cmp x9, CURRENTEL_EL2
|
||||
beq .Lin_el2
|
||||
// Otherwise, we are in EL3.
|
||||
|
||||
// Set EL2 to 64bit and enable the HVC instruction.
|
||||
mrs x9, scr_el3
|
||||
mov x10, SCR_EL3_NS | SCR_EL3_HCE | SCR_EL3_RW
|
||||
orr x9, x9, x10
|
||||
msr scr_el3, x9
|
||||
|
||||
// Set the return address and exception level.
|
||||
adr x9, .Ltarget
|
||||
msr elr_el3, x9
|
||||
mov x9, SPSR_ELX_DAIF | SPSR_ELX_EL1H
|
||||
msr spsr_el3, x9
|
||||
|
||||
.Lin_el2:
|
||||
// Disable EL1 timer traps and the timer offset.
|
||||
mrs x9, cnthctl_el2
|
||||
orr x9, x9, CNTHCTL_EL2_EL1PCEN | CNTHCTL_EL2_EL1PCTEN
|
||||
msr cnthctl_el2, x9
|
||||
msr cntvoff_el2, xzr
|
||||
|
||||
// Disable stage 2 translations.
|
||||
msr vttbr_el2, xzr
|
||||
|
||||
// Disable EL2 coprocessor traps.
|
||||
mov x9, CPTR_EL2_RES1
|
||||
msr cptr_el2, x9
|
||||
|
||||
// Disable EL1 FPU traps.
|
||||
mov x9, CPACR_EL1_FPEN
|
||||
msr cpacr_el1, x9
|
||||
|
||||
// Check whether the GIC system registers are supported.
|
||||
mrs x9, id_aa64pfr0_el1
|
||||
and x9, x9, ID_AA64PFR0_EL1_GIC
|
||||
cbz x9, .Lno_gic_sr
|
||||
|
||||
// Enable the GIC system registers in EL2, and allow their use in EL1.
|
||||
mrs x9, ICC_SRE_EL2
|
||||
mov x10, ICC_SRE_EL2_ENABLE | ICC_SRE_EL2_SRE
|
||||
orr x9, x9, x10
|
||||
msr ICC_SRE_EL2, x9
|
||||
|
||||
// Disable the GIC virtual CPU interface.
|
||||
msr ICH_HCR_EL2, xzr
|
||||
|
||||
.Lno_gic_sr:
|
||||
// Set EL1 to 64bit.
|
||||
mov x9, HCR_EL2_RW
|
||||
msr hcr_el2, x9
|
||||
|
||||
// Set the return address and exception level.
|
||||
adr x9, .Ltarget
|
||||
msr elr_el2, x9
|
||||
mov x9, SPSR_ELX_DAIF | SPSR_ELX_EL1H
|
||||
msr spsr_el2, x9
|
||||
|
||||
isb
|
||||
eret
|
||||
|
||||
.Ltarget:
|
||||
ret
|
||||
END_FUNC(arm64_elX_to_el1)
|
||||
|
||||
BEGIN_FUNC(invalidate_cache_all)
|
||||
mrs x0, clidr_el1
|
||||
and w3, w0, #0x07000000 // get 2x level of coherence
|
||||
lsr w3, w3, #23
|
||||
cbz w3, .Lfinished_inv_cache
|
||||
mov w10, #0 // w10 = 2x cache level
|
||||
mov w8, #1 // w8 = constant 1
|
||||
.Lloop1_inv_cache:
|
||||
add w2, w10, w10, lsr #1 // calculate 3x cache level
|
||||
lsr w1, w0, w2 // extract 3 bit cache type for this level
|
||||
and w1, w1, #0x7
|
||||
cmp w1, #2
|
||||
b.lt .Lskip_inv_cache // no data or unified cache at this level
|
||||
msr csselr_el1, x10 // select this cache level
|
||||
isb // synchronize change to csselr
|
||||
mrs x1, ccsidr_el1 // w1 = ccsidr
|
||||
and w2, w1, #7 // w2 = log2(line len) - 4
|
||||
add w2, w2, #4 // w2 = log2(line len)
|
||||
ubfx w4, w1, #3, #10 // w4 = max way number, right aligned
|
||||
clz w5, w4 // w5 = 32 - log2(ways), bit position of way in DC operand
|
||||
lsl w9, w4, w5 // w9 = max way number, aligned to position in DC operand
|
||||
lsl w12, w8, w5 // w12 = amount to decrement way number per iteration
|
||||
|
||||
.Lloop2_inv_cache:
|
||||
ubfx w7, w1, #13, #15 // w7 = max set number, right aligned
|
||||
lsl w7, w7, w2 // w7 = max set number, aligned to position in DC operand
|
||||
lsl w13, w8, w2 // w13 = amount to decrement set number per iteration
|
||||
.Lloop3_inv_cache:
|
||||
orr w11, w10, w9 // w11 = combine way number and cache number
|
||||
orr w11, w11, w7 // and set number for DC operand
|
||||
dc isw, x11 // data cache op
|
||||
subs w7, w7, w13 // decrement set number
|
||||
b.ge .Lloop3_inv_cache
|
||||
|
||||
subs w9, w9, w12 // decrement way number
|
||||
b.ge .Lloop2_inv_cache
|
||||
.Lskip_inv_cache:
|
||||
add w10, w10, #2 // increment 2x cache level
|
||||
cmp w3, w10
|
||||
dsb sy // ensure completetion of previous cache maintainance instructions
|
||||
b.gt .Lloop1_inv_cache
|
||||
.Lfinished_inv_cache:
|
||||
|
||||
// dump the instruction cache as well
|
||||
ic iallu
|
||||
isb
|
||||
ret
|
||||
END_FUNC(invalidate_cache_all)
|
||||
|
||||
.extern boot_ttbr0_l0
|
||||
.extern boot_ttbr1_l0
|
||||
|
||||
|
||||
/* Device-nGnRE memory */
|
||||
#define MMU_MAIR_ATTR1 (0x04 << (8 * 1))
|
||||
|
||||
/* Normal Memory, Outer Write-back non-transient Read/Write allocate,
|
||||
* Inner Write-back non-transient Read/Write allocate
|
||||
*/
|
||||
#define MMU_MAIR_ATTR2 (0xff << (8 * 2))
|
||||
|
||||
/* Normal Memory, Inner/Outer uncached, Write Combined */
|
||||
#define MMU_MAIR_ATTR3 (0x44 << (8 * 3))
|
||||
|
||||
|
||||
/*
|
||||
* Enable cached page table walks:
|
||||
* inner/outer (IRGN/ORGN): write-back + write-allocate
|
||||
*/
|
||||
#define MMU_TCR_TG1_4k (0 << 14)
|
||||
#define MMU_TCR_SH1_INNER_SH (3 << 28)
|
||||
#define MMU_TCR_ORGN1_WBA (1 << 26)
|
||||
#define MMU_TCR_IRGN1_WBA (1 << 24)
|
||||
#define MMU_TCR_T1SZ ((64 - 48) << 16) /* 48-bit */
|
||||
#define MMU_TCR_FLAGS1 (MMU_TCR_TG1_4k | MMU_TCR_SH1_INNER_SH | \
|
||||
MMU_TCR_ORGN1_WBA | MMU_TCR_IRGN1_WBA | MMU_TCR_T1SZ)
|
||||
|
||||
#define MMU_TCR_TG0_4k (0 << 30)
|
||||
#define MMU_TCR_SH0_INNER_SH (3 << 12)
|
||||
#define MMU_TCR_ORGN0_WBA (1 << 10)
|
||||
#define MMU_TCR_IRGN0_WBA (1 << 8)
|
||||
#define MMU_TCR_T0SZ ((64 - 48) << 0) /* 48-bit */
|
||||
#define MMU_TCR_FLAGS0 (MMU_TCR_TG0_4k | MMU_TCR_SH0_INNER_SH | \
|
||||
MMU_TCR_ORGN0_WBA | MMU_TCR_IRGN0_WBA | MMU_TCR_T0SZ)
|
||||
#define MMU_TCR_IPS (0b101 << 32) /* 48-bit */
|
||||
#define MMU_TCR_AS (1 << 36)
|
||||
|
||||
|
||||
BEGIN_FUNC(el1_mmu_activate)
|
||||
stp x29, x30, [sp, #-16]!
|
||||
mov x29, sp
|
||||
|
||||
bl invalidate_cache_all
|
||||
|
||||
/* Invalidate TLB */
|
||||
tlbi vmalle1is
|
||||
isb
|
||||
dsb sy
|
||||
|
||||
/* Initialize Memory Attribute Indirection Register */
|
||||
ldr x8, =MMU_MAIR_ATTR1 | MMU_MAIR_ATTR2 | MMU_MAIR_ATTR3
|
||||
msr mair_el1, x8
|
||||
|
||||
/* Initialize TCR_EL1 */
|
||||
/* set cacheable attributes on translation walk */
|
||||
/* (SMP extensions) non-shareable, inner write-back write-allocate */
|
||||
ldr x8, =MMU_TCR_FLAGS1 | MMU_TCR_FLAGS0 | MMU_TCR_IPS | MMU_TCR_AS
|
||||
msr tcr_el1, x8
|
||||
isb
|
||||
|
||||
/* Write ttbr with phys addr of the translation table */
|
||||
adrp x8, boot_ttbr0_l0
|
||||
msr ttbr0_el1, x8
|
||||
adrp x8, boot_ttbr1_l0
|
||||
msr ttbr1_el1, x8
|
||||
isb
|
||||
|
||||
mrs x8, sctlr_el1
|
||||
/* Enable MMU */
|
||||
orr x8, x8, #SCTLR_EL1_M
|
||||
/* Disable alignment checking */
|
||||
bic x8, x8, #SCTLR_EL1_A
|
||||
bic x8, x8, #SCTLR_EL1_SA0
|
||||
bic x8, x8, #SCTLR_EL1_SA
|
||||
orr x8, x8, #SCTLR_EL1_nAA
|
||||
/* Data accesses Cacheable */
|
||||
orr x8, x8, #SCTLR_EL1_C
|
||||
/* Instruction access Cacheable */
|
||||
orr x8, x8, #SCTLR_EL1_I
|
||||
msr sctlr_el1, x8
|
||||
|
||||
ldp x29, x30, [sp], #16
|
||||
ret
|
||||
END_FUNC(el1_mmu_activate)
|
||||
|
||||
|
||||
/* These simple function is written by ChCorers */
|
||||
BEGIN_FUNC(early_put32)
|
||||
str w1, [x0]
|
||||
ret
|
||||
END_FUNC(early_put32)
|
||||
|
||||
BEGIN_FUNC(early_get32)
|
||||
ldr w0, [x0]
|
||||
ret
|
||||
END_FUNC(early_get32)
|
||||
|
||||
BEGIN_FUNC(delay)
|
||||
subs x0, x0, #1
|
||||
bne delay
|
||||
ret
|
||||
END_FUNC(delay)
|
79
lab2/boot/uart.c
Normal file
79
lab2/boot/uart.c
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Sergey Matyukevich
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ChCore refers to
|
||||
* https://github.com/s-matyukevich/raspberry-pi-os/blob/master/docs/lesson01/rpi-os.md
|
||||
* for the min-uart init process.
|
||||
*/
|
||||
|
||||
#include "uart.h"
|
||||
|
||||
void early_uart_init(void)
|
||||
{
|
||||
unsigned int ra;
|
||||
|
||||
ra = early_get32(GPFSEL1);
|
||||
ra &= ~(7 << 12);
|
||||
ra |= 2 << 12;
|
||||
ra &= ~(7 << 15);
|
||||
ra |= 2 << 15;
|
||||
early_put32(GPFSEL1, ra);
|
||||
|
||||
early_put32(GPPUD, 0);
|
||||
delay(150);
|
||||
early_put32(GPPUDCLK0, (1 << 14) | (1 << 15));
|
||||
delay(150);
|
||||
early_put32(GPPUDCLK0, 0);
|
||||
|
||||
early_put32(AUX_ENABLES, 1);
|
||||
early_put32(AUX_MU_IER_REG, 0);
|
||||
early_put32(AUX_MU_CNTL_REG, 0);
|
||||
early_put32(AUX_MU_IER_REG, 0);
|
||||
early_put32(AUX_MU_LCR_REG, 3);
|
||||
early_put32(AUX_MU_MCR_REG, 0);
|
||||
early_put32(AUX_MU_BAUD_REG, 270);
|
||||
|
||||
early_put32(AUX_MU_CNTL_REG, 3);
|
||||
}
|
||||
|
||||
unsigned int early_uart_lsr(void)
|
||||
{
|
||||
return early_get32(AUX_MU_LSR_REG);
|
||||
}
|
||||
|
||||
static void early_uart_send(unsigned int c)
|
||||
{
|
||||
while (1) {
|
||||
if (early_uart_lsr() & 0x20)
|
||||
break;
|
||||
}
|
||||
early_put32(AUX_MU_IO_REG, c);
|
||||
}
|
||||
|
||||
void uart_send_string(char *str)
|
||||
{
|
||||
for (int i = 0; str[i] != '\0'; i++)
|
||||
early_uart_send((char)str[i]);
|
||||
}
|
58
lab2/boot/uart.h
Normal file
58
lab2/boot/uart.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Sergey Matyukevich
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ChCore refers to
|
||||
* https://github.com/s-matyukevich/raspberry-pi-os/blob/master/docs/lesson01/rpi-os.md
|
||||
* for the min-uart init process.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* This peripheral mapped offset is specific to BCM2837 */
|
||||
#define PHYSADDR_OFFSET 0x3F000000UL
|
||||
|
||||
/* BCM2835 and BCM2837 define the same offsets */
|
||||
#define GPFSEL1 (PHYSADDR_OFFSET + 0x00200004)
|
||||
#define GPSET0 (PHYSADDR_OFFSET + 0x0020001C)
|
||||
#define GPCLR0 (PHYSADDR_OFFSET + 0x00200028)
|
||||
#define GPPUD (PHYSADDR_OFFSET + 0x00200094)
|
||||
#define GPPUDCLK0 (PHYSADDR_OFFSET + 0x00200098)
|
||||
|
||||
#define AUX_ENABLES (PHYSADDR_OFFSET + 0x00215004)
|
||||
#define AUX_MU_IO_REG (PHYSADDR_OFFSET + 0x00215040)
|
||||
#define AUX_MU_IER_REG (PHYSADDR_OFFSET + 0x00215044)
|
||||
#define AUX_MU_IIR_REG (PHYSADDR_OFFSET + 0x00215048)
|
||||
#define AUX_MU_LCR_REG (PHYSADDR_OFFSET + 0x0021504C)
|
||||
#define AUX_MU_MCR_REG (PHYSADDR_OFFSET + 0x00215050)
|
||||
#define AUX_MU_LSR_REG (PHYSADDR_OFFSET + 0x00215054)
|
||||
#define AUX_MU_MSR_REG (PHYSADDR_OFFSET + 0x00215058)
|
||||
#define AUX_MU_SCRATCH (PHYSADDR_OFFSET + 0x0021505C)
|
||||
#define AUX_MU_CNTL_REG (PHYSADDR_OFFSET + 0x00215060)
|
||||
#define AUX_MU_STAT_REG (PHYSADDR_OFFSET + 0x00215064)
|
||||
#define AUX_MU_BAUD_REG (PHYSADDR_OFFSET + 0x00215068)
|
||||
|
||||
void early_put32(unsigned long int addr, unsigned int ch);
|
||||
unsigned int early_get32(unsigned long int addr);
|
||||
void delay(unsigned long time);
|
11
lab2/kernel/CMakeLists.txt
Normal file
11
lab2/kernel/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
add_library(${PROJECT_NAME}-arch OBJECT
|
||||
head.S
|
||||
main.c
|
||||
monitor.c
|
||||
common/tools.S
|
||||
common/uart.c
|
||||
common/printk.c
|
||||
mm/page_table.S
|
||||
)
|
39
lab2/kernel/common/asm.h
Normal file
39
lab2/kernel/common/asm.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define __ASM__
|
||||
|
||||
#define BEGIN_FUNC(_name) \
|
||||
.global _name; \
|
||||
.type _name, %function; \
|
||||
_name:
|
||||
|
||||
#define END_FUNC(_name) \
|
||||
.size _name, .-_name
|
||||
|
||||
#define EXPORT(symbol) \
|
||||
.globl symbol; \
|
||||
symbol:
|
||||
|
||||
#define LOCAL_DATA(x) \
|
||||
.type x,1; \
|
||||
x:
|
||||
|
||||
#define DATA(x) \
|
||||
.global x; \
|
||||
.hidden x; \
|
||||
LOCAL_DATA(x)
|
||||
|
||||
#define END_DATA(x) \
|
||||
.size x, .-x
|
40
lab2/kernel/common/errno.h
Normal file
40
lab2/kernel/common/errno.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define EPERM 1 /* Operation not permitted */
|
||||
#define EAGAIN 2 /* Try again */
|
||||
#define ENOMEM 3 /* Out of memory */
|
||||
#define EACCES 4 /* Permission denied */
|
||||
#define EINVAL 5 /* Invalid argument */
|
||||
#define EFBIG 6 /* File too large */
|
||||
#define ENOSPC 7 /* No space left on device */
|
||||
#define ENOSYS 8 /* Function not implemented */
|
||||
#define ENODATA 9 /* No data available */
|
||||
#define ETIME 10 /* Timer expired */
|
||||
#define ECAPBILITY 11 /* Invalid capability */
|
||||
#define ESUPPORT 12 /* Not supported */
|
||||
#define EBADSYSCALL 13 /* Bad syscall number */
|
||||
#define ENOMAPPING 14 /* Bad syscall number */
|
||||
#define ENOENT 15 /* Entry does not exist */
|
||||
#define EEXIST 16 /* Entry already exists */
|
||||
#define ENOTEMPTY 17 /* Dir is not empty */
|
||||
#define ENOTDIR 18 /* Does not refer to a directory */
|
||||
#define EFAULT 19 /* Bad address */
|
||||
#define EBUSY 20
|
||||
|
||||
#define EMAX 21
|
||||
|
||||
#define ERR_PTR(x) ((void *)(s64)(x))
|
||||
#define PTR_ERR(x) ((long)(x))
|
||||
#define IS_ERR(x) ((((s64)(x)) < 0) && ((s64)(x)) > -EMAX)
|
26
lab2/kernel/common/kmalloc.h
Normal file
26
lab2/kernel/common/kmalloc.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/types.h>
|
||||
#include <common/util.h>
|
||||
|
||||
u64 size_to_page_order(size_t size);
|
||||
void *kmalloc(size_t size);
|
||||
/* zero the allocated are */
|
||||
void *kzalloc(size_t size);
|
||||
void kfree(void *ptr);
|
||||
|
||||
/* return vaddr of (1 << order) continous free physical pages */
|
||||
void *get_pages(int order);
|
||||
void free_pages(void *addr);
|
39
lab2/kernel/common/kprint.h
Normal file
39
lab2/kernel/common/kprint.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "printk.h"
|
||||
|
||||
#define WARNING 0
|
||||
#define INFO 1
|
||||
#define DEBUG 2
|
||||
|
||||
/* LOG_LEVEL is INFO by default */
|
||||
|
||||
#if LOG_LEVEL >= WARNING
|
||||
#define kwarn(fmt, ...) printk("[WARN] "fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define kwarn(fmt, ...)
|
||||
#endif
|
||||
|
||||
#if LOG_LEVEL >= INFO
|
||||
#define kinfo(fmt, ...) printk("[INFO] "fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define kinfo(fmt, ...)
|
||||
#endif
|
||||
|
||||
#if LOG_LEVEL >= DEBUG
|
||||
#define kdebug(fmt, ...) printk("[DEBUG] "fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define kdebug(fmt, ...)
|
||||
#endif
|
75
lab2/kernel/common/list.h
Normal file
75
lab2/kernel/common/list.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/macro.h>
|
||||
#include <common/types.h>
|
||||
|
||||
struct list_head {
|
||||
struct list_head *prev;
|
||||
struct list_head *next;
|
||||
};
|
||||
|
||||
static inline void init_list_head(struct list_head *list)
|
||||
{
|
||||
list->next = list;
|
||||
list->prev = list;
|
||||
}
|
||||
|
||||
static inline void list_add(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
new->next = head->next;
|
||||
new->prev = head;
|
||||
head->next->prev = new;
|
||||
head->next = new;
|
||||
}
|
||||
|
||||
static inline void list_append(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
struct list_head *tail = head->prev;
|
||||
return list_add(new, tail);
|
||||
}
|
||||
|
||||
static inline void list_del(struct list_head *node)
|
||||
{
|
||||
node->prev->next = node->next;
|
||||
node->next->prev = node->prev;
|
||||
}
|
||||
|
||||
static inline bool list_empty(struct list_head *head)
|
||||
{
|
||||
return (head->prev == head && head->next == head);
|
||||
}
|
||||
|
||||
#define next_container_of_safe(obj, type, field) ({ \
|
||||
typeof (obj) __obj = (obj); \
|
||||
(__obj ? \
|
||||
container_of_safe(((__obj)->field).next, type, field) : NULL); \
|
||||
})
|
||||
|
||||
#define list_entry(ptr, type, field) \
|
||||
container_of(ptr, type, field)
|
||||
|
||||
#define for_each_in_list(elem, type, field, head) \
|
||||
for (elem = container_of((head)->next, type, field); \
|
||||
&((elem)->field) != (head); \
|
||||
elem = container_of(((elem)->field).next, type, field))
|
||||
|
||||
#define __for_each_in_list_safe(elem, tmp, type, field, head) \
|
||||
for (elem = container_of((head)->next, type, field), \
|
||||
tmp = next_container_of_safe(elem, type, field); \
|
||||
&((elem)->field) != (head); \
|
||||
elem = tmp, tmp = next_container_of_safe(tmp, type, field))
|
||||
|
||||
#define for_each_in_list_safe(elem, tmp, field, head) \
|
||||
__for_each_in_list_safe(elem, tmp, typeof (*elem), field, head)
|
33
lab2/kernel/common/machine.h
Normal file
33
lab2/kernel/common/machine.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/vars.h>
|
||||
|
||||
/* raspi3 config */
|
||||
#define PLAT_CPU_NUM 4
|
||||
|
||||
// Timers interrupt control registers
|
||||
#define IMER_IRQCNTL_BASE (KBASE + 0x40000040)
|
||||
#define CORE0_TIMER_IRQCNTL (IMER_IRQCNTL_BASE + 0x0)
|
||||
#define CORE1_TIMER_IRQCNTL (IMER_IRQCNTL_BASE + 0x4)
|
||||
#define CORE2_TIMER_IRQCNTL (IMER_IRQCNTL_BASE + 0x8)
|
||||
#define CORE3_TIMER_IRQCNTL (IMER_IRQCNTL_BASE + 0xc)
|
||||
#define INT_SRC_TIMER3 0x008
|
||||
|
||||
// IRQ & FIQ source registers
|
||||
#define IRQ_BASE (KBASE + 0x40000060)
|
||||
#define CORE0_IRQ (IRQ_BASE + 0x0)
|
||||
#define CORE1_IRQ (IRQ_BASE + 0x4)
|
||||
#define CORE2_IRQ (IRQ_BASE + 0x8)
|
||||
#define CORE3_IRQ (IRQ_BASE + 0xc)
|
71
lab2/kernel/common/macro.h
Normal file
71
lab2/kernel/common/macro.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define ALIGN(n) __attribute__((__aligned__(n)))
|
||||
|
||||
#define ROUND_UP(x, n) (((x) + (n) - 1) & ~((n) - 1))
|
||||
#define ROUND_DOWN(x, n) ((x) & ~((n) - 1))
|
||||
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
|
||||
|
||||
#define BUG_ON(expr) \
|
||||
do { \
|
||||
if ((expr)) { \
|
||||
printk("BUG: %s:%d %s\n", __func__, __LINE__, #expr); \
|
||||
for (;;) { \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BUG(str) \
|
||||
do { \
|
||||
printk("BUG: %s:%d %s\n", __func__, __LINE__, str); \
|
||||
for (;;) { \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define WARN(msg) \
|
||||
printk("WARN: %s:%d %s\n", __func__, __LINE__, msg)
|
||||
|
||||
#define WARN_ON(cond, msg) \
|
||||
do { \
|
||||
if ((cond)) { \
|
||||
printk("WARN: %s:%d %s on " #cond "\n", \
|
||||
__func__, __LINE__, msg); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define likely(x) (!!(x))
|
||||
#define unlikely(x) (!!(x))
|
||||
#endif // __GNUC__
|
||||
|
||||
#define BIT(x) (1UL << (x))
|
||||
|
||||
#define offsetof(TYPE, MEMBER) ((u64)&((TYPE *)0)->MEMBER)
|
||||
#define container_of(ptr, type, field) \
|
||||
((type *)((void *)(ptr) - (u64)(&(((type *)(0))->field))))
|
||||
|
||||
#define container_of_safe(ptr, type, field) ({ \
|
||||
typeof (ptr) __ptr = (ptr); \
|
||||
type *__obj = container_of(__ptr, type, field); \
|
||||
(__ptr ? __obj : NULL); \
|
||||
})
|
||||
|
||||
#define MAX(x, y) ((x) < (y) ? (y) : (x))
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0)
|
33
lab2/kernel/common/mm.h
Normal file
33
lab2/kernel/common/mm.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/vars.h>
|
||||
#include <common/types.h>
|
||||
#include <common/mmu.h>
|
||||
|
||||
#define PAGE_SIZE (0x1000)
|
||||
|
||||
void arch_mm_init(void);
|
||||
void mm_init();
|
||||
void set_page_table(paddr_t pgtbl);
|
||||
|
||||
static inline bool is_user_addr(vaddr_t vaddr)
|
||||
{
|
||||
return vaddr < KBASE;
|
||||
}
|
||||
|
||||
static inline bool is_user_addr_range(vaddr_t vaddr, size_t len)
|
||||
{
|
||||
return (vaddr + len >= vaddr) && is_user_addr(vaddr + len);
|
||||
}
|
35
lab2/kernel/common/mmu.h
Normal file
35
lab2/kernel/common/mmu.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/types.h>
|
||||
typedef u64 vmr_prop_t;
|
||||
#define VMR_READ (1 << 0)
|
||||
#define VMR_WRITE (1 << 1)
|
||||
#define VMR_EXEC (1 << 2)
|
||||
#define KERNEL_PT (1 << 3)
|
||||
/* functions */
|
||||
int map_range_in_pgtbl(vaddr_t * pgtbl, vaddr_t va, paddr_t pa,
|
||||
size_t len, vmr_prop_t flags);
|
||||
int unmap_range_in_pgtbl(vaddr_t * pgtbl, vaddr_t va, size_t len);
|
||||
|
||||
#ifndef KBASE
|
||||
#define KBASE 0xFFFFFF0000000000
|
||||
#endif
|
||||
|
||||
#ifdef CHCORE
|
||||
|
||||
#define phys_to_virt(x) ((vaddr_t)((paddr_t)(x) + KBASE))
|
||||
#define virt_to_phys(x) ((paddr_t)((vaddr_t)(x) - KBASE))
|
||||
|
||||
#endif
|
56
lab2/kernel/common/peripherals.h
Normal file
56
lab2/kernel/common/peripherals.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Sergey Matyukevich
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ChCore refers to
|
||||
* https://github.com/s-matyukevich/raspberry-pi-os/blob/master/docs/lesson01/rpi-os.md
|
||||
* for the min-uart init process.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/vars.h>
|
||||
|
||||
/* This peripheral mapped offset is specific to BCM2837 */
|
||||
#define PHYSADDR_OFFSET (KBASE + 0x3F000000UL)
|
||||
|
||||
/* BCM2835 and BCM2837 define the same offsets */
|
||||
#define GPFSEL1 (PHYSADDR_OFFSET + 0x00200004)
|
||||
#define GPSET0 (PHYSADDR_OFFSET + 0x0020001C)
|
||||
#define GPCLR0 (PHYSADDR_OFFSET + 0x00200028)
|
||||
#define GPPUD (PHYSADDR_OFFSET + 0x00200094)
|
||||
#define GPPUDCLK0 (PHYSADDR_OFFSET + 0x00200098)
|
||||
|
||||
#define AUX_ENABLES (PHYSADDR_OFFSET + 0x00215004)
|
||||
#define AUX_MU_IO_REG (PHYSADDR_OFFSET + 0x00215040)
|
||||
#define AUX_MU_IER_REG (PHYSADDR_OFFSET + 0x00215044)
|
||||
#define AUX_MU_IIR_REG (PHYSADDR_OFFSET + 0x00215048)
|
||||
#define AUX_MU_LCR_REG (PHYSADDR_OFFSET + 0x0021504C)
|
||||
#define AUX_MU_MCR_REG (PHYSADDR_OFFSET + 0x00215050)
|
||||
#define AUX_MU_LSR_REG (PHYSADDR_OFFSET + 0x00215054)
|
||||
#define AUX_MU_MSR_REG (PHYSADDR_OFFSET + 0x00215058)
|
||||
#define AUX_MU_SCRATCH (PHYSADDR_OFFSET + 0x0021505C)
|
||||
#define AUX_MU_CNTL_REG (PHYSADDR_OFFSET + 0x00215060)
|
||||
#define AUX_MU_STAT_REG (PHYSADDR_OFFSET + 0x00215064)
|
||||
#define AUX_MU_BAUD_REG (PHYSADDR_OFFSET + 0x00215068)
|
475
lab2/kernel/common/printk.c
Normal file
475
lab2/kernel/common/printk.c
Normal file
@ -0,0 +1,475 @@
|
||||
/*
|
||||
* BSD-3-Clause License
|
||||
*
|
||||
* Copyright (c) 2016, Matt Redfearn
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. 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.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder 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.
|
||||
*/
|
||||
#include <common/uart.h>
|
||||
|
||||
#define PRINT_BUF_LEN 64
|
||||
|
||||
typedef __builtin_va_list va_list;
|
||||
#define va_start(v,l) __builtin_va_start(v,l)
|
||||
#define va_end(v) __builtin_va_end(v)
|
||||
#define va_arg(v,l) __builtin_va_arg(v,l)
|
||||
#define va_copy(d,s) __builtin_va_copy(d,s)
|
||||
|
||||
static void simple_outputchar(char **str, char c)
|
||||
{
|
||||
if (str) {
|
||||
**str = c;
|
||||
++(*str);
|
||||
} else {
|
||||
uart_send(c);
|
||||
}
|
||||
}
|
||||
|
||||
enum flags {
|
||||
PAD_ZERO = 1,
|
||||
PAD_RIGHT = 2
|
||||
};
|
||||
|
||||
static int prints(char **out, const char *string, int width, int flags)
|
||||
{
|
||||
int pc = 0, padchar = ' ';
|
||||
|
||||
if (width > 0) {
|
||||
int len = 0;
|
||||
const char *ptr;
|
||||
for (ptr = string; *ptr; ++ptr)
|
||||
++len;
|
||||
if (len >= width)
|
||||
width = 0;
|
||||
else
|
||||
width -= len;
|
||||
if (flags & PAD_ZERO)
|
||||
padchar = '0';
|
||||
}
|
||||
if (!(flags & PAD_RIGHT)) {
|
||||
for (; width > 0; --width) {
|
||||
simple_outputchar(out, padchar);
|
||||
++pc;
|
||||
}
|
||||
}
|
||||
for (; *string; ++string) {
|
||||
simple_outputchar(out, *string);
|
||||
++pc;
|
||||
}
|
||||
for (; width > 0; --width) {
|
||||
simple_outputchar(out, padchar);
|
||||
++pc;
|
||||
}
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
// this function print number `i` in the base of `base` (base > 1)
|
||||
// `sign` is the flag of print signed number or unsigned number
|
||||
// `width` and `flags` mean the length of printed number at least `width`,
|
||||
// if the length of number is less than `width`, choose PAD_ZERO or PAD_RIGHT
|
||||
// `letbase` means uppercase('A') or lowercase('a') when using hex
|
||||
// you may need to call `prints`
|
||||
// you do not need to print prefix like "0x", "0"...
|
||||
// Remember the most significant digit is printed first.
|
||||
static int printk_write_num(char **out, long long i, int base, int sign,
|
||||
int width, int flags, int letbase)
|
||||
{
|
||||
char print_buf[PRINT_BUF_LEN];
|
||||
char *s;
|
||||
int t, neg = 0, pc = 0;
|
||||
unsigned long long u = i;
|
||||
|
||||
if (i == 0) {
|
||||
print_buf[0] = '0';
|
||||
print_buf[1] = '\0';
|
||||
return prints(out, print_buf, width, flags);
|
||||
}
|
||||
|
||||
if (sign && base == 10 && i < 0) {
|
||||
neg = 1;
|
||||
u = -i;
|
||||
}
|
||||
// TODO: fill your code here
|
||||
// store the digitals in the buffer `print_buf`:
|
||||
// 1. the last postion of this buffer must be '\0'
|
||||
// 2. the format is only decided by `base` and `letbase` here
|
||||
|
||||
if (neg) {
|
||||
if (width && (flags & PAD_ZERO)) {
|
||||
simple_outputchar(out, '-');
|
||||
++pc;
|
||||
--width;
|
||||
} else {
|
||||
*--s = '-';
|
||||
}
|
||||
}
|
||||
|
||||
return pc + prints(out, s, width, flags);
|
||||
}
|
||||
|
||||
static int simple_vsprintf(char **out, const char *format, va_list ap)
|
||||
{
|
||||
int width, flags;
|
||||
int pc = 0;
|
||||
char scr[2];
|
||||
union {
|
||||
char c;
|
||||
char *s;
|
||||
int i;
|
||||
unsigned int u;
|
||||
long li;
|
||||
unsigned long lu;
|
||||
long long lli;
|
||||
unsigned long long llu;
|
||||
short hi;
|
||||
unsigned short hu;
|
||||
signed char hhi;
|
||||
unsigned char hhu;
|
||||
void *p;
|
||||
} u;
|
||||
|
||||
for (; *format != 0; ++format) {
|
||||
if (*format == '%') {
|
||||
++format;
|
||||
width = flags = 0;
|
||||
if (*format == '\0')
|
||||
break;
|
||||
if (*format == '%')
|
||||
goto out;
|
||||
if (*format == '-') {
|
||||
++format;
|
||||
flags = PAD_RIGHT;
|
||||
}
|
||||
while (*format == '0') {
|
||||
++format;
|
||||
flags |= PAD_ZERO;
|
||||
}
|
||||
if (*format == '*') {
|
||||
width = va_arg(ap, int);
|
||||
format++;
|
||||
} else {
|
||||
for (; *format >= '0' && *format <= '9';
|
||||
++format) {
|
||||
width *= 10;
|
||||
width += *format - '0';
|
||||
}
|
||||
}
|
||||
switch (*format) {
|
||||
case ('d'):
|
||||
u.i = va_arg(ap, int);
|
||||
pc +=
|
||||
printk_write_num(out, u.i, 10, 1, width,
|
||||
flags, 'a');
|
||||
break;
|
||||
|
||||
case ('u'):
|
||||
u.u = va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.u, 10, 0, width,
|
||||
flags, 'a');
|
||||
break;
|
||||
|
||||
case ('o'):
|
||||
u.u = va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.u, 8, 0, width,
|
||||
flags, 'a');
|
||||
break;
|
||||
|
||||
case ('x'):
|
||||
u.u = va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.u, 16, 0, width,
|
||||
flags, 'a');
|
||||
break;
|
||||
|
||||
case ('X'):
|
||||
u.u = va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.u, 16, 0, width,
|
||||
flags, 'A');
|
||||
break;
|
||||
|
||||
case ('p'):
|
||||
u.lu = va_arg(ap, unsigned long);
|
||||
pc +=
|
||||
printk_write_num(out, u.lu, 16, 0, width,
|
||||
flags, 'a');
|
||||
break;
|
||||
|
||||
case ('c'):
|
||||
u.c = va_arg(ap, int);
|
||||
scr[0] = u.c;
|
||||
scr[1] = '\0';
|
||||
pc += prints(out, scr, width, flags);
|
||||
break;
|
||||
|
||||
case ('s'):
|
||||
u.s = va_arg(ap, char *);
|
||||
pc +=
|
||||
prints(out, u.s ? u.s : "(null)", width,
|
||||
flags);
|
||||
break;
|
||||
case ('l'):
|
||||
++format;
|
||||
switch (*format) {
|
||||
case ('d'):
|
||||
u.li = va_arg(ap, long);
|
||||
pc +=
|
||||
printk_write_num(out, u.li, 10, 1,
|
||||
width, flags, 'a');
|
||||
break;
|
||||
|
||||
case ('u'):
|
||||
u.lu = va_arg(ap, unsigned long);
|
||||
pc +=
|
||||
printk_write_num(out, u.lu, 10, 0,
|
||||
width, flags, 'a');
|
||||
break;
|
||||
|
||||
case ('o'):
|
||||
u.lu = va_arg(ap, unsigned long);
|
||||
pc +=
|
||||
printk_write_num(out, u.lu, 8, 0,
|
||||
width, flags, 'a');
|
||||
break;
|
||||
|
||||
case ('x'):
|
||||
u.lu = va_arg(ap, unsigned long);
|
||||
pc +=
|
||||
printk_write_num(out, u.lu, 16, 0,
|
||||
width, flags, 'a');
|
||||
break;
|
||||
|
||||
case ('X'):
|
||||
u.lu = va_arg(ap, unsigned long);
|
||||
pc +=
|
||||
printk_write_num(out, u.lu, 16, 0,
|
||||
width, flags, 'A');
|
||||
break;
|
||||
|
||||
case ('l'):
|
||||
++format;
|
||||
switch (*format) {
|
||||
case ('d'):
|
||||
u.lli = va_arg(ap, long long);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli,
|
||||
10, 1,
|
||||
width,
|
||||
flags,
|
||||
'a');
|
||||
break;
|
||||
|
||||
case ('u'):
|
||||
u.llu =
|
||||
va_arg(ap,
|
||||
unsigned long long);
|
||||
pc +=
|
||||
printk_write_num(out, u.llu,
|
||||
10, 0,
|
||||
width,
|
||||
flags,
|
||||
'a');
|
||||
break;
|
||||
|
||||
case ('o'):
|
||||
u.llu =
|
||||
va_arg(ap,
|
||||
unsigned long long);
|
||||
pc +=
|
||||
printk_write_num(out, u.llu,
|
||||
8, 0,
|
||||
width,
|
||||
flags,
|
||||
'a');
|
||||
break;
|
||||
|
||||
case ('x'):
|
||||
u.llu =
|
||||
va_arg(ap,
|
||||
unsigned long long);
|
||||
pc +=
|
||||
printk_write_num(out, u.llu,
|
||||
16, 0,
|
||||
width,
|
||||
flags,
|
||||
'a');
|
||||
break;
|
||||
|
||||
case ('X'):
|
||||
u.llu =
|
||||
va_arg(ap,
|
||||
unsigned long long);
|
||||
pc +=
|
||||
printk_write_num(out, u.llu,
|
||||
16, 0,
|
||||
width,
|
||||
flags,
|
||||
'A');
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ('h'):
|
||||
++format;
|
||||
switch (*format) {
|
||||
case ('d'):
|
||||
u.hi = va_arg(ap, int);
|
||||
pc +=
|
||||
printk_write_num(out, u.hi, 10, 1,
|
||||
width, flags, 'a');
|
||||
break;
|
||||
|
||||
case ('u'):
|
||||
u.hu = va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli, 10, 0,
|
||||
width, flags, 'a');
|
||||
break;
|
||||
|
||||
case ('o'):
|
||||
u.hu = va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli, 8, 0,
|
||||
width, flags, 'a');
|
||||
break;
|
||||
|
||||
case ('x'):
|
||||
u.hu = va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli, 16, 0,
|
||||
width, flags, 'a');
|
||||
break;
|
||||
|
||||
case ('X'):
|
||||
u.hu = va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli, 16, 0,
|
||||
width, flags, 'A');
|
||||
break;
|
||||
|
||||
case ('h'):
|
||||
++format;
|
||||
switch (*format) {
|
||||
case ('d'):
|
||||
u.hhi = va_arg(ap, int);
|
||||
pc +=
|
||||
printk_write_num(out, u.hhi,
|
||||
10, 1,
|
||||
width,
|
||||
flags,
|
||||
'a');
|
||||
break;
|
||||
|
||||
case ('u'):
|
||||
u.hhu =
|
||||
va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli,
|
||||
10, 0,
|
||||
width,
|
||||
flags,
|
||||
'a');
|
||||
break;
|
||||
|
||||
case ('o'):
|
||||
u.hhu =
|
||||
va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli,
|
||||
8, 0,
|
||||
width,
|
||||
flags,
|
||||
'a');
|
||||
break;
|
||||
|
||||
case ('x'):
|
||||
u.hhu =
|
||||
va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli,
|
||||
16, 0,
|
||||
width,
|
||||
flags,
|
||||
'a');
|
||||
break;
|
||||
|
||||
case ('X'):
|
||||
u.hhu =
|
||||
va_arg(ap, unsigned int);
|
||||
pc +=
|
||||
printk_write_num(out, u.lli,
|
||||
16, 0,
|
||||
width,
|
||||
flags,
|
||||
'A');
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
out:
|
||||
simple_outputchar(out, *format);
|
||||
++pc;
|
||||
}
|
||||
}
|
||||
if (out)
|
||||
**out = '\0';
|
||||
return pc;
|
||||
}
|
||||
|
||||
void printk(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
simple_vsprintf(NULL, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void break_point()
|
||||
{
|
||||
printk("[ChCore] Lab stalling ... \n");
|
||||
}
|
16
lab2/kernel/common/printk.h
Normal file
16
lab2/kernel/common/printk.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
void printk(const char *fmt, ...);
|
||||
void break_point();
|
117
lab2/kernel/common/registers.h
Normal file
117
lab2/kernel/common/registers.h
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/macro.h>
|
||||
|
||||
/* ARMv8 AA64 REGISTERS */
|
||||
|
||||
/* SPSR_EL1 Register aarch64 (FROM ARM-ARM C5-395) */
|
||||
/* Holds the saved process state when an exception is taken to EL1 */
|
||||
#define SPSR_EL1_N BIT(31) /* N condition flag */
|
||||
#define SPSR_EL1_Z BIT(30) /* Z condition flag */
|
||||
#define SPSR_EL1_C BIT(29) /* C condition flag */
|
||||
#define SPSR_EL1_V BIT(28) /* V condition flag */
|
||||
#define SPSR_EL1_DIT BIT(24) /* Data Independent Timing PSTATE.DIT ARMv8.4 */
|
||||
#define SPSR_EL1_UAO BIT(23) /* User Access Override PSTATE.UAO ARMv8.2 */
|
||||
#define SPSR_EL1_PAN BIT(22) /* Privileged Access Never PSTATE.PAN ARMv8.1 */
|
||||
#define SPSR_EL1_SS BIT(21) /* Software Step PSTATE.SS */
|
||||
#define SPSR_EL1_IL BIT(20) /* Illegal Execution state PSTATE.IL */
|
||||
#define SPSR_EL1_DEBUG BIT(9) /* Debug mask */
|
||||
#define SPSR_EL1_SERROR BIT(8) /* SERROR mask */
|
||||
#define SPSR_EL1_IRQ BIT(7) /* IRQ mask */
|
||||
#define SPSR_EL1_FIQ BIT(6) /* FIQ mask */
|
||||
#define SPSR_EL1_M BIT(4) /* Exception taken from AArch64 */
|
||||
#define SPSR_EL1_EL0t 0b0000
|
||||
#define SPSR_EL1_EL1t 0b0100
|
||||
#define SPSR_EL1_EL1h 0b0101
|
||||
|
||||
/* SPSR_EL1 DEFAULT */
|
||||
#define SPSR_EL1_KERNEL SPSR_EL1_EL1h
|
||||
#define SPSR_EL1_USER SPSR_EL1_EL0t
|
||||
|
||||
/* SCTLR_EL1 System Control Register aarch64 (FROM ARM-ARM D12-3081) */
|
||||
|
||||
#define SCTLR_EL1_EnIA BIT(31) /* Controls enabling of pointer authentication */
|
||||
#define SCTLR_EL1_EnIB BIT(30) /* Controls enabling of pointer authentication */
|
||||
#define SCTLR_EL1_LSMAOE BIT(29) /* Load Multiple and Store Multiple Atomicity and Ordering Enable */
|
||||
#define SCTLR_EL1_nTLSMD BIT(28) /* No Trap Load Multiple and Store Multiple to Device-nGRE/Device-nGnRE/Device-nGnRnE memory */
|
||||
#define SCTLR_EL1_EnDA BIT(27) /* Controls enabling of pointer authentication */
|
||||
#define SCTLR_EL1_UCI BIT(26) /* Traps EL0 execution of cache maintenance instructions to EL1, from AArch64 state only */
|
||||
#define SCTLR_EL1_EE BIT(25) /* Endianness of data accesses at EL1, and stage 1 translation table walks in the EL1&0 translation regime */
|
||||
#define SCTLR_EL1_E0E BIT(24) /* Endianness of data accesses at EL0 */
|
||||
#define SCTLR_EL1_SPAN BIT(23) /* Set Privileged Access Never, on taking an exception to EL1 */
|
||||
#define SCTLR_EL1_IESB BIT(21) /* Implicit error synchronization event enable */
|
||||
#define SCTLR_EL1_WXN BIT(19) /* Write permission implies XN (Execute-never) */
|
||||
#define SCTLR_EL1_nTWE BIT(18) /* Traps EL0 execution of WFE instructions to EL1, from both Execution states */
|
||||
#define SCTLR_EL1_nTWI BIT(16) /* Traps EL0 execution of WFI instructions to EL1, from both Execution states */
|
||||
#define SCTLR_EL1_UCT BIT(15) /* Traps EL0 accesses to the CTR_EL0 to EL1, from AArch64 state only */
|
||||
#define SCTLR_EL1_DZE BIT(14) /* Traps EL0 execution of DC ZVA instructions to EL1, from AArch64 state only */
|
||||
#define SCTLR_EL1_EnDB BIT(13) /* Controls enabling of pointer authentication */
|
||||
#define SCTLR_EL1_I BIT(12) /* Instruction access Cacheability control, for accesses at EL0 and EL1 */
|
||||
#define SCTLR_EL1_UMA BIT(9) /* User Mask Access: Traps EL0 execution of MSR and MRS instructions that access the PSTATE.{D, A, I, F} */
|
||||
#define SCTLR_EL1_SED BIT(8) /* SETEND instruction disable. Disables SETEND instructions at EL0 using AArch32 */
|
||||
#define SCTLR_EL1_ITD BIT(7) /* IT Disable. Disables some uses of IT instructions at EL0 using AArch32 */
|
||||
#define SCTLR_EL1_nAA BIT(6) /* Non-aligned access. This bit controls generation of Alignment faults at EL1 and EL0 under certain conditions */
|
||||
#define SCTLR_EL1_CP15BEN BIT(5) /* System instruction memory barrier enable (AArch32) */
|
||||
#define SCTLR_EL1_SA0 BIT(4) /* SP Alignment check enable for EL0 */
|
||||
#define SCTLR_EL1_SA BIT(3) /* SP Alignment check */
|
||||
#define SCTLR_EL1_C BIT(2) /* Cacheability control for data accesses */
|
||||
#define SCTLR_EL1_A BIT(1) /* Alignment check enable */
|
||||
#define SCTLR_EL1_M BIT(0) /* MMU enable for EL1 and EL0 stage 1 address translation */
|
||||
|
||||
#ifndef __ASM__
|
||||
/* Types of the registers */
|
||||
enum reg_type {
|
||||
X0 = 0, /* 0x00 */
|
||||
X1 = 1, /* 0x08 */
|
||||
X2 = 2, /* 0x10 */
|
||||
X3 = 3, /* 0x18 */
|
||||
X4 = 4, /* 0x20 */
|
||||
X5 = 5, /* 0x28 */
|
||||
X6 = 6, /* 0x30 */
|
||||
X7 = 7, /* 0x38 */
|
||||
X8 = 8, /* 0x40 */
|
||||
X9 = 9, /* 0x48 */
|
||||
X10 = 10, /* 0x50 */
|
||||
X11 = 11, /* 0x58 */
|
||||
X12 = 12, /* 0x60 */
|
||||
X13 = 13, /* 0x68 */
|
||||
X14 = 14, /* 0x70 */
|
||||
X15 = 15, /* 0x78 */
|
||||
X16 = 16, /* 0x80 */
|
||||
X17 = 17, /* 0x88 */
|
||||
X18 = 18, /* 0x90 */
|
||||
X19 = 19, /* 0x98 */
|
||||
X20 = 20, /* 0xa0 */
|
||||
X21 = 21, /* 0xa8 */
|
||||
X22 = 22, /* 0xb0 */
|
||||
X23 = 23, /* 0xb8 */
|
||||
X24 = 24, /* 0xc0 */
|
||||
X25 = 25, /* 0xc8 */
|
||||
X26 = 26, /* 0xd0 */
|
||||
X27 = 27, /* 0xd8 */
|
||||
X28 = 28, /* 0xe0 */
|
||||
X29 = 29, /* 0xe8 */
|
||||
X30 = 30, /* 0xf0 */
|
||||
SP_EL0 = 31, /* 0xf8 */
|
||||
ELR_EL1 = 32, /* 0x100 NEXT PC */
|
||||
SPSR_EL1 = 33, /* 0x108 */
|
||||
TPIDR_EL0 = 34
|
||||
};
|
||||
#endif /* ASMCODE */
|
||||
|
||||
#define REG_NUM 35
|
||||
|
||||
#define SZ_U64 8
|
||||
#define ARCH_EXEC_CONT_SIZE REG_NUM*SZ_U64 /* Cannot use sizeof in asm */
|
33
lab2/kernel/common/tools.S
Normal file
33
lab2/kernel/common/tools.S
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#include <common/asm.h>
|
||||
|
||||
BEGIN_FUNC(put32)
|
||||
str w1,[x0]
|
||||
ret
|
||||
END_FUNC(put32)
|
||||
|
||||
BEGIN_FUNC(get32)
|
||||
ldr w0,[x0]
|
||||
ret
|
||||
END_FUNC(put32)
|
||||
|
||||
BEGIN_FUNC(put64)
|
||||
str x1,[x0]
|
||||
ret
|
||||
END_FUNC(put32)
|
||||
|
||||
BEGIN_FUNC(get64)
|
||||
ldr x0,[x0]
|
||||
ret
|
||||
END_FUNC(put32)
|
17
lab2/kernel/common/tools.h
Normal file
17
lab2/kernel/common/tools.h
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern void put32(u64 addr, u32 data);
|
||||
extern unsigned int get32(u64 addr);
|
||||
extern void delay(u32 time);
|
162
lab2/kernel/common/types.h
Normal file
162
lab2/kernel/common/types.h
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/macro.h>
|
||||
|
||||
typedef unsigned long long u64;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned char u8;
|
||||
typedef long long s64;
|
||||
#ifdef CHCORE
|
||||
typedef int s32;
|
||||
typedef short s16;
|
||||
typedef signed char s8;
|
||||
|
||||
/* According to `https://pubs.opengroup.org/onlinepubs/9699919799/`. */
|
||||
|
||||
/* Used for file block counts. */
|
||||
typedef s64 blkcnt_t;
|
||||
|
||||
/* Used for block sizes. */
|
||||
typedef s64 blksize_t;
|
||||
|
||||
/* Used for system times in clock ticks or CLOCKS_PER_SEC; see <time.h>. */
|
||||
typedef u64 clock_t;
|
||||
|
||||
/* Used for clock ID type in the clock and timer functions.*/
|
||||
typedef u64 clockid_t;
|
||||
|
||||
/* Used for device IDs. */
|
||||
typedef u64 dev_t;
|
||||
|
||||
/* Used for file system block counts. */
|
||||
typedef u64 fsblkcnt_t;
|
||||
|
||||
/* Used for file system file counts. */
|
||||
typedef u64 fsfilcnt_t;
|
||||
|
||||
/* Used for group IDs. */
|
||||
typedef u64 gid_t;
|
||||
|
||||
/*
|
||||
* Used as a general identifier; can be used to contain at least a pid_t,
|
||||
* uid_t, or gid_t.
|
||||
*/
|
||||
typedef u64 id_t;
|
||||
|
||||
/* Used for file serial numbers. */
|
||||
typedef u64 ino_t;
|
||||
|
||||
/* Used for XSI interprocess communication. */
|
||||
typedef u64 key_t;
|
||||
|
||||
/* Used for some file attributes. */
|
||||
typedef u64 mode_t;
|
||||
|
||||
/* Used for link counts. */
|
||||
typedef u64 nlink_t;
|
||||
|
||||
/* Used for file sizes. */
|
||||
typedef s64 off_t;
|
||||
|
||||
/* Used for process IDs and process group IDs. */
|
||||
typedef s64 pid_t;
|
||||
|
||||
/* Used to identify a thread attribute object. */
|
||||
typedef u64 pthread_attr_t;
|
||||
|
||||
/* Used to identify a barrier. */
|
||||
typedef u64 pthread_barrier_t;
|
||||
|
||||
/* Used to define a barrier attributes object. */
|
||||
typedef u64 pthread_barrierattr_t;
|
||||
|
||||
/* Used for condition variables. */
|
||||
typedef u64 pthread_cond_t;
|
||||
|
||||
/* Used to identify a condition attribute object. */
|
||||
typedef u64 pthread_condattr_t;
|
||||
|
||||
/* Used for thread-specific data keys. */
|
||||
typedef u64 pthread_key_t;
|
||||
|
||||
/* Used for mutexes. */
|
||||
typedef u64 pthread_mutex_t;
|
||||
|
||||
/* Used to identify a mutex attribute object. */
|
||||
typedef u64 pthread_mutexattr_t;
|
||||
|
||||
/* Used for dynamic package initialization. */
|
||||
typedef u64 pthread_once_t;
|
||||
|
||||
/* Used for read-write locks. */
|
||||
typedef u64 pthread_rwlock_t;
|
||||
|
||||
/* Used for read-write lock attributes. */
|
||||
typedef u64 pthread_rwlockattr_t;
|
||||
|
||||
/* Used to identify a spin lock. */
|
||||
typedef u64 pthread_spinlock_t;
|
||||
|
||||
/* Used to identify a thread. */
|
||||
typedef u64 pthread_t;
|
||||
|
||||
/* Used for sizes of objects. */
|
||||
typedef u64 size_t;
|
||||
|
||||
/* Used for a count of bytes or an error indication. */
|
||||
typedef s64 ssize_t;
|
||||
|
||||
/* Used for time in microseconds. */
|
||||
typedef s64 suseconds_t;
|
||||
|
||||
/* Used for time in seconds. */
|
||||
typedef u64 time_t;
|
||||
|
||||
/* Used for timer ID returned by timer_create(). */
|
||||
typedef u64 timer_t;
|
||||
|
||||
/* Used to identify a trace stream attributes object. */
|
||||
typedef u64 trace_attr_t;
|
||||
|
||||
/* Used to identify a trace event type. */
|
||||
typedef u64 trace_event_id_t;
|
||||
|
||||
/* Used to identify a trace event type set. */
|
||||
typedef u64 trace_event_set_t;
|
||||
|
||||
/* Used to identify a trace stream. */
|
||||
typedef u64 trace_id_t;
|
||||
|
||||
/* Used for user IDs. */
|
||||
typedef u64 uid_t;
|
||||
|
||||
#define NULL ((void *)0)
|
||||
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
typedef char bool;
|
||||
#define true (1)
|
||||
#define false (0)
|
||||
typedef u64 paddr_t;
|
||||
typedef u64 vaddr_t;
|
||||
|
||||
typedef u64 atomic_cnt;
|
||||
|
||||
/* Different platform may have different cacheline size and may have some features like prefetch */
|
||||
#define CACHELINE_SZ 64
|
||||
#define pad_to_cache_line(n) (ROUND_UP(n, CACHELINE_SZ) - (n))
|
18
lab2/kernel/common/uaccess.h
Normal file
18
lab2/kernel/common/uaccess.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/types.h>
|
||||
|
||||
int copy_from_user(char *kbuf, char *ubuf, size_t size);
|
||||
int copy_to_user(char *ubuf, char *kbuf, size_t size);
|
101
lab2/kernel/common/uart.c
Normal file
101
lab2/kernel/common/uart.c
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Sergey Matyukevich
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ChCore refers to
|
||||
* https://github.com/s-matyukevich/raspberry-pi-os/blob/master/docs/lesson01/rpi-os.md
|
||||
* for the min-uart init process.
|
||||
*/
|
||||
#include <common/machine.h>
|
||||
#include <common/types.h>
|
||||
#include <common/tools.h>
|
||||
#include <common/uart.h>
|
||||
#include <common/peripherals.h>
|
||||
|
||||
void uart_init(void)
|
||||
{
|
||||
unsigned int ra;
|
||||
|
||||
ra = get32(GPFSEL1);
|
||||
ra &= ~(7 << 12);
|
||||
ra |= 2 << 12;
|
||||
ra &= ~(7 << 15);
|
||||
ra |= 2 << 15;
|
||||
put32(GPFSEL1, ra);
|
||||
|
||||
put32(GPPUD, 0);
|
||||
// delay(150);
|
||||
put32(GPPUDCLK0, (1 << 14) | (1 << 15));
|
||||
// delay(150);
|
||||
put32(GPPUDCLK0, 0);
|
||||
|
||||
put32(AUX_ENABLES, 1);
|
||||
put32(AUX_MU_IER_REG, 0);
|
||||
put32(AUX_MU_CNTL_REG, 0);
|
||||
put32(AUX_MU_IER_REG, 0);
|
||||
put32(AUX_MU_LCR_REG, 3);
|
||||
put32(AUX_MU_MCR_REG, 0);
|
||||
put32(AUX_MU_BAUD_REG, 270);
|
||||
|
||||
put32(AUX_MU_CNTL_REG, 3);
|
||||
|
||||
/* Clear the screen */
|
||||
uart_send(12);
|
||||
uart_send(27);
|
||||
uart_send('[');
|
||||
uart_send('2');
|
||||
uart_send('J');
|
||||
}
|
||||
|
||||
u32 uart_lsr(void)
|
||||
{
|
||||
return get32(AUX_MU_LSR_REG);
|
||||
}
|
||||
|
||||
u32 uart_recv(void)
|
||||
{
|
||||
while (1) {
|
||||
if (uart_lsr() & 0x01)
|
||||
break;
|
||||
}
|
||||
|
||||
return (get32(AUX_MU_IO_REG) & 0xFF);
|
||||
}
|
||||
|
||||
u32 nb_uart_recv(void)
|
||||
{
|
||||
if (uart_lsr() & 0x01)
|
||||
return (get32(AUX_MU_IO_REG) & 0xFF);
|
||||
else
|
||||
return NB_UART_NRET;
|
||||
}
|
||||
|
||||
void uart_send(u32 c)
|
||||
{
|
||||
while (1) {
|
||||
if (uart_lsr() & 0x20)
|
||||
break;
|
||||
}
|
||||
put32(AUX_MU_IO_REG, c);
|
||||
}
|
41
lab2/kernel/common/uart.h
Normal file
41
lab2/kernel/common/uart.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Sergey Matyukevich
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ChCore refers to
|
||||
* https://github.com/s-matyukevich/raspberry-pi-os/blob/master/docs/lesson01/rpi-os.md
|
||||
* for the min-uart init process.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/types.h>
|
||||
|
||||
void uart_init(void);
|
||||
u32 uart_recv(void);
|
||||
void uart_send(u32 c);
|
||||
|
||||
#define NB_UART_NRET 0xffffff
|
||||
/* Non-blocking receive */
|
||||
u32 nb_uart_recv(void);
|
82
lab2/kernel/common/util.h
Normal file
82
lab2/kernel/common/util.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/types.h>
|
||||
|
||||
#ifdef CHCORE
|
||||
/*
|
||||
* memcpy does not handle: dst and src overlap.
|
||||
* memmove does.
|
||||
*/
|
||||
|
||||
static inline void memset(void *dst, char ch, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
char *dst_ch = dst;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
dst_ch[i] = ch;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void memcpy(void *dst, const void *src, size_t size)
|
||||
{
|
||||
s64 i;
|
||||
char *dst_ch = dst;
|
||||
const char *src_ch = src;
|
||||
|
||||
for (i = size - 1; i >= 0; --i) {
|
||||
dst_ch[i] = src_ch[i];
|
||||
}
|
||||
}
|
||||
|
||||
static inline int strcmp(const char *src, const char *dst)
|
||||
{
|
||||
while (*src && *dst) {
|
||||
if (*src == *dst) {
|
||||
src++;
|
||||
dst++;
|
||||
continue;
|
||||
}
|
||||
return *src - *dst;
|
||||
}
|
||||
if (!*src && !*dst)
|
||||
return 0;
|
||||
if (!*src)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int strncmp(const char *src, const char *dst, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
if (src[i] == '\0' || src[i] != dst[i])
|
||||
return src[i] - dst[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline size_t strlen(const char *src)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
while (*src++)
|
||||
i++;
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
23
lab2/kernel/common/vars.h
Normal file
23
lab2/kernel/common/vars.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Leave 8K space to kernel stack */
|
||||
#define KERNEL_STACK_SIZE (8192)
|
||||
#define IDLE_STACK_SIZE (8192)
|
||||
#define STACK_ALIGNMENT 16
|
||||
|
||||
/* can be different in different architectures */
|
||||
#ifndef KBASE
|
||||
#define KBASE 0xffffff0000000000
|
||||
#endif
|
30
lab2/kernel/head.S
Normal file
30
lab2/kernel/head.S
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#include <common/asm.h>
|
||||
#include <common/vars.h>
|
||||
|
||||
BEGIN_FUNC(start_kernel)
|
||||
/*
|
||||
* Code in bootloader specified only the primary
|
||||
* cpu with MPIDR = 0 can be boot here. So we directly
|
||||
* set the TPIDR_EL1 to 0, which represent the logical
|
||||
* cpuid in the kernel
|
||||
*/
|
||||
mov x3, #0
|
||||
msr TPIDR_EL1, x3
|
||||
|
||||
ldr x2, =kernel_stack
|
||||
add x2, x2, KERNEL_STACK_SIZE
|
||||
mov sp, x2
|
||||
bl main
|
||||
END_FUNC(start_kernel)
|
55
lab2/kernel/main.c
Normal file
55
lab2/kernel/main.c
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#include <common/kprint.h>
|
||||
#include <common/macro.h>
|
||||
#include <common/uart.h>
|
||||
#include <common/machine.h>
|
||||
#include <common/mm.h>
|
||||
|
||||
ALIGN(STACK_ALIGNMENT)
|
||||
char kernel_stack[PLAT_CPU_NUM][KERNEL_STACK_SIZE];
|
||||
|
||||
int stack_backtrace();
|
||||
|
||||
// Test the stack backtrace function (lab 1 only)
|
||||
__attribute__ ((optimize("O1")))
|
||||
void stack_test(long x)
|
||||
{
|
||||
kinfo("entering stack_test %d\n", x);
|
||||
if (x > 0)
|
||||
stack_test(x - 1);
|
||||
else
|
||||
stack_backtrace();
|
||||
kinfo("leaving stack_test %d\n", x);
|
||||
}
|
||||
|
||||
void main(void *addr)
|
||||
{
|
||||
/* Init uart */
|
||||
uart_init();
|
||||
kinfo("[ChCore] uart init finished\n");
|
||||
|
||||
kinfo("Address of main() is 0x%lx\n", main);
|
||||
kinfo("123456 decimal is 0%o octal\n", 123456);
|
||||
|
||||
stack_test(5);
|
||||
|
||||
mm_init();
|
||||
kinfo("mm init finished\n");
|
||||
|
||||
break_point();
|
||||
return;
|
||||
|
||||
/* Should provide panic and use here */
|
||||
BUG("[FATAL] Should never be here!\n");
|
||||
}
|
13
lab2/kernel/mm/CMakeLists.txt
Normal file
13
lab2/kernel/mm/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
file(GLOB OBJECT_SOURCE "*.c")
|
||||
add_library(${PROJECT_NAME}-mm OBJECT ${OBJECT_SOURCE})
|
||||
target_include_directories(
|
||||
${PROJECT_NAME}-mm
|
||||
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||
)
|
||||
|
||||
#for testing
|
||||
#add_library(${PROJECT_NAME}-mm OBJECT mm.c vmregion.c buddy.c kmalloc.c slab.c
|
||||
#../../tests/mm/mm-slab/test_slab.c ../../tests/mm/mm-buddy/test_buddy.c
|
||||
#../../tests/mm/mm-pagetable/test_pagetable.c)
|
184
lab2/kernel/mm/buddy.c
Normal file
184
lab2/kernel/mm/buddy.c
Normal file
@ -0,0 +1,184 @@
|
||||
#include <common/util.h>
|
||||
#include <common/macro.h>
|
||||
#include <common/kprint.h>
|
||||
|
||||
#include "buddy.h"
|
||||
|
||||
/*
|
||||
* The layout of a phys_mem_pool:
|
||||
* | page_metadata are (an array of struct page) | alignment pad | usable memory |
|
||||
*
|
||||
* The usable memory: [pool_start_addr, pool_start_addr + pool_mem_size).
|
||||
*/
|
||||
void init_buddy(struct phys_mem_pool *pool, struct page *start_page,
|
||||
vaddr_t start_addr, u64 page_num)
|
||||
{
|
||||
int order;
|
||||
int page_idx;
|
||||
struct page *page;
|
||||
|
||||
/* Init the physical memory pool. */
|
||||
pool->pool_start_addr = start_addr;
|
||||
pool->page_metadata = start_page;
|
||||
pool->pool_mem_size = page_num * BUDDY_PAGE_SIZE;
|
||||
/* This field is for unit test only. */
|
||||
pool->pool_phys_page_num = page_num;
|
||||
|
||||
/* Init the free lists */
|
||||
for (order = 0; order < BUDDY_MAX_ORDER; ++order) {
|
||||
pool->free_lists[order].nr_free = 0;
|
||||
init_list_head(&(pool->free_lists[order].free_list));
|
||||
}
|
||||
|
||||
/* Clear the page_metadata area. */
|
||||
memset((char *)start_page, 0, page_num * sizeof(struct page));
|
||||
|
||||
/* Init the page_metadata area. */
|
||||
for (page_idx = 0; page_idx < page_num; ++page_idx) {
|
||||
page = start_page + page_idx;
|
||||
page->allocated = 1;
|
||||
page->order = 0;
|
||||
}
|
||||
|
||||
/* Put each physical memory page into the free lists. */
|
||||
for (page_idx = 0; page_idx < page_num; ++page_idx) {
|
||||
page = start_page + page_idx;
|
||||
buddy_free_pages(pool, page);
|
||||
}
|
||||
}
|
||||
|
||||
static struct page *get_buddy_chunk(struct phys_mem_pool *pool,
|
||||
struct page *chunk)
|
||||
{
|
||||
u64 chunk_addr;
|
||||
u64 buddy_chunk_addr;
|
||||
int order;
|
||||
|
||||
/* Get the address of the chunk. */
|
||||
chunk_addr = (u64) page_to_virt(pool, chunk);
|
||||
order = chunk->order;
|
||||
/*
|
||||
* Calculate the address of the buddy chunk according to the address
|
||||
* relationship between buddies.
|
||||
*/
|
||||
#define BUDDY_PAGE_SIZE_ORDER (12)
|
||||
buddy_chunk_addr = chunk_addr ^
|
||||
(1UL << (order + BUDDY_PAGE_SIZE_ORDER));
|
||||
|
||||
/* Check whether the buddy_chunk_addr belongs to pool. */
|
||||
if ((buddy_chunk_addr < pool->pool_start_addr) ||
|
||||
(buddy_chunk_addr >= (pool->pool_start_addr +
|
||||
pool->pool_mem_size))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return virt_to_page(pool, (void *)buddy_chunk_addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* split_page: split the memory block into two smaller sub-block, whose order
|
||||
* is half of the origin page.
|
||||
* pool @ physical memory structure reserved in the kernel
|
||||
* order @ order for origin page block
|
||||
* page @ splitted page
|
||||
*
|
||||
* Hints: don't forget to substract the free page number for the corresponding free_list.
|
||||
* you can invoke split_page recursively until the given page can not be splitted into two
|
||||
* smaller sub-pages.
|
||||
*/
|
||||
static struct page *split_page(struct phys_mem_pool *pool, u64 order,
|
||||
struct page *page)
|
||||
{
|
||||
// <lab2>
|
||||
struct page *split_page = NULL;
|
||||
return split_page;
|
||||
// </lab2>
|
||||
}
|
||||
|
||||
/*
|
||||
* buddy_get_pages: get free page from buddy system.
|
||||
* pool @ physical memory structure reserved in the kernel
|
||||
* order @ get the (1<<order) continous pages from the buddy system
|
||||
*
|
||||
* Hints: Find the corresonding free_list which can allocate 1<<order
|
||||
* continuous pages and don't forget to split the list node after allocation
|
||||
*/
|
||||
struct page *buddy_get_pages(struct phys_mem_pool *pool, u64 order)
|
||||
{
|
||||
// <lab2>
|
||||
struct page *page = NULL;
|
||||
|
||||
return page;
|
||||
// </lab2>
|
||||
}
|
||||
|
||||
/*
|
||||
* merge_page: merge the given page with the buddy page
|
||||
* pool @ physical memory structure reserved in the kernel
|
||||
* page @ merged page (attempted)
|
||||
*
|
||||
* Hints: you can invoke the merge_page recursively until
|
||||
* there is not corresponding buddy page. get_buddy_chunk
|
||||
* is helpful in this function.
|
||||
*/
|
||||
static struct page *merge_page(struct phys_mem_pool *pool, struct page *page)
|
||||
{
|
||||
// <lab2>
|
||||
|
||||
struct page *merge_page = NULL;
|
||||
return merge_page;
|
||||
// </lab2>
|
||||
}
|
||||
|
||||
/*
|
||||
* buddy_free_pages: give back the pages to buddy system
|
||||
* pool @ physical memory structure reserved in the kernel
|
||||
* page @ free page structure
|
||||
*
|
||||
* Hints: you can invoke merge_page.
|
||||
*/
|
||||
void buddy_free_pages(struct phys_mem_pool *pool, struct page *page)
|
||||
{
|
||||
// <lab2>
|
||||
|
||||
// </lab2>
|
||||
}
|
||||
|
||||
void *page_to_virt(struct phys_mem_pool *pool, struct page *page)
|
||||
{
|
||||
u64 addr;
|
||||
|
||||
/* page_idx * BUDDY_PAGE_SIZE + start_addr */
|
||||
addr = (page - pool->page_metadata) * BUDDY_PAGE_SIZE +
|
||||
pool->pool_start_addr;
|
||||
return (void *)addr;
|
||||
}
|
||||
|
||||
struct page *virt_to_page(struct phys_mem_pool *pool, void *addr)
|
||||
{
|
||||
struct page *page;
|
||||
|
||||
page = pool->page_metadata +
|
||||
(((u64) addr - pool->pool_start_addr) / BUDDY_PAGE_SIZE);
|
||||
return page;
|
||||
}
|
||||
|
||||
u64 get_free_mem_size_from_buddy(struct phys_mem_pool * pool)
|
||||
{
|
||||
int order;
|
||||
struct free_list *list;
|
||||
u64 current_order_size;
|
||||
u64 total_size = 0;
|
||||
|
||||
for (order = 0; order < BUDDY_MAX_ORDER; order++) {
|
||||
/* 2^order * 4K */
|
||||
current_order_size = BUDDY_PAGE_SIZE * (1 << order);
|
||||
list = pool->free_lists + order;
|
||||
total_size += list->nr_free * current_order_size;
|
||||
|
||||
/* debug : print info about current order */
|
||||
kdebug("buddy memory chunk order: %d, size: 0x%lx, num: %d\n",
|
||||
order, current_order_size, list->nr_free);
|
||||
}
|
||||
return total_size;
|
||||
}
|
67
lab2/kernel/mm/buddy.h
Normal file
67
lab2/kernel/mm/buddy.h
Normal file
@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/types.h>
|
||||
#include <common/list.h>
|
||||
|
||||
/*
|
||||
* Supported Order: [0, BUDDY_MAX_ORDER).
|
||||
* The max allocated size (continous physical memory size) is
|
||||
* 2^(BUDDY_MAX_ORDER - 1) * 4K, i.e., 16M.
|
||||
*/
|
||||
#define BUDDY_PAGE_SIZE (0x1000)
|
||||
#define BUDDY_MAX_ORDER (14UL)
|
||||
|
||||
/* `struct page` is the metadata of one physical 4k page. */
|
||||
struct page {
|
||||
/* Free list */
|
||||
struct list_head node;
|
||||
/* Whether the correspond physical page is free now. */
|
||||
int allocated;
|
||||
/* The order of the memory chunck that this page belongs to. */
|
||||
int order;
|
||||
/* Used for ChCore slab allocator. */
|
||||
void *slab;
|
||||
};
|
||||
|
||||
struct free_list {
|
||||
struct list_head free_list;
|
||||
u64 nr_free;
|
||||
};
|
||||
|
||||
/* Disjoint physical memory can be represented by several phys_mem_pool. */
|
||||
struct phys_mem_pool {
|
||||
/*
|
||||
* The start virtual address (for used in kernel) of
|
||||
* this physical memory pool.
|
||||
*/
|
||||
u64 pool_start_addr;
|
||||
u64 pool_mem_size;
|
||||
|
||||
/*
|
||||
* This field is only used in ChCore unit test.
|
||||
* The number of (4k) physical pages in this physical memory pool.
|
||||
*/
|
||||
u64 pool_phys_page_num;
|
||||
|
||||
/*
|
||||
* The start virtual address (for used in kernel) of
|
||||
* the metadata area of this pool.
|
||||
*/
|
||||
struct page *page_metadata;
|
||||
|
||||
/* The free list of different free-memory-chunk orders. */
|
||||
struct free_list free_lists[BUDDY_MAX_ORDER];
|
||||
};
|
||||
|
||||
/* Currently, ChCore only uses one physical memory pool. */
|
||||
extern struct phys_mem_pool global_mem;
|
||||
|
||||
void init_buddy(struct phys_mem_pool *zone, struct page *start_page,
|
||||
vaddr_t start_addr, u64 page_num);
|
||||
|
||||
struct page *buddy_get_pages(struct phys_mem_pool *, u64 order);
|
||||
void buddy_free_pages(struct phys_mem_pool *, struct page *page);
|
||||
|
||||
void *page_to_virt(struct phys_mem_pool *, struct page *page);
|
||||
struct page *virt_to_page(struct phys_mem_pool *, void *ptr);
|
||||
u64 get_free_mem_size_from_buddy(struct phys_mem_pool *);
|
100
lab2/kernel/mm/kmalloc.c
Normal file
100
lab2/kernel/mm/kmalloc.c
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#include <common/types.h>
|
||||
#include <common/macro.h>
|
||||
#include <common/util.h>
|
||||
#include <common/errno.h>
|
||||
|
||||
#include "slab.h"
|
||||
#include "buddy.h"
|
||||
|
||||
#define _SIZE (1UL << SLAB_MAX_ORDER)
|
||||
|
||||
u64 size_to_page_order(u64 size)
|
||||
{
|
||||
u64 order;
|
||||
u64 pg_num;
|
||||
u64 tmp;
|
||||
|
||||
order = 0;
|
||||
pg_num = ROUND_UP(size, BUDDY_PAGE_SIZE) / BUDDY_PAGE_SIZE;
|
||||
tmp = pg_num;
|
||||
|
||||
while (tmp > 1) {
|
||||
tmp >>= 1;
|
||||
order += 1;
|
||||
}
|
||||
|
||||
if (pg_num > (1 << order))
|
||||
order += 1;
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
void *kmalloc(size_t size)
|
||||
{
|
||||
u64 order;
|
||||
struct page *p_page;
|
||||
|
||||
if (size <= _SIZE) {
|
||||
return alloc_in_slab(size);
|
||||
}
|
||||
|
||||
if (size <= BUDDY_PAGE_SIZE)
|
||||
order = 0;
|
||||
else
|
||||
order = size_to_page_order(size);
|
||||
|
||||
p_page = buddy_get_pages(&global_mem, order);
|
||||
return page_to_virt(&global_mem, p_page);
|
||||
}
|
||||
|
||||
void *kzalloc(size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = kmalloc(size);
|
||||
|
||||
/* lack of memory */
|
||||
if (ptr == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(ptr, 0, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void kfree(void *ptr)
|
||||
{
|
||||
struct page *p_page;
|
||||
|
||||
p_page = virt_to_page(&global_mem, ptr);
|
||||
if (p_page && p_page->slab)
|
||||
free_in_slab(ptr);
|
||||
else
|
||||
buddy_free_pages(&global_mem, p_page);
|
||||
}
|
||||
|
||||
void *get_pages(int order)
|
||||
{
|
||||
struct page *p_page;
|
||||
|
||||
p_page = buddy_get_pages(&global_mem, order);
|
||||
return page_to_virt(&global_mem, p_page);
|
||||
}
|
||||
|
||||
void free_pages(void *addr)
|
||||
{
|
||||
struct page *p_page;
|
||||
p_page = virt_to_page(&global_mem, addr);
|
||||
buddy_free_pages(&global_mem, p_page);
|
||||
}
|
102
lab2/kernel/mm/mm.c
Normal file
102
lab2/kernel/mm/mm.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#include <common/mm.h>
|
||||
#include <common/kprint.h>
|
||||
#include <common/macro.h>
|
||||
|
||||
#include "buddy.h"
|
||||
#include "slab.h"
|
||||
|
||||
extern unsigned long *img_end;
|
||||
|
||||
#define PHYSICAL_MEM_START (24*1024*1024) //24M
|
||||
|
||||
#define START_VADDR phys_to_virt(PHYSICAL_MEM_START) //24M
|
||||
#define NPAGES (128*1000)
|
||||
|
||||
#define PHYSICAL_MEM_END (PHYSICAL_MEM_START+NPAGES*BUDDY_PAGE_SIZE)
|
||||
|
||||
/*
|
||||
* Layout:
|
||||
*
|
||||
* | metadata (npages * sizeof(struct page)) | start_vaddr ... (npages * PAGE_SIZE) |
|
||||
*
|
||||
*/
|
||||
|
||||
unsigned long get_ttbr1(void)
|
||||
{
|
||||
unsigned long pgd;
|
||||
|
||||
__asm__("mrs %0,ttbr1_el1":"=r"(pgd));
|
||||
return pgd;
|
||||
}
|
||||
|
||||
/*
|
||||
* map_kernel_space: map the kernel virtual address
|
||||
* [va:va+size] to physical addres [pa:pa+size].
|
||||
* 1. get the kernel pgd address
|
||||
* 2. fill the block entry with corresponding attribution bit
|
||||
*
|
||||
*/
|
||||
void map_kernel_space(vaddr_t va, paddr_t pa, size_t len)
|
||||
{
|
||||
// <lab2>
|
||||
|
||||
// </lab2>
|
||||
}
|
||||
|
||||
void kernel_space_check(void)
|
||||
{
|
||||
unsigned long kernel_val;
|
||||
for (unsigned long i = 128; i < 256; i++) {
|
||||
kernel_val = *(unsigned long *)(KBASE + (i << 21));
|
||||
kinfo("kernel_val: %lx\n", kernel_val);
|
||||
}
|
||||
kinfo("kernel space check pass\n");
|
||||
}
|
||||
|
||||
struct phys_mem_pool global_mem;
|
||||
|
||||
void mm_init(void)
|
||||
{
|
||||
vaddr_t free_mem_start = 0;
|
||||
struct page *page_meta_start = NULL;
|
||||
u64 npages = 0;
|
||||
u64 start_vaddr = 0;
|
||||
|
||||
free_mem_start =
|
||||
phys_to_virt(ROUND_UP((vaddr_t) (&img_end), PAGE_SIZE));
|
||||
npages = NPAGES;
|
||||
start_vaddr = START_VADDR;
|
||||
kdebug("[CHCORE] mm: free_mem_start is 0x%lx, free_mem_end is 0x%lx\n",
|
||||
free_mem_start, phys_to_virt(PHYSICAL_MEM_END));
|
||||
|
||||
if ((free_mem_start + npages * sizeof(struct page)) > start_vaddr) {
|
||||
BUG("kernel panic: init_mm metadata is too large!\n");
|
||||
}
|
||||
|
||||
page_meta_start = (struct page *)free_mem_start;
|
||||
kdebug("page_meta_start: 0x%lx, real_start_vadd: 0x%lx,"
|
||||
"npages: 0x%lx, meta_page_size: 0x%lx\n",
|
||||
page_meta_start, start_vaddr, npages, sizeof(struct page));
|
||||
|
||||
/* buddy alloctor for managing physical memory */
|
||||
init_buddy(&global_mem, page_meta_start, start_vaddr, npages);
|
||||
|
||||
/* slab alloctor for allocating small memory regions */
|
||||
init_slab();
|
||||
|
||||
map_kernel_space(KBASE + (128UL << 21), 128UL << 21, 128UL << 21);
|
||||
//check whether kernel space [KABSE + 256 : KBASE + 512] is mapped
|
||||
kernel_space_check();
|
||||
}
|
99
lab2/kernel/mm/page_table.S
Normal file
99
lab2/kernel/mm/page_table.S
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
// Copyright 2016 The Fuchsia Authors
|
||||
// Copyright (c) 2014, Google Inc. All rights reserved
|
||||
//
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include <common/asm.h>
|
||||
|
||||
BEGIN_FUNC(flush_idcache)
|
||||
ic iallu
|
||||
dsb nsh
|
||||
isb
|
||||
dsb sy
|
||||
mrs x0, clidr_el1
|
||||
and x3, x0, #0x7000000
|
||||
lsr x3, x3, #23
|
||||
cbz x3, finished
|
||||
mov x10, #0
|
||||
|
||||
loop1:
|
||||
add x2, x10, x10, lsr #1
|
||||
lsr x1, x0, x2
|
||||
and x1, x1, #7
|
||||
cmp x1, #2
|
||||
b.lt skip
|
||||
|
||||
msr csselr_el1, x10
|
||||
isb
|
||||
|
||||
mrs x1, ccsidr_el1
|
||||
and x2, x1, #7
|
||||
add x2, x2, #4
|
||||
mov x4, #0x3ff
|
||||
and x4, x4, x1, lsr #3
|
||||
clz w5, w4
|
||||
mov x7, #0x7fff
|
||||
and x7, x7, x1, lsr #13
|
||||
|
||||
loop2:
|
||||
mov x9, x4
|
||||
|
||||
loop3:
|
||||
lsl x6, x9, x5
|
||||
orr x11, x10, x6
|
||||
lsl x6, x7, x2
|
||||
orr x11, x11, x6
|
||||
dc cisw, x11
|
||||
subs x9, x9, #1
|
||||
b.ge loop3
|
||||
subs x7, x7, #1
|
||||
b.ge loop2
|
||||
|
||||
skip:
|
||||
add x10, x10, #2
|
||||
cmp x3, x10
|
||||
b.gt loop1
|
||||
|
||||
finished:
|
||||
mov x10, #0
|
||||
msr csselr_el1, x10
|
||||
dsb sy
|
||||
isb
|
||||
ret
|
||||
END_FUNC(flush_idcache)
|
||||
|
||||
BEGIN_FUNC(set_ttbr0_el1)
|
||||
msr ttbr0_el1, x0
|
||||
dsb sy
|
||||
tlbi vmalle1is
|
||||
dsb sy
|
||||
isb
|
||||
ret
|
||||
END_FUNC(set_ttbr0_el1)
|
||||
|
||||
/*
|
||||
* this is a simple implementation for now.
|
||||
* Note that tlbi is TLB invalidation instruction and vmalle1is is its arguement.
|
||||
* This function can flush all the TLB on all the (inner sharable) cores.
|
||||
* Different from x86 architecture, IPI is not required.
|
||||
*/
|
||||
BEGIN_FUNC(flush_tlb)
|
||||
tlbi vmalle1is
|
||||
dsb sy
|
||||
isb
|
||||
ret
|
||||
END_FUNC(flush_tlb)
|
215
lab2/kernel/mm/page_table.c
Normal file
215
lab2/kernel/mm/page_table.c
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#ifdef CHCORE
|
||||
#include <common/util.h>
|
||||
#include <common/kmalloc.h>
|
||||
#endif
|
||||
#include <common/vars.h>
|
||||
#include <common/macro.h>
|
||||
#include <common/types.h>
|
||||
#include <common/printk.h>
|
||||
#include <common/mm.h>
|
||||
#include <common/mmu.h>
|
||||
|
||||
#include <common/errno.h>
|
||||
|
||||
#include "page_table.h"
|
||||
|
||||
/* Page_table.c: Use simple impl for debugging now. */
|
||||
|
||||
extern void set_ttbr0_el1(paddr_t);
|
||||
extern void flush_tlb(void);
|
||||
|
||||
void set_page_table(paddr_t pgtbl)
|
||||
{
|
||||
set_ttbr0_el1(pgtbl);
|
||||
}
|
||||
|
||||
#define USER_PTE 0
|
||||
#define KERNEL_PTE 1
|
||||
/*
|
||||
* the 3rd arg means the kind of PTE.
|
||||
*/
|
||||
static int set_pte_flags(pte_t * entry, vmr_prop_t flags, int kind)
|
||||
{
|
||||
if (flags & VMR_WRITE)
|
||||
entry->l3_page.AP = AARCH64_PTE_AP_HIGH_RW_EL0_RW;
|
||||
else
|
||||
entry->l3_page.AP = AARCH64_PTE_AP_HIGH_RO_EL0_RO;
|
||||
|
||||
if (flags & VMR_EXEC)
|
||||
entry->l3_page.UXN = AARCH64_PTE_UX;
|
||||
else
|
||||
entry->l3_page.UXN = AARCH64_PTE_UXN;
|
||||
|
||||
// EL1 cannot directly execute EL0 accessiable region.
|
||||
if (kind == USER_PTE)
|
||||
entry->l3_page.PXN = AARCH64_PTE_PXN;
|
||||
entry->l3_page.AF = AARCH64_PTE_AF_ACCESSED;
|
||||
|
||||
// inner sharable
|
||||
entry->l3_page.SH = INNER_SHAREABLE;
|
||||
// memory type
|
||||
entry->l3_page.attr_index = NORMAL_MEMORY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define GET_PADDR_IN_PTE(entry) \
|
||||
(((u64)entry->table.next_table_addr) << PAGE_SHIFT)
|
||||
#define GET_NEXT_PTP(entry) phys_to_virt(GET_PADDR_IN_PTE(entry))
|
||||
|
||||
#define NORMAL_PTP (0)
|
||||
#define BLOCK_PTP (1)
|
||||
|
||||
/*
|
||||
* Find next page table page for the "va".
|
||||
*
|
||||
* cur_ptp: current page table page
|
||||
* level: current ptp level
|
||||
*
|
||||
* next_ptp: returns "next_ptp"
|
||||
* pte : returns "pte" (points to next_ptp) in "cur_ptp"
|
||||
*
|
||||
* alloc: if true, allocate a ptp when missing
|
||||
*
|
||||
*/
|
||||
static int get_next_ptp(ptp_t * cur_ptp, u32 level, vaddr_t va,
|
||||
ptp_t ** next_ptp, pte_t ** pte, bool alloc)
|
||||
{
|
||||
u32 index = 0;
|
||||
pte_t *entry;
|
||||
|
||||
if (cur_ptp == NULL)
|
||||
return -ENOMAPPING;
|
||||
|
||||
switch (level) {
|
||||
case 0:
|
||||
index = GET_L0_INDEX(va);
|
||||
break;
|
||||
case 1:
|
||||
index = GET_L1_INDEX(va);
|
||||
break;
|
||||
case 2:
|
||||
index = GET_L2_INDEX(va);
|
||||
break;
|
||||
case 3:
|
||||
index = GET_L3_INDEX(va);
|
||||
break;
|
||||
default:
|
||||
BUG_ON(1);
|
||||
}
|
||||
|
||||
entry = &(cur_ptp->ent[index]);
|
||||
if (IS_PTE_INVALID(entry->pte)) {
|
||||
if (alloc == false) {
|
||||
return -ENOMAPPING;
|
||||
} else {
|
||||
/* alloc a new page table page */
|
||||
ptp_t *new_ptp;
|
||||
paddr_t new_ptp_paddr;
|
||||
pte_t new_pte_val;
|
||||
|
||||
/* alloc a single physical page as a new page table page */
|
||||
new_ptp = get_pages(0);
|
||||
BUG_ON(new_ptp == NULL);
|
||||
memset((void *)new_ptp, 0, PAGE_SIZE);
|
||||
new_ptp_paddr = virt_to_phys((vaddr_t) new_ptp);
|
||||
|
||||
new_pte_val.pte = 0;
|
||||
new_pte_val.table.is_valid = 1;
|
||||
new_pte_val.table.is_table = 1;
|
||||
new_pte_val.table.next_table_addr
|
||||
= new_ptp_paddr >> PAGE_SHIFT;
|
||||
|
||||
/* same effect as: cur_ptp->ent[index] = new_pte_val; */
|
||||
entry->pte = new_pte_val.pte;
|
||||
}
|
||||
}
|
||||
*next_ptp = (ptp_t *) GET_NEXT_PTP(entry);
|
||||
*pte = entry;
|
||||
if (IS_PTE_TABLE(entry->pte))
|
||||
return NORMAL_PTP;
|
||||
else
|
||||
return BLOCK_PTP;
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate a va to pa, and get its pte for the flags
|
||||
*/
|
||||
/*
|
||||
* query_in_pgtbl: translate virtual address to physical
|
||||
* address and return the corresponding page table entry
|
||||
*
|
||||
* pgtbl @ ptr for the first level page table(pgd) virtual address
|
||||
* va @ query virtual address
|
||||
* pa @ return physical address
|
||||
* entry @ return page table entry
|
||||
*
|
||||
* Hint: check the return value of get_next_ptp, if ret == BLOCK_PTP
|
||||
* return the pa and block entry immediately
|
||||
*/
|
||||
int query_in_pgtbl(vaddr_t * pgtbl, vaddr_t va, paddr_t * pa, pte_t ** entry)
|
||||
{
|
||||
// <lab2>
|
||||
|
||||
// </lab2>
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* map_range_in_pgtbl: map the virtual address [va:va+size] to
|
||||
* physical address[pa:pa+size] in given pgtbl
|
||||
*
|
||||
* pgtbl @ ptr for the first level page table(pgd) virtual address
|
||||
* va @ start virtual address
|
||||
* pa @ start physical address
|
||||
* len @ mapping size
|
||||
* flags @ corresponding attribution bit
|
||||
*
|
||||
* Hint: In this function you should first invoke the get_next_ptp()
|
||||
* to get the each level page table entries. Read type pte_t carefully
|
||||
* and it is convenient for you to call set_pte_flags to set the page
|
||||
* permission bit. Don't forget to call flush_tlb at the end of this function
|
||||
*/
|
||||
int map_range_in_pgtbl(vaddr_t * pgtbl, vaddr_t va, paddr_t pa,
|
||||
size_t len, vmr_prop_t flags)
|
||||
{
|
||||
// <lab2>
|
||||
|
||||
// </lab2>
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* unmap_range_in_pgtble: unmap the virtual address [va:va+len]
|
||||
*
|
||||
* pgtbl @ ptr for the first level page table(pgd) virtual address
|
||||
* va @ start virtual address
|
||||
* len @ unmapping size
|
||||
*
|
||||
* Hint: invoke get_next_ptp to get each level page table, don't
|
||||
* forget the corner case that the virtual address is not mapped.
|
||||
* call flush_tlb() at the end of function
|
||||
*
|
||||
*/
|
||||
int unmap_range_in_pgtbl(vaddr_t * pgtbl, vaddr_t va, size_t len)
|
||||
{
|
||||
// <lab2>
|
||||
|
||||
// </lab2>
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: add hugepage support for user space.
|
128
lab2/kernel/mm/page_table.h
Normal file
128
lab2/kernel/mm/page_table.h
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/types.h>
|
||||
|
||||
#define INNER_SHAREABLE (0x3)
|
||||
/* Please search mair_el1 for these memory types. */
|
||||
#define NORMAL_MEMORY (0x4)
|
||||
#define DEVICE_MEMORY (0x0)
|
||||
|
||||
/* Description bits in page table entries. */
|
||||
|
||||
/* Read-write permission. */
|
||||
#define AARCH64_PTE_AP_HIGH_RW_EL0_RW (1)
|
||||
#define AARCH64_PTE_AP_HIGH_RO_EL0_RO (3)
|
||||
|
||||
/* X: execution permission. U: unprivileged. P: privileged. */
|
||||
#define AARCH64_PTE_UX (0)
|
||||
#define AARCH64_PTE_UXN (1)
|
||||
#define AARCH64_PTE_PXN (1)
|
||||
|
||||
/* Access flag bit. */
|
||||
#define AARCH64_PTE_AF_ACCESSED (1)
|
||||
|
||||
/* Present (valid) bit. */
|
||||
#define AARCH64_PTE_INVALID_MASK (1 << 0)
|
||||
/* Table bit: whether the next level is aonther pte or physical memory page. */
|
||||
#define AARCH64_PTE_TABLE_MASK (1 << 1)
|
||||
#define IS_PTE_INVALID(pte) (!((pte) & AARCH64_PTE_INVALID_MASK))
|
||||
#define IS_PTE_TABLE(pte) (!!((pte) & AARCH64_PTE_TABLE_MASK))
|
||||
|
||||
/* PAGE_SIZE (4k) == (1 << (PAGE_SHIFT)) */
|
||||
#define PAGE_SHIFT (12)
|
||||
#define PAGE_MASK (PAGE_SIZE - 1)
|
||||
#define PAGE_ORDER (9)
|
||||
|
||||
#define PTP_INDEX_MASK ((1 << (PAGE_ORDER)) - 1)
|
||||
#define L0_INDEX_SHIFT ((3 * PAGE_ORDER) + PAGE_SHIFT)
|
||||
#define L1_INDEX_SHIFT ((2 * PAGE_ORDER) + PAGE_SHIFT)
|
||||
#define L2_INDEX_SHIFT ((1 * PAGE_ORDER) + PAGE_SHIFT)
|
||||
#define L3_INDEX_SHIFT ((0 * PAGE_ORDER) + PAGE_SHIFT)
|
||||
|
||||
#define GET_L0_INDEX(addr) ((addr >> L0_INDEX_SHIFT) & PTP_INDEX_MASK)
|
||||
#define GET_L1_INDEX(addr) ((addr >> L1_INDEX_SHIFT) & PTP_INDEX_MASK)
|
||||
#define GET_L2_INDEX(addr) ((addr >> L2_INDEX_SHIFT) & PTP_INDEX_MASK)
|
||||
#define GET_L3_INDEX(addr) ((addr >> L3_INDEX_SHIFT) & PTP_INDEX_MASK)
|
||||
|
||||
#define PTP_ENTRIES (1UL << PAGE_ORDER)
|
||||
/* Number of 4KB-pages that an Lx-block describes */
|
||||
#define L0_PER_ENTRY_PAGES ((PTP_ENTRIES) * (L1_PER_ENTRY_PAGES))
|
||||
#define L1_PER_ENTRY_PAGES ((PTP_ENTRIES) * (L2_PER_ENTRY_PAGES))
|
||||
#define L2_PER_ENTRY_PAGES ((PTP_ENTRIES) * (L3_PER_ENTRY_PAGES))
|
||||
#define L3_PER_ENTRY_PAGES (1)
|
||||
|
||||
/* Bitmask used by GET_VA_OFFSET_Lx */
|
||||
#define L1_BLOCK_MASK ((L1_PER_ENTRY_PAGES << PAGE_SHIFT) - 1)
|
||||
#define L2_BLOCK_MASK ((L2_PER_ENTRY_PAGES << PAGE_SHIFT) - 1)
|
||||
#define L3_PAGE_MASK ((L3_PER_ENTRY_PAGES << PAGE_SHIFT) - 1)
|
||||
|
||||
#define GET_VA_OFFSET_L1(va) (va & L1_BLOCK_MASK)
|
||||
#define GET_VA_OFFSET_L2(va) (va & L2_BLOCK_MASK)
|
||||
#define GET_VA_OFFSET_L3(va) (va & L3_PAGE_MASK)
|
||||
|
||||
/* table format */
|
||||
typedef union {
|
||||
struct {
|
||||
u64 is_valid:1, is_table:1, ignored1:10, next_table_addr:36, reserved:4, ignored2:7, PXNTable:1, // Privileged Execute-never for next level
|
||||
XNTable:1, // Execute-never for next level
|
||||
APTable:2, // Access permissions for next level
|
||||
NSTable:1;
|
||||
} table;
|
||||
struct {
|
||||
u64 is_valid:1, is_table:1, attr_index:3, // Memory attributes index
|
||||
NS:1, // Non-secure
|
||||
AP:2, // Data access permissions
|
||||
SH:2, // Shareability
|
||||
AF:1, // Accesss flag
|
||||
nG:1, // Not global bit
|
||||
reserved1:4, nT:1, reserved2:13, pfn:18, reserved3:2, GP:1, reserved4:1, DBM:1, // Dirty bit modifier
|
||||
Contiguous:1, PXN:1, // Privileged execute-never
|
||||
UXN:1, // Execute never
|
||||
soft_reserved:4, PBHA:4; // Page based hardware attributes
|
||||
} l1_block;
|
||||
struct {
|
||||
u64 is_valid:1, is_table:1, attr_index:3, // Memory attributes index
|
||||
NS:1, // Non-secure
|
||||
AP:2, // Data access permissions
|
||||
SH:2, // Shareability
|
||||
AF:1, // Accesss flag
|
||||
nG:1, // Not global bit
|
||||
reserved1:4, nT:1, reserved2:4, pfn:27, reserved3:2, GP:1, reserved4:1, DBM:1, // Dirty bit modifier
|
||||
Contiguous:1, PXN:1, // Privileged execute-never
|
||||
UXN:1, // Execute never
|
||||
soft_reserved:4, PBHA:4; // Page based hardware attributes
|
||||
} l2_block;
|
||||
struct {
|
||||
u64 is_valid:1, is_page:1, attr_index:3, // Memory attributes index
|
||||
NS:1, // Non-secure
|
||||
AP:2, // Data access permissions
|
||||
SH:2, // Shareability
|
||||
AF:1, // Accesss flag
|
||||
nG:1, // Not global bit
|
||||
pfn:36, reserved:3, DBM:1, // Dirty bit modifier
|
||||
Contiguous:1, PXN:1, // Privileged execute-never
|
||||
UXN:1, // Execute never
|
||||
soft_reserved:4, PBHA:4, // Page based hardware attributes
|
||||
ignored:1;
|
||||
} l3_page;
|
||||
u64 pte;
|
||||
} pte_t;
|
||||
|
||||
#define PTE_DESCRIPTOR_INVALID (0)
|
||||
|
||||
/* page_table_page type */
|
||||
typedef struct {
|
||||
pte_t ent[PTP_ENTRIES];
|
||||
} ptp_t;
|
184
lab2/kernel/mm/slab.c
Normal file
184
lab2/kernel/mm/slab.c
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#include <common/macro.h>
|
||||
#include <common/types.h>
|
||||
#include <common/kprint.h>
|
||||
|
||||
#include "slab.h"
|
||||
#include "buddy.h"
|
||||
|
||||
/* local variables */
|
||||
slab_header_t *slabs[SLAB_MAX_ORDER + 1];
|
||||
|
||||
/* local functions */
|
||||
static inline u64 size_to_order(u64 size)
|
||||
{
|
||||
u64 order = 0;
|
||||
int tmp = size;
|
||||
|
||||
while (tmp > 1) {
|
||||
tmp >>= 1;
|
||||
order += 1;
|
||||
}
|
||||
if (size > (1 << order))
|
||||
order += 1;
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
static inline u64 order_to_size(u64 order)
|
||||
{
|
||||
return 1UL << order;
|
||||
}
|
||||
|
||||
static void *alloc_slab_memory(u64 size)
|
||||
{
|
||||
struct page *p_page, *page;
|
||||
void *addr;
|
||||
u64 order, page_num;
|
||||
void *page_addr;
|
||||
int i;
|
||||
|
||||
order = size_to_order(size / BUDDY_PAGE_SIZE);
|
||||
p_page = buddy_get_pages(&global_mem, order);
|
||||
if (p_page == NULL) {
|
||||
kwarn("failed to alloc_slab_memory: out of memory\n");
|
||||
BUG_ON(1);
|
||||
}
|
||||
addr = page_to_virt(&global_mem, p_page);
|
||||
|
||||
//BUG_ON(check_alignment((u64)addr, SLAB_INIT_SIZE));
|
||||
page_num = order_to_size(order);
|
||||
for (i = 0; i < page_num; i++) {
|
||||
page_addr = (void *)((u64) addr + i * BUDDY_PAGE_SIZE);
|
||||
page = virt_to_page(&global_mem, page_addr);
|
||||
page->slab = addr;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
static slab_header_t *init_slab_cache(int order, int size)
|
||||
{
|
||||
void *addr;
|
||||
slab_slot_list_t *slot;
|
||||
slab_header_t *slab;
|
||||
u64 cnt, obj_size;
|
||||
int i;
|
||||
|
||||
addr = alloc_slab_memory(size);
|
||||
slab = (slab_header_t *) addr;
|
||||
|
||||
obj_size = order_to_size(order);
|
||||
/* the first slot is used as metadata */
|
||||
cnt = size / obj_size - 1;
|
||||
|
||||
slot = (slab_slot_list_t *) (addr + obj_size);
|
||||
slab->free_list_head = (void *)slot;
|
||||
slab->next_slab = NULL;
|
||||
slab->order = order;
|
||||
|
||||
/* the last slot has no next one */
|
||||
for (i = 0; i < cnt - 1; i++) {
|
||||
slot->next_free = (void *)((u64) slot + obj_size);
|
||||
slot = (slab_slot_list_t *) ((u64) slot + obj_size);
|
||||
}
|
||||
slot->next_free = NULL;
|
||||
|
||||
return slab;
|
||||
}
|
||||
|
||||
static void *_alloc_in_slab_nolock(slab_header_t * slab_header, int order)
|
||||
{
|
||||
slab_slot_list_t *first_slot;
|
||||
void *next_slot;
|
||||
slab_header_t *next_slab;
|
||||
slab_header_t *new_slab;
|
||||
|
||||
first_slot = (slab_slot_list_t *) (slab_header->free_list_head);
|
||||
if (likely(first_slot != NULL)) {
|
||||
next_slot = first_slot->next_free;
|
||||
slab_header->free_list_head = next_slot;
|
||||
return first_slot;
|
||||
}
|
||||
|
||||
next_slab = slab_header->next_slab;
|
||||
while (next_slab != NULL) {
|
||||
first_slot = (slab_slot_list_t *) (next_slab->free_list_head);
|
||||
if (likely(first_slot != NULL)) {
|
||||
next_slot = first_slot->next_free;
|
||||
next_slab->free_list_head = next_slot;
|
||||
return first_slot;
|
||||
}
|
||||
next_slab = next_slab->next_slab;
|
||||
}
|
||||
|
||||
//alloc new slab
|
||||
new_slab = init_slab_cache(order, SLAB_INIT_SIZE);
|
||||
new_slab->next_slab = slab_header;
|
||||
slabs[order] = new_slab;
|
||||
|
||||
return _alloc_in_slab_nolock(new_slab, order);
|
||||
}
|
||||
|
||||
static void *_alloc_in_slab(slab_header_t * slab_header, int order)
|
||||
{
|
||||
void *free_slot;
|
||||
|
||||
free_slot = _alloc_in_slab_nolock(slab_header, order);
|
||||
|
||||
return free_slot;
|
||||
}
|
||||
|
||||
/*
|
||||
* exported functions
|
||||
*/
|
||||
|
||||
void init_slab()
|
||||
{
|
||||
int order;
|
||||
|
||||
/* slab obj size: 32, 64, 128, 256, 512, 1024, 2048 */
|
||||
for (order = SLAB_MIN_ORDER; order <= SLAB_MAX_ORDER; order++) {
|
||||
slabs[order] = init_slab_cache(order, SLAB_INIT_SIZE);
|
||||
}
|
||||
kdebug("mm: finish initing slab allocators\n");
|
||||
}
|
||||
|
||||
void *alloc_in_slab(u64 size)
|
||||
{
|
||||
int order;
|
||||
|
||||
BUG_ON(size > order_to_size(SLAB_MAX_ORDER));
|
||||
|
||||
order = (int)size_to_order(size);
|
||||
if (order < SLAB_MIN_ORDER)
|
||||
order = SLAB_MIN_ORDER;
|
||||
|
||||
return _alloc_in_slab(slabs[order], order);
|
||||
}
|
||||
|
||||
void free_in_slab(void *addr)
|
||||
{
|
||||
struct page *page;
|
||||
slab_header_t *slab;
|
||||
slab_slot_list_t *slot;
|
||||
|
||||
slot = (slab_slot_list_t *) addr;
|
||||
page = virt_to_page(&global_mem, addr);
|
||||
BUG_ON(page == NULL);
|
||||
|
||||
slab = page->slab;
|
||||
slot->next_free = slab->free_list_head;
|
||||
slab->free_list_head = slot;
|
||||
}
|
38
lab2/kernel/mm/slab.h
Normal file
38
lab2/kernel/mm/slab.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/types.h>
|
||||
|
||||
#define SLAB_INIT_SIZE (2*1024*1024) //2M
|
||||
|
||||
/* order range: [SLAB_MIN_ORDER, SLAB_MAX_ORDER] */
|
||||
#define SLAB_MIN_ORDER (5)
|
||||
#define SLAB_MAX_ORDER (11)
|
||||
|
||||
typedef struct slab_header slab_header_t;
|
||||
struct slab_header {
|
||||
void *free_list_head;
|
||||
slab_header_t *next_slab;
|
||||
int order;
|
||||
};
|
||||
|
||||
typedef struct slab_slot_list slab_slot_list_t;
|
||||
struct slab_slot_list {
|
||||
void *next_free;
|
||||
};
|
||||
|
||||
void init_slab(void);
|
||||
|
||||
void *alloc_in_slab(u64);
|
||||
void free_in_slab(void *addr);
|
35
lab2/kernel/monitor.c
Normal file
35
lab2/kernel/monitor.c
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
|
||||
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||||
* You may obtain a copy of Mulan PSL v1 at:
|
||||
* http://license.coscl.org.cn/MulanPSL
|
||||
* 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 v1 for more details.
|
||||
*/
|
||||
|
||||
// Simple command-line kernel monitor useful for
|
||||
// controlling the kernel and exploring the system interactively.
|
||||
|
||||
#include <common/printk.h>
|
||||
#include <common/types.h>
|
||||
|
||||
static inline __attribute__ ((always_inline))
|
||||
u64 read_fp()
|
||||
{
|
||||
u64 fp;
|
||||
__asm __volatile("mov %0, x29":"=r"(fp));
|
||||
return fp;
|
||||
}
|
||||
|
||||
__attribute__ ((optimize("O1")))
|
||||
int stack_backtrace()
|
||||
{
|
||||
printk("Stack backtrace:\n");
|
||||
|
||||
// Your code here.
|
||||
|
||||
return 0;
|
||||
}
|
33
lab2/scripts/build.sh
Executable file
33
lab2/scripts/build.sh
Executable file
@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ ! -d "build" ]; then
|
||||
mkdir build
|
||||
cd build
|
||||
cat > simulate.sh <<EOF
|
||||
#!/bin/bash
|
||||
|
||||
basedir=\$(dirname "\$0")
|
||||
if [[ \$@ == *"gdb"* ]]; then
|
||||
qemu-system-aarch64 -machine raspi3 -nographic -serial null -serial mon:stdio -m size=1G -kernel \$basedir/kernel.img -S -gdb tcp::1234
|
||||
else
|
||||
qemu-system-aarch64 -machine raspi3 -nographic -serial null -serial mon:stdio -m size=1G -kernel \$basedir/kernel.img
|
||||
fi
|
||||
EOF
|
||||
chmod +x simulate.sh
|
||||
cd ..
|
||||
fi
|
||||
|
||||
# compile kernel
|
||||
echo "compiling kernel ..."
|
||||
cd build
|
||||
|
||||
cmake -DCMAKE_LINKER=aarch64-linux-gnu-ld -DCMAKE_C_LINK_EXECUTABLE="<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>" .. -G Ninja "$@"
|
||||
echo "before ninja"
|
||||
ninja
|
||||
echo "after ninja"
|
||||
if [ ! -f "kernel.img" ]; then
|
||||
echo "kernel.img is not exist"
|
||||
fi
|
||||
aarch64-linux-gnu-nm -n kernel.img > kernel.sym
|
||||
# print the compile logs
|
||||
#ninja -v
|
4
lab2/scripts/docker_build.sh
Executable file
4
lab2/scripts/docker_build.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
rm -rf ./build
|
||||
|
||||
docker run -it --rm -u $(id -u ${USER}):$(id -g ${USER}) -v $(pwd):/chos -w /chos ipads/chcore_builder:v1.0 ./scripts/build.sh "$@"
|
45
lab2/scripts/grade-lab1
Executable file
45
lab2/scripts/grade-lab1
Executable file
@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import re
|
||||
from gradelib import *
|
||||
|
||||
r = Runner(save("chcore.out"),
|
||||
stop_breakpoint("break_point"))
|
||||
|
||||
@test(0, "running ChCore")
|
||||
def test_chcore():
|
||||
r.run_qemu(30)
|
||||
|
||||
@test(15, parent=test_chcore)
|
||||
def test_print_hex():
|
||||
addrs = [int(sym[:16], 16) for sym in open("./build/kernel.sym")
|
||||
if sym[19:].strip() == "main"]
|
||||
r.match("\[INFO\] Address of main\(\) is 0x%x" % addrs[0])
|
||||
|
||||
@test(15, parent=test_chcore)
|
||||
def test_print_oct():
|
||||
r.match("\[INFO\] 123456 decimal is 0361100 octal")
|
||||
|
||||
BACKTRACE_RE = r" *LR *ffffff00000[0-9a-z]{5} *FP *ffffff0000[0-9a-z]{6} *Args *([0-9a-z]+)"
|
||||
BACKTRACE_LR = r" *LR *(ffffff00000[0-9a-z]{5}) *FP *ffffff0000[0-9a-z]{6} *Args *[0-9a-z]+"
|
||||
|
||||
@test(15, parent=test_chcore)
|
||||
def test_stack_count():
|
||||
matches = re.findall(BACKTRACE_RE, r.qemu.output, re.MULTILINE)
|
||||
assert_equal(len(matches), 7)
|
||||
|
||||
@test(15, parent=test_chcore)
|
||||
def test_stack_arguments():
|
||||
matches = re.findall(BACKTRACE_RE, r.qemu.output, re.MULTILINE)
|
||||
assert_equal("\n".join(matches[:6]),
|
||||
"\n".join("%01x" % n for n in [0,1,2,3,4,5]))
|
||||
|
||||
@test(20, parent=test_chcore)
|
||||
def test_stack_lr():
|
||||
matches = re.findall(BACKTRACE_LR, r.qemu.output, re.MULTILINE)
|
||||
addrs = [int(sym[:16], 16) for sym in open("./build/kernel.sym")
|
||||
if sym[19:].strip() == "stack_test"][0] + 80
|
||||
for i in range(5):
|
||||
assert_equal(int(matches[i], 16), addrs)
|
||||
|
||||
run_tests()
|
27
lab2/scripts/grade-lab2
Executable file
27
lab2/scripts/grade-lab2
Executable file
@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import re
|
||||
from gradelib import *
|
||||
|
||||
r = Runner(save("chcore.out"),
|
||||
stop_breakpoint("break_point"))
|
||||
|
||||
@test(0, "running chcore")
|
||||
def test_chcore():
|
||||
r.run_qemu(10)
|
||||
|
||||
@test(30, parent=test_chcore)
|
||||
def test_buddy():
|
||||
r.file_match("./tests/mm/buddy/buddy.out","0 failures")
|
||||
|
||||
@test(40, parent=test_chcore)
|
||||
def test_page_table():
|
||||
r.file_match("./tests/mm/page_table/page_table.out","0 failures")
|
||||
|
||||
@test(30, parent=test_chcore)
|
||||
def test_kernel_space_check():
|
||||
r.match("\[INFO\] mm init finished")
|
||||
|
||||
|
||||
|
||||
run_tests()
|
693
lab2/scripts/gradelib.py
Normal file
693
lab2/scripts/gradelib.py
Normal file
@ -0,0 +1,693 @@
|
||||
# The gradelib.py is:
|
||||
#
|
||||
# Copyright (c) 2006-2019 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.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys, os, re, time, socket, select, subprocess, errno, shutil, random, string
|
||||
from subprocess import check_call, Popen
|
||||
from optparse import OptionParser
|
||||
|
||||
__all__ = []
|
||||
|
||||
##################################################################
|
||||
# Test structure
|
||||
#
|
||||
|
||||
__all__ += ["test", "end_part", "run_tests", "get_current_test"]
|
||||
|
||||
TESTS = []
|
||||
TOTAL = POSSIBLE = 0
|
||||
PART_TOTAL = PART_POSSIBLE = 0
|
||||
CURRENT_TEST = None
|
||||
|
||||
def test(points, title=None, parent=None):
|
||||
"""Decorator for declaring test functions. If title is None, the
|
||||
title of the test will be derived from the function name by
|
||||
stripping the leading "test_" and replacing underscores with
|
||||
spaces."""
|
||||
|
||||
def register_test(fn, title=title):
|
||||
if not title:
|
||||
assert fn.__name__.startswith("test_")
|
||||
title = fn.__name__[5:].replace("_", " ")
|
||||
if parent:
|
||||
title = " " + title
|
||||
|
||||
def run_test():
|
||||
global TOTAL, POSSIBLE, CURRENT_TEST
|
||||
|
||||
# Handle test dependencies
|
||||
if run_test.complete:
|
||||
return run_test.ok
|
||||
run_test.complete = True
|
||||
parent_failed = False
|
||||
if parent:
|
||||
parent_failed = not parent()
|
||||
|
||||
# Run the test
|
||||
fail = None
|
||||
start = time.time()
|
||||
CURRENT_TEST = run_test
|
||||
sys.stdout.write("%s: " % title)
|
||||
sys.stdout.flush()
|
||||
try:
|
||||
if parent_failed:
|
||||
raise AssertionError('Parent failed: %s' % parent.__name__)
|
||||
fn()
|
||||
except AssertionError as e:
|
||||
fail = str(e)
|
||||
|
||||
# Display and handle test result
|
||||
POSSIBLE += points
|
||||
if points:
|
||||
print("%s" % \
|
||||
(color("red", "FAIL") if fail else color("green", "OK")), end=' ')
|
||||
if time.time() - start > 0.1:
|
||||
print("(%.1fs)" % (time.time() - start), end=' ')
|
||||
print()
|
||||
if fail:
|
||||
print(" %s" % fail.replace("\n", "\n "))
|
||||
else:
|
||||
TOTAL += points
|
||||
for callback in run_test.on_finish:
|
||||
callback(fail)
|
||||
CURRENT_TEST = None
|
||||
|
||||
run_test.ok = not fail
|
||||
return run_test.ok
|
||||
|
||||
# Record test metadata on the test wrapper function
|
||||
run_test.__name__ = fn.__name__
|
||||
run_test.title = title
|
||||
run_test.complete = False
|
||||
run_test.ok = False
|
||||
run_test.on_finish = []
|
||||
TESTS.append(run_test)
|
||||
return run_test
|
||||
return register_test
|
||||
|
||||
def end_part(name):
|
||||
def show_part():
|
||||
global PART_TOTAL, PART_POSSIBLE
|
||||
print("Part %s score: %d/%d" % \
|
||||
(name, TOTAL - PART_TOTAL, POSSIBLE - PART_POSSIBLE))
|
||||
print()
|
||||
PART_TOTAL, PART_POSSIBLE = TOTAL, POSSIBLE
|
||||
show_part.title = ""
|
||||
TESTS.append(show_part)
|
||||
|
||||
def run_tests():
|
||||
"""Set up for testing and run the registered test functions."""
|
||||
|
||||
# Handle command line
|
||||
global options
|
||||
parser = OptionParser(usage="usage: %prog [-v] [filters...]")
|
||||
parser.add_option("-v", "--verbose", action="store_true",
|
||||
help="print commands")
|
||||
parser.add_option("--color", choices=["never", "always", "auto"],
|
||||
default="auto", help="never, always, or auto")
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
# Start with a full build to catch build errors
|
||||
make()
|
||||
|
||||
# Clean the file system if there is one
|
||||
# reset_fs()
|
||||
|
||||
# Run tests
|
||||
limit = list(map(str.lower, args))
|
||||
try:
|
||||
for test in TESTS:
|
||||
if not limit or any(l in test.title.lower() for l in limit):
|
||||
test()
|
||||
if not limit:
|
||||
print("Score: %d/%d" % (TOTAL, POSSIBLE))
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
if TOTAL < POSSIBLE:
|
||||
sys.exit(1)
|
||||
|
||||
def get_current_test():
|
||||
if not CURRENT_TEST:
|
||||
raise RuntimeError("No test is running")
|
||||
return CURRENT_TEST
|
||||
|
||||
##################################################################
|
||||
# Assertions
|
||||
#
|
||||
|
||||
__all__ += ["assert_equal", "assert_lines_match"]
|
||||
|
||||
def assert_equal(got, expect, msg=""):
|
||||
if got == expect:
|
||||
return
|
||||
if msg:
|
||||
msg += "\n"
|
||||
raise AssertionError("%sgot:\n %s\nexpected:\n %s" %
|
||||
(msg, str(got).replace("\n", "\n "),
|
||||
str(expect).replace("\n", "\n ")))
|
||||
|
||||
def assert_lines_match(text, *regexps, **kw):
|
||||
"""Assert that all of regexps match some line in text. If a 'no'
|
||||
keyword argument is given, it must be a list of regexps that must
|
||||
*not* match any line in text."""
|
||||
|
||||
def assert_lines_match_kw(no=[]):
|
||||
return no
|
||||
no = assert_lines_match_kw(**kw)
|
||||
|
||||
# Check text against regexps
|
||||
lines = text.splitlines()
|
||||
good = set()
|
||||
bad = set()
|
||||
first_line = 0
|
||||
for i, line in enumerate(lines):
|
||||
if any(re.match(r, line) for r in regexps):
|
||||
if (first_line == 0):
|
||||
first_line = i
|
||||
good.add(i)
|
||||
regexps = [r for r in regexps if not re.match(r, line)]
|
||||
if any(re.match(r, line) for r in no):
|
||||
bad.add(i)
|
||||
|
||||
if not regexps and not bad:
|
||||
return first_line
|
||||
|
||||
# We failed; construct an informative failure message
|
||||
show = set()
|
||||
for lineno in good.union(bad):
|
||||
for offset in range(-2, 3):
|
||||
show.add(lineno + offset)
|
||||
if regexps:
|
||||
show.update(n for n in range(len(lines) - 5, len(lines)))
|
||||
|
||||
msg = []
|
||||
last = -1
|
||||
for lineno in sorted(show):
|
||||
if 0 <= lineno < len(lines):
|
||||
if lineno != last + 1:
|
||||
msg.append("...")
|
||||
last = lineno
|
||||
msg.append("%s %s" % (color("red", "BAD ") if lineno in bad else
|
||||
color("green", "GOOD") if lineno in good
|
||||
else " ",
|
||||
lines[lineno]))
|
||||
if last != len(lines) - 1:
|
||||
msg.append("...")
|
||||
if bad:
|
||||
msg.append("unexpected lines in output")
|
||||
for r in regexps:
|
||||
msg.append(color("red", "MISSING") + " '%s'" % r)
|
||||
raise AssertionError("\n".join(msg))
|
||||
return 0
|
||||
|
||||
def assert_lines_match_line(line_num, text, *regexps, **kw):
|
||||
"""Assert that all of regexps match some line in text. If a 'no'
|
||||
keyword argument is given, it must be a list of regexps that must
|
||||
*not* match any line in text."""
|
||||
|
||||
def assert_lines_match_kw(no=[]):
|
||||
return no
|
||||
no = assert_lines_match_kw(**kw)
|
||||
|
||||
# Check text against regexps
|
||||
lines = text.splitlines()
|
||||
good = set()
|
||||
bad = set()
|
||||
first_line = 0
|
||||
for i, line in enumerate(lines):
|
||||
if (i >=line_num):
|
||||
if any(re.match(r, line) for r in regexps):
|
||||
if (first_line == 0 ):
|
||||
first_line = i
|
||||
good.add(i)
|
||||
regexps = [r for r in regexps if not re.match(r, line)]
|
||||
if any(re.match(r, line) for r in no):
|
||||
bad.add(i)
|
||||
|
||||
if not regexps and not bad:
|
||||
return first_line
|
||||
|
||||
# We failed; construct an informative failure message
|
||||
show = set()
|
||||
for lineno in good.union(bad):
|
||||
for offset in range(-2, 3):
|
||||
show.add(lineno + offset)
|
||||
if regexps:
|
||||
show.update(n for n in range(len(lines) - 5, len(lines)))
|
||||
|
||||
msg = []
|
||||
last = -1
|
||||
for lineno in sorted(show):
|
||||
if 0 <= lineno < len(lines):
|
||||
if lineno != last + 1:
|
||||
msg.append("...")
|
||||
last = lineno
|
||||
msg.append("%s %s" % (color("red", "BAD ") if lineno in bad else
|
||||
color("green", "GOOD") if lineno in good
|
||||
else " ",
|
||||
lines[lineno]))
|
||||
if last != len(lines) - 1:
|
||||
msg.append("...")
|
||||
if bad:
|
||||
msg.append("unexpected lines in output")
|
||||
for r in regexps:
|
||||
msg.append(color("red", "MISSING or WRONG ORDER") + " '%s'" % r)
|
||||
raise AssertionError("\n".join(msg))
|
||||
return 0
|
||||
|
||||
##################################################################
|
||||
# Utilities
|
||||
#
|
||||
|
||||
__all__ += ["make", "maybe_unlink", "reset_fs", "color", "random_str"]
|
||||
|
||||
MAKE_TIMESTAMP = 0
|
||||
|
||||
def pre_make():
|
||||
"""Delay prior to running make to ensure file mtimes change."""
|
||||
while int(time.time()) == MAKE_TIMESTAMP:
|
||||
time.sleep(0.1)
|
||||
|
||||
def post_make():
|
||||
"""Record the time after make completes so that the next run of
|
||||
make can be delayed if needed."""
|
||||
global MAKE_TIMESTAMP
|
||||
MAKE_TIMESTAMP = int(time.time())
|
||||
|
||||
def make(*target):
|
||||
pre_make()
|
||||
#print(target)
|
||||
if Popen(("make",) + target).wait():
|
||||
sys.exit(1)
|
||||
post_make()
|
||||
|
||||
def show_command(cmd):
|
||||
from pipes import quote
|
||||
print("\n$", " ".join(map(quote, cmd)))
|
||||
|
||||
def maybe_unlink(*paths):
|
||||
for path in paths:
|
||||
try:
|
||||
os.unlink(path)
|
||||
except EnvironmentError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
raise
|
||||
|
||||
COLORS = {"default": "\033[0m", "red": "\033[31m", "green": "\033[32m"}
|
||||
|
||||
def color(name, text):
|
||||
if options.color == "always" or (options.color == "auto" and os.isatty(1)):
|
||||
return COLORS[name] + text + COLORS["default"]
|
||||
return text
|
||||
|
||||
def reset_fs():
|
||||
if os.path.exists("obj/fs/clean-fs.img"):
|
||||
shutil.copyfile("obj/fs/clean-fs.img", "obj/fs/fs.img")
|
||||
|
||||
def random_str(n=8):
|
||||
letters = string.ascii_letters + string.digits
|
||||
return ''.join(random.choice(letters) for _ in range(n))
|
||||
|
||||
##################################################################
|
||||
# Controllers
|
||||
#
|
||||
|
||||
__all__ += ["QEMU", "GDBClient"]
|
||||
|
||||
class QEMU(object):
|
||||
_GDBPORT = None
|
||||
|
||||
def __init__(self, *make_args):
|
||||
# Check that QEMU is not currently running
|
||||
try:
|
||||
GDBClient(self.get_gdb_port(), timeout=0).close()
|
||||
except socket.error:
|
||||
pass
|
||||
else:
|
||||
print("""\
|
||||
GDB stub found on port %d.
|
||||
QEMU appears to already be running. Please exit it if possible or use
|
||||
'killall qemu' or 'killall qemu.real'.""" % self.get_gdb_port(), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if options.verbose:
|
||||
show_command(("make",) + make_args)
|
||||
cmd = ("make", "-s", "--no-print-directory") + make_args
|
||||
self.proc = Popen(cmd, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
stdin=subprocess.PIPE)
|
||||
# Accumulated output as a string
|
||||
self.output = ""
|
||||
# Accumulated output as a bytearray
|
||||
self.outbytes = bytearray()
|
||||
self.on_output = []
|
||||
|
||||
@staticmethod
|
||||
def get_gdb_port():
|
||||
if QEMU._GDBPORT is None:
|
||||
p = Popen(["make", "-s", "--no-print-directory", "gdbport"],
|
||||
stdout=subprocess.PIPE)
|
||||
(out, _) = p.communicate()
|
||||
if p.returncode:
|
||||
raise RuntimeError(
|
||||
"Failed to get gdbport: make exited with %d" %
|
||||
p.returncode)
|
||||
QEMU._GDBPORT = int(out)
|
||||
return QEMU._GDBPORT
|
||||
|
||||
def fileno(self):
|
||||
if self.proc:
|
||||
return self.proc.stdout.fileno()
|
||||
|
||||
def handle_read(self):
|
||||
buf = os.read(self.proc.stdout.fileno(), 4096)
|
||||
self.outbytes.extend(buf)
|
||||
self.output = self.outbytes.decode("utf-8", "replace")
|
||||
for callback in self.on_output:
|
||||
callback(buf)
|
||||
if buf == b"":
|
||||
self.wait()
|
||||
return
|
||||
|
||||
def write(self, buf):
|
||||
if isinstance(buf, str):
|
||||
buf = buf.encode('utf-8')
|
||||
self.proc.stdin.write(buf)
|
||||
self.proc.stdin.flush()
|
||||
|
||||
def wait(self):
|
||||
if self.proc:
|
||||
self.proc.wait()
|
||||
self.proc = None
|
||||
|
||||
def kill(self):
|
||||
if self.proc:
|
||||
self.proc.terminate()
|
||||
|
||||
class GDBClient(object):
|
||||
def __init__(self, port, timeout=15):
|
||||
start = time.time()
|
||||
while True:
|
||||
self.sock = socket.socket()
|
||||
try:
|
||||
self.sock.settimeout(1)
|
||||
self.sock.connect(("localhost", port))
|
||||
break
|
||||
except socket.error:
|
||||
if time.time() >= start + timeout:
|
||||
raise
|
||||
self.__buf = ""
|
||||
|
||||
def fileno(self):
|
||||
if self.sock:
|
||||
return self.sock.fileno()
|
||||
|
||||
def handle_read(self):
|
||||
try:
|
||||
data = self.sock.recv(4096).decode("ascii", "replace")
|
||||
except socket.error:
|
||||
data = ""
|
||||
if data == "":
|
||||
self.sock.close()
|
||||
self.sock = None
|
||||
return
|
||||
self.__buf += data
|
||||
|
||||
while True:
|
||||
m = re.search(r"\$([^#]*)#[0-9a-zA-Z]{2}", self.__buf)
|
||||
if not m:
|
||||
break
|
||||
pkt = m.group(1)
|
||||
self.__buf = self.__buf[m.end():]
|
||||
|
||||
if pkt.startswith("T05"):
|
||||
# Breakpoint
|
||||
raise TerminateTest
|
||||
|
||||
def __send(self, cmd):
|
||||
packet = "$%s#%02x" % (cmd, sum(map(ord, cmd)) % 256)
|
||||
self.sock.sendall(packet.encode("ascii"))
|
||||
|
||||
def __send_break(self):
|
||||
self.sock.sendall(b"\x03")
|
||||
|
||||
def close(self):
|
||||
if self.sock:
|
||||
self.sock.close()
|
||||
self.sock = None
|
||||
|
||||
def cont(self):
|
||||
self.__send("c")
|
||||
|
||||
def breakpoint(self, addr):
|
||||
self.__send("Z1,%x,1" % addr)
|
||||
|
||||
|
||||
##################################################################
|
||||
# QEMU test runner
|
||||
#
|
||||
|
||||
__all__ += ["TerminateTest", "Runner"]
|
||||
|
||||
class TerminateTest(Exception):
|
||||
pass
|
||||
|
||||
class Runner():
|
||||
def __init__(self, *default_monitors):
|
||||
self.__default_monitors = default_monitors
|
||||
|
||||
def run_qemu(self, lab_timeout, *monitors, **kw):
|
||||
"""Run a QEMU-based test. monitors should functions that will
|
||||
be called with this Runner instance once QEMU and GDB are
|
||||
started. Typically, they should register callbacks that throw
|
||||
TerminateTest when stop events occur. The target_base
|
||||
argument gives the make target to run. The make_args argument
|
||||
should be a list of additional arguments to pass to make. The
|
||||
timeout argument bounds how long to run before returning."""
|
||||
|
||||
def run_qemu_kw(target_base="qemu", make_args=[], timeout=lab_timeout):
|
||||
return target_base, make_args, timeout
|
||||
target_base, make_args, timeout = run_qemu_kw(**kw)
|
||||
|
||||
# Start QEMU
|
||||
pre_make()
|
||||
self.qemu = QEMU(target_base + "-gdb", *make_args)
|
||||
self.gdb = None
|
||||
|
||||
try:
|
||||
# Wait for QEMU to start or make to fail. This will set
|
||||
# self.gdb if QEMU starts.
|
||||
self.qemu.on_output = [self.__monitor_start]
|
||||
self.__react([self.qemu], timeout=30)
|
||||
self.qemu.on_output = []
|
||||
if self.gdb is None:
|
||||
print("Failed to connect to QEMU; output:")
|
||||
print(self.qemu.output)
|
||||
sys.exit(1)
|
||||
post_make()
|
||||
|
||||
# QEMU and GDB are up
|
||||
self.reactors = [self.qemu, self.gdb]
|
||||
|
||||
# Start monitoring
|
||||
for m in self.__default_monitors + monitors:
|
||||
m(self)
|
||||
|
||||
# Run and react
|
||||
self.gdb.cont()
|
||||
self.__react(self.reactors, timeout)
|
||||
finally:
|
||||
# Shutdown QEMU
|
||||
try:
|
||||
if self.gdb is None:
|
||||
sys.exit(1)
|
||||
self.qemu.kill()
|
||||
self.__react(self.reactors, 5)
|
||||
self.gdb.close()
|
||||
self.qemu.wait()
|
||||
except:
|
||||
print("""\
|
||||
Failed to shutdown QEMU. You might need to 'killall qemu' or
|
||||
'killall qemu.real'.
|
||||
""")
|
||||
raise
|
||||
|
||||
def __monitor_start(self, output):
|
||||
if b"\n" in output:
|
||||
try:
|
||||
self.gdb = GDBClient(self.qemu.get_gdb_port(), timeout=30)
|
||||
raise TerminateTest
|
||||
except socket.error:
|
||||
pass
|
||||
if not len(output):
|
||||
raise TerminateTest
|
||||
|
||||
def __react(self, reactors, timeout):
|
||||
deadline = time.time() + timeout
|
||||
try:
|
||||
while True:
|
||||
timeleft = deadline - time.time()
|
||||
if timeleft < 0:
|
||||
# sys.stdout.write("Timeout! ")
|
||||
sys.stdout.flush()
|
||||
return
|
||||
|
||||
rset = [r for r in reactors if r.fileno() is not None]
|
||||
if not rset:
|
||||
return
|
||||
|
||||
rset, _, _ = select.select(rset, [], [], timeleft)
|
||||
for reactor in rset:
|
||||
reactor.handle_read()
|
||||
except TerminateTest:
|
||||
pass
|
||||
|
||||
def user_test(self, binary, *monitors, **kw):
|
||||
"""Run a user test using the specified binary. Monitors and
|
||||
keyword arguments are as for run_qemu. This runs on a disk
|
||||
snapshot unless the keyword argument 'snapshot' is False."""
|
||||
|
||||
maybe_unlink("obj/kern/init.o", "obj/kern/kernel")
|
||||
if kw.pop("snapshot", True):
|
||||
kw.setdefault("make_args", []).append("QEMUEXTRA+=-snapshot")
|
||||
self.run_qemu(target_base="run-%s" % binary, *monitors, **kw)
|
||||
|
||||
def match(self, *args, **kwargs):
|
||||
"""Shortcut to call assert_lines_match on the most recent QEMU
|
||||
output."""
|
||||
|
||||
return assert_lines_match(self.qemu.output, *args, **kwargs)
|
||||
|
||||
def match_line(self, line_num, *args, **kwargs):
|
||||
"""Shortcut to call assert_lines_match on the most recent QEMU
|
||||
output."""
|
||||
return assert_lines_match_line(line_num, self.qemu.output, *args, **kwargs)
|
||||
|
||||
def make_kernel(self, binary):
|
||||
os.system("./scripts/docker_build.sh %s > tmp.out" % binary)
|
||||
|
||||
def file_match(self, file_name, r):
|
||||
f = open(file_name, 'r')
|
||||
file_text = f.read()
|
||||
lines = file_text.splitlines()
|
||||
good = set()
|
||||
bad = set()
|
||||
isMatch = 0
|
||||
for i, line in enumerate(lines):
|
||||
if r in line:
|
||||
isMatch = 1
|
||||
good.add(i)
|
||||
if isMatch:
|
||||
return
|
||||
# We failed; construct an informative failure message
|
||||
show = set()
|
||||
for lineno in good.union(bad):
|
||||
for offset in range(-2, 3):
|
||||
show.add(lineno + offset)
|
||||
show.update(n for n in range(len(lines) - 1, len(lines)))
|
||||
msg = []
|
||||
last = -1
|
||||
for lineno in sorted(show):
|
||||
if 0 <= lineno < len(lines):
|
||||
if lineno != last + 1:
|
||||
msg.append("...")
|
||||
last = lineno
|
||||
msg.append("%s %s" % (color("red", "BAD ") if lineno in bad else
|
||||
color("green", "GOOD") if lineno in good
|
||||
else " ",
|
||||
lines[lineno]))
|
||||
if last != len(lines) - 1:
|
||||
msg.append("...")
|
||||
if bad:
|
||||
msg.append("unexpected lines in output")
|
||||
msg.append(color("red", "MISSING") + " '%s'" % r)
|
||||
raise AssertionError("\n".join(msg))
|
||||
|
||||
##################################################################
|
||||
# Monitors
|
||||
#
|
||||
|
||||
__all__ += ["save", "stop_breakpoint", "call_on_line", "stop_on_line"]
|
||||
|
||||
def save(path):
|
||||
"""Return a monitor that writes QEMU's output to path. If the
|
||||
test fails, copy the output to path.test-name."""
|
||||
|
||||
def setup_save(runner):
|
||||
f.seek(0)
|
||||
f.truncate()
|
||||
runner.qemu.on_output.append(f.write)
|
||||
get_current_test().on_finish.append(save_on_finish)
|
||||
|
||||
def save_on_finish(fail):
|
||||
f.flush()
|
||||
save_path = path + "." + get_current_test().__name__[5:]
|
||||
if fail:
|
||||
shutil.copyfile(path, save_path)
|
||||
print(" QEMU output saved to %s" % save_path)
|
||||
elif os.path.exists(save_path):
|
||||
os.unlink(save_path)
|
||||
print(" (Old %s failure log removed)" % save_path)
|
||||
|
||||
f = open(path, "wb")
|
||||
return setup_save
|
||||
|
||||
def stop_breakpoint(addr):
|
||||
"""Returns a monitor that stops when addr is reached. addr may be
|
||||
a number or the name of a symbol."""
|
||||
|
||||
def setup_breakpoint(runner):
|
||||
if isinstance(addr, str):
|
||||
addrs = [int(sym[:16], 16) for sym in open("./build/kernel.sym")
|
||||
if sym[19:].strip() == addr]
|
||||
assert len(addrs), "Symbol %s not found" % addr
|
||||
runner.gdb.breakpoint(addrs[0])
|
||||
else:
|
||||
runner.gdb.breakpoint(addr)
|
||||
return setup_breakpoint
|
||||
|
||||
def call_on_line(regexp, callback):
|
||||
"""Returns a monitor that calls 'callback' when QEMU prints a line
|
||||
matching 'regexp'."""
|
||||
|
||||
def setup_call_on_line(runner):
|
||||
buf = bytearray()
|
||||
def handle_output(output):
|
||||
buf.extend(output)
|
||||
while b"\n" in buf:
|
||||
line, buf[:] = buf.split(b"\n", 1)
|
||||
line = line.decode("utf-8", "replace")
|
||||
if re.match(regexp, line):
|
||||
callback(line)
|
||||
runner.qemu.on_output.append(handle_output)
|
||||
return setup_call_on_line
|
||||
|
||||
def stop_on_line(regexp):
|
||||
"""Returns a monitor that stops when QEMU prints a line matching
|
||||
'regexp'."""
|
||||
|
||||
def stop(line):
|
||||
raise TerminateTest
|
||||
return call_on_line(regexp, stop)
|
37
lab2/scripts/linker-aarch64.lds.in
Normal file
37
lab2/scripts/linker-aarch64.lds.in
Normal file
@ -0,0 +1,37 @@
|
||||
#include "../boot/image.h"
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = TEXT_OFFSET;
|
||||
img_start = .;
|
||||
init : {
|
||||
${init_object}
|
||||
}
|
||||
|
||||
. = ALIGN(SZ_16K);
|
||||
|
||||
init_end = ABSOLUTE(.);
|
||||
|
||||
.text KERNEL_VADDR + init_end : AT(init_end) {
|
||||
*(.text*)
|
||||
}
|
||||
|
||||
. = ALIGN(SZ_64K);
|
||||
.data : {
|
||||
*(.data*)
|
||||
}
|
||||
. = ALIGN(SZ_64K);
|
||||
|
||||
.rodata : {
|
||||
*(.rodata*)
|
||||
}
|
||||
_edata = . - KERNEL_VADDR;
|
||||
|
||||
_bss_start = . - KERNEL_VADDR;
|
||||
.bss : {
|
||||
*(.bss*)
|
||||
}
|
||||
_bss_end = . - KERNEL_VADDR;
|
||||
. = ALIGN(SZ_64K);
|
||||
img_end = . - KERNEL_VADDR;
|
||||
}
|
15
lab2/scripts/mm_test_script.sh
Executable file
15
lab2/scripts/mm_test_script.sh
Executable file
@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
cd ./tests/mm
|
||||
cd buddy
|
||||
cmake ./
|
||||
make
|
||||
./test_buddy > buddy.out
|
||||
make clean
|
||||
cd ../
|
||||
cd page_table
|
||||
cmake ./
|
||||
make
|
||||
./test_aarch64_page_table > page_table.out
|
||||
make clean
|
||||
cd ../../../
|
||||
|
2
lab2/scripts/run_docker.sh
Executable file
2
lab2/scripts/run_docker.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
docker run -it --rm -u $(id -u ${USER}):$(id -g ${USER}) -v $(pwd):/chos -w /chos ipads/chcore_builder:v1.0
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user