diff --git a/.cargo/config.toml b/.cargo/config.toml index cc0571f..5d2f920 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -3,4 +3,3 @@ runner = "ostool cargo-test" [build] target = "aarch64-unknown-none" - diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3dbb838..1ffc805 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,15 +16,21 @@ jobs: run: sudo apt update && sudo apt install qemu-system -y - name: Install libudev-dev run: sudo apt update && sudo apt install libudev-dev -y - - name: Install cargo-binutils - run: cargo install cargo-binutils - - name: Install ostool - run: cargo install ostool - - name: Install toolchain run: rustup show - name: Check rust version run: rustc --version --verbose + + - uses: Swatinem/rust-cache@v2 + with: + workspaces: "." + + - name: Install cargo-binutils + run: cargo install cargo-binutils + - name: Install ostool + run: cargo install ostool + - name: Add Target + run: rustup target add aarch64-unknown-none - name: Check code format run: cargo fmt --all -- --check @@ -62,7 +68,7 @@ jobs: - name: Test sparreal-macros if: ${{ always() }} working-directory: crates/sparreal-macros - run: cargo test + run: cargo test --target x86_64-unknown-linux-gnu - name: Test page-table-arm if: ${{ always() }} diff --git a/.gitignore b/.gitignore index 49cba62..33f7630 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ /target -/*.log .project* \ No newline at end of file diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 35410ca..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# 默认忽略的文件 -/shelf/ -/workspace.xml -# 基于编辑器的 HTTP 客户端请求 -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/deployment.xml b/.idea/deployment.xml deleted file mode 100644 index 54f1838..0000000 --- a/.idea/deployment.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project version="4"> - <component name="PublishConfigData" remoteFilesAllowedToDisappearOnAutoupload="false"> - <serverData> - <paths name="Remote Host (1cb00ee0-ef68-4e12-9ae6-73b43003e4c6)"> - <serverdata> - <mappings> - <mapping local="$PROJECT_DIR$" web="/" /> - </mappings> - </serverdata> - </paths> - <paths name="t113"> - <serverdata> - <mappings> - <mapping local="$PROJECT_DIR$" web="/" /> - </mappings> - </serverdata> - </paths> - </serverData> - </component> -</project> \ No newline at end of file diff --git a/.idea/editor.xml b/.idea/editor.xml deleted file mode 100644 index 7b63cd0..0000000 --- a/.idea/editor.xml +++ /dev/null @@ -1,588 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project version="4"> - <component name="BackendCodeEditorSettings"> - <option name="/Default/CodeInspection/GeneratedCode/GeneratedCodeRegions/=Windows_0020Form_0020Designer_0020generated_0020code/@EntryIndexedValue" value="Windows Form Designer generated code" type="string" /> - <option name="/Default/CodeInspection/GeneratedCode/GeneratedCodeRegions/=Windows_0020Form_0020Designer_0020generated_0020code/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/GeneratedCode/GeneratedCodeRegions/=Component_0020Designer_0020generated_0020code/@EntryIndexedValue" value="Component Designer generated code" type="string" /> - <option name="/Default/CodeInspection/GeneratedCode/GeneratedCodeRegions/=Component_0020Designer_0020generated_0020code/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/GeneratedCode/GeneratedCodeRegions/=Designer_0020generated_0020code/@EntryIndexedValue" value="Designer generated code" type="string" /> - <option name="/Default/CodeInspection/GeneratedCode/GeneratedCodeRegions/=Designer_0020generated_0020code/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/GeneratedCode/GeneratedCodeRegions/=Web_0020Form_0020Designer_0020generated_0020code/@EntryIndexedValue" value="Web Form Designer generated code" type="string" /> - <option name="/Default/CodeInspection/GeneratedCode/GeneratedCodeRegions/=Web_0020Form_0020Designer_0020generated_0020code/@EntryIndexRemoved" /> - <option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/EditorConfig/EnableClangFormatSupport/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_BINARY_EXPRESSIONS_CHAIN/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXPRESSION/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_FOR_STMT/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTIPLE_DECLARATION/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_TERNARY/@EntryValue" value="ALIGN_ALL" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_CLASS_DEFINITION/@EntryValue" value="1" type="int" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue" value="2" type="int" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_CODE/@EntryValue" value="2" type="int" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_USER_LINEBREAKS/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SIMPLE_BLOCK_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_PARAMS/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_SEMICOLON/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_SEMICOLON/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_UNARY_OPERATOR/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_ARRAY_ACCESS_BRACKETS/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_METHOD_PARENTHESES/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPECIAL_ELSE_IF_TREATMENT/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_BINARY_OPSIGN/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_TERNARY_OPSIGNS/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TYPE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="END_OF_LINE" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DECLARATION/@EntryValue" value="1" type="int" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DEFINITION/@EntryValue" value="1" type="int" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_INDENTATION/@EntryValue" value="All" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_ARGUMENT/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_PARAMETER/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_ARGUMENT/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_PARAMETER/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_DECLARATIONS/@EntryValue" value="0" type="int" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_ACCESS_SPECIFIERS_FROM_CLASS/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/LINE_BREAK_AFTER_COLON_IN_MEMBER_INITIALIZER_LISTS/@EntryValue" value="ON_SINGLE_LINE" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/MEMBER_INITIALIZER_LIST_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_NAMESPACE_DEFINITIONS_ON_SAME_LINE/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_EXTENDS_COLON/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_EXTENDS_COLON/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_COLON/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_COLON/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_METHOD/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_NESTED_DECLARATOR/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_METHOD/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_METHOD/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_METHOD/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BETWEEN_CLOSING_ANGLE_BRACKETS_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_DECLARATION_PARENTHESES/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_BLOCKS/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_LPAR/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_INVOCATION_LPAR/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_RPAR/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_LPAR/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_DECLARATION_LPAR/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_RPAR/@EntryValue" value="false" type="bool" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_ARGUMENTS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_PARAMETERS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BREAK_TEMPLATE_DECLARATION/@EntryValue" value="LINE_BREAK" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/FREE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="END_OF_LINE_NO_SPACE" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Space" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CONTINUOUS_LINE_INDENT/@EntryValue" value="Double" type="string" /> - <option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TAB_WIDTH/@EntryValue" value="4" type="int" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSmartPointerVsMakeFunction/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionalStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReinterpretCastFromVoidPtr/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConvertingConstructor/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConversionOperator/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDiscardedPostfixOperatorResult/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstValueFunctionReturnType/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeConst/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeStatic/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMayBeConst/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConst/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVariableCanBeMadeConstexpr/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConstPtrOrRef/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPassValueParameterByConstReference/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppThrowExpressionCanBeReplacedWithRethrow/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroConstantCanBeReplacedWithNullptr/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCompileTimeConstantCanBeReplacedWithBooleanConstant/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIfCanBeReplacedByConstexprIf/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IfStdIsConstantEvaluatedCanBeReplaced/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StdIsConstantEvaluatedWillAlwaysEvaluateToConstant/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConstevalIfIsAlwaysConstant/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassCanBeFinal/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStructuredBinding/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseTypeTraitAlias/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAlgorithmWithCount/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseRangeAlgorithm/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseElementsView/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStdSize/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForLoopCanBeReplacedWithWhile/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppJoinDeclarationAndAssignment/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceTieWithStructuredBinding/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceMemsetWithZeroInitialization/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAssociativeContains/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseEraseAlgorithm/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseFamiliarTemplateSyntaxForGenericLambdas/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScope/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScopeInitStatement/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantNamespaceDefinition/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineFunctionDefinitionInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineVariableDefinitionInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionIsNotImplemented/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrivateSpecialMemberFunctionIsNotImplemented/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHiddenFunction/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHidingFunction/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPolymorphicClassWithNonVirtualPublicDestructor/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractClassWithoutSpecifier/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompleteSwitchStatement/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultCaseNotHandledInSwitchStatement/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyErroneousEmptyStatements/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExpressionWithoutSideEffects/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNoDiscardExpression/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionResultShouldBeUsed/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingKeywordThrow/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTypeWithoutTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTemplateWithoutTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppImplicitDefaultConstructorNotAvailable/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeedsConstructorBecauseOfUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedNonStaticDataMember/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRangeBasedForIncompatibleReference/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroValuedExpressionUsedAsNullPointer/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUnintendedObjectSlicing/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorDisambiguatedAsFunction/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionInFinalClass/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMustBePublicVirtualToImplementInterface/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationSpecifierWithoutDeclarators/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEmptyDeclaration/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesLocal/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesUncapturedLocal/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMismatchedClassTags/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUsingResultOfAssignmentAsCondition/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIntegralToPointerConversion/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerToIntegralConversion/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompatiblePointerConversion/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerConversionDropsQualifiers/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStringLiteralToCharPointerConversion/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExceptionSafeResourceAcquisition/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionCallInsideCtor/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractVirtualFunctionCallInCtor/@EntryIndexedValue" value="ERROR" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInvalidLineContinuation/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfBadFormat/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfRiskyFormat/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfMissedArg/@EntryIndexedValue" value="ERROR" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfExtraArg/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatBadCode/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatLegacyCode/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatMixedArgs/@EntryIndexedValue" value="ERROR" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooFewArgs/@EntryIndexedValue" value="ERROR" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooManyArgs/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedEntity/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingIncludeGuard/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenSyntaxError/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUnresolvedReference/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUndocumentedParameter/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeletingVoidPointer/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBooleanIncrementExpression/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedRegisterStorageClassSpecifier/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIdenticalOperandsInBinaryExpression/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEqualOperandsInBinaryExpression/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedefinitionOfDefaultArgumentInOverrideFunction/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnamedNamespaceInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNamesMismatch/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultedSpecialMemberFunctionIsImplicitlyDeleted/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNodiscardFunctionWithoutReturnValue/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantComplexityInComparison/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractFinalClass/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSpecialFunctionWithoutNoexceptSpecification/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnsignedZeroComparison/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterLiteral/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterWideLiteral/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantQualifier/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantAccessSpecifier/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAccessSpecifierWithNoDeclarations/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeyword/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeywordInsideCompoundStatement/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantControlFlowJump/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyStatement/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyDeclaration/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantParentheses/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantLambdaParameterList/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantCastExpression/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHeaderHasBeenAlreadyIncluded/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateArgumentsCanBeDeduced/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateArguments/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticSpecifierOnAnonymousNamespaceMember/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnMemberAllocationFunction/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnThreadLocalLocalVariable/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassAccessSpecifier/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantInlineSpecifier/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConstSpecifier/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBooleanExpressionArgument/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantVoidArgumentList/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantMemberInitializer/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassInitializer/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstParameterInDeclaration/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVolatileParameterInDeclaration/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalFunctionInFinalClass/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalNonOverridingVirtualFunction/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElaboratedTypeSpecifier/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantDereferencingAndTakingAddress/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConditionalExpression/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConditionalExpressionCanBeSimplified/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantExportKeyword/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantZeroInitializerInAggregateInitialization/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUserDefinedLiteralSuffixDoesNotStartWithUnderscore/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassIsIncomplete/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterShadowing/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMutableSpecifierOnReferenceMember/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultInitializationWithNoUserConstructor/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExplicitSpecializationInNonNamespaceScope/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnionMemberOfReferenceType/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedDependentBaseClass/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderIsNotIncluded/@EntryIndexedValue" value="ERROR" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderNotFound/@EntryIndexedValue" value="ERROR" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCoroutineCallResolveError/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAwaiterTypeIsNotClass/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppOutParameterMustBeWritten/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWarningDirective/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticAssertFailure/@EntryIndexedValue" value="ERROR" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEvaluationFailure/@EntryIndexedValue" value="ERROR" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorNeverUsed/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTypeAliasNeverUsed/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConceptNeverUsed/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeverUsed/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnumeratorNeverUsed/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLambdaCaptureNeverUsed/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableWithNonTrivialDtorIsNeverUsed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityAssignedButNoRead/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityUsedOnlyInUnevaluatedContext/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppObjectMemberMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSomeObjectMembersMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorUsedBeforeInitialization/@EntryIndexedValue" value="ERROR" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnusedIncludeDirective/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNotAllPathsReturnValue/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CDeclarationWithImplicitIntType/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionDoesntReturnValue/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReturnNoValueInNonVoidFunction/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCVQualifierCanNotBeAppliedToReference/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDereferenceOperatorLimitExceeded/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForwardEnumDeclarationWithoutUnderlyingType/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaRegionDirective/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaEndRegionDirective/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticDataMemberInUnnamedStruct/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultIsUsedAsIdentifier/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLongFloat/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtReinterpretCastFromNullptr/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtBindingRValueToLvalueReference/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtAddressOfClassRValue/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtDoubleUserConversionInCopyInit/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtCopyElisionInCopyInitDeclarator/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtNotInitializedStaticConstLocalVar/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRemoveRedundantBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceIfStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceForStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceWhileStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceDoStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongIncludesOrder/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongSlashesInIncludeDirective/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceNestedNamespacesStyle/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceTypeAliasCodeStyle/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceFunctionDeclarationStyle/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberInitializersOrder/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingFunctionStyle/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingDestructorStyle/@EntryIndexedValue" value="SUGGESTION" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAuto/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAutoForNumeric/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersPlacement/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersOrder/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnecessaryWhitespace/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTabsAreDisallowed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantConditions/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANullDereference/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANotInitializedField/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALoopConditionNotUpdated/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFADeletedPointer/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAMemoryLeak/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInvalidatedMemory/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesScope/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesFunction/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantParameter/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantFunctionResult/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAArrayIndexOutOfBounds/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableCode/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableFunctionCall/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAEndlessLoop/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInfiniteRecursion/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnusedValue/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreadVariable/@EntryIndexedValue" value="WARNING" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFATimeOver/@EntryIndexedValue" value="HINT" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInconsistentNaming/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StringLiteralTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CommentTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IdentifierTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSmartPointerVsMakeFunction/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCStyleCast/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionalStyleCast/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReinterpretCastFromVoidPtr/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConvertingConstructor/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConversionOperator/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDiscardedPostfixOperatorResult/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstValueFunctionReturnType/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeConst/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeStatic/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMayBeConst/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConst/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVariableCanBeMadeConstexpr/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConstPtrOrRef/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPassValueParameterByConstReference/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppThrowExpressionCanBeReplacedWithRethrow/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroConstantCanBeReplacedWithNullptr/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCompileTimeConstantCanBeReplacedWithBooleanConstant/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIfCanBeReplacedByConstexprIf/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IfStdIsConstantEvaluatedCanBeReplaced/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StdIsConstantEvaluatedWillAlwaysEvaluateToConstant/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConstevalIfIsAlwaysConstant/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassCanBeFinal/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStructuredBinding/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseTypeTraitAlias/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAlgorithmWithCount/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseRangeAlgorithm/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseElementsView/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStdSize/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForLoopCanBeReplacedWithWhile/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppJoinDeclarationAndAssignment/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceTieWithStructuredBinding/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceMemsetWithZeroInitialization/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAssociativeContains/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseEraseAlgorithm/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseFamiliarTemplateSyntaxForGenericLambdas/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScope/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScopeInitStatement/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantNamespaceDefinition/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineFunctionDefinitionInHeaderFile/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineVariableDefinitionInHeaderFile/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionIsNotImplemented/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrivateSpecialMemberFunctionIsNotImplemented/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHiddenFunction/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHidingFunction/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPolymorphicClassWithNonVirtualPublicDestructor/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractClassWithoutSpecifier/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompleteSwitchStatement/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultCaseNotHandledInSwitchStatement/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyErroneousEmptyStatements/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExpressionWithoutSideEffects/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNoDiscardExpression/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionResultShouldBeUsed/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingKeywordThrow/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTypeWithoutTypenameKeyword/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTemplateWithoutTemplateKeyword/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppImplicitDefaultConstructorNotAvailable/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeedsConstructorBecauseOfUninitializedMember/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedNonStaticDataMember/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRangeBasedForIncompatibleReference/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroValuedExpressionUsedAsNullPointer/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUnintendedObjectSlicing/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUninitializedMember/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorDisambiguatedAsFunction/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionInFinalClass/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMustBePublicVirtualToImplementInterface/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationSpecifierWithoutDeclarators/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEmptyDeclaration/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesLocal/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesUncapturedLocal/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMismatchedClassTags/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUsingResultOfAssignmentAsCondition/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIntegralToPointerConversion/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerToIntegralConversion/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompatiblePointerConversion/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerConversionDropsQualifiers/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStringLiteralToCharPointerConversion/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExceptionSafeResourceAcquisition/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionCallInsideCtor/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractVirtualFunctionCallInCtor/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInvalidLineContinuation/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfBadFormat/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfRiskyFormat/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfMissedArg/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfExtraArg/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatBadCode/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatLegacyCode/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatMixedArgs/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooFewArgs/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooManyArgs/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedEntity/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingIncludeGuard/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenSyntaxError/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUnresolvedReference/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUndocumentedParameter/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeletingVoidPointer/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBooleanIncrementExpression/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedRegisterStorageClassSpecifier/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIdenticalOperandsInBinaryExpression/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEqualOperandsInBinaryExpression/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedefinitionOfDefaultArgumentInOverrideFunction/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnamedNamespaceInHeaderFile/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNamesMismatch/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultedSpecialMemberFunctionIsImplicitlyDeleted/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNodiscardFunctionWithoutReturnValue/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantComplexityInComparison/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractFinalClass/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSpecialFunctionWithoutNoexceptSpecification/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnsignedZeroComparison/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterLiteral/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterWideLiteral/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantQualifier/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantAccessSpecifier/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAccessSpecifierWithNoDeclarations/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTypenameKeyword/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateKeyword/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeyword/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeywordInsideCompoundStatement/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantControlFlowJump/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyStatement/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyDeclaration/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantParentheses/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantLambdaParameterList/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantCastExpression/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHeaderHasBeenAlreadyIncluded/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateArgumentsCanBeDeduced/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateArguments/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticSpecifierOnAnonymousNamespaceMember/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnMemberAllocationFunction/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnThreadLocalLocalVariable/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassAccessSpecifier/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantInlineSpecifier/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConstSpecifier/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBooleanExpressionArgument/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantVoidArgumentList/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantMemberInitializer/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassInitializer/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstParameterInDeclaration/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVolatileParameterInDeclaration/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalFunctionInFinalClass/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalNonOverridingVirtualFunction/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElaboratedTypeSpecifier/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantDereferencingAndTakingAddress/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConditionalExpression/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConditionalExpressionCanBeSimplified/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantExportKeyword/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantZeroInitializerInAggregateInitialization/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUserDefinedLiteralSuffixDoesNotStartWithUnderscore/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassIsIncomplete/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterShadowing/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMutableSpecifierOnReferenceMember/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultInitializationWithNoUserConstructor/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExplicitSpecializationInNonNamespaceScope/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnionMemberOfReferenceType/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedDependentBaseClass/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderIsNotIncluded/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderNotFound/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCoroutineCallResolveError/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAwaiterTypeIsNotClass/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppOutParameterMustBeWritten/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWarningDirective/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticAssertFailure/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEvaluationFailure/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorNeverUsed/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTypeAliasNeverUsed/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConceptNeverUsed/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeverUsed/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnumeratorNeverUsed/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLambdaCaptureNeverUsed/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableWithNonTrivialDtorIsNeverUsed/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNeverUsed/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterNeverUsed/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityAssignedButNoRead/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityUsedOnlyInUnevaluatedContext/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMightNotBeInitialized/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppObjectMemberMightNotBeInitialized/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSomeObjectMembersMightNotBeInitialized/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorUsedBeforeInitialization/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnusedIncludeDirective/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNotAllPathsReturnValue/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CDeclarationWithImplicitIntType/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionDoesntReturnValue/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReturnNoValueInNonVoidFunction/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCVQualifierCanNotBeAppliedToReference/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDereferenceOperatorLimitExceeded/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForwardEnumDeclarationWithoutUnderlyingType/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaRegionDirective/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaEndRegionDirective/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticDataMemberInUnnamedStruct/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultIsUsedAsIdentifier/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLongFloat/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtReinterpretCastFromNullptr/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtBindingRValueToLvalueReference/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtAddressOfClassRValue/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtDoubleUserConversionInCopyInit/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtCopyElisionInCopyInitDeclarator/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtNotInitializedStaticConstLocalVar/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRemoveRedundantBraces/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceIfStatementBraces/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceForStatementBraces/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceWhileStatementBraces/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceDoStatementBraces/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongIncludesOrder/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongSlashesInIncludeDirective/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceNestedNamespacesStyle/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceTypeAliasCodeStyle/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceFunctionDeclarationStyle/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberInitializersOrder/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingFunctionStyle/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingDestructorStyle/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAuto/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAutoForNumeric/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersPlacement/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersOrder/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnecessaryWhitespace/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTabsAreDisallowed/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantConditions/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANullDereference/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANotInitializedField/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALoopConditionNotUpdated/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFADeletedPointer/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAMemoryLeak/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInvalidatedMemory/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesScope/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesFunction/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantParameter/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantFunctionResult/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAArrayIndexOutOfBounds/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableCode/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableFunctionCall/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAEndlessLoop/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInfiniteRecursion/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnusedValue/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreadVariable/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFATimeOver/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInconsistentNaming/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StringLiteralTypo/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CommentTypo/@EntryIndexRemoved" /> - <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IdentifierTypo/@EntryIndexRemoved" /> - </component> -</project> \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 42846c7..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project version="4"> - <component name="ProjectModuleManager"> - <modules> - <module fileurl="file://$PROJECT_DIR$/.idea/sparreal-os.iml" filepath="$PROJECT_DIR$/.idea/sparreal-os.iml" /> - </modules> - </component> -</project> \ No newline at end of file diff --git a/.idea/sparreal-os.iml b/.idea/sparreal-os.iml deleted file mode 100644 index f875314..0000000 --- a/.idea/sparreal-os.iml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<module type="CPP_MODULE" version="4"> - <component name="NewModuleRootManager"> - <content url="file://$MODULE_DIR$"> - <sourceFolder url="file://$MODULE_DIR$/app/helloworld/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/crates/arm-gic/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/crates/arm-pl011/examples" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/crates/arm-pl011/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/crates/driver-interface/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/crates/flat_device_tree/examples" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/crates/flat_device_tree/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/crates/page-table-interface/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/crates/page-table/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/crates/sparreal-build/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/crates/sparreal-kernel/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/crates/sparreal-macros/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/crates/sparreal-rt/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/xtask/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/app/simple_test/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/app/simple_test/tests" isTestSource="true" /> - <sourceFolder url="file://$MODULE_DIR$/crates/bare-test-macros/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/crates/bare-test/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/crates/page-table-arm/src" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/crates/page-table-arm/tests" isTestSource="true" /> - <excludeFolder url="file://$MODULE_DIR$/target" /> - </content> - <orderEntry type="inheritedJdk" /> - <orderEntry type="sourceFolder" forTests="false" /> - </component> -</module> \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project version="4"> - <component name="VcsDirectoryMappings"> - <mapping directory="" vcs="Git" /> - </component> -</project> \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 7428ce8..405bd9d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,31 +4,19 @@ // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ - { - "type": "lldb", - "request": "launch", - "name": "xtask", - "cargo": { - "args": [ - "build", - "-p", - "xtask" - ] - }, - "args": ["elf", "kernel/hal/bsp/aarch64/raspi4.toml"] - }, // lldb 不支持 riscv,需要用此配置调试 { "type": "cppdbg", - "name": "KDebug Riscv", + "name": "KDebug cppdbg", "request": "launch", "miDebuggerServerAddress": "localhost:1234", - "program": "${workspaceFolder}/target/riscv64gc-unknown-none-elf/debug/kernel", - "miDebuggerPath": "gdb-multiarch.exe", + "program": "${workspaceFolder}/target/kernel.elf", + "miDebuggerPath": "gdb-multiarch", "cwd": "${workspaceRoot}", + "preLaunchTask": "qemu debug" }, { - "name": "KDebug", + "name": "KDebug lldb", "type": "lldb", "request": "custom", "initCommands": [ @@ -39,7 +27,8 @@ ], "processCreateCommands": [ "gdb-remote localhost:1234" // Connect to the GDB Server - ] + ], + "preLaunchTask": "qemu debug" } ] } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 4c70df0..08ef4fe 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "rust-analyzer.cargo.allTargets": false, - "rust-analyzer.checkOnSave": false, + "rust-analyzer.checkOnSave": true, "rust-analyzer.check.command": "clippy", "lldb.displayFormat": "auto", "lldb.dereferencePointers": true, diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 081b1fa..ce60521 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,12 +1,33 @@ { - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format "version": "2.0.0", "tasks": [ { - "label": "qemu debug", "type": "shell", - "command": "cargo xtask -d" + "label": "qemu debug", + "command": "ostool", + "args": [ + "run", + "qemu", + "-d" + ], + + "options": { + "cwd": "${workspaceFolder}", + }, + "problemMatcher": { + "base": "$rustc", + "background": { + "activeOnStart": true, + "beginsPattern": "^.*", + "endsPattern": "^qemu-system.*" + } + }, + "group": { + "kind": "test", + "isDefault": true + }, + "detail": "断点调试 test 测试用例", + "isBackground": true, } ] } \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index bad733c..bbc13be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,26 @@ dependencies = [ "tock-registers", ] +[[package]] +name = "abi-singleton" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbdf894742ece5360a74aa8278c42e0f305aa9f7c35d43ebc9cceca105f7e434" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "ansi_rgb" version = "0.2.0" @@ -20,6 +40,62 @@ dependencies = [ "rgb", ] +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +dependencies = [ + "anstyle", + "once_cell", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" + [[package]] name = "arm-gic-driver" version = "0.3.1" @@ -46,6 +122,21 @@ dependencies = [ "tock-registers", ] +[[package]] +name = "arm_pl031" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13696b1c2b59992f4223e0ae5bb173c81c63039367ca90eee845346ad2a13421" +dependencies = [ + "chrono", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "autocfg" version = "1.4.0" @@ -54,17 +145,18 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "bare-test" -version = "0.2.0" +version = "0.3.1" dependencies = [ "bare-test-macros", "log", + "sparreal-kernel", "sparreal-macros", "sparreal-rt", ] [[package]] name = "bare-test-macros" -version = "0.0.1" +version = "0.2.0" dependencies = [ "proc-macro2", "quote", @@ -73,9 +165,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "buddy_system_allocator" @@ -86,11 +178,36 @@ dependencies = [ "spin", ] +[[package]] +name = "byte-unit" +version = "5.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cd29c3c585209b0cbc7309bfe3ed7efd8c84c21b7af29c8bfae908f8777174" +dependencies = [ + "rust_decimal", + "utf8-width", +] + [[package]] name = "bytemuck" -version = "1.20.0" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" + +[[package]] +name = "chrono" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +dependencies = [ + "num-traits", +] + +[[package]] +name = "colorchoice" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "dma-api" @@ -100,10 +217,11 @@ checksum = "13029088ff130c8eb6a35ff20410ebed5f6750507681bf3d90f74ba97032a407" [[package]] name = "driver-interface" -version = "0.0.1" +version = "0.2.0" dependencies = [ "embedded-io", "futures", + "log", ] [[package]] @@ -133,11 +251,34 @@ dependencies = [ "syn", ] +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "fdt-parser" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5234fbedee2700b63a66aca1c368f2ae09a9632b55015e6a4e91af20fab12bf5" +checksum = "0deb230715aa771c49f2eda04e5532a34acccbf31335885d9bd4e3cebee8dac0" [[package]] name = "futures" @@ -205,9 +346,31 @@ name = "helloworld" version = "0.1.0" dependencies = [ "log", + "sparreal-kernel", "sparreal-rt", ] +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + [[package]] name = "lock_api" version = "0.4.12" @@ -220,9 +383,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" + +[[package]] +name = "memchr" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memory_addr" @@ -230,6 +399,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f769efcf10b9dfb4c913bebb409cda77b1a3f072b249bf5465e250bcb30eb49" +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "once_cell" version = "1.20.2" @@ -242,23 +420,31 @@ version = "0.1.0" dependencies = [ "aarch64-cpu", "bitflags", + "env_logger", + "log", ] [[package]] name = "page-table-generic" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7021c5181b020f777dfd4b0ae239d2f4954323c88c810e657a8f9ab8c475b68" +checksum = "734d342878ce1fd65c53078b17bc30adfb22e753c1bbe8f205d818837e9410f8" dependencies = [ "bitflags", "log", ] +[[package]] +name = "pasts" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efcd36303871fb977a47dabc9af736c75c492bb32a92fa26262b2741531e97ce" + [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -268,22 +454,51 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "rgb" version = "0.8.50" @@ -293,6 +508,16 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "rust_decimal" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" +dependencies = [ + "arrayvec", + "num-traits", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -301,7 +526,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "simple_test" -version = "0.1.0" +version = "0.6.2" dependencies = [ "bare-test", "bare-test-macros", @@ -310,24 +535,32 @@ dependencies = [ [[package]] name = "sparreal-kernel" -version = "0.1.7" +version = "0.6.2" dependencies = [ "ansi_rgb", + "anyhow", "buddy_system_allocator", + "byte-unit", + "dma-api", "driver-interface", "fdt-parser", + "lazy_static", "lock_api", "log", + "memory_addr", "page-table-generic", + "pasts", "rgb", "sparreal-macros", - "spin_on", + "spin", + "thiserror", ] [[package]] name = "sparreal-macros" -version = "0.0.5" +version = "0.6.2" dependencies = [ + "abi-singleton", "proc-macro2", "quote", "syn", @@ -335,19 +568,18 @@ dependencies = [ [[package]] name = "sparreal-rt" -version = "0.2.0" +version = "0.6.2" dependencies = [ "aarch64-cpu", "arm-gic-driver", "arm-pl011-rs", + "arm_pl031", "bitflags", + "buddy_system_allocator", "dma-api", - "driver-interface", - "embedded-io", "fdt-parser", "futures", "log", - "memory_addr", "page-table-arm", "page-table-generic", "sparreal-kernel", @@ -375,15 +607,35 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.90" +version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "thiserror" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tock-registers" version = "0.9.0" @@ -395,3 +647,88 @@ name = "unicode-ident" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "utf8-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml index 6387d14..1d16e6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,38 +1,17 @@ [workspace] -resolver = "2" -members = ["app/helloworld", "app/simple_test", "crates/*"] +resolver = "3" +members = ["app/*", "crates/*"] + +[workspace.package] +version = "0.6.2" +edition = "2024" [workspace.dependencies] -embedded-hal = "1.0" -nb = "1.1" -embedded-hal-nb = "1.0" -embedded-hal-async = "1.0" -embedded-io = "0.6.1" -log = { version = "0.4" } -colored = "2.1" -clap = { version = "4.5" } -ansi_rgb = { version = "0.2" } -rgb = "0.8.47" -memory_addr = "0.3" -toml = "0.8" -serde = { default-features = false, version = "1", features = [ - "alloc", - "derive", -] } -tock-registers = "0.9" -goblin = "0.9" -lock_api = "0.4" -futures = { version = "0.3", default-features = false } -sparreal-kernel = { path = "crates/sparreal-kernel" } sparreal-rt = { path = "crates/sparreal-rt" } sparreal-macros = { path = "crates/sparreal-macros" } +sparreal-kernel = { path = "crates/sparreal-kernel" } page-table-arm = { path = "crates/page-table-arm" } driver-interface = { path = "crates/driver-interface" } bare-test = { path = "crates/bare-test" } bare-test-macros = { path = "crates/bare-test-macros" } -arm-gic-driver = "0.3" -arm-pl011-rs = "0.2" - -[workspace.package] -version = "0.1.0" -edition = "2021" +log = "0.4" diff --git a/app/helloworld/Cargo.toml b/app/helloworld/Cargo.toml index 3ad36ba..6496f23 100644 --- a/app/helloworld/Cargo.toml +++ b/app/helloworld/Cargo.toml @@ -1,8 +1,9 @@ [package] name = "helloworld" version = "0.1.0" -edition = "2021" +edition.workspace = true [dependencies] -sparreal-rt = { workspace = true, features = ["early-print"]} +sparreal-rt = { workspace = true, features = ["early-print"] } +sparreal-kernel = { workspace = true } log = { workspace = true } diff --git a/app/helloworld/src/main.rs b/app/helloworld/src/main.rs index 1a4418c..1de8794 100644 --- a/app/helloworld/src/main.rs +++ b/app/helloworld/src/main.rs @@ -1,22 +1,40 @@ #![no_std] #![no_main] +extern crate alloc; + +use core::time::Duration; use alloc::string::ToString; use log::info; +use sparreal_kernel::{ + task::{self, TaskConfig}, + time::{self, spin_delay}, +}; +use sparreal_rt::prelude::*; -extern crate alloc; -extern crate sparreal_rt; - -#[sparreal_rt::entry] +#[entry] fn main() { - info!("hello world"); - let s = "hello world".to_string(); - let st = s.as_str(); + info!("Hello, world!"); + + time::after(Duration::from_secs(1), || { + info!("Timer callback"); + // shutdown(); + }); - // unsafe { - // let a = *(0xffff_ffff_ffff_ffff as *const u8); - // sparreal_rt::println!("{:x}", a); - // } + task::spawn_with_config( + || { + info!("task2"); + }, + TaskConfig { + name: "task2".to_string(), + priority: 0, + stack_size: 0x1000 * 4, + }, + ) + .unwrap(); - assert_eq!(st, "hello world"); + loop { + spin_delay(Duration::from_secs(1)); + info!("123"); + } } diff --git a/app/simple_test/Cargo.toml b/app/simple_test/Cargo.toml index 7babf7b..3f22d08 100644 --- a/app/simple_test/Cargo.toml +++ b/app/simple_test/Cargo.toml @@ -9,3 +9,8 @@ log = { workspace = true } [build-dependencies] bare-test-macros = { workspace = true } + + +[[test]] +name = "test1" +harness = false diff --git a/app/simple_test/tests/test1.rs b/app/simple_test/tests/test1.rs index 6b7eecf..93c9914 100644 --- a/app/simple_test/tests/test1.rs +++ b/app/simple_test/tests/test1.rs @@ -1,51 +1,19 @@ #![no_std] #![no_main] -#![feature(custom_test_frameworks)] -#![test_runner(bare_test::test_runner)] -#![reexport_test_harness_main = "test_main"] +#![feature(used_with_arg)] -bare_test::test_setup!(); +#[bare_test::tests] +mod tests { -use bare_test::{driver::device_tree::get_device_tree, mem::mmu::iomap, println}; + use bare_test::*; + use globals::{PlatformInfoKind, global_val}; -#[test_case] -fn it_works2() { - // non-panic assert_eq! - macro_rules! assert_eq { - ($left:expr, $right:expr $(,)?) => { - if $left != $right { ::log::error!("{} ≠ {}", $left, $right); } + #[test] + fn test2() { + let _fdt = match &global_val().platform_info { + PlatformInfoKind::DeviceTree(fdt) => fdt.get(), }; - ($left:expr, $right:expr, $($arg:tt)+) => { - if $left != $right { - ::log::error!("{} ≠ {}", $left, $right); - ::log::error!($($arg)+); - } - }; - } - println!("test2... "); - assert_eq!(1, 2, "Not eq on purpose."); -} - -#[test_case] -#[allow(clippy::eq_op)] -fn it_works1() { - println!("test1... "); - assert_eq!(1, 1); -} - -#[test_case] -fn test_uart() { - // map uart data register for using. - let uart_data_reg = iomap(0x9000000.into(), 0x1000); - - let _fdt = get_device_tree().unwrap(); - - // write to uart, then it will be print to the screen. - unsafe { - uart_data_reg.write_volatile(b'A'); - uart_data_reg.write_volatile(b'\n'); + assert_eq!(2 + 2, 4) } - - println!("uart test passed!"); } diff --git a/crates/bare-test-macros/Cargo.toml b/crates/bare-test-macros/Cargo.toml index 34c6c6f..1b3b81f 100644 --- a/crates/bare-test-macros/Cargo.toml +++ b/crates/bare-test-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bare-test-macros" -version = "0.0.1" +version = "0.2.0" edition = "2021" license = "MIT" description = "macros for bare-test" diff --git a/crates/bare-test-macros/src/lib.rs b/crates/bare-test-macros/src/lib.rs index d5f473d..2322045 100644 --- a/crates/bare-test-macros/src/lib.rs +++ b/crates/bare-test-macros/src/lib.rs @@ -6,38 +6,88 @@ extern crate proc_macro2; extern crate syn; use proc_macro::TokenStream; +use syn::{parse, spanned::Spanned, Item, ItemMod}; -/// Setup the test entry point. -/// # Example -/// -///```rust -///#![no_std] -///#![no_main] -///#![feature(custom_test_frameworks)] -///#![test_runner(bare_test::test_runner)] -///#![reexport_test_harness_main = "test_main"] -/// -///bare_test::test_setup!(); -///``` #[proc_macro] -pub fn test_setup(_input: TokenStream) -> TokenStream { +pub fn build_test_setup(_input: TokenStream) -> TokenStream { quote! { - - #[bare_test::entry] - fn main() { - test_main(); + println!("cargo::rustc-link-arg-tests=-Ttest_case_link.ld"); + println!("cargo::rustc-link-arg-tests=-no-pie"); + println!("cargo::rustc-link-arg-tests=-znostart-stop-gc"); } + .into() +} +#[proc_macro_attribute] +pub fn tests(args: TokenStream, input: TokenStream) -> TokenStream { + match tests_impl(args, input) { + Ok(tokens) => tokens, + Err(e) => e.to_compile_error().into(), } - .into() } -#[proc_macro] -pub fn build_test_setup(_input: TokenStream) -> TokenStream { - quote! { - println!("cargo::rustc-link-arg-tests=-Tlink.x"); - println!("cargo::rustc-link-arg-tests=-no-pie"); - println!("cargo::rustc-link-arg-tests=-znostart-stop-gc"); +fn tests_impl(_args: TokenStream, input: TokenStream) -> Result<TokenStream, parse::Error> { + let krate = format_ident!("bare_test"); + let module: ItemMod = syn::parse(input)?; + + let ident = &module.ident; + + let mut untouched_tokens = vec![]; + let mut test_functions = vec![]; + let span = module.span(); + + let items = &module + .content + .ok_or(parse::Error::new( + span, + "module must be inline (e.g. `mod foo {}`)", + ))? + .1; + + for item in items { + match item { + Item::Fn(f) => { + if f.attrs.iter().any(|attr| attr.path().is_ident("test")) { + let f_name = &f.sig.ident; + let _f_name = format_ident!("__{}", f.sig.ident); + let block = &f.block; + let static_name = format_ident!("__TEST_{}", f_name.to_string().to_uppercase()); + let f_name_str = f_name.to_string(); + + test_functions.push(quote! { + #[test] + fn #f_name() { + #_f_name() + } + + fn #_f_name() { + #block + } + + #[used(linker)] + #[unsafe(link_section = ".test_case")] + static #static_name: #krate::TestCase = #krate::TestCase { + name: #f_name_str, + test_fn: #_f_name, + }; + }); + } else { + untouched_tokens.push(item); + } + } + _ => { + untouched_tokens.push(item); + } + } } - .into() + + Ok(quote!( + #[cfg(test)] + mod #ident{ + #(#untouched_tokens)* + #(#test_functions)* + + } + ) + .into()) } diff --git a/crates/bare-test/Cargo.toml b/crates/bare-test/Cargo.toml index d83b9de..bee9ec5 100644 --- a/crates/bare-test/Cargo.toml +++ b/crates/bare-test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bare-test" -version = "0.2.0" +version = "0.3.1" authors = ["Zhourui <zrufo747@outlook.com>"] edition = "2021" repository = "https://github.com/qclic/sparreal-os/tree/main/crates/bare-test" @@ -10,10 +10,13 @@ keywords = ["test", "case", "testing", "testcase", "unittest"] categories = ["development-tools", "development-tools::testing"] [features] -build = [] +default = ["rt"] +# 使用 `sparreal-rt` 作为运行时 +rt = ["dep:sparreal-rt"] [dependencies] -sparreal-rt = { version = "0.2", path = "../sparreal-rt" } -sparreal-macros = { version = "0.0.5", path = "../sparreal-macros" } -bare-test-macros = { version = "0.0.1", path = "../bare-test-macros" } +sparreal-rt = { version = "0.6", path = "../sparreal-rt", optional = true } +sparreal-kernel = { version = "0.6", path = "../sparreal-kernel" } +sparreal-macros = { version = "0.6", path = "../sparreal-macros" } +bare-test-macros = { version = "0.2", path = "../bare-test-macros" } log = { version = "0.4" } diff --git a/crates/bare-test/README.md b/crates/bare-test/README.md index f3cdea9..ccf5085 100644 --- a/crates/bare-test/README.md +++ b/crates/bare-test/README.md @@ -23,60 +23,50 @@ A test framework for testing the bare metal. ```toml [dev-dependencies] - bare-test = "0.0.1" + bare-test = "0.2" [build-dependencies] - sparreal-macros = "0.0.1" + bare-test-macros = "0.2" + + [[test]] + name = "test" + harness = false ``` 4. setup `build.rs`. ```rust fn main() { - sparreal_macros::build_test_setup!(); + bare_test_macros::build_test_setup!(); } ``` -5. new `tests` dir and add `tests.rs`. +5. new `tests` dir and add `test.rs`. ```rust #![no_std] #![no_main] - #![feature(custom_test_frameworks)] - #![test_runner(bare_test::test_runner)] - #![reexport_test_harness_main = "test_main"] + #![feature(used_with_arg)] - extern crate bare_test; + #[bare_test::tests] + mod tests { - #[bare_test::entry] - fn main() { - test_main(); - } - - use bare_test::println; - #[test_case] - fn it_not_works() { - println!("test2... "); - assert_eq!(1, 2); - } - #[test_case] - fn it_works1() { - println!("test1... "); - assert_eq!(1, 1); - } - #[test_case] - fn test_uart(){ - // map uart data register for using. - let uart_data_reg = iomap(0x9000000.into(), 0x1000); - - // write to uart, then it will be print to the screen. - unsafe{ - uart_data_reg.write_volatile(b'A'); - uart_data_reg.write_volatile(b'\n'); + #[test] + fn it_works() { + assert_eq!(2 + 2, 4) } - println!("uart test passed!"); + #[test] + fn test2() { + assert_eq!(2 + 2, 4) + } } ``` -6. run `cargo test --test tests -- --show-output`. +6. run `cargo test --test test -- --show-output`. + +7. for uboot board test: + +```sh +cargo test --test tests -- --show-output --uboot +``` diff --git a/crates/bare-test/build.rs b/crates/bare-test/build.rs new file mode 100644 index 0000000..ea53461 --- /dev/null +++ b/crates/bare-test/build.rs @@ -0,0 +1,11 @@ +use std::{fs, path::PathBuf}; + +fn main() { + let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); + let link = "test_case_link.ld"; + + let _ = fs::copy("link.ld", out_dir.join(link)); + + println!("cargo:rustc-link-search={}", out_dir.display()); + println!("cargo:rerun-if-changed=test_case_link.ld"); +} diff --git a/crates/bare-test/link.ld b/crates/bare-test/link.ld new file mode 100644 index 0000000..d7c9cac --- /dev/null +++ b/crates/bare-test/link.ld @@ -0,0 +1,14 @@ +INCLUDE link.x + +SECTIONS +{ + .test_case : ALIGN(4) + { + _stest_case = .; + *(.test_case) + *(.test_case.*) + _etest_case = .; + } + /* 其他段定义 */ +} +INSERT AFTER .rodata; \ No newline at end of file diff --git a/crates/bare-test/src/lib.rs b/crates/bare-test/src/lib.rs index 664807f..7a231e5 100644 --- a/crates/bare-test/src/lib.rs +++ b/crates/bare-test/src/lib.rs @@ -1,26 +1,51 @@ #![no_std] extern crate alloc; -#[cfg(not(feature = "build"))] +extern crate sparreal_kernel; + +#[cfg(feature = "rt")] extern crate sparreal_rt; -#[cfg(not(feature = "build"))] -pub use sparreal_rt::*; +use core::ptr::slice_from_raw_parts; + +pub use bare_test_macros::tests; +pub use sparreal_kernel::prelude::*; +pub use sparreal_kernel::*; + +mod test_case; + +#[sparreal_macros::entry] +fn main() -> ! { + println!("begin test"); -pub use bare_test_macros::test_setup; + for test in test_case_list() { + println!("Run test: {}", test.name); -#[cfg(feature = "build")] -pub use sparreal_macros::build_test_setup; + (test.test_fn)(); -#[cfg(not(feature = "build"))] -pub fn test_runner(tests: &[&dyn Fn()]) { - pub use sparreal_rt::println; - println!("Running {} tests", tests.len()); - for (i, test) in tests.iter().enumerate() { - println!("[test {} start]", i); - test(); - println!("[test {} passed]", i); + println!("test {} passed", test.name); } + println!("All tests passed"); - shutdown() +} + +#[repr(C)] +#[derive(Clone)] +pub struct TestCase { + pub name: &'static str, + pub test_fn: fn(), +} + +fn test_case_list() -> test_case::Iter<'static> { + unsafe extern "C" { + fn _stest_case(); + fn _etest_case(); + } + + let data = _stest_case as usize as *const u8; + let len = _etest_case as usize - _stest_case as usize; + + let list = test_case::ListRef::from_raw(unsafe { &*slice_from_raw_parts(data, len) }); + + list.iter() } diff --git a/crates/bare-test/src/test_case.rs b/crates/bare-test/src/test_case.rs new file mode 100644 index 0000000..ad41f4d --- /dev/null +++ b/crates/bare-test/src/test_case.rs @@ -0,0 +1,53 @@ +use core::ptr::slice_from_raw_parts; + +use crate::TestCase; + +#[repr(C)] +pub struct ListRef { + data: *const u8, + len: usize, +} + +impl ListRef { + pub fn from_raw(data: &'static [u8]) -> Self { + Self { + data: data.as_ptr() as _, + len: data.len(), + } + } + + pub fn iter(&self) -> Iter<'static> { + Iter::new(unsafe { core::slice::from_raw_parts(self.data, self.len) }) + } +} + +pub struct Iter<'a> { + data: &'a [u8], + iter: usize, +} + +impl<'a> Iter<'a> { + pub fn new(data: &'a [u8]) -> Self { + Iter { data, iter: 0 } + } +} + +impl Iterator for Iter<'_> { + type Item = TestCase; + + fn next(&mut self) -> Option<Self::Item> { + if self.data.is_empty() { + return None; + } + + let slice = unsafe { + &*slice_from_raw_parts( + self.data.as_ptr() as *const TestCase, + self.data.len() / size_of::<TestCase>(), + ) + }; + let out = slice.get(self.iter).cloned(); + self.iter += 1; + out + } +} diff --git a/crates/driver-interface/Cargo.toml b/crates/driver-interface/Cargo.toml index 83fcd0a..ff9d17b 100644 --- a/crates/driver-interface/Cargo.toml +++ b/crates/driver-interface/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "driver-interface" -version = "0.0.1" +version = "0.2.0" authors = ["Zhourui <zrufo747@outlook.com>"] edition = "2021" repository = "https://github.com/qclic/sparreal-os" @@ -12,3 +12,4 @@ categories = ["embedded", "no-std"] [dependencies] futures = { version = "0.3", default-features = false, features = ["alloc"] } embedded-io = "0.6" +log = "0.4" diff --git a/crates/driver-interface/src/_macro.rs b/crates/driver-interface/src/_macro.rs new file mode 100644 index 0000000..50c9464 --- /dev/null +++ b/crates/driver-interface/src/_macro.rs @@ -0,0 +1,30 @@ +#[macro_export] +macro_rules! custom_type { + ($name:ident, $target:ty, $debug: expr) => { + #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] + #[repr(transparent)] + pub struct $name($target); + + impl From<$target> for $name { + fn from(value: $target) -> Self { + Self(value) + } + } + + impl From<$name> for $target { + fn from(value: $name) -> Self { + value.0 + } + } + + impl Debug for $name { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, $debug, self.0) + } + } + }; + + ($name:ident, $target:ty) => { + $crate::custom_type!($name, $target, "{:?}") + }; +} diff --git a/crates/driver-interface/src/err.rs b/crates/driver-interface/src/err.rs new file mode 100644 index 0000000..809019b --- /dev/null +++ b/crates/driver-interface/src/err.rs @@ -0,0 +1,6 @@ +#[derive(Debug)] +pub enum DriverError { + NotSupported, +} + +pub type DriverResult<T> = core::result::Result<T, DriverError>; diff --git a/crates/driver-interface/src/interrupt_controller.rs b/crates/driver-interface/src/interrupt_controller.rs new file mode 100644 index 0000000..a9db348 --- /dev/null +++ b/crates/driver-interface/src/interrupt_controller.rs @@ -0,0 +1,43 @@ +use core::{error::Error, fmt::Debug}; + +use crate::{custom_type, DriverGeneric, RegAddress}; +use alloc::{boxed::Box, vec::Vec}; + +custom_type!(IrqId, usize, "{:#x}"); +custom_type!(CpuId, usize, "{:#x}"); + +pub type Hardware = Box<dyn Interface>; +pub type ProbeFn = fn(regs: Vec<RegAddress>) -> Hardware; +pub type HardwareCPU = Box<dyn InterfaceCPU>; + +pub trait InterfaceCPU: Send { + fn get_and_acknowledge_interrupt(&mut self) -> Option<IrqId>; + fn end_interrupt(&mut self, irq: IrqId); + fn irq_enable(&mut self, irq: IrqId); + fn irq_disable(&mut self, irq: IrqId); + fn set_priority(&mut self, irq: IrqId, priority: usize); + fn set_trigger(&mut self, irq: IrqId, triger: Trigger); + fn set_bind_cpu(&mut self, irq: IrqId, cpu_list: &[CpuId]); + fn parse_fdt_config(&self, prop_interrupts: &[u32]) -> Result<IrqConfig, Box<dyn Error>>; + fn irq_pin_to_id(&self, pin: usize) -> Result<IrqId, Box<dyn Error>>; +} + +pub trait Interface: DriverGeneric { + fn current_cpu_setup(&self) -> HardwareCPU; +} + +/// The trigger configuration for an interrupt. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Trigger { + EdgeBoth, + EdgeRising, + EdgeFailling, + LevelHigh, + LevelLow, +} + +#[derive(Debug, Clone)] +pub struct IrqConfig { + pub irq: IrqId, + pub trigger: Trigger, +} diff --git a/crates/driver-interface/src/io/mod.rs b/crates/driver-interface/src/io/mod.rs deleted file mode 100644 index 3337104..0000000 --- a/crates/driver-interface/src/io/mod.rs +++ /dev/null @@ -1,41 +0,0 @@ -use core::fmt; - -use alloc::boxed::Box; - -pub type IOError = embedded_io::ErrorKind; -pub type IOResult<T = ()> = Result<T, IOError>; - -pub type BoxWrite = Box<dyn Write>; - -pub trait Write: Send + Sync { - // Required methods - fn write(&mut self, buf: &[u8]) -> IOResult<usize>; - fn flush(&mut self) -> IOResult; - - /// Write an entire buffer into this writer. - /// - /// This function calls `write()` in a loop until exactly `buf.len()` bytes have - /// been written, blocking if needed. - /// - /// If you are using [`WriteReady`] to avoid blocking, you should not use this function. - /// `WriteReady::write_ready()` returning true only guarantees the first call to `write()` will - /// not block, so this function may still block in subsequent calls. - /// - /// This function will panic if `write()` returns `Ok(0)`. - fn write_all(&mut self, mut buf: &[u8]) -> IOResult { - while !buf.is_empty() { - match self.write(buf) { - Ok(0) => panic!("write() returned Ok(0)"), - Ok(n) => buf = &buf[n..], - Err(e) => return Err(e), - } - } - Ok(()) - } -} - -impl fmt::Write for dyn Write { - fn write_str(&mut self, s: &str) -> fmt::Result { - self.write_all(s.as_bytes()).map_err(|_| fmt::Error) - } -} diff --git a/crates/driver-interface/src/irq.rs b/crates/driver-interface/src/irq.rs deleted file mode 100644 index 8c7c3f2..0000000 --- a/crates/driver-interface/src/irq.rs +++ /dev/null @@ -1,28 +0,0 @@ -use alloc::boxed::Box; - -pub use crate::IrqProbeConfig; - -pub trait Driver: super::DriverGeneric { - fn get_and_acknowledge_interrupt(&self) -> Option<usize>; - fn end_interrupt(&self, irq: usize); - fn irq_max_size(&self) -> usize; - fn irq_enable(&mut self, irq: usize); - fn irq_disable(&mut self, irq: usize); - fn current_cpu_setup(&self); - fn set_priority(&mut self, irq: usize, priority: usize); - fn set_trigger(&mut self, irq: usize, triger: Trigger); - fn set_bind_cpu(&mut self, irq: usize, cpu_list: &[u64]); - fn fdt_parse_config(&self, prop_interupt: &[usize]) -> IrqProbeConfig; -} - -pub type BoxDriver = Box<dyn Driver>; - -/// The trigger configuration for an interrupt. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum Trigger { - EdgeBoth, - EdgeRising, - EdgeFailling, - LevelHigh, - LevelLow, -} diff --git a/crates/driver-interface/src/lib.rs b/crates/driver-interface/src/lib.rs index f80c697..cfe7b17 100644 --- a/crates/driver-interface/src/lib.rs +++ b/crates/driver-interface/src/lib.rs @@ -1,111 +1,26 @@ -#![no_std] - -use core::{fmt::Display, ptr::NonNull}; - -use alloc::{ - string::{String, ToString}, - sync::Arc, - vec::Vec, -}; +#![cfg_attr(not(test), no_std)] extern crate alloc; -pub use futures::future::BoxFuture; -use futures::future::LocalBoxFuture; -use irq::Trigger; +use alloc::string::String; -pub mod io; -pub mod irq; +pub(crate) mod _macro; +pub mod interrupt_controller; +mod register; pub mod timer; -pub mod uart; - -pub type DriverResult<T = ()> = Result<T, DriverError>; - -pub trait DriverGeneric: Send + Sync + 'static {} - -#[derive(Clone)] -pub struct Register { - pub name: String, - pub compatible: Vec<&'static str>, - pub kind: DriverKind, - pub probe: Arc<dyn Probe>, -} -impl Register { - pub fn new( - name: &str, - compatible: Vec<&'static str>, - kind: DriverKind, - probe: impl Probe, - ) -> Self { - Register { - name: name.to_string(), - compatible, - kind, - probe: Arc::new(probe), - } - } - - pub fn compatible_matched(&self, compatible: &str) -> bool { - self.compatible.contains(&compatible) - } -} - -#[derive(Default, Clone)] -pub struct ProbeConfig { - pub id: DeviceId, - pub reg: Vec<NonNull<u8>>, - pub irq: Vec<IrqProbeConfig>, - pub clock_freq: Vec<u64>, -} - -#[derive(Clone)] -pub struct IrqProbeConfig { - pub irq: usize, - pub trigger: Trigger, -} - -pub trait Probe: Send + Sync + 'static { - fn probe<'a>(&self, config: ProbeConfig) -> LocalBoxFuture<'a, DriverResult<DriverSpecific>>; -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum DriverKind { - InteruptChip, - Uart, - Timer, -} - -pub enum DriverSpecific { - Uart(uart::BoxDriver), - InteruptChip(irq::BoxDriver), - Timer(timer::BoxDriver), -} - -#[derive(Debug)] -pub enum DriverError { - Init(String), - NotFound, - NoMemory, -} - -#[repr(transparent)] -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct DeviceId(u64); - -impl From<DeviceId> for u64 { - fn from(val: DeviceId) -> Self { - val.0 - } -} +pub use register::*; +pub(crate) mod err; +pub use err::DriverError; +pub use err::DriverResult; +pub use interrupt_controller::IrqConfig; -impl From<u64> for DeviceId { - fn from(value: u64) -> Self { - Self(value) - } +pub trait DriverGeneric: Send { + fn open(&mut self) -> Result<(), String>; + fn close(&mut self) -> Result<(), String>; } -impl Display for DeviceId { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.0) - } +#[derive(Debug, Clone, Copy)] +pub struct RegAddress { + pub addr: usize, + pub size: Option<usize>, } diff --git a/crates/driver-interface/src/register.rs b/crates/driver-interface/src/register.rs new file mode 100644 index 0000000..985f688 --- /dev/null +++ b/crates/driver-interface/src/register.rs @@ -0,0 +1,39 @@ +use crate::{interrupt_controller, timer}; + +#[repr(C)] +#[derive(Clone)] +pub struct DriverRegister { + pub name: &'static str, + pub compatibles: &'static [&'static str], + pub probe: ProbeFnKind, +} + +unsafe impl Send for DriverRegister {} +unsafe impl Sync for DriverRegister {} + +#[derive(Clone)] +pub enum ProbeFnKind { + InterruptController(interrupt_controller::ProbeFn), + Timer(timer::ProbeFn), +} + +#[repr(C)] +pub struct DriverRegisterListRef { + data: *const u8, + len: usize, +} + +impl DriverRegisterListRef { + pub fn from_raw(data: &'static [u8]) -> Self { + Self { + data: data.as_ptr(), + len: data.len(), + } + } + + pub fn as_slice(&self) -> &[DriverRegister] { + unsafe { + core::slice::from_raw_parts(self.data as _, self.len / size_of::<DriverRegister>()) + } + } +} diff --git a/crates/driver-interface/src/timer.rs b/crates/driver-interface/src/timer.rs deleted file mode 100644 index 7536fa8..0000000 --- a/crates/driver-interface/src/timer.rs +++ /dev/null @@ -1,13 +0,0 @@ -use alloc::boxed::Box; - -pub trait Driver: super::DriverGeneric { - fn set_interval(&mut self, ticks: u64); - fn current_ticks(&self) -> u64; - fn tick_hz(&self) -> u64; - fn set_enable(&mut self, enable: bool); - fn set_irq_enable(&mut self, enable: bool); - fn read_irq_status(&self) -> bool; - fn irq_num(&self) -> u64; -} - -pub type BoxDriver = Box<dyn Driver>; diff --git a/crates/driver-interface/src/timer/mod.rs b/crates/driver-interface/src/timer/mod.rs new file mode 100644 index 0000000..e54f213 --- /dev/null +++ b/crates/driver-interface/src/timer/mod.rs @@ -0,0 +1,120 @@ +use core::{ + sync::atomic::{fence, Ordering}, + time::Duration, +}; + +use crate::{interrupt_controller::IrqConfig, DriverGeneric}; +use alloc::{boxed::Box, vec::Vec}; + +mod queue; + +pub type Hardware = Box<dyn Interface>; +pub type ProbeFn = fn(Vec<IrqConfig>) -> Hardware; +pub type HardwareCPU = Box<dyn InterfaceCPU>; +const NANO_PER_SEC: u128 = 1_000_000_000; + +pub trait Interface: Send { + fn get_current_cpu(&mut self) -> Box<dyn InterfaceCPU>; +} + +pub trait InterfaceCPU: DriverGeneric + Sync { + fn set_timeval(&mut self, ticks: u64); + fn current_ticks(&self) -> u64; + fn tick_hz(&self) -> u64; + fn set_irq_enable(&mut self, enable: bool); + fn get_irq_status(&self) -> bool; + fn irq(&self) -> IrqConfig; +} + +pub struct Timer { + timer: HardwareCPU, + q: queue::Queue, +} + +unsafe impl Sync for Timer {} + +impl Timer { + pub fn new(timer: HardwareCPU) -> Self { + Self { + timer, + q: queue::Queue::new(), + } + } + + pub fn enable(&mut self) { + let _ = self.timer.open(); + } + + pub fn since_boot(&self) -> Duration { + self.tick_to_duration(self.timer.current_ticks()) + } + + pub fn after(&mut self, duration: Duration, callback: impl Fn() + 'static) { + let ticks = self.duration_to_tick(duration); + + let event = queue::Event { + interval: None, + at_tick: self.timer.current_ticks() + ticks, + callback: Box::new(callback), + called: false, + }; + + self.add_event(event); + } + + pub fn every(&mut self, duration: Duration, callback: impl Fn() + 'static) { + let ticks = self.duration_to_tick(duration); + + let event = queue::Event { + interval: Some(ticks), + at_tick: self.timer.current_ticks() + ticks, + callback: Box::new(callback), + called: false, + }; + + self.add_event(event); + } + + fn add_event(&mut self, event: queue::Event) { + self.timer.set_irq_enable(false); + fence(Ordering::SeqCst); + + let next_tick = self.q.add_and_next_tick(event); + let v = next_tick - self.timer.current_ticks(); + self.timer.set_timeval(v); + + fence(Ordering::SeqCst); + self.timer.set_irq_enable(true); + } + + pub fn handle_irq(&mut self) { + while let Some(event) = self.q.pop(self.timer.current_ticks()) { + (event.callback)(); + } + + match self.q.next_tick() { + Some(next_tick) => { + self.timer.set_timeval(next_tick); + } + None => { + self.timer.set_irq_enable(false); + } + } + } + + pub fn set_irq_enable(&mut self, enable: bool) { + self.timer.set_irq_enable(enable); + } + + fn tick_to_duration(&self, tick: u64) -> Duration { + Duration::from_nanos((tick as u128 * NANO_PER_SEC / self.timer.tick_hz() as u128) as _) + } + + fn duration_to_tick(&self, duration: Duration) -> u64 { + (duration.as_nanos() * self.timer.tick_hz() as u128 / NANO_PER_SEC) as _ + } + + pub fn irq(&self) -> IrqConfig { + self.timer.irq() + } +} diff --git a/crates/driver-interface/src/timer/queue.rs b/crates/driver-interface/src/timer/queue.rs new file mode 100644 index 0000000..125150d --- /dev/null +++ b/crates/driver-interface/src/timer/queue.rs @@ -0,0 +1,65 @@ +use alloc::{boxed::Box, vec::Vec}; +use core::fmt::Debug; + +#[derive(Debug)] +pub struct Queue { + events: Vec<Event>, +} + +pub struct Event { + pub at_tick: u64, + pub interval: Option<u64>, + pub called: bool, + pub callback: Box<dyn Fn()>, +} + +impl Debug for Event { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Event") + .field("at_tick", &self.at_tick) + .field("interval", &self.interval) + .field("called", &self.called) + .finish() + } +} + +impl Queue { + pub fn new() -> Self { + Self { events: Vec::new() } + } + + pub fn add_and_next_tick(&mut self, event: Event) -> u64 { + self.events.retain(|e| !e.called); + self.events.push(event); + self.events.sort_by(|a, b| a.at_tick.cmp(&b.at_tick)); + self.events[0].at_tick + } + + pub fn next_tick(&self) -> Option<u64> { + for e in self.events.iter() { + if e.called { + continue; + } + + return Some(e.at_tick); + } + None + } + + pub fn pop(&mut self, now: u64) -> Option<&Event> { + for e in self.events.iter_mut() { + if e.called { + continue; + } + if e.at_tick <= now { + if let Some(interval) = e.interval { + e.at_tick += interval; + } else { + e.called = true; + } + return Some(e); + } + } + None + } +} diff --git a/crates/driver-interface/src/uart.rs b/crates/driver-interface/src/uart.rs deleted file mode 100644 index d0e3d3b..0000000 --- a/crates/driver-interface/src/uart.rs +++ /dev/null @@ -1,44 +0,0 @@ -use core::ptr::NonNull; - -use alloc::boxed::Box; - -use crate::io; - -pub trait Driver: super::DriverGeneric + io::Write {} - -pub type BoxDriver = Box<dyn Driver>; - -/// Word length. -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum DataBits { - Bits5, - Bits6, - Bits7, - Bits8, -} - -/// Parity bit. -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum Parity { - None, - Even, - Odd, -} - -/// Stop bits. -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum StopBits { - #[doc = "1 stop bit"] - STOP1, - #[doc = "2 stop bits"] - STOP2, -} - -pub struct Config { - pub reg: NonNull<u8>, - pub baud_rate: u32, - pub clock_freq: u64, - pub data_bits: DataBits, - pub stop_bits: StopBits, - pub parity: Parity, -} diff --git a/crates/page-table-arm/Cargo.toml b/crates/page-table-arm/Cargo.toml index a389e93..07db62a 100644 --- a/crates/page-table-arm/Cargo.toml +++ b/crates/page-table-arm/Cargo.toml @@ -2,7 +2,7 @@ name = "page-table-arm" description = "A library of arm page table" version = "0.1.0" -edition = "2021" +edition = "2024" authors = ["周睿 <zrufo747@outlook.com>"] repository = "https://github.com/qclic/sparreal-os/tree/main/crates/page-table-arm" documentation = "https://docs.rs/page-table-arm" @@ -12,4 +12,9 @@ categories = ["no-std"] [dependencies] bitflags = "2.6" +log = "0.4" aarch64-cpu = "10.0.0" + + +[dev-dependencies] +env_logger = "0.11.5" diff --git a/crates/page-table-arm/src/pte64.rs b/crates/page-table-arm/src/pte64.rs index 0fe59db..81a87a3 100644 --- a/crates/page-table-arm/src/pte64.rs +++ b/crates/page-table-arm/src/pte64.rs @@ -1,5 +1,4 @@ use crate::{MAIRKind, MAIRSetting}; -#[cfg(target_arch = "aarch64")] use aarch64_cpu::registers::*; pub struct MAIRDefault; @@ -7,9 +6,9 @@ pub struct MAIRDefault; impl MAIRDefault { #[cfg(target_arch = "aarch64")] pub const fn mair_value() -> u64 { - // Device-nGnRE memory + // Device-nGnRnE memory use aarch64_cpu::registers::*; - let attr0 = MAIR_EL1::Attr0_Device::nonGathering_nonReordering_EarlyWriteAck.value; + let attr0 = MAIR_EL1::Attr0_Device::nonGathering_nonReordering_noEarlyWriteAck.value; // Normal memory let attr1 = MAIR_EL1::Attr1_Normal_Inner::WriteBack_NonTransient_ReadWriteAlloc.value | MAIR_EL1::Attr1_Normal_Outer::WriteBack_NonTransient_ReadWriteAlloc.value; diff --git a/crates/sparreal-kernel/Cargo.toml b/crates/sparreal-kernel/Cargo.toml index ab7fde8..ad2d6d8 100644 --- a/crates/sparreal-kernel/Cargo.toml +++ b/crates/sparreal-kernel/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "sparreal-kernel" -version = "0.1.7" +version.workspace = true authors = ["周睿 <zrufo747@outlook.com>"] -edition = "2021" -repository = "https://github.com/qclic/sparreal-os" +edition = "2024" +repository = "https://github.com/ZR233/sparreal-os" license = "MPL-2.0" description = "Sparreal OS kernel" keywords = ["os"] @@ -16,14 +16,18 @@ mmu = [] [dependencies] log = "0.4" buddy_system_allocator = "0.11" -sparreal-macros = { version = "0.0.5", path = "../sparreal-macros" } -# memory_addr = "0.3" -page-table-generic = { version = "0.2" } +sparreal-macros = { version = "0.6", path = "../sparreal-macros" } +driver-interface = { version = "0.2", path = "../driver-interface" } +memory_addr = "0.3" +page-table-generic = { version = "0.3" } fdt-parser = "0.4" lock_api = "0.4" -driver-interface = { version = "0.0.1", path = "../driver-interface" } -# pasts = { version = "0.14", default-features = false } +pasts = { version = "0.14", default-features = false } ansi_rgb = "0.2" rgb = "0.8.47" -# embedded-hal-async = "1.0" -spin_on = "0.1" +spin = "0.9" +anyhow = { version = "1.0", default-features = false } +byte-unit = { version = "5.1", features = ["byte"], default-features = false } +lazy_static = { version = "1.5", features = ["spin_no_std"] } +thiserror = { version = "2", default-features = false } +dma-api = "0.2" \ No newline at end of file diff --git a/crates/sparreal-kernel/src/__export.rs b/crates/sparreal-kernel/src/__export.rs index 8a836e3..5334268 100644 --- a/crates/sparreal-kernel/src/__export.rs +++ b/crates/sparreal-kernel/src/__export.rs @@ -1 +1 @@ -pub use crate::stdout::{debug_hex, early_print_str, print}; +pub use crate::io::print::print; diff --git a/crates/sparreal-kernel/src/async_std/mod.rs b/crates/sparreal-kernel/src/async_std/mod.rs new file mode 100644 index 0000000..077885d --- /dev/null +++ b/crates/sparreal-kernel/src/async_std/mod.rs @@ -0,0 +1 @@ +pub mod time; diff --git a/crates/sparreal-kernel/src/async_std/time.rs b/crates/sparreal-kernel/src/async_std/time.rs new file mode 100644 index 0000000..04f5c05 --- /dev/null +++ b/crates/sparreal-kernel/src/async_std/time.rs @@ -0,0 +1,31 @@ +use core::time::Duration; + +use crate::time::since_boot; + +pub fn sleep(duration: Duration) -> FutureSleep { + let now = since_boot(); + FutureSleep { + wake_at: now + duration, + } +} + +pub struct FutureSleep { + wake_at: Duration, +} + +impl Future for FutureSleep { + type Output = (); + + fn poll( + self: core::pin::Pin<&mut Self>, + cx: &mut core::task::Context<'_>, + ) -> core::task::Poll<Self::Output> { + let now = since_boot(); + if now >= self.wake_at { + core::task::Poll::Ready(()) + } else { + cx.waker().wake_by_ref(); + core::task::Poll::Pending + } + } +} diff --git a/crates/sparreal-kernel/src/boot/debug.rs b/crates/sparreal-kernel/src/boot/debug.rs new file mode 100644 index 0000000..2c4b531 --- /dev/null +++ b/crates/sparreal-kernel/src/boot/debug.rs @@ -0,0 +1,22 @@ +use core::fmt::Write; + +use crate::platform_if::PlatformImpl; + +pub struct DebugWriter; + +impl Write for DebugWriter { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + write_str(s); + Ok(()) + } +} +pub fn write_str(s: &str) { + s.bytes().for_each(|ch| { + PlatformImpl::debug_put(ch); + }); +} + +pub fn print(args: core::fmt::Arguments) { + let mut writer = DebugWriter; + let _ = writer.write_fmt(args); +} diff --git a/crates/sparreal-kernel/src/boot/mmu.rs b/crates/sparreal-kernel/src/boot/mmu.rs new file mode 100644 index 0000000..ec801d0 --- /dev/null +++ b/crates/sparreal-kernel/src/boot/mmu.rs @@ -0,0 +1,45 @@ +use core::sync::atomic::{Ordering, fence}; + +use super::{__start, print_info}; +use crate::{ + globals::global_val, + io::print::*, + mem::{mmu::*, set_va_offset_now}, + platform::PlatformInfoKind, + platform_if::MMUImpl, +}; + +pub fn start( + va_offset: usize, + platform_info: PlatformInfoKind, + rsv_memory: &[BootMemoryRegion], +) -> Result<(), &'static str> { + early_dbgln("Booting up"); + + crate::mem::set_va_offset(va_offset); + unsafe { crate::globals::setup(platform_info)? }; + + print_info(); + + let table = new_boot_table(rsv_memory)?; + + fence(Ordering::SeqCst); + + set_user_table(table); + set_kernel_table(table); + + flush_tlb_all(); + + fence(Ordering::SeqCst); + + let jump_to = __start as usize + va_offset; + let stack_top = global_val().kstack_top.as_usize() + va_offset; + unsafe { set_va_offset_now(va_offset) }; + + early_dbg("Jump to __start: "); + early_dbg_hex(jump_to as _); + early_dbg(", stack top: "); + early_dbg_hexln(stack_top as _); + + MMUImpl::enable_mmu(stack_top, jump_to) +} diff --git a/crates/sparreal-kernel/src/boot/mod.rs b/crates/sparreal-kernel/src/boot/mod.rs new file mode 100644 index 0000000..2f7b5e0 --- /dev/null +++ b/crates/sparreal-kernel/src/boot/mod.rs @@ -0,0 +1,110 @@ +#![allow(unused)] + +use ansi_rgb::{Foreground, orange}; +use log::LevelFilter; + +use crate::{ + driver_manager, + globals::{self, global_val}, + io::{self, print::*}, + irq, + logger::KLogger, + mem::{self, VirtAddr, region, va_offset}, + platform::{self, app_main, module_registers, platform_name, shutdown}, + platform_if::*, + println, task, time, +}; + +pub mod debug; + +#[cfg(feature = "mmu")] +mod mmu; + +#[cfg(feature = "mmu")] +pub use mmu::start; + +#[repr(align(0x10))] +pub extern "C" fn __start() -> ! { + early_dbgln("Relocate success."); + + io::print::stdout_use_debug(); + + mem::init_heap(); + + print_start_msg(); + + let _ = log::set_logger(&KLogger); + log::set_max_level(LevelFilter::Trace); + + PlatformImpl::on_boot_success(); + + mem::init_page_and_memory(); + + unsafe { globals::setup_percpu() }; + + driver_manager::register_drivers(&module_registers()); + + irq::init_main_cpu(); + + time::init_main_cpu(); + + irq::enable_all(); + + task::init(); + + app_main(); + + shutdown() +} + +fn print_info() { + early_dbg("va: "); + early_dbg_hexln(va_offset() as _); + + let regions = crate::platform_if::PlatformImpl::kernel_regions(); + + early_dbg_mem("kernel.text", regions.text.as_slice()); + early_dbg_mem("kernel.data", regions.data.as_slice()); + early_dbg_mem("kernel.bss ", regions.bss.as_slice()); +} + +macro_rules! print_pair { + ($name:expr, $($arg:tt)*) => { + $crate::print!("{:<30}: {}\r\n", $name, format_args!($($arg)*)); + }; +} + +fn print_start_msg() { + println!("{}", LOGO.fg(orange())); + + print_pair!("Version", env!("CARGO_PKG_VERSION")); + print_pair!("Platfrom", "{}", platform_name()); + print_pair!("Kernel Base", "{:p}", region::text().as_ptr()); + + let size = + region::bss().as_ptr_range().end as usize - region::text().as_ptr_range().start as usize; + + print_pair!("Kernel Size", "{:#}", byte_unit::Byte::from_u64(size as _)); + print_pair!( + "Kernel Stack Top", + "{}", + VirtAddr::from(global_val().kstack_top) + ); + + print_pair!("Start CPU", "{:?}", platform::cpu_id()); + + if let Some(debug) = global_val().platform_info.debugcon() { + if let Some(c) = debug.compatibles().next() { + print_pair!("Debug Serial", "{}", c); + } + } +} + +static LOGO: &str = r#" + _____ __ + / ___/ ____ ____ _ _____ _____ ___ ____ _ / / + \__ \ / __ \ / __ `// ___// ___// _ \ / __ `// / + ___/ // /_/ // /_/ // / / / / __// /_/ // / + /____// .___/ \__,_//_/ /_/ \___/ \__,_//_/ + /_/ +"#; diff --git a/crates/sparreal-kernel/src/driver/container.rs b/crates/sparreal-kernel/src/driver/container.rs deleted file mode 100644 index a665820..0000000 --- a/crates/sparreal-kernel/src/driver/container.rs +++ /dev/null @@ -1,169 +0,0 @@ -use super::{ - device_id_by_node_name, device_tree::get_device_tree, DeviceId, DriverIrqChip, DriverTimer, - DriverUart, -}; - -use crate::{driver::device_tree::FDTExtend as _, sync::RwLock}; -use alloc::{ - collections::{btree_map::BTreeMap, btree_set::BTreeSet}, - string::{String, ToString}, - vec::Vec, -}; -use driver_interface::{DriverKind, DriverSpecific, ProbeConfig, Register}; -use log::{error, info}; - -pub(super) static CONTAINER: Container = Container::new(); - -type ContainerKind<T> = RwLock<BTreeMap<DeviceId, T>>; - -const fn new_kind<T>() -> ContainerKind<T> { - RwLock::new(BTreeMap::new()) -} - -pub(super) struct Container { - pub(super) registers: RwLock<BTreeMap<String, Register>>, - probed: RwLock<BTreeSet<DeviceId>>, - pub(super) uart: ContainerKind<DriverUart>, - pub(super) irq_chip: ContainerKind<DriverIrqChip>, - pub(super) timer: ContainerKind<DriverTimer>, -} - -impl Container { - const fn new() -> Self { - Self { - registers: RwLock::new(BTreeMap::new()), - probed: RwLock::new(BTreeSet::new()), - uart: new_kind(), - irq_chip: new_kind(), - timer: new_kind(), - } - } - - pub fn add_driver(&self, id: DeviceId, name: String, spec: DriverSpecific) { - macro_rules! add_to { - ($driver:expr,$field:ident) => { - let d = $crate::driver::DriverCommon::new(id.clone(), name, $driver); - self.$field.write().insert(id, d.into()); - }; - } - - match spec { - DriverSpecific::Uart(driver) => { - add_to!(driver, uart); - } - DriverSpecific::InteruptChip(driver) => { - add_to!(driver, irq_chip); - } - DriverSpecific::Timer(driver) => { - add_to!(driver, timer); - } - } - } -} -pub fn add_driver<N: ToString>(id: DeviceId, name: N, spec: DriverSpecific) { - CONTAINER.add_driver(id, name.to_string(), spec); -} - -pub async fn probe_by_register(register: Register) -> Option<()> { - let fdt = get_device_tree()?; - let node = fdt.find_compatible(®ister.compatible).next()?; - - let config = node.probe_config(); - - probe(config, register).await; - Some(()) -} - -pub async fn probe_by_node(node: fdt_parser::Node<'_>) -> Option<()> { - let id = device_id_by_node_name(node.name); - - if is_probed(&id) { - return Some(()); - } - - let caps = node.compatibles().collect::<Vec<_>>(); - let register = register_by_compatible(&caps)?; - let config = node.probe_config(); - - probe(config, register).await; - Some(()) -} - -pub(crate) fn is_probed(id: &DeviceId) -> bool { - CONTAINER.probed.read().contains(id) -} - -pub async fn probe(config: ProbeConfig, register: Register) -> Option<()> { - let id = config.id; - if is_probed(&id) { - return None; - } - info!("[{}]Probe driver [{}]", id, register.name); - for irq in &config.irq { - info!("[{}] Irq: {}, triger {:?}", id, irq.irq, irq.trigger); - } - - let kind = register - .probe - .probe(config) - .await - .inspect_err(|e| error!("{:?}", e)) - .ok()?; - info!("[{}]Probe success!", id); - - CONTAINER.probed.write().insert(id); - - add_driver(id, register.name, kind); - Some(()) -} - -pub fn uart_list() -> Vec<DriverUart> { - let g = CONTAINER.uart.read(); - g.values().cloned().collect() -} - -pub fn uart_by_id(id: DeviceId) -> Option<DriverUart> { - CONTAINER.uart.read().get(&id).cloned() -} - -pub fn irq_chip_list() -> Vec<DriverIrqChip> { - let g = CONTAINER.irq_chip.read(); - g.values().cloned().collect() -} -pub fn irq_chip_by_id_or_first(id: DeviceId) -> Option<DriverIrqChip> { - let g = CONTAINER.irq_chip.read(); - g.get(&id).or_else(|| g.values().next()).cloned() -} - -pub fn irq_by_id(id: DeviceId) -> Option<DriverIrqChip> { - CONTAINER.irq_chip.read().get(&id).cloned() -} - -pub fn register_append(registers: impl IntoIterator<Item = Register>) { - let mut c = CONTAINER.registers.write(); - for reg in registers { - for cap in ®.compatible { - c.insert(cap.to_string(), reg.clone()); - } - } -} - -pub fn register_by_compatible(compatible: &[&str]) -> Option<Register> { - let c = CONTAINER.registers.read(); - for cap in compatible { - if let Some(reg) = c.get(*cap) { - return Some(reg.clone()); - } - } - None -} - -pub fn register_by_kind(kind: DriverKind) -> Vec<Register> { - let c = CONTAINER.registers.read(); - c.values().filter(|one| one.kind == kind).cloned().collect() -} - -pub fn register_all() -> Vec<Register> { - let c = CONTAINER.registers.read(); - c.values().cloned().collect() -} diff --git a/crates/sparreal-kernel/src/driver/device_tree/mod.rs b/crates/sparreal-kernel/src/driver/device_tree/mod.rs deleted file mode 100644 index fc4f6a1..0000000 --- a/crates/sparreal-kernel/src/driver/device_tree/mod.rs +++ /dev/null @@ -1,92 +0,0 @@ -use core::ptr::NonNull; - -use alloc::{vec, vec::Vec}; -use driver_interface::ProbeConfig; - -use super::{device_id_by_node_name, irq_by_id}; - -// #[link_section = ".data.boot"] -static mut DTB_ADDR: Option<NonNull<u8>> = None; - -pub(crate) unsafe fn set_dtb_addr(addr: Option<NonNull<u8>>) { - DTB_ADDR = addr; -} - -pub fn get_device_tree<'a>() -> Option<fdt_parser::Fdt<'a>> { - unsafe { - let dtb_addr = DTB_ADDR?; - fdt_parser::Fdt::from_ptr(dtb_addr).ok() - } -} -pub trait FDTExtend { - fn interrupt_list(&self) -> Vec<Vec<usize>>; - fn probe_config(&self) -> ProbeConfig; - fn find_clock(&self) -> Vec<u64>; -} - -impl FDTExtend for fdt_parser::Node<'_> { - fn interrupt_list(&self) -> Vec<Vec<usize>> { - let mut ret = Vec::new(); - let info = match self.interrupts() { - Some(i) => i, - None => return Vec::new(), - }; - for itr in info { - let elem = itr.map(|o| o as usize).collect::<Vec<_>>(); - ret.push(elem); - } - ret - } - - fn probe_config(&self) -> ProbeConfig { - let mut config = ProbeConfig { - id: device_id_by_node_name(self.name), - ..Default::default() - }; - - if let Some(regs) = self.reg() { - for reg in regs { - #[cfg(feature = "mmu")] - let reg_base = crate::mem::mmu::iomap( - (reg.address as usize).into(), - reg.size.unwrap_or(0x1000), - ); - #[cfg(not(feature = "mmu"))] - let reg_base = NonNull::new(reg.address as usize as _).unwrap(); - config.reg.push(reg_base); - } - } - - let irq_origin = self.interrupt_list(); - - if let Some(itr_node) = self.interrupt_parent() { - let id = device_id_by_node_name(itr_node.node.name); - if let Some(irq) = irq_by_id(id) { - let g = irq.spec.read(); - - for elem in irq_origin { - config.irq.push(g.fdt_parse_config(&elem)); - } - } - } - - config.clock_freq = self.find_clock(); - - config - } - - fn find_clock(&self) -> Vec<u64> { - if let Some(clk) = self.clock_frequency() { - vec![clk as _] - } else { - let mut out = Vec::new(); - for clk in self.clocks() { - if let Some(freq) = clk.node.clock_frequency() { - out.push(freq as _); - } - } - - out - } - } -} diff --git a/crates/sparreal-kernel/src/driver/id.rs b/crates/sparreal-kernel/src/driver/id.rs deleted file mode 100644 index 87df120..0000000 --- a/crates/sparreal-kernel/src/driver/id.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::sync::RwLock; -use alloc::{ - collections::btree_map::BTreeMap, - string::{String, ToString}, -}; - -pub use driver_interface::DeviceId; - -static MANAGER: RwLock<IdManager> = RwLock::new(IdManager::new()); - -pub fn device_id_by_node_name(name: &str) -> DeviceId { - MANAGER.write().id_by_node_name(name) -} -pub fn device_id_next() -> DeviceId { - let mut g = MANAGER.write(); - g.id_iter += 1; - g.id_iter.into() -} - -struct IdManager { - id_iter: u64, - node_name_id_map: BTreeMap<String, DeviceId>, -} - -impl IdManager { - const fn new() -> Self { - Self { - id_iter: 0, - node_name_id_map: BTreeMap::new(), - } - } - - pub fn id_by_node_name(&mut self, name: &str) -> DeviceId { - *self - .node_name_id_map - .entry(name.to_string()) - .or_insert_with(|| { - self.id_iter += 1; - self.id_iter.into() - }) - } -} diff --git a/crates/sparreal-kernel/src/driver/irq.rs b/crates/sparreal-kernel/src/driver/irq.rs deleted file mode 100644 index 3f8b55a..0000000 --- a/crates/sparreal-kernel/src/driver/irq.rs +++ /dev/null @@ -1,21 +0,0 @@ -pub use driver_interface::irq::*; -use driver_interface::DriverKind; -use log::info; - -use crate::{platform, struct_driver}; - -use super::{irq_chip_list, probe_by_register, register_by_kind}; - -pub(super) async fn init_irq() { - for reg in register_by_kind(DriverKind::InteruptChip) { - let _ = probe_by_register(reg).await; - } - - for chip in irq_chip_list() { - info!("CPU {} IRQ init", unsafe { platform::cpu_id_display() }); - chip.spec.read().current_cpu_setup(); - info!("IRQ chip init success!"); - } -} - -struct_driver!(DriverIrqChip, BoxDriver); diff --git a/crates/sparreal-kernel/src/driver/mod.rs b/crates/sparreal-kernel/src/driver/mod.rs deleted file mode 100644 index 07ede87..0000000 --- a/crates/sparreal-kernel/src/driver/mod.rs +++ /dev/null @@ -1,133 +0,0 @@ -use core::{ - fmt::Display, - ptr::{slice_from_raw_parts, slice_from_raw_parts_mut, NonNull}, -}; - -use alloc::{ - string::{String, ToString}, - sync::{Arc, Weak}, - vec::Vec, -}; -use device_tree::{get_device_tree, FDTExtend}; -use fdt_parser::Fdt; -use irq::init_irq; -use log::info; - -use crate::{ - stdout::{set_stdout, UartWrite}, - sync::RwLock, -}; - -mod container; -pub mod device_tree; -mod id; -mod irq; -mod timer; - -pub use container::*; -pub use driver_interface::uart; -pub use id::*; -pub use irq::DriverIrqChip; -pub use timer::DriverTimer; - -pub async fn init() { - init_irq().await; - init_stdout().await; - info!("Stdout ok!"); - - init_all().await; -} - -pub type DriverArc<T> = Arc<RwLock<T>>; -pub type DriverWeak<T> = Weak<RwLock<T>>; - -#[derive(Debug, Clone)] -pub struct DriverDescriptor { - pub id: DeviceId, - pub name: String, -} - -#[derive(Clone)] -pub(crate) struct DriverCommon<T> { - pub desc: DriverDescriptor, - pub spec: DriverArc<T>, -} -impl<T> DriverCommon<T> { - pub fn new<N: ToString>(id: DeviceId, name: N, spec: T) -> DriverCommon<T> { - Self { - desc: DriverDescriptor { - id, - name: name.to_string(), - }, - spec: Arc::new(RwLock::new(spec)), - } - } -} - -impl Display for DriverDescriptor { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Driver({}) {}", self.id, self.name) - } -} - -#[macro_export(local_inner_macros)] -macro_rules! struct_driver { - ($name:ident, $spec:ty) => { - #[derive(Clone)] - pub struct $name { - pub desc: $crate::driver::DriverDescriptor, - pub spec: $crate::driver::DriverArc<$spec>, - } - impl From<$crate::driver::DriverCommon<$spec>> for $name { - fn from(value: $crate::driver::DriverCommon<$spec>) -> Self { - Self { - desc: value.desc, - spec: value.spec, - } - } - } - }; -} - -pub unsafe fn move_dtb(src: *const u8, mut dst: NonNull<u8>) -> Option<&'static [u8]> { - let fdt = Fdt::from_ptr(NonNull::new_unchecked(src as usize as _)).ok()?; - let size = fdt.total_size(); - let dest = &mut *slice_from_raw_parts_mut(dst.as_mut(), size); - let src = &*slice_from_raw_parts(src, size); - dest.copy_from_slice(src); - Some(dest) -} - -async fn init_stdout() -> Option<()> { - let fdt = get_device_tree()?; - let chosen = fdt.chosen()?; - let stdout = chosen.stdout()?; - let node = stdout.node; - let caps = node.compatibles().collect::<Vec<_>>(); - - let register = register_by_compatible(&caps)?; - let config = node.probe_config(); - let id = config.id; - probe(config, register).await?; - - let driver = uart_by_id(id)?; - - let stdout = UartWrite::new(&driver.spec); - - set_stdout(stdout); - - Some(()) -} - -async fn init_all() { - if let Some(fdt) = get_device_tree() { - for node in fdt - .all_nodes() - .filter(|node| !node.name.contains("memory@")) - { - probe_by_node(node).await; - } - } -} - -struct_driver!(DriverUart, uart::BoxDriver); diff --git a/crates/sparreal-kernel/src/driver/timer.rs b/crates/sparreal-kernel/src/driver/timer.rs deleted file mode 100644 index 3f0ef8f..0000000 --- a/crates/sparreal-kernel/src/driver/timer.rs +++ /dev/null @@ -1,42 +0,0 @@ -use core::time::Duration; - -use alloc::vec::Vec; -pub use driver_interface::timer::*; - -use crate::{ - irq::{irq_set_handle, IrqHandle}, - struct_driver, -}; - -use super::CONTAINER; - -struct_driver!(DriverTimer, BoxDriver); - -#[allow(unused)] -pub fn list() -> Vec<DriverTimer> { - let g = CONTAINER.timer.read(); - g.values().cloned().collect() -} - -impl DriverTimer { - pub fn once_shot(&self, duration: Duration, callback: impl Fn() + 'static) { - let mut timer = self.spec.write(); - let irq = timer.irq_num() as usize; - let t = self.clone(); - - irq_set_handle(irq, self.desc.id, move |_| { - let mut timer = t.spec.write(); - if timer.read_irq_status() { - callback(); - timer.set_irq_enable(false); - IrqHandle::Handled - } else { - IrqHandle::None - } - }); - let ticks = timer.tick_hz() as f64 * duration.as_secs_f64(); - timer.set_interval(ticks as _); - timer.set_enable(true); - timer.set_irq_enable(true); - } -} diff --git a/crates/sparreal-kernel/src/driver_manager/device/descriptor.rs b/crates/sparreal-kernel/src/driver_manager/device/descriptor.rs new file mode 100644 index 0000000..8f62960 --- /dev/null +++ b/crates/sparreal-kernel/src/driver_manager/device/descriptor.rs @@ -0,0 +1,28 @@ +use alloc::string::String; +use core::fmt::Debug; + +use super::irq::IrqInfo; + +custom_id!(DeviceId, u64); +custom_id!(DriverId, u64); + +#[derive(Default, Debug, Clone)] +pub struct Descriptor { + pub device_id: DeviceId, + pub driver_id: DriverId, + pub name: String, + pub irq: Option<IrqInfo>, +} + +macro_rules! impl_driver_id_for { + ($t:ty) => { + impl From<$t> for DriverId { + fn from(value: $t) -> Self { + Self(value as _) + } + } + }; +} + +impl_driver_id_for!(usize); +impl_driver_id_for!(u32); diff --git a/crates/sparreal-kernel/src/driver_manager/device/irq.rs b/crates/sparreal-kernel/src/driver_manager/device/irq.rs new file mode 100644 index 0000000..2fde8be --- /dev/null +++ b/crates/sparreal-kernel/src/driver_manager/device/irq.rs @@ -0,0 +1,81 @@ +use core::ptr::NonNull; + +use alloc::{ + collections::btree_map::BTreeMap, + format, + string::{String, ToString}, + vec::Vec, +}; +pub use driver_interface::interrupt_controller::Hardware; +use driver_interface::{DriverRegister, ProbeFnKind, RegAddress, interrupt_controller::IrqConfig}; +use fdt_parser::Fdt; + +use super::{super::device::Descriptor, Device, DriverId}; + +pub fn init_by_fdt( + registers: &[DriverRegister], + fdt_addr: NonNull<u8>, +) -> Result<Vec<Device<Hardware>>, String> { + let fdt = Fdt::from_ptr(fdt_addr).map_err(|e| format!("{e:?}"))?; + let mut out = Vec::with_capacity(registers.len()); + for r in registers { + if let ProbeFnKind::InterruptController(probe) = r.probe { + let compa = r + .compatibles + .iter() + .filter_map(|e| if e.is_empty() { None } else { Some(*e) }) + .collect::<Vec<_>>(); + for node in fdt.find_compatible(&compa) { + let reg = node + .reg() + .ok_or(format!("[{}] has no reg", node.name))? + .map(|reg| RegAddress { + addr: reg.address as _, + size: reg.size, + }) + .collect(); + let mut irq = probe(reg); + irq.open()?; + let dev = Device::new( + Descriptor { + driver_id: node.phandle().unwrap().as_usize().into(), + name: r.name.to_string(), + ..Default::default() + }, + irq, + ); + + out.push(dev); + } + } + } + Ok(out) +} + +pub struct Container(BTreeMap<DriverId, Device<Hardware>>); + +impl Container { + pub const fn new() -> Self { + Self(BTreeMap::new()) + } + + pub(crate) fn set(&mut self, dev: Device<Hardware>) { + self.0.insert(dev.descriptor.driver_id, dev); + } + + pub(crate) fn set_list(&mut self, dev_list: Vec<Device<Hardware>>) { + for dev in dev_list { + self.set(dev); + } + } + + pub fn list(&self) -> Vec<&Device<Hardware>> { + self.0.values().collect() + } +} + +#[derive(Default, Debug, Clone)] +pub struct IrqInfo { + pub irq_parent: DriverId, + pub cfgs: Vec<IrqConfig>, +} diff --git a/crates/sparreal-kernel/src/driver_manager/device/mod.rs b/crates/sparreal-kernel/src/driver_manager/device/mod.rs new file mode 100644 index 0000000..8064c7b --- /dev/null +++ b/crates/sparreal-kernel/src/driver_manager/device/mod.rs @@ -0,0 +1,119 @@ +use alloc::{ + string::{String, ToString}, + sync::Arc, +}; +use core::{ + cell::UnsafeCell, + fmt::Debug, + ops::{Deref, DerefMut}, +}; + +mod descriptor; +pub mod irq; +pub mod timer; + +pub use descriptor::*; +use spin::Mutex; + +use super::DriverError; + +#[derive(Clone)] +pub struct Device<T> { + pub descriptor: Descriptor, + lock: Arc<Mutex<Lock>>, + data: Arc<UnsafeCell<T>>, +} + +unsafe impl<T> Send for Device<T> {} + +impl<T> Debug for Device<T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Device") + .field("device_id", &self.descriptor.device_id) + .field("driver_id", &self.descriptor.driver_id) + .field("name", &self.descriptor.name) + .field("irq_configs", &self.descriptor.irq) + .finish() + } +} + +struct Lock { + who_using: Option<String>, +} + +impl<T> Device<T> { + pub fn new(descriptor: Descriptor, data: T) -> Self { + Device { + descriptor, + data: Arc::new(UnsafeCell::new(data)), + lock: Arc::new(Mutex::new(Lock { who_using: None })), + } + } + + pub fn try_use_by(&self, who: impl ToString) -> Result<BorrowGuard<T>, DriverError> { + let descriptor = self.descriptor.clone(); + let lock = self.lock.clone(); + let mut g = self.lock.lock(); + if let Some(ref who) = g.who_using { + return Err(DriverError::UsedByOthers(who.to_string())); + } + g.who_using = Some(who.to_string()); + let data = self.data.clone(); + Ok(BorrowGuard { + lock, + descriptor, + data, + }) + } + + pub fn spin_try_use(&self, who: impl ToString) -> BorrowGuard<T> { + loop { + if let Ok(g) = self.try_use_by(who.to_string()) { + return g; + } + } + } + + /// 强制获取设备 + /// + /// # Safety + /// 一般用于中断处理中 + pub unsafe fn force_use(&self) -> *mut T { + self.data.get() + } +} + +impl<T: Sync> Deref for Device<T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.data.get() } + } +} + +pub struct BorrowGuard<T> { + pub descriptor: Descriptor, + lock: Arc<Mutex<Lock>>, + data: Arc<UnsafeCell<T>>, +} + +impl<T> Deref for BorrowGuard<T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.data.get() } + } +} + +impl<T> DerefMut for BorrowGuard<T> { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.data.get() } + } +} + +impl<T> Drop for BorrowGuard<T> { + fn drop(&mut self) { + let mut g = self.lock.lock(); + g.who_using = None; + } +} diff --git a/crates/sparreal-kernel/src/driver_manager/device/timer/mod.rs b/crates/sparreal-kernel/src/driver_manager/device/timer/mod.rs new file mode 100644 index 0000000..1cc4472 --- /dev/null +++ b/crates/sparreal-kernel/src/driver_manager/device/timer/mod.rs @@ -0,0 +1,79 @@ +use core::ptr::NonNull; + +use alloc::{ + format, + string::{String, ToString}, + vec::Vec, +}; +use driver_interface::{DriverRegister, ProbeFnKind, timer::*}; +use fdt_parser::Fdt; +use log::debug; + +use crate::prelude::GetIrqConfig; + +use super::{Descriptor, Device}; + +pub struct Container { + data: Option<Device<Hardware>>, +} + +impl Container { + pub const fn new() -> Self { + Self { data: None } + } + + pub fn set(&mut self, device: Device<Hardware>) { + self.data = Some(device); + } + + pub fn get_cpu_timer(&self) -> Option<Device<Timer>> { + if let Some(device) = self.data.as_ref() { + loop { + if let Ok(mut d) = device.try_use_by("cpu") { + let p = d.get_current_cpu(); + let mut desc = d.descriptor.clone(); + desc.device_id = Default::default(); + return Some(Device::new(desc, Timer::new(p))); + } + } + } + + None + } +} + +pub fn init_by_fdt( + registers: &[DriverRegister], + fdt_addr: NonNull<u8>, +) -> Result<Device<Hardware>, String> { + let fdt = Fdt::from_ptr(fdt_addr).map_err(|e| format!("{e:?}"))?; + for r in registers { + if let ProbeFnKind::Timer(probe) = r.probe { + let compa = r + .compatibles + .iter() + .filter_map(|e| if e.is_empty() { None } else { Some(*e) }) + .collect::<Vec<_>>(); + for node in fdt.find_compatible(&compa) { + let irq = match node.irq_info() { + Some(irq) => irq, + None => continue, + }; + + let timer = probe(irq.cfgs.clone()); + debug!("[{}] ok", r.name); + let dev = Device::new( + Descriptor { + name: r.name.to_string(), + irq: Some(irq), + ..Default::default() + }, + timer, + ); + + return Ok(dev); + } + } + } + Err("No timer found".into()) +} diff --git a/crates/sparreal-kernel/src/driver_manager/err.rs b/crates/sparreal-kernel/src/driver_manager/err.rs new file mode 100644 index 0000000..662c6d9 --- /dev/null +++ b/crates/sparreal-kernel/src/driver_manager/err.rs @@ -0,0 +1,8 @@ +use alloc::string::String; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum DriverError { + #[error("Already used by `{0}`")] + UsedByOthers(String), +} diff --git a/crates/sparreal-kernel/src/driver_manager/id.rs b/crates/sparreal-kernel/src/driver_manager/id.rs new file mode 100644 index 0000000..194bf28 --- /dev/null +++ b/crates/sparreal-kernel/src/driver_manager/id.rs @@ -0,0 +1,25 @@ +macro_rules! custom_id { + ($name:ident, $target:ty) => { + #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] + #[repr(transparent)] + pub struct $name($target); + + impl From<$target> for $name { + fn from(value: $target) -> Self { + Self(value) + } + } + + impl From<$name> for $target { + fn from(value: $name) -> Self { + value.0 + } + } + + impl Debug for $name { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self.0) + } + } + }; +} diff --git a/crates/sparreal-kernel/src/driver_manager/mod.rs b/crates/sparreal-kernel/src/driver_manager/mod.rs new file mode 100644 index 0000000..572b317 --- /dev/null +++ b/crates/sparreal-kernel/src/driver_manager/mod.rs @@ -0,0 +1,78 @@ +use alloc::{string::String, vec::Vec}; +use core::ptr::NonNull; +use device::{ + BorrowGuard, + irq::{self}, + timer, +}; +use log::warn; + +pub use driver_interface::DriverRegister; +use driver_interface::interrupt_controller; +use spin::{Mutex, MutexGuard}; + +#[macro_use] +mod id; + +pub mod device; +mod err; + +pub use err::*; + +static MANAGER: Mutex<DeviceManager> = Mutex::new(DeviceManager::new()); + +pub struct DeviceManager { + registers: Vec<DriverRegister>, + pub irq_chip: device::irq::Container, + pub timer: device::timer::Container, +} + +impl DeviceManager { + const fn new() -> Self { + Self { + registers: Vec::new(), + irq_chip: device::irq::Container::new(), + timer: device::timer::Container::new(), + } + } +} + +pub fn init_irq_chips_by_fdt(fdt_addr: NonNull<u8>) -> Result<(), String> { + let dev_list = irq::init_by_fdt(®isters(), fdt_addr)?; + manager().irq_chip.set_list(dev_list); + Ok(()) +} + +pub fn init_timer_by_fdt(fdt_addr: NonNull<u8>) -> Result<(), String> { + let timer = timer::init_by_fdt(®isters(), fdt_addr)?; + manager().timer.set(timer); + Ok(()) +} + +pub fn manager() -> MutexGuard<'static, DeviceManager> { + MANAGER.lock() +} + +pub fn register_drivers(drivers: &[DriverRegister]) { + manager().registers.extend(drivers.iter().cloned()); +} + +fn registers() -> Vec<DriverRegister> { + manager().registers.clone() +} + +pub fn use_irq_chips_by(who: &str) -> Vec<BorrowGuard<interrupt_controller::Hardware>> { + manager() + .irq_chip + .list() + .into_iter() + .map(|v| v.try_use_by(who)) + .filter_map(|d| match d { + Ok(v) => Some(v), + Err(e) => { + warn!("{}", e); + None + } + }) + .collect() +} diff --git a/crates/sparreal-kernel/src/executor/mod.rs b/crates/sparreal-kernel/src/executor/mod.rs deleted file mode 100644 index 6d7bf51..0000000 --- a/crates/sparreal-kernel/src/executor/mod.rs +++ /dev/null @@ -1,45 +0,0 @@ -// use core::hint::spin_loop; -// use core::ptr; -// use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; - -// use pasts::prelude::*; - -// pub fn init_exeutor() { -// unsafe { -// EXECUTOR = Some(Executor::default()); -// } -// } - -// fn executor() -> &'static Executor { -// unsafe { EXECUTOR.as_ref().unwrap() } -// } - -// pub fn block_on(f: impl Future<Output = ()> + 'static) { -// Executor::default().block_on(f); -// } - -// pub fn spawn_boxed(f: impl Future<Output = ()> + 'static) { -// executor().spawn_boxed(f) -// } - -// static VTABLE: RawWakerVTable = RawWakerVTable::new( -// |_| RawWaker::new(ptr::null(), &VTABLE), -// |_| {}, -// |_| {}, -// |_| {}, -// ); - -// pub fn block_on<F: Future>(mut fut: F) -> F::Output { -// // safety: we don't move the future after this line. -// let mut fut = unsafe { Pin::new_unchecked(&mut fut) }; - -// let raw_waker = RawWaker::new(ptr::null(), &VTABLE); -// let waker = unsafe { Waker::from_raw(raw_waker) }; -// let mut cx = Context::from_waker(&waker); -// loop { -// if let Poll::Ready(res) = fut.as_mut().poll(&mut cx) { -// return res; -// } -// spin_loop(); -// } -// } diff --git a/crates/sparreal-kernel/src/fdt.rs b/crates/sparreal-kernel/src/fdt.rs deleted file mode 100644 index 472ce2d..0000000 --- a/crates/sparreal-kernel/src/fdt.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub use fdt_parser::*; - -use crate::driver::device_tree::get_device_tree; - -pub fn device_tree<'a>() -> Option<Fdt<'a>> { - get_device_tree() -} diff --git a/crates/sparreal-kernel/src/globals/mod.rs b/crates/sparreal-kernel/src/globals/mod.rs new file mode 100644 index 0000000..287e360 --- /dev/null +++ b/crates/sparreal-kernel/src/globals/mod.rs @@ -0,0 +1,137 @@ +#![allow(unused)] + +use core::{ + cell::UnsafeCell, + ops::Range, + sync::atomic::{AtomicBool, Ordering}, +}; + +use alloc::collections::btree_map::BTreeMap; +use driver_interface::interrupt_controller::CpuId; +use percpu::PerCPU; + +pub use crate::platform::PlatformInfoKind; +use crate::{ + mem::PhysAddr, + platform::{self, cpu_list}, +}; + +mod percpu; + +pub struct GlobalVal { + pub platform_info: PlatformInfoKind, + pub kstack_top: PhysAddr, + pub main_memory: Range<PhysAddr>, + percpu: BTreeMap<CpuId, percpu::PerCPU>, +} + +struct LazyGlobal { + g_ok: AtomicBool, + cpu_ok: AtomicBool, + g: UnsafeCell<Option<GlobalVal>>, +} + +unsafe impl Sync for LazyGlobal {} + +static GLOBAL: LazyGlobal = LazyGlobal::new(); + +pub fn global_val() -> &'static GlobalVal { + global_val_meybeuninit().expect("GlobalVal is not init!") +} + +pub fn global_val_meybeuninit() -> Option<&'static GlobalVal> { + if !GLOBAL.g_ok.load(Ordering::SeqCst) { + return None; + } + Some(unsafe { (*GLOBAL.g.get()).as_ref().unwrap() }) +} + +impl LazyGlobal { + const fn new() -> Self { + Self { + g_ok: AtomicBool::new(false), + cpu_ok: AtomicBool::new(false), + g: UnsafeCell::new(None), + } + } +} + +/// 修改全局变量 +/// +/// # Safty +/// 只能在其他CPU启动前调用 +pub(crate) unsafe fn edit(f: impl FnOnce(&mut GlobalVal)) { + unsafe { + let global = (*GLOBAL.g.get()).as_mut().unwrap(); + f(global); + } +} + +unsafe fn get_mut() -> &'static mut GlobalVal { + unsafe { (*GLOBAL.g.get()).as_mut().unwrap() } +} + +/// # Safty +/// 只能在其他CPU启动前调用 +pub(crate) unsafe fn setup(platform_info: PlatformInfoKind) -> Result<(), &'static str> { + let main_memory = platform_info + .main_memory() + .ok_or("No memory in platform info")?; + + let g = GlobalVal { + platform_info, + kstack_top: main_memory.end, + main_memory, + percpu: Default::default(), + }; + + unsafe { + GLOBAL.g.get().write(Some(g)); + GLOBAL.g_ok.store(true, Ordering::SeqCst); + + match &mut get_mut().platform_info { + PlatformInfoKind::DeviceTree(fdt) => { + fdt.setup()?; + } + } + } + Ok(()) +} + +/// #Safty +/// 需要在内存初始化完成之后调用 +pub(crate) unsafe fn setup_percpu() { + let cpus = cpu_list(); + let g = unsafe { get_mut() }; + for cpu in cpus { + let percpu = PerCPU::default(); + g.percpu.insert(cpu.cpu_id, percpu); + } + GLOBAL.cpu_ok.store(true, Ordering::SeqCst); +} + +pub(crate) fn cpu_global() -> &'static PerCPU { + cpu_global_meybeuninit().expect("CPU global is not init!") +} + +pub(crate) fn cpu_global_meybeuninit() -> Option<&'static PerCPU> { + if !GLOBAL.cpu_ok.load(Ordering::SeqCst) { + return None; + } + + let g = unsafe { get_mut() }; + Some(g.percpu.get(&platform::cpu_id()).unwrap()) +} + +pub(crate) unsafe fn cpu_global_mut() -> &'static mut PerCPU { + unsafe { cpu_global_mut_meybeunint().expect("CPU global is not init!") } +} + +pub(crate) unsafe fn cpu_global_mut_meybeunint() -> Option<&'static mut PerCPU> { + if !GLOBAL.cpu_ok.load(Ordering::SeqCst) { + return None; + } + + let g = unsafe { get_mut() }; + Some(g.percpu.get_mut(&platform::cpu_id()).unwrap()) +} diff --git a/crates/sparreal-kernel/src/globals/percpu.rs b/crates/sparreal-kernel/src/globals/percpu.rs new file mode 100644 index 0000000..4946693 --- /dev/null +++ b/crates/sparreal-kernel/src/globals/percpu.rs @@ -0,0 +1,7 @@ +use crate::{irq, time::TimerData}; + +#[derive(Default)] +pub struct PerCPU { + pub irq_chips: irq::CpuIrqChips, + pub timer: TimerData, +} diff --git a/crates/sparreal-kernel/src/io/mod.rs b/crates/sparreal-kernel/src/io/mod.rs new file mode 100644 index 0000000..f6380ae --- /dev/null +++ b/crates/sparreal-kernel/src/io/mod.rs @@ -0,0 +1 @@ +pub mod print; diff --git a/crates/sparreal-kernel/src/io/print.rs b/crates/sparreal-kernel/src/io/print.rs new file mode 100644 index 0000000..2d665e6 --- /dev/null +++ b/crates/sparreal-kernel/src/io/print.rs @@ -0,0 +1,76 @@ +use core::fmt; + +use alloc::boxed::Box; +use spin::Mutex; + +use crate::{boot::debug, platform_if::PlatformImpl}; + +static STDOUT: Mutex<Option<Box<dyn fmt::Write + Send>>> = Mutex::new(None); + +pub fn stdout_use_debug() { + *STDOUT.lock() = Some(Box::new(debug::DebugWriter {})); +} + +pub fn print(args: fmt::Arguments<'_>) { + let mut g = STDOUT.lock(); + + if let Some(ref mut writer) = *g { + let _ = writer.write_fmt(args); + } +} + +pub fn early_dbg(s: &str) { + for c in s.bytes() { + PlatformImpl::debug_put(c); + } +} + +pub fn early_dbgln(s: &str) { + early_dbg(s); + early_dbg("\r\n"); +} + +pub fn early_dbg_hexln(v: u64) { + early_dbg_hex(v); + early_dbg("\r\n"); +} +pub fn early_dbg_mem(name: &str, mem: &[u8]) { + let range = mem.as_ptr_range(); + early_dbg_range(name, (range.start as usize)..(range.end as usize)); +} +pub fn early_dbg_range(name: &str, range: core::ops::Range<usize>) { + early_dbg(name); + early_dbg(": ["); + early_dbg_hex(range.start as _); + early_dbg(", "); + early_dbg_hex(range.end as _); + early_dbg(")\r\n"); +} + +pub fn early_dbg_hex(v: u64) { + const HEX_BUF_SIZE: usize = 20; // 最大长度,包括前缀"0x"和数字 + let mut hex_buf: [u8; HEX_BUF_SIZE] = [b'0'; HEX_BUF_SIZE]; + let mut n = v; + early_dbg("0x"); + + if n == 0 { + early_dbg("0"); + return; + } + let mut i = 0; + while n > 0 { + let digit = n & 0xf; + let ch = if digit < 10 { + b'0' + digit as u8 + } else { + b'a' + (digit - 10) as u8 + }; + n >>= 4; // 右移四位 + hex_buf[i] = ch; + i += 1; + } + let s = &hex_buf[..i]; + for ch in s.iter().rev() { + PlatformImpl::debug_put(*ch); + } +} diff --git a/crates/sparreal-kernel/src/irq/mod.rs b/crates/sparreal-kernel/src/irq/mod.rs index 550d3d2..44d6935 100644 --- a/crates/sparreal-kernel/src/irq/mod.rs +++ b/crates/sparreal-kernel/src/irq/mod.rs @@ -1,148 +1,242 @@ -use alloc::{collections::btree_map::BTreeMap, sync::Arc, vec::Vec}; -use driver_interface::{irq::Trigger, DeviceId}; -use log::{debug, info, warn}; +use core::{cell::UnsafeCell, error::Error}; + +use alloc::{boxed::Box, collections::btree_map::BTreeMap, vec::Vec}; +use driver_interface::interrupt_controller::*; +use log::{debug, error, warn}; +use spin::Mutex; use crate::{ - driver::{irq_chip_by_id_or_first, irq_chip_list, DriverIrqChip}, - platform, - sync::RwLock, + driver_manager::{ + self, + device::{Device, DriverId}, + }, + globals::{self, cpu_global, global_val}, + platform::{self}, + platform_if::PlatformImpl, }; +pub use driver_manager::device::irq::IrqInfo; -type Handler = Arc<dyn Fn(usize) -> IrqHandle>; +#[derive(Default)] +pub struct CpuIrqChips(BTreeMap<DriverId, Chip>); -static IRQ_VECTOR: RwLock<Vector> = RwLock::new(Vector::new()); +pub type IrqHandler = dyn Fn(IrqId) -> IrqHandleResult; -struct VectorPerIrq(BTreeMap<DeviceId, Handler>); -struct VectorPerCpu(BTreeMap<usize, VectorPerIrq>); -struct Vector(BTreeMap<usize, VectorPerCpu>); +pub struct Chip { + device: Device<HardwareCPU>, + mutex: Mutex<()>, + handlers: UnsafeCell<BTreeMap<IrqId, Box<IrqHandler>>>, +} -unsafe impl Send for Vector {} -unsafe impl Sync for Vector {} +unsafe impl Send for Chip {} +unsafe impl Sync for Chip {} -#[allow(unused)] -impl Vector { - const fn new() -> Self { - Self(BTreeMap::new()) - } +pub fn enable_all() { + PlatformImpl::irq_all_enable(); +} - fn insert(&mut self, cpu_id: usize, irq_num: usize, dev_id: DeviceId, handler: Handler) { - self.0 - .entry(cpu_id) - .or_insert(VectorPerCpu(BTreeMap::new())) - .0 - .entry(irq_num) - .or_insert(VectorPerIrq(BTreeMap::new())) - .0 - .insert(dev_id, handler); +pub(crate) fn init_main_cpu() { + match &global_val().platform_info { + crate::globals::PlatformInfoKind::DeviceTree(fdt) => { + if let Err(e) = driver_manager::init_irq_chips_by_fdt(fdt.get_addr()) { + error!("{}", e); + } + } } - fn remove(&mut self, cpu_id: usize, irq_num: usize, dev_id: DeviceId) { - self.0 - .get_mut(&cpu_id) - .and_then(|one| one.0.get_mut(&irq_num)) - .and_then(|one| one.0.remove(&dev_id)); - } + init_current_cpu(); +} + +pub(crate) fn init_current_cpu() { + let chip = driver_manager::use_irq_chips_by("Kernel IRQ init"); + let g = unsafe { globals::cpu_global_mut() }; + + for c in chip { + let id = c.descriptor.driver_id; + let device = c.current_cpu_setup(); + debug!( + "[{}]({id:?}) Init cpu: {:?}", + c.descriptor.name, + platform::cpu_id(), + ); + + let device = Device::new(c.descriptor.clone(), device); - fn get_handle_stack(&self, irq_num: usize) -> Vec<Handler> { - let cpu_id = unsafe { platform::cpu_id() } as usize; - self.0 - .get(&cpu_id) - .and_then(|map| map.0.get(&irq_num)) - .map(|map| map.0.values().cloned().collect::<Vec<_>>()) - .unwrap_or_default() + g.irq_chips.0.insert(id, Chip { + device, + mutex: Mutex::new(()), + handlers: UnsafeCell::new(Default::default()), + }); } } -fn vector_cpu_set_handle(cpu_id: usize, irq_num: usize, dev_id: DeviceId, handler: Handler) { - IRQ_VECTOR.write().insert(cpu_id, irq_num, dev_id, handler); +pub enum IrqHandleResult { + Handled, + None, +} + +fn chip(id: DriverId) -> &'static Chip { + globals::cpu_global() + .irq_chips + .0 + .get(&id) + .unwrap_or_else(|| panic!("irq chip {:?} not found", id)) } -pub fn irq_set_handle( - irq_num: usize, - dev_id: DeviceId, - handler: impl Fn(usize) -> IrqHandle + 'static, -) { - let handler = Arc::new(handler); - vector_cpu_set_handle(unsafe { platform::cpu_id() } as _, irq_num, dev_id, handler); + +pub fn fdt_parse_config( + irq_parent: DriverId, + prop_interrupts: &[u32], +) -> Result<IrqConfig, Box<dyn Error>> { + unsafe { &*chip(irq_parent).device.force_use() }.parse_fdt_config(prop_interrupts) } -pub enum IrqHandle { - Handled, - None, +pub struct IrqRegister { + pub param: IrqParam, + pub handler: Box<IrqHandler>, + pub priority: Option<usize>, + pub cpu_list: Vec<CpuId>, } -#[derive(Debug, Clone)] -pub struct IrqConfig { - pub irq: usize, - pub trigger: Trigger, - pub priority: usize, - pub cpu_list: Vec<u64>, -} -pub fn irq_setup(irq: usize, dev_id: DeviceId, trigger: Trigger) { - //TODO - let controller_id = DeviceId::default(); - - if let Some(chip) = irq_chip_by_id_or_first(controller_id) { - info!( - "[{}]Enable irq {} on chip: {} ", - dev_id, irq, chip.desc.name - ); - let mut c = chip.spec.write(); +impl IrqRegister { + pub fn register(self) { + let irq = self.param.cfg.irq; + let irq_parent = self.param.irq_chip; + debug!("Enable irq {:?} on chip {:?}", irq, irq_parent); + + let chip = chip(irq_parent); + chip.register_handle(irq, self.handler); + + let mut c = chip.device.spin_try_use("register irq"); + if let Some(p) = self.priority { + c.set_priority(irq, p); + } else { + c.set_priority(irq, 0); + } + + if !self.cpu_list.is_empty() { + c.set_bind_cpu(irq, &self.cpu_list); + } + + c.set_trigger(irq, self.param.cfg.trigger); c.irq_enable(irq); - c.set_priority(irq, 0); - c.set_trigger(irq, trigger); + } + + pub fn priority(mut self, priority: usize) -> Self { + self.priority = Some(priority); + self + } + + pub fn cpu_list(mut self, cpu_list: Vec<CpuId>) -> Self { + self.cpu_list = cpu_list; + self } } -pub fn register_irq( - cfg: IrqConfig, - dev_id: DeviceId, - handler: impl Fn(usize) -> IrqHandle + 'static, -) { - irq_set_handle(cfg.irq, dev_id, handler); +impl Chip { + fn register_handle(&self, irq: IrqId, handle: Box<IrqHandler>) { + let g = NoIrqGuard::new(); + let gm = self.mutex.lock(); + unsafe { &mut *self.handlers.get() }.insert(irq, handle); + drop(gm); + drop(g); + } - //TODO - let controller_id = DeviceId::default(); + fn unregister_handle(&self, irq: IrqId) { + let g = NoIrqGuard::new(); + let gm = self.mutex.lock(); + unsafe { &mut *self.handlers.get() }.remove(&irq); + drop(gm); + drop(g); + } - if let Some(chip) = irq_chip_by_id_or_first(controller_id) { - info!( - "[{}]Enable irq {} on chip: {} ", - dev_id, cfg.irq, chip.desc.name - ); - let mut c = chip.spec.write(); - c.irq_enable(cfg.irq); - c.set_priority(cfg.irq, cfg.priority); - c.set_trigger(cfg.irq, cfg.trigger); + fn handle_irq(&self) -> Option<()> { + let chip = unsafe { &mut *self.device.force_use() }; + + let irq = chip.get_and_acknowledge_interrupt()?; + + if let Some(handler) = unsafe { &mut *self.handlers.get() }.get(&irq) { + let res = (handler)(irq); + if let IrqHandleResult::None = res { + return Some(()); + } + } else { + warn!("IRQ {:?} no handler", irq); + } + chip.end_interrupt(irq); + Some(()) + } + + fn pin_to_id(&self, pin: usize) -> Result<IrqId, Box<dyn Error>> { + let chip = unsafe { &*self.device.force_use() }; + chip.irq_pin_to_id(pin) } } -fn get_chip() -> Option<DriverIrqChip> { - irq_chip_list().first().cloned() +pub struct NoIrqGuard { + is_enabled: bool, } -pub fn handle_irq() { - if let Some(chip) = get_chip() { - let c = chip.spec.read(); +impl NoIrqGuard { + pub fn new() -> Self { + let is_enabled = PlatformImpl::irq_all_is_enabled(); + PlatformImpl::irq_all_disable(); + Self { is_enabled } + } +} - let irq_id = c.get_and_acknowledge_interrupt(); - if let Some(irq_id) = irq_id { - handle_irq_by_id(irq_id); - c.end_interrupt(irq_id); +impl Default for NoIrqGuard { + fn default() -> Self { + Self::new() + } +} + +impl Drop for NoIrqGuard { + fn drop(&mut self) { + if self.is_enabled { + enable_all(); } } } -fn handle_irq_by_id(irq_id: usize) { - debug!("irq {}", irq_id); - let stack = { IRQ_VECTOR.read().get_handle_stack(irq_id) }; +pub fn handle_irq() { + for chip in cpu_global().irq_chips.0.values() { + chip.handle_irq(); + } +} - for handler in stack { - match handler(irq_id) { - IrqHandle::Handled => { - return; - } - IrqHandle::None => {} +#[derive(Debug, Clone)] +pub struct IrqParam { + pub irq_chip: DriverId, + pub cfg: IrqConfig, +} + +impl IrqParam { + pub fn new_pin(pin: usize, irq_chip: DriverId) -> Result<Self, Box<dyn Error>> { + let chip = chip(irq_chip); + let irq_id = chip.pin_to_id(pin)?; + Ok(Self { + irq_chip, + cfg: IrqConfig { + irq: irq_id, + trigger: Trigger::LevelLow, + }, + }) + } + + pub fn register_builder( + &self, + handler: impl Fn(IrqId) -> IrqHandleResult + 'static, + ) -> IrqRegister { + IrqRegister { + param: self.clone(), + handler: Box::new(handler), + priority: None, + cpu_list: Vec::new(), } } +} - warn!("Irq {} not handled", irq_id); +pub fn unregister_irq(irq: IrqId) { + for chip in cpu_global().irq_chips.0.values() { + chip.unregister_handle(irq); + } } diff --git a/crates/sparreal-kernel/src/kernel.rs b/crates/sparreal-kernel/src/kernel.rs deleted file mode 100644 index 5a1a824..0000000 --- a/crates/sparreal-kernel/src/kernel.rs +++ /dev/null @@ -1,111 +0,0 @@ -use core::ptr::NonNull; - -use driver_interface::Register; -use log::*; - -use page_table_generic::{AccessSetting, CacheSetting}; -use spin_on::spin_on; - -use crate::{ - driver::{self, device_tree::set_dtb_addr}, - logger::KLogger, - mem::{self, *}, - platform::{self, app_main}, - println, - stdout::{self, EarlyDebugWrite}, -}; - -/// 初始化日志和内存 -/// -/// # Safety -/// -/// 1. BSS 应当清零。 -/// 2. 若有MMU,应当已开启,且虚拟地址与代码段映射一致。 -pub unsafe fn init_log_and_memory(kconfig: &KernelConfig) { - set_dtb_addr(kconfig.dtb_addr); - let _ = log::set_logger(&KLogger); - log::set_max_level(LevelFilter::Trace); - stdout::set_stdout(EarlyDebugWrite {}); - info!("Logger initialized."); - - mem::init(kconfig); - - let version = env!("CARGO_PKG_VERSION"); - println!("Welcome to sparreal\nVersion: {version}"); - platform::print_system_info(); -} - -/// 注册驱动 -pub fn driver_register_append(registers: impl IntoIterator<Item = Register>) { - driver::register_append(registers); -} - -/// 运行内核主逻辑 -/// -/// # Safety -/// -/// 需在 [init_log_and_memory] 之后执行,[run] 之前可用 [driver_register_append] 注册驱动。 -pub unsafe fn run() -> ! { - spin_on(async { - driver::init().await; - }); - platform::irqs_enable(); - app_main(); - println!("Waiting for interrupt..."); - loop { - platform::wait_for_interrupt(); - } -} - -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct MemoryRange { - pub start: Phys<u8>, - pub size: usize, -} - -impl MemoryRange { - #[allow(clippy::new_without_default)] - pub const fn new() -> Self { - Self { - start: Phys::new(), - size: 0, - } - } -} - -#[repr(C)] -/// 内核配置 -#[derive(Clone)] -pub struct KernelConfig { - /// 启动配置 - pub boot_info: BootConfig, - /// 栈顶 - pub stack_top: Phys<u8>, - /// 设备树地址 - pub dtb_addr: Option<NonNull<u8>>, -} - -#[derive(Clone)] -pub struct BootConfig { - /// Kernel 所在的内存 - pub main_memory: MemoryRange, - /// 已使用的内存 - pub main_memory_heap_offset: usize, - /// 每核 Kernel sp 大小 - pub hart_stack_size: usize, - /// 需要提前map的内存 - pub reserved_memory: [Option<MemoryReservedRange>; 24], - /// 物理内存和虚拟内存的偏移 - pub va_offset: usize, -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct MemoryReservedRange { - pub name: &'static str, - pub start: Phys<u8>, - pub size: usize, - pub access: AccessSetting, - pub cache: CacheSetting, -} diff --git a/crates/sparreal-kernel/src/lang_items.rs b/crates/sparreal-kernel/src/lang_items.rs index ad7137e..45c1358 100644 --- a/crates/sparreal-kernel/src/lang_items.rs +++ b/crates/sparreal-kernel/src/lang_items.rs @@ -2,14 +2,10 @@ use core::panic::PanicInfo; use log::error; -use crate::platform; +use crate::platform::shutdown; #[panic_handler] fn panic(info: &PanicInfo) -> ! { - error!("{info}"); - - unsafe { - platform::shutdown(); - }; - unreachable!() + error!("kernel panic: {:?}", info); + shutdown() } diff --git a/crates/sparreal-kernel/src/lib.rs b/crates/sparreal-kernel/src/lib.rs index e3de2bc..2b307b9 100644 --- a/crates/sparreal-kernel/src/lib.rs +++ b/crates/sparreal-kernel/src/lib.rs @@ -1,45 +1,25 @@ #![no_std] -#![feature(trait_upcasting)] -#![allow(clippy::missing_safety_doc)] +#![feature(linkage)] +#![feature(fn_align)] extern crate alloc; pub mod __export; -pub mod driver; -pub mod executor; -pub mod fdt; +pub mod boot; +mod driver_manager; +pub mod globals; +pub mod io; + +pub mod async_std; pub mod irq; -pub mod kernel; -#[cfg(all(target_os = "none", not(test)))] mod lang_items; -pub mod logger; +mod logger; pub mod mem; pub mod platform; +pub mod platform_if; pub mod prelude; -pub mod stdout; -pub mod sync; +pub mod task; pub mod time; -pub mod trap; -pub mod util; - -pub use kernel::{KernelConfig, MemoryRange}; -pub use mem::PhysAddr; -pub use platform::Platform; -pub use sparreal_macros::entry; - -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => {{ - $crate::__export::print(format_args!($($arg)*)); - }}; -} -#[macro_export] -macro_rules! println { - () => { - $crate::print!("\n") - }; - ($($arg:tt)*) => {{ - $crate::__export::print(format_args!("{}\r\n", format_args!($($arg)*))); - }}; -} +pub use driver_interface; +pub use mem::Address; diff --git a/crates/sparreal-kernel/src/logger.rs b/crates/sparreal-kernel/src/logger.rs index 5476f28..d2a347c 100644 --- a/crates/sparreal-kernel/src/logger.rs +++ b/crates/sparreal-kernel/src/logger.rs @@ -1,8 +1,6 @@ -use ansi_rgb::{red, yellow, Foreground}; +use ansi_rgb::{Foreground, red, yellow}; use log::{Level, Log}; -use rgb::{Rgb, RGB8}; - -use crate::stdout; +use rgb::{RGB8, Rgb}; fn level_to_rgb(level: Level) -> RGB8 { match level { @@ -24,24 +22,6 @@ fn level_icon(level: Level) -> &'static str { } } -macro_rules! format_record { - ($record:expr, $d: expr) => {{ - format_args!( - "{}", - format_args!( - "{} {:.3?} [{path}:{line}] {args}\r\n", - // "{} [{path}:{line}] {args}\n", - level_icon($record.level()), - $d, - path = $record.target(), - line = $record.line().unwrap_or(0), - args = $record.args() - ) - .fg(level_to_rgb($record.level())) - ) - }}; -} - pub struct KLogger; impl Log for KLogger { @@ -51,9 +31,35 @@ impl Log for KLogger { fn log(&self, record: &log::Record) { if self.enabled(record.metadata()) { + let level = record.level(); + let line = record.line().unwrap_or(0); + let path = record.target(); + let args = record.args(); + let duration = crate::time::since_boot(); - stdout::print(format_record!(record, duration)); + crate::__export::print(format_args!( + "{}", + format_args!( + "{} {duration:<10.3?} [{path}:{line}] {args}\r\n", + level_icon(level), + ) + .fg(level_to_rgb(level)) + )); } } fn flush(&self) {} } + +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => { + $crate::__export::print(format_args!($($arg)*)); + }; +} + +#[macro_export] +macro_rules! println { + ($($arg:tt)*) => { + $crate::print!("{}\r\n", format_args!($($arg)*)); + }; +} diff --git a/crates/sparreal-kernel/src/mem/addr.rs b/crates/sparreal-kernel/src/mem/addr.rs index 6e2063c..4f24b33 100644 --- a/crates/sparreal-kernel/src/mem/addr.rs +++ b/crates/sparreal-kernel/src/mem/addr.rs @@ -1,40 +1,101 @@ -use core::{ - fmt::Display, - ops::{Add, Sub}, -}; +use core::fmt::Display; +use core::marker::PhantomData; +use core::ops::{Add, Sub}; +use core::ptr::NonNull; -#[derive(Clone, Copy)] +use super::va_offset_now; + +#[derive(Debug, Clone, Copy)] +pub struct Address { + pub cpu: usize, + pub virt: Option<usize>, + pub bus: Option<u64>, +} + +impl Address { + pub fn new(cpu: usize, virt: Option<*mut u8>, bus: Option<u64>) -> Self { + Self { + cpu, + virt: virt.map(|s| s as usize), + bus, + } + } + + pub fn as_ptr(&self) -> *const u8 { + match self.virt { + Some(virt) => virt as *const u8, + None => self.cpu as *const u8, + } + } + + pub fn bus(&self) -> u64 { + match self.bus { + Some(bus) => bus, + None => self.cpu as _, + } + } + + pub fn physical(&self) -> usize { + self.cpu + } +} + +impl Add<usize> for Address { + type Output = Self; + + fn add(self, rhs: usize) -> Self::Output { + Self { + cpu: self.cpu + rhs, + virt: self.virt.map(|s| s + rhs), + bus: self.bus.map(|s| s + rhs as u64), + } + } +} + +impl Sub<usize> for Address { + type Output = Self; + + fn sub(self, rhs: usize) -> Self::Output { + Self { + cpu: self.cpu - rhs, + virt: self.virt.map(|s| s - rhs), + bus: self.bus.map(|s| s - rhs as u64), + } + } +} + +#[derive(Clone, Copy, PartialEq, PartialOrd)] #[repr(transparent)] -pub struct Virt<T>(*const T); +pub struct Virt<T>(usize, PhantomData<T>); unsafe impl<T> Send for Virt<T> {} -unsafe impl<T> Sync for Virt<T> {} impl<T> From<*const T> for Virt<T> { fn from(value: *const T) -> Self { - Self(value) + Self(value as _, PhantomData) } } impl<T> From<*mut T> for Virt<T> { fn from(value: *mut T) -> Self { - Self(value as *const T) + Self(value as _, PhantomData) } } +impl<T> From<NonNull<T>> for Virt<T> { + fn from(value: NonNull<T>) -> Self { + Self(value.as_ptr() as _, PhantomData) + } +} + impl<T> From<Virt<T>> for *const T { fn from(value: Virt<T>) -> Self { - value.0 + value.0 as *const T } } -pub type VirtAddr<T = u8> = Virt<T>; +pub type VirtAddr = Virt<u8>; impl<T> Virt<T> { - #[allow(clippy::new_without_default)] pub const fn new() -> Self { - Self(0 as *const T) - } - - pub fn convert_to_phys(self, va_offset: usize) -> Phys<T> { - Phys::from(self.0 as usize - va_offset) + Self(0, PhantomData) } pub fn as_mut_ptr(self) -> *mut T { @@ -42,65 +103,71 @@ impl<T> Virt<T> { } pub fn as_usize(self) -> usize { - self.0 as usize + self.0 + } +} + +impl<T> Default for Virt<T> { + fn default() -> Self { + Self::new() } } impl<T> From<usize> for Virt<T> { fn from(value: usize) -> Self { - Self(value as *const T) + Self(value, PhantomData) } } impl<T> From<Virt<T>> for usize { fn from(value: Virt<T>) -> Self { - value.0 as usize + value.0 } } -impl<T> From<Phys<T>> for usize { - fn from(value: Phys<T>) -> Self { - value.0 as usize + +impl<T> From<PhysAddr> for Virt<T> { + fn from(value: PhysAddr) -> Self { + Self((value.0 + va_offset_now()) as _, PhantomData) + } +} + +impl From<PhysAddr> for usize { + fn from(value: PhysAddr) -> Self { + value.0 } } -#[derive(Clone, Copy)] -#[repr(transparent)] -pub struct Phys<T>(*const T); -impl<T> PartialEq for Phys<T> { - fn eq(&self, other: &Self) -> bool { - core::ptr::eq(self.0, other.0) +impl<T> From<Virt<T>> for PhysAddr { + fn from(value: Virt<T>) -> Self { + Self(value.as_usize() - va_offset_now()) } } -unsafe impl<T> Send for Phys<T> {} -unsafe impl<T> Sync for Phys<T> {} +#[derive(Default, Clone, Copy, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct PhysAddr(usize); -pub type PhysAddr<T = u8> = Phys<T>; +unsafe impl Send for PhysAddr {} -impl<T> From<usize> for Phys<T> { +impl From<usize> for PhysAddr { fn from(value: usize) -> Self { Self(value as _) } } -impl<T> From<*const T> for Phys<T> { - fn from(value: *const T) -> Self { - Self(value as _) - } -} -impl<T> Phys<T> { - #[allow(clippy::new_without_default)] + +impl PhysAddr { pub const fn new() -> Self { - Self(0 as *const T) + Self(0) } pub fn as_usize(&self) -> usize { - self.0 as usize + self.0 } } -impl<T> Sub<Phys<T>> for Phys<T> { +impl Sub<PhysAddr> for PhysAddr { type Output = usize; - fn sub(self, rhs: Phys<T>) -> Self::Output { + fn sub(self, rhs: PhysAddr) -> Self::Output { self.as_usize() - rhs.as_usize() } } @@ -160,7 +227,7 @@ pub const fn align_up(addr: usize, align: usize) -> usize { (addr + align - 1) & !(align - 1) } -impl<T> Add<usize> for Phys<T> { +impl Add<usize> for PhysAddr { type Output = Self; fn add(self, rhs: usize) -> Self::Output { @@ -176,24 +243,32 @@ impl<T> Sub<usize> for Virt<T> { } } -impl<T> Display for Phys<T> { +impl<T> Sub<Virt<T>> for Virt<T> { + type Output = usize; + + fn sub(self, rhs: Virt<T>) -> Self::Output { + self.as_usize() - rhs.as_usize() + } +} + +impl Display for PhysAddr { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "PA({:p})", self.0) + write!(f, "{:#x}", self.0) } } impl<T> Display for Virt<T> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "VA({:p})", self.0) + write!(f, "{:#x}", self.0) } } -impl<T> core::fmt::Debug for Phys<T> { +impl core::fmt::Debug for PhysAddr { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "PA({:p})", self.0) + write!(f, "{:#x}", self.0) } } impl<T> core::fmt::Debug for Virt<T> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "VA({:p})", self.0) + write!(f, "{:#x}", self.0) } } diff --git a/crates/sparreal-kernel/src/mem/cache.rs b/crates/sparreal-kernel/src/mem/cache.rs new file mode 100644 index 0000000..0f0b0b5 --- /dev/null +++ b/crates/sparreal-kernel/src/mem/cache.rs @@ -0,0 +1,29 @@ +use core::ptr::NonNull; + +use dma_api::Impl; + +use crate::platform_if::{CacheOp, PlatformImpl}; + +use super::{PhysAddr, VirtAddr}; + +struct DMAImpl; + +impl Impl for DMAImpl { + fn map(addr: NonNull<u8>, _size: usize, _direction: dma_api::Direction) -> u64 { + let vaddr = VirtAddr::from(addr); + let paddr = PhysAddr::from(vaddr); + paddr.as_usize() as _ + } + + fn unmap(_addr: NonNull<u8>, _size: usize) {} + + fn flush(addr: NonNull<u8>, size: usize) { + PlatformImpl::dcache_range(CacheOp::Clean, addr.as_ptr() as _, size); + } + + fn invalidate(addr: NonNull<u8>, size: usize) { + PlatformImpl::dcache_range(CacheOp::Invalidate, addr.as_ptr() as _, size); + } +} + +dma_api::set_impl!(DMAImpl); diff --git a/crates/sparreal-kernel/src/mem/dma.rs b/crates/sparreal-kernel/src/mem/dma.rs deleted file mode 100644 index dd95612..0000000 --- a/crates/sparreal-kernel/src/mem/dma.rs +++ /dev/null @@ -1,79 +0,0 @@ -use core::{alloc::Layout, ptr::NonNull}; - -use super::{Virt, VirtToPhys}; - -/// Allocates **coherent** memory that meets Direct Memory Access (DMA) requirements. -/// -/// This function allocates a block of memory through the global allocator. The memory pages must be contiguous, undivided, and have consistent read and write access. -/// -/// - `layout`: The memory layout, which describes the size and alignment requirements of the requested memory. -/// -/// Returns an [`DMAInfo`] structure containing details about the allocated memory, such as the starting address and size. If it's not possible to allocate memory meeting the criteria, returns [`None`]. -/// # Safety -/// This function is unsafe because it directly interacts with the global allocator, which can potentially cause memory leaks or other issues if not used correctly. -pub unsafe fn alloc_coherent(layout: Layout) -> Option<DMAMem> { - let cpu_addr = NonNull::new(alloc::alloc::alloc(layout))?; - let bus_addr = Virt::<u8>::from(cpu_addr.as_ptr() as usize); - let bus_addr = bus_addr.to_phys(); - let bus_addr: usize = bus_addr.into(); - - Some(DMAMem { - cpu_addr, - bus_addr: BusAddr(bus_addr as _), - }) -} - -/// Frees coherent memory previously allocated. -/// -/// This function releases the memory block that was previously allocated and marked as coherent. It ensures proper deallocation and management of resources associated with the memory block. -/// -/// - `dma_info`: An instance of [`DMAInfo`] containing the details of the memory block to be freed, such as its starting address and size. -/// # Safety -/// This function is unsafe because it directly interacts with the global allocator, which can potentially cause memory leaks or other issues if not used correctly. -pub unsafe fn dealloc_coherent(dma: DMAMem, layout: Layout) { - alloc::alloc::dealloc(dma.cpu_addr.as_ptr(), layout); -} - -/// Represents information related to a DMA operation. -#[derive(Debug, Clone, Copy)] -pub struct DMAMem { - /// The `cpu_addr` field represents the address at which the CPU accesses this memory region. - /// This address is a virtual memory address used by the CPU to access memory. - pub cpu_addr: NonNull<u8>, - /// The `bus_addr` field represents the physical address of this memory region on the bus. - /// The DMA controller uses this address to directly access memory. - pub bus_addr: BusAddr, -} - -/// A bus memory address. -/// -/// It's a wrapper type around an [`u64`]. -#[repr(transparent)] -#[derive(Copy, Clone, Default, Ord, PartialOrd, Eq, PartialEq)] -pub struct BusAddr(u64); - -impl BusAddr { - /// Converts an [`u64`] to a physical address. - pub const fn new(addr: u64) -> Self { - Self(addr) - } - - /// Converts the address to an [`u64`]. - pub const fn as_u64(self) -> u64 { - self.0 - } -} - -impl From<u64> for BusAddr { - fn from(value: u64) -> Self { - Self::new(value) - } -} - -impl core::fmt::Debug for BusAddr { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_tuple("BusAddr") - .field(&format_args!("{:#X}", self.0)) - .finish() - } -} diff --git a/crates/sparreal-kernel/src/mem/mmu/boot.rs b/crates/sparreal-kernel/src/mem/mmu/boot.rs deleted file mode 100644 index f55c0d7..0000000 --- a/crates/sparreal-kernel/src/mem/mmu/boot.rs +++ /dev/null @@ -1,123 +0,0 @@ -use core::ptr::NonNull; - -use page_table_generic::{err::PagingResult, Access, AccessSetting, CacheSetting, MapConfig}; - -use crate::{dbg, dbg_hex, dbg_hexln, dbgln, kernel::BootConfig}; - -use super::{table::PageTableRef, PageAllocator}; - -pub fn new_boot_table(config: BootConfig) -> PagingResult<usize> { - let heap_size = - (config.main_memory.size - config.main_memory_heap_offset - config.hart_stack_size) / 2; - let heap_start = config.main_memory.start + config.main_memory_heap_offset + heap_size; - - let mut access = unsafe { - PageAllocator::new( - NonNull::new_unchecked(heap_start.as_usize() as _), - heap_size, - ) - }; - - let mut table = PageTableRef::create_empty(&mut access)?; - dbg_hexln!(config.va_offset); - - unsafe { - map_boot_region( - "main memory", - &mut table, - config.main_memory.start.into(), - config.main_memory.size, - AccessSetting::Read | AccessSetting::Write | AccessSetting::Execute, - CacheSetting::Normal, - &mut access, - config.va_offset, - )?; - - for rsv in config.reserved_memory.into_iter().flatten() { - map_boot_region( - rsv.name, - &mut table, - rsv.start.into(), - rsv.size, - rsv.access, - rsv.cache, - &mut access, - config.va_offset, - )?; - } - } - Ok(table.paddr()) -} - -#[allow(clippy::too_many_arguments)] -unsafe fn map_boot_region( - name: &str, - table: &mut PageTableRef<'_>, - paddr: usize, - size: usize, - access_setting: AccessSetting, - cache_setting: CacheSetting, - access: &mut impl Access, - va_offset: usize, -) -> PagingResult<()> { - map_boot_region_once( - name, - table, - paddr, - paddr, - size, - access_setting, - cache_setting, - access, - )?; - - map_boot_region_once( - name, - table, - paddr + va_offset, - paddr, - size, - access_setting, - cache_setting, - access, - )?; - - Ok(()) -} - -#[allow(clippy::too_many_arguments)] -unsafe fn map_boot_region_once( - name: &str, - table: &mut PageTableRef<'_>, - vaddr: usize, - paddr: usize, - size: usize, - access_setting: AccessSetting, - cache_setting: CacheSetting, - access: &mut impl Access, -) -> PagingResult<()> { - let name_count = name.chars().count(); - let name_space = 12usize; - let space = name_space.saturating_sub(name_count); - dbg!("Map ["); - dbg!(name); - for _ in 0..space { - dbg!(" "); - } - dbg!("]: ["); - dbg_hex!(vaddr); - dbg!(", "); - dbg_hex!(vaddr + size); - dbg!(") -> ["); - dbg_hex!(paddr); - dbg!(", "); - dbg_hex!(paddr + size); - dbgln!(")"); - - table.map_region( - MapConfig::new(vaddr as _, paddr, access_setting, cache_setting), - size, - true, - access, - ) -} diff --git a/crates/sparreal-kernel/src/mem/mmu/mod.rs b/crates/sparreal-kernel/src/mem/mmu/mod.rs index e79996f..dec1ce9 100644 --- a/crates/sparreal-kernel/src/mem/mmu/mod.rs +++ b/crates/sparreal-kernel/src/mem/mmu/mod.rs @@ -1,114 +1,183 @@ -use core::ptr::NonNull; +use core::{alloc::Layout, ops::Range, ptr::NonNull}; -use log::debug; -use page_table_generic::{err::PagingResult, AccessSetting, CacheSetting, MapConfig}; +use buddy_system_allocator::Heap; +use page_table_generic::err::PagingError; +pub use page_table_generic::{AccessSetting, CacheSetting, MapConfig}; -mod boot; -mod table; +mod paging; -use super::*; -use crate::platform; -pub use boot::*; -use table::{get_kernal_table, PageTableRef}; +pub use paging::iomap; -struct BootInfo { - va_offset: usize, -} +use crate::{ + globals::global_val, + io::print::{early_dbg, early_dbg_hex, early_dbg_hexln, early_dbg_range, early_dbgln}, + platform_if::MMUImpl, +}; + +use paging::PageTableRef; +pub use paging::init_table; + +use super::{Align, va_offset}; + +struct PageHeap(Heap<32>); -#[link_section = ".data.boot"] -static mut BOOT_INFO: BootInfo = BootInfo { va_offset: 0 }; +impl page_table_generic::Access for PageHeap { + fn va_offset(&self) -> usize { + 0 + } + + unsafe fn alloc(&mut self, layout: Layout) -> Option<NonNull<u8>> { + self.0.alloc(layout).ok() + } -pub(super) unsafe fn set_va_offset(offset: usize) { - BOOT_INFO.va_offset = offset; + unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: core::alloc::Layout) { + self.0.dealloc(ptr, layout); + } } -pub fn va_offset() -> usize { - unsafe { BOOT_INFO.va_offset } +pub struct BootMemoryRegion { + pub name: &'static str, + pub range: Range<usize>, + pub access: AccessSetting, + pub cache: CacheSetting, } +pub fn new_boot_table(rsv: &[BootMemoryRegion]) -> Result<usize, &'static str> { + let debugcon = global_val().platform_info.debugcon(); + + let mut access = PageHeap(Heap::empty()); + let memory = &global_val().main_memory; + let size = (memory.end - memory.start) / 2; + let start = memory.start + size; + let end = memory.end; + + early_dbg_range("page table allocator", start.as_usize()..end.as_usize()); + unsafe { access.0.add_to_heap(start.as_usize(), end.as_usize()) }; + + let mut table = + PageTableRef::create_empty(&mut access).map_err(|_| "page table allocator no memory")?; + + let va_offset = va_offset(); + + for memory in global_val().platform_info.memorys() { + map_region( + &mut table, + va_offset, + &BootMemoryRegion { + name: "memory", + range: memory.start.as_usize()..memory.end.as_usize(), + access: AccessSetting::Read | AccessSetting::Write | AccessSetting::Execute, + cache: CacheSetting::Normal, + }, + &mut access, + ); + } -pub(crate) unsafe fn init_table( - kconfig: &KernelConfig, - access: &mut PageAllocatorRef, -) -> PagingResult<()> { - debug!("Initializing page table..."); - - let mut table = PageTableRef::create_empty(access)?; - - for memory in kconfig.boot_info.reserved_memory.into_iter().flatten() { - let virt = memory.start.to_virt(); - let size = memory.size.align_up(BYTES_1M * 2); - debug!( - "Map reserved memory region {:#X} -> {:#X} size: {:#X}", - virt.as_usize(), - memory.start.as_usize(), - size, + if let Some(con) = debugcon { + let start = con.addr.align_down(0x1000).as_usize(); + + map_region( + &mut table, + va_offset, + &BootMemoryRegion { + name: "debugcon", + range: start..start + 0x1000, + access: AccessSetting::Read | AccessSetting::Write | AccessSetting::Execute, + cache: CacheSetting::Device, + }, + &mut access, ); + } - table.map_region( - MapConfig::new( - virt.as_mut_ptr(), - memory.start.as_usize(), - memory.access, - memory.cache, - ), - size, - true, - access, - )?; + for region in rsv { + map_region(&mut table, va_offset, region, &mut access); } - let virt = kconfig.boot_info.main_memory.start.to_virt(); - debug!( - "Map memory {:#X} -> {:#X} size {:#X}", - virt.as_usize(), - kconfig.boot_info.main_memory.start.as_usize(), - kconfig.boot_info.main_memory.size - ); - - table.map_region( - MapConfig::new( - virt.as_mut_ptr(), - kconfig.boot_info.main_memory.start.as_usize(), - AccessSetting::Read | AccessSetting::Write | AccessSetting::Execute, - CacheSetting::Normal, - ), - kconfig.boot_info.main_memory.size, - true, - access, - )?; - - platform::set_kernel_table(table.paddr()); - platform::set_user_table(0); - - debug!("Done!"); - Ok(()) + let table_addr = table.paddr(); + + early_dbg("Table: "); + early_dbg_hexln(table_addr as _); + + Ok(table_addr) } -pub fn iomap(paddr: PhysAddr, size: usize) -> NonNull<u8> { +fn map_region( + table: &mut PageTableRef<'_>, + va_offset: usize, + region: &BootMemoryRegion, + access: &mut PageHeap, +) { + let addr = region.range.start; + let size = region.range.end - region.range.start; + + // let addr = align_down_1g(addr); + // let size = align_up_1g(size); + let vaddr = addr + va_offset; + + early_dbg("map region: ["); + early_dbg(region.name); + early_dbg("] ["); + early_dbg_hex(vaddr as _); + early_dbg(", "); + early_dbg_hex((vaddr + size) as _); + early_dbg(") -> ["); + early_dbg_hex(addr as _); + early_dbg(", "); + early_dbg_hex((addr + size) as _); + early_dbgln(")"); + unsafe { - let mut table = get_kernal_table(); - let paddr = paddr.align_down(0x1000); - let vaddr = paddr.to_virt().as_mut_ptr(); - let size = size.max(0x1000); - - let heap = HEAP_ALLOCATOR.write(); - let mut heap_mut = PageAllocatorRef::new(heap); - - let _ = table.map_region_with_handle( - MapConfig::new( - vaddr, - paddr.as_usize(), - AccessSetting::Read | AccessSetting::Write, - CacheSetting::Device, - ), + if let Err(e) = table.map_region( + MapConfig::new(addr as _, addr, region.access, region.cache), size, true, - &mut heap_mut, - Some(&|p| { - platform::flush_tlb(Some(p)); - }), - ); + access, + ) { + early_handle_err(e); + } + + if let Err(e) = table.map_region( + MapConfig::new(vaddr as _, addr, region.access, region.cache), + size, + true, + access, + ) { + early_handle_err(e); + } + } +} - NonNull::new_unchecked(vaddr) +fn early_handle_err(e: PagingError) { + match e { + PagingError::NoMemory => early_dbgln("no memory"), + PagingError::NotAligned => early_dbgln("not aligned"), + PagingError::NotMapped => early_dbgln("not mapped"), + PagingError::AlreadyMapped => {} + PagingError::MappedToHugePage => early_dbgln("mapped to huge page"), } + panic!() +} + +pub fn set_kernel_table(addr: usize) { + MMUImpl::set_kernel_table(addr); +} + +pub fn set_user_table(addr: usize) { + MMUImpl::set_user_table(addr); +} +pub fn get_user_table() -> usize { + MMUImpl::get_user_table() +} + +#[allow(unused)] +pub(crate) fn flush_tlb(addr: *const u8) { + unsafe { MMUImpl::flush_tlb(addr) }; +} +pub fn flush_tlb_all() { + MMUImpl::flush_tlb_all(); +} +pub fn page_size() -> usize { + MMUImpl::page_size() +} +pub fn table_level() -> usize { + MMUImpl::table_level() } diff --git a/crates/sparreal-kernel/src/mem/mmu/paging.rs b/crates/sparreal-kernel/src/mem/mmu/paging.rs new file mode 100644 index 0000000..096b68c --- /dev/null +++ b/crates/sparreal-kernel/src/mem/mmu/paging.rs @@ -0,0 +1,148 @@ +use core::sync::atomic::{Ordering, fence}; + +use log::*; +use page_table_generic::{Access, PTEArch, PTEGeneric}; +use spin::MutexGuard; + +use crate::{ + globals::global_val, + mem::{ALLOCATOR, Align, PhysAddr, VirtAddr}, +}; + +use super::*; + +pub type PageTableRef<'a> = page_table_generic::PageTableRef<'a, PTEImpl>; + +#[allow(unused)] +pub(crate) fn get_kernel_table<'a>() -> PageTableRef<'a> { + let addr = MMUImpl::get_kernel_table(); + let level = table_level(); + PageTableRef::from_addr(addr, level) +} + +#[derive(Clone, Copy)] +pub struct PTEImpl; + +impl PTEArch for PTEImpl { + fn page_size() -> usize { + MMUImpl::page_size() + } + + fn level() -> usize { + MMUImpl::table_level() + } + + fn new_pte(config: PTEGeneric) -> usize { + MMUImpl::new_pte(config) + } + + fn read_pte(pte: usize) -> PTEGeneric { + MMUImpl::read_pte(pte) + } +} + +struct HeapGuard<'a>(MutexGuard<'a, Heap<32>>); + +impl Access for HeapGuard<'_> { + fn va_offset(&self) -> usize { + va_offset() + } + + unsafe fn alloc(&mut self, layout: Layout) -> Option<NonNull<u8>> { + self.0.alloc(layout).ok() + } + + unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) { + self.0.dealloc(ptr, layout); + } +} + +pub fn init_table() { + debug!("Initializing page table..."); + let info = &global_val().platform_info; + let debugcon = info.debugcon(); + + unsafe { + let mut access = HeapGuard(ALLOCATOR.inner.lock()); + + let mut table = PageTableRef::create_empty(&mut access).unwrap(); + + for memory in info.memorys() { + let size = memory.end - memory.start; + let vaddr = VirtAddr::from(memory.start); + + trace!( + "Mapping memory [{}, {}) -> [{}, {})", + vaddr, + vaddr + size, + memory.start, + memory.end, + ); + + table + .map_region( + MapConfig::new( + vaddr.into(), + memory.start.into(), + AccessSetting::Read | AccessSetting::Write | AccessSetting::Execute, + CacheSetting::Normal, + ), + size, + true, + &mut access, + ) + .unwrap() + } + + if let Some(con) = debugcon { + let reg = con.addr.align_down(0x1000); + + let vaddr = VirtAddr::from(reg); + trace!("Mapping stdout {} -> {}", vaddr, reg); + + let _ = table.map_region( + MapConfig::new( + vaddr.into(), + reg.into(), + AccessSetting::Read | AccessSetting::Write, + CacheSetting::Device, + ), + 0x1000, + true, + &mut access, + ); + } + + fence(Ordering::SeqCst); + set_kernel_table(table.paddr()); + flush_tlb_all(); + }; +} + +pub fn iomap(paddr: PhysAddr, size: usize) -> NonNull<u8> { + unsafe { + let mut table = get_kernel_table(); + let paddr = paddr.align_down(0x1000); + let vaddr = VirtAddr::from(paddr); + let size = size.max(0x1000); + + let mut heap = HeapGuard(ALLOCATOR.inner.lock()); + + let _ = table.map_region_with_handle( + MapConfig::new( + vaddr.into(), + paddr.as_usize(), + AccessSetting::Read | AccessSetting::Write, + CacheSetting::Device, + ), + size, + true, + &mut heap, + Some(&|p| { + MMUImpl::flush_tlb(p); + }), + ); + + NonNull::new(vaddr.as_mut_ptr()).unwrap() + } +} diff --git a/crates/sparreal-kernel/src/mem/mmu/table.rs b/crates/sparreal-kernel/src/mem/mmu/table.rs deleted file mode 100644 index b73f3ff..0000000 --- a/crates/sparreal-kernel/src/mem/mmu/table.rs +++ /dev/null @@ -1,32 +0,0 @@ -use page_table_generic::{PTEArch, PTEGeneric}; - -use crate::platform::{self, new_pte, page_size, read_pte, table_level}; - -pub type PageTableRef<'a> = page_table_generic::PageTableRef<'a, PTEImpl>; - -pub fn get_kernal_table<'a>() -> PageTableRef<'a> { - let addr = unsafe { platform::get_kernel_table() }; - let level = unsafe { platform::table_level() }; - PageTableRef::from_addr(addr, level) -} - -#[derive(Clone, Copy)] -pub struct PTEImpl; - -impl PTEArch for PTEImpl { - fn page_size() -> usize { - unsafe { page_size() } - } - - fn level() -> usize { - unsafe { table_level() } - } - - fn new_pte(config: PTEGeneric) -> usize { - unsafe { new_pte(config) } - } - - fn read_pte(pte: usize) -> PTEGeneric { - unsafe { read_pte(pte) } - } -} diff --git a/crates/sparreal-kernel/src/mem/mod.rs b/crates/sparreal-kernel/src/mem/mod.rs index 816b415..3c7f1ba 100644 --- a/crates/sparreal-kernel/src/mem/mod.rs +++ b/crates/sparreal-kernel/src/mem/mod.rs @@ -1,174 +1,161 @@ -mod addr; - -pub mod dma; -#[cfg(feature = "mmu")] -pub mod mmu; +#![allow(unused)] use core::{ - alloc::{GlobalAlloc, Layout}, - ptr::{null_mut, NonNull}, + alloc::GlobalAlloc, + ptr::{NonNull, null_mut, slice_from_raw_parts_mut}, }; -pub use addr::*; use buddy_system_allocator::Heap; -use log::*; +use log::debug; +use spin::Mutex; -use crate::{ - kernel::KernelConfig, - sync::{RwLock, RwLockWriteGuard}, -}; +use crate::{globals::global_val, platform::kstack_size, println}; -#[global_allocator] -static HEAP_ALLOCATOR: LockedHeap = LockedHeap::new(); +mod addr; +mod cache; +#[cfg(feature = "mmu")] +pub mod mmu; +pub mod region; -pub const BYTES_1K: usize = 1024; -pub const BYTES_1M: usize = 1024 * BYTES_1K; -pub const BYTES_1G: usize = 1024 * BYTES_1M; +pub use addr::*; -pub unsafe fn init(kconfig: &KernelConfig) { - #[cfg(feature = "mmu")] - mmu::set_va_offset(kconfig.boot_info.va_offset); +#[global_allocator] +static ALLOCATOR: KAllocator = KAllocator { + inner: Mutex::new(Heap::empty()), +}; - let stack_size = kconfig.boot_info.hart_stack_size; - let start = - (kconfig.boot_info.main_memory.start + kconfig.boot_info.main_memory_heap_offset).to_virt(); - let size = - kconfig.boot_info.main_memory.size - kconfig.boot_info.main_memory_heap_offset - stack_size; - let stack_top = kconfig.stack_top.to_virt(); +pub struct KAllocator { + pub(crate) inner: Mutex<Heap<32>>, +} - debug!("Heap: [{}, {})", start, start + size); - debug!("Stack: [{}, {})", stack_top - stack_size, stack_top); +impl KAllocator { + pub fn reset(&self, memory: &mut [u8]) { + let mut g = self.inner.lock(); - let mut heap = HEAP_ALLOCATOR.write(); - heap.init(start.as_usize(), size); + let mut h = Heap::empty(); - debug!("Heap initialized."); + unsafe { h.init(memory.as_mut_ptr() as usize, memory.len()) }; - #[cfg(feature = "mmu")] - { - let mut heap_mut = PageAllocatorRef::new(heap); - if let Err(e) = mmu::init_table(kconfig, &mut heap_mut) { - error!("Failed to initialize page table: {:?}", e); - } + *g = h; } -} - -struct LockedHeap(RwLock<Heap<32>>); - -unsafe impl Sync for LockedHeap {} -unsafe impl Send for LockedHeap {} -impl LockedHeap { - const fn new() -> Self { - Self(RwLock::new(Heap::new())) - } + pub fn add_to_heap(&self, memory: &mut [u8]) { + let mut g = self.inner.lock(); + let range = memory.as_mut_ptr_range(); - fn write(&self) -> RwLockWriteGuard<'_, Heap<32>> { - self.0.write() + unsafe { g.add_to_heap(range.start as usize, range.end as usize) }; } } -unsafe impl GlobalAlloc for LockedHeap { - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - match self.write().alloc(layout) { - Ok(ptr) => ptr.as_ptr(), - Err(_) => null_mut(), +unsafe impl GlobalAlloc for KAllocator { + unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 { + if let Ok(p) = self.inner.lock().alloc(layout) { + p.as_ptr() + } else { + null_mut() } } - unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { - self.write().dealloc(NonNull::new_unchecked(ptr), layout); + unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) { + self.inner + .lock() + .dealloc(unsafe { NonNull::new_unchecked(ptr) }, layout); } } -pub(crate) trait PhysToVirt<T> { - fn to_virt(self) -> Virt<T>; -} +static mut VA_OFFSET: usize = 0; +static mut VA_OFFSET_NOW: usize = 0; -impl<T> PhysToVirt<T> for Phys<T> { - fn to_virt(self) -> Virt<T> { - let a: usize = self.into(); +pub(crate) fn set_va_offset(offset: usize) { + unsafe { VA_OFFSET = offset }; +} - #[cfg(feature = "mmu")] - { - use mmu::va_offset; - (a + va_offset()).into() - } +pub fn va_offset() -> usize { + unsafe { VA_OFFSET } +} - #[cfg(not(feature = "mmu"))] - { - a.into() - } - } +pub(crate) unsafe fn set_va_offset_now(va: usize) { + unsafe { VA_OFFSET_NOW = va }; } -pub(crate) trait VirtToPhys<T> { - fn to_phys(self) -> Phys<T>; +fn va_offset_now() -> usize { + unsafe { VA_OFFSET_NOW } } -impl<T> VirtToPhys<T> for Virt<T> { - fn to_phys(self) -> Phys<T> { - #[cfg(feature = "mmu")] - { - use mmu::va_offset; - self.convert_to_phys(va_offset()) - } +pub(crate) fn init_heap() { + let main = global_val().main_memory.clone(); + let mut start = VirtAddr::from(main.start); + let mut end = VirtAddr::from(main.end); - #[cfg(not(feature = "mmu"))] - { - let a: usize = self.into(); - a.into() - } + let bss_end = crate::mem::region::bss().as_ptr_range().end.into(); + + if (start..end).contains(&bss_end) { + start = bss_end; } -} -#[allow(dead_code)] -pub struct PageAllocatorRef<'a> { - inner: RwLockWriteGuard<'a, Heap<32>>, -} -impl<'a> PageAllocatorRef<'a> { - pub fn new(inner: RwLockWriteGuard<'a, Heap<32>>) -> Self { - Self { inner } + let stack_top = VirtAddr::from(global_val().kstack_top); + let stack_bottom = stack_top - kstack_size(); + + if (start..end).contains(&stack_bottom) { + end = stack_bottom; } + + println!("heap add memory [{}, {})", start, end); + ALLOCATOR + .add_to_heap(unsafe { &mut *slice_from_raw_parts_mut(start.as_mut_ptr(), end - start) }); + + println!("heap initialized"); } -#[cfg(feature = "mmu")] -impl page_table_generic::Access for PageAllocatorRef<'_> { - fn va_offset(&self) -> usize { - mmu::va_offset() - } +pub(crate) fn init_page_and_memory() { + #[cfg(feature = "mmu")] + mmu::init_table(); - unsafe fn alloc(&mut self, layout: Layout) -> Option<NonNull<u8>> { - self.inner.alloc(layout).ok() - } + let main = global_val().main_memory.clone(); + + for memory in global_val().platform_info.memorys() { + if memory.contains(&main.start) { + continue; + } + let start = VirtAddr::from(memory.start); + let end = VirtAddr::from(memory.end); + let len = memory.end - memory.start; - unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) { - self.inner.dealloc(ptr, layout); + debug!("Heap add memory [{}, {})", start, end); + ALLOCATOR.add_to_heap(unsafe { &mut *slice_from_raw_parts_mut(start.as_mut_ptr(), len) }); } } -#[allow(unused)] -pub struct PageAllocator(Heap<32>); +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CMemRange { + pub start: usize, + pub end: usize, +} -impl PageAllocator { - pub unsafe fn new(start: NonNull<u8>, size: usize) -> Self { - let mut heap = Heap::new(); - heap.init(start.as_ptr() as usize, size); - Self(heap) +impl CMemRange { + pub fn as_slice(&self) -> &'static [u8] { + unsafe { core::slice::from_raw_parts(self.start as *const u8, self.end - self.start) } } } -#[cfg(feature = "mmu")] -impl page_table_generic::Access for PageAllocator { - fn va_offset(&self) -> usize { - mmu::va_offset() - } +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct KernelRegions { + pub text: CMemRange, + pub rodata: CMemRange, + pub data: CMemRange, + pub bss: CMemRange, +} - unsafe fn alloc(&mut self, layout: Layout) -> Option<NonNull<u8>> { - self.0.alloc(layout).ok() +pub fn iomap(paddr: PhysAddr, _size: usize) -> NonNull<u8> { + #[cfg(feature = "mmu")] + { + mmu::iomap(paddr, _size) } - unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) { - self.0.dealloc(ptr, layout); + #[cfg(not(feature = "mmu"))] + unsafe { + NonNull::new_unchecked(paddr.as_usize() as *mut u8) } } diff --git a/crates/sparreal-kernel/src/mem/region.rs b/crates/sparreal-kernel/src/mem/region.rs new file mode 100644 index 0000000..5bae6db --- /dev/null +++ b/crates/sparreal-kernel/src/mem/region.rs @@ -0,0 +1,9 @@ +use crate::platform_if::PlatformImpl; + +pub fn bss() -> &'static [u8] { + PlatformImpl::kernel_regions().bss.as_slice() +} + +pub fn text() -> &'static [u8] { + PlatformImpl::kernel_regions().text.as_slice() +} diff --git a/crates/sparreal-kernel/src/platform/fdt.rs b/crates/sparreal-kernel/src/platform/fdt.rs new file mode 100644 index 0000000..c13d930 --- /dev/null +++ b/crates/sparreal-kernel/src/platform/fdt.rs @@ -0,0 +1,146 @@ +use alloc::string::{String, ToString}; +use alloc::vec::Vec; +use core::{ + ops::Range, + ptr::{NonNull, slice_from_raw_parts, slice_from_raw_parts_mut}, +}; +use fdt_parser::Node; +use log::error; + +use crate::driver_manager::device::DriverId; +use crate::globals::{self, global_val}; +use crate::irq::IrqInfo; +use crate::mem::{Align, VirtAddr}; +use crate::{io::print::*, mem::PhysAddr}; + +use super::{CPUInfo, SerialPort}; + +pub struct Fdt(PhysAddr); + +impl Fdt { + pub fn new(addr: NonNull<u8>) -> Self { + Self(VirtAddr::from(addr).into()) + } + + pub fn model_name(&self) -> Option<String> { + let fdt = self.get(); + let node = fdt.all_nodes().next()?; + + let model = node.find_property("model")?; + + Some(model.str().to_string()) + } + + pub fn cpus(&self) -> Vec<CPUInfo> { + let fdt = self.get(); + + fdt.find_nodes("/cpus/cpu") + .map(|cpu| { + let reg = cpu.reg().unwrap().next().unwrap(); + CPUInfo { + cpu_id: (reg.address as usize).into(), + } + }) + .collect() + } + + pub fn setup(&mut self) -> Result<(), &'static str> { + let main_memory = global_val().main_memory.clone(); + let fdt_start = self.move_to(main_memory.end.as_usize()); + unsafe { globals::edit(|g| g.kstack_top = fdt_start.into()) }; + Ok(()) + } + + fn move_to(&mut self, dst_end: usize) -> usize { + let size = self.get().total_size(); + + let dst = (dst_end - size).align_down(0x1000); + + early_dbg("Move FDT from "); + early_dbg_hex(self.0.as_usize() as _); + early_dbg(" to "); + early_dbg_hexln(dst as _); + + unsafe { + let dest = &mut *slice_from_raw_parts_mut(dst as _, size); + let src = &*slice_from_raw_parts(VirtAddr::from(self.0).as_mut_ptr(), size); + dest.copy_from_slice(src); + self.0 = dst.into(); + } + dst + } + + pub fn get(&self) -> fdt_parser::Fdt<'static> { + let addr = VirtAddr::from(self.0).as_mut_ptr(); + let ptr = NonNull::new(addr).unwrap(); + fdt_parser::Fdt::from_ptr(ptr).unwrap() + } + + pub fn get_addr(&self) -> NonNull<u8> { + unsafe { NonNull::new_unchecked(VirtAddr::from(self.0).as_mut_ptr()) } + } + + pub fn memorys(&self) -> Vec<Range<PhysAddr>> { + let mut out = Vec::new(); + + let fdt = self.get(); + + for node in fdt.memory() { + for region in node.regions() { + let addr = (region.address as usize).into(); + out.push(addr..addr + region.size); + } + } + out + } + + pub fn take_memory(&self) -> Range<PhysAddr> { + let region = self + .get() + .memory() + .next() + .unwrap() + .regions() + .next() + .unwrap(); + let addr = (region.address as usize).into(); + addr..addr + region.size + } + + pub fn debugcon(&self) -> Option<SerialPort> { + let fdt = self.get(); + let stdout = fdt.chosen()?.stdout()?; + let compatible = stdout.node.compatibles(); + let reg = stdout.node.reg()?.next()?; + Some(SerialPort::new( + (reg.address as usize).into(), + reg.size, + compatible, + )) + } +} + +pub trait GetIrqConfig { + fn irq_info(&self) -> Option<IrqInfo>; +} + +impl GetIrqConfig for Node<'_> { + fn irq_info(&self) -> Option<IrqInfo> { + let irq_chip_node = self.interrupt_parent()?; + + let irq_parent = DriverId::from(irq_chip_node.node.phandle()?.as_usize()); + + let mut cfgs = Vec::new(); + if let Some(irqs) = self.interrupts() { + for irq in irqs { + let raw = irq.collect::<Vec<_>>(); + match crate::irq::fdt_parse_config(irq_parent, &raw) { + Ok(cfg) => cfgs.push(cfg), + Err(e) => error!("{:?}", e), + } + } + } + + Some(IrqInfo { irq_parent, cfgs }) + } +} diff --git a/crates/sparreal-kernel/src/platform/mod.rs b/crates/sparreal-kernel/src/platform/mod.rs index 4b1fd65..5d6c74d 100644 --- a/crates/sparreal-kernel/src/platform/mod.rs +++ b/crates/sparreal-kernel/src/platform/mod.rs @@ -1,56 +1,177 @@ use alloc::string::String; -use sparreal_macros::api_trait; +use alloc::vec::Vec; +use core::ffi::CStr; +use core::ops::Range; +use core::ptr::NonNull; +use driver_interface::DriverRegister; +use driver_interface::interrupt_controller::CpuId; -#[cfg(feature = "mmu")] -use page_table_generic::PTEGeneric; +use crate::globals::global_val; +use crate::mem::PhysAddr; +use crate::platform_if::*; +use fdt::Fdt; -pub enum PageAttribute { - Read, - Write, - Device, - Execute, - NonCache, +pub mod fdt; + +pub enum PlatformInfoKind { + DeviceTree(Fdt), +} + +impl PlatformInfoKind { + pub fn new_fdt(addr: NonNull<u8>) -> Self { + PlatformInfoKind::DeviceTree(Fdt::new(addr)) + } + + pub fn memorys(&self) -> impl Iterator<Item = Range<PhysAddr>> { + let mut out: [Option<Range<PhysAddr>>; 24] = + unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + let mut len = 0; + + match self { + PlatformInfoKind::DeviceTree(fdt) => { + for (i, m) in fdt + .get() + .memory() + .flat_map(|m| m.regions()) + .map(|r| { + let start = PhysAddr::from(r.address as usize); + start..start + r.size + }) + .enumerate() + { + if i >= out.len() { + break; + } + out[i] = Some(m); + len += 1; + } + } + } + + let mut iter = 0; + core::iter::from_fn(move || { + if iter >= len { + None + } else { + let m = out[iter].take().unwrap(); + iter += 1; + Some(m) + } + }) + } + + pub fn main_memory(&self) -> Option<Range<PhysAddr>> { + let kernel_text = PlatformImpl::kernel_regions().text; + + let mut first = None; + + for m in self.memorys() { + let r = m.start.as_usize()..m.end.as_usize(); + if r.contains(&kernel_text.end) { + return Some(m); + } + if first.is_none() { + first = Some(m); + } + } + + first + } + + pub fn debugcon(&self) -> Option<SerialPort> { + match self { + Self::DeviceTree(fdt) => fdt.debugcon(), + } + } +} + +pub fn cpu_list() -> Vec<CPUInfo> { + match &global_val().platform_info { + PlatformInfoKind::DeviceTree(fdt) => fdt.cpus(), + } +} + +pub fn cpu_id() -> CpuId { + PlatformImpl::cpu_id().into() } -pub enum PageError { - NoMemory, - Other, +pub fn platform_name() -> String { + match &global_val().platform_info { + PlatformInfoKind::DeviceTree(fdt) => fdt.model_name().unwrap_or_default(), + } +} + +pub fn shutdown() -> ! { + PlatformImpl::shutdown() +} + +pub fn wait_for_interrupt() { + PlatformImpl::wait_for_interrupt(); +} + +pub fn kstack_size() -> usize { + PlatformImpl::kstack_size() } pub fn app_main() { - extern "C" { + unsafe extern "C" { fn __sparreal_rt_main(); } - unsafe { __sparreal_rt_main() } } -#[api_trait] -pub trait Platform { - unsafe fn shutdown(); - unsafe fn wait_for_interrupt(); - unsafe fn current_ticks() -> u64; - unsafe fn tick_hz() -> u64; - unsafe fn debug_write_byte(ch: u8); - - fn print_system_info(); - - fn irqs_enable(); - fn irqs_disable(); - fn cpu_id() -> u64; - fn cpu_id_display() -> String; -} - -#[cfg(feature = "mmu")] -#[api_trait] -pub trait PlatformPageTable { - fn set_kernel_table(addr: usize); - fn get_kernel_table() -> usize; - fn set_user_table(addr: usize); - fn get_user_table() -> usize; - fn flush_tlb(addr: Option<*const u8>); - fn page_size() -> usize; - fn table_level() -> usize; - fn new_pte(config: PTEGeneric) -> usize; - fn read_pte(pte: usize) -> PTEGeneric; +#[derive(Debug)] +pub struct CPUInfo { + pub cpu_id: CpuId, +} + +#[derive(Debug, Clone, Copy)] +pub struct SerialPort { + pub addr: PhysAddr, + pub size: Option<usize>, + compatible: [Option<[u8; 128]>; 4], +} + +impl SerialPort { + pub fn new<'a>( + addr: PhysAddr, + size: Option<usize>, + compatibles: impl Iterator<Item = &'a str>, + ) -> Self { + let mut compatible_out = [None; 4]; + + for (i, c) in compatibles.enumerate() { + if i == compatible_out.len() { + break; + } + let bytes = c.as_bytes(); + let mut bytes_out = [0u8; 128]; + bytes_out[..bytes.len()].copy_from_slice(bytes); + compatible_out[i] = Some(bytes_out); + } + + Self { + addr, + size, + compatible: compatible_out, + } + } + + pub fn compatibles(&self) -> impl Iterator<Item = &str> { + let mut iter = 0; + + core::iter::from_fn(move || { + if iter >= self.compatible.len() { + None + } else { + let bytes = self.compatible[iter].as_ref()?; + iter += 1; + CStr::from_bytes_until_nul(bytes).ok()?.to_str().ok() + } + }) + } +} + +pub fn module_registers() -> Vec<DriverRegister> { + PlatformImpl::driver_registers().as_slice().to_vec() } diff --git a/crates/sparreal-kernel/src/platform_if/mod.rs b/crates/sparreal-kernel/src/platform_if/mod.rs new file mode 100644 index 0000000..1ff6724 --- /dev/null +++ b/crates/sparreal-kernel/src/platform_if/mod.rs @@ -0,0 +1,84 @@ +use core::ffi::c_void; + +pub use driver_interface::DriverRegisterListRef; +use sparreal_macros::api_trait; + +use crate::mem::KernelRegions; + +#[api_trait] +pub trait Platform { + fn kernel_regions() -> KernelRegions; + fn kstack_size() -> usize; + fn cpu_id() -> usize; + fn cpu_context_size() -> usize; + + /// # Safety + /// + /// + unsafe fn get_current_tcb_addr() -> *const u8; + + /// # Safety + /// + /// + unsafe fn set_current_tcb_addr(addr: *const u8); + + /// # Safety + /// + /// + unsafe fn cpu_context_init(ctx_ptr: *mut u8, pc: *const c_void, stack_top: *const u8); + + /// # Safety + /// + /// `ctx_ptr` 是有效的上下文指针 + unsafe fn cpu_context_sp(ctx_ptr: *const u8) -> usize; + + /// # Safety + /// + /// + unsafe fn cpu_context_switch(prev: *mut u8, next: *mut u8); + + fn wait_for_interrupt(); + + fn irq_all_enable(); + fn irq_all_disable(); + fn irq_all_is_enabled() -> bool; + + fn on_boot_success() {} + fn shutdown() -> !; + fn debug_put(b: u8); + + fn dcache_range(op: CacheOp, addr: usize, size: usize); + + fn driver_registers() -> DriverRegisterListRef; +} + +#[cfg(feature = "mmu")] +#[api_trait] +pub trait MMU { + fn set_kernel_table(addr: usize); + fn get_kernel_table() -> usize; + fn set_user_table(addr: usize); + fn get_user_table() -> usize; + + /// flush tlb + /// # Safety + /// addr must be page aligned + unsafe fn flush_tlb(addr: *const u8); + fn flush_tlb_all(); + fn page_size() -> usize; + fn table_level() -> usize; + fn new_pte(config: page_table_generic::PTEGeneric) -> usize; + fn read_pte(pte: usize) -> page_table_generic::PTEGeneric; + fn enable_mmu(stack_top: usize, jump_to: usize) -> !; +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub enum CacheOp { + /// Write back to memory + Clean, + /// Invalidate cache + Invalidate, + /// Clean and invalidate + CleanAndInvalidate, +} diff --git a/crates/sparreal-kernel/src/prelude.rs b/crates/sparreal-kernel/src/prelude.rs index 59236ee..75909e9 100644 --- a/crates/sparreal-kernel/src/prelude.rs +++ b/crates/sparreal-kernel/src/prelude.rs @@ -1 +1,5 @@ -pub use crate::driver::device_tree::FDTExtend; +pub use crate::platform::fdt::GetIrqConfig; +pub use crate::print; +pub use crate::println; +pub use fdt_parser; +pub use sparreal_macros::entry; diff --git a/crates/sparreal-kernel/src/stdout/mod.rs b/crates/sparreal-kernel/src/stdout/mod.rs deleted file mode 100644 index 4d39c59..0000000 --- a/crates/sparreal-kernel/src/stdout/mod.rs +++ /dev/null @@ -1,107 +0,0 @@ -use core::fmt::{self, Write}; - -use alloc::{boxed::Box, sync::Arc}; -use driver_interface::uart; - -use crate::{ - driver::{DriverArc, DriverWeak}, - platform, - sync::RwLock, - util::boot::boot_debug_hex, -}; - -static STDOUT: RwLock<Option<Box<dyn StdoutWrite>>> = RwLock::new(None); - -pub trait StdoutWrite: Send + Sync + Write + 'static {} - -pub fn print(args: fmt::Arguments) { - let mut stdout = STDOUT.write(); - if let Some(stdout) = stdout.as_mut() { - let _ = stdout.write_fmt(args); - } -} - -pub fn set_stdout(stdout: impl StdoutWrite) { - let stdout = Box::new(stdout); - *STDOUT.write() = Some(stdout); -} - -#[derive(Clone)] -pub struct UartWrite { - pub driver: DriverWeak<uart::BoxDriver>, -} - -impl UartWrite { - pub fn new(driver: &DriverArc<uart::BoxDriver>) -> Self { - Self { - driver: Arc::downgrade(driver), - } - } -} - -impl Write for UartWrite { - fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { - if let Some(arc) = self.driver.upgrade() { - let mut g = arc.write(); - let _ = g.write_all(s.as_bytes()); - } - Ok(()) - } -} -impl StdoutWrite for UartWrite {} - -#[derive(Clone, Copy)] -pub struct EarlyDebugWrite; - -impl Write for EarlyDebugWrite { - fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { - unsafe { - s.bytes().for_each(|ch| { - platform::debug_write_byte(ch); - }); - } - Ok(()) - } -} -impl StdoutWrite for EarlyDebugWrite {} - -pub fn early_print_str(s: &str) { - let _ = EarlyDebugWrite {}.write_str(s); -} - -#[macro_export] -macro_rules! dbg { - ($v:expr) => { - $crate::__export::early_print_str($v) - }; -} - -#[macro_export] -macro_rules! dbgln { - () => { - $crate::dbg!("\r\n") - }; - ($v:expr) => { - $crate::dbg!($v); - $crate::dbg!("\r\n") - }; -} - -#[macro_export] -macro_rules! dbg_hex { - ($v:expr) => { - $crate::__export::debug_hex($v as _) - }; -} - -#[macro_export] -macro_rules! dbg_hexln { - ($v:expr) => { - $crate::__export::debug_hex($v as _); - $crate::dbgln!() - }; -} - -pub fn debug_hex(v: u64) { - boot_debug_hex(EarlyDebugWrite {}, v); -} diff --git a/crates/sparreal-kernel/src/sync/mod.rs b/crates/sparreal-kernel/src/sync/mod.rs deleted file mode 100644 index 98d21fc..0000000 --- a/crates/sparreal-kernel/src/sync/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod rwlock; -mod spin; - -pub use rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; -pub use spin::{Spinlock, SpinlockGuard}; diff --git a/crates/sparreal-kernel/src/sync/rwlock.rs b/crates/sparreal-kernel/src/sync/rwlock.rs deleted file mode 100644 index 2157bc1..0000000 --- a/crates/sparreal-kernel/src/sync/rwlock.rs +++ /dev/null @@ -1,125 +0,0 @@ -#![allow(unused)] - -use core::{ - hint::spin_loop, - sync::atomic::{AtomicUsize, Ordering}, -}; - -use lock_api::GuardSend; -use log::warn; - -const READER: usize = 1 << 2; -const UPGRADED: usize = 1 << 1; -const WRITER: usize = 1; -const READERS_MASK: usize = !(WRITER | UPGRADED); - -pub type RwLock<T> = lock_api::RwLock<RawRwLock, T>; -/// RAII structure used to release the shared read access of a lock when -/// dropped. -pub type RwLockReadGuard<'a, T> = lock_api::RwLockReadGuard<'a, RawRwLock, T>; - -/// RAII structure used to release the exclusive write access of a lock when -/// dropped. -pub type RwLockWriteGuard<'a, T> = lock_api::RwLockWriteGuard<'a, RawRwLock, T>; - -/// Raw reader-writer lock type backed by the parking lot. -pub struct RawRwLock { - lock: AtomicUsize, -} - -unsafe impl lock_api::RawRwLock for RawRwLock { - #[allow(clippy::declare_interior_mutable_const)] - const INIT: RawRwLock = RawRwLock { - lock: AtomicUsize::new(0), - }; - - type GuardMarker = GuardSend; - - #[inline] - fn lock_exclusive(&self) { - // Note: This isn't the best way of implementing a spinlock, but it - // suffices for the sake of this example. - while !self.try_lock_exclusive() { - spin_loop(); - } - } - - #[inline] - fn try_lock_exclusive(&self) -> bool { - self.lock - .compare_exchange(0, WRITER, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - } - - #[inline] - unsafe fn unlock_exclusive(&self) { - // Writer is responsible for clearing both WRITER and UPGRADED bits. - // The UPGRADED bit may be set if an upgradeable lock attempts an upgrade while this lock is held. - self.lock.fetch_and(!(WRITER | UPGRADED), Ordering::Release); - } - - #[inline] - fn lock_shared(&self) { - // Note: This isn't the best way of implementing a spinlock, but it - // suffices for the sake of this example. - while !self.try_lock_shared() { - spin_loop(); - } - } - - #[inline] - fn try_lock_shared(&self) -> bool { - let value = match self.acquire_reader() { - Some(v) => v, - None => return false, - }; - // We check the UPGRADED bit here so that new readers are prevented when an UPGRADED lock is held. - // This helps reduce writer starvation. - if value & (WRITER | UPGRADED) != 0 { - // Lock is taken, undo. - self.lock.fetch_sub(READER, Ordering::Release); - false - } else { - true - } - } - - #[inline] - unsafe fn unlock_shared(&self) { - self.lock.fetch_sub(READER, Ordering::Release); - } - - #[inline] - fn is_locked(&self) -> bool { - let state = self.lock.load(Ordering::Relaxed); - state & (WRITER | READERS_MASK) != 0 - } - - #[inline] - fn is_locked_exclusive(&self) -> bool { - let state = self.lock.load(Ordering::Relaxed); - state & (WRITER) != 0 - } -} -impl RawRwLock { - // Acquire a read lock, returning the new lock value. - fn acquire_reader(&self) -> Option<usize> { - // An arbitrary cap that allows us to catch overflows long before they happen - const MAX_READERS: usize = usize::MAX / READER / 2; - - let value = self.lock.fetch_add(READER, Ordering::Acquire); - - if value > MAX_READERS * READER { - self.lock.fetch_sub(READER, Ordering::Relaxed); - warn!("Too many lock readers, cannot safely proceed"); - None - } else { - Some(value) - } - } - - unsafe fn force_write_unlock(&self) { - debug_assert_eq!(self.lock.load(Ordering::Relaxed) & !(WRITER | UPGRADED), 0); - self.lock.fetch_and(!(WRITER | UPGRADED), Ordering::Release); - } -} diff --git a/crates/sparreal-kernel/src/sync/spin.rs b/crates/sparreal-kernel/src/sync/spin.rs deleted file mode 100644 index 0c0b9c3..0000000 --- a/crates/sparreal-kernel/src/sync/spin.rs +++ /dev/null @@ -1,41 +0,0 @@ -// pub use spin::Mutex; - -use core::{ - hint::spin_loop, - sync::atomic::{AtomicBool, Ordering}, -}; -use lock_api::{GuardSend, RawMutex}; - -// 1. Define our raw lock type -pub struct RawSpinlock(AtomicBool); - -// 2. Implement RawMutex for this type -unsafe impl RawMutex for RawSpinlock { - #[allow(clippy::declare_interior_mutable_const)] - const INIT: RawSpinlock = RawSpinlock(AtomicBool::new(false)); - - // A spinlock guard can be sent to another thread and unlocked there - type GuardMarker = GuardSend; - - fn lock(&self) { - // Note: This isn't the best way of implementing a spinlock, but it - // suffices for the sake of this example. - while !self.try_lock() { - spin_loop(); - } - } - - fn try_lock(&self) -> bool { - self.0 - .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - } - - unsafe fn unlock(&self) { - self.0.store(false, Ordering::Release); - } -} - -// 3. Export the wrappers. This are the types that your users will actually use. -pub type Spinlock<T> = lock_api::Mutex<RawSpinlock, T>; -pub type SpinlockGuard<'a, T> = lock_api::MutexGuard<'a, RawSpinlock, T>; diff --git a/crates/sparreal-kernel/src/task/mod.rs b/crates/sparreal-kernel/src/task/mod.rs new file mode 100644 index 0000000..9bb3b51 --- /dev/null +++ b/crates/sparreal-kernel/src/task/mod.rs @@ -0,0 +1,53 @@ +use alloc::string::{String, ToString}; +use tcb::{Pid, TaskControlBlock, set_current}; + +mod schedule; +mod tcb; + +pub use schedule::suspend; +pub use tcb::current; + +#[derive(Debug, Clone)] +pub enum TaskError { + NoMemory, +} + +#[derive(Debug, Clone)] +pub struct TaskConfig { + pub name: String, + pub priority: usize, + pub stack_size: usize, +} + +impl TaskConfig { + pub fn new(name: impl ToString) -> Self { + Self { + name: name.to_string(), + priority: 0, + stack_size: 2 * 1024 * 1024, + } + } +} + +pub fn spawn_with_config<F>(f: F, config: TaskConfig) -> Result<(), TaskError> +where + F: FnOnce() + Send + 'static, +{ + let task = TaskControlBlock::new(f, config)?; + + tcb::current().switch_to(&task); + + Ok(()) +} + +pub fn init() { + let task = TaskControlBlock::new(|| {}, TaskConfig { + name: "Task0".into(), + priority: 0, + stack_size: 0, + }) + .unwrap(); + set_current(&task); +} + +pub fn wake_up_in_irq(_pid: Pid) {} diff --git a/crates/sparreal-kernel/src/task/schedule.rs b/crates/sparreal-kernel/src/task/schedule.rs new file mode 100644 index 0000000..56b8669 --- /dev/null +++ b/crates/sparreal-kernel/src/task/schedule.rs @@ -0,0 +1,54 @@ +use alloc::collections::vec_deque::VecDeque; +use log::debug; +use spin::Mutex; + +use crate::platform_if::PlatformImpl; + +use super::tcb::{TaskControlBlock, TaskState, current}; + +static IDLE: Mutex<VecDeque<TaskControlBlock>> = Mutex::new(VecDeque::new()); +static FINISHED: Mutex<VecDeque<TaskControlBlock>> = Mutex::new(VecDeque::new()); + +pub fn schedule() { + let idle = idle_pop(); + if let Some(mut idle) = idle { + let mut cu = current(); + if matches!(cu.info().state, TaskState::Running) { + cu.info_mut().state = TaskState::Suspend; + } + idle.info_mut().state = TaskState::Running; + + cu.switch_to(&idle); + } else { + debug!("No task idle"); + loop { + PlatformImpl::wait_for_interrupt(); + } + } +} + +pub fn idle_push(tcb: TaskControlBlock) { + IDLE.lock().push_back(tcb); +} + +pub fn idle_pop() -> Option<TaskControlBlock> { + let mut g = IDLE.lock(); + while let Some(one) = g.pop_front() { + if matches!(one.info().state, TaskState::Stopped) { + unsafe { one.drop() }; + continue; + } + return Some(one); + } + None +} + +pub fn finished_push(tcb: TaskControlBlock) { + FINISHED.lock().push_back(tcb); +} + +pub fn suspend() { + let mut current = current(); + current.info_mut().state = TaskState::Suspend; + schedule(); +} diff --git a/crates/sparreal-kernel/src/task/tcb.rs b/crates/sparreal-kernel/src/task/tcb.rs new file mode 100644 index 0000000..bbaf26c --- /dev/null +++ b/crates/sparreal-kernel/src/task/tcb.rs @@ -0,0 +1,193 @@ +use core::{ + alloc::Layout, + fmt::Debug, + ptr::NonNull, + sync::atomic::{AtomicUsize, Ordering}, +}; + +use alloc::{boxed::Box, string::String}; +use log::debug; + +use crate::{platform_if::PlatformImpl, task::schedule::*}; + +use super::{TaskConfig, TaskError}; + +const TCB_ALIGN: usize = 16; + +#[repr(transparent)] +#[derive(Clone, Copy)] +pub struct TaskControlBlock(*mut u8); + +unsafe impl Send for TaskControlBlock {} + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct Pid(usize); + +impl Pid { + pub fn new() -> Self { + static ITER: AtomicUsize = AtomicUsize::new(0); + Self(ITER.fetch_add(1, Ordering::SeqCst)) + } +} + +impl Default for Pid { + fn default() -> Self { + Self::new() + } +} + +impl Debug for Pid { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + writeln!(f, "{:?}", self.0) + } +} + +impl TaskControlBlock { + pub(super) fn new<F>(entry: F, config: TaskConfig) -> Result<Self, TaskError> + where + F: FnOnce() + Send + 'static, + { + let entry_box = Box::new(entry); + + let buffer = NonNull::new(unsafe { + alloc::alloc::alloc_zeroed( + Layout::from_size_align(Self::tcb_size(config.stack_size), TCB_ALIGN).unwrap(), + ) + }) + .ok_or(TaskError::NoMemory)?; + + let pid = Pid::new(); + + let pc; + + unsafe { + let task_info = &mut *(buffer.as_ptr() as *mut TaskInfo); + task_info.pid = pid; + task_info.stack_size = config.stack_size; + task_info.priority = config.priority; + task_info.name = config.name; + task_info.state = TaskState::Idle; + task_info.entry = Some(entry_box); + + pc = task_entry as usize as _; + } + + let task = Self(buffer.as_ptr()); + + unsafe { + let stack_top = task.stack().as_ptr().add(config.stack_size); + + debug!( + "New task [{:?}], stack_top: {:p}", + task.info().name, + stack_top + ); + + PlatformImpl::cpu_context_init( + task.cpu_context_ptr(), + pc, + task.stack().as_ptr().add(config.stack_size), + ); + } + Ok(task) + } + + fn tcb_size(stack_size: usize) -> usize { + size_of::<TaskInfo>() + stack_size + PlatformImpl::cpu_context_size() + } + + pub fn info(&self) -> &TaskInfo { + unsafe { &*(self.0 as *mut TaskInfo) } + } + + pub(super) fn info_mut(&mut self) -> &mut TaskInfo { + unsafe { &mut *(self.0 as *mut TaskInfo) } + } + + pub(super) fn stack(&self) -> &[u8] { + let stack_size = self.info().stack_size; + unsafe { core::slice::from_raw_parts_mut(self.0.add(size_of::<TaskInfo>()), stack_size) } + } + + pub(super) unsafe fn drop(self) { + let info = self.info(); + + let size = Self::tcb_size(info.stack_size); + + unsafe { + alloc::alloc::dealloc(self.0, Layout::from_size_align_unchecked(size, TCB_ALIGN)) + }; + } + + fn cpu_context_ptr(&self) -> *mut u8 { + unsafe { + self.0 + .add(size_of::<TaskInfo>()) + .add(self.info().stack_size) + } + } + + fn addr(&self) -> *mut u8 { + self.0 as _ + } + + pub(super) fn switch_to(&self, next: &TaskControlBlock) { + debug!("switch {} -> {}", self.info().name, next.info().name); + set_current(next); + match self.info().state { + TaskState::Stopped => finished_push(*self), + _ => idle_push(*self), + } + + unsafe { + PlatformImpl::cpu_context_switch(self.cpu_context_ptr(), next.cpu_context_ptr()); + } + } + + #[allow(unused)] + pub fn sp(&self) -> usize { + unsafe { PlatformImpl::cpu_context_sp(self.cpu_context_ptr()) } + } +} + +pub struct TaskInfo { + pub pid: Pid, + pub name: String, + pub priority: usize, + pub stack_size: usize, + pub entry: Option<Box<dyn FnOnce()>>, + pub state: TaskState, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum TaskState { + Idle, + Running, + Suspend, + Stopped, +} + +extern "C" fn task_entry() -> ! { + let mut task = current(); + let task_mut = task.info_mut(); + if let Some(entry) = task_mut.entry.take() { + entry(); + task_mut.state = TaskState::Stopped; + } + schedule(); + unreachable!("task exited!"); +} + +pub fn current() -> TaskControlBlock { + unsafe { + let ptr = PlatformImpl::get_current_tcb_addr(); + TaskControlBlock(ptr as _) + } +} + +pub fn set_current(tcb: &TaskControlBlock) { + unsafe { + PlatformImpl::set_current_tcb_addr(tcb.addr()); + } +} diff --git a/crates/sparreal-kernel/src/time.rs b/crates/sparreal-kernel/src/time.rs deleted file mode 100644 index 3522220..0000000 --- a/crates/sparreal-kernel/src/time.rs +++ /dev/null @@ -1,40 +0,0 @@ -use core::{future::Future, time::Duration}; - -use crate::platform; - -pub fn since_boot() -> Duration { - let current_tick = unsafe { platform::current_ticks() }; - let freq = unsafe { platform::tick_hz() }; - Duration::from_nanos(current_tick * 1_000_000_000 / freq) -} - -pub fn delay(duration: Duration) -> impl Future<Output = ()> { - unsafe { - let current_tick = platform::current_ticks(); - let freq = platform::tick_hz(); - let ticks = duration.as_nanos() * freq as u128 / 1_000_000_000; - let until = current_tick + ticks as u64; - FutureDelay { until } - } -} - -pub struct FutureDelay { - until: u64, -} - -impl Future for FutureDelay { - type Output = (); - - fn poll( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll<Self::Output> { - let current_tick = unsafe { platform::current_ticks() }; - if current_tick >= self.until { - core::task::Poll::Ready(()) - } else { - cx.waker().wake_by_ref(); - core::task::Poll::Pending - } - } -} diff --git a/crates/sparreal-kernel/src/time/mod.rs b/crates/sparreal-kernel/src/time/mod.rs new file mode 100644 index 0000000..5eae1ea --- /dev/null +++ b/crates/sparreal-kernel/src/time/mod.rs @@ -0,0 +1,98 @@ +use core::time::Duration; + +use crate::{ + driver_manager::{ + self, + device::{BorrowGuard, Device}, + manager, + }, + globals::{cpu_global, cpu_global_meybeuninit, cpu_global_mut, global_val}, + irq::{IrqHandleResult, IrqParam}, +}; + +use driver_interface::{interrupt_controller::IrqId, timer::*}; +use log::error; + +#[derive(Default)] +pub(crate) struct TimerData { + timer: Option<Device<Timer>>, +} + +pub fn since_boot() -> Duration { + _since_boot().unwrap_or_default() +} + +fn _since_boot() -> Option<Duration> { + Some(cpu_global_meybeuninit()?.timer.timer.as_ref()?.since_boot()) +} + +pub(crate) fn init_main_cpu() { + match &global_val().platform_info { + crate::globals::PlatformInfoKind::DeviceTree(fdt) => { + if let Err(e) = driver_manager::init_timer_by_fdt(fdt.get_addr()) { + error!("{}", e); + } + } + } + + init_current_cpu(); +} + +pub(crate) fn init_current_cpu() -> Option<()> { + let timer = manager().timer.get_cpu_timer(); + unsafe { cpu_global_mut().timer.timer = timer }; + + let mut t = timer_write()?; + + t.set_irq_enable(false); + t.enable(); + + let irq_chip = t.descriptor.irq.as_ref()?.irq_parent; + + IrqParam { + irq_chip, + cfg: t.irq(), + } + .register_builder(irq_handle) + .register(); + + Some(()) +} + +fn timer_write() -> Option<BorrowGuard<Timer>> { + Some(timer_data().timer.as_ref()?.spin_try_use("Kernel")) +} +fn irq_handle(_irq: IrqId) -> IrqHandleResult { + let t = unsafe { &mut *timer_data().timer.as_ref().unwrap().force_use() }; + t.handle_irq(); + IrqHandleResult::Handled +} + +fn timer_data() -> &'static TimerData { + &cpu_global().timer +} + +pub fn after(duration: Duration, call: impl Fn() + 'static) { + if let Some(mut t) = timer_write() { + t.after(duration, call); + } +} + +pub fn spin_delay(duration: Duration) { + let now = since_boot(); + let at = now + duration; + + loop { + if since_boot() >= at { + break; + } + } +} + +pub fn sleep(duration: Duration) { + let pid = crate::task::current().info().pid; + after(duration, move || { + crate::task::wake_up_in_irq(pid); + }); + crate::task::suspend(); +} diff --git a/crates/sparreal-kernel/src/trap.rs b/crates/sparreal-kernel/src/trap.rs deleted file mode 100644 index 8b13789..0000000 --- a/crates/sparreal-kernel/src/trap.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/crates/sparreal-kernel/src/util/boot.rs b/crates/sparreal-kernel/src/util/boot.rs deleted file mode 100644 index d9fb636..0000000 --- a/crates/sparreal-kernel/src/util/boot.rs +++ /dev/null @@ -1,49 +0,0 @@ -use core::{fmt::Write, ptr::NonNull}; - -use fdt_parser::Fdt; - -pub fn boot_debug_hex(mut w: impl Write, v: u64) { - const HEX_BUF_SIZE: usize = 20; // 最大长度,包括前缀"0x"和数字 - let mut hex_buf: [char; HEX_BUF_SIZE] = ['0'; HEX_BUF_SIZE]; - let mut n = v; - let _ = w.write_str("0x"); - - if n == 0 { - let _ = w.write_str("0"); - return; - } - let mut i = 0; - while n > 0 { - let digit = n & 0xf; - let ch = if digit < 10 { - (b'0' + digit as u8) as char - } else { - (b'a' + (digit - 10) as u8) as char - }; - n >>= 4; // 右移四位 - hex_buf[i] = ch; - i += 1; - } - let s = &hex_buf[..i]; - for ch in s.iter().rev() { - let _ = w.write_char(*ch); - } -} - -pub struct StdoutReg { - pub reg: *const u8, - pub size: usize, -} - -pub unsafe fn stdout_reg(dtb: NonNull<u8>) -> Option<StdoutReg> { - let fdt = Fdt::from_ptr(dtb).ok()?; - let chosen = fdt.chosen()?; - if let Some(stdout) = chosen.stdout() { - let r = stdout.node.reg()?.next()?; - return Some(StdoutReg { - reg: r.address as usize as _, - size: r.size.unwrap_or_default(), - }); - } - None -} diff --git a/crates/sparreal-kernel/src/util/mod.rs b/crates/sparreal-kernel/src/util/mod.rs deleted file mode 100644 index 1fc13aa..0000000 --- a/crates/sparreal-kernel/src/util/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod boot; diff --git a/crates/sparreal-kernel/tests/test.rs b/crates/sparreal-kernel/tests/test.rs deleted file mode 100644 index 61e9a15..0000000 --- a/crates/sparreal-kernel/tests/test.rs +++ /dev/null @@ -1,15 +0,0 @@ -use sparreal_kernel::util::boot::boot_debug_hex; -use std::fmt; - -#[test] -fn test_hex_fmt() { - struct TestWriter; - impl fmt::Write for TestWriter { - fn write_str(&mut self, s: &str) -> fmt::Result { - std::println!("{}", s); - Ok(()) - } - } - - boot_debug_hex(TestWriter {}, 0x12345678); -} diff --git a/crates/sparreal-macros/Cargo.toml b/crates/sparreal-macros/Cargo.toml index 9122060..78a2712 100644 --- a/crates/sparreal-macros/Cargo.toml +++ b/crates/sparreal-macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sparreal-macros" -version = "0.0.5" -edition = "2021" +version.workspace = true +edition = "2024" license = "MIT" description = "macros for sparreal" authors = ["周睿 <zrufo747@outlook.com>"] @@ -15,5 +15,5 @@ proc-macro = true quote = "1.0" proc-macro2 = "1.0" syn = { version = "2.0", features = ["extra-traits", "full"] } - +abi-singleton = "0.3" [features] diff --git a/crates/sparreal-macros/src/api_trait.rs b/crates/sparreal-macros/src/api_trait.rs index 0f51d1a..1c49845 100644 --- a/crates/sparreal-macros/src/api_trait.rs +++ b/crates/sparreal-macros/src/api_trait.rs @@ -3,6 +3,8 @@ mod tests { use syn::TraitItem; + use super::*; + #[test] fn it_works() { let f = syn::parse_str::<syn::ItemTrait>( diff --git a/crates/sparreal-macros/src/arch/aarch64.rs b/crates/sparreal-macros/src/arch/aarch64.rs new file mode 100644 index 0000000..42bff9b --- /dev/null +++ b/crates/sparreal-macros/src/arch/aarch64.rs @@ -0,0 +1,72 @@ +#![allow(unused)] + +use proc_macro::TokenStream; +use syn::parse; + +pub fn store_cpu_context(input: TokenStream) -> Result<TokenStream, parse::Error> { + // let reg = syn::parse::<syn::LitStr>(input)?; + + // let after = format!("[{},#-0x20]!", reg.value()); + + let after = format!("[{},#-0x20]!", "sp"); + let asm_str = reg_op_pair("stp", "q", 0..32, &after, true); + + Ok(asm_str.parse().unwrap()) +} + +fn reg_op_pair( + op: &str, + reg: &str, + range: std::ops::Range<usize>, + after: &str, + reverse: bool, +) -> String { + let mut ls = range + .step_by(2) + .map(|p0| { + format!( + "{op} {:>3},{:>3}, {after}", + format!("{reg}{p0}"), + format!("{reg}{}", p0 + 1) + ) + }) + .collect::<Vec<_>>(); + + if reverse { + ls.reverse(); + } + + ls.join("\n") +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_reg_op_pair() { + let want = " +ldp X1, X2, [sp], #0x10 +ldp X3, X4, [sp], #0x10 +ldp X5, X6, [sp], #0x10 +ldp X7, X8, [sp], #0x10 +ldp X9,X10, [sp], #0x10 +ldp X11,X12, [sp], #0x10 +ldp X13,X14, [sp], #0x10 +ldp X15,X16, [sp], #0x10 +ldp X17,X18, [sp], #0x10 +ldp X19,X20, [sp], #0x10 +ldp X21,X22, [sp], #0x10 +ldp X23,X24, [sp], #0x10 +ldp X25,X26, [sp], #0x10 +ldp X27,X28, [sp], #0x10 +ldp X29,X30, [sp], #0x10 +"; + + let a_str = reg_op_pair("ldp", "X", 1..31, "[sp], #0x10", false); + + println!("{a_str}"); + + assert_eq!(a_str.trim(), want.trim()); + } +} diff --git a/crates/sparreal-macros/src/arch/mod.rs b/crates/sparreal-macros/src/arch/mod.rs new file mode 100644 index 0000000..de0a2a6 --- /dev/null +++ b/crates/sparreal-macros/src/arch/mod.rs @@ -0,0 +1 @@ +pub mod aarch64; diff --git a/crates/sparreal-macros/src/lib.rs b/crates/sparreal-macros/src/lib.rs index f8cf27a..8047d81 100644 --- a/crates/sparreal-macros/src/lib.rs +++ b/crates/sparreal-macros/src/lib.rs @@ -7,13 +7,11 @@ extern crate proc_macro2; extern crate syn; mod api_trait; +mod arch; use proc_macro::TokenStream; -use proc_macro2::{Ident, Span}; -use syn::{ - parse, spanned::Spanned, FnArg, ImplItem, ItemFn, ItemImpl, ItemTrait, Pat, PathArguments, - TraitItem, Type, Visibility, -}; +use proc_macro2::Span; +use syn::{FnArg, ItemFn, PathArguments, Type, Visibility, parse, spanned::Spanned}; /// Attribute to declare the entry point of the program /// @@ -113,7 +111,7 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { quote!( #[allow(non_snake_case)] - #[no_mangle] + #[unsafe(no_mangle)] #(#attrs)* pub #unsafety extern "C" fn __sparreal_rt_main(#args) { #(#stmts)* @@ -135,109 +133,61 @@ fn is_simple_type(ty: &Type, name: &str) -> bool { false } -fn func_ident(trait_ident: &Ident, func_ident: &Ident) -> Ident { - let trait_ident = trait_ident.to_string().to_ascii_lowercase(); - format_ident!("__sparreal_api_{}_{}", trait_ident, func_ident) -} +const NAMESPACE: &str = "sparreal_os"; #[proc_macro_attribute] -pub fn api_trait(_args: TokenStream, input: TokenStream) -> TokenStream { - let f = parse_macro_input!(input as ItemTrait); - - let mut funcs = Vec::new(); - - for item in &f.items { - if let TraitItem::Fn(func) = item { - let ident = func.sig.ident.clone(); - let inputs = func.sig.inputs.clone(); - let output = func.sig.output.clone(); - - let api_name = func_ident(&f.ident, &ident); - - let mut args = Vec::new(); - - for arg in &inputs { - if let FnArg::Typed(t) = arg { - if let Pat::Ident(i) = t.pat.as_ref() { - let ident = &i.ident; - args.push(quote! { #ident , }); - } - } - } - funcs.push(quote! { - - pub unsafe fn #ident (#inputs) #output{ - extern "Rust" { - fn #api_name ( #inputs ) #output; - } +pub fn api_trait(_args: TokenStream, item: TokenStream) -> TokenStream { + abi_singleton::api_trait(item, NAMESPACE) +} - #api_name ( #(#args)* ) - } - }); - } - } +#[proc_macro_attribute] +pub fn api_impl(_args: TokenStream, item: TokenStream) -> TokenStream { + abi_singleton::api_impl(item, NAMESPACE) +} +#[proc_macro] +pub fn build_test_setup(_input: TokenStream) -> TokenStream { quote! { - #f - #(#funcs)* - + println!("cargo::rustc-link-arg-tests=-Tlink.x"); + println!("cargo::rustc-link-arg-tests=-no-pie"); + println!("cargo::rustc-link-arg-tests=-znostart-stop-gc"); } .into() } -#[proc_macro_attribute] -pub fn api_impl(_args: TokenStream, input: TokenStream) -> TokenStream { - let f = parse_macro_input!(input as ItemImpl); - - let mut funcs = Vec::new(); - - let ty = f.self_ty.clone(); - - for item in &f.items { - if let ImplItem::Fn(func) = item { - let ident = func.sig.ident.clone(); - let inputs = func.sig.inputs.clone(); - let output = func.sig.output.clone(); - - let api_name = func_ident( - f.trait_.clone().unwrap().1.get_ident().unwrap(), - &func.sig.ident, - ); - - let mut args = Vec::new(); - - for arg in &inputs { - if let FnArg::Typed(t) = arg { - if let Pat::Ident(i) = t.pat.as_ref() { - let ident = &i.ident; - args.push(quote! { #ident , }); +#[proc_macro] +pub fn module_driver(input: TokenStream) -> TokenStream { + let input = proc_macro2::TokenStream::from(input); + let mut name = None; + + { + let mut it = input.clone().into_iter(); + while let Some(t) = it.next() { + if let proc_macro2::TokenTree::Ident(i) = t { + if i == "name" { + it.next(); + if let Some(proc_macro2::TokenTree::Literal(l)) = it.next() { + let l = l.to_string(); + let l = l.trim_matches('"'); + name = Some(l.to_string()); + break; } } } - - funcs.push(quote! { - #[no_mangle] - unsafe fn #api_name (#inputs) #output{ - #ty:: #ident ( #(#args)* ) - } - }); } } - quote! { - #f - #(#funcs)* + let st_name = name.unwrap_or_default().replace("-", "_").replace(" ", "_"); - } - .into() -} + let static_name = format_ident!("DRIVER_{}", st_name.to_uppercase()); -#[proc_macro] -pub fn build_test_setup(_input: TokenStream) -> TokenStream { quote! { - println!("cargo::rustc-link-arg-tests=-Tlink.x"); - println!("cargo::rustc-link-arg-tests=-no-pie"); - println!("cargo::rustc-link-arg-tests=-znostart-stop-gc"); + #[unsafe(link_section = ".driver.register")] + #[unsafe(no_mangle)] + #[used(linker)] + pub static #static_name: sparreal_kernel::driver_interface::DriverRegister = sparreal_kernel::driver_interface::DriverRegister{ + #input + }; } .into() } diff --git a/crates/sparreal-macros/tests/test.rs b/crates/sparreal-macros/tests/test.rs new file mode 100644 index 0000000..0bbac32 --- /dev/null +++ b/crates/sparreal-macros/tests/test.rs @@ -0,0 +1,4 @@ +#![feature(used_with_arg)] + +#[test] +fn test_module() {} diff --git a/crates/sparreal-rt/.gitignore b/crates/sparreal-rt/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/crates/sparreal-rt/.gitignore @@ -0,0 +1 @@ +/target diff --git a/crates/sparreal-rt/Cargo.toml b/crates/sparreal-rt/Cargo.toml index bd675c8..5d5c7d7 100644 --- a/crates/sparreal-rt/Cargo.toml +++ b/crates/sparreal-rt/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "sparreal-rt" -version = "0.2.0" -authors = ["Zhourui <zrufo747@outlook.com>"] -edition = "2021" -repository = "https://github.com/qclic/sparreal-os" +version.workspace = true +authors = ["周睿 <zrufo747@outlook.com>"] +edition = "2024" +repository = "https://github.com/ZR233/sparreal-os" license = "MPL-2.0" description = "Sparreal OS Runtime" keywords = ["os"] @@ -15,18 +15,16 @@ early-print = [] [dependencies] log = "0.4" -sparreal-kernel = { version = "0.1", path = "../sparreal-kernel", features = [ +page-table-generic = { version = "0.3" } +futures = { version = "0.3", default-features = false, features = ["alloc"] } +sparreal-macros = { version = "0.6", path = "../sparreal-macros" } +sparreal-kernel = { version = "0.6", path = "../sparreal-kernel", features = [ "mmu", ] } -page-table-generic = { version = "0.2.2" } -driver-interface = { version = "0.0.1", path = "../driver-interface" } -futures = { version = "0.3", default-features = false, features = ["alloc"] } -embedded-io = "0.6" -memory_addr = "0.3" -sparreal-macros = { version = "0.0.5", path = "../sparreal-macros" } bitflags = "2.6" fdt-parser = "0.4" dma-api = "0.2" +buddy_system_allocator = "0.11" [target.'cfg(target_arch = "aarch64")'.dependencies] @@ -34,5 +32,5 @@ aarch64-cpu = "10.0" tock-registers = "0.9" arm-pl011-rs = "0.2" arm-gic-driver = "0.3" -# arm_pl031 = "0.2.1" +arm_pl031 = "0.2.1" page-table-arm = { version = "0.1", path = "../page-table-arm" } diff --git a/crates/sparreal-rt/build.rs b/crates/sparreal-rt/build.rs index 4a261e7..0a5f311 100644 --- a/crates/sparreal-rt/build.rs +++ b/crates/sparreal-rt/build.rs @@ -12,8 +12,13 @@ fn main() { println!("cargo::rustc-link-arg=-znostart-stop-gc"); println!("cargo:rustc-link-search={}", config.out_dir.display()); - println!("cargo:rerun-if-changed=Link.ld"); - // println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=link.ld"); + println!("cargo:rerun-if-changed=build.rs"); + + println!("cargo::rustc-check-cfg=cfg(hard_float)"); + if std::env::var("TARGET").unwrap() == "aarch64-unknown-none" { + println!("cargo::rustc-cfg=hard_float"); + } } #[derive(Debug)] pub enum Arch { @@ -32,23 +37,25 @@ impl Default for Arch { } } } + struct Config { - // smp: usize, - hart_stack_size: usize, + stack_size: usize, out_dir: PathBuf, arch: Arch, } // 8MiB stack size per hart -const DEFAULT_HART_STACK_SIZE: usize = 8 * 1024 * 1024; +const DEFAULT_KERNEL_STACK_SIZE: usize = 8 * 1024 * 1024; const KERNEL_VADDR: u64 = 0xffff_ff00_0008_0000; +// const KERNEL_VADDR: u64 = 0x40080000; +// const KERNEL_VADDR: u64 = 0x1000000; impl Config { fn new() -> Self { let arch = Arch::default(); Self { - hart_stack_size: DEFAULT_HART_STACK_SIZE, + stack_size: DEFAULT_KERNEL_STACK_SIZE, out_dir: PathBuf::from(std::env::var("OUT_DIR").unwrap()), arch, } @@ -63,24 +70,19 @@ impl Config { format!("{:?}", self.arch) }; - let ld_content = std::fs::read_to_string("Link.ld").unwrap(); + let ld_content = std::fs::read_to_string("link.ld").unwrap(); let ld_content = ld_content.replace("%ARCH%", &output_arch); let ld_content = ld_content.replace("%KERNEL_VADDR%", &format!("{:#x}", KERNEL_VADDR)); - let ld_content = - ld_content.replace("%STACK_SIZE%", &format!("{:#x}", self.hart_stack_size)); - let ld_content = - ld_content.replace("%CPU_STACK_SIZE%", &format!("{:#x}", self.hart_stack_size)); + + let ld_content = ld_content.replace("%STACK_SIZE%", &format!("{:#x}", self.stack_size)); std::fs::write(self.out_dir.join("link.x"), ld_content).expect("link.x write failed"); } fn gen_const(&self) { let const_content = format!( - r#" - - pub const SMP: usize = {:#x}; - pub const HART_STACK_SIZE: usize = {:#x}; + r#"pub const KERNEL_STACK_SIZE: usize = {:#x}; "#, - 1, self.hart_stack_size + self.stack_size ); std::fs::write(self.out_dir.join("constant.rs"), const_content) diff --git a/crates/sparreal-rt/Link.ld b/crates/sparreal-rt/link.ld similarity index 73% rename from crates/sparreal-rt/Link.ld rename to crates/sparreal-rt/link.ld index 1571863..d2936bd 100644 --- a/crates/sparreal-rt/Link.ld +++ b/crates/sparreal-rt/link.ld @@ -2,15 +2,7 @@ OUTPUT_ARCH(%ARCH%) ENTRY(_start) -/* Define the program headers we want so the bootloader gives us the right */ -/* MMU permissions; this also allows us to exert more control over the linking */ -/* process. */ -PHDRS -{ - text PT_LOAD; - rodata PT_LOAD; - data PT_LOAD; -} + SECTIONS { @@ -19,14 +11,14 @@ SECTIONS .text : ALIGN(4K) { _stext = .; - KEEP(*(.head.text)) + KEEP(*(.text.head)) KEEP(*(.text.boot.start)) KEEP(*(.text.boot .text.boot.*)) . = ALIGN(4); *(.text .text.*); . = ALIGN(4K); _etext = .; - } :text + } .rodata : ALIGN(4K) { _srodata = .; @@ -35,8 +27,14 @@ SECTIONS *(.sdata2 .sdata2.*) . = ALIGN(4K); _erodata = .; - } :rodata + } + .driver.register : ALIGN(4K) { + _sdriver = .; + *(.driver.register .driver.register.*) + _edriver = .; + . = ALIGN(4K); + } .data : ALIGN(4K) { _sdata = .; @@ -45,20 +43,20 @@ SECTIONS *(.data .data.*) *(.sdata .sdata.*) *(.got .got.*) - } :data + } .tdata : ALIGN(0x10) { _stdata = .; *(.tdata .tdata.*) _etdata = .; - } :data + } .tbss : ALIGN(0x10) { _stbss = .; *(.tbss .tbss.*) *(.tcommon) _etbss = .; - } :data + } . = ALIGN(4K); _edata = .; @@ -70,14 +68,14 @@ SECTIONS *(COMMON) . = ALIGN(4K); _ebss = .; - } :data + } _ekernel = .; + _kernel_size = _ekernel - _skernel; . = ALIGN(4K); + _stack_bottom = .; _stack_top = . + %STACK_SIZE%; - _cpu_stack_size = %CPU_STACK_SIZE%; - _kernel_size = _stack_top - _skernel; /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } diff --git a/crates/sparreal-rt/src/arch/aarch64/boot.rs b/crates/sparreal-rt/src/arch/aarch64/boot.rs index a47f411..edd258f 100644 --- a/crates/sparreal-rt/src/arch/aarch64/boot.rs +++ b/crates/sparreal-rt/src/arch/aarch64/boot.rs @@ -1,187 +1,38 @@ use core::{ arch::{asm, global_asm}, - cell::UnsafeCell, - ptr::{slice_from_raw_parts_mut, NonNull}, + ptr::NonNull, }; -use aarch64_cpu::{asm::barrier, registers::*}; -use fdt_parser::Fdt; -use kernel::{BootConfig, MemoryReservedRange}; -use mem::*; -use page_table_generic::{AccessSetting, CacheSetting}; -use platform::PlatformPageTable; -use sparreal_kernel::*; -use tock_registers::interfaces::ReadWriteable; +use crate::mem::clear_bss; +use aarch64_cpu::registers::*; +use sparreal_kernel::{io::print::*, platform::PlatformInfoKind}; -use crate::{ - arch::{ - debug::{init_debug, mmu_add_offset}, - mmu::PageTableImpl, - }, - consts::*, -}; - -use super::mmu; - -global_asm!(include_str!("boot.S")); -global_asm!(include_str!("vectors.S")); - -extern "C" { - fn _skernel(); - fn _ekernel(); - fn _stack_top(); -} - -pub(crate) static BOOT_INFO: BootInfoWapper = BootInfoWapper::new(); - -#[no_mangle] -unsafe extern "C" fn __rust_main(dtb_addr: usize, va_offset: usize) -> ! { - clear_bss(); - print_info(dtb_addr, va_offset); - BOOT_INFO.as_mut().va_offset = va_offset; - - let mut kernel_end = Phys::from(_ekernel as *const u8); - - let new_dtb_addr = sparreal_kernel::driver::move_dtb( - dtb_addr as _, - NonNull::new_unchecked(kernel_end.as_usize() as _), - ); - - if let Some(addr) = new_dtb_addr { - BOOT_INFO.as_mut().fdt_addr = addr.as_ptr() as usize; - - dbg!("DTB moved to "); - dbg_hex!(BOOT_INFO.as_ref().fdt_addr); - dbg!(", size: "); - dbg_hexln!(addr.len()); - kernel_end = kernel_end + addr.len(); - } - - dbg!("Kernel @"); - dbg_hexln!(_skernel as *const u8 as usize); - - let kernel_start = Phys::from(_skernel as *const u8).align_down(BYTES_1M * 2); - let kernel_size = kernel_end - kernel_start; - - if let Err(msg) = config_memory_by_fdt(kernel_start, kernel_size) { - dbgln!(msg); - - BOOT_INFO.as_mut().main_memory.start = kernel_start; - BOOT_INFO.as_mut().main_memory_heap_offset = kernel_size; - BOOT_INFO.as_mut().main_memory.size = - BOOT_INFO.as_ref().main_memory_heap_offset + BYTES_1M * 16; - } - - let table = mmu::init_boot_table(); - - dbgln!("table initialized"); - - // Enable TTBR0 and TTBR1 walks, page size = 4K, vaddr size = 48 bits, paddr size = 40 bits. - let tcr_flags0 = TCR_EL1::EPD0::EnableTTBR0Walks - + TCR_EL1::TG0::KiB_4 - + TCR_EL1::SH0::Inner - + TCR_EL1::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::T0SZ.val(16); - let tcr_flags1 = TCR_EL1::EPD1::EnableTTBR1Walks - + TCR_EL1::TG1::KiB_4 - + TCR_EL1::SH1::Inner - + TCR_EL1::ORGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::IRGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::T1SZ.val(16); - TCR_EL1.write(TCR_EL1::IPS::Bits_48 + tcr_flags0 + tcr_flags1); - - // 需要先清缓存 - PageTableImpl::flush_tlb(None); +global_asm!(include_str!("boot.s")); - // Set both TTBR0 and TTBR1 - TTBR1_EL1.set_baddr(table); - TTBR0_EL1.set_baddr(table); +#[unsafe(no_mangle)] +extern "C" fn __rust_boot(va_offset: usize, fdt_addr: usize) { + unsafe { + clear_bss(); - BOOT_INFO.as_mut().stack_top = - BOOT_INFO.as_ref().main_memory.start + BOOT_INFO.as_ref().main_memory.size; + let platform_info: PlatformInfoKind = if let Some(addr) = NonNull::new(fdt_addr as _) { + PlatformInfoKind::new_fdt(addr) + } else { + todo!() + }; - let stack_top = BOOT_INFO.as_ref().stack_top.as_usize() + va_offset; - - dbg!("stack top: "); - dbg_hexln!(stack_top); - dbg!("TCR_EL1:"); - dbg_hexln!(TCR_EL1.get()); - dbgln!("table set"); - - mmu_add_offset(va_offset); - if BOOT_INFO.as_ref().fdt_addr > 0 { - BOOT_INFO.as_mut().fdt_addr += va_offset; - } - PageTableImpl::flush_tlb(None); - // Enable the MMU and turn on I-cache and D-cache - SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable); - barrier::isb(barrier::SY); - - asm!(" - MOV sp, {sp_top} - ADD x30, x30, {offset} - LDR x8, =__rust_main_after_mmu - BLR x8 - B . - ", - sp_top = in(reg) stack_top, - offset = in(reg) va_offset, - options(noreturn) - ) -} - -#[no_mangle] -unsafe extern "C" fn __rust_main_after_mmu() -> ! { - dbgln!("MMU enabled"); - - let cfg = KernelConfig { - boot_info: BOOT_INFO.to_boot_config(), - stack_top: BOOT_INFO.as_ref().stack_top, - dtb_addr: NonNull::new(BOOT_INFO.as_ref().fdt_addr as _), - }; - - crate::boot(cfg); -} + if let Some(info) = platform_info.debugcon() { + crate::debug::init_by_info(info); + } -unsafe fn clear_bss() { - extern "C" { - fn _sbss(); - fn _ebss(); - } - let bss = &mut *slice_from_raw_parts_mut(_sbss as *mut u8, _ebss as usize - _sbss as usize); - bss.fill(0); -} + let rsv = []; -unsafe fn print_info(dtb_addr: usize, va_offset: usize) { - if let Some(dtb) = NonNull::new(dtb_addr as *mut u8) { - if let Some(reg) = util::boot::stdout_reg(dtb) { - BOOT_INFO.as_mut().early_debug_reg = Some(MemoryRange { - start: reg.reg.into(), - size: reg.size, - }); - init_debug(reg); + if let Err(s) = sparreal_kernel::boot::start(va_offset, platform_info, &rsv) { + early_dbgln(s); } } - if let Some(dtb) = NonNull::new(dtb_addr as *mut u8) { - if let Ok(fdt) = fdt_parser::Fdt::from_ptr(dtb) { - let cpu = fdt.boot_cpuid_phys(); - dbg!("DTB boot CPU: "); - dbg_hexln!(cpu); - } - } - - dbg!("dtb @"); - dbg_hex!(dtb_addr); - dbg!(" va_offset: "); - dbg_hexln!(va_offset); } -fn device_tree() -> Option<Fdt<'static>> { - Fdt::from_ptr(NonNull::new(BOOT_INFO.as_ref().fdt_addr as _)?).ok() -} - -#[no_mangle] +#[unsafe(no_mangle)] unsafe extern "C" fn __switch_to_el1() { SPSel.write(SPSel::SP::ELx); SP_EL0.set(0); @@ -200,12 +51,14 @@ unsafe extern "C" fn __switch_to_el1() { + SPSR_EL3::I::Masked + SPSR_EL3::F::Masked, ); - asm!( - " + unsafe { + asm!( + " adr x2, _start_boot msr elr_el3, x2 " - ); + ); + } } // Disable EL1 timer traps and the timer offset. CNTHCTL_EL2.modify(CNTHCTL_EL2::EL1PCEN::SET + CNTHCTL_EL2::EL1PCTEN::SET); @@ -220,9 +73,9 @@ unsafe extern "C" fn __switch_to_el1() { + SPSR_EL2::I::Masked + SPSR_EL2::F::Masked, ); - - asm!( - " + unsafe { + asm!( + " mov x8, sp msr sp_el1, x8 MOV x0, x19 @@ -230,113 +83,9 @@ unsafe extern "C" fn __switch_to_el1() { msr elr_el2, x2 eret " - ); - } else { - asm!("bl _el1_entry") - } -} - -unsafe fn config_memory_by_fdt( - kernel_start: Phys<u8>, - kernel_size: usize, -) -> Result<(), &'static str> { - let fdt = device_tree().ok_or("FDT not found")?; - - for node in fdt.memory() { - for region in node.regions() { - let address = region.address as usize; - dbg!("memory @"); - dbg_hex!(address); - dbg!(", size: "); - dbg_hexln!(region.size); - - if address <= kernel_start.as_usize() && kernel_start.as_usize() < address + region.size - { - BOOT_INFO.as_mut().main_memory.start = address.into(); - BOOT_INFO.as_mut().main_memory.size = region.size; - BOOT_INFO.as_mut().main_memory_heap_offset = - kernel_start.as_usize() + kernel_size - address; - - dbg!("Kernel start: "); - dbg_hex!(kernel_start.as_usize()); - dbg!(", Kernel is in this memory, used: "); - dbg_hexln!(BOOT_INFO.as_ref().main_memory_heap_offset); - - return Ok(()); - } - } - } - if BOOT_INFO.as_mut().main_memory.size == 0 { - Err("No memory region found") + ) + }; } else { - Ok(()) - } -} - -pub(crate) struct BootInfoWapper(UnsafeCell<BootInfo>); - -unsafe impl Sync for BootInfoWapper {} - -impl BootInfoWapper { - pub const fn new() -> Self { - Self(UnsafeCell::new(BootInfo::new())) - } - - #[allow(clippy::mut_from_ref)] - pub unsafe fn as_mut(&self) -> &mut BootInfo { - &mut *self.0.get() - } - - pub fn as_ref(&self) -> &BootInfo { - unsafe { &*self.0.get() } - } - - pub fn to_boot_config(&self) -> BootConfig { - self.as_ref().to_boot_config() - } -} - -pub(crate) struct BootInfo { - va_offset: usize, - fdt_addr: usize, - main_memory: MemoryRange, - main_memory_heap_offset: usize, - early_debug_reg: Option<MemoryRange>, - stack_top: Phys<u8>, -} - -unsafe impl Send for BootInfo {} - -impl BootInfo { - const fn new() -> Self { - Self { - va_offset: 0, - fdt_addr: 0, - main_memory: MemoryRange::new(), - main_memory_heap_offset: 0, - early_debug_reg: None, - stack_top: Phys::new(), - } - } - - pub fn to_boot_config(&self) -> BootConfig { - let mut reserved_memory = [None; 24]; - - if let Some(reg) = self.early_debug_reg { - reserved_memory[0] = Some(MemoryReservedRange { - start: reg.start, - size: reg.size, - access: AccessSetting::Read | AccessSetting::Write, - cache: CacheSetting::Device, - name: "debug uart", - }); - } - BootConfig { - main_memory: self.main_memory, - main_memory_heap_offset: self.main_memory_heap_offset, - hart_stack_size: HART_STACK_SIZE, - reserved_memory, - va_offset: self.va_offset, - } + unsafe { asm!("bl _el1_entry") } } } diff --git a/crates/sparreal-rt/src/arch/aarch64/boot.S b/crates/sparreal-rt/src/arch/aarch64/boot.s similarity index 65% rename from crates/sparreal-rt/src/arch/aarch64/boot.S rename to crates/sparreal-rt/src/arch/aarch64/boot.s index a677374..905e9a1 100644 --- a/crates/sparreal-rt/src/arch/aarch64/boot.S +++ b/crates/sparreal-rt/src/arch/aarch64/boot.s @@ -1,4 +1,4 @@ -.section ".head.text","ax" +.section ".text.head","ax" .global _start // Linux header @@ -39,31 +39,40 @@ _start_boot: MOV x19, x0 // x19 = dtb_addr + // // 获取当前CPU ID + // MRS x2, mpidr_el1 + // AND x2, x2, #0xFF // 只保留CPU ID部分 + + // // 设备树中的start cpuid存储在设备树的偏移量处 + // ADD x3, x19, #0x28 + // LDR x4, [x3] // x4 = start cpuid from dtb + + // // 比较当前CPU ID和start cpuid + // CMP x2, x4 + // BNE .wfi_loop // 如果不相等,跳转到wfi循环 + LDR x1, =_stack_top SUB x1, x1, x18 // X1 == STACK_TOP MOV sp, x1 - BL __switch_to_el1 -.global _el1_entry -.type _el1_entry, @function + _el1_entry: // Install vector table // --------------------- .global vector_table_el1 LDR x0, =vector_table_el1 MSR VBAR_EL1, x0 - + MOV X1, #(0x3 << 20) // FPEN disables trapping to EL1. MSR CPACR_EL1, X1 ISB - MOV x0, x19 - MOV x1, x18 - BL __rust_main - B . + MOV x0, x18 + MOV x1, x19 + BL __rust_boot -_suspend: - wfi - B _suspend \ No newline at end of file +.wfi_loop: + WFI // 等待中断 + B .wfi_loop // 无限循环等待中断 \ No newline at end of file diff --git a/crates/sparreal-rt/src/arch/aarch64/cache.rs b/crates/sparreal-rt/src/arch/aarch64/cache.rs index 9e48c25..1b1e760 100644 --- a/crates/sparreal-rt/src/arch/aarch64/cache.rs +++ b/crates/sparreal-rt/src/arch/aarch64/cache.rs @@ -1,7 +1,10 @@ -use core::{arch::asm, ptr::NonNull}; +#![allow(unused)] -use dma_api::Impl; -use sparreal_kernel::mem::{mmu::va_offset, Virt}; +use core::arch::asm; + +use aarch64_cpu::{asm::barrier::*, registers::*}; + +use super::CacheOp; #[inline(always)] fn cache_line_size() -> usize { @@ -14,78 +17,91 @@ fn cache_line_size() -> usize { } } -struct DCacheIter { - aligned_addr: usize, - end: usize, - cache_line_size: usize, -} +/// Performs a cache operation on all memory. +pub fn dcache_all(op: CacheOp) { + let clidr = CLIDR_EL1.get(); -impl DCacheIter { - fn new(addr: NonNull<u8>, size: usize) -> DCacheIter { - let start = addr.as_ptr() as usize; - let end = start + size; - let cache_line_size = cache_line_size(); - - let aligned_addr = addr.as_ptr() as usize & !(cache_line_size - 1); - DCacheIter { - aligned_addr, - end, - cache_line_size, + for level in 0..8 { + let ty = (clidr >> (level * 3)) & 0b111; + if ty == 0 { + return; } + + dcache_level(op, level); } + dsb(SY); + isb(SY); } -impl Iterator for DCacheIter { - type Item = usize; +/// Performs a cache operation on a range of memory. +#[inline] +pub fn dcache_range(op: CacheOp, addr: usize, size: usize) { + let start = addr; + let end = start + size; + let cache_line_size = cache_line_size(); - fn next(&mut self) -> Option<Self::Item> { - if self.aligned_addr < self.end { - let addr = self.aligned_addr; - self.aligned_addr += self.cache_line_size; - Some(addr) - } else { - None - } + let mut aligned_addr = addr & !(cache_line_size - 1); + + while aligned_addr < end { + _dcache_line(op, aligned_addr); + aligned_addr += cache_line_size; } + + dsb(SY); + isb(SY); } -/// Invalidate data cache -pub fn dcache_invalidate_range(addr: NonNull<u8>, size: usize) { +/// Performs a cache operation on a cache line. +#[inline] +fn _dcache_line(op: CacheOp, addr: usize) { unsafe { - for addr in DCacheIter::new(addr, size) { - asm!("dc ivac, {}", in(reg) addr); + match op { + CacheOp::Invalidate => asm!("dc ivac, {0}", in(reg) addr), + CacheOp::Clean => asm!("dc cvac, {0}", in(reg) addr), + CacheOp::CleanAndInvalidate => asm!("dc civac, {0}", in(reg) addr), } - asm!("dsb sy"); } } -/// Flush data cache -pub fn dcache_flush_range(addr: NonNull<u8>, size: usize) { - unsafe { - for addr in DCacheIter::new(addr, size) { - asm!("dc civac, {}", in(reg) addr); - } - asm!("dsb sy"); - } +/// Performs a cache operation on a cache line. +#[inline] +pub fn dcache_line(op: CacheOp, addr: usize) { + _dcache_line(op, addr); + dsb(SY); + isb(SY); } -struct DMAImpl; +/// Performs a cache operation on a cache level. +/// https://developer.arm.com/documentation/ddi0601/2024-12/AArch64-Instructions/DC-CISW--Data-or-unified-Cache-line-Clean-and-Invalidate-by-Set-Way +#[inline] +fn dcache_level(op: CacheOp, level: u64) { + assert!(level < 8, "armv8 level range is 0-7"); -impl Impl for DMAImpl { - fn map(addr: NonNull<u8>, _size: usize, _direction: dma_api::Direction) -> u64 { - let p: Virt<u8> = Virt::from(addr.as_ptr()); - p.convert_to_phys(va_offset()).as_usize() as _ - } + isb(SY); + CSSELR_EL1.write(CSSELR_EL1::InD::Data + CSSELR_EL1::Level.val(level)); + isb(SY); + let lines = CCSIDR_EL1.read(CCSIDR_EL1::LineSize) as u32; + let ways = CCSIDR_EL1.read(CCSIDR_EL1::AssociativityWithCCIDX) as u32; + let sets = CCSIDR_EL1.read(CCSIDR_EL1::NumSetsWithCCIDX) as u32; - fn unmap(_addr: NonNull<u8>, _size: usize) {} + let l = lines + 4; - fn flush(addr: NonNull<u8>, size: usize) { - dcache_flush_range(addr, size); - } + // Calculate bit position of number of ways + let way_adjust = ways.leading_zeros(); - fn invalidate(addr: NonNull<u8>, size: usize) { - dcache_invalidate_range(addr, size); + // Loop over sets and ways + for set in 0..sets { + for way in 0..ways { + let set_way = (way << way_adjust) | (set << l); + + let cisw = (level << 1) | set_way as u64; + unsafe { + match op { + CacheOp::Invalidate => asm!("dc isw, {0}", in(reg) cisw), + CacheOp::Clean => asm!("dc csw, {0}", in(reg) cisw), + CacheOp::CleanAndInvalidate => asm!("dc cisw, {0}", in(reg) cisw), + } + } + } } } - -dma_api::set_impl!(DMAImpl); diff --git a/crates/sparreal-rt/src/arch/aarch64/debug.rs b/crates/sparreal-rt/src/arch/aarch64/debug.rs deleted file mode 100644 index bd5c4b9..0000000 --- a/crates/sparreal-rt/src/arch/aarch64/debug.rs +++ /dev/null @@ -1,24 +0,0 @@ -use sparreal_kernel::util::boot::StdoutReg; - -static mut OUT_REG: usize = 0; - -pub unsafe fn mmu_add_offset(va_offset: usize) { - OUT_REG += va_offset; -} - -#[cfg(feature = "early-print")] -pub unsafe fn put_debug(char: u8) { - if OUT_REG == 0 { - return; - } - let base = OUT_REG; - - let state = (base + 0x18) as *mut u8; - let put = (base) as *mut u8; - while (state.read_volatile() & 0x20_u8) != 0 {} - put.write_volatile(char); -} - -pub fn init_debug(stdout: StdoutReg) { - unsafe { OUT_REG = stdout.reg as usize }; -} diff --git a/crates/sparreal-rt/src/arch/aarch64/gic/gic_v2.rs b/crates/sparreal-rt/src/arch/aarch64/gic/gic_v2.rs new file mode 100644 index 0000000..08e7c24 --- /dev/null +++ b/crates/sparreal-rt/src/arch/aarch64/gic/gic_v2.rs @@ -0,0 +1,131 @@ +use alloc::{boxed::Box, format, sync::Arc, vec::Vec}; +use core::{cell::UnsafeCell, error::Error, ptr::NonNull}; + +use arm_gic_driver::GicGeneric; +use sparreal_kernel::{ + driver_interface::{DriverGeneric, ProbeFnKind, RegAddress, interrupt_controller::*}, + mem::iomap, +}; +use sparreal_macros::module_driver; + +use super::*; + +module_driver!( + name: "GICv2", + compatibles: &["arm,cortex-a15-gic", "arm,gic-400"], + probe: ProbeFnKind::InterruptController(probe_gic_v2), +); + +struct GicV2 { + gicd: NonNull<u8>, + gicc: NonNull<u8>, + gic: Arc<UnsafeCell<Option<arm_gic_driver::GicV2>>>, +} + +unsafe impl Send for GicV2 {} + +impl GicV2 { + #[allow(clippy::arc_with_non_send_sync)] + fn new(gicd: NonNull<u8>, gicc: NonNull<u8>) -> Self { + Self { + gic: Arc::new(UnsafeCell::new(None)), + gicd, + gicc, + } + } +} + +struct GicV2PerCpu(Arc<UnsafeCell<Option<arm_gic_driver::GicV2>>>); + +unsafe impl Send for GicV2PerCpu {} + +impl GicV2PerCpu { + fn get_mut(&mut self) -> &mut arm_gic_driver::GicV2 { + unsafe { &mut *self.0.get() }.as_mut().unwrap() + } +} + +impl InterfaceCPU for GicV2PerCpu { + fn get_and_acknowledge_interrupt(&mut self) -> Option<IrqId> { + self.get_mut() + .get_and_acknowledge_interrupt() + .map(|id| (id.to_u32() as usize).into()) + } + + fn end_interrupt(&mut self, irq: IrqId) { + self.get_mut().end_interrupt(convert_id(irq)); + } + + fn irq_enable(&mut self, irq: IrqId) { + self.get_mut().irq_enable(convert_id(irq)); + } + + fn irq_disable(&mut self, irq: IrqId) { + self.get_mut().irq_disable(convert_id(irq)); + } + + fn set_priority(&mut self, irq: IrqId, priority: usize) { + self.get_mut().set_priority(convert_id(irq), priority); + } + + fn set_trigger(&mut self, irq: IrqId, trigger: Trigger) { + self.get_mut().set_trigger(convert_id(irq), match trigger { + Trigger::EdgeBoth => arm_gic_driver::Trigger::Edge, + Trigger::EdgeRising => arm_gic_driver::Trigger::Edge, + Trigger::EdgeFailling => arm_gic_driver::Trigger::Edge, + Trigger::LevelHigh => arm_gic_driver::Trigger::Level, + Trigger::LevelLow => arm_gic_driver::Trigger::Level, + }); + } + + fn set_bind_cpu(&mut self, irq: IrqId, cpu_list: &[CpuId]) { + let id_list = cpu_list + .iter() + .map(|v| arm_gic_driver::MPID::from(Into::<usize>::into(*v))) + .map(|v| v.into()) + .collect::<Vec<_>>(); + + self.get_mut().set_bind_cpu(convert_id(irq), &id_list); + } + + fn parse_fdt_config(&self, prop_interupt: &[u32]) -> Result<IrqConfig, Box<dyn Error>> { + fdt_parse_irq_config(prop_interupt) + } + + fn irq_pin_to_id(&self, pin: usize) -> Result<IrqId, Box<dyn Error>> { + super::irq_pin_to_id(pin) + } +} + +impl DriverGeneric for GicV2 { + fn open(&mut self) -> Result<(), alloc::string::String> { + let gic = + arm_gic_driver::GicV2::new(self.gicd, self.gicc).map_err(|e| format!("{:?}", e))?; + unsafe { &mut *self.gic.get() }.replace(gic); + + Ok(()) + } + + fn close(&mut self) -> Result<(), alloc::string::String> { + Ok(()) + } +} + +impl Interface for GicV2 { + fn current_cpu_setup(&self) -> Box<dyn InterfaceCPU> { + unsafe { &mut *self.gic.get() } + .as_mut() + .unwrap() + .current_cpu_setup(); + Box::new(GicV2PerCpu(self.gic.clone())) + } +} + +fn probe_gic_v2(regs: Vec<RegAddress>) -> Hardware { + let gicd_reg = regs[0]; + let gicc_reg = regs[1]; + let gicd = iomap(gicd_reg.addr.into(), gicd_reg.size.unwrap_or(0x1000)); + let gicc = iomap(gicc_reg.addr.into(), gicc_reg.size.unwrap_or(0x1000)); + + Box::new(GicV2::new(gicd, gicc)) +} diff --git a/crates/sparreal-rt/src/arch/aarch64/gic/gic_v3.rs b/crates/sparreal-rt/src/arch/aarch64/gic/gic_v3.rs new file mode 100644 index 0000000..608f233 --- /dev/null +++ b/crates/sparreal-rt/src/arch/aarch64/gic/gic_v3.rs @@ -0,0 +1,137 @@ +use core::{cell::UnsafeCell, error::Error, ptr::NonNull}; + +use alloc::{boxed::Box, format, sync::Arc, vec::Vec}; +use arm_gic_driver::{GicGeneric, GicV3, Trigger}; +use sparreal_kernel::{ + driver_interface::{ + DriverGeneric, ProbeFnKind, RegAddress, + interrupt_controller::{self, CpuId, InterfaceCPU}, + }, + mem::iomap, +}; +use sparreal_macros::module_driver; + +use super::*; + +module_driver!( + name: "GICv3", + compatibles: &["arm,gic-v3"], + probe: ProbeFnKind::InterruptController(probe_gic), +); + +struct Gic { + gicd: NonNull<u8>, + gicr: NonNull<u8>, + gic: Arc<UnsafeCell<Option<GicV3>>>, +} + +unsafe impl Send for Gic {} + +impl Gic { + #[allow(clippy::arc_with_non_send_sync)] + fn new(gicd: NonNull<u8>, gicr: NonNull<u8>) -> Self { + Self { + gic: Arc::new(UnsafeCell::new(None)), + gicd, + gicr, + } + } +} + +struct GicPerCpu(Arc<UnsafeCell<Option<GicV3>>>); + +unsafe impl Send for GicPerCpu {} + +impl GicPerCpu { + fn get_mut(&mut self) -> &mut GicV3 { + unsafe { &mut *self.0.get() }.as_mut().unwrap() + } +} + +impl InterfaceCPU for GicPerCpu { + fn get_and_acknowledge_interrupt(&mut self) -> Option<interrupt_controller::IrqId> { + self.get_mut() + .get_and_acknowledge_interrupt() + .map(|id| (id.to_u32() as usize).into()) + } + + fn end_interrupt(&mut self, irq: interrupt_controller::IrqId) { + self.get_mut().end_interrupt(convert_id(irq)); + } + + fn irq_enable(&mut self, irq: interrupt_controller::IrqId) { + self.get_mut().irq_enable(convert_id(irq)); + } + + fn irq_disable(&mut self, irq: interrupt_controller::IrqId) { + self.get_mut().irq_disable(convert_id(irq)); + } + + fn set_priority(&mut self, irq: interrupt_controller::IrqId, priority: usize) { + self.get_mut().set_priority(convert_id(irq), priority); + } + + fn set_trigger( + &mut self, + irq: interrupt_controller::IrqId, + trigger: interrupt_controller::Trigger, + ) { + self.get_mut().set_trigger(convert_id(irq), match trigger { + interrupt_controller::Trigger::EdgeBoth => Trigger::Edge, + interrupt_controller::Trigger::EdgeRising => Trigger::Edge, + interrupt_controller::Trigger::EdgeFailling => Trigger::Edge, + interrupt_controller::Trigger::LevelHigh => Trigger::Level, + interrupt_controller::Trigger::LevelLow => Trigger::Level, + }); + } + + fn set_bind_cpu(&mut self, irq: interrupt_controller::IrqId, cpu_list: &[CpuId]) { + let id_list = cpu_list + .iter() + .map(|v| arm_gic_driver::MPID::from(Into::<usize>::into(*v))) + .map(|v| v.into()) + .collect::<Vec<_>>(); + + self.get_mut().set_bind_cpu(convert_id(irq), &id_list); + } + + fn parse_fdt_config(&self, prop_interupt: &[u32]) -> Result<IrqConfig, Box<dyn Error>> { + fdt_parse_irq_config(prop_interupt) + } + + fn irq_pin_to_id(&self, pin: usize) -> Result<IrqId, Box<dyn Error>> { + super::irq_pin_to_id(pin) + } +} + +impl DriverGeneric for Gic { + fn open(&mut self) -> Result<(), alloc::string::String> { + let gic = GicV3::new(self.gicd, self.gicr).map_err(|e| format!("{:?}", e))?; + unsafe { &mut *self.gic.get() }.replace(gic); + + Ok(()) + } + + fn close(&mut self) -> Result<(), alloc::string::String> { + Ok(()) + } +} + +impl interrupt_controller::Interface for Gic { + fn current_cpu_setup(&self) -> Box<dyn interrupt_controller::InterfaceCPU> { + unsafe { &mut *self.gic.get() } + .as_mut() + .unwrap() + .current_cpu_setup(); + Box::new(GicPerCpu(self.gic.clone())) + } +} + +fn probe_gic(regs: Vec<RegAddress>) -> interrupt_controller::Hardware { + let gicd_reg = regs[0]; + let gicc_reg = regs[1]; + let gicd = iomap(gicd_reg.addr.into(), gicd_reg.size.unwrap_or(0x1000)); + let gicr = iomap(gicc_reg.addr.into(), gicc_reg.size.unwrap_or(0x1000)); + + Box::new(Gic::new(gicd, gicr)) +} diff --git a/crates/sparreal-rt/src/arch/aarch64/gic/mod.rs b/crates/sparreal-rt/src/arch/aarch64/gic/mod.rs new file mode 100644 index 0000000..05edd7a --- /dev/null +++ b/crates/sparreal-rt/src/arch/aarch64/gic/mod.rs @@ -0,0 +1,69 @@ +use core::error::Error; + +use alloc::boxed::Box; +use arm_gic_driver::IntId; +use sparreal_kernel::driver_interface::interrupt_controller::{IrqConfig, IrqId, Trigger}; + +mod gic_v2; +mod gic_v3; + +fn convert_id(irq: IrqId) -> IntId { + let id: usize = irq.into(); + unsafe { IntId::raw(id as u32) } +} + +use bitflags::bitflags; + +// The `bitflags!` macro generates `struct`s that manage a set of flags. +bitflags! { + /// Represents a set of flags. + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + struct TriggerFlag: usize { + const NONE = 0; + const EDGE_RISING = 1; + const EDGE_FALLING = 2; + const EDGE_BOTH = Self::EDGE_RISING.bits()| Self::EDGE_FALLING.bits(); + const LEVEL_HIGH = 4; + const LEVEL_LOW = 8; + } +} + +fn fdt_parse_irq_config(itr: &[u32]) -> Result<IrqConfig, Box<dyn Error>> { + const SPI: u32 = 0; + const PPI: u32 = 1; + + let num = itr[1]; + + let irq_id: u32 = match itr[0] { + SPI => IntId::spi(num), + PPI => IntId::ppi(num), + _ => panic!("Invalid irq type {}", itr[0]), + } + .into(); + + let flag = TriggerFlag::from_bits_truncate(itr[2] as _); + + let trigger = if flag.contains(TriggerFlag::EDGE_BOTH) { + Trigger::EdgeBoth + } else if flag.contains(TriggerFlag::EDGE_RISING) { + Trigger::EdgeRising + } else if flag.contains(TriggerFlag::EDGE_FALLING) { + Trigger::EdgeFailling + } else if flag.contains(TriggerFlag::LEVEL_HIGH) { + Trigger::LevelHigh + } else if flag.contains(TriggerFlag::LEVEL_LOW) { + Trigger::LevelLow + } else { + panic!("Invalid irq type {}", itr[2]) + }; + + Ok(IrqConfig { + irq: (irq_id as usize).into(), + trigger, + }) +} + +fn irq_pin_to_id(pin: usize) -> Result<IrqId, Box<dyn Error>> { + let irq_id = arm_gic_driver::IntId::spi(pin as _); + Ok((irq_id.to_u32() as usize).into()) +} diff --git a/crates/sparreal-rt/src/arch/aarch64/mmu.rs b/crates/sparreal-rt/src/arch/aarch64/mmu.rs index 143f846..31def34 100644 --- a/crates/sparreal-rt/src/arch/aarch64/mmu.rs +++ b/crates/sparreal-rt/src/arch/aarch64/mmu.rs @@ -1,53 +1,25 @@ use core::arch::asm; -use aarch64_cpu::registers::*; -use page_table_arm::{MAIRDefault, MAIRKind, MAIRSetting, PTEFlags, PTE}; +use aarch64_cpu::{asm::barrier::*, registers::*}; +use page_table_arm::*; use page_table_generic::*; -use sparreal_kernel::{dbg, platform::PlatformPageTable}; +use sparreal_kernel::{ + io::print::{early_dbg, early_dbg_hexln}, + mem::va_offset, + platform_if::*, +}; use sparreal_macros::api_impl; -use super::boot::BOOT_INFO; - -extern "C" { - fn _skernel(); - fn _stack_top(); - fn _ekernel(); -} - -pub unsafe fn init_boot_table() -> u64 { - let table = match sparreal_kernel::mem::mmu::new_boot_table(BOOT_INFO.to_boot_config()) { - Ok(t) => t, - Err(e) => { - dbg!("failed to create boot table: "); - dbg!(match e { - err::PagingError::NoMemory => "NoMemory", - err::PagingError::NotAligned => "NotAligned", - err::PagingError::NotMapped => "NotMapped", - err::PagingError::AlreadyMapped => "AlreadyMapped", - err::PagingError::MappedToHugePage => "MappedToHugePage", - }); - panic!("Failed to create boot table"); - } - }; - - MAIRDefault::mair_el1_apply(); - - table as _ -} - pub struct PageTableImpl; #[api_impl] -impl PlatformPageTable for PageTableImpl { - fn flush_tlb(addr: Option<*const u8>) { - unsafe { - if let Some(vaddr) = addr { - asm!("tlbi vaae1is, {}; dsb nsh; isb", in(reg) vaddr as usize) - } else { - // flush the entire TLB - asm!("tlbi vmalle1; dsb nsh; isb") - }; - } +impl MMU for PageTableImpl { + unsafe fn flush_tlb(addr: *const u8) { + unsafe { asm!("tlbi vaae1is, {}; dsb nsh; isb", in(reg) addr as usize) }; + } + + fn flush_tlb_all() { + unsafe { asm!("tlbi vmalle1is; dsb nsh; isb") }; } fn page_size() -> usize { @@ -74,6 +46,8 @@ impl PlatformPageTable for PageTableImpl { CacheSetting::Normal => MAIRKind::Normal, CacheSetting::Device => MAIRKind::Device, CacheSetting::NonCache => MAIRKind::NonCache, + CacheSetting::ToDevice => MAIRKind::Device, + CacheSetting::FromDevice => MAIRKind::Device, })); let privilege = &config.setting.privilege_access; @@ -176,7 +150,7 @@ impl PlatformPageTable for PageTableImpl { fn set_kernel_table(addr: usize) { TTBR1_EL1.set_baddr(addr as _); - Self::flush_tlb(None); + Self::flush_tlb_all(); } fn get_kernel_table() -> usize { @@ -185,10 +159,53 @@ impl PlatformPageTable for PageTableImpl { fn set_user_table(addr: usize) { TTBR0_EL1.set_baddr(addr as _); - Self::flush_tlb(None); + Self::flush_tlb_all(); } fn get_user_table() -> usize { TTBR0_EL1.get_baddr() as _ } + + fn enable_mmu(stack_top: usize, jump_to: usize) -> ! { + MAIRDefault::mair_el1_apply(); + + // Enable TTBR0 and TTBR1 walks, page size = 4K, vaddr size = 48 bits, paddr size = 40 bits. + let tcr_flags0 = TCR_EL1::EPD0::EnableTTBR0Walks + + TCR_EL1::TG0::KiB_4 + + TCR_EL1::SH0::Inner + + TCR_EL1::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL1::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL1::T0SZ.val(16); + let tcr_flags1 = TCR_EL1::EPD1::EnableTTBR1Walks + + TCR_EL1::TG1::KiB_4 + + TCR_EL1::SH1::Inner + + TCR_EL1::ORGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL1::IRGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL1::T1SZ.val(16); + TCR_EL1.write(TCR_EL1::IPS::Bits_48 + tcr_flags0 + tcr_flags1); + + early_dbg("TCR_EL1: "); + early_dbg_hexln(TCR_EL1.get()); + unsafe { + crate::debug::mmu_add_offset(va_offset()); + + asm!("tlbi vmalle1"); + isb(SY); + dsb(NSH); + // Enable the MMU and turn on I-cache and D-cache + SCTLR_EL1 + .modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable); + isb(SY); + + asm!( + "MOV sp, {stack}", + "MOV x8, {entry}", + "BLR x8", + "B .", + stack = in(reg) stack_top, + entry = in(reg) jump_to, + options(nomem, nostack,noreturn) + ) + } + } } diff --git a/crates/sparreal-rt/src/arch/aarch64/mod.rs b/crates/sparreal-rt/src/arch/aarch64/mod.rs index 9fdeb51..32cf5a0 100644 --- a/crates/sparreal-rt/src/arch/aarch64/mod.rs +++ b/crates/sparreal-rt/src/arch/aarch64/mod.rs @@ -1,84 +1,113 @@ +use core::{arch::asm, ffi::c_void}; + +use aarch64_cpu::registers::*; +use sparreal_kernel::{ + globals::global_val, mem::KernelRegions, platform::PlatformInfoKind, platform_if::*, println, +}; +use sparreal_macros::api_impl; + +use crate::mem::driver_registers; + mod boot; mod cache; -mod debug; -mod mmu; +mod gic; +pub(crate) mod mmu; mod psci; +mod timer; mod trap; -use core::arch::asm; - -use aarch64_cpu::registers::*; -use alloc::{format, string::String}; -use sparreal_kernel::{driver::device_tree::get_device_tree, platform::Platform, print, println}; -use sparreal_macros::api_impl; +pub(crate) fn cpu_id() -> usize { + const CPU_ID_MASK: u64 = 0xFF_FFFF + (0xFFFF_FFFF << 32); + (aarch64_cpu::registers::MPIDR_EL1.get() & CPU_ID_MASK) as usize +} -pub struct PlatformImpl; +struct PlatformImpl; #[api_impl] impl Platform for PlatformImpl { - unsafe fn shutdown() { - psci::system_off(); + fn kstack_size() -> usize { + crate::config::KERNEL_STACK_SIZE } - unsafe fn wait_for_interrupt() { - aarch64_cpu::asm::wfi(); + fn kernel_regions() -> KernelRegions { + crate::mem::kernel_regions() } - unsafe fn current_ticks() -> u64 { - CNTPCT_EL0.get() + fn cpu_id() -> usize { + cpu_id() } - unsafe fn tick_hz() -> u64 { - CNTFRQ_EL0.get() + fn cpu_context_size() -> usize { + size_of::<trap::Context>() } - unsafe fn debug_write_byte(_value: u8) { - #[cfg(feature = "early-print")] - debug::put_debug(_value); + unsafe fn cpu_context_sp(ctx_ptr: *const u8) -> usize { + let ctx = unsafe { &*(ctx_ptr as *const trap::Context) }; + ctx.sp } - fn print_system_info() { - println!( - "CPU: {}.{}.{}.{}", - MPIDR_EL1.read(MPIDR_EL1::Aff0), - MPIDR_EL1.read(MPIDR_EL1::Aff1), - MPIDR_EL1.read(MPIDR_EL1::Aff2), - MPIDR_EL1.read(MPIDR_EL1::Aff3) - ); - let _ = print_board_info(); + unsafe fn get_current_tcb_addr() -> *const u8 { + SP_EL0.get() as usize as _ } - fn irqs_enable() { - unsafe { asm!("msr daifclr, #2") }; + unsafe fn set_current_tcb_addr(addr: *const u8) { + SP_EL0.set(addr as usize as _); } - fn irqs_disable() { - unsafe { asm!("msr daifset, #2") }; + unsafe fn cpu_context_init(ctx_ptr: *mut u8, pc: *const c_void, stack_top: *const u8) { + unsafe { + let ctx = &mut *(ctx_ptr as *mut trap::Context); + ctx.spsr = SPSR_EL1.get(); + ctx.pc = pc as usize; + ctx.sp = stack_top as usize; + } + } + unsafe fn cpu_context_switch(prev: *mut u8, next: *mut u8) { + unsafe { + let prev = &mut *(prev as *mut trap::Context); + let next = &mut *(next as *mut trap::Context); + prev.switch_to(next); + } } - fn cpu_id() -> u64 { - MPIDR_EL1.get() + fn wait_for_interrupt() { + aarch64_cpu::asm::wfi(); } - fn cpu_id_display() -> String { - format!( - "{}.{}.{}.{}", - MPIDR_EL1.read(MPIDR_EL1::Aff0), - MPIDR_EL1.read(MPIDR_EL1::Aff1), - MPIDR_EL1.read(MPIDR_EL1::Aff2), - MPIDR_EL1.read(MPIDR_EL1::Aff3) - ) + + fn shutdown() -> ! { + psci::system_off() + } + + fn debug_put(b: u8) { + crate::debug::put(b); } -} -fn print_board_info() -> Option<()> { - let fdt = get_device_tree()?; - let root = fdt.all_nodes().next()?; - let caps = root.compatibles(); + fn irq_all_enable() { + unsafe { asm!("msr daifclr, #2") }; + } + fn irq_all_disable() { + unsafe { asm!("msr daifset, #2") }; + } + fn irq_all_is_enabled() -> bool { + let c = DAIF.read(DAIF::I); + c > 0 + } + + fn on_boot_success() { + match &global_val().platform_info { + PlatformInfoKind::DeviceTree(fdt) => { + if let Err(e) = psci::setup_method_by_fdt(fdt.get()) { + println!("{}", e); + } + } + } + } + + fn dcache_range(op: CacheOp, addr: usize, size: usize) { + cache::dcache_range(op, addr, size); + } - print!("Board:"); - for cap in caps { - print!(" {}", cap); + fn driver_registers() -> DriverRegisterListRef { + DriverRegisterListRef::from_raw(driver_registers()) } - println!(); - Some(()) } diff --git a/crates/sparreal-rt/src/arch/aarch64/psci.rs b/crates/sparreal-rt/src/arch/aarch64/psci.rs index e2f2b34..cfa757d 100644 --- a/crates/sparreal-rt/src/arch/aarch64/psci.rs +++ b/crates/sparreal-rt/src/arch/aarch64/psci.rs @@ -2,8 +2,26 @@ #![allow(dead_code)] +use fdt_parser::Fdt; use log::{error, info}; -use sparreal_kernel::{driver::device_tree::get_device_tree, Platform}; +use sparreal_kernel::platform::wait_for_interrupt; + +#[derive(Debug, Clone, Copy)] +pub enum Method { + Smc, + Hvc, +} + +static mut METHOD: Method = Method::Smc; +fn set_method(method: Method) { + unsafe { + METHOD = method; + } +} + +fn method() -> Method { + unsafe { METHOD } +} pub const PSCI_0_2_FN_BASE: u32 = 0x84000000; pub const PSCI_0_2_64BIT: u32 = 0x40000000; @@ -50,6 +68,23 @@ impl From<i32> for PsciError { } } +pub(crate) fn setup_method_by_fdt(fdt: Fdt<'_>) -> Result<(), &'static str> { + let node = fdt + .find_compatible(&["arm,psci", "arm,psci-1.0"]) + .next() + .ok_or("PSCI node not found")?; + let prop = node + .find_property("method") + .ok_or("FDT PSCI method property not found")?; + match prop.str() { + "smc" => set_method(Method::Smc), + "hvc" => set_method(Method::Hvc), + _ => return Err("Unknown PSCI method"), + } + + Ok(()) +} + /// arm,psci method: smc /// when SMCCC_CONDUIT_SMC = 1 fn arm_smccc_smc(func: u32, arg0: usize, arg1: usize, arg2: usize) -> usize { @@ -82,17 +117,9 @@ fn psci_hvc_call(func: u32, arg0: usize, arg1: usize, arg2: usize) -> usize { } fn psci_call(func: u32, arg0: usize, arg1: usize, arg2: usize) -> Result<(), PsciError> { - let dtb = get_device_tree().ok_or(PsciError::NotSupported)?; - let node = dtb - .find_compatible(&["arm,psci"]) - .next() - .ok_or(PsciError::NotSupported)?; - let method = node.find_property("method").unwrap().str(); - - let ret = match method { - "smc" => arm_smccc_smc(func, arg0, arg1, arg2), - "hvc" => psci_hvc_call(func, arg0, arg1, arg2), - _ => panic!("Unknown PSCI method: {}", method), + let ret = match method() { + Method::Smc => arm_smccc_smc(func, arg0, arg1, arg2), + Method::Hvc => psci_hvc_call(func, arg0, arg1, arg2), }; if ret == 0 { Ok(()) @@ -105,9 +132,7 @@ fn psci_call(func: u32, arg0: usize, arg1: usize, arg2: usize) -> Result<(), Psc pub fn system_off() -> ! { psci_call(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0).ok(); loop { - unsafe { - super::PlatformImpl::wait_for_interrupt(); - } + wait_for_interrupt(); } } @@ -120,10 +145,10 @@ pub fn system_off() -> ! { /// `entry_point` is the physical address of the secondary CPU's entry point. /// `arg` will be passed to the `X0` register of the secondary CPU. pub fn cpu_on(target_cpu: usize, entry_point: usize, arg: usize) { - info!("Starting CPU {:x} ON ...", target_cpu); + info!("Starting CPU {:#x} ON ...", target_cpu); let res = psci_call(PSCI_0_2_FN64_CPU_ON, target_cpu, entry_point, arg); if let Err(e) = res { - error!("failed to boot CPU {:x} ({:?})", target_cpu, e); + error!("failed to boot CPU {:#x} ({:?})", target_cpu, e); } } diff --git a/crates/sparreal-rt/src/arch/aarch64/timer.rs b/crates/sparreal-rt/src/arch/aarch64/timer.rs new file mode 100644 index 0000000..b1aa9ef --- /dev/null +++ b/crates/sparreal-rt/src/arch/aarch64/timer.rs @@ -0,0 +1,71 @@ +use aarch64_cpu::registers::*; +use alloc::{boxed::Box, vec::Vec}; +use sparreal_kernel::driver_interface::{ + DriverGeneric, ProbeFnKind, interrupt_controller::IrqConfig, timer::*, +}; +use sparreal_macros::module_driver; + +module_driver!( + name: "ARMv8 Timer", + compatibles: &["arm,armv8-timer"], + probe: ProbeFnKind::Timer(probe_timer), +); + +#[derive(Clone)] +struct ArmV8Timer { + irq: IrqConfig, +} + +impl Interface for ArmV8Timer { + fn get_current_cpu(&mut self) -> Box<dyn InterfaceCPU> { + Box::new(self.clone()) + } +} + +impl InterfaceCPU for ArmV8Timer { + fn set_timeval(&mut self, ticks: u64) { + CNTP_TVAL_EL0.set(ticks); + } + + fn current_ticks(&self) -> u64 { + CNTPCT_EL0.get() + } + + fn tick_hz(&self) -> u64 { + CNTFRQ_EL0.get() + } + + fn set_irq_enable(&mut self, enable: bool) { + CNTP_CTL_EL0.modify(if enable { + CNTP_CTL_EL0::IMASK::CLEAR + } else { + CNTP_CTL_EL0::IMASK::SET + }); + } + + fn get_irq_status(&self) -> bool { + CNTP_CTL_EL0.is_set(CNTP_CTL_EL0::ISTATUS) + } + + fn irq(&self) -> IrqConfig { + self.irq.clone() + } +} + +impl DriverGeneric for ArmV8Timer { + fn open(&mut self) -> Result<(), alloc::string::String> { + CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET); + Ok(()) + } + + fn close(&mut self) -> Result<(), alloc::string::String> { + CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + Ok(()) + } +} + +fn probe_timer(irqs: Vec<IrqConfig>) -> Hardware { + Box::new(ArmV8Timer { + irq: irqs[1].clone(), + }) +} diff --git a/crates/sparreal-rt/src/arch/aarch64/trap.rs b/crates/sparreal-rt/src/arch/aarch64/trap.rs index ed601f3..2b41d8b 100644 --- a/crates/sparreal-rt/src/arch/aarch64/trap.rs +++ b/crates/sparreal-rt/src/arch/aarch64/trap.rs @@ -1,14 +1,15 @@ -use core::fmt; - use aarch64_cpu::registers::*; +use core::{ + arch::{asm, global_asm, naked_asm}, + fmt::{self, Debug}, +}; use log::*; -use memory_addr::VirtAddr; -#[no_mangle] -unsafe extern "C" fn __handle_sync(tf: &TrapFrame) { +#[unsafe(no_mangle)] +unsafe extern "C" fn __handle_sync(ctx: &Context) { let esr = ESR_EL1.extract(); let iss = esr.read(ESR_EL1::ISS); - let elr = tf.elr; + let elr = ctx.pc; if let Some(code) = esr.read_as_enum(ESR_EL1::EC) { match code { @@ -23,8 +24,8 @@ unsafe extern "C" fn __handle_sync(tf: &TrapFrame) { } _ => { panic!( - "\r\n{}\r\nUnhandled synchronous exception @ {:#x}: ESR={:#x} (EC {:#08b}, ISS {:#x})", - tf, + "\r\n{:?}\r\nUnhandled synchronous exception @ {:#x}: ESR={:#x} (EC {:#08b}, ISS {:#x})", + ctx, elr, esr.get(), esr.read(ESR_EL1::EC), @@ -35,19 +36,25 @@ unsafe extern "C" fn __handle_sync(tf: &TrapFrame) { } } -#[no_mangle] -unsafe extern "C" fn __handle_irq() { - debug!("IRQ!"); +#[unsafe(no_mangle)] +unsafe extern "C" fn __handle_irq(ctx: &Context) { + let sp = ctx.sp; sparreal_kernel::irq::handle_irq(); + unsafe { + asm!( + "mov x0, {0}", + in(reg) sp, + ); + } } -#[no_mangle] -unsafe extern "C" fn __handle_serror(tf: &TrapFrame) { +#[unsafe(no_mangle)] +unsafe extern "C" fn __handle_serror(ctx: &Context) { error!("SError exception:"); let esr = ESR_EL1.extract(); let _iss = esr.read(ESR_EL1::ISS); let elr = ELR_EL1.get(); - error!("{}", tf); + error!("{:?}", ctx); panic!( "Unhandled synchronous exception @ {:#x}: ESR={:#x} (EC {:#08b}, ISS {:#x})", elr, @@ -57,97 +64,396 @@ unsafe extern "C" fn __handle_serror(tf: &TrapFrame) { ); } -#[no_mangle] -unsafe extern "C" fn __handle_frq() { - panic!("frq") +#[unsafe(no_mangle)] +unsafe extern "C" fn __handle_fiq() { + panic!("fiq") } fn handle_data_abort(iss: u64, _is_user: bool) { let wnr = (iss & (1 << 6)) != 0; // WnR: Write not Read let cm = (iss & (1 << 8)) != 0; // CM: Cache maintenance - let reason = if wnr & !cm { + let _reason = if wnr & !cm { PageFaultReason::Write } else { PageFaultReason::Read }; - let vaddr = VirtAddr::from(FAR_EL1.get() as usize); + // let vaddr = VirtAddr::from(FAR_EL1.get() as usize); - handle_page_fault(vaddr, reason); + // handle_page_fault(vaddr, reason); } -pub fn handle_page_fault(vaddr: VirtAddr, reason: PageFaultReason) { - panic!("Invalid addr fault @{vaddr:?}, reason: {reason:?}"); -} - -#[derive(Debug)] pub enum PageFaultReason { Read, Write, } -#[derive(Debug)] -#[repr(C)] -pub struct TrapFrame { +// pub fn handle_page_fault(vaddr: VirtAddr, reason: PageFaultReason) { +// // panic!("Invalid addr fault @{vaddr:?}, reason: {reason:?}"); +// } + +#[repr(C, align(0x10))] +#[derive(Clone)] +pub struct Context { + pub sp: usize, + pub pc: usize, + #[cfg(hard_float)] + /// Floating-point Control Register (FPCR) + pub fpcr: usize, + #[cfg(hard_float)] + /// Floating-point Status Register (FPSR) + pub fpsr: usize, + #[cfg(hard_float)] + pub q: [u128; 32], pub spsr: u64, - pub sp: u64, - pub cpacr: u64, - pub elr: u64, - pub q: [u64; 64], - pub x29: u64, - pub x30: u64, - pub x18: u64, - pub x19: u64, - pub x16: u64, - pub x17: u64, - pub x14: u64, - pub x15: u64, - pub x12: u64, - pub x13: u64, - pub x10: u64, - pub x11: u64, - pub x8: u64, - pub x9: u64, - pub x6: u64, - pub x7: u64, - pub x4: u64, - pub x5: u64, - pub x2: u64, - pub x3: u64, - pub x0: u64, - pub x1: u64, -} - -impl fmt::Display for TrapFrame { + pub x: [usize; 31], +} + +impl Debug for Context { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "TrapFrame:")?; - writeln!(f, " spsr: {:#x}", self.spsr)?; - writeln!(f, " sp: {:#x}", self.sp)?; - writeln!(f, " cpacr: {:#x}", self.cpacr)?; - writeln!(f, " elr: {:#x}", self.elr)?; - writeln!( - f, - " x00: {:#x} x01: {:#x} x02: {:#x} x03: {:#x}", - self.x0, self.x1, self.x2, self.x3 - )?; - writeln!( - f, - " x04: {:#x} x05: {:#x} x06: {:#x} x07: {:#x}", - self.x4, self.x5, self.x6, self.x7 - )?; - writeln!( - f, - " x08: {:#x} x09: {:#x} x10: {:#x} x11: {:#x}", - self.x8, self.x9, self.x10, self.x11 - )?; - writeln!( - f, - " x12: {:#x} x13: {:#x} x14: {:#x} x15: {:#x}", - self.x12, self.x13, self.x14, self.x15 - )?; - writeln!( - f, - " x16: {:#x} x17: {:#x} x18: {:#x} x19: {:#x}", - self.x16, self.x17, self.x18, self.x19 - )?; - writeln!(f, " x29: {:#x} x30: {:#x} ", self.x29, self.x30) + writeln!(f, "Context:")?; + + const NUM_CHUNKS: usize = 4; + + for (r, chunk) in self.x.chunks(NUM_CHUNKS).enumerate() { + let row_start = r * NUM_CHUNKS; + + for (i, v) in chunk.iter().enumerate() { + let i = row_start + i; + write!(f, " x{:<3}: {:#18x}", i, v)?; + } + writeln!(f)?; + } + writeln!(f, " spsr: {:#18x}", self.spsr)?; + writeln!(f, " pc : {:#18x}", self.pc)?; + writeln!(f, " sp : {:#18x}", self.sp) + } +} + +impl Context { + /// Switches to another task. + /// + /// It first saves the current task's context from CPU to this place, and then + /// restores the next task's context from `next_ctx` to CPU. + pub fn switch_to(&mut self, next_ctx: &Self) { + debug!("switch_to {:?}", next_ctx); + unsafe { context_switch(self, next_ctx) } + } +} + +#[cfg(hard_float)] +macro_rules! save_q { + () => { + " + stp q30, q31, [sp,#-0x20]! + stp q28, q29, [sp,#-0x20]! + stp q26, q27, [sp,#-0x20]! + stp q24, q25, [sp,#-0x20]! + stp q22, q23, [sp,#-0x20]! + stp q20, q21, [sp,#-0x20]! + stp q18, q19, [sp,#-0x20]! + stp q16, q17, [sp,#-0x20]! + stp q14, q15, [sp,#-0x20]! + stp q12, q13, [sp,#-0x20]! + stp q10, q11, [sp,#-0x20]! + stp q8, q9, [sp,#-0x20]! + stp q6, q7, [sp,#-0x20]! + stp q4, q5, [sp,#-0x20]! + stp q2, q3, [sp,#-0x20]! + stp q0, q1, [sp,#-0x20]! + mrs x9, fpcr + mrs x10, fpsr + stp x9, x10, [sp,#-0x10]! +" + }; +} + +#[cfg(hard_float)] +macro_rules! restore_q { + () => { + " + ldp x9, x10, [sp], #0x10 + msr fpcr, x9 + msr fpsr, x10 + ldp q0, q1, [sp], #0x20 + ldp q2, q3, [sp], #0x20 + ldp q4, q5, [sp], #0x20 + ldp q6, q7, [sp], #0x20 + ldp q8, q9, [sp], #0x20 + ldp q10, q11, [sp], #0x20 + ldp q12, q13, [sp], #0x20 + ldp q14, q15, [sp], #0x20 + ldp q16, q17, [sp], #0x20 + ldp q18, q19, [sp], #0x20 + ldp q20, q21, [sp], #0x20 + ldp q22, q23, [sp], #0x20 + ldp q24, q25, [sp], #0x20 + ldp q26, q27, [sp], #0x20 + ldp q28, q29, [sp], #0x20 + ldp q30, q31, [sp], #0x20 +" + }; +} + +macro_rules! save_x_spsr { + () => { + " + stp X29,X30, [sp,#-0x10]! + stp X27,X28, [sp,#-0x10]! + stp X25,X26, [sp,#-0x10]! + stp X23,X24, [sp,#-0x10]! + stp X21,X22, [sp,#-0x10]! + stp X19,X20, [sp,#-0x10]! + stp X17,X18, [sp,#-0x10]! + stp X15,X16, [sp,#-0x10]! + stp X13,X14, [sp,#-0x10]! + stp X11,X12, [sp,#-0x10]! + stp X9,X10, [sp,#-0x10]! + stp X7,X8, [sp,#-0x10]! + stp X5,X6, [sp,#-0x10]! + stp X3,X4, [sp,#-0x10]! + stp X1,X2, [sp,#-0x10]! + mrs x9, SPSR_EL1 + stp x9, x0, [sp,#-0x10]! + " + }; +} + +macro_rules! save_pc_sp { + () => { + " + mrs x10, ELR_EL1 + mov x0, sp + sub x0, x0, #0x10 + stp x0, x10, [sp,#-0x10]! + " + }; +} + +macro_rules! restore_pc_sp { + () => { + " + mov sp, x0 + ldp X0, X10, [sp], #0x10 + msr ELR_EL1, X10 + " + }; +} + +macro_rules! restore_x_spsr { + () => { + " + ldp X9,X0, [sp], #0x10 + msr SPSR_EL1, X9 + ldp X1,X2, [sp], #0x10 + ldp X3,X4, [sp], #0x10 + ldp X5,X6, [sp], #0x10 + ldp X7,X8, [sp], #0x10 + ldp X9,X10, [sp], #0x10 + ldp X11,X12, [sp], #0x10 + ldp X13,X14, [sp], #0x10 + ldp X15,X16, [sp], #0x10 + ldp X17,X18, [sp], #0x10 + ldp X19,x20, [sp], #0x10 + ldp X21,X22, [sp], #0x10 + ldp X23,X24, [sp], #0x10 + ldp X25,X26, [sp], #0x10 + ldp X27,X28, [sp], #0x10 + ldp X29,X30, [sp], #0x10 + " + }; +} + +#[cfg(hard_float)] +// `handler`返回时,从 `x0` 取出 `sp`,作为栈顶地址 +macro_rules! handler { + ($name:ident, $handler:expr) => { + #[naked] + extern "C" fn $name(ctx: &Context) { + unsafe { + naked_asm!( + save_x_spsr!(), + save_q!(), + save_pc_sp!(), + "mov x0, sp", + "BL {handle}", + restore_pc_sp!(), + restore_q!(), + restore_x_spsr!(), + "eret", + handle = sym $handler, + ) + } + } + }; +} + +#[cfg(not(hard_float))] +// `handler`返回时,从 `x0` 取出 `sp`,作为栈顶地址 +macro_rules! handler { + ($name:ident, $handler:expr) => { + #[naked] + extern "C" fn $name(ctx: &Context) { + unsafe { + naked_asm!( + save_x_spsr!(), + save_pc_sp!(), + "mov x0, sp", + "BL {handle}", + restore_pc_sp!(), + restore_x_spsr!(), + "eret", + handle = sym $handler, + ) + } + } + }; +} + +handler!(handle_fiq, __handle_fiq); +handler!(handle_irq, __handle_irq); +handler!(handle_sync, __handle_sync); +handler!(handle_serror, __handle_serror); + +global_asm!( + include_str!("vectors.s"), + irq_handler = sym handle_irq, + fiq_handler = sym handle_fiq, + sync_handler = sym handle_sync, + serror_handler = sym handle_serror, +); + +macro_rules! save_task_x { + () => { + " + add x0, x0, {size} + stp X29,X30, [x0,#-0x10]! + stp X27,X28, [x0,#-0x10]! + stp X25,X26, [x0,#-0x10]! + stp X23,X24, [x0,#-0x10]! + stp X21,X22, [x0,#-0x10]! + stp X19,X20, [x0,#-0x10]! + sub x0, x0, #0x90 + mrs x9, SPSR_EL1 + stp x9, x10, [x0,#-0x10]! + " + }; +} + +macro_rules! save_task_q { + () => { + " + stp q30, q31, [x0,#-0x20]! + stp q28, q29, [x0,#-0x20]! + stp q26, q27, [x0,#-0x20]! + stp q24, q25, [x0,#-0x20]! + stp q22, q23, [x0,#-0x20]! + stp q20, q21, [x0,#-0x20]! + stp q18, q19, [x0,#-0x20]! + stp q16, q17, [x0,#-0x20]! + stp q14, q15, [x0,#-0x20]! + stp q12, q13, [x0,#-0x20]! + stp q10, q11, [x0,#-0x20]! + stp q8, q9, [x0,#-0x20]! + stp q6, q7, [x0,#-0x20]! + stp q4, q5, [x0,#-0x20]! + stp q2, q3, [x0,#-0x20]! + stp q0, q1, [x0,#-0x20]! + mrs x9, fpcr + mrs x10, fpsr + stp x9, x10, [x0,#-0x10]! + " + }; +} + +macro_rules! save_task_lr { + () => { + " + mov x9, sp + stp x9, lr, [x0,#-0x10]! + " + }; +} + +macro_rules! restore_task_x { + () => { + " + add x1, x1, {size} + ldp X29,X30, [x1,#-0x10]! + ldp X27,X28, [x1,#-0x10]! + ldp X25,X26, [x1,#-0x10]! + ldp X23,X24, [x1,#-0x10]! + ldp X21,X22, [x1,#-0x10]! + ldp X19,X20, [x1,#-0x10]! + sub x1, x1, #0x90 + ldp x9, x10, [x1,#-0x10]! + msr SPSR_EL1, x9 + " + }; +} + +macro_rules! restore_task_q { + () => { + " + ldp q30, q31, [x1,#-0x20]! + ldp q28, q29, [x1,#-0x20]! + ldp q26, q27, [x1,#-0x20]! + ldp q24, q25, [x1,#-0x20]! + ldp q22, q23, [x1,#-0x20]! + ldp q20, q21, [x1,#-0x20]! + ldp q18, q19, [x1,#-0x20]! + ldp q16, q17, [x1,#-0x20]! + ldp q14, q15, [x1,#-0x20]! + ldp q12, q13, [x1,#-0x20]! + ldp q10, q11, [x1,#-0x20]! + ldp q8, q9, [x1,#-0x20]! + ldp q6, q7, [x1,#-0x20]! + ldp q4, q5, [x1,#-0x20]! + ldp q2, q3, [x1,#-0x20]! + ldp q0, q1, [x1,#-0x20]! + ldp x9, x10, [x1,#-0x10]! + msr fpcr, x9 + msr fpsr, x10 + " + }; +} + +macro_rules! restore_task_lr { + () => { + " + ldp x9, lr, [x1,#-0x10]! + mov sp, x9 + ret" + }; +} +#[cfg(hard_float)] +#[naked] +unsafe extern "C" fn context_switch(_current_task: &mut Context, _next_task: &Context) { + unsafe { + naked_asm!( + //x0 + save_task_x!(), + save_task_q!(), + save_task_lr!(), + //x1 + restore_task_x!(), + restore_task_q!(), + restore_task_lr!(), + size = const size_of::<Context>() + ) + } +} + +#[cfg(not(hard_float))] +#[naked] +unsafe extern "C" fn context_switch(_current_task: &mut Context, _next_task: &Context) { + unsafe { + naked_asm!( + //x0 + save_task_x!(), + save_task_lr!(), + //x1 + restore_task_x!(), + restore_task_lr!(), + size = const size_of::<Context>() + ) } } diff --git a/crates/sparreal-rt/src/arch/aarch64/vectors.S b/crates/sparreal-rt/src/arch/aarch64/vectors.s similarity index 72% rename from crates/sparreal-rt/src/arch/aarch64/vectors.S rename to crates/sparreal-rt/src/arch/aarch64/vectors.s index 3d237de..a8d53b8 100644 --- a/crates/sparreal-rt/src/arch/aarch64/vectors.S +++ b/crates/sparreal-rt/src/arch/aarch64/vectors.s @@ -64,6 +64,7 @@ // Typical exception vector table code. .balign 0x800 +.global vector_table_el1 vector_table_el1: curr_el_sp0_sync: // The exception handler for the synchronous B . @@ -81,16 +82,16 @@ vector_table_el1: B . .balign 0x80 curr_el_spx_sync: - B SynchronousHandler + B {sync_handler} .balign 0x80 curr_el_spx_irq: - B IRQHandler + B {irq_handler} .balign 0x80 curr_el_spx_frq: - B FIQInterruptHandler + B {fiq_handler} .balign 0x80 curr_el_spx_serror: // The exception handler for the system error - B SErrorInterruptHandler + B {serror_handler} // exception from the current EL using the // current SP. .balign 0x80 @@ -122,78 +123,6 @@ vector_table_el1: // ------------------------------------------------------------ -SynchronousHandler: - SaveRegister - mrs x0, CPACR_EL1 - mrs x1, ELR_EL1 - mrs x2, SPSR_EL1 - stp x0, x1, [sp,#-0x10]! - mov x21, sp - add x21, x21, #704 /*EXCEPTION_FRAME_SIZE 704 = 22*8 + 32*16 + 2*8, except sp and spsr in FExcFrame */ - stp x2,x21, [sp,#-0x10]! - mov x0, sp - - bl __handle_sync - - eret - -IRQHandler: - SaveRegister - /* Save the status of SPSR, ELR and CPTR to stack */ - mrs x0, CPACR_EL1 - mrs x1, ELR_EL1 - mrs x2, SPSR_EL1 - - stp x0, x1, [sp,#-0x10]! - str x2, [sp,#-0x10]! - - bl __handle_irq - - /* Restore the status of SPSR, ELR and CPTR from stack */ - ldr x2,[sp],0x10 - ldp x0, x1, [sp],0x10 - - msr CPACR_EL1, x0 - msr ELR_EL1, x1 - msr SPSR_EL1, x2 - - RestoreRegister - eret - - - -FIQInterruptHandler: - - SaveRegister - - bl __handle_frq - - RestoreRegister - - eret - - -SErrorInterruptHandler: - - SaveRegister - /* Save the status of SPSR, ELR and CPTR to stack */ - mrs x0, CPACR_EL1 - mrs x1, ELR_EL1 - mrs x2, SPSR_EL1 - stp x0, x1, [sp,#-0x10]! - mov x21, sp - add x21, x21, #704 /*EXCEPTION_FRAME_SIZE 704 = 22*8 + 32*16 + 2*8, except sp and spsr in FExcFrame */ - stp x21,x21, [sp,#-0x10]! - mov x0, sp - - mov x0, sp - bl __handle_serror - - RestoreRegister - - eret - - .align 8 diff --git a/crates/sparreal-rt/src/config.rs b/crates/sparreal-rt/src/config.rs new file mode 100644 index 0000000..f850b9a --- /dev/null +++ b/crates/sparreal-rt/src/config.rs @@ -0,0 +1,3 @@ +#![allow(unused)] + +include!(concat!(env!("OUT_DIR"), "/constant.rs")); diff --git a/crates/sparreal-rt/src/consts.rs b/crates/sparreal-rt/src/consts.rs deleted file mode 100644 index 90e948d..0000000 --- a/crates/sparreal-rt/src/consts.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![allow(unused)] - -include!(concat!(env!("OUT_DIR"), "/constant.rs")); - -pub const MAX_HART_ID: usize = SMP - 1; -pub const STACK_SIZE: usize = HART_STACK_SIZE * SMP; diff --git a/crates/sparreal-rt/src/debug/aux_mini.rs b/crates/sparreal-rt/src/debug/aux_mini.rs new file mode 100644 index 0000000..7a9987e --- /dev/null +++ b/crates/sparreal-rt/src/debug/aux_mini.rs @@ -0,0 +1,23 @@ +use core::sync::atomic::{Ordering, fence}; + +pub struct AuxMini {} + +impl AuxMini { + pub fn write(&self, base: usize, byte: u8) { + const TXFF: u32 = 1 << 5; + + unsafe { + let state = (base + 0x24) as *const u32; + loop { + let lsr = state.read_volatile(); + + fence(Ordering::Release); + if lsr & TXFF == 0 { + break; + } + } + let data = base as *mut u32; + data.write_volatile(byte as _); + } + } +} diff --git a/crates/sparreal-rt/src/debug/mod.rs b/crates/sparreal-rt/src/debug/mod.rs new file mode 100644 index 0000000..40c3481 --- /dev/null +++ b/crates/sparreal-rt/src/debug/mod.rs @@ -0,0 +1,70 @@ +use core::cell::UnsafeCell; + +use aux_mini::AuxMini; +use pl011::Pl011; +use sparreal_kernel::platform::SerialPort; + +mod aux_mini; +mod pl011; + +static mut REG_BASE: usize = 0; +static UART: UartWapper = UartWapper(UnsafeCell::new(Uart::None)); + +struct UartWapper(UnsafeCell<Uart>); + +unsafe impl Send for UartWapper {} +unsafe impl Sync for UartWapper {} + +impl UartWapper { + fn set(&self, uart: Uart) { + unsafe { + *self.0.get() = uart; + } + } +} + +fn uart() -> &'static Uart { + unsafe { &*UART.0.get() } +} + +pub unsafe fn mmu_add_offset(va_offset: usize) { + unsafe { REG_BASE += va_offset }; +} + +pub fn put(byte: u8) { + unsafe { + match uart() { + Uart::Pl011(uart) => uart.write(REG_BASE, byte), + Uart::AuxMini(uart) => uart.write(REG_BASE, byte), + Uart::None => {} + } + } +} +pub fn init_by_info(s: SerialPort) -> Option<()> { + unsafe { REG_BASE = s.addr.as_usize() }; + + for c in s.compatibles() { + if c.contains("brcm,bcm2835-aux-uart") { + UART.set(Uart::AuxMini(aux_mini::AuxMini {})); + break; + } + + if c.contains("arm,pl011") { + UART.set(Uart::Pl011(Pl011 {})); + break; + } + + if c.contains("arm,primecell") { + UART.set(Uart::Pl011(Pl011 {})); + break; + } + } + + Some(()) +} + +enum Uart { + None, + Pl011(Pl011), + AuxMini(AuxMini), +} diff --git a/crates/sparreal-rt/src/debug/pl011.rs b/crates/sparreal-rt/src/debug/pl011.rs new file mode 100644 index 0000000..7e40875 --- /dev/null +++ b/crates/sparreal-rt/src/debug/pl011.rs @@ -0,0 +1,17 @@ +use core::sync::atomic::{Ordering, fence}; + +pub struct Pl011 {} + +impl Pl011 { + pub fn write(&self, base: usize, byte: u8) { + const TXFF: u8 = 1 << 5; + + unsafe { + let state = (base + 0x18) as *mut u8; + let put = (base) as *mut u8; + while (state.read_volatile() & TXFF) != 0 {} + fence(Ordering::SeqCst); + put.write_volatile(byte); + } + } +} diff --git a/crates/sparreal-rt/src/drivers/gic.rs b/crates/sparreal-rt/src/drivers/gic.rs deleted file mode 100644 index f87469f..0000000 --- a/crates/sparreal-rt/src/drivers/gic.rs +++ /dev/null @@ -1,180 +0,0 @@ -use alloc::{ - boxed::Box, - format, - {vec, vec::Vec}, -}; -use arm_gic_driver::*; -use driver_interface::*; - -use futures::{future::LocalBoxFuture, FutureExt}; -pub fn register_v2() -> Register { - Register::new( - "GICv2", - vec!["arm,cortex-a15-gic"], - DriverKind::InteruptChip, - RegisterGicV2 {}, - ) -} -pub fn register_v3() -> Register { - Register::new( - "GICv3", - vec!["arm,gic-v3"], - DriverKind::InteruptChip, - RegisterGicV3 {}, - ) -} -struct RegisterGicV2 {} - -impl Probe for RegisterGicV2 { - fn probe<'a>(&self, config: ProbeConfig) -> LocalBoxFuture<'a, DriverResult<DriverSpecific>> { - async move { - let gic = GicV2::new(config.reg[0], config.reg[1]) - .map_err(|e| DriverError::Init(format!("{:?}", e)))?; - let b: irq::BoxDriver = Box::new(DriverGicV2(gic)); - - Ok(DriverSpecific::InteruptChip(b)) - } - .boxed_local() - } -} -struct RegisterGicV3 {} - -impl Probe for RegisterGicV3 { - fn probe<'a>(&self, config: ProbeConfig) -> LocalBoxFuture<'a, DriverResult<DriverSpecific>> { - async move { - let gic = GicV3::new(config.reg[0], config.reg[1]) - .map_err(|e| DriverError::Init(format!("{:?}", e)))?; - - let b: irq::BoxDriver = Box::new(DriverGicV3(gic)); - Ok(DriverSpecific::InteruptChip(b)) - } - .boxed_local() - } -} - -macro_rules! impl_driver_gic { - ($name:ident, $inner:ident) => { - struct $name($inner); - impl DriverGeneric for $name {} - impl irq::Driver for $name { - fn get_and_acknowledge_interrupt(&self) -> Option<usize> { - self.0.get_and_acknowledge_interrupt().map(|id| { - let id: u32 = id.into(); - id as _ - }) - } - - fn end_interrupt(&self, irq_id: usize) { - self.0.end_interrupt(unsafe { IntId::raw(irq_id as _) }); - } - - fn irq_max_size(&self) -> usize { - self.0.irq_max_size() - } - - fn irq_disable(&mut self, irq_id: usize) { - self.0.irq_disable(unsafe { IntId::raw(irq_id as _) }); - } - - fn current_cpu_setup(&self) { - self.0.current_cpu_setup(); - } - - fn fdt_parse_config(&self, itr: &[usize]) -> IrqProbeConfig { - fdt_itr_to_config(itr) - } - - fn set_priority(&mut self, irq: usize, priority: usize) { - self.0 - .set_priority(unsafe { IntId::raw(irq as _) }, priority); - } - - fn set_trigger(&mut self, irq: usize, trigger: irq::Trigger) { - self.0.set_trigger( - unsafe { IntId::raw(irq as _) }, - match trigger { - irq::Trigger::EdgeBoth => Trigger::Edge, - irq::Trigger::EdgeRising => Trigger::Edge, - irq::Trigger::EdgeFailling => Trigger::Edge, - irq::Trigger::LevelHigh => Trigger::Level, - irq::Trigger::LevelLow => Trigger::Level, - }, - ); - } - - fn set_bind_cpu(&mut self, irq: usize, cpu_list: &[u64]) { - let list = cpu_list_to_target_list(cpu_list); - self.0.set_bind_cpu(unsafe { IntId::raw(irq as _) }, &list); - } - - fn irq_enable(&mut self, irq: usize) { - self.0.irq_enable(unsafe { IntId::raw(irq as _) }); - } - } - }; -} - -impl_driver_gic!(DriverGicV2, GicV2); -impl_driver_gic!(DriverGicV3, GicV3); - -fn cpu_list_to_target_list(cpu_list: &[u64]) -> Vec<CPUTarget> { - cpu_list - .iter() - .map(|id| cpu_id_u64_to_cpu_id(*id)) - .collect() -} -fn cpu_id_u64_to_cpu_id(cpu_id: u64) -> CPUTarget { - let mpid: MPID = cpu_id.into(); - mpid.into() -} - -use bitflags::bitflags; - -// The `bitflags!` macro generates `struct`s that manage a set of flags. -bitflags! { - /// Represents a set of flags. - #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] - struct TriggerFlag: usize { - const NONE = 0; - const EDGE_RISING = 1; - const EDGE_FALLING = 2; - const EDGE_BOTH = Self::EDGE_RISING.bits()| Self::EDGE_FALLING.bits(); - const LEVEL_HIGH = 4; - const LEVEL_LOW = 8; - } -} - -fn fdt_itr_to_config(itr: &[usize]) -> IrqProbeConfig { - const SPI: usize = 0; - const PPI: usize = 1; - - let num = itr[1] as u32; - - let irq_id: u32 = match itr[0] { - SPI => IntId::spi(num), - PPI => IntId::ppi(num), - _ => panic!("Invalid irq type {}", itr[0]), - } - .into(); - - let flag = TriggerFlag::from_bits_truncate(itr[2]); - - let trigger = if flag.contains(TriggerFlag::EDGE_BOTH) { - irq::Trigger::EdgeBoth - } else if flag.contains(TriggerFlag::EDGE_RISING) { - irq::Trigger::EdgeRising - } else if flag.contains(TriggerFlag::EDGE_FALLING) { - irq::Trigger::EdgeFailling - } else if flag.contains(TriggerFlag::LEVEL_HIGH) { - irq::Trigger::LevelHigh - } else if flag.contains(TriggerFlag::LEVEL_LOW) { - irq::Trigger::LevelLow - } else { - panic!("Invalid irq type {}", itr[2]) - }; - - IrqProbeConfig { - irq: irq_id as _, - trigger, - } -} diff --git a/crates/sparreal-rt/src/drivers/mod.rs b/crates/sparreal-rt/src/drivers/mod.rs deleted file mode 100644 index 48a8e49..0000000 --- a/crates/sparreal-rt/src/drivers/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -use alloc::{vec, vec::Vec}; -use driver_interface::Register; - -mod gic; -mod timer; -mod uart; - -pub fn registers() -> Vec<Register> { - vec![ - gic::register_v2(), - gic::register_v3(), - timer::armv8::register(), - uart::pl011::register(), - ] -} diff --git a/crates/sparreal-rt/src/drivers/timer/armv8.rs b/crates/sparreal-rt/src/drivers/timer/armv8.rs deleted file mode 100644 index 38b83df..0000000 --- a/crates/sparreal-rt/src/drivers/timer/armv8.rs +++ /dev/null @@ -1,98 +0,0 @@ -use aarch64_cpu::registers::*; -use alloc::{boxed::Box, vec}; -use driver_interface::*; -use futures::{future::LocalBoxFuture, FutureExt}; -use sparreal_kernel::irq::irq_setup; -use timer::Driver; -use tock_registers::interfaces::ReadWriteable; - -pub fn register() -> Register { - Register::new( - "Timer Armv8", - vec!["arm,armv8-timer"], - DriverKind::Timer, - ProbeTimerArmv8 {}, - ) -} - -struct ProbeTimerArmv8 {} - -impl Probe for ProbeTimerArmv8 { - fn probe<'a>(&self, config: ProbeConfig) -> LocalBoxFuture<'a, DriverResult<DriverSpecific>> { - async move { - let irq_ns = &config.irq[1]; - irq_setup(irq_ns.irq, config.id, irq_ns.trigger); - // register_irq( - // IrqConfig { - // irq: irq_ns.irq, - // trigger: irq_ns.trigger, - // priority: 0, - // cpu_list: vec![], - // }, - // config.id, - // move |_irq| { - // let clr = CNTP_CTL_EL0.is_set(CNTP_CTL_EL0::ISTATUS); - // info!("armv8 timer irq! {}", clr); - - // CNTP_CTL_EL0.write(CNTP_CTL_EL0::IMASK::SET); - // IrqHandle::Handled - // }, - // ); - - let mut timer = Box::new(DriverTimerArmv8 { - irq: irq_ns.irq as _, - }); - // timer.set_enable(true); - // timer.set_irq_enable(true); - timer.set_irq_enable(false); - // let freq = timer.tick_hz(); - // let ticks = 2 * freq; - // timer.set_interval(ticks); - Ok(DriverSpecific::Timer(timer)) - } - .boxed_local() - } -} - -struct DriverTimerArmv8 { - irq: u64, -} - -impl DriverGeneric for DriverTimerArmv8 {} -impl timer::Driver for DriverTimerArmv8 { - fn current_ticks(&self) -> u64 { - CNTFRQ_EL0.get() - } - - fn tick_hz(&self) -> u64 { - CNTPCT_EL0.get() - } - - fn set_interval(&mut self, ticks: u64) { - CNTP_TVAL_EL0.set(ticks); - } - - fn set_enable(&mut self, enable: bool) { - CNTP_CTL_EL0.modify(if enable { - CNTP_CTL_EL0::ENABLE::SET - } else { - CNTP_CTL_EL0::ENABLE::CLEAR - }); - } - - fn set_irq_enable(&mut self, enable: bool) { - CNTP_CTL_EL0.modify(if enable { - CNTP_CTL_EL0::IMASK::CLEAR - } else { - CNTP_CTL_EL0::IMASK::SET - }); - } - - fn read_irq_status(&self) -> bool { - CNTP_CTL_EL0.is_set(CNTP_CTL_EL0::ISTATUS) - } - - fn irq_num(&self) -> u64 { - self.irq - } -} diff --git a/crates/sparreal-rt/src/drivers/timer/mod.rs b/crates/sparreal-rt/src/drivers/timer/mod.rs deleted file mode 100644 index 19c6d59..0000000 --- a/crates/sparreal-rt/src/drivers/timer/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod armv8; diff --git a/crates/sparreal-rt/src/drivers/uart/mod.rs b/crates/sparreal-rt/src/drivers/uart/mod.rs deleted file mode 100644 index 50c33c8..0000000 --- a/crates/sparreal-rt/src/drivers/uart/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod pl011; diff --git a/crates/sparreal-rt/src/drivers/uart/pl011.rs b/crates/sparreal-rt/src/drivers/uart/pl011.rs deleted file mode 100644 index e8e9a32..0000000 --- a/crates/sparreal-rt/src/drivers/uart/pl011.rs +++ /dev/null @@ -1,95 +0,0 @@ -use alloc::{boxed::Box, vec}; - -use arm_pl011_rs::Pl011; -use driver_interface::*; -use embedded_io::*; -use future::{FutureExt, LocalBoxFuture}; -use futures::prelude::*; -use log::debug; - -pub fn register() -> Register { - Register::new( - "PL011", - vec!["arm,pl011"], - DriverKind::Uart, - RegisterPl011 {}, - ) -} - -struct RegisterPl011 {} - -struct DriverPl011(Pl011); - -unsafe impl Send for DriverPl011 {} -unsafe impl Sync for DriverPl011 {} - -impl uart::Driver for DriverPl011 {} -impl io::Write for DriverPl011 { - fn write(&mut self, buf: &[u8]) -> io::IOResult<usize> { - match self.0.write(buf) { - Ok(n) => Ok(n), - Err(e) => Err(e.kind()), - } - } - - fn flush(&mut self) -> io::IOResult { - Ok(()) - } -} - -impl DriverGeneric for DriverPl011 {} - -// impl RegisterPl011 { -// fn conv_config(config: uart::Config) -> arm_pl011_rs::Config { -// arm_pl011_rs::Config { -// baud_rate: config.baud_rate, -// clock_freq: config.clock_freq, -// data_bits: match config.data_bits { -// uart::DataBits::Bits5 => arm_pl011_rs::DataBits::Bits5, -// uart::DataBits::Bits6 => arm_pl011_rs::DataBits::Bits6, -// uart::DataBits::Bits7 => arm_pl011_rs::DataBits::Bits7, -// uart::DataBits::Bits8 => arm_pl011_rs::DataBits::Bits8, -// }, -// stop_bits: match config.stop_bits { -// uart::StopBits::STOP1 => arm_pl011_rs::StopBits::STOP1, -// uart::StopBits::STOP2 => arm_pl011_rs::StopBits::STOP2, -// }, -// parity: match config.parity { -// uart::Parity::None => arm_pl011_rs::Parity::None, -// uart::Parity::Even => arm_pl011_rs::Parity::Even, -// uart::Parity::Odd => arm_pl011_rs::Parity::Odd, -// }, -// } -// } -// } - -impl Probe for RegisterPl011 { - fn probe<'a>(&self, config: ProbeConfig) -> LocalBoxFuture<'a, DriverResult<DriverSpecific>> { - let clock_freq = config.clock_freq[0]; - debug!( - "Interupt: {}, {:?}, clk: {}Mhz", - config.irq[0].irq, - config.irq[0].trigger, - clock_freq / 1_000_000, - ); - - async move { - let uart = Pl011::new( - config.reg[0], - Some(arm_pl011_rs::Config { - baud_rate: 115200, - clock_freq, - data_bits: arm_pl011_rs::DataBits::Bits8, - stop_bits: arm_pl011_rs::StopBits::STOP1, - parity: arm_pl011_rs::Parity::None, - }), - ) - .await; - - let d = DriverSpecific::Uart(Box::new(DriverPl011(uart))); - - Ok(d) - } - .boxed_local() - } -} diff --git a/crates/sparreal-rt/src/lib.rs b/crates/sparreal-rt/src/lib.rs index 1e65652..2b9f5a5 100644 --- a/crates/sparreal-rt/src/lib.rs +++ b/crates/sparreal-rt/src/lib.rs @@ -1,24 +1,24 @@ #![no_std] +#![no_main] #![feature(naked_functions)] +#![feature(used_with_arg)] +#![feature(stmt_expr_attributes)] extern crate alloc; +extern crate sparreal_kernel; + #[cfg_attr(target_arch = "aarch64", path = "arch/aarch64/mod.rs")] pub mod arch; -mod consts; -mod drivers; - -pub use sparreal_kernel::*; - -unsafe fn boot(kconfig: kernel::KernelConfig) -> ! { - kernel::init_log_and_memory(&kconfig); - kernel::driver_register_append(drivers::registers()); - kernel::run() -} +mod config; +mod debug; +pub(crate) mod mem; +pub mod prelude; -pub fn shutdown() -> ! { - unsafe { - arch::PlatformImpl::shutdown(); - } - unreachable!() -} +// We export this static with an informative name so that if an application attempts to link +// two copies of cortex-m-rt together, linking will fail. We also declare a links key in +// Cargo.toml which is the more modern way to solve the same problem, but we have to keep +// __ONCE__ around to prevent linking with versions before the links key was added. +#[unsafe(export_name = "error: sparreal-rt appears more than once in the dependency graph")] +#[doc(hidden)] +pub static __ONCE__: () = (); diff --git a/crates/sparreal-rt/src/mem.rs b/crates/sparreal-rt/src/mem.rs new file mode 100644 index 0000000..eb87775 --- /dev/null +++ b/crates/sparreal-rt/src/mem.rs @@ -0,0 +1,55 @@ +use core::ptr::{slice_from_raw_parts, slice_from_raw_parts_mut}; + +use sparreal_kernel::mem::{CMemRange, KernelRegions}; + +pub unsafe fn clear_bss() { + unsafe { + unsafe extern "C" { + fn _sbss(); + fn _ebss(); + } + let bss = &mut *slice_from_raw_parts_mut(_sbss as *mut u8, _ebss as usize - _sbss as usize); + bss.fill(0); + } +} + +pub(crate) fn kernel_regions() -> KernelRegions { + unsafe extern "C" { + fn _stext(); + fn _etext(); + fn _srodata(); + fn _erodata(); + fn _sdata(); + fn _edata(); + fn _sbss(); + fn _ebss(); + } + + KernelRegions { + text: CMemRange { + start: _stext as usize, + end: _etext as usize, + }, + rodata: CMemRange { + start: _srodata as usize, + end: _erodata as usize, + }, + data: CMemRange { + start: _sdata as usize, + end: _edata as usize, + }, + bss: CMemRange { + start: _sbss as usize, + end: _ebss as usize, + }, + } +} + +pub fn driver_registers() -> &'static [u8] { + unsafe extern "C" { + fn _sdriver(); + fn _edriver(); + } + + unsafe { &*slice_from_raw_parts(_sdriver as *const u8, _edriver as usize - _sdriver as usize) } +} diff --git a/crates/sparreal-rt/src/prelude.rs b/crates/sparreal-rt/src/prelude.rs new file mode 100644 index 0000000..796f46a --- /dev/null +++ b/crates/sparreal-rt/src/prelude.rs @@ -0,0 +1 @@ +pub use sparreal_macros::entry; diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 32adaef..53d075f 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,3 @@ [toolchain] channel = "nightly" -components = ["rust-src", "rustfmt", "clippy"] -targets = ["aarch64-unknown-none"] +components = ["rust-src", "rustfmt", "clippy"] \ No newline at end of file