diff --git a/.clang-tidy b/.clang-tidy index 72e28b0c4..720a49662 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -5,18 +5,24 @@ # .clang-tidy for Simple-XX/SimpleKernel. --- -Checks: '-*,\ - bugprone-*,\ - clang-analyzer-*,\ - cppcoreguidelines-*,\ - hicpp-*,\ - llvm-*,\ - misc-* - modernize-*,\ - performance-*,\ - portability-*,\ - readability-*,\ - -cppcoreguidelines-pro-type-reinterpret-cast' -HeaderFilterRegex: '^${sourceDir}/src' -AnalyzeTemporaryDtors: true +Checks: > + -*, + bugprone-*, + google-*, + misc-*, + modernize-*, + performance-*, + portability-*, + readability-*, + -google-readability-namespace-comments, + -google-runtime-int, + -google-runtime-references, + -misc-non-private-member-variables-in-classes, + -readability-named-parameter, + -readability-braces-around-statements, + -readability-magic-numbers, + -performance-no-int-to-ptr, + -modernize-use-std-print, + -bugprone-reserved-identifier +FormatStyle: google ... diff --git a/.cmake-format.json b/.cmake-format.json new file mode 100644 index 000000000..d45a3b0ed --- /dev/null +++ b/.cmake-format.json @@ -0,0 +1,311 @@ +{ + "_help_parse": "Options affecting listfile parsing", + "parse": { + "_help_additional_commands": [ + "Specify structure for custom cmake functions" + ], + "additional_commands": { + "foo": { + "flags": [ + "BAR", + "BAZ" + ], + "kwargs": { + "HEADERS": "*", + "SOURCES": "*", + "DEPENDS": "*" + } + } + }, + "_help_override_spec": [ + "Override configurations per-command where available" + ], + "override_spec": {}, + "_help_vartags": [ + "Specify variable tags." + ], + "vartags": [], + "_help_proptags": [ + "Specify property tags." + ], + "proptags": [] + }, + "_help_format": "Options affecting formatting.", + "format": { + "_help_disable": [ + "Disable formatting entirely, making cmake-format a no-op" + ], + "disable": false, + "_help_line_width": [ + "How wide to allow formatted cmake files" + ], + "line_width": 80, + "_help_tab_size": [ + "How many spaces to tab for indent" + ], + "tab_size": 4, + "_help_use_tabchars": [ + "If true, lines are indented using tab characters (utf-8", + "0x09) instead of space characters (utf-8 0x20).", + "In cases where the layout would require a fractional tab", + "character, the behavior of the fractional indentation is", + "governed by " + ], + "use_tabchars": false, + "_help_fractional_tab_policy": [ + "If is True, then the value of this variable", + "indicates how fractional indentions are handled during", + "whitespace replacement. If set to 'use-space', fractional", + "indentation is left as spaces (utf-8 0x20). If set to", + "`round-up` fractional indentation is replaced with a single", + "tab character (utf-8 0x09) effectively shifting the column", + "to the next tabstop" + ], + "fractional_tab_policy": "use-space", + "_help_max_subgroups_hwrap": [ + "If an argument group contains more than this many sub-groups", + "(parg or kwarg groups) then force it to a vertical layout." + ], + "max_subgroups_hwrap": 2, + "_help_max_pargs_hwrap": [ + "If a positional argument group contains more than this many", + "arguments, then force it to a vertical layout." + ], + "max_pargs_hwrap": 6, + "_help_max_rows_cmdline": [ + "If a cmdline positional group consumes more than this many", + "lines without nesting, then invalidate the layout (and nest)" + ], + "max_rows_cmdline": 2, + "_help_separate_ctrl_name_with_space": [ + "If true, separate flow control names from their parentheses", + "with a space" + ], + "separate_ctrl_name_with_space": false, + "_help_separate_fn_name_with_space": [ + "If true, separate function names from parentheses with a", + "space" + ], + "separate_fn_name_with_space": true, + "_help_dangle_parens": [ + "If a statement is wrapped to more than one line, than dangle", + "the closing parenthesis on its own line." + ], + "dangle_parens": false, + "_help_dangle_align": [ + "If the trailing parenthesis must be 'dangled' on its on", + "line, then align it to this reference: `prefix`: the start", + "of the statement, `prefix-indent`: the start of the", + "statement, plus one indentation level, `child`: align to", + "the column of the arguments" + ], + "dangle_align": "prefix", + "_help_min_prefix_chars": [ + "If the statement spelling length (including space and", + "parenthesis) is smaller than this amount, then force reject", + "nested layouts." + ], + "min_prefix_chars": 4, + "_help_max_prefix_chars": [ + "If the statement spelling length (including space and", + "parenthesis) is larger than the tab width by more than this", + "amount, then force reject un-nested layouts." + ], + "max_prefix_chars": 10, + "_help_max_lines_hwrap": [ + "If a candidate layout is wrapped horizontally but it exceeds", + "this many lines, then reject the layout." + ], + "max_lines_hwrap": 2, + "_help_line_ending": [ + "What style line endings to use in the output." + ], + "line_ending": "unix", + "_help_command_case": [ + "Format command names consistently as 'lower' or 'upper' case" + ], + "command_case": "upper", + "_help_keyword_case": [ + "Format keywords consistently as 'lower' or 'upper' case" + ], + "keyword_case": "upper", + "_help_always_wrap": [ + "A list of command names which should always be wrapped" + ], + "always_wrap": [], + "_help_enable_sort": [ + "If true, the argument lists which are known to be sortable", + "will be sorted lexicographicall" + ], + "enable_sort": true, + "_help_autosort": [ + "If true, the parsers may infer whether or not an argument", + "list is sortable (without annotation)." + ], + "autosort": false, + "_help_require_valid_layout": [ + "By default, if cmake-format cannot successfully fit", + "everything into the desired linewidth it will apply the", + "last, most aggressive attempt that it made. If this flag is", + "True, however, cmake-format will print error, exit with non-", + "zero status code, and write-out nothing" + ], + "require_valid_layout": false, + "_help_layout_passes": [ + "A dictionary mapping layout nodes to a list of wrap", + "decisions. See the documentation for more information." + ], + "layout_passes": {} + }, + "_help_markup": "Options affecting comment reflow and formatting.", + "markup": { + "_help_bullet_char": [ + "What character to use for bulleted lists" + ], + "bullet_char": "*", + "_help_enum_char": [ + "What character to use as punctuation after numerals in an", + "enumerated list" + ], + "enum_char": ".", + "_help_first_comment_is_literal": [ + "If comment markup is enabled, don't reflow the first comment", + "block in each listfile. Use this to preserve formatting of", + "your copyright/license statements." + ], + "first_comment_is_literal": false, + "_help_literal_comment_pattern": [ + "If comment markup is enabled, don't reflow any comment block", + "which matches this (regex) pattern. Default is `None`", + "(disabled)." + ], + "literal_comment_pattern": null, + "_help_fence_pattern": [ + "Regular expression to match preformat fences in comments", + "default= ``r'^\\s*([`~]{3}[`~]*)(.*)$'``" + ], + "fence_pattern": "^\\s*([`~]{3}[`~]*)(.*)$", + "_help_ruler_pattern": [ + "Regular expression to match rulers in comments default=", + "``r'^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$'``" + ], + "ruler_pattern": "^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$", + "_help_explicit_trailing_pattern": [ + "If a comment line matches starts with this pattern then it", + "is explicitly a trailing comment for the preceding argument.", + "Default is '#<'" + ], + "explicit_trailing_pattern": "#<", + "_help_hashruler_min_length": [ + "If a comment line starts with at least this many consecutive", + "hash characters, then don't lstrip() them off. This allows", + "for lazy hash rulers where the first hash char is not", + "separated by space" + ], + "hashruler_min_length": 10, + "_help_canonicalize_hashrulers": [ + "If true, then insert a space between the first hash char and", + "remaining hash chars in a hash ruler, and normalize its", + "length to fill the column" + ], + "canonicalize_hashrulers": true, + "_help_enable_markup": [ + "enable comment markup parsing and reflow" + ], + "enable_markup": false + }, + "_help_lint": "Options affecting the linter", + "lint": { + "_help_disabled_codes": [ + "a list of lint codes to disable" + ], + "disabled_codes": [], + "_help_function_pattern": [ + "regular expression pattern describing valid function names" + ], + "function_pattern": "[0-9a-z_]+", + "_help_macro_pattern": [ + "regular expression pattern describing valid macro names" + ], + "macro_pattern": "[0-9A-Z_]+", + "_help_global_var_pattern": [ + "regular expression pattern describing valid names for", + "variables with global (cache) scope" + ], + "global_var_pattern": "[A-Z][0-9A-Z_]+", + "_help_internal_var_pattern": [ + "regular expression pattern describing valid names for", + "variables with global scope (but internal semantic)" + ], + "internal_var_pattern": "_[A-Z][0-9A-Z_]+", + "_help_local_var_pattern": [ + "regular expression pattern describing valid names for", + "variables with local scope" + ], + "local_var_pattern": "[a-z][a-z0-9_]+", + "_help_private_var_pattern": [ + "regular expression pattern describing valid names for", + "privatedirectory variables" + ], + "private_var_pattern": "_[0-9a-z_]+", + "_help_public_var_pattern": [ + "regular expression pattern describing valid names for public", + "directory variables" + ], + "public_var_pattern": "[A-Z][0-9A-Z_]+", + "_help_argument_var_pattern": [ + "regular expression pattern describing valid names for", + "function/macro arguments and loop variables." + ], + "argument_var_pattern": "[a-z][a-z0-9_]+", + "_help_keyword_pattern": [ + "regular expression pattern describing valid names for", + "keywords used in functions or macros" + ], + "keyword_pattern": "[A-Z][0-9A-Z_]+", + "_help_max_conditionals_custom_parser": [ + "In the heuristic for C0201, how many conditionals to match", + "within a loop in before considering the loop a parser." + ], + "max_conditionals_custom_parser": 2, + "_help_min_statement_spacing": [ + "Require at least this many newlines between statements" + ], + "min_statement_spacing": 1, + "_help_max_statement_spacing": [ + "Require no more than this many newlines between statements" + ], + "max_statement_spacing": 2, + "max_returns": 6, + "max_branches": 12, + "max_arguments": 5, + "max_localvars": 15, + "max_statements": 50 + }, + "_help_encode": "Options affecting file encoding", + "encode": { + "_help_emit_byteorder_mark": [ + "If true, emit the unicode byte-order mark (BOM) at the start", + "of the file" + ], + "emit_byteorder_mark": false, + "_help_input_encoding": [ + "Specify the encoding of the input file. Defaults to utf-8" + ], + "input_encoding": "utf-8", + "_help_output_encoding": [ + "Specify the encoding of the output file. Defaults to utf-8.", + "Note that cmake only claims to support utf-8 so be careful", + "when using anything else" + ], + "output_encoding": "utf-8" + }, + "_help_misc": "Miscellaneous configurations options.", + "misc": { + "_help_per_command": [ + "A dictionary containing any per-command configuration", + "overrides. Currently only `command_case` is supported." + ], + "per_command": {} + } +} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..a7cab7ffc --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,15 @@ +{ + "name": "SimpleKernel DevContainer", + "dockerFile": "../tools/Dockerfile", + "postCreateCommand": "bash -i -c 'pre-commit install'", + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cpptools", + "ms-vscode.cpptools-extension-pack", + "twxs.cmake", + "ms-vscode.cmake-tools" + ] + } + } +} diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 83520b6cf..bd9b54609 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -13,59 +13,63 @@ on: env: CMAKE_BUILD_TYPE: Release + DOCKER_IMAGE: ptrnull233/simple_kernel:latest jobs: - build_ubuntu: + build: runs-on: ubuntu-latest permissions: contents: write + packages: read + statuses: write steps: - - uses: actions/checkout@v3 - - - name: Install dependencies - run: | - sudo apt update --fix-missing -y - sudo apt upgrade --fix-missing -y - sudo apt install --fix-missing -y gcc g++ gcc-riscv64-linux-gnu g++-riscv64-linux-gnu gcc-aarch64-linux-gnu g++-aarch64-linux-gnu - sudo apt install --fix-missing -y cmake qemu-system gdb-multiarch - sudo apt install --fix-missing -y doxygen graphviz - sudo apt install --fix-missing -y clang-format clang-tidy cppcheck libgtest-dev lcov - git submodule update --init --recursive + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules : true - name: x86_64 - run: | - cmake --preset=build_x86_64 - cmake --build build_x86_64 --target boot - cmake --build build_x86_64 --target kernel - cmake --build build_x86_64 --target unit-test - cmake --build build_x86_64 --target coverage + uses: addnab/docker-run-action@v3 + with: + image: ${{ env.DOCKER_IMAGE }} + options: -v ${{ github.workspace }}:/root -e CMAKE_BUILD_TYPE=${{ env.CMAKE_BUILD_TYPE }} + run: | + cmake --preset=build_x86_64 + cmake --build build_x86_64 --target kernel unit-test coverage doc - name: riscv64 - run: | - cmake --preset=build_riscv64 - cmake --build build_riscv64 --target kernel + uses: addnab/docker-run-action@v3 + with: + image: ${{ env.DOCKER_IMAGE }} + options: -v ${{ github.workspace }}:/root -e CMAKE_BUILD_TYPE=${{ env.CMAKE_BUILD_TYPE }} + run: | + cmake --preset=build_riscv64 + cmake --build build_riscv64 --target kernel - name: aarch64 - run: | - cmake --preset=build_aarch64 - cmake --build build_aarch64 --target boot - cmake --build build_aarch64 --target kernel + uses: addnab/docker-run-action@v3 + with: + image: ${{ env.DOCKER_IMAGE }} + options: -v ${{ github.workspace }}:/root -e CMAKE_BUILD_TYPE=${{ env.CMAKE_BUILD_TYPE }} + run: | + cmake --preset=build_aarch64 + cmake --build build_aarch64 --target kernel - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v3 with: - files: build_x86_64/coverage/coverage.info + files: ${{ github.workspace }}/build_x86_64/coverage/coverage.info verbose: true - - name: Build Doc - if: github.ref == 'refs/heads/main' - run: | - cmake --preset=build_x86_64 - cmake --build build_x86_64 --target doc - - name: Publish if: github.ref == 'refs/heads/main' uses: peaceiris/actions-gh-pages@v3 with: - github_token: ${{secrets.GITHUB_TOKEN}} - publish_dir: ${{github.workspace}}/doc/html + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ${{ github.workspace }}/doc/html + + # - name: Super-Linter + # uses: super-linter/super-linter@v7.2.0 + # env: + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index fdc7b6552..43e728bde 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ - # This file is a part of Simple-XX/SimpleKernel # (https://github.com/Simple-XX/SimpleKernel). # @@ -9,8 +8,12 @@ build_aarch64 build_riscv64 build_x86_64 doc/html -.gdbinit -.vscode +.vscode/* +!.vscode/tasks.json +!.vscode/launch.json .idea Doxyfile -.gdbinit +*.o +*.objdump +*.elf +.pre-commit-config.yaml diff --git a/.gitmodules b/.gitmodules index 2c4a3d518..f7991be64 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,22 +1,34 @@ -[submodule "3rd/printf_bare_metal"] - path = 3rd/printf_bare_metal - url = https://github.com/MRNIU/printf_bare_metal.git [submodule "3rd/opensbi_interface"] path = 3rd/opensbi_interface url = https://github.com/MRNIU/opensbi_interface.git [submodule "3rd/opensbi"] path = 3rd/opensbi url = https://github.com/riscv-software-src/opensbi.git -[submodule "3rd/gdbinit"] - path = 3rd/gdbinit - url = https://github.com/gdbinit/Gdbinit.git -[submodule "3rd/gnu-efi"] - path = 3rd/gnu-efi - url = https://github.com/ncroxon/gnu-efi.git [submodule "3rd/dtc"] path = 3rd/dtc url = https://git.kernel.org/pub/scm/utils/dtc/dtc.git [submodule "3rd/googletest"] path = 3rd/googletest url = https://github.com/google/googletest.git +[submodule "3rd/cpu_io"] + path = 3rd/cpu_io + url = https://github.com/MRNIU/cpu_io.git +[submodule "3rd/arm-trusted-firmware"] + path = 3rd/arm-trusted-firmware + url = https://github.com/ARM-software/arm-trusted-firmware.git +[submodule "3rd/optee/optee_os"] + path = 3rd/optee/optee_os + url = https://github.com/OP-TEE/optee_os.git +[submodule "3rd/optee/build"] + path = 3rd/optee/build + url = https://github.com/OP-TEE/build.git +[submodule "3rd/optee/optee_client"] + path = 3rd/optee/optee_client + url = https://github.com/OP-TEE/optee_client.git +[submodule "3rd/u-boot"] + path = 3rd/u-boot + url = https://github.com/u-boot/u-boot.git +[submodule "3rd/printf"] + path = 3rd/printf + url = https://github.com/eyalroz/printf.git diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..7d9aea7dc --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,65 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "riscv64-debug", + "type": "cppdbg", + "request": "launch", + "miDebuggerServerAddress": "127.0.0.1:1234", + "miDebuggerPath": "/usr/bin/gdb-multiarch", + "program": "${workspaceFolder}/build_riscv64/bin/kernel.elf", + "args": [], + "stopAtEntry": true, + "cwd": "${workspaceFolder}/build_riscv64/bin", + "environment": [], + "externalConsole": true, + "logging": { + "engineLogging": "verbose" + }, + "MIMode": "gdb", + "preLaunchTask": "debug_riscv64" + }, + { + "name": "x86_64-debug", + "type": "cppdbg", + "request": "launch", + "miDebuggerServerAddress": "127.0.0.1:1234", + "miDebuggerPath": "/usr/bin/gdb-multiarch", + "program": "${workspaceFolder}/build_x86_64/bin/kernel.elf", + "args": [], + "stopAtEntry": true, + "cwd": "${workspaceFolder}/build_x86_64/bin", + "environment": [], + "externalConsole": true, + "logging": { + "engineLogging": "verbose" + }, + "MIMode": "gdb", + "preLaunchTask": "debug_x86_64" + }, + { + "name": "aarch64-debug", + "type": "cppdbg", + "request": "launch", + "miDebuggerServerAddress": "127.0.0.1:1234", + "miDebuggerPath": "/usr/bin/gdb-multiarch", + "program": "${workspaceFolder}/build_aarch64/bin/kernel.elf", + "args": [], + "stopAtEntry": true, + "cwd": "${workspaceFolder}/build_aarch64/bin", + "setupCommands": [ + { "text": "add-symbol-file ${workspaceFolder}/build_aarch64/3rd/arm-trusted-firmware/qemu/debug/bl1/bl1.elf" }, + { "text": "add-symbol-file ${workspaceFolder}/build_aarch64/3rd/arm-trusted-firmware/qemu/debug/bl2/bl2.elf" }, + { "text": "add-symbol-file ${workspaceFolder}/build_aarch64/3rd/arm-trusted-firmware/qemu/debug/bl31/bl31.elf" }, + { "text": "add-symbol-file ${workspaceFolder}/build_aarch64/3rd/optee/optee_os/core/tee.elf" } + ], + "environment": [], + "externalConsole": true, + "logging": { + "engineLogging": "verbose" + }, + "MIMode": "gdb", + "preLaunchTask": "debug_aarch64" + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000..624492574 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,275 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "::54320", + "type": "shell", + "command": "python3", + "args": [ + "${workspaceFolder}/3rd/optee/build/soc_term.py", + "54320" + ], + "isBackground": true, + "problemMatcher": [], + "presentation": { + "reveal": "always", + "panel": "new", + "group": "aarch64" + } + }, + { + "label": "::54321", + "type": "shell", + "command": "python3", + "args": [ + "${workspaceFolder}/3rd/optee/build/soc_term.py", + "54321" + ], + "isBackground": true, + "problemMatcher": [], + "presentation": { + "reveal": "always", + "panel": "new", + "group": "aarch64" + } + }, + { + "label": "build_riscv64", + "type": "process", + "command": "make", + "args": [], + "options": { + "cwd": "${workspaceFolder}/build_riscv64" + }, + "group": { + "kind": "build", + "isDefault": false + }, + "problemMatcher": [ + "$gcc" + ], + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "dedicated", + "showReuseMessage": true, + "clear": true + } + }, + { + "label": "run_riscv64", + "type": "process", + "command": "make", + "args": [ + "run" + ], + "options": { + "cwd": "${workspaceFolder}/build_riscv64" + }, + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [], + "isBackground": true, + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "dedicated", + "showReuseMessage": true, + "clear": true + } + }, + { + "label": "debug_riscv64", + "type": "process", + "command": "make", + "args": [ + "debug" + ], + "options": { + "cwd": "${workspaceFolder}/build_riscv64" + }, + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [], + "isBackground": true, + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "dedicated", + "showReuseMessage": true, + "clear": true + }, + "hide": true + }, + { + "label": "build_aarch64", + "type": "process", + "command": "make", + "args": [], + "options": { + "cwd": "${workspaceFolder}/build_aarch64" + }, + "group": { + "kind": "build", + "isDefault": false + }, + "problemMatcher": [ + "$gcc" + ], + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "dedicated", + "showReuseMessage": true, + "clear": true + } + }, + { + "label": "run_aarch64_warp", + "type": "process", + "command": "make", + "args": [ + "run" + ], + "options": { + "cwd": "${workspaceFolder}/build_aarch64" + }, + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [], + "isBackground": true, + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "new", + "showReuseMessage": true, + "clear": true, + "group": "aarch64" + }, + "hide": true + }, + { + "label": "run_aarch64", + "problemMatcher": [], + "dependsOn": [ + "run_aarch64_warp", + "::54320", + "::54321" + ], + "dependsOrder": "parallel" + }, + { + "label": "debug_aarch64", + "type": "process", + "command": "make", + "args": [ + "debug" + ], + "options": { + "cwd": "${workspaceFolder}/build_aarch64" + }, + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [], + "isBackground": true, + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "dedicated", + "showReuseMessage": true, + "clear": true, + "group": "aarch64" + }, + "hide": true + }, + { + "label": "build_x86_64", + "type": "process", + "command": "make", + "args": [], + "options": { + "cwd": "${workspaceFolder}/build_x86_64" + }, + "group": { + "kind": "build", + "isDefault": false + }, + "problemMatcher": [ + "$gcc" + ], + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "dedicated", + "showReuseMessage": true, + "clear": true + } + }, + { + "label": "run_x86_64", + "type": "process", + "command": "make", + "args": [ + "run" + ], + "options": { + "cwd": "${workspaceFolder}/build_x86_64" + }, + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [], + "isBackground": true, + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "dedicated", + "showReuseMessage": true, + "clear": true + } + }, + { + "label": "debug_x86_64", + "type": "process", + "command": "make", + "args": [ + "debug" + ], + "options": { + "cwd": "${workspaceFolder}/build_x86_64" + }, + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [], + "isBackground": true, + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "dedicated", + "showReuseMessage": true, + "clear": true + }, + "hide": true + } + ] +} diff --git a/3rd/arm-trusted-firmware b/3rd/arm-trusted-firmware new file mode 160000 index 000000000..408ba4ddf --- /dev/null +++ b/3rd/arm-trusted-firmware @@ -0,0 +1 @@ +Subproject commit 408ba4ddfe9a8d55e3e2488bea89c39adef07981 diff --git a/3rd/cpu_io b/3rd/cpu_io new file mode 160000 index 000000000..47c3a1ac1 --- /dev/null +++ b/3rd/cpu_io @@ -0,0 +1 @@ +Subproject commit 47c3a1ac1cc64e429233cea6a81dea252c48bce8 diff --git a/3rd/gdbinit b/3rd/gdbinit deleted file mode 160000 index 40c819bf9..000000000 --- a/3rd/gdbinit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 40c819bf99ec5dfb9353d4244c007a1e0021ac03 diff --git a/3rd/gnu-efi b/3rd/gnu-efi deleted file mode 160000 index 9e479726e..000000000 --- a/3rd/gnu-efi +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9e479726ed02f325c8a82b0985d021ed1fd13f00 diff --git a/3rd/optee/build b/3rd/optee/build new file mode 160000 index 000000000..05f265e0f --- /dev/null +++ b/3rd/optee/build @@ -0,0 +1 @@ +Subproject commit 05f265e0f8daeb67ae0944cece0c102176bde1f8 diff --git a/3rd/optee/optee_client b/3rd/optee/optee_client new file mode 160000 index 000000000..648677358 --- /dev/null +++ b/3rd/optee/optee_client @@ -0,0 +1 @@ +Subproject commit 6486773583b5983af8250a47cf07eca938e0e422 diff --git a/3rd/optee/optee_os b/3rd/optee/optee_os new file mode 160000 index 000000000..0919de0f7 --- /dev/null +++ b/3rd/optee/optee_os @@ -0,0 +1 @@ +Subproject commit 0919de0f7c79ad35ad3c8ace5f823ad1344b4716 diff --git a/3rd/printf b/3rd/printf new file mode 160000 index 000000000..ce439cbe5 --- /dev/null +++ b/3rd/printf @@ -0,0 +1 @@ +Subproject commit ce439cbe5d7e041db2f1160ca50f19502b56ca98 diff --git a/3rd/printf_bare_metal b/3rd/printf_bare_metal deleted file mode 160000 index 127aaad21..000000000 --- a/3rd/printf_bare_metal +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 127aaad21176c309f3b6ded6b46e2ccb52dcab22 diff --git a/3rd/u-boot b/3rd/u-boot new file mode 160000 index 000000000..cde005061 --- /dev/null +++ b/3rd/u-boot @@ -0,0 +1 @@ +Subproject commit cde0050618968aae335dfbc930641656d51ff5d0 diff --git a/CMakeLists.txt b/CMakeLists.txt index b6d65f1e7..2e730bb0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,92 +1,38 @@ - # This file is a part of Simple-XX/SimpleKernel # (https://github.com/Simple-XX/SimpleKernel). # # CMakeLists.txt for Simple-XX/SimpleKernel. # 设置最小 cmake 版本 -cmake_minimum_required(VERSION 3.27 FATAL_ERROR) +CMAKE_MINIMUM_REQUIRED (VERSION 3.27 FATAL_ERROR) # 设置项目名与版本 -project( - SimpleKernel - VERSION 0.0.1 -) +PROJECT (SimpleKernel VERSION 0.0.1) # 禁止原地编译 -if (${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR}) - # 如果你看到这句话,cmake 此时已经在根目录下生成了一些临时文件,你需要删除它们 - # CMakeFiles, CMakeCache.txt - message( - FATAL_ERROR - "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there." - ) -endif () +IF(${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR}) + MESSAGE ( + FATAL_ERROR + "In-source builds not allowed." + "Please make a new directory (called a build directory) " + "and run CMake from there.") +ENDIF() # 设置辅助 cmake 脚本路径 -list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") +LIST (APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") # 导入项目配置 -include(project_config) +INCLUDE (project_config) # 导入函数 -include(functions) +INCLUDE (functions) # 导入第三方依赖 -include(3rd) +INCLUDE (3rd) # 导入编译配置 -include(compile_config) - -# qemu 参数设置 -list(APPEND QEMU_FLAGS - # 不启用图形界面 - -nographic - # 使用标准输出显示 - -serial stdio - # 启动 telnet 服务,使用 2333 端口,不等待连接 - -monitor ${QEMU_MONITOR_ARG} -) -# 目标平台参数 -if (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - list(APPEND QEMU_FLAGS - -m 128M - -net none - -bios ${ovmf_BINARY_DIR}/OVMF_${CMAKE_SYSTEM_PROCESSOR}.fd - -hda fat:rw:./image/ - ) -elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") - list(APPEND QEMU_FLAGS - -machine virt - # 可选项,qemu7.0 自带了 opensbi1.0 - -bios ${opensbi_BINARY_DIR}/platform/generic/firmware/fw_jump.elf - -kernel $ - # @todo 暂时还不支持 riscv64 的 uefi 启动 - # 预期路线: qemu->uefi->opensbi + kernel(payload) - # -bios ${ovmf_BINARY_DIR}/OVMF_${CMAKE_SYSTEM_PROCESSOR}.fd - # -hda fat:rw:./image/ - ) -elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") - list(APPEND QEMU_FLAGS - -machine virt - -cpu cortex-a57 - -m 128M - -net none - -bios ${ovmf_BINARY_DIR}/OVMF_${CMAKE_SYSTEM_PROCESSOR}.fd - -hda fat:rw:./image/ - ) -endif () +INCLUDE (compile_config) # 添加要编译的目录 -add_subdirectory(${PROJECT_SOURCE_DIR}/src) -add_subdirectory(${PROJECT_SOURCE_DIR}/test) -add_subdirectory(${PROJECT_SOURCE_DIR}/doc) - -# 添加 run 和 debug target -add_run_target( - DEPENDS ovmf $<$:opensbi-fw_jump> $<$:boot> $<$:boot> $<$:boot> kernel - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - TARGET ${CMAKE_SYSTEM_PROCESSOR} - BOOT ${PROJECT_BINARY_DIR}/src/boot/boot.efi - KERNEL $ - QEMU_FLAGS ${QEMU_FLAGS} -) +ADD_SUBDIRECTORY (${PROJECT_SOURCE_DIR}/src) +ADD_SUBDIRECTORY (${PROJECT_SOURCE_DIR}/test) +ADD_SUBDIRECTORY (${PROJECT_SOURCE_DIR}/doc) diff --git a/CMakePresets.json b/CMakePresets.json index 238257a92..9c6c69fce 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -59,29 +59,29 @@ "type": "STRING", "value": "Generic" }, - "COVERAGE_OUTPUT_DIR": { + "CMAKE_BUILD_PARALLEL_LEVEL": { "type": "STRING", - "value": "coverage" + "value": "8" }, - "PLATFORM": { + "COVERAGE_OUTPUT_DIR": { "type": "STRING", - "value": "qemu" + "value": "coverage" }, - "QEMU_GDB_PORT": { + "QEMU_NORMAL_WORLD_DEV_PATH": { "type": "STRING", - "value": "tcp::1234" + "value": "tcp:127.0.0.1:54320" }, - "QEMU_MONITOR_ARG": { + "QEMU_SECURE_WORLD_DEV_PATH": { "type": "STRING", - "value": "telnet::2333,server,nowait" + "value": "tcp:127.0.0.1:54321" }, - "BOOT_ELF_OUTPUT_NAME": { + "QEMU_DEBUG_FLAGS": { "type": "STRING", - "value": "boot.elf" + "value": "-S;-gdb;tcp::1234" }, - "BOOT_EFI_OUTPUT_NAME": { + "QEMU_COMMON_FLAG": { "type": "STRING", - "value": "boot.efi" + "value": "-nographic;-serial;stdio;-monitor;telnet::2333,server,nowait;-m;1024M;-smp;2;-netdev;user,id=net0,tftp=/srv/tftp;-device;e1000,netdev=net0" }, "KERNEL_ELF_OUTPUT_NAME": { "type": "STRING", @@ -110,7 +110,11 @@ }, "LIBRARY_OUTPUT_PATH": { "type": "STRING", - "value": "${sourceDir}/build_x86_64/lib" + "value": "${sourceDir}/build_x86_64/bin" + }, + "QEMU_MACHINE_FLAGS": { + "type": "STRING", + "value": "" } } }, @@ -135,11 +139,15 @@ }, "LIBRARY_OUTPUT_PATH": { "type": "STRING", - "value": "${sourceDir}/build_riscv64/lib" + "value": "${sourceDir}/build_riscv64/bin" }, "USE_NO_RELAX": { "type": "BOOL", "value": "OFF" + }, + "QEMU_MACHINE_FLAGS": { + "type": "STRING", + "value": "-machine;virt" } } }, @@ -164,9 +172,13 @@ }, "LIBRARY_OUTPUT_PATH": { "type": "STRING", - "value": "${sourceDir}/build_aarch64/lib" + "value": "${sourceDir}/build_aarch64/bin" + }, + "QEMU_MACHINE_FLAGS": { + "type": "STRING", + "value": "-machine;virt,secure=on,gic_version=3;-cpu;cortex-a72" } } } ] -} \ No newline at end of file +} diff --git a/README.md b/README.md index 1b96d52bc..d201dbd95 100644 --- a/README.md +++ b/README.md @@ -14,101 +14,50 @@ boot branch ## 关键词 -- kernel +- kernel, own kernel - x86_64, riscv64, aarch64 - osdev -- bare metal -- c++, cmake -- uefi, opensbi +- c++ bare metal +- u-boot, opensbi +- linux -## 简介 +## 快速开始 -提供了各个阶段完成度不同的内核,你可以从自己喜欢的地方开始。 +### 使用构建好的 Docker -## 快速开始 +```shell +# 拉取代码 +git pull https://github.com/MRNIU/SimpleKernel.git +git submodule update --init --recursive +# 拉取 Docker Image +docker pull ptrnull233/simple_kernel:latest +# 运行 Docker +docker run --name SimpleKernel-container -itd -p 233:22 -v ./SimpleKernel:/root/ ptrnull233/simple_kernel:latest +# 进入 Docker +docker exec -it SimpleKernel-container /bin/zsh +``` -1. 需要 Ubuntu 环境或使用 docker(见 tools/docker.md) - -2. 安装依赖 - - ```shell - sudo apt install --fix-missing -y gcc g++ gcc-riscv64-linux-gnu g++-riscv64-linux-gnu gcc-aarch64-linux-gnu g++-aarch64-linux-gnu - sudo apt install --fix-missing -y cmake qemu-system gdb-multiarch - sudo apt install --fix-missing -y doxygen graphviz - sudo apt install --fix-missing -y doxygen graphviz - sudo apt install --fix-missing -y clang-format clang-tidy cppcheck libgtest-dev lcov - ``` - - ```shell - git submodule update --init --recursive - ``` - -3. 编译并运行 - - ```shell - cd SimpleKernel - # 支持三种架构 - cmake --preset build_riscv64 - # cmake --preset build_x86_64 - # cmake --preset build_aarch64 - # 进入其中一个架构 - cd build_riscv64 - # 编译内核 - make kernel - # 在 qemu 中运行 - make run - ``` - -4. 调试 - - ```shell - # 进入构建目录后执行 - make debug - ``` - - 在一个新的 shell 中进入 gdb - ```shell - # 进入 gdb - gdb-multiarch - # 连接端口 - target remote :1234 - # 加载符号表 - file image/kernel.elf - # 开始执行 - c - ``` - +### 编译并运行 -## 执行流 +```shell +cd SimpleKernel +# build_riscv64/build_aarch64/build_x86_64/ +cmake --preset build_riscv64 +cd build_riscv64 +# 编译内核 +make kernel +# 在 qemu 中运行 +make run +``` - - x86_64/aarch64 - - - - - riscv64 - - +### 使用 vscode +提供了用于运行、调试的 vscode 相关配置,可以直接使用 vscode 运行内核或进行调试。 + + +## 执行流 + +[common_bootflow](https://www.planttext.com?text=dLDRIyCm57xU-HM7-2WROsCl1MLkYAWR38TF8YLjWmis5xDKEd-zITQkhHqezg4b9zyjvwJplQN65Y87iDpc39TA22LnePJ5BViec4mPx1ZDc44o6Kzcena1e8LLiX09Cm29Ad5gChnOyRUTlJFi0DffyfHhAYqcJYbNWQ-CVq_m1GPNmM0LwZ0OkWS6X3mFVPaGU0KcCqSj0J4Oa2qNEcUFp4YMayfhaHUivrMvJCV1nbT6syOXJcg33Z5qeSiKbCjHgdMB6r1ziWDnoN_Gz-znpfEqBBiQIwtl7ROlukr-2-0hVIOrwQxlxwjnN-B6bSy7s0iT_pL4xC3d5VuLPhlUT6OEhJipl3vEDGgN9Upusd5W4JuKGiDnuQhr92Bqifpc_ClTwCjBV2gavO910mr7ZN3jFxVIcaEpTUf4X2vPjGiqjVoJMXQOpQe60mIAevzQ4A4_O8W29yrAlmNo7WqGsgWwnK6ck55SMiXODqThtIIPkqQwN_eR) ## 新增特性 @@ -116,9 +65,9 @@ boot branch ||x86_64|riscv64|aarch64| | :-----------------------: | :-------------------------------: | :---------------------------------------------: | :-------------------: | -|引导|UEFI|opensbi|UEFI(未完成)| -|基本输出|通过 serial 实现|通过 opensbi 提供的 ecall 实现|TODO| -|硬件资源探测|由 UEFI 传递|dtb 解析|TODO| +|引导|u-boot|u-boot+opensbi|u-boot+atf+optee| +|基本输出|通过 serial 实现|通过 opensbi 提供的 ecall 实现|通过 serial 实现| +|硬件资源探测|由 u-boot 传递|由 u-boot 传递的 dtb|由 u-boot+atf 传递的 dtb| - 构建系统 @@ -126,24 +75,45 @@ boot branch - libc 支持 - | 函数/变量名 | 用途 | | - | :------------------: | :------------------------------: | :--: | - | `__stack_chk_guard` | 栈保护 | | - | `__stack_chk_fail()` | 栈保护检查失败后调用 | | - | `memcpy()` | 复制内存块 | | - | `memmove()` | 复制内存块,可以处理重叠区域。 | | - | `memset()` | 设置内存块 | | - | `memcmp()` | 比较内存块 | | - | `memchr()` | 在内存块中查找字符 | | - | `strcpy()` | 复制字符串 | | - | `strncpy()` | 复制指定长度的字符串 | | - | `strcat()` | 连接字符串 | | - | `strcmp()` | 比较字符串 | | - | `strncmp()` | 比较指定长度的字符串 | | - | `strlen()` | 获取字符串长度 | | - | `strnlen()` | 获取指定字符串长度 | | - | `strchr()` | 查找字符在字符串中的首次出现 | | - | `strrchr()` | 反向查找字符在字符串中的首次出现 | | + | 函数/变量名 | 用途 | | + | :------------------: | :----------------------------------------------: | :--: | + | `__stack_chk_guard` | 栈保护 | | + | `__stack_chk_fail()` | 栈保护检查失败后调用 | | + | `memcpy()` | 复制内存块 | | + | `memmove()` | 复制内存块,可以处理重叠区域。 | | + | `memset()` | 设置内存块 | | + | `memcmp()` | 比较内存块 | | + | `memchr()` | 在内存块中查找字符 | | + | `strcpy()` | 复制字符串 | | + | `strncpy()` | 复制指定长度的字符串 | | + | `strcat()` | 连接字符串 | | + | `strcmp()` | 比较字符串 | | + | `strncmp()` | 比较指定长度的字符串 | | + | `strlen()` | 获取字符串长度 | | + | `strnlen()` | 获取指定字符串长度 | | + | `strchr()` | 查找字符在字符串中的首次出现 | | + | `strrchr()` | 反向查找字符在字符串中的首次出现 | | + | `strtoull()` | 将字符串按指定进制转换为无符号长长整数 | | + | `strtoul()` | 将字符串按指定进制转换为无符号长整数 | | + | `strtoll()` | 将字符串按指定进制转换为长长整数 | | + | `strtol()` | 将字符串按指定进制转换为长整数 | | + | `atoll()` | 将字符串转换为长长整数 | | + | `atol()` | 将字符串转换为长整数 | | + | `atoi()` | 将字符串转换为整数 | | + | `isalnum()` | 检查字符是否为字母或数字 | | + | `isalpha()` | 检查字符是否为字母 | | + | `isblank()` | 检查字符是否为空白字符(空格或制表符) | | + | `iscntrl()` | 检查字符是否为控制字符 | | + | `isdigit()` | 检查字符是否为十进制数字(0-9) | | + | `isgraph()` | 检查字符是否为可打印字符(不包括空格) | | + | `islower()` | 检查字符是否为小写字母 | | + | `isprint()` | 检查字符是否为可打印字符(包括空格) | | + | `ispunct()` | 检查字符是否为标点符号 | | + | `isspace()` | 检查字符是否为空白字符(空格、制表符、换行符等) | | + | `isupper()` | 检查字符是否为大写字母 | | + | `isxdigit()` | 检查字符是否为十六进制数字(0-9、a-f、A-F) | | + | `tolower()` | 将字符转换为小写 | | + | `toupper()` | 将字符转换为大写 | | - libc++ 支持 @@ -172,31 +142,43 @@ boot branch 通过 throw 抛出异常后停机,没有上下文相关的处理 -- 带颜色的输出 +- klog 内核日志模块 基于 ANSI 转义码,在支持 ANSI 转义码的终端中可以显示有颜色的字符串 -- 基于 gnu-efi 引导的 x86_64 内核 - - 编译后生成 boot.efi 与 kernel.elf,进入 uefi 环境后首先执行 boot.efi,初始化完成后跳转到 kernel.elf 执行 - -- 基于 opensbi 引导的 riscv64 内核 +- 基于 u-boot+opensbi 引导的 riscv64 内核 1. 由 opensbi 进行初始化,直接跳转到内核地址,进入内核逻辑时为 S 态 2. gp 寄存器的初始化 - 3. 使用 libfdt(dtc 的一部分) 对 opensbi 传递的 dtb 信息进行解析 - 4. ns16550a 串口驱动 - 5. 基于 opensbi 的 printf + 3. 基于 opensbi 的 printf + 4. 使用 FIT 打包的内核 + +- 基于 u-boot 引导的 amd64 内核 + + 1. 由 u-boot 进行初始化,进入内核时为 64 位状态 + 2. 使用 FIT 打包的内核 -- 全局对象 +- 基于 u-boot+arm-trusted-firmware+optee 的 aarch64 内核 - | 对象名 | 位置 | 用途 | - | :--------------------------------------: | :----------------------------------: | :---------------------: | - | `static ostream cout` | src/kernel/libcxx/include/iostream | 内核中的 std::cout 实现 | - | `static Singleton kKernelElf` | src/kernel/include/kernel_elf.hpp | 解析内核自身的 elf 信息 | - | `static Singleton kKernelFdt` | src/kernel/include/kernel_fdt.hpp | 解析 dtb 信息 | - | `static Singleton kBasicInfo` | src/kernel/include/basic_info.hpp | 内核基本信息 | - | `static cpu::Serial kSerial(cpu::kCom1)` | src/kernel/arch/x86_64/arch_main.cpp | X86_64 下的串口 | + 1. 使用 FIT 打包的内核 + 2. 由 u-boot 进行初始化,进入内核时为 64 位状态 + 3. 使用 atf 框架 + +- SMP 支持 + + 多核支持 + +- spinlock + + 适用于多核抢占的自旋锁,主要用于 klog 模块 + +- dtb 解析 + +- elf 解析 + +- ns16550a 串口驱动 + +- pl011 串口驱动 - 基于 doxygen 的文档生成与自动部署 @@ -228,19 +210,25 @@ boot branch ## 使用的第三方资源 -[opensbi](https://github.com/riscv-software-src/opensbi) +[google/googletest](https://github.com/google/googletest.git) + +[eyalroz/printf](https://github.com/eyalroz/printf.git) + +[MRNIU/cpu_io](https://github.com/MRNIU/cpu_io.git) + +[riscv-software-src/opensbi](https://github.com/riscv-software-src/opensbi.git) -[gnu-efi](https://sourceforge.net/projects/gnu-efi/) +[MRNIU/opensbi_interface](https://github.com/MRNIU/opensbi_interface.git) -[gdbinit](https://github.com/gdbinit/Gdbinit) +[u-boot/u-boot](https://github.com/u-boot/u-boot.git) -[opensbi_interface](https://github.com/MRNIU/opensbi_interface) +[OP-TEE/optee_os](https://github.com/OP-TEE/optee_os.git) -[printf_bare_metal](https://github.com/MRNIU/printf_bare_metal) +[OP-TEE/optee_client](https://github.com/OP-TEE/optee_client.git) -[dtc](https://git.kernel.org/pub/scm/utils/dtc/dtc.git) +[ARM-software/arm-trusted-firmware](https://github.com/ARM-software/arm-trusted-firmware.git) -[google/googletest](https://github.com/google/googletest) +[dtc/dtc](https://git.kernel.org/pub/scm/utils/dtc/dtc.git) ## 开发指南 diff --git a/README_ENG.md b/README_ENG.md index fbaf7615a..20dedc7bd 100644 --- a/README_ENG.md +++ b/README_ENG.md @@ -10,66 +10,123 @@ # SimpleKernel +boot branch + ## Key Words -- kernel -- x86_64, riscv64, aarch64 +- kernel, own kernel +- x86_64/ riscv64/ aarch64 - osdev -- bare metal -- c++, cmake -- uefi, opensbi +- c++ bare metal +- u-boot, opensbi +- linux -## Introduction -SimpleKernel, a simple kernel for learning. Contains the basic functionality of an operating system +## Quick Start -Kernels with different levels of completion are available, and you can start from where you like. +### Using Pre-built Docker -## What's NEW +```shell +# Clone repository +git clone https://github.com/MRNIU/SimpleKernel.git +git submodule update --init --recursive +# Pull Docker Image +docker pull ptrnull233/simple_kernel:latest +# Run Docker +docker run --name SimpleKernel-container -itd -p 233:22 -v ./SimpleKernel:/root/ ptrnull233/simple_kernel:latest +# Enter Docker +docker exec -it SimpleKernel-container /bin/zsh +``` -This branch is the first branch of SImpleKernel. In this branch, the foundation of the build system is completed, basic documentation deployment and automated testing, and of course the most important, there is a uefi based x86_64 kernel and riscv64 kernel started by opensbi, which can run on qemu, and achieve simple screen output. +### Build and Run + +```shell +cd SimpleKernel +# build_riscv64/build_aarch64/build_x86_64/ +cmake --preset build_riscv64 +cd build_riscv64 +# Build kernel +make kernel +# Run in QEMU +make run +``` + +### Using VSCode + +Pre-configured VSCode settings for running and debugging the kernel are provided. -- Control flow - - - x86_64/aarch64 - - - - - riscv64 - - +## Execution Flow + +[common_bootflow](https://www.planttext.com?text=dLDRIyCm57xU-HM7-2WROsCl1MLkYAWR38TF8YLjWmis5xDKEd-zITQkhHqezg4b9zyjvwJplQN65Y87iDpc39TA22LnePJ5BViec4mPx1ZDc44o6Kzcena1e8LLiX09Cm29Ad5gChnOyRUTlJFi0DffyfHhAYqcJYbNWQ-CVq_m1GPNmM0LwZ0OkWS6X3mFVPaGU0KcCqSj0J4Oa2qNEcUFp4YMayfhaHUivrMvJCV1nbT6syOXJcg33Z5qeSiKbCjHgdMB6r1ziWDnoN_Gz-znpfEqBBiQIwtl7ROlukr-2-0hVIOrwQxlxwjnN-B6bSy7s0iT_pL4xC3d5VuLPhlUT6OEhJipl3vEDGgN9Upusd5W4JuKGiDnuQhr92Bqifpc_ClTwCjBV2gavO910mr7ZN3jFxVIcaEpTUf4X2vPjGiqjVoJMXQOpQe60mIAevzQ4A4_O8W29yrAlmNo7WqGsgWwnK6ck55SMiXODqThtIIPkqQwN_eR) + +## New Features + +This branch is the first branch of SImpleKernel. In this branch, the foundation of the build system is completed, basic documentation deployment and automated testing, and of course the most important, there is a uefi based x86_64 kernel and riscv64 kernel started by opensbi, which can run on qemu, and achieve simple screen output. - Build system Reference [MRNIU/cmake-kernel](https://github.com/MRNIU/cmake-kernel) build system, a detailed explanation see [doc/build_system.md](./doc/build_system.md) -- x86_64 kernel based on gnu-efi boot +- Stack Trace Printing + + Traverse frame pointers and cross-reference with ELF symbol tables to reconstruct function call stacks. + +- Basic C++ Exception Support + + Implements throw to trigger exceptions followed by system termination (no context-aware exception handling). + +- klog Kernel Logging Module + + Supports ANSI escape codes for colored text output in ANSI-compatible terminals. + +- RISC-V64 (U-Boot + OpenSBI) + + - Initialized by OpenSBI; kernel entry in Supervisor (S) mode. + + - GP (Global Pointer) register initialization. + + - printf implementation leveraging OpenSBI. + + - FIT (Flattened Image Tree) image packaging. + +- AMD64 (U-Boot) - After compiling, boot.efi and kernel.elf are generated. After entering uefi environment, boot.efi is executed first. After initialization, kernel.elf is executed + - Initialized by U-Boot; kernel enters 64-bit mode directly. -- riscv64 kernel based on opensbi boot + - FIT image packaging. + +- AArch64 (U-Boot + Arm Trusted Firmware [ATF] + OP-TEE) + + - FIT image packaging. + + - Initialized by U-Boot in 64-bit mode. + + - ATF (Arm Trusted Firmware) framework integration. + +- SMP Support + + Multi-core CPU coordination + +- Spinlock + + Preemptive multi-core spinlock implementation (primarily for klog synchronization). + +- Device Tree Blob (DTB) Parsing + + Hardware configuration decoding. + +- ELF Parsing + + Executable/linkable format analysis. + +- NS16550A + + UART driver for x86/RISC-V platforms. + +- PL011 + + UART driver for ARM platforms. - Initializing by opensbi, it jumps directly to the kernel address and enters the S state when entering the kernel logic - Doxygen-based document generation and automatic deployment @@ -90,31 +147,38 @@ This branch is the first branch of SImpleKernel. In this branch, the foundation - Code formatting Use the llvm style - + - docker Supports building with docker, see [doc/docker.md](./doc/docker.md) -## Supported +## Supported Features -See What's NEW +See "New Features" section ## 3rd -[CPM](https://github.com/cpm-cmake/CPM.cmake) +[google/googletest](https://github.com/google/googletest.git) + +[eyalroz/printf](https://github.com/eyalroz/printf.git) + +[MRNIU/cpu_io](https://github.com/MRNIU/cpu_io.git) + +[riscv-software-src/opensbi](https://github.com/riscv-software-src/opensbi.git) -[opensbi](https://github.com/riscv-software-src/opensbi) +[MRNIU/opensbi_interface](https://github.com/MRNIU/opensbi_interface.git) -[gnu-efi](https://sourceforge.net/projects/gnu-efi/) +[u-boot/u-boot](https://github.com/u-boot/u-boot.git) -[gdbinit](https://github.com/gdbinit/Gdbinit) +[OP-TEE/optee_os](https://github.com/OP-TEE/optee_os.git) -[opensbi_interface](https://github.com/MRNIU/opensbi_interface) +[OP-TEE/optee_client](https://github.com/OP-TEE/optee_client.git) -[printf_bare_metal](https://github.com/MRNIU/printf_bare_metal) +[ARM-software/arm-trusted-firmware](https://github.com/ARM-software/arm-trusted-firmware.git) -[fdt_parser](https://github.com/MRNIU/fdt_parser) +[dtc/dtc](https://git.kernel.org/pub/scm/utils/dtc/dtc.git)https://github.com/google/googletest) -[CPMLicences.cmake](https://github.com/TheLartians/CPMLicenses.cmake) -[google/googletest](https://github.com/google/googletest) +## Development Guide +- Code Style: Google Style (enforced via .clang-format) +- Naming Convention: [Google Open Source Style Guide](https://google.github.io/styleguide/cppguide.html) diff --git a/cmake/3rd.cmake b/cmake/3rd.cmake index 9cfcbbe79..caebc6fbd 100644 --- a/cmake/3rd.cmake +++ b/cmake/3rd.cmake @@ -1,4 +1,3 @@ - # This file is a part of Simple-XX/SimpleKernel # (https://github.com/Simple-XX/SimpleKernel). # @@ -52,288 +51,184 @@ # add_library(Freetype::Freetype ALIAS freetype) # endif() +# Pre-commit hooks +IF(NOT EXISTS ${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit) + EXECUTE_PROCESS (COMMAND pre-commit install) +ENDIF() + # https://github.com/google/googletest.git -if (NOT TARGET gtest) - add_subdirectory(3rd/googletest) - include(GoogleTest) -endif () +IF(NOT TARGET gtest) + ADD_SUBDIRECTORY (3rd/googletest) + INCLUDE (GoogleTest) +ENDIF() -# https://github.com/gdbinit/Gdbinit.git -set(gdbinit_SOURCE_DIR ${CMAKE_SOURCE_DIR}/3rd/gdbinit) -set(gdbinit_BINARY_DIR ${CMAKE_BINARY_DIR}/3rd/gdbinit) -add_custom_target(gdbinit - COMMENT "Generate gdbinit ..." - WORKING_DIRECTORY ${gdbinit_SOURCE_DIR} - # 复制到根目录下并重命名 - COMMAND - ${CMAKE_COMMAND} - -E - copy - ${gdbinit_SOURCE_DIR}/gdbinit - ${CMAKE_SOURCE_DIR}/.gdbinit - COMMAND - echo "target remote ${QEMU_GDB_PORT}" >> ${CMAKE_SOURCE_DIR}/.gdbinit - COMMAND - echo "add-symbol-file ${kernel_BINARY_DIR}/${KERNEL_ELF_OUTPUT_NAME}" >> ${CMAKE_SOURCE_DIR}/.gdbinit - COMMAND - echo "add-symbol-file ${boot_BINARY_DIR}/${BOOT_ELF_OUTPUT_NAME}" >> ${CMAKE_SOURCE_DIR}/.gdbinit -) -# 在 make clean 时删除 .gdbinit -set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES - ${CMAKE_SOURCE_DIR}/.gdbinit -) +# https://github.com/eyalroz/printf.git +ADD_SUBDIRECTORY (3rd/printf) -# https://github.com/MRNIU/printf_bare_metal.git -add_subdirectory(3rd/printf_bare_metal) +# https://github.com/MRNIU/cpu_io.git +ADD_SUBDIRECTORY (3rd/cpu_io) -if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "riscv64") +IF(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "riscv64") # https://github.com/riscv-software-src/opensbi.git # 编译 opensbi - set(opensbi_SOURCE_DIR ${CMAKE_SOURCE_DIR}/3rd/opensbi) - set(opensbi_BINARY_DIR ${CMAKE_BINARY_DIR}/3rd/opensbi) - add_custom_target(opensbi - COMMENT "build opensbi..." - # make 时编译 - ALL - WORKING_DIRECTORY ${opensbi_SOURCE_DIR} - COMMAND - ${CMAKE_COMMAND} - -E - make_directory - ${opensbi_BINARY_DIR} - COMMAND - make - CROSS_COMPILE=${TOOLCHAIN_PREFIX} - FW_JUMP=y - FW_JUMP_ADDR=0x80210000 - PLATFORM_RISCV_XLEN=64 - PLATFORM=generic - O=${opensbi_BINARY_DIR} - COMMAND - ${CMAKE_COMMAND} - -E - copy_directory - ${opensbi_SOURCE_DIR}/include - ${opensbi_BINARY_DIR}/include - ) - add_library(opensbi-fw_jump INTERFACE) - add_dependencies(opensbi-fw_jump opensbi) - target_include_directories(opensbi-fw_jump INTERFACE - ${dtc_BINARY_DIR}/libfdt - ) - target_link_libraries(opensbi-fw_jump INTERFACE - ${dtc_BINARY_DIR}/libfdt/libfdt.a - ) + SET (opensbi_SOURCE_DIR ${CMAKE_SOURCE_DIR}/3rd/opensbi) + SET (opensbi_BINARY_DIR ${CMAKE_BINARY_DIR}/3rd/opensbi) + ADD_CUSTOM_TARGET ( + opensbi + COMMENT "build opensbi..." + # make 时编译 + ALL + WORKING_DIRECTORY ${opensbi_SOURCE_DIR} + COMMAND ${CMAKE_COMMAND} -E make_directory ${opensbi_BINARY_DIR} + COMMAND + make PLATFORM_RISCV_XLEN=64 PLATFORM=generic FW_JUMP_ADDR=0x80210000 + CROSS_COMPILE=${TOOLCHAIN_PREFIX} O=${opensbi_BINARY_DIR} + -j${CMAKE_BUILD_PARALLEL_LEVEL} + COMMAND ln -s -f ${opensbi_SOURCE_DIR}/include ${opensbi_BINARY_DIR}) # https://github.com/MRNIU/opensbi_interface.git - add_subdirectory(3rd/opensbi_interface) -endif () - -# https://git.kernel.org/pub/scm/utils/dtc/dtc.git -set(dtc_SOURCE_DIR ${CMAKE_SOURCE_DIR}/3rd/dtc) -set(dtc_BINARY_DIR ${CMAKE_BINARY_DIR}/3rd/dtc) -set(dtc_CC ${CMAKE_C_COMPILER}) -set(dtc_AR ${CMAKE_AR}) -# 编译 libfdt -add_custom_target(dtc - COMMENT "build libdtc..." + ADD_SUBDIRECTORY (3rd/opensbi_interface) +ENDIF() + +# https://github.com/u-boot/u-boot.git +SET (u-boot_SOURCE_DIR ${CMAKE_SOURCE_DIR}/3rd/u-boot) +SET (u-boot_BINARY_DIR ${CMAKE_BINARY_DIR}/3rd/u-boot) +ADD_CUSTOM_TARGET ( + u-boot + COMMENT "build u-boot..." + # make 时编译 + ALL + DEPENDS $<$:opensbi> + WORKING_DIRECTORY ${u-boot_SOURCE_DIR} + COMMAND ${CMAKE_COMMAND} -E make_directory ${u-boot_BINARY_DIR} + COMMAND + make O=${u-boot_BINARY_DIR} + $<$:qemu_arm64_defconfig> + $<$:qemu-riscv64_spl_defconfig> + $<$:qemu-x86_64_defconfig> + -j${CMAKE_BUILD_PARALLEL_LEVEL} + COMMAND + make CROSS_COMPILE=${TOOLCHAIN_PREFIX} O=${u-boot_BINARY_DIR} + $<$:OPENSBI=${opensbi_BINARY_DIR}/platform/generic/firmware/fw_dynamic.bin> + -j${CMAKE_BUILD_PARALLEL_LEVEL}) +SET_DIRECTORY_PROPERTIES (PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES + ${u-boot_BINARY_DIR}) + +IF(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64") + # https://github.com/OP-TEE/optee_os.git + SET (optee_os_SOURCE_DIR ${CMAKE_SOURCE_DIR}/3rd/optee/optee_os) + SET (optee_os_BINARY_DIR ${CMAKE_BINARY_DIR}/3rd/optee/optee_os) + ADD_CUSTOM_TARGET ( + optee_os + COMMENT "build optee_os..." # make 时编译 ALL - WORKING_DIRECTORY ${dtc_SOURCE_DIR} + WORKING_DIRECTORY ${optee_os_SOURCE_DIR} + COMMAND ${CMAKE_COMMAND} -E make_directory ${optee_os_BINARY_DIR} COMMAND - ${CMAKE_COMMAND} - -E - make_directory - ${dtc_BINARY_DIR}/libfdt - COMMAND - CC=${dtc_CC} - AR=${dtc_AR} - HOME=${dtc_BINARY_DIR} - make libfdt/libfdt.a - COMMAND - ${CMAKE_COMMAND} - -E - copy - ${dtc_SOURCE_DIR}/libfdt/*.a - ${dtc_SOURCE_DIR}/libfdt/*.h - ${dtc_BINARY_DIR}/libfdt - COMMAND - make clean -) -add_library(dtc-lib INTERFACE) -add_dependencies(dtc-lib dtc) -target_include_directories(dtc-lib INTERFACE - ${dtc_BINARY_DIR}/libfdt -) -target_link_libraries(dtc-lib INTERFACE - ${dtc_BINARY_DIR}/libfdt/libfdt.a -) - -# https://github.com/ncroxon/gnu-efi.git -set(gnu-efi_SOURCE_DIR ${CMAKE_SOURCE_DIR}/3rd/gnu-efi) -set(gnu-efi_BINARY_DIR ${CMAKE_BINARY_DIR}/3rd/gnu-efi) -if (CMAKE_SYSTEM_PROCESSOR STREQUAL CMAKE_HOST_SYSTEM_PROCESSOR) -set(CC_ ${CMAKE_C_COMPILER}) -set(AR_ ${CMAKE_AR}) -elseif (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64" AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") -set(CROSS_COMPILE_ x86_64-linux-gnu-) -elseif (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64" AND CMAKE_SYSTEM_PROCESSOR MATCHES "riscv64") -set(CROSS_COMPILE_ riscv64-linux-gnu-) -endif () -# 编译 gnu-efi -add_custom_target(gnu-efi - COMMENT "build gnu-efi..." + make CFG_ARM64_core=y CFG_TEE_BENCHMARK=n CFG_TEE_CORE_LOG_LEVEL=3 + CROSS_COMPILE=${TOOLCHAIN_PREFIX} + CROSS_COMPILE_core=${TOOLCHAIN_PREFIX} + CROSS_COMPILE_ta_arm32=${TOOLCHAIN_PREFIX32} + CROSS_COMPILE_ta_arm64=${TOOLCHAIN_PREFIX} DEBUG=$· + O=${optee_os_BINARY_DIR} PLATFORM=vexpress-qemu_armv8a + CFG_ARM_GICV3=y -j${CMAKE_BUILD_PARALLEL_LEVEL}) + SET_DIRECTORY_PROPERTIES (PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES + ${optee_os_BINARY_DIR}) + + # https://github.com/OP-TEE/optee_client.git + ADD_SUBDIRECTORY (${CMAKE_SOURCE_DIR}/3rd/optee/optee_client) + + # https://github.com/ARM-software/arm-trusted-firmware + # 编译 atf + SET (arm-trusted-firmware_SOURCE_DIR + ${CMAKE_SOURCE_DIR}/3rd/arm-trusted-firmware) + SET (arm-trusted-firmware_BINARY_DIR + ${CMAKE_BINARY_DIR}/3rd/arm-trusted-firmware) + ADD_CUSTOM_TARGET ( + arm-trusted-firmware + COMMENT "build arm-trusted-firmware..." # make 时编译 ALL - WORKING_DIRECTORY ${gnu-efi_SOURCE_DIR} + DEPENDS optee_os u-boot + WORKING_DIRECTORY ${arm-trusted-firmware_SOURCE_DIR} + COMMAND ${CMAKE_COMMAND} -E make_directory + ${arm-trusted-firmware_BINARY_DIR} COMMAND - ${CMAKE_COMMAND} - -E - make_directory - ${gnu-efi_BINARY_DIR} + make DEBUG=$ CROSS_COMPILE=${TOOLCHAIN_PREFIX} + PLAT=qemu BUILD_BASE=${arm-trusted-firmware_BINARY_DIR} + BL32=${optee_os_BINARY_DIR}/core/tee-header_v2.bin + BL32_EXTRA1=${optee_os_BINARY_DIR}/core/tee-pager_v2.bin + BL32_EXTRA2=${optee_os_BINARY_DIR}/core/tee-pageable_v2.bin + BL33=${u-boot_BINARY_DIR}/u-boot.bin BL32_RAM_LOCATION=tdram + QEMU_USE_GIC_DRIVER=QEMU_GICV3 SPD=opteed all fip + -j${CMAKE_BUILD_PARALLEL_LEVEL} COMMAND - # @note 仅支持 gcc - make lib gnuefi inc - CROSS_COMPILE=${CROSS_COMPILE_} - ARCH=${CMAKE_SYSTEM_PROCESSOR} - OBJDIR=${gnu-efi_BINARY_DIR} - V=1 + dd + if=${arm-trusted-firmware_BINARY_DIR}/qemu/$,debug,release>/bl1.bin + of=${arm-trusted-firmware_BINARY_DIR}/flash.bin bs=4096 conv=notrunc COMMAND - ${CMAKE_COMMAND} - -E - copy_directory - ${gnu-efi_SOURCE_DIR}/inc - ${gnu-efi_BINARY_DIR}/inc -) -add_library(gnu-efi-lib INTERFACE) -add_dependencies(gnu-efi-lib gnu-efi) -target_include_directories(gnu-efi-lib INTERFACE - ${gnu-efi_BINARY_DIR}/inc - ${gnu-efi_BINARY_DIR}/inc/${CMAKE_SYSTEM_PROCESSOR} - ${gnu-efi_BINARY_DIR}/inc/protocol -) -target_link_libraries(gnu-efi-lib INTERFACE - ${gnu-efi_BINARY_DIR}/gnuefi/reloc_${CMAKE_SYSTEM_PROCESSOR}.o - ${gnu-efi_BINARY_DIR}/gnuefi/crt0-efi-${CMAKE_SYSTEM_PROCESSOR}.o - ${gnu-efi_BINARY_DIR}/gnuefi/libgnuefi.a - ${gnu-efi_BINARY_DIR}/lib/libefi.a -) + dd + if=${arm-trusted-firmware_BINARY_DIR}/qemu/$,debug,release>/fip.bin + of=${arm-trusted-firmware_BINARY_DIR}/flash.bin seek=64 bs=4096 + conv=notrunc) + SET_DIRECTORY_PROPERTIES (PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES + ${arm-trusted-firmware_BINARY_DIR}) +ENDIF() -# ovmf -# @todo 使用互联网连接或从 edk2 编译 -# https://efi.akeo.ie/QEMU_EFI/QEMU_EFI-AA64.zip -set(ovmf_SOURCE_DIR ${CMAKE_SOURCE_DIR}/tools/ovmf) -set(ovmf_BINARY_DIR ${CMAKE_BINARY_DIR}/3rd/ovmf) -add_custom_target(ovmf - COMMENT "build ovmf ..." +# https://git.kernel.org/pub/scm/utils/dtc/dtc.git +SET (dtc_SOURCE_DIR ${CMAKE_SOURCE_DIR}/3rd/dtc) +SET (dtc_BINARY_DIR ${CMAKE_BINARY_DIR}/3rd/dtc) +SET (dtc_CC ${CMAKE_C_COMPILER}) +SET (dtc_AR ${CMAKE_AR}) +# 编译 libfdt +IF(NOT EXISTS ${dtc_BINARY_DIR}/libfdt/libfdt.a) + ADD_CUSTOM_TARGET ( + dtc + COMMENT "build libdtc..." # make 时编译 ALL - WORKING_DIRECTORY ${ovmf_SOURCE_DIR} - COMMAND - ${CMAKE_COMMAND} - -E - make_directory - ${ovmf_BINARY_DIR} - COMMAND - ${CMAKE_COMMAND} - -E - copy - ${ovmf_SOURCE_DIR}/* - ${ovmf_BINARY_DIR} -) - -# gdb -find_program(GDB_EXE gdb) -if (NOT GDB_EXE) - message(FATAL_ERROR "gdb not found.\n" - "Following https://www.sourceware.org/gdb/ to install.") -endif () - -# qemu -find_program(QEMU_EXE qemu-system-${CMAKE_SYSTEM_PROCESSOR}) -if (NOT QEMU_EXE) - message(FATAL_ERROR "qemu-system-${CMAKE_SYSTEM_PROCESSOR} not found.\n" - "Following https://www.qemu.org/ to install.") -endif () + WORKING_DIRECTORY ${dtc_SOURCE_DIR} + COMMAND ${CMAKE_COMMAND} -E make_directory ${dtc_BINARY_DIR}/libfdt + COMMAND CC=${dtc_CC} AR=${dtc_AR} HOME=${dtc_BINARY_DIR} make + libfdt/libfdt.a -j${CMAKE_BUILD_PARALLEL_LEVEL} + COMMAND ${CMAKE_COMMAND} -E copy ${dtc_SOURCE_DIR}/libfdt/*.a + ${dtc_SOURCE_DIR}/libfdt/*.h ${dtc_BINARY_DIR}/libfdt + COMMAND make clean) +ELSE() + ADD_CUSTOM_TARGET ( + dtc + COMMENT "libdtc already exists, skipping..." + # make 时编译 + ALL + WORKING_DIRECTORY ${dtc_SOURCE_DIR}) +ENDIF() +ADD_LIBRARY (dtc-lib INTERFACE) +ADD_DEPENDENCIES (dtc-lib dtc) +TARGET_INCLUDE_DIRECTORIES (dtc-lib INTERFACE ${dtc_BINARY_DIR}/libfdt) +TARGET_LINK_LIBRARIES (dtc-lib INTERFACE ${dtc_BINARY_DIR}/libfdt/libfdt.a) # doxygen -find_package(Doxygen - REQUIRED dot) -if (NOT DOXYGEN_FOUND) - message(FATAL_ERROR "Doxygen not found.\n" - "Following https://www.doxygen.nl/index.html to install.") -endif () +FIND_PACKAGE (Doxygen REQUIRED dot) # cppcheck -find_program(CPPCHECK_EXE NAMES cppcheck) -if (NOT CPPCHECK_EXE) - message(FATAL_ERROR "cppcheck not found.\n" - "Following https://cppcheck.sourceforge.io to install.") -endif () -add_custom_target(cppcheck - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - COMMENT "Run cppcheck on ${CMAKE_BINARY_DIR}/compile_commands.json ..." - COMMAND - ${CPPCHECK_EXE} - --enable=all +FIND_PROGRAM (CPPCHECK_EXE NAMES cppcheck) + +# cppcheck +FIND_PROGRAM (CPPCHECK_EXE NAMES cppcheck) +ADD_CUSTOM_TARGET ( + cppcheck + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMENT "Run cppcheck on ${CMAKE_BINARY_DIR}/compile_commands.json ..." + COMMAND + ${CPPCHECK_EXE} --enable=all --project=${CMAKE_BINARY_DIR}/compile_commands.json --suppress-xml=${CMAKE_SOURCE_DIR}/tools/cppcheck-suppressions.xml - --output-file=${CMAKE_BINARY_DIR}/cppcheck_report.log -) - -# 获取全部源文件 -file(GLOB_RECURSE ALL_SOURCE_FILES - ${CMAKE_SOURCE_DIR}/src/*.h - ${CMAKE_SOURCE_DIR}/src/*.hpp - ${CMAKE_SOURCE_DIR}/src/*.c - ${CMAKE_SOURCE_DIR}/src/*.cpp - ${CMAKE_SOURCE_DIR}/test/*.h - ${CMAKE_SOURCE_DIR}/test/*.hpp - ${CMAKE_SOURCE_DIR}/test/*.c - ${CMAKE_SOURCE_DIR}/test/*.cpp -) + --output-file=${CMAKE_BINARY_DIR}/cppcheck_report.log) -# clang-tidy -find_program(CLANG_TIDY_EXE NAMES clang-tidy) -if (NOT CLANG_TIDY_EXE) - message(FATAL_ERROR "clang-tidy not found.\n" - "Following https://clang.llvm.org/extra/clang-tidy to install.") -endif () -add_custom_target(clang-tidy - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - COMMENT "Run clang-tidy on ${ALL_SOURCE_FILES} ..." - COMMAND - ${CLANG_TIDY_EXE} - --config-file=${CMAKE_SOURCE_DIR}/.clang-tidy - -p=${CMAKE_BINARY_DIR} - ${ALL_SOURCE_FILES} - > ${CMAKE_BINARY_DIR}/clang_tidy_report.log 2>&1 -) - -# clang-format -find_program(CLANG_FORMAT_EXE NAMES clang-format) -if (NOT CLANG_FORMAT_EXE) - message(FATAL_ERROR "clang-format not found.\n" - "Following https://clang.llvm.org/docs/ClangFormat.html to install.") -endif () -add_custom_target(clang-format - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - COMMENT "Run clang-format on ${ALL_SOURCE_FILES} ..." - COMMAND ${CLANG_FORMAT_EXE} -i -style=file ${ALL_SOURCE_FILES} -) - -if (CMAKE_SYSTEM_PROCESSOR STREQUAL CMAKE_HOST_SYSTEM_PROCESSOR) +IF(CMAKE_SYSTEM_PROCESSOR STREQUAL CMAKE_HOST_SYSTEM_PROCESSOR) # genhtml 生成测试覆盖率报告网页 - find_program(GENHTML_EXE genhtml) - if (NOT GENHTML_EXE) - message(FATAL_ERROR "genhtml not found.\n" - "Following https://github.com/linux-test-project/lcov to install.") - endif () - + FIND_PROGRAM (GENHTML_EXE genhtml) # lcov 生成测试覆盖率报告 - find_program(LCOV_EXE lcov) - if (NOT LCOV_EXE) - message(FATAL_ERROR "lcov not found.\n" - "Following https://github.com/linux-test-project/lcov to install.") - endif () -endif () + FIND_PROGRAM (LCOV_EXE lcov) +ENDIF() diff --git a/cmake/aarch64-gcc.cmake b/cmake/aarch64-gcc.cmake index ddf3d9b14..c9fdaefea 100644 --- a/cmake/aarch64-gcc.cmake +++ b/cmake/aarch64-gcc.cmake @@ -1,39 +1,45 @@ - # This file is a part of Simple-XX/SimpleKernel # (https://github.com/Simple-XX/SimpleKernel). -# +# # aarch64-gcc.cmake for Simple-XX/SimpleKernel. -if (NOT UNIX) - message(FATAL_ERROR "Only support Linux.") -endif () +IF(NOT UNIX) + MESSAGE (FATAL_ERROR "Only support Linux.") +ENDIF() + +IF(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64") + FIND_PROGRAM (Compiler_gcc g++) + IF(NOT Compiler_gcc) + MESSAGE ( + FATAL_ERROR "g++ not found.\n" + "Run `sudo apt-get install -y gcc g++` to install.") + ELSE() + MESSAGE (STATUS "Found g++ ${Compiler_gcc}") + ENDIF() -if (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64") - find_program(Compiler_gcc g++) - if (NOT Compiler_gcc) - message(FATAL_ERROR "g++ not found.\n" - "Run `sudo apt-get install -y gcc g++` to install.") - else () - message(STATUS "Found g++ ${Compiler_gcc}") - endif () -elseif (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "x86_64") - find_program(Compiler_gcc aarch64-linux-gnu-g++) - if (NOT Compiler_gcc) - message(FATAL_ERROR "aarch64-linux-gnu-g++ not found.\n" - "Run `sudo apt install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu` to install.") - else () - message(STATUS "Found aarch64-linux-gnu-g++ ${Compiler_gcc}") - endif () + SET (TOOLCHAIN_PREFIX32 arm-linux-gnueabihf-) +ELSEIF(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "x86_64") + FIND_PROGRAM (Compiler_gcc aarch64-linux-gnu-g++) + IF(NOT Compiler_gcc) + MESSAGE ( + FATAL_ERROR + "aarch64-linux-gnu-g++ not found.\n" + "Run `sudo apt install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu` to install." + ) + ELSE() + MESSAGE (STATUS "Found aarch64-linux-gnu-g++ ${Compiler_gcc}") + ENDIF() - set(TOOLCHAIN_PREFIX aarch64-linux-gnu-) - set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc) - set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++) - set(CMAKE_READELF ${TOOLCHAIN_PREFIX}readelf) - set(CMAKE_AR ${TOOLCHAIN_PREFIX}ar) - set(CMAKE_LINKER ${TOOLCHAIN_PREFIX}ld) - set(CMAKE_NM ${TOOLCHAIN_PREFIX}nm) - set(CMAKE_OBJDUMP ${TOOLCHAIN_PREFIX}objdump) - set(CMAKE_RANLIB ${TOOLCHAIN_PREFIX}ranlib) -else () - message(FATAL_ERROR "NOT support ${CMAKE_HOST_SYSTEM_PROCESSOR}") -endif () + SET (TOOLCHAIN_PREFIX aarch64-linux-gnu-) + SET (CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc) + SET (CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++) + SET (CMAKE_READELF ${TOOLCHAIN_PREFIX}readelf) + SET (CMAKE_AR ${TOOLCHAIN_PREFIX}ar) + SET (CMAKE_LINKER ${TOOLCHAIN_PREFIX}ld) + SET (CMAKE_NM ${TOOLCHAIN_PREFIX}nm) + SET (CMAKE_OBJDUMP ${TOOLCHAIN_PREFIX}objdump) + SET (CMAKE_RANLIB ${TOOLCHAIN_PREFIX}ranlib) + SET (TOOLCHAIN_PREFIX32 arm-linux-gnueabihf-) +ELSE() + MESSAGE (FATAL_ERROR "NOT support ${CMAKE_HOST_SYSTEM_PROCESSOR}") +ENDIF() diff --git a/cmake/compile_config.cmake b/cmake/compile_config.cmake index b189a3275..47cc8e278 100644 --- a/cmake/compile_config.cmake +++ b/cmake/compile_config.cmake @@ -1,208 +1,150 @@ - # This file is a part of Simple-XX/SimpleKernel # (https://github.com/Simple-XX/SimpleKernel). # -# compile_config.cmake for Simple-XX/SimpleKernel. -# 配置信息 +# compile_config.cmake for Simple-XX/SimpleKernel. 配置信息 # 通用宏定义 -add_library(compile_definitions INTERFACE) -target_compile_definitions(compile_definitions INTERFACE - $<$:SIMPLEKERNEL_RELEASE> - $<$:SIMPLEKERNEL_DEBUG> -) +ADD_LIBRARY (compile_definitions INTERFACE) +TARGET_COMPILE_DEFINITIONS ( + compile_definitions INTERFACE $<$:SIMPLEKERNEL_RELEASE> + $<$:SIMPLEKERNEL_DEBUG>) + +# 获取 gcc 的 include 路径 +EXECUTE_PROCESS ( + COMMAND sh -c "echo | ${CMAKE_CXX_COMPILER} -v -x c -E - 2>&1 | sed -n \ + '/#include <...> search starts here:/,/End of search list./{/^ /p}'" + OUTPUT_VARIABLE GCC_OUTPUT + ERROR_VARIABLE GCC_ERROR + RESULT_VARIABLE GCC_RESULT + OUTPUT_STRIP_TRAILING_WHITESPACE) +# 检查 gcc 是否成功执行 +IF(NOT GCC_RESULT EQUAL 0) + MESSAGE (FATAL_ERROR "Failed to run ${CMAKE_CXX_COMPILER} -v") +ENDIF() +# 分割路径并生成路径列表 +STRING (REPLACE "\n" ";" INCLUDE_PATH_LIST "${GCC_OUTPUT}") +# 使用 `-I` 将路径添加到编译选项中 +FOREACH(item ${INCLUDE_PATH_LIST}) + STRING (REGEX REPLACE " " "" CLEAN_PATH ${item}) + LIST (APPEND CROSS_INCLUDE_PATHS "-I${CLEAN_PATH}") +ENDFOREACH() +MESSAGE (STATUS "GCC Include CROSS_INCLUDE_PATHS: ${CROSS_INCLUDE_PATHS}") # 通用编译选项 -add_library(compile_options INTERFACE) -target_compile_options(compile_options INTERFACE - # 如果 CMAKE_BUILD_TYPE 为 Release 则使用 -O3 -Werror,否则使用 -O0 -ggdb - # -g 在 Debug 模式下由 cmake 自动添加 - $<$:-O3;-Werror> - $<$:-O0;-ggdb> - # 打开全部警告 - -Wall - # 打开额外警告 - -Wextra - # 不符合规范的代码会警告 - -pedantic - # 生成位置无关代码 - -fPIC - # 生成位置无关可执行程序 - -fPIE - # 禁用运行时类型支持 - $<$:-fno-rtti> - # 启用 free-standing 环境,该选项隐含了 -fno-builtin - -ffreestanding - # 保留帧指针,便于调试和栈回溯 - -fno-omit-frame-pointer - # 不使用 common 段 - -fno-common - - # 目标平台编译选项 - $<$: - # 禁用 red-zone - -mno-red-zone - > - - $<$: - > - - $<$: - # 生成 armv8-a 代码 - -march=armv8-a - # 针对 cortex-a72 优化代码 - -mtune=cortex-a72 - > - - # gcc 特定选项 - $<$: - > - - # clang 特定选项 - $<$: - > - - # 平台相关 - $<$: - > -) +ADD_LIBRARY (compile_options INTERFACE) +TARGET_COMPILE_OPTIONS ( + compile_options + INTERFACE # 如果 CMAKE_BUILD_TYPE 为 Release 则使用 -O3 -Werror,否则使用 -O0 -ggdb -g + # 在 Debug 模式下由 cmake 自动添加 + $<$:-O3;-Werror> + $<$:-O0;-ggdb> + # 打开全部警告 + -Wall + # 打开额外警告 + -Wextra + # 不符合规范的代码会警告 + -pedantic + # 生成位置无关代码 + -fPIC + # 生成位置无关可执行程序 + -fPIE + # 禁用运行时类型支持 + $<$:-fno-rtti> + # 启用 free-standing 环境,该选项隐含了 -fno-builtin + -ffreestanding + # 保留帧指针,便于调试和栈回溯 + -fno-omit-frame-pointer + # 不使用 common 段 + -fno-common + # 目标平台编译选项 + $<$: + # 禁用 red-zone + -mno-red-zone + > + $<$: + > + $<$: + # 生成 armv8-a 代码 + -march=armv8-a + # 针对 cortex-a72 优化代码 + -mtune=cortex-a72 + -mno-outline-atomics + > + # gcc 特定选项 + $<$: + > + # clang 特定选项 + $<$: + > + # 平台相关 + $<$: + > + # 将编译器的 include 路径添加到编译选项中,以便 clang-tidy 使用 + ${CROSS_INCLUDE_PATHS}) # 通用链接选项 -add_library(link_options INTERFACE) -target_link_options(link_options INTERFACE - # 不链接 ctr0 等启动代码 - -nostartfiles -) +ADD_LIBRARY (link_options INTERFACE) +TARGET_LINK_OPTIONS ( + link_options INTERFACE + # 不链接 ctr0 等启动代码 + -nostartfiles) # 通用库选项 -add_library(link_libraries INTERFACE) -target_link_libraries(link_libraries INTERFACE - compile_definitions - compile_options - link_options -) - -add_library(boot_compile_definitions INTERFACE) -target_compile_definitions(boot_compile_definitions INTERFACE - # 使用 gnu-efi - GNU_EFI_USE_MS_ABI -) - -add_library(boot_compile_options INTERFACE) -target_compile_options(boot_compile_options INTERFACE - # 使用 2 字节 wchar_t - -fshort-wchar - # 允许 wchar_t - -fpermissive - - # 目标平台编译选项 - $<$: - > - - $<$: - > -) - -add_library(boot_link_options INTERFACE) -target_link_options(boot_link_options INTERFACE - $<$: - # 编译为共享库 - -shared - # 符号级别绑定 - -Wl,-Bsymbolic - > - - $<$: - # 编译为共享库 - -shared - # 符号级别绑定 - -Wl,-Bsymbolic - > - - $<$: - -shared - -Wl,-Bsymbolic - > -) - -add_library(boot_link_libraries INTERFACE) -target_link_libraries(boot_link_libraries INTERFACE - link_libraries - boot_compile_definitions - boot_compile_options - boot_link_options - - # 目标平台编译选项 - $<$: - # 链接 gnu-efi - gnu-efi-lib - > - - $<$: - # 链接 gnu-efi - gnu-efi-lib - > - - $<$: - # 链接 gnu-efi - gnu-efi-lib - > -) - -add_library(kernel_compile_definitions INTERFACE) -target_compile_definitions(kernel_compile_definitions INTERFACE - USE_NO_RELAX=$ -) - -add_library(kernel_compile_options INTERFACE) -target_compile_options(kernel_compile_options INTERFACE - $<$: - # 使用 kernel 内存模型 - -mcmodel=large - > - - $<$: - # 使用 medany 内存模型 - # 代码和数据段可以在任意地址 - -mcmodel=medany - > -) - -add_library(kernel_link_options INTERFACE) -target_link_options(kernel_link_options INTERFACE - # 链接脚本 - -T ${CMAKE_SOURCE_DIR}/src/kernel/arch/${CMAKE_SYSTEM_PROCESSOR}/link.ld - - # 静态链接 - -static - # 不链接标准库 - -nostdlib - - $<$: - # 设置最大页大小为 0x1000(4096) 字节 - -z max-page-size=0x1000 - > - - $<$: - # 禁用 relax 优化 - $<$:-mno-relax> - > -) - -add_library(kernel_link_libraries INTERFACE) -target_link_libraries(kernel_link_libraries INTERFACE - link_libraries - kernel_compile_definitions - kernel_compile_options - kernel_link_options - - printf_bare_metal - dtc-lib - - $<$: - opensbi_interface - > - - $<$: - > -) +ADD_LIBRARY (link_libraries INTERFACE) +TARGET_LINK_LIBRARIES (link_libraries INTERFACE compile_definitions + compile_options link_options) + +ADD_LIBRARY (kernel_compile_definitions INTERFACE) +TARGET_COMPILE_DEFINITIONS (kernel_compile_definitions + INTERFACE USE_NO_RELAX=$) + +ADD_LIBRARY (kernel_compile_options INTERFACE) +TARGET_COMPILE_OPTIONS ( + kernel_compile_options + INTERFACE $<$: + # 使用 kernel 内存模型 + -mcmodel=large + > + $<$: + # 使用 medany 内存模型 代码和数据段可以在任意地址 + -mcmodel=medany + >) + +ADD_LIBRARY (kernel_link_options INTERFACE) +TARGET_LINK_OPTIONS ( + kernel_link_options + INTERFACE + # 链接脚本 + -T + ${CMAKE_SOURCE_DIR}/src/arch/${CMAKE_SYSTEM_PROCESSOR}/link.ld + # 静态链接 + -static + # 不链接标准库 + -nostdlib + $<$: + # 设置最大页大小为 0x1000(4096) 字节 + -z + max-page-size=0x1000 + > + $<$: + # 禁用 relax 优化 + $<$:-mno-relax> + >) + +ADD_LIBRARY (kernel_link_libraries INTERFACE) +TARGET_LINK_LIBRARIES ( + kernel_link_libraries + INTERFACE link_libraries + kernel_compile_definitions + kernel_compile_options + kernel_link_options + printf + dtc-lib + cpu_io + gcc + $<$: + opensbi_interface + > + $<$: + teec + >) diff --git a/cmake/functions.cmake b/cmake/functions.cmake index c44ed31da..d1d7b1cc0 100644 --- a/cmake/functions.cmake +++ b/cmake/functions.cmake @@ -1,156 +1,134 @@ - # This file is a part of Simple-XX/SimpleKernel # (https://github.com/Simple-XX/SimpleKernel). # # functions.cmake for Simple-XX/SimpleKernel. # 辅助函数 -# 生成 target 输出文件的 objdump -D, readelf -a, nm -a -# _target: target 名 -# 在 ${${_target}_BINARY_DIR} 目录下生成 $.asm 文件 -# 在 ${${_target}_BINARY_DIR} 目录下生成 $.readelf 文件 -# 在 ${${_target}_BINARY_DIR} 目录下生成 $.sym 文件 -function(objdump_readelf_nm _target) - add_custom_command(TARGET ${_target} - VERBATIM - POST_BUILD - DEPENDS ${_target} - WORKING_DIRECTORY ${${_target}_BINARY_DIR} - COMMAND ${CMAKE_OBJDUMP} -D $ > $/${_target}.asm || exit 0 - COMMAND ${CMAKE_READELF} -a $ > $/${_target}.readelf || exit 0 - COMMAND ${CMAKE_NM} -a $ > $/${_target}.sym - COMMENT "Generating symbol table, assembly, and readelf result for ${_target}" - ) - set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES - "$/${_target}.asm;$/${_target}.readelf;$/${_target}.sym;" - ) -endfunction() - -# 将 elf 转换为 efi -# _elf: 要转换的 target 名 -# _efi: 输出的 efi 文件名 -# 在 ${${_target}_BINARY_DIR} 目录下生成 ${_efi} 文件 -function(elf2efi _target _efi) - add_custom_command(TARGET ${_target} - COMMENT "Convert $ to efi ..." - POST_BUILD - DEPENDS ${_target} - WORKING_DIRECTORY ${${_target}_BINARY_DIR} - COMMAND ${CMAKE_OBJCOPY} $ ${_efi} - -S - -R .comment - -R .note.gnu.build-id - -R .gnu.hash - -R .dynsym - --target=efi-app-${CMAKE_SYSTEM_PROCESSOR} --subsystem=10 - ) -endfunction() - # 添加测试覆盖率 target # DEPENDS 要生成的 targets # SOURCE_DIR 源码路径 # BINARY_DIR 二进制文件路径 # EXCLUDE_DIR 要排除的目录 -function(add_coverage_target) +FUNCTION(add_coverage_target) # 解析参数 - set(options) - set(one_value_keywords SOURCE_DIR BINARY_DIR) - set(multi_value_keywords DEPENDS EXCLUDE_DIR) - cmake_parse_arguments( - ARG "${options}" "${one_value_keywords}" "${multi_value_keywords}" ${ARGN} - ) + SET (options) + SET (one_value_keywords SOURCE_DIR BINARY_DIR) + SET (multi_value_keywords DEPENDS EXCLUDE_DIR) + CMAKE_PARSE_ARGUMENTS (ARG "${options}" "${one_value_keywords}" + "${multi_value_keywords}" ${ARGN}) # 不检查的目录 - list(APPEND EXCLUDES --exclude) - foreach (_item ${ARG_EXCLUDE_DIR}) - list(APPEND EXCLUDES '${_item}') - endforeach () + LIST (APPEND EXCLUDES --exclude) + FOREACH(item ${ARG_EXCLUDE_DIR}) + LIST (APPEND EXCLUDES '${item}') + ENDFOREACH() # 添加 target - add_custom_target(coverage DEPENDS ${ARG_DEPENDS} - COMMAND ${CMAKE_CTEST_COMMAND} - ) + ADD_CUSTOM_TARGET ( + coverage + COMMENT "" + DEPENDS ${ARG_DEPENDS} + COMMAND ${CMAKE_CTEST_COMMAND}) # 在 coverage 执行完毕后生成报告 - add_custom_command(TARGET coverage - COMMENT "Generating coverage report ..." - POST_BUILD - WORKING_DIRECTORY ${ARG_BINARY_DIR} - COMMAND ${CMAKE_COMMAND} -E make_directory ${COVERAGE_OUTPUT_DIR} - COMMAND ${LCOV_EXE} - -c - -o ${COVERAGE_OUTPUT_DIR}/coverage.info - -d ${ARG_BINARY_DIR} - -b ${ARG_SOURCE_DIR} - --no-external - ${EXCLUDES} - --rc branch_coverage=1 - --ignore-errors mismatch - COMMAND ${GENHTML_EXE} - ${COVERAGE_OUTPUT_DIR}/coverage.info - -o ${COVERAGE_OUTPUT_DIR} - --branch-coverage - ) -endfunction() + ADD_CUSTOM_COMMAND ( + TARGET coverage + COMMENT "Generating coverage report ..." + POST_BUILD + WORKING_DIRECTORY ${ARG_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E make_directory ${COVERAGE_OUTPUT_DIR} + COMMAND + ${LCOV_EXE} -c -o ${COVERAGE_OUTPUT_DIR}/coverage.info -d + ${ARG_BINARY_DIR} -b ${ARG_SOURCE_DIR} --no-external ${EXCLUDES} + --rc branch_coverage=1 --ignore-errors mismatch + COMMAND ${GENHTML_EXE} ${COVERAGE_OUTPUT_DIR}/coverage.info -o + ${COVERAGE_OUTPUT_DIR} --branch-coverage) +ENDFUNCTION() -# 添加运行 qemu target -# NAME 生成的 target 前缀 -# TARGET 目标架构 -# WORKING_DIRECTORY 工作目录 -# BOOT boot 文件路径 -# KERNEL kernel 文件路径 +# 添加在 qemu 中运行内核 # DEPENDS 依赖的 target # QEMU_FLAGS qemu 参数 -function(add_run_target) +FUNCTION(add_run_target) # 解析参数 - set(options) - set(one_value_keywords NAME TARGET WORKING_DIRECTORY BOOT KERNEL) - set(multi_value_keywords DEPENDS QEMU_FLAGS) - cmake_parse_arguments( - ARG "${options}" "${one_value_keywords}" "${multi_value_keywords}" ${ARGN} - ) + SET (options) + SET (one_value_keywords NAME TARGET) + SET (multi_value_keywords DEPENDS QEMU_BOOT_FLAGS) + CMAKE_PARSE_ARGUMENTS (ARG "${options}" "${one_value_keywords}" + "${multi_value_keywords}" ${ARGN}) - list(APPEND commands - COMMAND ${CMAKE_COMMAND} -E copy ${ARG_KERNEL} image/ + # 获取目标文件信息 + ADD_CUSTOM_COMMAND ( + TARGET ${ARG_TARGET} + POST_BUILD + COMMENT "Generating binary info for $" + VERBATIM + WORKING_DIRECTORY $ + COMMAND + ${CMAKE_OBJDUMP} -D $ > + $/$.objdump + || true + COMMAND + ${CMAKE_READELF} -a $ > + $/$.readelf + || true + COMMAND + ${CMAKE_NM} -a $ > + $/$.nm + COMMAND + ${CMAKE_OBJCOPY} -O binary $ + $/$.bin ) - if (${ARG_TARGET} STREQUAL "x86_64") - get_filename_component(BOOT_FILE_NAME ${ARG_BOOT} NAME) - configure_file(${CMAKE_SOURCE_DIR}/tools/startup.nsh.in image/startup.nsh @ONLY) - list(APPEND commands - COMMAND ${CMAKE_COMMAND} -E copy ${ARG_BOOT} image/ - ) - elseif (${ARG_TARGET} STREQUAL "riscv64") - get_filename_component(BOOT_FILE_NAME ${ARG_BOOT} NAME) - configure_file(${CMAKE_SOURCE_DIR}/tools/startup.nsh.in image/startup.nsh @ONLY) - list(APPEND commands - COMMAND ${CMAKE_COMMAND} -E copy ${ARG_BOOT} image/ - ) - elseif (${ARG_TARGET} STREQUAL "aarch64") - get_filename_component(BOOT_FILE_NAME ${ARG_BOOT} NAME) - configure_file(${CMAKE_SOURCE_DIR}/tools/startup.nsh.in image/startup.nsh @ONLY) - list(APPEND commands - COMMAND ${CMAKE_COMMAND} -E copy ${ARG_BOOT} image/ - ) - endif () + + # 生成 QEMU DTS 和 DTB + ADD_CUSTOM_COMMAND ( + OUTPUT ${CMAKE_BINARY_DIR}/bin/qemu.dtb ${CMAKE_BINARY_DIR}/bin/qemu.dts + COMMENT "Generating QEMU DTS and DTB ..." + VERBATIM + WORKING_DIRECTORY $ + COMMAND + qemu-system-${CMAKE_SYSTEM_PROCESSOR} ${QEMU_COMMON_FLAG} + ${QEMU_MACHINE_FLAGS} -machine + dumpdtb=$/qemu.dtb + COMMAND dtc -I dtb $/qemu.dtb -O dts -o + $/qemu.dts) + + # 生成 U-BOOT FIT + ADD_CUSTOM_TARGET ( + ${ARG_TARGET}_gen_fit + COMMENT "Generating U-BOOT FIT ..." + VERBATIM + WORKING_DIRECTORY $ + DEPENDS + $<$:$/qemu.dtb> + $<$:$/qemu.dtb> + ${ARG_TARGET} + COMMAND + ${CMAKE_COMMAND} -D + IN_FILE=${CMAKE_SOURCE_DIR}/tools/${CMAKE_SYSTEM_PROCESSOR}_qemu_virt.its.in + -D OUT_FILE=${CMAKE_BINARY_DIR}/bin/boot.its -D + KV_PAIRS=DESC\;$\;KERNEL_PATH\;$\;DTB_PATH\;$/qemu.dtb; + -P ${CMAKE_SOURCE_DIR}/cmake/replace_kv.cmake + COMMAND mkimage -f $/boot.its + $/boot.fit || true + COMMAND + mkimage -T script -d + ${CMAKE_SOURCE_DIR}/tools/${CMAKE_SYSTEM_PROCESSOR}_boot_scr.txt + $/boot.scr.uimg + COMMAND ln -s -f $/* /srv/tftp) # 添加 target - add_custom_target(${ARG_NAME}run DEPENDS ${ARG_DEPENDS} - WORKING_DIRECTORY ${ARG_WORKING_DIRECTORY} - COMMAND ${CMAKE_COMMAND} -E make_directory image/ - ${commands} - COMMAND - qemu-system-${ARG_TARGET} - ${ARG_QEMU_FLAGS} - ) - add_custom_target(${ARG_NAME}debug DEPENDS ${ARG_DEPENDS} - WORKING_DIRECTORY ${ARG_WORKING_DIRECTORY} - COMMAND ${CMAKE_COMMAND} -E make_directory image/ - ${commands} - COMMAND - qemu-system-${ARG_TARGET} - ${ARG_QEMU_FLAGS} - # 等待 gdb 连接 - -S - # 使用 1234 端口 - -gdb ${QEMU_GDB_PORT} - ) -endfunction() + ADD_CUSTOM_TARGET ( + ${ARG_NAME}run + COMMENT "Run $ ..." + DEPENDS ${ARG_DEPENDS} ${ARG_TARGET}_gen_fit + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMAND qemu-system-${CMAKE_SYSTEM_PROCESSOR} ${QEMU_COMMON_FLAG} + ${QEMU_MACHINE_FLAGS} ${ARG_QEMU_BOOT_FLAGS}) + ADD_CUSTOM_TARGET ( + ${ARG_NAME}debug + COMMENT "Debug $ ..." + DEPENDS ${ARG_DEPENDS} ${ARG_TARGET}_gen_fit + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMAND + qemu-system-${CMAKE_SYSTEM_PROCESSOR} ${QEMU_COMMON_FLAG} + ${QEMU_MACHINE_FLAGS} ${QEMU_DEBUG_FLAGS} ${ARG_QEMU_BOOT_FLAGS}) +ENDFUNCTION() diff --git a/cmake/project_config.cmake b/cmake/project_config.cmake index 06b845575..2b39cd013 100644 --- a/cmake/project_config.cmake +++ b/cmake/project_config.cmake @@ -1,64 +1,21 @@ - # This file is a part of Simple-XX/SimpleKernel # (https://github.com/Simple-XX/SimpleKernel). # # project_config.cmake for Simple-XX/SimpleKernel. # 配置信息 -# 设置 cmake 目标环境根目录 -# @todo 设置目录 -list(APPEND CMAKE_FIND_ROOT_PATH - /usr/x86_64-linux-gnu - /usr/riscv64-linux-gnu - /usr/aarch64-linux-gnu -) # 在目标环境搜索 program -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # 在目标环境搜索库文件 -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) # 在目标环境搜索头文件 -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - -# 要运行的平台 -list(APPEND VALID_PLATFORM qemu) -if (NOT DEFINED PLATFORM) - set(PLATFORM qemu) -endif () -message(STATUS "PLATFORM is: ${PLATFORM}") -# 如果不合法则报错 -if (NOT PLATFORM IN_LIST VALID_PLATFORM) - message(FATAL_ERROR "PLATFORM must be one of ${VALID_PLATFORM}") -endif () - -# 目标架构 -list(APPEND VALID_CMAKE_SYSTEM_PROCESSOR x86_64 riscv64 aarch64) -# 默认构建 x86_64 -if (NOT DEFINED CMAKE_SYSTEM_PROCESSOR) - set(CMAKE_SYSTEM_PROCESSOR x86_64) -endif () -message(STATUS "CMAKE_SYSTEM_PROCESSOR is: ${CMAKE_SYSTEM_PROCESSOR}") -# 如果不合法则报错 -if (NOT CMAKE_SYSTEM_PROCESSOR IN_LIST VALID_CMAKE_SYSTEM_PROCESSOR) - message(FATAL_ERROR "CMAKE_SYSTEM_PROCESSOR must be one of ${VALID_CMAKE_SYSTEM_PROCESSOR}") -endif () - -message(STATUS "CMAKE_TOOLCHAIN_FILE is: ${CMAKE_TOOLCHAIN_FILE}") -# 编译器只支持 gnu-gcc 或 clang -if (NOT ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) - message(FATAL_ERROR "Only support gnu-gcc/clang") -endif () - -# qemu gdb 调试端口 -if (NOT DEFINED QEMU_GDB_PORT) - set(QEMU_GDB_PORT tcp::1234) -endif () +SET (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -# qemu monitor 参数 -if (NOT DEFINED QEMU_MONITOR_ARG) - set(QEMU_MONITOR_ARG - telnet::2333,server,nowait - ) -endif () +MESSAGE (STATUS "CMAKE_SYSTEM_PROCESSOR is: ${CMAKE_SYSTEM_PROCESSOR}") +MESSAGE (STATUS "CMAKE_TOOLCHAIN_FILE is: ${CMAKE_TOOLCHAIN_FILE}") # 生成项目配置头文件,传递给代码 -configure_file(${CMAKE_SOURCE_DIR}/tools/project_config.h.in ${CMAKE_SOURCE_DIR}/src/project_config.h @ONLY) +CONFIGURE_FILE (${CMAKE_SOURCE_DIR}/tools/project_config.h.in + ${CMAKE_SOURCE_DIR}/src/project_config.h @ONLY) +CONFIGURE_FILE (${CMAKE_SOURCE_DIR}/tools/.pre-commit-config.yaml.in + ${CMAKE_SOURCE_DIR}/.pre-commit-config.yaml @ONLY) diff --git a/cmake/replace_kv.cmake b/cmake/replace_kv.cmake new file mode 100644 index 000000000..c2eae1f6d --- /dev/null +++ b/cmake/replace_kv.cmake @@ -0,0 +1,71 @@ +# This file is a part of Simple-XX/SimpleKernel +# (https://github.com/Simple-XX/SimpleKernel). +# +# replace_kv.cmake for Simple-XX/SimpleKernel. +# 动态替换文件中的键值对 + +# 键值替换函数 +# 参数: +# in_file - 源文件路径 +# out_file - 目标文件路径 +# [PAIRS] - 可变参数键值对列表 (KEY VALUE KEY VALUE...) +FUNCTION(replace_keys) + # 参数校验 + LIST (LENGTH ARGN arg_count) + IF(arg_count LESS 2) + MESSAGE ( + FATAL_ERROR "Usage: replace_keys(in_file out_file [KEY VALUE]...)") + ENDIF() + + # 提取前两个固定参数 + LIST (GET ARGN 0 in_file) + LIST (GET ARGN 1 out_file) + LIST (REMOVE_AT ARGN 0 1) + + # 检查键值对数量 + LIST (LENGTH ARGN pair_count) + MATH (EXPR remainder "${pair_count} % 2") + IF(NOT remainder EQUAL 0) + MESSAGE ( + FATAL_ERROR + "key-value pairs must be in pairs (KEY VALUE KEY VALUE...) ${ARGN}" + ) + ENDIF() + + # 读取源文件 + IF(NOT EXISTS "${in_file}") + MESSAGE (FATAL_ERROR "File not exist: ${in_file}") + ENDIF() + FILE (READ "${in_file}" TEXT) + + # 处理键值替换 + WHILE(ARGN) + LIST (GET ARGN 0 key) + LIST (GET ARGN 1 value) + LIST (REMOVE_AT ARGN 0 1) + + # 安全替换模式 + STRING (REPLACE "@${key}@" "${value}" TEXT "${TEXT}") + MESSAGE (STATUS "Replace KV: @${key}@ -> ${value}") + ENDWHILE() + + # 确保目标目录存在 + GET_FILENAME_COMPONENT (target_dir "${out_file}" DIRECTORY) + FILE (MAKE_DIRECTORY "${target_dir}") + + # 写入目标文件 + FILE (WRITE "${out_file}" "${TEXT}") +ENDFUNCTION() + +# 脚本模式入口 +IF(CMAKE_SCRIPT_MODE_FILE) + IF(NOT DEFINED IN_FILE + OR NOT DEFINED OUT_FILE + OR NOT DEFINED KV_PAIRS) + MESSAGE ( + FATAL_ERROR + "Usage: cmake -D IN_FILE= -D OUT_FILE= -D KV_PAIRS=\"KEY1=VAL1;KEY2=VAL2\" -P replace_kv.cmake" + ) + ENDIF() + REPLACE_KEYS (${IN_FILE} ${OUT_FILE} ${KV_PAIRS}) +ENDIF() diff --git a/doc/docker.md b/doc/docker.md index 06c36410e..700bd816c 100644 --- a/doc/docker.md +++ b/doc/docker.md @@ -6,7 +6,7 @@ ```shell cd SimpleKernel docker pull ptrnull233/simple_kernel:latest -docker run --name SimpleKernel-container -itd -p 233:22 -v ./:/root/SimpleKernel ptrnull233/simple_kernel:latest +docker run --name SimpleKernel-container -itd -p 233:22 -v ./:/root/SimpleKernel -v ~/.ssh:/root/.ssh -v ~/.gitconfig:/root/.gitconfig ptrnull233/simple_kernel:latest docker exec -it SimpleKernel-container /bin/zsh ``` diff --git a/doc/git_commit.md b/doc/git_commit.md new file mode 100644 index 000000000..40b3df84e --- /dev/null +++ b/doc/git_commit.md @@ -0,0 +1,60 @@ +# Git Commit 规范 + +Based on https://zhuanlan.zhihu.com/p/182553920 + +- 格式 + +``` +(): +``` + +- type(必须) + + 用于说明 git commit 的类别,只允许使用下面的标识 + + - feat: 新功能(feature) + + - fix: 修复 bug + + - bug: 发现 bug,但没有修复 + + - docs: 文档(documentation) + + - style: 格式(不影响代码运行的变动) + + - refactor: 重构(即不是新增功能,也不是修改 bug 的代码变动) + + - perf: 优化相关,比如提升性能、体验 + + - test: 增加测试 + + - build: 构建过程或辅助工具的变动 + + - revert: 回滚到上一个版本 + + - merge: 代码合并 + + - sync: 同步主线或分支 + + - comment: 修改注释 + +- scope(可选) + scope 用于说明 commit 影响的范围,视项目不同而不同。 + + 例如在 SimpleKernel,可以是 PMM,VMM,include 等。多个 scope 使用英文逗号隔开。如果 + + 你的修改影响了很多 scope,你可以使用 * 代替,但为了保证原子性,不建议一次修改多个 scope。 + +- subject(必须) + + subject 是 commit 目的的简短描述,不超过50个字符。 + + 结尾不加句号或其他标点符号。 + + +根据以上规范 git commit message 将是如下的格式: + +``` +fix(DAO): 用户查询缺少username属性 +feat(Controller): 用户查询接口开发 +``` diff --git a/docker.sh b/docker.sh deleted file mode 100755 index 9085fe1ab..000000000 --- a/docker.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -# This file is a part of Simple-XX/SimpleKernel -# (https://github.com/Simple-XX/SimpleKernel). -# -# docker.sh for Simple-XX/SimpleKernel. -# 运行预制了工具链的 docker - -# shell 执行出错时终止运行 -set -e -# 输出实际执行内容 -set -x - -docker pull ptrnull233/simple_kernel:latest -docker run --name SimpleKernel-container -itd -p 233:22 -v ./:/root/SimpleKernel -v ~/.ssh:/root/.ssh -v ~/.gitconfig:/root/.gitconfig ptrnull233/simple_kernel:latest -docker exec -it SimpleKernel-container /bin/zsh diff --git a/run.sh b/run.sh deleted file mode 100755 index 81a5d8eac..000000000 --- a/run.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -# This file is a part of Simple-XX/SimpleKernel -# (https://github.com/Simple-XX/SimpleKernel). -# -# run.sh for Simple-XX/SimpleKernel. -# 在虚拟机中运行内核 - -# shell 执行出错时终止运行 -set -e -# 输出实际执行内容 -#set -x - -# CMAKE_SYSTEM_PROCESSOR=x86_64 -CMAKE_SYSTEM_PROCESSOR=riscv64 -# CMAKE_SYSTEM_PROCESSOR=aarch64 - -# 删除旧文件 -# rm -rf build_${CMAKE_SYSTEM_PROCESSOR} -# 生成 -cmake --preset build_${CMAKE_SYSTEM_PROCESSOR} -# 编译并运行 -cmake --build build_${CMAKE_SYSTEM_PROCESSOR} --target run_run diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9c472d28c..48b83d43b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,8 +1,66 @@ - # This file is a part of Simple-XX/SimpleKernel # (https://github.com/Simple-XX/SimpleKernel). # # CMakeLists.txt for Simple-XX/SimpleKernel. -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/boot) -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/kernel) +# 设置项目名与版本 +PROJECT (kernel VERSION 0.0.1) + +ENABLE_LANGUAGE (ASM) +ENABLE_LANGUAGE (C) +ENABLE_LANGUAGE (CXX) + +ADD_SUBDIRECTORY (libc) +ADD_SUBDIRECTORY (libcxx) +ADD_SUBDIRECTORY (arch) +ADD_SUBDIRECTORY (driver) + +ADD_EXECUTABLE (${PROJECT_NAME} main.cpp) + +# 添加头文件 +TARGET_INCLUDE_DIRECTORIES (${PROJECT_NAME} PRIVATE ./ include) + +# 添加要链接的库 +TARGET_LINK_LIBRARIES (${PROJECT_NAME} PRIVATE kernel_link_libraries libc + libcxx arch driver) + +SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES OUTPUT_NAME + ${KERNEL_ELF_OUTPUT_NAME}) + +# qemu 参数设置 +LIST (APPEND QEMU_BOOT_FLAGS "") +# 目标平台参数 +IF(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + LIST (APPEND QEMU_BOOT_FLAGS -drive + file=fat:rw:${CMAKE_BINARY_DIR}/bin,format=raw,media=disk -bios + ${u-boot_BINARY_DIR}/u-boot.rom) +ELSEIF(CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") + LIST (APPEND QEMU_BOOT_FLAGS -bios ${u-boot_BINARY_DIR}/spl/u-boot-spl.bin + -device loader,file=${u-boot_BINARY_DIR}/u-boot.itb,addr=0x80200000) +ELSEIF(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") + LIST ( + APPEND + QEMU_BOOT_FLAGS + -drive + file=fat:rw:${CMAKE_BINARY_DIR}/bin,format=raw,media=disk + -serial + ${QEMU_NORMAL_WORLD_DEV_PATH} + -serial + ${QEMU_SECURE_WORLD_DEV_PATH} + -bios + ${arm-trusted-firmware_BINARY_DIR}/flash.bin + -kernel + $) +ENDIF() + +# 添加 run 和 debug target +ADD_RUN_TARGET ( + TARGET + ${PROJECT_NAME} + DEPENDS + u-boot + $<$:opensbi> + $<$:optee_os> + $<$:arm-trusted-firmware> + QEMU_BOOT_FLAGS + ${QEMU_BOOT_FLAGS}) diff --git a/src/kernel/arch/CMakeLists.txt b/src/arch/CMakeLists.txt similarity index 67% rename from src/kernel/arch/CMakeLists.txt rename to src/arch/CMakeLists.txt index f1c93ebaa..d17b9e479 100644 --- a/src/kernel/arch/CMakeLists.txt +++ b/src/arch/CMakeLists.txt @@ -1,21 +1,21 @@ - # This file is a part of Simple-XX/SimpleKernel # (https://github.com/Simple-XX/SimpleKernel). # # CMakeLists.txt for Simple-XX/SimpleKernel. -add_library(arch INTERFACE) +ADD_LIBRARY (arch INTERFACE) -target_include_directories(arch INTERFACE - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_SYSTEM_PROCESSOR}/include -) +TARGET_INCLUDE_DIRECTORIES ( + arch + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_SYSTEM_PROCESSOR}/include) -target_sources(arch INTERFACE +TARGET_SOURCES ( + arch + INTERFACE $<$: ${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_SYSTEM_PROCESSOR}/macro.S - ${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_SYSTEM_PROCESSOR}/boot.S > + ${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_SYSTEM_PROCESSOR}/boot.S ${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_SYSTEM_PROCESSOR}/arch_main.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_SYSTEM_PROCESSOR}/backtrace.cpp -) + ${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_SYSTEM_PROCESSOR}/backtrace.cpp) diff --git a/src/kernel/arch/README.md b/src/arch/README.md similarity index 96% rename from src/kernel/arch/README.md rename to src/arch/README.md index a277ce464..0a72fe18c 100644 --- a/src/kernel/arch/README.md +++ b/src/arch/README.md @@ -62,8 +62,8 @@ arch 目录下放置了与架构强相关的内容 * */ -#ifndef SIMPLEKERNEL_SRC_KERNEL_ARCH_RISCV64_INCLUDE_CPU_HPP_ -#define SIMPLEKERNEL_SRC_KERNEL_ARCH_RISCV64_INCLUDE_CPU_HPP_ +#ifndef SIMPLEKERNEL_SRC_ARCH_RISCV64_INCLUDE_CPU_HPP_ +#define SIMPLEKERNEL_SRC_ARCH_RISCV64_INCLUDE_CPU_HPP_ #include #include @@ -207,7 +207,6 @@ struct AllXreg { }; // namespace cpu -#endif // SIMPLEKERNEL_SRC_KERNEL_ARCH_RISCV64_INCLUDE_CPU_HPP_ +#endif // SIMPLEKERNEL_SRC_ARCH_RISCV64_INCLUDE_CPU_HPP_ ``` - diff --git a/src/arch/aarch64/arch_main.cpp b/src/arch/aarch64/arch_main.cpp new file mode 100644 index 000000000..52625133d --- /dev/null +++ b/src/arch/aarch64/arch_main.cpp @@ -0,0 +1,115 @@ + +/** + * @file arch_main.cpp + * @brief arch_main cpp + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-07-15 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-07-15Zone.N (Zone.Niuzh@hotmail.com)创建文件 + *
+ */ + +#include + +#include "arch.h" +#include "basic_info.hpp" +#include "kernel_elf.hpp" +#include "kernel_fdt.hpp" +#include "per_cpu.hpp" +#include "pl011.h" +#include "sk_cstdio" +#include "sk_libc.h" + +// printf_bare_metal 基本输出实现 +namespace { +Pl011 *pl011 = nullptr; +} +extern "C" void putchar_(char character) { + if (pl011) { + pl011->PutChar(character); + } +} + +extern "C" void *sizeof_dtb[]; + +BasicInfo::BasicInfo(int argc, const char **argv) { + (void)argc; + (void)argv; + + auto [memory_base, memory_size] = + Singleton::GetInstance().GetMemory(); + physical_memory_addr = memory_base; + physical_memory_size = memory_size; + + kernel_addr = reinterpret_cast(__executable_start); + kernel_size = reinterpret_cast(end) - + reinterpret_cast(__executable_start); + elf_addr = kernel_addr; + elf_size = kernel_size; + + fdt_addr = strtoull(argv[2], nullptr, 16); + + core_count = Singleton::GetInstance().GetCoreCount(); +} + +void ArchInit(int argc, const char **argv) { + // 初始化 FPU + cpu_io::SetupFpu(); + + Singleton::GetInstance() = + KernelFdt(strtoull(argv[2], nullptr, 16)); + + auto [serial_base, serial_size] = + Singleton::GetInstance().GetSerial(); + + static auto uart = Pl011(serial_base); + pl011 = &uart; + + Singleton::GetInstance() = BasicInfo(argc, argv); + + // 解析内核 elf 信息 + Singleton::GetInstance() = + KernelElf(Singleton::GetInstance().elf_addr); + + sk_std::cout << Singleton::GetInstance(); + + Singleton::GetInstance().CheckPSCI(); + + klog::Info("serial_base: 0x%lx\n", serial_base); + + uart.PutChar('H'); + uart.PutChar('e'); + uart.PutChar('l'); + uart.PutChar('l'); + uart.PutChar('o'); + uart.PutChar(' '); + uart.PutChar('u'); + uart.PutChar('a'); + uart.PutChar('r'); + uart.PutChar('t'); + uart.PutChar('!'); + uart.PutChar('\n'); + + klog::Info("Hello aarch64 ArchInit\n"); + + // 唤醒其余 core + for (size_t i = 0; i < Singleton::GetInstance().core_count; i++) { + auto ret = cpu_io::psci::CpuOn(i, reinterpret_cast(_boot), 0); + if ((ret != cpu_io::psci::SUCCESS) && (ret != cpu_io::psci::ALREADY_ON)) { + klog::Warn("hart %d start failed: %d\n", i, ret); + } + } +} + +void ArchInitSMP(int, const char **) { + // 初始化 FPU + cpu_io::SetupFpu(); + + // caller(); + putchar_('!'); +} diff --git a/src/arch/aarch64/backtrace.cpp b/src/arch/aarch64/backtrace.cpp new file mode 100644 index 000000000..90320498a --- /dev/null +++ b/src/arch/aarch64/backtrace.cpp @@ -0,0 +1,64 @@ +/** + * @file backtrace.cpp + * @brief 栈回溯实现 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-07-15 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-07-15Zone.N (Zone.Niuzh@hotmail.com)创建文件 + *
+ */ + +#include +#include + +#include +#include +#include + +#include "arch.h" +#include "basic_info.hpp" +#include "kernel_elf.hpp" +#include "kernel_log.hpp" +#include "singleton.hpp" + +__always_inline auto backtrace(std::array &buffer) + -> int { + auto *x29 = reinterpret_cast(cpu_io::X29::Read()); + size_t count = 0; + while ((x29 != nullptr) && (x29[0] != 0U) && + x29[0] >= reinterpret_cast(__executable_start) && + x29[0] <= reinterpret_cast(__etext) && + count < buffer.max_size()) { + auto lr = x29[1]; + x29 = reinterpret_cast(x29[0]); + buffer[count++] = lr; + } + + return int(count); +} + +void DumpStack() { + std::array buffer{}; + + // 获取调用栈中的地址 + auto num_frames = backtrace(buffer); + + // 打印函数名 + for (auto current_frame_idx = 0; current_frame_idx < num_frames; + current_frame_idx++) { + for (auto symtab : Singleton::GetInstance().symtab_) { + if ((ELF64_ST_TYPE(symtab.st_info) == STT_FUNC) && + (buffer[current_frame_idx] >= symtab.st_value) && + (buffer[current_frame_idx] <= symtab.st_value + symtab.st_size)) { + klog::Err("[%s] 0x%p\n", + Singleton::GetInstance().strtab_ + symtab.st_name, + buffer[current_frame_idx]); + } + } + } +} diff --git a/src/arch/aarch64/boot.S b/src/arch/aarch64/boot.S new file mode 100644 index 000000000..21a7b7e9c --- /dev/null +++ b/src/arch/aarch64/boot.S @@ -0,0 +1,51 @@ + +/** + * @file boot.S + * @brief boot S + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2024-12-30 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2024-12-30Zone.N (Zone.Niuzh@hotmail.com)创建文件 + *
+ */ + +// clang-format off + +.section .text.boot +.global _boot +.type _boot, @function +.extern _start +_boot: + // 获取启动核 ID + mrs x10, mpidr_el1 + and x10, x10, #0xFF + + // 按照每个 core 设置栈地址 + add x10, x10, #1 + lsl x10, x10, #12 + ldr x11, =stack_top + add x11, x11, x10 + mov sp, x11 + + // 保存传递的参数(假设传递的参数在 x0 和 x1 中) + // 开辟栈空间 + stp x0, x1, [sp, #-16]! + + bl _start + b . + +// 声明所属段 +.section .bss.boot +// 16 字节对齐 +.align 16 +.global stack_top +stack_top: + // 跳过 16KB + .space 4096 * 4 + +// clang-format on diff --git a/src/kernel/arch/aarch64/link.ld b/src/arch/aarch64/link.ld similarity index 98% rename from src/kernel/arch/aarch64/link.ld rename to src/arch/aarch64/link.ld index af1dc5ffe..8bd144629 100644 --- a/src/kernel/arch/aarch64/link.ld +++ b/src/arch/aarch64/link.ld @@ -15,12 +15,13 @@ OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64", "elf64-littleaarch64") OUTPUT_ARCH(aarch64) -ENTRY(_start) +ENTRY(_boot) SECTIONS { /* Read-only sections, merged into text segment: */ - PROVIDE (__executable_start = SEGMENT_START("text-segment", 0xFFFF800000000000)); - . = SEGMENT_START("text-segment", 0xFFFF800000000000) + SIZEOF_HEADERS; + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x40100000)); + . = SEGMENT_START("text-segment", 0x40100000) + SIZEOF_HEADERS; + .boot : ALIGN(0x1000) { *(.text.boot) *(.data.boot) *(.bss.boot) } .interp : { *(.interp) } .note.gnu.build-id : { *(.note.gnu.build-id) } .hash : { *(.hash) } diff --git a/src/kernel/arch/arch.h b/src/arch/arch.h similarity index 72% rename from src/kernel/arch/arch.h rename to src/arch/arch.h index 93e0e329c..091859fe8 100644 --- a/src/kernel/arch/arch.h +++ b/src/arch/arch.h @@ -14,8 +14,10 @@ * */ -#ifndef SIMPLEKERNEL_SRC_KERNEL_ARCH_ARCH_H_ -#define SIMPLEKERNEL_SRC_KERNEL_ARCH_ARCH_H_ +#ifndef SIMPLEKERNEL_SRC_ARCH_ARCH_H_ +#define SIMPLEKERNEL_SRC_ARCH_ARCH_H_ + +#include #include #include @@ -25,10 +27,11 @@ * @param argc 在不同体系结构有不同含义,同 _start * @param argv 在不同体系结构有不同含义,同 _start */ -uint32_t ArchInit(uint32_t argc, uint8_t *argv); +void ArchInit(int argc, const char **argv); +void ArchInitSMP(int argc, const char **argv); /// 最多回溯 128 层调用栈 -static constexpr const size_t kMaxFramesCount = 128; +static constexpr const size_t kMaxFrameCount = 128; /** * 获取调用栈 @@ -36,11 +39,11 @@ static constexpr const size_t kMaxFramesCount = 128; * @param size 数组的大小,即调用栈中最多存储多少个返回地址 * @return int 成功时返回实际写入数组中的地址数量,失败时返回 -1 */ -__always_inline int backtrace(void **buffer, int size); +__always_inline auto backtrace(void **buffer, int size) -> int; /** * 打印调用栈 */ void DumpStack(); -#endif /* SIMPLEKERNEL_SRC_KERNEL_ARCH_ARCH_H_ */ +#endif /* SIMPLEKERNEL_SRC_ARCH_ARCH_H_ */ diff --git a/src/kernel/arch/riscv64/arch_main.cpp b/src/arch/riscv64/arch_main.cpp similarity index 51% rename from src/kernel/arch/riscv64/arch_main.cpp rename to src/arch/riscv64/arch_main.cpp index 57f692e02..cd49cb562 100644 --- a/src/kernel/arch/riscv64/arch_main.cpp +++ b/src/arch/riscv64/arch_main.cpp @@ -13,54 +13,58 @@ * */ +#include #include #include "basic_info.hpp" -#include "cpu/cpu.hpp" +#include "config.h" #include "kernel_elf.hpp" #include "kernel_fdt.hpp" +#include "kernel_log.hpp" #include "ns16550a.h" +#include "per_cpu.hpp" #include "sk_cstdio" #include "sk_libc.h" // printf_bare_metal 基本输出实现 -extern "C" void _putchar(char character) { +extern "C" void putchar_(char character) { sbi_debug_console_write_byte(character); } -// 引用链接脚本中的变量 -/// @see http://wiki.osdev.org/Using_Linker_Script_Values -/// 内核开始 -extern "C" void *__executable_start[]; -/// 内核结束 -extern "C" void *end[]; -BasicInfo::BasicInfo(uint32_t argc, uint8_t *argv) { +BasicInfo::BasicInfo(int argc, const char **argv) { (void)argc; (void)argv; - auto [memory_base, memory_size] = kKernelFdt.GetInstance().GetMemory(); + auto [memory_base, memory_size] = + Singleton::GetInstance().GetMemory(); physical_memory_addr = memory_base; physical_memory_size = memory_size; kernel_addr = reinterpret_cast(__executable_start); kernel_size = reinterpret_cast(end) - reinterpret_cast(__executable_start); - elf_addr = 0; - elf_size = 0; + elf_addr = kernel_addr; + /// @todo 这个大小会不会丢掉 elf 信息? + elf_size = kernel_size; fdt_addr = reinterpret_cast(argv); + + core_count = Singleton::GetInstance().GetCoreCount(); } -uint32_t ArchInit(uint32_t argc, uint8_t *argv) { - printf("boot hart id: %d\n", argc); - printf("dtb info addr: %p\n", argv); +void ArchInit(int argc, const char **argv) { + Singleton::GetInstance() = + KernelFdt(reinterpret_cast(argv)); - kKernelFdt.GetInstance() = KernelFdt((uint64_t)argv); + Singleton::GetInstance() = BasicInfo(argc, argv); + sk_std::cout << Singleton::GetInstance(); - kBasicInfo.GetInstance() = BasicInfo(argc, argv); - sk_std::cout << kBasicInfo.GetInstance(); + // 解析内核 elf 信息 + Singleton::GetInstance() = + KernelElf(Singleton::GetInstance().elf_addr); - auto [serial_base, serial_size] = kKernelFdt.GetInstance().GetSerial(); + auto [serial_base, serial_size] = + Singleton::GetInstance().GetSerial(); auto uart = Ns16550a(serial_base); uart.PutChar('H'); uart.PutChar('e'); @@ -75,10 +79,16 @@ uint32_t ArchInit(uint32_t argc, uint8_t *argv) { uart.PutChar('!'); uart.PutChar('\n'); - // 解析内核 elf 信息 - kKernelElf.GetInstance() = KernelElf(); - klog::Info("Hello riscv64 ArchInit\n"); - return 0; + // 唤醒其余 core + for (size_t i = 0; i < Singleton::GetInstance().core_count; i++) { + auto ret = sbi_hart_start(i, reinterpret_cast(_boot), 0); + if ((ret.error != SBI_SUCCESS) && + (ret.error != SBI_ERR_ALREADY_AVAILABLE)) { + klog::Warn("hart %d start failed: %d\n", i, ret.error); + } + } } + +void ArchInitSMP(int, const char **) {} diff --git a/src/arch/riscv64/backtrace.cpp b/src/arch/riscv64/backtrace.cpp new file mode 100644 index 000000000..862fee4d8 --- /dev/null +++ b/src/arch/riscv64/backtrace.cpp @@ -0,0 +1,64 @@ + +/** + * @file backtrace.cpp + * @brief 栈回溯实现 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-07-15 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-07-15Zone.N (Zone.Niuzh@hotmail.com)创建文件 + *
+ */ + +#include +#include + +#include +#include +#include + +#include "arch.h" +#include "basic_info.hpp" +#include "kernel_elf.hpp" +#include "kernel_log.hpp" +#include "singleton.hpp" + +__always_inline auto backtrace(std::array &buffer) + -> int { + auto *fp = reinterpret_cast(cpu_io::Fp::Read()); + size_t count = 0; + while ((fp != nullptr) && (*fp != 0U) && + *(fp - 2) >= reinterpret_cast(__executable_start) && + *(fp - 2) <= reinterpret_cast(__etext) && + count < buffer.max_size()) { + auto ra = *(fp - 1); + fp = reinterpret_cast(*(fp - 2)); + buffer[count++] = ra; + } + return int(count); +} + +void DumpStack() { + std::array buffer{}; + + // 获取调用栈中的地址 + auto num_frames = backtrace(buffer); + + // 打印函数名 + for (auto current_frame_idx = 0; current_frame_idx < num_frames; + current_frame_idx++) { + for (auto symtab : Singleton::GetInstance().symtab_) { + if ((ELF64_ST_TYPE(symtab.st_info) == STT_FUNC) && + (buffer[current_frame_idx] >= symtab.st_value) && + (buffer[current_frame_idx] <= symtab.st_value + symtab.st_size)) { + klog::Err("[%s] 0x%p\n", + Singleton::GetInstance().strtab_ + symtab.st_name, + buffer[current_frame_idx]); + } + } + } +} diff --git a/src/kernel/arch/riscv64/boot.S b/src/arch/riscv64/boot.S similarity index 86% rename from src/kernel/arch/riscv64/boot.S rename to src/arch/riscv64/boot.S index 4b343e7dd..f4ba8f5a1 100644 --- a/src/kernel/arch/riscv64/boot.S +++ b/src/arch/riscv64/boot.S @@ -26,7 +26,8 @@ .extern __global_pointer$ #endif _boot: - + // Check if dtb address (a1) is zero + beqz a1, 2f #if USE_NO_RELAX == 0 /// @see riscv-abi.pdf#9.1.4 /// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/releases/tag/v1.0 @@ -39,9 +40,14 @@ _boot: .option pop #endif - // 设置栈地址 +2: // 按照每个 core 设置栈地址 + add t0, a0, 1 + slli t0, t0, 12 la sp, stack_top + add sp, sp, t0 + // 将 a0 的值写入 tp + mv tp, a0 // 保存 sbi 传递的参数 // 开辟栈空间 addi sp, sp, -8*2 diff --git a/src/kernel/arch/riscv64/link.ld b/src/arch/riscv64/link.ld similarity index 100% rename from src/kernel/arch/riscv64/link.ld rename to src/arch/riscv64/link.ld diff --git a/src/kernel/arch/riscv64/macro.S b/src/arch/riscv64/macro.S similarity index 100% rename from src/kernel/arch/riscv64/macro.S rename to src/arch/riscv64/macro.S diff --git a/src/kernel/arch/x86_64/arch_main.cpp b/src/arch/x86_64/arch_main.cpp similarity index 58% rename from src/kernel/arch/x86_64/arch_main.cpp rename to src/arch/x86_64/arch_main.cpp index b34c13e66..dfec09e1b 100644 --- a/src/kernel/arch/x86_64/arch_main.cpp +++ b/src/arch/x86_64/arch_main.cpp @@ -14,31 +14,29 @@ * */ -#include +#include + +#include #include "basic_info.hpp" -#include "cpu/cpu.hpp" #include "kernel_elf.hpp" #include "kernel_log.hpp" -#include "sk_cstdio" -#include "sk_cstring" +#include "per_cpu.hpp" +#include "singleton.hpp" +#include "sk_iostream" // printf_bare_metal 基本输出实现 /// @note 这里要注意,保证在 serial 初始化之前不能使用 printf /// 函数,否则会有全局对象依赖问题 -static cpu::Serial kSerial(cpu::kCom1); -extern "C" void _putchar(char character) { kSerial.Write(character); } - -// 引用链接脚本中的变量 -/// @see http://wiki.osdev.org/Using_Linker_Script_Values -/// 内核开始 -extern "C" void *__executable_start[]; -/// 内核结束 -extern "C" void *end[]; -BasicInfo::BasicInfo(uint32_t argc, uint8_t *argv) { +namespace { +cpu_io::Serial kSerial(cpu_io::kCom1); +extern "C" void putchar_(char character) { kSerial.Write(character); } +} // namespace + +BasicInfo::BasicInfo(int argc, const char **argv) { (void)argc; - auto basic_info = *reinterpret_cast(argv); + auto basic_info = *reinterpret_cast(argv); physical_memory_addr = basic_info.physical_memory_addr; physical_memory_size = basic_info.physical_memory_size; @@ -50,22 +48,32 @@ BasicInfo::BasicInfo(uint32_t argc, uint8_t *argv) { elf_size = basic_info.elf_size; fdt_addr = 0; + + /// @todo 获取 core 数量 + core_count = 1; } -uint32_t ArchInit(uint32_t argc, uint8_t *argv) { +auto ArchInit(int argc, const char **argv) -> int { if (argc != 1) { klog::Err("argc != 1 [%d]\n", argc); throw; } - kBasicInfo.GetInstance() = BasicInfo(argc, argv); - sk_std::cout << kBasicInfo.GetInstance(); + Singleton::GetInstance() = BasicInfo(argc, argv); + sk_std::cout << Singleton::GetInstance(); // 解析内核 elf 信息 - kKernelElf.GetInstance() = KernelElf(kBasicInfo.GetInstance().elf_addr, - kBasicInfo.GetInstance().elf_size); + Singleton::GetInstance() = + KernelElf(Singleton::GetInstance().elf_addr, + Singleton::GetInstance().elf_size); klog::Info("Hello x86_64 ArchInit\n"); return 0; } + +auto ArchInitSMP(int argc, const char **argv) -> int { + (void)argc; + (void)argv; + return 0; +} diff --git a/src/arch/x86_64/backtrace.cpp b/src/arch/x86_64/backtrace.cpp new file mode 100644 index 000000000..7bc0e8229 --- /dev/null +++ b/src/arch/x86_64/backtrace.cpp @@ -0,0 +1,61 @@ +/** + * @file backtrace.cpp + * @brief 栈回溯实现 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-07-15 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-07-15Zone.N (Zone.Niuzh@hotmail.com)创建文件 + *
+ */ + +#include +#include + +#include +#include +#include + +#include "arch.h" +#include "kernel_elf.hpp" +#include "kernel_log.hpp" +#include "singleton.hpp" + +auto backtrace(std::array &buffer) -> int { + auto *rbp = reinterpret_cast(cpu_io::Rbp::Read()); + uint64_t *rip = nullptr; + + size_t count = 0; + while ((rbp != nullptr) && (*rbp != 0U) && count < buffer.max_size()) { + rip = rbp + 1; + rbp = reinterpret_cast(*rbp); + buffer[count++] = *rip; + } + + return int(count); +} + +void DumpStack() { + std::array buffer{}; + + // 获取调用栈中的地址 + auto num_frames = backtrace(buffer); + + for (auto current_frame_idx = 0; current_frame_idx < num_frames; + current_frame_idx++) { + // 打印函数名 + for (auto symtab : Singleton::GetInstance().symtab_) { + if ((ELF64_ST_TYPE(symtab.st_info) == STT_FUNC) && + (buffer[current_frame_idx] >= symtab.st_value) && + (buffer[current_frame_idx] <= symtab.st_value + symtab.st_size)) { + klog::Err("[%s] 0x%p\n", + Singleton::GetInstance().strtab_ + symtab.st_name, + buffer[current_frame_idx]); + } + } + } +} diff --git a/src/arch/x86_64/boot.S b/src/arch/x86_64/boot.S new file mode 100644 index 000000000..6d07b153f --- /dev/null +++ b/src/arch/x86_64/boot.S @@ -0,0 +1,42 @@ + +/** + * @file boot.S + * @brief boot S + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-07-15 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-07-15Zone.N (Zone.Niuzh@hotmail.com)创建文件 + *
+ */ + +// clang-format off + +// 声明所属段 +.section .text.boot +.global _boot +.type _boot, @function +.extern _start +_boot: + // 关中断 + cli + + call _start + hlt + ret + +// 声明所属段 +.section .bss.boot +// 16 字节对齐 +.align 16 +.global stack_top +// 栈 +stack_top: + // 跳过 16KB + .space 4096 * 4 + +// clang-format on diff --git a/src/kernel/arch/x86_64/link.ld b/src/arch/x86_64/link.ld similarity index 99% rename from src/kernel/arch/x86_64/link.ld rename to src/arch/x86_64/link.ld index 96d245e7f..65805dfc1 100644 --- a/src/kernel/arch/x86_64/link.ld +++ b/src/arch/x86_64/link.ld @@ -15,11 +15,12 @@ OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") OUTPUT_ARCH(i386:x86-64) -ENTRY(_start) +ENTRY(_boot) SECTIONS { PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; + .boot : ALIGN(0x1000) { *(.text.boot) *(.data.boot) *(.bss.boot) } .interp : ALIGN(0x1000) { *(.interp) } .note.gnu.build-id : ALIGN(0x1000) { *(.note.gnu.build-id) } .hash : ALIGN(0x1000) { *(.hash) } diff --git a/src/boot/CMakeLists.txt b/src/boot/CMakeLists.txt deleted file mode 100644 index 87bd8c9fa..000000000 --- a/src/boot/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ - -# This file is a part of Simple-XX/SimpleKernel -# (https://github.com/Simple-XX/SimpleKernel). -# -# CMakeLists.txt for Simple-XX/SimpleKernel. - -# 设置项目名与版本 -project( - boot - VERSION 0.0.1 -) - -enable_language(CXX) - -add_executable(${PROJECT_NAME} - boot.cpp - load_elf.cpp - out_stream.cpp - memory.cpp -) - -# 添加头文件 -target_include_directories(${PROJECT_NAME} PRIVATE - include - ${CMAKE_SOURCE_DIR}/src -) - -# 添加要链接的库 -target_link_libraries(${PROJECT_NAME} PRIVATE - boot_link_libraries -) - -set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") -set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${BOOT_ELF_OUTPUT_NAME}) - -# 获取目标文件信息 -objdump_readelf_nm(${PROJECT_NAME}) - -# 制作 boot.efi -# 将引导调整为 efi -elf2efi(${PROJECT_NAME} ${BOOT_EFI_OUTPUT_NAME}) diff --git a/src/boot/boot.cpp b/src/boot/boot.cpp deleted file mode 100644 index 8b8a95895..000000000 --- a/src/boot/boot.cpp +++ /dev/null @@ -1,133 +0,0 @@ - -/** - * @file boot.cpp - * @brief boot cpp - * @author Zone.N (Zone.Niuzh@hotmail.com) - * @version 1.0 - * @date 2023-07-15 - * @copyright MIT LICENSE - * https://github.com/Simple-XX/SimpleKernel - * @par change log: - * - *
DateAuthorDescription - *
2023-07-15Zone.N (Zone.Niuzh@hotmail.com)创建文件 - *
- */ - -#include "load_elf.h" -#include "out_stream.hpp" -#include "project_config.h" - -// efi 使用的全局变量 -#if defined(__x86_64__) || defined(__aarch64__) -uintptr_t ImageBase = 0; -#endif - -extern "C" [[maybe_unused]] EFI_STATUS EFIAPI -efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) { - EFI_STATUS status = EFI_SUCCESS; - - InitializeLib(image_handle, system_table); - - // 输出 efi 信息 - EFI_LOADED_IMAGE *loaded_image = nullptr; - /// @bug 在 aarch64 下会出错 - status = LibLocateProtocol(&LoadedImageProtocol, - reinterpret_cast(&loaded_image)); - if (EFI_ERROR(status)) { - debug << L"LibLocateProtocol: " << status << OutStream::endl; - return status; - } - - debug << L"Revision: " << OutStream::hex_X << loaded_image->Revision - << OutStream::endl; - debug << L"ParentHandle: " << OutStream::hex_X - << loaded_image->ParentHandle << OutStream::endl; - debug << L"SystemTable: " << OutStream::hex_X << loaded_image->SystemTable - << OutStream::endl; - debug << L"DeviceHandle: " << OutStream::hex_X - << loaded_image->DeviceHandle << OutStream::endl; - debug << L"FilePath: " << OutStream::hex_X << loaded_image->FilePath - << OutStream::endl; - debug << L"Reserved: " << OutStream::hex_X << loaded_image->Reserved - << OutStream::endl; - debug << L"LoadOptionsSize: " << OutStream::hex_X - << loaded_image->LoadOptionsSize << OutStream::endl; - debug << L"LoadOptions: " << OutStream::hex_X << loaded_image->LoadOptions - << OutStream::endl; - debug << L"ImageBase: " << OutStream::hex_X << loaded_image->ImageBase - << OutStream::endl; - debug << L"ImageSize: " << OutStream::hex_X << loaded_image->ImageSize - << OutStream::endl; - debug << L"ImageCodeType: " << OutStream::hex_X - << loaded_image->ImageCodeType << OutStream::endl; - debug << L"ImageDataType: " << OutStream::hex_X - << loaded_image->ImageDataType << OutStream::endl; - debug << L"Unload: " << OutStream::hex_X << loaded_image->Unload - << OutStream::endl; - - // 初始化 Memory - auto memory = Memory(); - // 加载内核 - auto elf = Elf(KERNEL_NAME); - auto [kernel_addr, elf_info] = elf.Load(); - if (kernel_addr == 0) { - debug << L"Failed to load kernel" << OutStream::endl; - return EFI_LOAD_ERROR; - } - - // 输出内存映射 Memory - memory.PrintInfo(); - - debug << L"Set Kernel Entry Point to: [" << OutStream::hex_X << kernel_addr - << L"]." << OutStream::endl; - debug << L"Elf addr: [" << OutStream::hex_X << elf_info.first << L"]." - << OutStream::endl; - debug << L"Elf size: [" << OutStream::hex_X << elf_info.second << L"]." - << OutStream::endl; - // 退出 boot service - uint64_t desc_count = 0; - EFI_MEMORY_DESCRIPTOR *memory_map = nullptr; - uint64_t map_key = 0; - uint64_t desc_size = 0; - uint32_t desc_version = 0; - memory_map = LibMemoryMap(&desc_count, &map_key, &desc_size, &desc_version); - if (memory_map == nullptr) { - debug << L"LibMemoryMap failed: memory_map == nullptr" << OutStream::endl; - } - - // 退出后不能使用输出相关方法 - status = uefi_call_wrapper(gBS->ExitBootServices, 2, image_handle, map_key); - if (EFI_ERROR(status)) { - debug << L"ExitBootServices failed, Memory Map has Changed " << status - << OutStream::endl; - return status; - } - - /// 基础信息 - /// @note 结构与 basic_info.hpp 同步 - struct { - uint64_t physical_memory_addr; - size_t physical_memory_size; - uint64_t kernel_addr; - size_t kernel_size; - uint64_t elf_addr; - size_t elf_size; - } basic_info; - std::fill_n(reinterpret_cast(&basic_info), sizeof(basic_info), 0); - - // 获取物理内存信息 - auto [physical_memory_addr, physical_memory_size] = memory.GetMemory(); - - // 填充信息 - basic_info.physical_memory_addr = physical_memory_addr; - basic_info.physical_memory_size = physical_memory_size; - basic_info.elf_addr = elf_info.first; - basic_info.elf_size = elf_info.second; - - auto kernel_entry = (void (*)(uint32_t, uint8_t *))kernel_addr; - kernel_entry(1, reinterpret_cast(&basic_info)); - - // 不会执行到这里 - return EFI_SUCCESS; -} diff --git a/src/boot/include/boot.h b/src/boot/include/boot.h deleted file mode 100644 index d66e9f9bb..000000000 --- a/src/boot/include/boot.h +++ /dev/null @@ -1,30 +0,0 @@ - -/** - * @file boot.h - * @brief boot 头文件 - * @author Zone.N (Zone.Niuzh@hotmail.com) - * @version 1.0 - * @date 2023-07-15 - * @copyright MIT LICENSE - * https://github.com/Simple-XX/SimpleKernel - * @par change log: - * - *
DateAuthorDescription - *
2023-07-15Zone.N (Zone.Niuzh@hotmail.com)创建文件 - *
- */ - -#ifndef SIMPLEKERNEL_SRC_BOOT_INCLUDE_BOOT_H_ -#define SIMPLEKERNEL_SRC_BOOT_INCLUDE_BOOT_H_ - -#include - -/** - * @brief 入口 - * @param argc 参数个数 - * @param argv 参数列表 - * @return int 正常返回 0 - */ -int main(int argc, char **argv); - -#endif /* SIMPLEKERNEL_SRC_BOOT_INCLUDE_BOOT_H_ */ diff --git a/src/boot/include/load_elf.h b/src/boot/include/load_elf.h deleted file mode 100644 index fcf1998ae..000000000 --- a/src/boot/include/load_elf.h +++ /dev/null @@ -1,198 +0,0 @@ - -/** - * @file load_elf.h - * @brief load_elf h - * @author Zone.N (Zone.Niuzh@hotmail.com) - * @version 1.0 - * @date 2023-07-15 - * @copyright MIT LICENSE - * https://github.com/Simple-XX/SimpleKernel - * @par change log: - * - *
DateAuthorDescription - *
2023-07-15Zone.N (Zone.Niuzh@hotmail.com)创建文件 - *
- */ - -#ifndef SIMPLEKERNEL_SRC_BOOT_INCLUDE_LOAD_ELF_H_ -#define SIMPLEKERNEL_SRC_BOOT_INCLUDE_LOAD_ELF_H_ - -#include - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#include "efi.h" -#include "efilib.h" - -#ifdef __cplusplus -} -#endif - -/** - * 内存相关 - */ -class Memory { - public: - /** - * 构造函数 - */ - Memory(); - - /** - * 析构函数 - */ - ~Memory() = default; - - /// @name 不使用的构造函数 - /// @{ - Memory(const Memory &) = delete; - Memory(Memory &&) = delete; - auto operator=(const Memory &) -> Memory & = delete; - auto operator=(Memory &&) -> Memory & = delete; - /// @} - - /** - * 获取内存信息,只保留地址与长度 - * @return std::pair 内存地址与长度 - */ - std::pair GetMemory() const; - - /** - * 输出内存映射信息 - */ - void PrintInfo(); - - private: - /// @name 内存映射信息 - /// @{ - uint64_t desc_count_ = 0; - EFI_MEMORY_DESCRIPTOR *memory_map_ = nullptr; - uint64_t map_key_ = 0; - uint64_t desc_size_ = 0; - uint32_t desc_version_ = 0; - /// @} - - /** - * 更新内存映射信息 - * @return 失败返回 false - */ - bool FlushDesc(); -}; - -/** - * elf 文件相关 - */ -class Elf { - public: - /** - * 构造函数 - * @param kernel_image_filename 要加载的内核文件 - */ - explicit Elf(wchar_t *kernel_image_filename); - - /** - * 析构函数 - */ - ~Elf(); - - /// @name 不使用的构造函数 - /// @{ - Elf(const Elf &) = delete; - Elf(Elf &&) = delete; - auto operator=(const Elf &) -> Elf & = delete; - auto operator=(Elf &&) -> Elf & = delete; - /// @} - - /** - * 将 elf 文件加载进内存,返回程序入口和 elf 文件地址 - * @return first 成功返回内核入口地址,失败返回 0 - * @return second elf 文件在内存中的位置与大小 - */ - [[nodiscard]] auto Load() const - -> std::pair>; - - private: - /// @name elf 文件相关 - /// @{ - EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *file_system_protocol_ = nullptr; - EFI_FILE *root_file_system_ = nullptr; - /// elf 文件指针 - EFI_FILE *elf_ = nullptr; - /// elf 文件大小 - size_t elf_file_size_ = 0; - /// elf 文件内容缓冲区 - void *elf_file_buffer_ = nullptr; - /// elf 文件访问 - std::span file_ = {}; - Elf64_Ehdr ehdr_ = {}; - std::span phdr_ = {}; - std::span shdr_ = {}; - /// section 缓冲区大小 - static constexpr const size_t kSectionBufferSize = 1024; - /// shstrtab 缓冲 - std::array shstrtab_buf_ = {}; - /// @} - - /** - * 获取文件大小 - * @return 文件大小 - */ - [[nodiscard]] auto GetFileSize() const -> size_t; - - /** - * 检查 elf 标识 - * @return 失败返回 false - */ - [[nodiscard]] auto CheckElfIdentity() const -> bool; - - /** - * 读取 elf 文件的 ehdr - */ - void GetEhdr(); - - /** - * 输出 elf ehdr - */ - void PrintEhdr() const; - - /** - * 读取 elf 文件的 phdr - */ - void GetPhdr(); - - /** - * 输出 phdr - */ - void PrintPhdr() const; - - /** - * 读取 elf 文件的 shdr - */ - void GetShdr(); - - /** - * 输出 shdr - */ - void PrintShdr() const; - - /** - * 将 elf 段加载到内存 - * @param phdr 要加载的程序段 phdr - */ - [[nodiscard]] bool LoadSections(const Elf64_Phdr &phdr) const; - - /** - * 加载程序段 - * @return 失败返回 false - */ - [[nodiscard]] bool LoadProgramSections() const; -}; - -#endif /* SIMPLEKERNEL_SRC_BOOT_INCLUDE_LOAD_ELF_H_ */ diff --git a/src/boot/include/out_stream.hpp b/src/boot/include/out_stream.hpp deleted file mode 100644 index 710b4ad02..000000000 --- a/src/boot/include/out_stream.hpp +++ /dev/null @@ -1,209 +0,0 @@ - -/** - * @file ostream.hpp - * @brief ostream hpp - * @author Zone.N (Zone.Niuzh@hotmail.com) - * @version 1.0 - * @date 2023-07-15 - * @copyright MIT LICENSE - * https://github.com/Simple-XX/SimpleKernel - * @par change log: - * - *
DateAuthorDescription - *
2023-07-15Zone.N (Zone.Niuzh@hotmail.com)创建文件 - *
- */ - -#ifndef SIMPLEKERNEL_SRC_BOOT_INCLUDE_OUT_STREAM_HPP_ -#define SIMPLEKERNEL_SRC_BOOT_INCLUDE_OUT_STREAM_HPP_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#include "efi.h" -#include "efilib.h" - -#ifdef __cplusplus -} -#endif - -/** - * 等待输入 - * @param key 输入的按键 - * @return efi 错误码 - */ -[[maybe_unused]] auto WaitForInput(EFI_INPUT_KEY *key) -> EFI_STATUS; - -/** - * 输出流 - */ -class OutStream { - public: - /** - * 使用默认构造 - */ - OutStream() = default; - - /** - * 使用默认析构 - */ - ~OutStream() = default; - - /// @name 不使用的构造函数 - /// @{ - OutStream(const OutStream &) = delete; - OutStream(OutStream &&) = delete; - auto operator=(const OutStream &) -> OutStream & = delete; - auto operator=(OutStream &&) -> OutStream & = delete; - /// @} - - /** - * 输出类型 - * @tparam T 模板类型 - * @param val 数据 - * @return 输出流 - */ - template - inline auto operator<<(T val) -> OutStream &; - - /** - * ‘<<’ 操作符重载 - * @param ostream 输出流 - * @return 输出流 - */ - auto operator<<(OutStream &(*ostream)(OutStream &)) -> OutStream &; - - /** - * 输出 16 进制 - * @param ostream 输出流 - * @return 输出流 - */ - static auto hex_x(OutStream &ostream) -> OutStream &; - - /** - * 输出 16 进制 - * @param ostream 输出流 - * @return 输出流 - */ - static auto hex_X(OutStream &ostream) -> OutStream &; - - /** - * 输出换行 - * @param ostream - * @return 输出流 - */ - static auto endl(OutStream &ostream) -> OutStream &; - - private: - /** - * 输出流模式枚举 - */ - enum Mode : uint8_t { - /// 16 进制 %x - x, - /// 16 进制 %X - X, - /// 10 进制 %d - d, - }; - /// 输出流模式 - Mode mode_; -}; - -/// @name 输出流特化 -/// @{ - -template -auto OutStream::operator<<(T val) -> OutStream & { - *this << (uint64_t)val; - return *this; -} - -template <> -inline auto OutStream::operator<<(int32_t val) -> OutStream & { - if (mode_ == d) { - Print(L"%d", val); - } else if (mode_ == x) { - Print(L"0x%x", val); - } else if (mode_ == X) { - Print(L"0x%X", val); - } - mode_ = d; - return *this; -} - -template <> -inline auto OutStream::operator<<(uint32_t val) -> OutStream & { - if (mode_ == d) { - Print(L"%d", val); - } else if (mode_ == x) { - Print(L"0x%x", val); - } else if (mode_ == X) { - Print(L"0x%X", val); - } - mode_ = d; - return *this; -} - -template <> -inline auto OutStream::operator<<(int64_t val) -> OutStream & { - if (mode_ == d) { - Print(L"%ld", val); - } else if (mode_ == x) { - Print(L"0x%x", val); - } else if (mode_ == X) { - Print(L"0x%X", val); - } - mode_ = d; - return *this; -} - -template <> -inline auto OutStream::operator<<(uint64_t val) -> OutStream & { - if (mode_ == d) { - Print(L"%ld", val); - } else if (mode_ == x) { - Print(L"0x%x", val); - } else if (mode_ == X) { - Print(L"0x%X", val); - } - mode_ = d; - return *this; -} - -template <> -inline auto OutStream::operator<<(wchar_t val) -> OutStream & { - Print(L"%c", val); - mode_ = d; - return *this; -} - -template <> -inline auto OutStream::operator<<(const wchar_t *val) -> OutStream & { - Print(L"%s", val); - mode_ = d; - return *this; -} - -template <> -inline auto OutStream::operator<<(void *val) -> OutStream & { - *this << reinterpret_cast(val); - return *this; -} - -template <> -inline auto OutStream::operator<<(const void *val) -> OutStream & { - *this << reinterpret_cast(val); - return *this; -} - -/// @} - -/// 全局输出流 -extern OutStream debug; - -#endif /* SIMPLEKERNEL_SRC_BOOT_INCLUDE_OUT_STREAM_HPP_ */ diff --git a/src/boot/load_elf.cpp b/src/boot/load_elf.cpp deleted file mode 100644 index 854068033..000000000 --- a/src/boot/load_elf.cpp +++ /dev/null @@ -1,835 +0,0 @@ - -/** - * @file load_elf.cpp - * @brief 加载 elf 文件 - * @author Zone.N (Zone.Niuzh@hotmail.com) - * @version 1.0 - * @date 2023-07-15 - * @copyright MIT LICENSE - * https://github.com/Simple-XX/SimpleKernel - * @par change log: - * - *
DateAuthorDescription - *
2023-07-15Zone.N (Zone.Niuzh@hotmail.com)创建文件 - *
- */ - -#include "load_elf.h" - -#include -#include -#include -#include - -#include "out_stream.hpp" - -/** - * 将 char* 转换为 wchar_t* - * @param dst 输出 - * @param src 输入 - * @return 字符数量 - */ -static auto Char2Wchar(wchar_t *dst, const char *src) -> size_t { - size_t idx = 0; - while (src[idx] != '\0') { - dst[idx] = src[idx]; - idx++; - } - return idx; -} - -/// 一个制表符大小 -static constexpr const uint32_t kOneTabSize = 8; -/// 两个制表符大小 -static constexpr const uint32_t kTwoTabSize = 16; -/// 两位数对齐 -static constexpr const uint32_t kAlignTwo = 10; - -Elf::Elf(wchar_t *kernel_image_filename) { - EFI_STATUS status = EFI_SUCCESS; - // 打开文件系统协议 - status = LibLocateProtocol(&FileSystemProtocol, - reinterpret_cast(&file_system_protocol_)); - if (EFI_ERROR(status)) { - debug << L"Elf::Elf LibLocateProtocol failed: " << status - << OutStream::endl; - return; - } - - // 打开根文件系统 - status = uefi_call_wrapper(file_system_protocol_->OpenVolume, 2, - file_system_protocol_, &root_file_system_); - if (EFI_ERROR(status)) { - debug << L"Elf::Elf OpenVolume failed: " << status << OutStream::endl; - return; - } - - // 打开 elf 文件 - status = uefi_call_wrapper(root_file_system_->Open, 5, root_file_system_, - &elf_, kernel_image_filename, EFI_FILE_MODE_READ, - EFI_FILE_READ_ONLY); - - if (EFI_ERROR(status)) { - debug << L"Elf::Elf Open failed: " << status << OutStream::endl; - return; - } - - // 获取 elf 文件大小 - elf_file_size_ = GetFileSize(); - debug << L"Kernel file size: " << elf_file_size_ << OutStream::endl; - - // 分配 elf 文件缓存 - status = uefi_call_wrapper(gBS->AllocatePool, 3, EfiLoaderData, - elf_file_size_, &elf_file_buffer_); - - if (EFI_ERROR(status)) { - debug << L"Elf::Elf AllocatePool failed: " << status << OutStream::endl; - return; - } - - // 将内核文件读入内存 - status = uefi_call_wrapper(elf_->Read, 3, (EFI_FILE *)elf_, &elf_file_size_, - elf_file_buffer_); - if (EFI_ERROR(status)) { - debug << L"Elf::Elf Read failed: " << status << OutStream::endl; - return; - } - - file_ = std::span(static_cast(elf_file_buffer_), - elf_file_size_); - - // 检查 elf 头数据 - auto check_elf_identity_ret = CheckElfIdentity(); - if (!check_elf_identity_ret) { - debug << L"Elf::Elf NOT valid ELF file" << OutStream::endl; - return; - } - - // 读取 ehdr - GetEhdr(); - PrintEhdr(); - // 读取 phdr - GetPhdr(); - PrintPhdr(); - // 读取 shdr - GetShdr(); - PrintShdr(); -} - -Elf::~Elf() { - EFI_STATUS status = EFI_SUCCESS; - // 关闭 elf 文件 - status = uefi_call_wrapper(elf_->Close, 1, elf_); - if (EFI_ERROR(status)) { - debug << L"Elf::~Elf() Close failed: " << status << OutStream::endl; - return; - } - /// @note elf_file_buffer_ 不会被释放,传递给内核使用 -} - -auto Elf::Load() const -> std::pair> { - auto ret = LoadProgramSections(); - if (!ret) { - debug << L"Elf::Load() failed." << OutStream::endl; - return {0, {(uintptr_t)elf_file_buffer_, elf_file_size_}}; - } - return {ehdr_.e_entry, {(uintptr_t)elf_file_buffer_, elf_file_size_}}; -} - -auto Elf::GetFileSize() const -> size_t { - // 获取 elf 文件大小 - auto *elf_file_info = LibFileInfo(elf_); - auto file_size = elf_file_info->FileSize; - return file_size; -} - -auto Elf::CheckElfIdentity() const -> bool { - if ((file_[EI_MAG0] != ELFMAG0) || (file_[EI_MAG1] != ELFMAG1) || - (file_[EI_MAG2] != ELFMAG2) || (file_[EI_MAG3] != ELFMAG3)) { - debug << L"Fatal Error: Invalid ELF header" << OutStream::endl; - return false; - } - if (file_[EI_CLASS] == ELFCLASS32) { - debug << L"Found 32bit executable but NOT SUPPORT" << OutStream::endl; - return false; - } - if (file_[EI_CLASS] == ELFCLASS64) { - debug << L"Found 64bit executable" << OutStream::endl; - } else { - debug << L"Fatal Error: Invalid executable" << OutStream::endl; - return false; - } - return true; -} - -void Elf::GetEhdr() { - ehdr_ = *reinterpret_cast(file_.data()); -} - -void Elf::PrintEhdr() const { - debug << L" Magic: "; - for (auto idx : ehdr_.e_ident) { - debug << OutStream::hex_x << idx << L" "; - } - debug << OutStream::endl; - - debug << L" Class: "; - switch (ehdr_.e_ident[EI_CLASS]) { - case ELFCLASSNONE: { - debug << L"Invalid class"; - break; - } - case ELFCLASS32: { - debug << L"ELF32"; - break; - } - case ELFCLASS64: { - debug << L"ELF64"; - break; - } - default: { - debug << ehdr_.e_ident[EI_CLASS]; - break; - } - } - debug << OutStream::endl; - - debug << L" Data: "; - switch (ehdr_.e_ident[EI_DATA]) { - case ELFDATANONE: { - debug << L"Invalid data encoding"; - break; - } - case ELFDATA2LSB: { - debug << L"2's complement, little endian"; - break; - } - case ELFDATA2MSB: { - debug << L"2's complement, big endian"; - break; - } - default: { - debug << ehdr_.e_ident[EI_DATA]; - break; - } - } - debug << OutStream::endl; - - debug << L" Version: " - << ehdr_.e_ident[EI_VERSION] << L" "; - switch (ehdr_.e_ident[EI_VERSION]) { - case EV_NONE: { - debug << L"Invalid ELF version"; - break; - } - case EV_CURRENT: { - debug << L"Current version"; - break; - } - default: { - debug << ehdr_.e_ident[EI_VERSION]; - break; - } - } - debug << OutStream::endl; - - debug << L" OS/ABI: "; - switch (ehdr_.e_ident[EI_OSABI]) { - case ELFOSABI_SYSV: { - debug << L"UNIX System V ABI"; - break; - } - default: { - debug << ehdr_.e_ident[EI_OSABI]; - break; - } - } - debug << OutStream::endl; - - debug << L" ABI Version: " - << ehdr_.e_ident[EI_ABIVERSION] << OutStream::endl; - - debug << L" Type: "; - switch (ehdr_.e_type) { - case ET_NONE: { - debug << L"No file type"; - break; - } - case ET_REL: { - debug << L"Relocatable file"; - break; - } - case ET_EXEC: { - debug << L"Executable file"; - break; - } - case ET_DYN: { - debug << L"DYN (Shared object file)"; - break; - } - case ET_CORE: { - debug << L"Core file"; - break; - } - default: { - debug << ehdr_.e_type; - break; - } - } - debug << OutStream::endl; - - debug << L" Machine: "; - switch (ehdr_.e_machine) { - case EM_X86_64: { - debug << L"AMD x86-64 architecture"; - break; - } - case EM_RISCV: { - debug << L"RISC-V"; - break; - } - case EM_AARCH64: { - debug << L"ARM AARCH64"; - break; - } - default: { - debug << ehdr_.e_machine; - break; - } - } - debug << OutStream::endl; - - debug << L" Version: " << OutStream::hex_x - << ehdr_.e_version << OutStream::endl; - debug << L" Entry point address: " << OutStream::hex_x - << ehdr_.e_entry << OutStream::endl; - debug << L" Start of program headers: " << ehdr_.e_phoff - << L" (bytes into file)" << OutStream::endl; - debug << L" Start of section headers: " << ehdr_.e_shoff - << L" (bytes into file)" << OutStream::endl; - debug << L" Flags: " << OutStream::hex_x - << ehdr_.e_flags << OutStream::endl; - debug << L" Size of this header: " << ehdr_.e_ehsize - << L" (bytes)" << OutStream::endl; - debug << L" Size of program headers: " << ehdr_.e_phentsize - << L" (bytes)" << OutStream::endl; - debug << L" Number of program headers: " << ehdr_.e_phnum - << OutStream::endl; - debug << L" Size of section headers: " << ehdr_.e_shentsize - << L" (bytes)" << OutStream::endl; - debug << L" Number of section headers: " << ehdr_.e_shnum - << OutStream::endl; - debug << L" Section header string table index: " << ehdr_.e_shstrndx - << OutStream::endl; -} - -void Elf::GetPhdr() { - phdr_ = std::span( - reinterpret_cast(file_.data() + ehdr_.e_phoff), - ehdr_.e_phnum); -} - -void Elf::PrintPhdr() const { - debug << L"\nProgram Headers:" << OutStream::endl; - debug << L" " - L"Type\t\tOffset\t\tVirtAddr\tPhysAddr\tFileSiz\t\tMemSiz\t\tFlags" - L"\tAlign" - << OutStream::endl; - for (uint64_t i = 0; i < ehdr_.e_phnum; i++) { - switch (phdr_[i].p_type) { - case PT_NULL: { - debug << L" NULL\t\t"; - break; - } - - case PT_LOAD: { - debug << L" LOAD\t\t"; - break; - } - case PT_DYNAMIC: { - debug << L" DYNAMIC\t"; - break; - } - case PT_INTERP: { - debug << L" INTERP\t"; - break; - } - case PT_NOTE: { - debug << L" NOTE\t\t"; - break; - } - case PT_SHLIB: { - debug << L" SHLIB\t\t"; - break; - } - case PT_PHDR: { - debug << L" PHDR\t\t"; - break; - } - case PT_TLS: { - debug << L" TLS\t\t"; - break; - } - case PT_NUM: { - debug << L" NUM\t\t"; - break; - } - case PT_LOOS: { - debug << L" LOOS\t\t"; - break; - } - case PT_GNU_EH_FRAME: { - debug << L" GNU_EH_FRAME\t"; - break; - } - case PT_GNU_STACK: { - debug << L" GNU_STACK\t"; - break; - } - case PT_GNU_RELRO: { - debug << L" GNU_RELRO\t"; - break; - } - case PT_GNU_PROPERTY: { - debug << L" GNU_PROPERTY\t"; - break; - } - case PT_SUNWBSS: { - debug << L" SUNWBSS\t\t"; - break; - } - case PT_SUNWSTACK: { - debug << L" SUNWSTACK\t"; - break; - } - case PT_HIOS: { - debug << L" HIOS\t\t"; - break; - } - case PT_LOPROC: { - debug << L" LOPROC\t\t"; - break; - } - case PT_HIPROC: { - debug << L" HIPROC\t\t"; - break; - } - default: { - debug << L" Unknown " << OutStream::hex_X << phdr_[i].p_type << L"\t"; - break; - } - } - - debug << OutStream::hex_X << phdr_[i].p_offset << L"\t"; - debug << OutStream::hex_X << phdr_[i].p_vaddr << L"\t"; - debug << OutStream::hex_X << phdr_[i].p_paddr << L"\t"; - debug << OutStream::hex_X << phdr_[i].p_filesz << L"\t"; - debug << OutStream::hex_X << phdr_[i].p_memsz << L"\t"; - - switch (phdr_[i].p_flags) { - case PF_X: { - debug << L"E\t"; - break; - } - case PF_W: { - debug << L"W\t"; - break; - } - case PF_R: { - debug << L"R\t"; - break; - } - case PF_MASKOS: { - debug << L"OS-specific\t"; - break; - } - case PF_MASKPROC: { - debug << L"Processor-specific\t"; - break; - } - case (PF_X | PF_R): { - debug << L"R E\t"; - break; - } - case (PF_W | PF_R): { - debug << L"RW\t"; - break; - } - default: { - debug << L"Unknown " << OutStream::hex_x << phdr_[i].p_flags << L"\t"; - break; - } - } - debug << OutStream::hex_x << phdr_[i].p_align << OutStream::endl; - } -} - -void Elf::GetShdr() { - shdr_ = std::span( - reinterpret_cast(file_.data() + ehdr_.e_shoff), - ehdr_.e_shnum); - // 将 shstrtab 的内容复制到 shstrtab_buf 中 - - memcpy(shstrtab_buf_.data(), file_.data() + shdr_[ehdr_.e_shstrndx].sh_offset, - shdr_[ehdr_.e_shstrndx].sh_size); -} - -void Elf::PrintShdr() const { - debug << L"\nSection Headers:" << OutStream::endl; - debug << L" [Nr] " - L"Name\t\t\tType\t\tAddress\t\tOffset\t\tSize\t\tEntSize\t\tFl" - L"ags\tLink\tInfo\tAlign" - << OutStream::endl; - for (uint64_t i = 0; i < ehdr_.e_shnum; i++) { - debug << L" ["; - // 对齐 - if (i < kAlignTwo) { - debug << L" "; - } - debug << i << L"] "; - - std::array buf = {0}; - auto char2wchar_ret = - Char2Wchar(buf.data(), reinterpret_cast( - shstrtab_buf_.data() + shdr_[i].sh_name)); - debug << (const wchar_t *)buf.data() << L"\t"; - - if (char2wchar_ret <= kTwoTabSize) { - debug << L"\t"; - } - if (char2wchar_ret <= kOneTabSize) { - debug << L"\t"; - } - if (char2wchar_ret <= 1) { - debug << L"\t"; - } - switch (shdr_[i].sh_type) { - case SHT_NULL: { - debug << L"NULL\t\t"; - break; - } - case SHT_PROGBITS: { - debug << L"PROGBITS\t"; - break; - } - case SHT_SYMTAB: { - debug << L"SYMTAB\t\t"; - break; - } - case SHT_STRTAB: { - debug << L"STRTAB\t\t"; - break; - } - case SHT_RELA: { - debug << L"RELA\t\t"; - break; - } - case SHT_HASH: { - debug << L"HASH\t\t"; - break; - } - case SHT_DYNAMIC: { - debug << L"DYNAMIC\t\t"; - break; - } - case SHT_NOTE: { - debug << L"NOTE\t\t"; - break; - } - case SHT_NOBITS: { - debug << L"NOBITS\t\t"; - break; - } - case SHT_REL: { - debug << L"REL\t\t"; - break; - } - case SHT_SHLIB: { - debug << L"SHLIB\t\t"; - break; - } - case SHT_DYNSYM: { - debug << L"DYNSYM\t\t"; - break; - } - case SHT_INIT_ARRAY: { - debug << L"INIT_ARRAY\t"; - break; - } - case SHT_FINI_ARRAY: { - debug << L"FINI_ARRAY\t"; - break; - } - case SHT_PREINIT_ARRAY: { - debug << L"PREINIT_ARRAY\t\t"; - break; - } - case SHT_GROUP: { - debug << L"GROUP\t\t"; - break; - } - case SHT_SYMTAB_SHNDX: { - debug << L"SYMTAB_SHNDX\t\t"; - break; - } - case SHT_RELR: { - debug << L"RELR\t\t"; - break; - } - case SHT_NUM: { - debug << L"NUM\t\t"; - break; - } - case SHT_LOOS: { - debug << L"LOOS\t\t"; - break; - } - case SHT_GNU_ATTRIBUTES: { - debug << L"GNU_ATTRIBUTE\t\t"; - break; - } - case SHT_GNU_HASH: { - debug << L"GNU_HASH\t"; - break; - } - case SHT_GNU_LIBLIST: { - debug << L"GNU_LIBLIST\t\t"; - break; - } - case SHT_CHECKSUM: { - debug << L"CHECKSUM\t\t"; - break; - } - case SHT_SUNW_move: { - debug << L"SUNW_move\t\t"; - break; - } - case SHT_SUNW_COMDAT: { - debug << L"SUNW_COMDAT\t\t"; - break; - } - case SHT_SUNW_syminfo: { - debug << L"SUNW_syminfo\t\t"; - break; - } - case SHT_GNU_verdef: { - debug << L"GNU_verdef\t\t"; - break; - } - case SHT_GNU_verneed: { - debug << L"GNU_verneed\t"; - break; - } - case SHT_GNU_versym: { - debug << L"GNU_versym\t"; - break; - } - case SHT_LOPROC: { - debug << L"LOPROC\t\t"; - break; - } - case SHT_HIPROC: { - debug << L"HIPROC\t\t"; - break; - } - case SHT_LOUSER: { - debug << L"LOUSER\t\t"; - break; - } - case SHT_HIUSER: { - debug << L"HIUSER\t\t"; - break; - } - default: { - debug << L"Unknown " << OutStream::hex_X << shdr_[i].sh_type << L"\t"; - - break; - } - } - - debug << OutStream::hex_X << shdr_[i].sh_addr << L"\t"; - debug << OutStream::hex_x << shdr_[i].sh_offset << L"\t\t"; - debug << OutStream::hex_X << shdr_[i].sh_size << L"\t"; - debug << OutStream::hex_X << shdr_[i].sh_entsize << L"\t"; - - switch (shdr_[i].sh_flags) { - case 0: { - debug << L"0\t"; - break; - } - case SHF_WRITE: { - debug << L"WRITE\t"; - break; - } - case SHF_ALLOC: { - debug << L"A\t"; - break; - } - case SHF_EXECINSTR: { - debug << L"EXECINSTR\t"; - break; - } - case SHF_MERGE: { - debug << L"MERGE\t"; - break; - } - case SHF_STRINGS: { - debug << L"STRINGS\t"; - break; - } - case SHF_INFO_LINK: { - debug << L"INFO_LINK\t"; - break; - } - case SHF_LINK_ORDER: { - debug << L"LINK_ORDER\t"; - break; - } - case SHF_OS_NONCONFORMING: { - debug << L"OS_NONCONFORMING\t"; - break; - } - case SHF_GROUP: { - debug << L"GROUP\t"; - break; - } - case SHF_TLS: { - debug << L"TLS\t"; - break; - } - case SHF_COMPRESSED: { - debug << L"COMPRESSED\t"; - break; - } - case SHF_MASKOS: { - debug << L"MASKOS\t"; - break; - } - case SHF_MASKPROC: { - debug << L"MASKPROC\t"; - break; - } - case SHF_GNU_RETAIN: { - debug << L"GNU_RETAIN\t"; - break; - } - case SHF_ORDERED: { - debug << L"ORDERED\t"; - break; - } - case SHF_EXCLUDE: { - debug << L"EXCLUDE\t"; - break; - } - case (SHF_WRITE | SHF_ALLOC): { - debug << L"WA\t"; - break; - } - case (SHF_ALLOC | SHF_MERGE): { - debug << L"AM\t"; - break; - } - case (SHF_ALLOC | SHF_EXECINSTR): { - debug << L"AX\t"; - break; - } - case (SHF_MERGE | SHF_STRINGS): { - debug << L"MS\t"; - break; - } - default: { - debug << L"Unknown " << OutStream::hex_X << shdr_[i].sh_flags << L"\t"; - break; - } - } - - debug << shdr_[i].sh_link << L"\t"; - debug << shdr_[i].sh_info << L"\t"; - debug << shdr_[i].sh_addralign << L"\t"; - debug << OutStream::endl; - } -} - -bool Elf::LoadSections(const Elf64_Phdr &phdr) const { - EFI_STATUS status = EFI_SUCCESS; - void *data = nullptr; - // 计算使用的内存页数 - auto section_page_count = EFI_SIZE_TO_PAGES(phdr.p_memsz); - - // 设置文件偏移到 p_offset - status = uefi_call_wrapper(elf_->SetPosition, 2, elf_, phdr.p_offset); - if (EFI_ERROR(status)) { - debug << L"Elf::LoadSections SetPosition failed: " << status - << OutStream::endl; - return false; - } - status = uefi_call_wrapper(gBS->AllocatePages, 4, AllocateAddress, - EfiLoaderData, section_page_count, - (EFI_PHYSICAL_ADDRESS *)&phdr.p_paddr); - if (EFI_ERROR(status)) { - debug << L"Elf::LoadSections AllocatePages AllocateAddress failed: " - << status << L", phdr.p_paddr: " << OutStream::hex_X << phdr.p_paddr - << OutStream::endl; - return false; - } - - if (phdr.p_filesz > 0) { - auto buffer_read_size = phdr.p_filesz; - // 为 program_data 分配内存 - status = uefi_call_wrapper(gBS->AllocatePool, 3, EfiLoaderCode, - buffer_read_size, (void **)&data); - if (EFI_ERROR(status)) { - debug << L"Elf::LoadSections AllocatePool failed: " << status - << OutStream::endl; - return false; - } - // 读数据 - status = - uefi_call_wrapper(elf_->Read, 3, elf_, &buffer_read_size, (void *)data); - if (EFI_ERROR(status)) { - debug << L"Elf::LoadSections Read failed: " << status << OutStream::endl; - return false; - } - - // 将读出来的数据复制到其对应的物理地址 - uefi_call_wrapper(gBS->CopyMem, 3, reinterpret_cast(phdr.p_paddr), - data, phdr.p_filesz); - - // 释放 program_data - status = uefi_call_wrapper(gBS->FreePool, 1, data); - if (EFI_ERROR(status)) { - debug << L"Elf::LoadSections FreePool failed: " << status - << OutStream::endl; - return false; - } - } - - // 计算填充大小 - auto *zero_fill_start = - reinterpret_cast(phdr.p_paddr + phdr.p_filesz); - auto zero_fill_count = phdr.p_memsz - phdr.p_filesz; - if (zero_fill_count > 0) { - debug << L"Debug: Zero-filling " << zero_fill_count - << L" bytes at address '" << OutStream::hex_x << zero_fill_start - << L"'" << OutStream::endl; - - // 将填充部分置 0 - uefi_call_wrapper(gBS->SetMem, 3, zero_fill_start, zero_fill_count, 0); - } - return true; -} - -bool Elf::LoadProgramSections() const { - for (uint64_t i = 0; i < ehdr_.e_phnum; i++) { - if (phdr_[i].p_type != PT_LOAD) { - continue; - } - auto load_sections_ret = LoadSections(phdr_[i]); - if (!load_sections_ret) { - debug << L"Elf::LoadProgramSections() LoadSections failed " << i - << OutStream::endl; - return false; - } - } - return true; -} diff --git a/src/boot/memory.cpp b/src/boot/memory.cpp deleted file mode 100644 index de96d1495..000000000 --- a/src/boot/memory.cpp +++ /dev/null @@ -1,143 +0,0 @@ - -/** - * @file memory.cpp - * @brief 内存相关 - * @author Zone.N (Zone.Niuzh@hotmail.com) - * @version 1.0 - * @date 2023-07-15 - * @copyright MIT LICENSE - * https://github.com/Simple-XX/SimpleKernel - * @par change log: - * - *
DateAuthorDescription - *
2023-07-15Zone.N (Zone.Niuzh@hotmail.com)创建文件 - *
- */ - -#include "load_elf.h" -#include "out_stream.hpp" - -bool Memory::FlushDesc() { - memory_map_ = - LibMemoryMap(&desc_count_, &map_key_, &desc_size_, &desc_version_); - if (memory_map_ == nullptr) { - debug << L"LibMemoryMap failed: memory_map == nullptr" << OutStream::endl; - return false; - } - return true; -} - -Memory::Memory() { - auto flush_desc_ret = FlushDesc(); - if (!flush_desc_ret) { - debug << L"Memory::Memory() FlushDesc failed." << OutStream::endl; - return; - } -} - -std::pair Memory::GetMemory() const { - uint64_t addr = 0; - size_t size = 0; - // 统计所有内存 - for (uint64_t i = 0; i < desc_count_; i++) { - auto *desc = reinterpret_cast( - (reinterpret_cast(memory_map_)) + i * desc_size_); - size += desc->NumberOfPages * EFI_PAGE_SIZE; - } - - return {addr, size}; -} - -void Memory::PrintInfo() { - auto flush_desc_ret = FlushDesc(); - if (!flush_desc_ret) { - debug << L"Memory::PrintInfo() FlushDesc failed." << OutStream::endl; - return; - } - - debug << L"memory_map_: " << OutStream::hex_X << memory_map_ - << L", desc_count_: " << desc_count_ << L", desc_size_: " << desc_size_ - << L", sizeof(EFI_MEMORY_DESCRIPTOR): " << sizeof(EFI_MEMORY_DESCRIPTOR) - << L"." << OutStream::endl; - - debug << L"Type\t\t\t\tPages\tPhysicalStart\tVirtualStart\tAttribute" - << OutStream::endl; - - for (uint64_t i = 0; i < desc_count_; i++) { - auto *desc = reinterpret_cast( - (reinterpret_cast(memory_map_)) + i * desc_size_); - - switch (desc->Type) { - case EfiReservedMemoryType: { - debug << L"iReservedMemoryType\t\t"; - break; - } - case EfiLoaderCode: { - debug << L"EfiLoaderCode\t\t\t"; - break; - } - case EfiLoaderData: { - debug << L"EfiLoaderData\t\t\t"; - break; - } - case EfiBootServicesCode: { - debug << L"EfiBootServicesCode\t\t"; - break; - } - case EfiBootServicesData: { - debug << L"EfiBootServicesData\t\t"; - break; - } - case EfiRuntimeServicesCode: { - debug << L"EfiRuntimeServicesCode\t\t"; - break; - } - case EfiRuntimeServicesData: { - debug << L"EfiRuntimeServicesData\t\t"; - break; - } - case EfiConventionalMemory: { - debug << L"EfiConventionalMemory\t\t"; - break; - } - case EfiUnusableMemory: { - debug << L"EfiUnusableMemory\t\t"; - break; - } - case EfiACPIReclaimMemory: { - debug << L"EfiACPIReclaimMemory\t\t"; - break; - } - case EfiACPIMemoryNVS: { - debug << L"EfiACPIMemoryNVS\t\t"; - break; - } - case EfiMemoryMappedIO: { - debug << L"EfiMemoryMappedIO\t\t"; - break; - } - case EfiMemoryMappedIOPortSpace: { - debug << L"EfiMemoryMappedIOPortSpace\t\t"; - break; - } - case EfiPalCode: { - debug << L"EfiPalCode\t\t"; - break; - } - case EfiMaxMemoryType: { - debug << L"EfiMaxMemoryType\t\t"; - break; - } - default: { - debug << L"Unknown " << OutStream::hex_x << desc->Type << L"\t\t"; - break; - } - } - - debug << desc->NumberOfPages << L"\t" << OutStream::hex_X - << desc->PhysicalStart << L"\t" << OutStream::hex_X - << desc->VirtualStart << L"\t" << OutStream::hex_X << desc->Attribute - << OutStream::endl; - } - debug << L"map_key: " << OutStream::hex_X << map_key_ << OutStream::endl; -} diff --git a/src/boot/out_stream.cpp b/src/boot/out_stream.cpp deleted file mode 100644 index bf93a2065..000000000 --- a/src/boot/out_stream.cpp +++ /dev/null @@ -1,47 +0,0 @@ - -/** - * @file ostream.cpp - * @brief 输出 - * @author Zone.N (Zone.Niuzh@hotmail.com) - * @version 1.0 - * @date 2023-07-15 - * @copyright MIT LICENSE - * https://github.com/Simple-XX/SimpleKernel - * @par change log: - * - *
DateAuthorDescription - *
2023-07-15Zone.N (Zone.Niuzh@hotmail.com)创建文件 - *
- */ - -#include "out_stream.hpp" - -[[maybe_unused]] auto WaitForInput(EFI_INPUT_KEY *_key) -> EFI_STATUS { - EFI_STATUS status = EFI_SUCCESS; - do { - status = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, _key); - } while (EFI_NOT_READY == status); - - return status; -} - -auto OutStream::operator<<(OutStream &(*ostream)(OutStream &)) -> OutStream & { - return ostream(*this); -} - -auto OutStream::hex_x(OutStream &ostream) -> OutStream & { - ostream.mode_ = OutStream::x; - return ostream; -} - -auto OutStream::hex_X(OutStream &ostream) -> OutStream & { - ostream.mode_ = OutStream::X; - return ostream; -} - -auto OutStream::endl(OutStream &ostream) -> OutStream & { - return ostream << L'\n'; -} - -/// 全局输出流 -OutStream debug; diff --git a/src/driver/CMakeLists.txt b/src/driver/CMakeLists.txt new file mode 100644 index 000000000..43025c258 --- /dev/null +++ b/src/driver/CMakeLists.txt @@ -0,0 +1,25 @@ +# This file is a part of Simple-XX/SimpleKernel +# (https://github.com/Simple-XX/SimpleKernel). +# +# CMakeLists.txt for Simple-XX/SimpleKernel. + +ADD_LIBRARY (driver INTERFACE) + +TARGET_INCLUDE_DIRECTORIES (driver + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) + +TARGET_SOURCES (driver INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/driver.cpp) + +TARGET_LINK_LIBRARIES ( + driver + INTERFACE $<$:ns16550a> + $<$:pl011> + $<$:acpi>) + +IF(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "riscv64") + ADD_SUBDIRECTORY (ns16550a) +ELSEIF(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64") + ADD_SUBDIRECTORY (pl011) +ELSEIF(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64") + ADD_SUBDIRECTORY (acpi) +ENDIF() diff --git a/src/kernel/driver/README.md b/src/driver/README.md similarity index 100% rename from src/kernel/driver/README.md rename to src/driver/README.md diff --git a/src/driver/acpi/CMakeLists.txt b/src/driver/acpi/CMakeLists.txt new file mode 100644 index 000000000..f0e035494 --- /dev/null +++ b/src/driver/acpi/CMakeLists.txt @@ -0,0 +1,10 @@ +# This file is a part of Simple-XX/SimpleKernel +# (https://github.com/Simple-XX/SimpleKernel). +# +# CMakeLists.txt for Simple-XX/SimpleKernel. + +ADD_LIBRARY (acpi INTERFACE) + +TARGET_INCLUDE_DIRECTORIES (acpi INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) + +TARGET_SOURCES (acpi INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/acpi.cpp) diff --git a/src/driver/acpi/README.md b/src/driver/acpi/README.md new file mode 100644 index 000000000..1c5099ec0 --- /dev/null +++ b/src/driver/acpi/README.md @@ -0,0 +1,5 @@ +# acpi + +acpi 驱动 + +https://uefi.org/sites/default/files/resources/ACPI_Spec_6_5_Aug29.pdf diff --git a/src/driver/acpi/acpi.cpp b/src/driver/acpi/acpi.cpp new file mode 100644 index 000000000..c035fa066 --- /dev/null +++ b/src/driver/acpi/acpi.cpp @@ -0,0 +1,21 @@ + +/** + * @file acpi.cpp + * @brief acpi 实现 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2024-05-24 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2024-05-24Zone.N (Zone.Niuzh@hotmail.com)创建文件 + *
+ */ + +#include "acpi.h" + +#include "io.hpp" + +Acpi::Acpi(uint64_t rsdp) : rsdp_addr_(rsdp) {} diff --git a/src/driver/acpi/include/acpi.h b/src/driver/acpi/include/acpi.h new file mode 100644 index 000000000..3720d8401 --- /dev/null +++ b/src/driver/acpi/include/acpi.h @@ -0,0 +1,182 @@ + +/** + * @file acpi.h + * @brief acpi 头文件 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2024-05-24 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2024-05-24Zone.N (Zone.Niuzh@hotmail.com)创建文件 + *
+ */ + +#ifndef SIMPLEKERNEL_SRC_DRIVER_ACPI_INCLUDE_ACPI_H_ +#define SIMPLEKERNEL_SRC_DRIVER_ACPI_INCLUDE_ACPI_H_ + +#include + +/** + * @brief acpi 驱动 + * @see https://uefi.org/sites/default/files/resources/ACPI_Spec_6_5_Aug29.pdf + */ +class Acpi { + public: + /** + * 构造函数 + * @param rsdp rsdp 地址 + */ + explicit Acpi(uint64_t rsdp); + + /// @name 默认构造/析构函数 + /// @{ + Acpi() = delete; + Acpi(const Acpi&) = delete; + Acpi(Acpi&&) = delete; + auto operator=(const Acpi&) -> Acpi& = delete; + auto operator=(Acpi&&) -> Acpi& = delete; + ~Acpi() = default; + /// @} + + private: + /** + * @brief Generic Address Structure + * @see ACPI_Spec_6_5_Aug29.pdf#5.2.3.2 + */ + struct GenericAddressStructure { + uint8_t address_space_id; + uint8_t register_bit_width; + uint8_t register_bit_offset; + uint8_t access_size; + uint64_t address; + } __attribute__((packed)); + + /** + * @brief Root System Description Pointer (RSDP) Structure + * @see ACPI_Spec_6_5_Aug29.pdf#5.2.5.3 + */ + struct Rsdp { + char signature[8]; + uint8_t checksum; + char oemid[6]; + uint8_t revision; + uint32_t rsdt_address; + uint32_t length; + uint64_t xsdt_address; + uint8_t extended_checksum; + uint8_t reserved[3]; + } __attribute__((packed)); + + /** + * @brief System Description Table Header + * @see ACPI_Spec_6_5_Aug29.pdf#5.2.6 + */ + struct Description_header { + char signature[4]; + uint32_t length; + uint8_t revision; + uint8_t checksum; + char oemid[6]; + char oem_table_id[8]; + uint32_t oem_revision; + uint32_t creator_id; + uint32_t creator_revision; + } __attribute__((packed)); + + /** + * @brief Root System Description Table (RSDT) + * @see ACPI_Spec_6_5_Aug29.pdf#5.2.7 + */ + struct Rsdt { + Description_header header; + uint32_t* entry; + } __attribute__((packed)); + + /** + * @brief Extended System Description Table (XSDT) + * @see ACPI_Spec_6_5_Aug29.pdf#5.2.8 + */ + struct Xsdt { + Description_header header; + uint64_t* entry; + } __attribute__((packed)); + + /** + * @brief Fixed ACPI Description Table (FADT) + * @see ACPI_Spec_6_5_Aug29.pdf#5.2.9 + */ + struct Fadt { + Description_header header; + uint32_t firmware_ctrl; + uint32_t dsdt; + uint8_t reserved; + uint8_t preferred_pm_profile; + uint16_t sci_int; + uint32_t smi_cmd; + uint8_t acpi_enable; + uint8_t acpi_disable; + uint8_t s4bios_req; + uint8_t pstate_cnt; + uint32_t pm1a_evt_blk; + uint32_t pm1b_evt_blk; + uint32_t pm1a_cnt_blk; + uint32_t pm1b_cnt_blk; + uint32_t pm2_cnt_blk; + uint32_t pm_tmr_blk; + uint32_t gpe0_blk; + uint32_t gpe1_blk; + uint8_t pm1_evt_len; + uint8_t pm1_cnt_len; + uint8_t pm2_cnt_len; + uint8_t pm_tmr_len; + uint8_t gpe0_blk_len; + uint8_t gpe1_blk_len; + uint8_t gpe1_base; + uint8_t cst_cnt; + uint16_t p_lvl2_lat; + uint16_t p_lvl3_lat; + uint16_t flush_size; + uint16_t flush_stride; + uint8_t duty_offset; + uint8_t duty_width; + uint8_t day_alrm; + uint8_t mon_alrm; + uint8_t century; + uint16_t iapc_boot_arch; + uint8_t reserved2; + uint32_t flags; + GenericAddressStructure reset_reg; + uint8_t reset_value; + uint16_t arm_boot_arch; + uint8_t fadt_minor_version; + uint64_t x_firmware_ctrl; + uint64_t x_dsdt; + GenericAddressStructure x_pm1a_evt_blk; + GenericAddressStructure x_pm1b_evt_blk; + GenericAddressStructure x_pm1a_cnt_blk; + GenericAddressStructure x_pm1b_cnt_blk; + GenericAddressStructure x_pm2_cnt_blk; + GenericAddressStructure x_pm_tmr_blk; + GenericAddressStructure x_gpe0_blk; + GenericAddressStructure x_gpe1_blk; + GenericAddressStructure sleep_control_reg; + GenericAddressStructure sleep_status_reg; + uint64_t hypervisor_vendor_id; + } __attribute__((packed)); + + /** + * @brief Differentiated System Description Table (DSDT) + * @see ACPI_Spec_6_5_Aug29.pdf#5.2.11.1 + */ + struct Dsdt { + Description_header header; + uint8_t* definition_block; + } __attribute__((packed)); + + uint64_t rsdp_addr_ = 0; +}; + +#endif /* SIMPLEKERNEL_SRC_DRIVER_ACPI_INCLUDE_ACPI_H_ */ diff --git a/src/kernel/driver/driver.cpp b/src/driver/driver.cpp similarity index 82% rename from src/kernel/driver/driver.cpp rename to src/driver/driver.cpp index 60001ec7a..254d37af0 100644 --- a/src/kernel/driver/driver.cpp +++ b/src/driver/driver.cpp @@ -16,12 +16,14 @@ #include "driver.h" -uint32_t Driver(uint32_t argc, uint8_t *argv) { +#include + +auto Driver(uint32_t argc, const uint8_t *argv) -> uint32_t { (void)argc; (void)argv; // 进入死循环 - while (1) { + while (true) { ; } diff --git a/src/kernel/driver/include/driver.h b/src/driver/include/driver.h similarity index 69% rename from src/kernel/driver/include/driver.h rename to src/driver/include/driver.h index 836feb3a3..678d7da28 100644 --- a/src/kernel/driver/include/driver.h +++ b/src/driver/include/driver.h @@ -14,8 +14,8 @@ * */ -#ifndef SIMPLEKERNEL_SRC_KERNEL_DRIVER_INCLUDE_DRIVER_H_ -#define SIMPLEKERNEL_SRC_KERNEL_DRIVER_INCLUDE_DRIVER_H_ +#ifndef SIMPLEKERNEL_SRC_DRIVER_INCLUDE_DRIVER_H_ +#define SIMPLEKERNEL_SRC_DRIVER_INCLUDE_DRIVER_H_ #include @@ -25,6 +25,6 @@ * @param argv 参数列表 * @return uint32_t 正常返回 0 */ -uint32_t Driver(uint32_t argc, uint8_t *argv); +auto Driver(uint32_t argc, const uint8_t *argv) -> uint32_t; -#endif /* SIMPLEKERNEL_SRC_KERNEL_DRIVER_INCLUDE_DRIVER_H_ */ +#endif /* SIMPLEKERNEL_SRC_DRIVER_INCLUDE_DRIVER_H_ */ diff --git a/src/driver/ns16550a/CMakeLists.txt b/src/driver/ns16550a/CMakeLists.txt new file mode 100644 index 000000000..10f7627f5 --- /dev/null +++ b/src/driver/ns16550a/CMakeLists.txt @@ -0,0 +1,11 @@ +# This file is a part of Simple-XX/SimpleKernel +# (https://github.com/Simple-XX/SimpleKernel). +# +# CMakeLists.txt for Simple-XX/SimpleKernel. + +ADD_LIBRARY (ns16550a INTERFACE) + +TARGET_INCLUDE_DIRECTORIES (ns16550a + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) + +TARGET_SOURCES (ns16550a INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/ns16550a.cpp) diff --git a/src/kernel/driver/ns16550a/README.md b/src/driver/ns16550a/README.md similarity index 99% rename from src/kernel/driver/ns16550a/README.md rename to src/driver/ns16550a/README.md index 41a438acd..e215531f7 100644 --- a/src/kernel/driver/ns16550a/README.md +++ b/src/driver/ns16550a/README.md @@ -11,5 +11,3 @@ serial@10000000 { compatible = "ns16550a"; }; ``` - - diff --git a/src/kernel/driver/ns16550a/include/ns16550a.h b/src/driver/ns16550a/include/ns16550a.h similarity index 80% rename from src/kernel/driver/ns16550a/include/ns16550a.h rename to src/driver/ns16550a/include/ns16550a.h index 77406ccd7..4640ec9aa 100644 --- a/src/kernel/driver/ns16550a/include/ns16550a.h +++ b/src/driver/ns16550a/include/ns16550a.h @@ -14,8 +14,8 @@ * */ -#ifndef SIMPLEKERNEL_SRC_KERNEL_DRIVER_NS16550A_INCLUDE_NS16550A_H_ -#define SIMPLEKERNEL_SRC_KERNEL_DRIVER_NS16550A_INCLUDE_NS16550A_H_ +#ifndef SIMPLEKERNEL_SRC_DRIVER_NS16550A_INCLUDE_NS16550A_H_ +#define SIMPLEKERNEL_SRC_DRIVER_NS16550A_INCLUDE_NS16550A_H_ #include @@ -25,7 +25,7 @@ class Ns16550a { * 构造函数 * @param dev_addr 设备地址 */ - explicit Ns16550a(uintptr_t dev_addr); + explicit Ns16550a(uint64_t dev_addr); /// @name 默认构造/析构函数 /// @{ @@ -37,7 +37,7 @@ class Ns16550a { ~Ns16550a() = default; /// @} - void PutChar(uint8_t c); + void PutChar(uint8_t c) const; private: /// read mode: Receive holding reg @@ -64,13 +64,7 @@ class Ns16550a { /// MSB of divisor Latch when enabled static constexpr const uint8_t kUartDLM = 1; - uintptr_t base_addr_; - - inline volatile uint8_t* Reg(uint8_t reg); - - inline uint8_t Read(uint8_t reg); - - inline void Write(uint8_t reg, uint8_t c); + uint64_t base_addr_; }; -#endif /* SIMPLEKERNEL_SRC_KERNEL_DRIVER_NS16550A_INCLUDE_NS16550A_H_ */ +#endif /* SIMPLEKERNEL_SRC_DRIVER_NS16550A_INCLUDE_NS16550A_H_ */ diff --git a/src/driver/ns16550a/ns16550a.cpp b/src/driver/ns16550a/ns16550a.cpp new file mode 100644 index 000000000..4ff4be1d1 --- /dev/null +++ b/src/driver/ns16550a/ns16550a.cpp @@ -0,0 +1,41 @@ + +/** + * @file ns16550a.h + * @brief ns16550a 头文件 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2024-05-24 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2024-05-24Zone.N (Zone.Niuzh@hotmail.com)创建文件 + *
+ */ + +#include "ns16550a.h" + +#include "io.hpp" + +Ns16550a::Ns16550a(uint64_t dev_addr) : base_addr_(dev_addr) { + // disable interrupt + io::Out(base_addr_ + kRegIER, 0x00); + // set baud rate + io::Out(base_addr_ + kRegLCR, 0x80); + io::Out(base_addr_ + kUartDLL, 0x03); + io::Out(base_addr_ + kUartDLM, 0x00); + // set word length to 8-bits + io::Out(base_addr_ + kRegLCR, 0x03); + // enable FIFOs + io::Out(base_addr_ + kRegFCR, 0x07); + // enable receiver interrupts + io::Out(base_addr_ + kRegIER, 0x01); +} + +void Ns16550a::PutChar(uint8_t c) const { + while ((io::In(base_addr_ + kRegLSR) & (1 << 5)) == 0) { + ; + } + io::Out(base_addr_ + kRegTHR, c); +} diff --git a/src/driver/pl011/CMakeLists.txt b/src/driver/pl011/CMakeLists.txt new file mode 100644 index 000000000..2e6be4087 --- /dev/null +++ b/src/driver/pl011/CMakeLists.txt @@ -0,0 +1,10 @@ +# This file is a part of Simple-XX/SimpleKernel +# (https://github.com/Simple-XX/SimpleKernel). +# +# CMakeLists.txt for Simple-XX/SimpleKernel. + +ADD_LIBRARY (pl011 INTERFACE) + +TARGET_INCLUDE_DIRECTORIES (pl011 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) + +TARGET_SOURCES (pl011 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/pl011.cpp) diff --git a/src/driver/pl011/README.md b/src/driver/pl011/README.md new file mode 100644 index 000000000..b061fdc4f --- /dev/null +++ b/src/driver/pl011/README.md @@ -0,0 +1,15 @@ +# pl011 + +aarch64 使用的 uart + +https://developer.arm.com/documentation/ddi0183/g/ + +``` +pl011@9000000 { + clock-names = "uartclk\0apb_pclk"; + clocks = <0x8000 0x8000>; + interrupts = <0x00 0x01 0x04>; + reg = <0x00 0x9000000 0x00 0x1000>; + compatible = "arm,pl011\0arm,primecell"; + }; +``` diff --git a/src/driver/pl011/include/pl011.h b/src/driver/pl011/include/pl011.h new file mode 100644 index 000000000..bd237c7b0 --- /dev/null +++ b/src/driver/pl011/include/pl011.h @@ -0,0 +1,131 @@ + +/** + * @file pl011.h + * @brief pl011 头文件 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2024-05-24 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2024-05-24Zone.N (Zone.Niuzh@hotmail.com)创建文件 + *
+ */ + +#ifndef SIMPLEKERNEL_SRC_DRIVER_PL011_INCLUDE_PL011_H_ +#define SIMPLEKERNEL_SRC_DRIVER_PL011_INCLUDE_PL011_H_ + +#include + +/** + * @brief PL011 串口驱动 + * @see https://developer.arm.com/documentation/ddi0183/g/ + */ +class Pl011 { + public: + /** + * 构造函数 + * @param dev_addr 设备地址 + * @param uart_clk 串口时钟 + * @param baud_rate 波特率 + */ + explicit Pl011(uint64_t dev_addr, uint64_t clock = 0, uint64_t baud_rate = 0); + + /// @name 默认构造/析构函数 + /// @{ + Pl011() = delete; + Pl011(const Pl011& na16550a) = delete; + Pl011(Pl011&& na16550a) = delete; + auto operator=(const Pl011& na16550a) -> Pl011& = delete; + auto operator=(Pl011&& na16550a) -> Pl011& = delete; + ~Pl011() = default; + /// @} + + void PutChar(uint8_t c); + + private: + /// data register + static constexpr const uint32_t kRegDR = 0x00; + /// receive status or error clear + static constexpr const uint32_t kRegRSRECR = 0x04; + /// DMA watermark configure + static constexpr const uint32_t kRegDmaWm = 0x08; + /// Timeout period + static constexpr const uint32_t kRegTimeOut = 0x0C; + /// flag register + static constexpr const uint32_t kRegFR = 0x18; + /// IrDA low-poer + static constexpr const uint32_t kRegILPR = 0x20; + /// integer baud register + static constexpr const uint32_t kRegIBRD = 0x24; + /// fractional baud register + static constexpr const uint32_t kRegFBRD = 0x28; + /// line control register + static constexpr const uint32_t kRegLCRH = 0x2C; + /// control register + static constexpr const uint32_t kRegCR = 0x30; + /// interrupt FIFO level select + static constexpr const uint32_t kRegIFLS = 0x34; + /// interrupt mask set/clear + static constexpr const uint32_t kRegIMSC = 0x38; + /// raw interrupt register + static constexpr const uint32_t kRegRIS = 0x3C; + /// masked interrupt register + static constexpr const uint32_t kRegMIS = 0x40; + /// interrupt clear register + static constexpr const uint32_t kRegICR = 0x44; + /// DMA control register + static constexpr const uint32_t kRegDmaCR = 0x48; + + /// flag register bits + static constexpr const uint32_t kFRRTXDIS = (1 << 13); + static constexpr const uint32_t kFRTERI = (1 << 12); + static constexpr const uint32_t kFRDDCD = (1 << 11); + static constexpr const uint32_t kFRDDSR = (1 << 10); + static constexpr const uint32_t kFRDCTS = (1 << 9); + static constexpr const uint32_t kFRRI = (1 << 8); + static constexpr const uint32_t kFRTXFE = (1 << 7); + static constexpr const uint32_t kFRRXFF = (1 << 6); + static constexpr const uint32_t kFRTxFIFO = (1 << 5); + static constexpr const uint32_t kFRRXFE = (1 << 4); + static constexpr const uint32_t kFRBUSY = (1 << 3); + static constexpr const uint32_t kFRDCD = (1 << 2); + static constexpr const uint32_t kFRDSR = (1 << 1); + static constexpr const uint32_t kFRCTS = (1 << 0); + + /// transmit/receive line register bits + static constexpr const uint32_t kLCRHSPS = (1 << 7); + static constexpr const uint32_t kLCRHWlen8 = (3 << 5); + static constexpr const uint32_t kLCRHWLEN_7 = (2 << 5); + static constexpr const uint32_t kLCRHWLEN_6 = (1 << 5); + static constexpr const uint32_t kLCRHWLEN_5 = (0 << 5); + static constexpr const uint32_t kLCRHFEN = (1 << 4); + static constexpr const uint32_t kLCRHSTP2 = (1 << 3); + static constexpr const uint32_t kLCRHEPS = (1 << 2); + static constexpr const uint32_t kLCRHPEN = (1 << 1); + static constexpr const uint32_t kLCRHBRK = (1 << 0); + + /// control register bits + static constexpr const uint32_t kCRCTSEN = (1 << 15); + static constexpr const uint32_t kCRRTSEN = (1 << 14); + static constexpr const uint32_t kCROUT2 = (1 << 13); + static constexpr const uint32_t kCROUT1 = (1 << 12); + static constexpr const uint32_t kCRRTS = (1 << 11); + static constexpr const uint32_t kCRDTR = (1 << 10); + static constexpr const uint32_t kCRRxEnable = (1 << 9); + static constexpr const uint32_t kCRTxEnable = (1 << 8); + static constexpr const uint32_t kCRLPE = (1 << 7); + static constexpr const uint32_t kCROVSFACT = (1 << 3); + static constexpr const uint32_t kCREnable = (1 << 0); + + static constexpr const uint32_t kIMSCRTIM = (1 << 6); + static constexpr const uint32_t kIMSCRxim = (1 << 4); + + uint64_t base_addr_ = 0; + uint64_t base_clock_ = 0; + uint64_t baud_rate_ = 0; +}; + +#endif /* SIMPLEKERNEL_SRC_DRIVER_PL011_INCLUDE_PL011_H_ */ diff --git a/src/driver/pl011/pl011.cpp b/src/driver/pl011/pl011.cpp new file mode 100644 index 000000000..be4fa1498 --- /dev/null +++ b/src/driver/pl011/pl011.cpp @@ -0,0 +1,52 @@ + +/** + * @file pl011.h + * @brief pl011 头文件 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2024-05-24 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2024-05-24Zone.N (Zone.Niuzh@hotmail.com)创建文件 + *
+ */ + +#include "pl011.h" + +#include "io.hpp" + +Pl011::Pl011(uint64_t dev_addr, uint64_t clock, uint64_t baud_rate) + : base_addr_(dev_addr), base_clock_(clock), baud_rate_(baud_rate) { + // Clear all errors + io::Out(base_addr_ + kRegRSRECR, 0); + // Disable everything + io::Out(base_addr_ + kRegCR, 0); + + if (baud_rate_ != 0) { + uint32_t divisor = (base_clock_ * 4) / baud_rate_; + + io::Out(base_addr_ + kRegIBRD, divisor >> 6); + io::Out(base_addr_ + kRegFBRD, divisor & 0x3f); + } + + // Configure TX to 8 bits, 1 stop bit, no parity, fifo disabled. + io::Out(base_addr_ + kRegLCRH, kLCRHWlen8); + + // Enable receive interrupt + io::Out(base_addr_ + kRegIMSC, kIMSCRxim); + + // Enable UART and RX/TX + io::Out(base_addr_ + kRegCR, kCREnable | kCRTxEnable | kCRRxEnable); +} + +void Pl011::PutChar(uint8_t c) { + // Wait until there is space in the FIFO or device is disabled + while (io::In(base_addr_ + kRegFR) & kFRTxFIFO) { + ; + } + + io::Out(base_addr_ + kRegDR, c); +} diff --git a/src/kernel/include/basic_info.hpp b/src/include/basic_info.hpp similarity index 50% rename from src/kernel/include/basic_info.hpp rename to src/include/basic_info.hpp index 286f3df29..75fdece94 100644 --- a/src/kernel/include/basic_info.hpp +++ b/src/include/basic_info.hpp @@ -14,16 +14,27 @@ * */ -#ifndef SIMPLEKERNEL_SRC_KERNEL_INCLUDE_BASIC_INFO_HPP_ -#define SIMPLEKERNEL_SRC_KERNEL_INCLUDE_BASIC_INFO_HPP_ +#ifndef SIMPLEKERNEL_SRC_INCLUDE_BASIC_INFO_HPP_ +#define SIMPLEKERNEL_SRC_INCLUDE_BASIC_INFO_HPP_ #include #include +#include "kernel_log.hpp" #include "singleton.hpp" -#include "sk_cstdio" #include "sk_iostream" +// 引用链接脚本中的变量 +/// @see http://wiki.osdev.org/Using_Linker_Script_Values +/// 内核开始 +extern "C" void *__executable_start[]; +/// 代码段结束 +extern "C" void *__etext[]; +/// 内核结束 +extern "C" void *end[]; +/// 内核入口,在 boot.S 中定义 +extern "C" void _boot(); + struct BasicInfo { /// physical_memory 地址 uint64_t physical_memory_addr; @@ -43,12 +54,15 @@ struct BasicInfo { /// fdt 地址 uint64_t fdt_addr; + /// cpu 核数 + size_t core_count; + /** * 构造函数,在 arch_main.cpp 中定义 * @param argc 同 _start * @param argv 同 _start */ - explicit BasicInfo(uint32_t argc, uint8_t *argv); + explicit BasicInfo(int argc, const char **argv); /// @name 构造/析构函数 /// @{ @@ -60,20 +74,19 @@ struct BasicInfo { ~BasicInfo() = default; /// @} - friend sk_std::ostream &operator<<(sk_std::ostream &os, - const BasicInfo &basic_info) { - printf("physical_memory_addr: 0x%X, size 0x%X.\n", - basic_info.physical_memory_addr, basic_info.physical_memory_size); - printf("kernel_addr: 0x%X, size 0x%X.\n", basic_info.kernel_addr, - basic_info.kernel_size); - printf("elf_addr: 0x%X, size 0x%X\n", basic_info.elf_addr, - basic_info.elf_size); - printf("fdt_addr: 0x%X\n", basic_info.fdt_addr); - return os; + friend auto operator<<(sk_std::ostream &ostream, const BasicInfo &basic_info) + -> sk_std::ostream & { + klog::Info("physical_memory_addr: 0x%X, size 0x%X.\n", + basic_info.physical_memory_addr, + basic_info.physical_memory_size); + klog::Info("kernel_addr: 0x%X, size 0x%X.\n", basic_info.kernel_addr, + basic_info.kernel_size); + klog::Info("elf_addr: 0x%X, size 0x%X\n", basic_info.elf_addr, + basic_info.elf_size); + klog::Info("fdt_addr: 0x%X\n", basic_info.fdt_addr); + klog::Info("core_count: %d\n", basic_info.core_count); + return ostream; } }; -/// 保存基本信息 -[[maybe_unused]] static Singleton kBasicInfo; - -#endif /* SIMPLEKERNEL_SRC_KERNEL_INCLUDE_BASIC_INFO_HPP_ */ +#endif /* SIMPLEKERNEL_SRC_INCLUDE_BASIC_INFO_HPP_ */ diff --git a/src/kernel/libc/include/sk_libc.h b/src/include/config.h similarity index 59% rename from src/kernel/libc/include/sk_libc.h rename to src/include/config.h index 12c22a19f..6c245f1ec 100644 --- a/src/kernel/libc/include/sk_libc.h +++ b/src/include/config.h @@ -1,7 +1,7 @@ /** - * @file sk_libc.h - * @brief sk_libc 头文件 + * @file config.h + * @brief 配置文件 * @author Zone.N (Zone.Niuzh@hotmail.com) * @version 1.0 * @date 2023-07-15 @@ -14,7 +14,9 @@ * */ -#ifndef SIMPLEKERNEL_SRC_KERNEL_LIBC_INCLUDE_SK_LIBC_H_ -#define SIMPLEKERNEL_SRC_KERNEL_LIBC_INCLUDE_SK_LIBC_H_ +#ifndef SIMPLEKERNEL_SRC_INCLUDE_CONFIG_H_ +#define SIMPLEKERNEL_SRC_INCLUDE_CONFIG_H_ -#endif /* SIMPLEKERNEL_SRC_KERNEL_LIBC_INCLUDE_SK_LIBC_H_ */ +#include "project_config.h" + +#endif /* SIMPLEKERNEL_SRC_INCLUDE_CONFIG_H_ */ diff --git a/src/include/io.hpp b/src/include/io.hpp new file mode 100644 index 000000000..8e715fba3 --- /dev/null +++ b/src/include/io.hpp @@ -0,0 +1,54 @@ + +/** + * @file io.hpp + * @brief 直接内存读写 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2022-01-01 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2022-01-01MRNIU迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_SRC_INCLUDE_IO_HPP_ +#define SIMPLEKERNEL_SRC_INCLUDE_IO_HPP_ + +#include + +#include +#include +#include + +#include "per_cpu.hpp" +#include "sk_cstdio" + +namespace io { +/** + * @brief 从指定地址读数据 + * @tparam T 要读的数据类型 + * @param addr 要读的指定地址 + * @return T 读取到的数据 + */ +template +static __always_inline auto In(const uint64_t addr) -> T { + return *reinterpret_cast(addr); +} + +/** + * @brief 向指定地址写数据 + * @tparam T 要写的数据类型 + * @param addr 要写的指定地址 + * @param data 要写的数据 + */ +template +static __always_inline void Out(const uint64_t addr, const T data) { + *reinterpret_cast(addr) = data; +} + +} // namespace io + +#endif /* SIMPLEKERNEL_SRC_INCLUDE_IO_HPP_ */ diff --git a/src/kernel/include/kernel.h b/src/include/kernel.h similarity index 64% rename from src/kernel/include/kernel.h rename to src/include/kernel.h index 6d7d59946..cbe5bc108 100644 --- a/src/kernel/include/kernel.h +++ b/src/include/kernel.h @@ -14,10 +14,9 @@ * */ -#ifndef SIMPLEKERNEL_SRC_KERNEL_INCLUDE_KERNEL_H_ -#define SIMPLEKERNEL_SRC_KERNEL_INCLUDE_KERNEL_H_ +#ifndef SIMPLEKERNEL_SRC_INCLUDE_KERNEL_H_ +#define SIMPLEKERNEL_SRC_INCLUDE_KERNEL_H_ -#include #include /** @@ -30,15 +29,15 @@ * x86_64: BasicInfo 地址 * @return uint32_t 正常返回 0 */ -extern "C" [[maybe_unused]] [[noreturn]] void _start(uint32_t argc, - uint8_t* argv); +extern "C" [[maybe_unused]] [[noreturn]] void _start(int argc, + const char** argv); /** * @brief 内核入口 * @param argc 同 _start * @param argv 同 _start - * @return uint32_t 正常返回 0 + * @return int 正常返回 0 */ -uint32_t main(uint32_t argc, uint8_t* argv); +auto main(int argc, const char** argv) -> int; -#endif /* SIMPLEKERNEL_SRC_KERNEL_INCLUDE_KERNEL_H_ */ +#endif /* SIMPLEKERNEL_SRC_INCLUDE_KERNEL_H_ */ diff --git a/src/kernel/include/kernel_elf.hpp b/src/include/kernel_elf.hpp similarity index 67% rename from src/kernel/include/kernel_elf.hpp rename to src/include/kernel_elf.hpp index f23cf577d..26e4d3dc6 100644 --- a/src/kernel/include/kernel_elf.hpp +++ b/src/include/kernel_elf.hpp @@ -14,16 +14,16 @@ * */ -#ifndef SIMPLEKERNEL_SRC_KERNEL_INCLUDE_KERNEL_ELF_HPP_ -#define SIMPLEKERNEL_SRC_KERNEL_INCLUDE_KERNEL_ELF_HPP_ +#ifndef SIMPLEKERNEL_SRC_INCLUDE_KERNEL_ELF_HPP_ +#define SIMPLEKERNEL_SRC_INCLUDE_KERNEL_ELF_HPP_ #include #include #include +#include #include -#include "sk_cstring" #include "kernel_log.hpp" #include "singleton.hpp" @@ -33,7 +33,7 @@ class KernelElf { public: /// 符号表 - std::span symtab_ = {}; + std::span symtab_; /// 字符串表 uint8_t *strtab_ = nullptr; @@ -43,12 +43,13 @@ class KernelElf { * @param elf_size elf 大小,默认为 64,Elf64_Ehdr 的大小 */ explicit KernelElf(uint64_t elf_addr, size_t elf_size = 64) { - if (!elf_addr || !elf_size) { - klog::Err("Fatal Error: Invalid elf_addr or elf_size.\n"); + if ((elf_addr == 0U) || (elf_size == 0U)) { + klog::Err("Fatal Error: Invalid elf_addr[0x%lX] or elf_size[0x%lX].\n", + elf_addr, elf_size); throw; } - elf_ = std::span((uint8_t *)elf_addr, elf_size); + elf_ = std::span(reinterpret_cast(elf_addr), elf_size); // 检查 elf 头数据 auto check_elf_identity_ret = CheckElfIdentity(); @@ -67,15 +68,16 @@ class KernelElf { reinterpret_cast(elf_.data() + ehdr_.e_shoff), ehdr_.e_shnum); - auto shstrtab = - (const char *)elf_.data() + shdr_[ehdr_.e_shstrndx].sh_offset; - for (auto i : shdr_) { - if (strcmp(shstrtab + i.sh_name, ".symtab") == 0) { + const auto *shstrtab = reinterpret_cast(elf_.data()) + + shdr_[ehdr_.e_shstrndx].sh_offset; + for (auto shdr : shdr_) { + klog::Debug("sh_name: [%s]\n", shstrtab + shdr.sh_name); + if (strcmp(shstrtab + shdr.sh_name, ".symtab") == 0) { symtab_ = std::span( - reinterpret_cast(elf_.data() + i.sh_offset), - (i.sh_size / sizeof(Elf64_Sym))); - } else if (strcmp(shstrtab + i.sh_name, ".strtab") == 0) { - strtab_ = elf_.data() + i.sh_offset; + reinterpret_cast(elf_.data() + shdr.sh_offset), + (shdr.sh_size / sizeof(Elf64_Sym))); + } else if (strcmp(shstrtab + shdr.sh_name, ".strtab") == 0) { + strtab_ = elf_.data() + shdr.sh_offset; } } } @@ -90,20 +92,20 @@ class KernelElf { ~KernelElf() = default; /// @} - private: + protected: /// @name elf 文件相关 /// @{ - std::span elf_ = {}; + std::span elf_; Elf64_Ehdr ehdr_ = {}; - std::span phdr_ = {}; - std::span shdr_ = {}; + std::span phdr_; + std::span shdr_; /// @} /** * 检查 elf 标识 * @return 失败返回 false */ - [[nodiscard]] bool CheckElfIdentity() const { + [[nodiscard]] auto CheckElfIdentity() const -> bool { if ((elf_[EI_MAG0] != ELFMAG0) || (elf_[EI_MAG1] != ELFMAG1) || (elf_[EI_MAG2] != ELFMAG2) || (elf_[EI_MAG3] != ELFMAG3)) { klog::Err("Fatal Error: Invalid ELF header.\n"); @@ -121,7 +123,4 @@ class KernelElf { } }; -/// 全局 elf 对象,需要在相应体系结构初始化时重新初始化 -[[maybe_unused]] static Singleton kKernelElf; - -#endif /* SIMPLEKERNEL_SRC_KERNEL_INCLUDE_KERNEL_ELF_HPP_ */ +#endif /* SIMPLEKERNEL_SRC_INCLUDE_KERNEL_ELF_HPP_ */ diff --git a/src/include/kernel_fdt.hpp b/src/include/kernel_fdt.hpp new file mode 100644 index 000000000..ad58dc408 --- /dev/null +++ b/src/include/kernel_fdt.hpp @@ -0,0 +1,266 @@ + +/** + * @file kernel_fdt.hpp + * @brief 用于解析内核自身的 fdt 解析 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-07-15 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-07-15Zone.N (Zone.Niuzh@hotmail.com)创建文件 + *
+ */ + +#ifndef SIMPLEKERNEL_SRC_INCLUDE_KERNEL_FDT_HPP_ +#define SIMPLEKERNEL_SRC_INCLUDE_KERNEL_FDT_HPP_ + +// 禁用 GCC/Clang 的警告 +#include +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#endif + +#include + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +#include +#include +#include + +#include "kernel_log.hpp" +#include "singleton.hpp" + +/** + * fdt 相关 + */ +class KernelFdt { + public: + fdt_header *fdt_header_; + + /** + * 构造函数 + * @param fdt_addr fdt 地址 + */ + explicit KernelFdt(uint64_t header) + : fdt_header_(reinterpret_cast(header)) { + if (fdt_header_ == nullptr) { + klog::Err("Fatal Error: Invalid fdt_addr.\n"); + throw; + } + + // 检查 fdt 头数据 + if (fdt_check_header(fdt_header_) != 0) { + klog::Err("Invalid device tree blob [0x%p]\n", fdt_header_); + klog::Debug("fdt_header_->magic 0x%X\n", fdt_header_->magic); + klog::DebugBlob(fdt_header_, 32); + throw; + } + + klog::Debug("Load dtb at [0x%X], size [0x%X]\n", fdt_header_, + fdt_header_->totalsize); + } + + /// @name 构造/析构函数 + /// @{ + KernelFdt() = default; + KernelFdt(const KernelFdt &) = default; + KernelFdt(KernelFdt &&) = default; + auto operator=(const KernelFdt &) -> KernelFdt & = default; + auto operator=(KernelFdt &&) -> KernelFdt & = default; + ~KernelFdt() = default; + /// @} + + /** + * 获取 core 数量 + * @return core 数量 + */ + [[nodiscard]] auto GetCoreCount() const -> size_t { + size_t core_count = 0; + auto offset = -1; + + while (true) { + offset = fdt_next_node(fdt_header_, offset, nullptr); + if (offset < 0) { + break; + } + + const auto *prop = + fdt_get_property(fdt_header_, offset, "device_type", nullptr); + if (prop != nullptr) { + const char *device_type = reinterpret_cast(prop->data); + if (strcmp(device_type, "cpu") == 0) { + ++core_count; + } + } + } + + return core_count; + } + + /** + * 判断 psci 信息 + */ + void CheckPSCI() const { + // Find the PSCI node + auto offset = fdt_path_offset(fdt_header_, "/psci"); + if (offset < 0) { + klog::Err("Error finding /psci node: %s\n", fdt_strerror(offset)); + return; + } + + // Get the method property + int len = 0; + const auto *method_prop = + fdt_get_property(fdt_header_, offset, "method", &len); + if (method_prop == nullptr) { + klog::Err("Error finding PSCI method property\n"); + return; + } + + // Determine the method (SMC or HVC) + const char *method_str = reinterpret_cast(method_prop->data); + klog::Debug("PSCI method: %s\n", method_str); + + // 暂时只支持 smc + if (strcmp(method_str, "smc") != 0) { + klog::Err("Unsupported PSCI method: %s\n", method_str); + } + + // Log function IDs for debugging + auto assert_function_id = [&](const char *name, uint64_t value) { + const auto *prop = fdt_get_property(fdt_header_, offset, name, &len); + if (prop != nullptr && (size_t)len >= sizeof(uint32_t)) { + uint32_t id = + fdt32_to_cpu(*reinterpret_cast(prop->data)); + klog::Debug("PSCI %s function ID: 0x%X\n", name, id); + if (id != value) { + klog::Err("PSCI %s function ID mismatch: expected 0x%X, got 0x%X\n", + name, value, id); + } + } + }; + + /// @see https://developer.arm.com/documentation/den0022/fb/?lang=en + assert_function_id("cpu_on", 0xC4000003); + assert_function_id("cpu_off", 0x84000002); + assert_function_id("cpu_suspend", 0xC4000001); + } + + /** + * 获取内存信息 + * @return 内存信息<地址,长度> + */ + [[nodiscard]] auto GetMemory() const -> std::pair { + uint64_t base = 0; + uint64_t size = 0; + + int len = 0; + + // 找到 /memory 节点 + auto offset = fdt_path_offset(fdt_header_, "/memory"); + if (offset < 0) { + klog::Err("Error finding /memory node: %s\n", fdt_strerror(offset)); + throw; + } + + // 获取 reg 属性 + const auto *prop = fdt_get_property(fdt_header_, offset, "reg", &len); + if (prop == nullptr) { + klog::Err("Error finding reg property: %s\n", fdt_strerror(len)); + throw; + } + + // 解析 reg 属性,通常包含基地址和大小 + const auto *reg = reinterpret_cast(prop->data); + for (size_t i = 0; i < len / sizeof(uint64_t); i += 2) { + base = fdt64_to_cpu(reg[i]); + size = fdt64_to_cpu(reg[i + 1]); + } + return {base, size}; + } + + /** + * 获取串口信息 + * @return 内存信息<地址,长度> + */ + [[nodiscard]] auto GetSerial() const -> std::pair { + uint64_t base = 0; + uint64_t size = 0; + int len = 0; + + // Find the /chosen node + int chosen_offset = fdt_path_offset(fdt_header_, "/chosen"); + if (chosen_offset < 0) { + klog::Err("Error finding /chosen node: %s\n", + fdt_strerror(chosen_offset)); + throw; + } + + // Get the stdout-path property + const auto *prop = + fdt_get_property(fdt_header_, chosen_offset, "stdout-path", &len); + if (prop == nullptr || len <= 0) { + klog::Err("Error finding stdout-path property: %s\n", fdt_strerror(len)); + throw; + } + + // Get the path as a string + const char *stdout_path = reinterpret_cast(prop->data); + + // Create a copy of the path that we can modify + std::array path_buffer; + strncpy(path_buffer.data(), stdout_path, path_buffer.max_size()); + + // Extract the path without any parameters (everything before ':') + char *colon = strchr(path_buffer.data(), ':'); + if (colon != nullptr) { + *colon = '\0'; // Terminate the string at the colon + } + + // Find the node at the stdout path + int stdout_offset = -1; + + // Handle aliases (paths starting with '&') + if (path_buffer[0] == '&') { + const char *alias = path_buffer.data() + 1; // Skip the '&' + const char *aliased_path = fdt_get_alias(fdt_header_, alias); + if (aliased_path != nullptr) { + stdout_offset = fdt_path_offset(fdt_header_, aliased_path); + } + } else { + stdout_offset = fdt_path_offset(fdt_header_, path_buffer.data()); + } + + if (stdout_offset < 0) { + klog::Err("Error finding node for stdout-path %s: %s\n", path_buffer, + fdt_strerror(stdout_offset)); + throw; + } + + // Get the reg property of the stdout device + prop = fdt_get_property(fdt_header_, stdout_offset, "reg", &len); + if (prop == nullptr) { + klog::Err("Error finding reg property for stdout device: %s\n", + fdt_strerror(len)); + throw; + } + + // Parse the reg property to get base address and size + const auto *reg = reinterpret_cast(prop->data); + for (size_t i = 0; i < len / sizeof(uint64_t); i += 2) { + base = fdt64_to_cpu(reg[i]); + size = fdt64_to_cpu(reg[i + 1]); + } + + return {base, size}; + } +}; + +#endif /* SIMPLEKERNEL_SRC_INCLUDE_KERNEL_FDT_HPP_ */ diff --git a/src/include/kernel_log.hpp b/src/include/kernel_log.hpp new file mode 100644 index 000000000..bb21553c9 --- /dev/null +++ b/src/include/kernel_log.hpp @@ -0,0 +1,194 @@ + +/** + * @file kernel_log.hpp + * @brief 内核日志相关函数 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-07-15 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-07-15Zone.N (Zone.Niuzh@hotmail.com)创建文件 + *
+ */ + +#ifndef SIMPLEKERNEL_SRC_INCLUDE_KERNEL_LOG_HPP_ +#define SIMPLEKERNEL_SRC_INCLUDE_KERNEL_LOG_HPP_ + +#include +#include +#include +#include + +#include "config.h" +#include "singleton.hpp" +#include "sk_cstdio" +#include "sk_iostream" +#include "spinlock.hpp" + +namespace klog { +namespace detail { + +/// ANSI 转义码,在支持 ANSI 转义码的终端中可以显示颜色 +static constexpr const auto kReset = "\033[0m"; +static constexpr const auto kRed = "\033[31m"; +static constexpr const auto kGreen = "\033[32m"; +static constexpr const auto kYellow = "\033[33m"; +static constexpr const auto kBlue = "\033[34m"; +static constexpr const auto kMagenta = "\033[35m"; +static constexpr const auto kCyan = "\033[36m"; +static constexpr const auto kWhite = "\033[37m"; + +template