diff --git a/.clang-format b/.clang-format index 958f4c2f5f514a1d9460299f9aa3dbcede18aa76..f39a0e9ba92b54c4720d23e2e0f79eab145f8ea8 100644 --- a/.clang-format +++ b/.clang-format @@ -3,9 +3,15 @@ BasedOnStyle: LLVM IndentWidth: 8 UseTab: Always -BreakBeforeBraces: Linux +BreakBeforeBraces: Custom BreakBeforeBinaryOperators: NonAssignment AllowShortFunctionsOnASingleLine: Empty AllowShortIfStatementsOnASingleLine: false IndentCaseLabels: false SortIncludes: false +BinPackParameters: false +AlignAfterOpenBracket: Align +BraceWrapping: + AfterControlStatement: false + AfterFunction: true +Cpp11BracedListStyle: false diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 80d96932aa86b141990e251da6919bacb3e43b65..0000000000000000000000000000000000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,95 +0,0 @@ -# https://help.github.com/articles/about-codeowners/ - -# These owners are the default owners for all Unikraft core files. -* @unikraft/maintainers-core - -# These owners oversee the core parts of Unikraft. -/lib/isrlib @unikraft/maintainers-core -/lib/nolibc @unikraft/maintainers-core -/lib/posix-libdl @unikraft/maintainers-core -/lib/posix-sysinfo @unikraft/maintainers-core -/lib/syscall_shim @unikraft/maintainers-core -/lib/ukargparse @unikraft/maintainers-core -/lib/ukboot @unikraft/maintainers-core -/lib/uklibparam @unikraft/maintainers-core -/lib/ukring @unikraft/maintainers-core -/lib/uksglist @unikraft/maintainers-core -/lib/ukstore @unikraft/maintainers-core -/lib/uktime @unikraft/maintainers-core -/lib/uktimeconv @unikraft/maintainers-core - -# These owners oversee the APIs. -/arch/*/*/include @unikraft/maintainers-api -/arch/*/include @unikraft/maintainers-api -/include @unikraft/maintainers-api -/plat/include @unikraft/maintainers-api - -# These owners oversee all architectures. -/arch @unikraft/maintainers-arch - -# These owners oversee the ARM architecture. -/arch/arm @unikraft/maintainers-arch-arm -/lib/fdt @unikraft/maintainers-arch-arm -/plat/*/arm @unikraft/maintainers-arch-arm -/plat/*/include/*-arm @unikraft/maintainers-arch-arm - -# These owners oversee the x86 architecture. -/arch/x86 @unikraft/maintainers-arch-x86 -/plat/*/include/*-x86 @unikraft/maintainers-arch-x86 -/plat/*/x86 @unikraft/maintainers-arch-x86 - -# These owners oversee all platforms. -/plat @unikraft/maintainers-plat - -# These owners oversee the KVM platform. -/plat/kvm @unikraft/maintainers-plat-kvm - -# These owners oversee the scheduler-related components. -/lib/posix-process @unikraft/maintainers-sched -/lib/uklock @unikraft/maintainers-sched -/lib/ukmpi @unikraft/maintainers-sched -/lib/uksched* @unikraft/maintainers-sched -/lib/uksignal @unikraft/maintainers-sched - -# These owners oversee the memory manangement-related components. -/lib/ukalloc* @unikraft/maintainers-mem -/lib/ukfalloc* @unikraft/maintainers-mem -/lib/ukmmap @unikraft/maintainers-mem - -# These owners oversee the security-related components. -/lib/ubsan @unikraft/maintainers-security -/lib/uksp @unikraft/maintainers-security -/lib/ukswrand @unikraft/maintainers-security - -# These owners oversee the network-related components. -/lib/uknetdev @unikraft/maintainers-net - -# These owners oversee the filesystem-related components. -/lib/9pfs @unikraft/maintainers-fs -/lib/devfs @unikraft/maintainers-fs -/lib/posix-user @unikraft/maintainers-fs -/lib/ramfs @unikraft/maintainers-fs -/lib/uk9p @unikraft/maintainers-fs -/lib/ukblkdev @unikraft/maintainers-fs -/lib/ukcpio @unikraft/maintainers-fs -/lib/vfscore @unikraft/maintainers-fs - -# These owners oversee the device-related components. -/lib/ukbus @unikraft/maintainers-device - -# These owners oversee the build system. -/lib/Config.uk @unikraft/maintainers-build -/lib/Makefile.uk @unikraft/maintainers-build -/Makefile @unikraft/maintainers-build -/Makefile.uk @unikraft/maintainers-build -/support @unikraft/maintainers-build - -# These owners oversee the debugging support. -/lib/ukdebug @unikraft/maintainers-debug - -# These owners oversee internal use of Rust within Unikraft. -/lib/ukrust @unikraft/maintainers-lang-rust - -# These owners oversee testing within Unikraft. -/lib/uktest @unikraft/maintainers-test -tests/test_* @unikraft/maintainers-test diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index b6e4148a4edae2d642d0085a623c5ee707a03340..0000000000000000000000000000000000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: 🐞 Report a bug -description: Create a bug report about unexpected behavior. -labels: [kind/bug] -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this bug report! - - Please only use this form to submit problems with builds or the runtime of Unikraft unikernels. This includes unexpected or undefined behavior, stacktraces, critical messages, and things just breaking or exploding. - - **Ensure you have tested against the latest changes on `staging` branch before submitting this form.** - - For questions, concerns or help with running Unikraft, please check out our additional resources: - - * [Unikraft Documentation](https://docs.unikraft.org) - * [Getting Started Guide](https://unikraft.org/getting-started) - * [Unikraft Discussions Forum](https://github.com/unikraft/unikraft/discussions) - - type: textarea - id: bug-description - attributes: - label: Describe the bug - description: Please provide a clear and concise description of the bug. - validations: - required: true - - type: textarea - id: steps-to-reproduce - attributes: - label: Steps to reproduce - description: Please provide the steps necessary to reproduce the behavior, for example the command used to run the unikernel, or the sequence of actions, auxiliary components, networking setup, etc. leading up to the error or bug. Please also include any options you set during the configuration step. - placeholder: | - For example, I enabled these options: - - - `CONFIG_LIB9PFS=y` - - ... - validations: - required: false - - type: textarea - id: expected-behavior - attributes: - label: Expected behavior - description: A clear and concise description of what you expected to happen. - placeholder: For example, I expected the unikernel to boot and print "Hello, world!" - validations: - required: false - - type: dropdown - id: architectures - attributes: - label: Which architectures were you using or does this bug affect? - description: If this bug is architecture agnostic or you are unsure then please do not select an architecture listed below. - multiple: true - options: - - x86_64 - - arm - - arm64 - - type: dropdown - id: platforms - attributes: - label: Which platforms were you using or does this bug affect? - description: If this bug is platform agnostic or you are unsure then please do not select an platform listed below. If this affects an external platform (i.e. one in a separate repository) then please open the bug report in the relevant repository. - multiple: true - options: - - kvm - - xen - - linuxu - - type: textarea - id: logs - attributes: - label: Relevant log output - description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. - render: shell diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index d9f879d57b1c69b82793eb053347b93144b456da..0000000000000000000000000000000000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,6 +0,0 @@ -blank_issues_enabled: false - -contact_links: - - name: 💡 Discuss an idea - url: https://github.com/unikraft/unikraft/discussions/new - about: Discuss a feature or usecase which Unikraft could support. diff --git a/.github/ISSUE_TEMPLATE/project_backlog.yml b/.github/ISSUE_TEMPLATE/project_backlog.yml deleted file mode 100644 index ae79f1c148a5508dd26fced71aab62f32274824a..0000000000000000000000000000000000000000 --- a/.github/ISSUE_TEMPLATE/project_backlog.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: 📥 Add to the backlog -description: Create an issue for new work to be done which has been discussed. -labels: [kind/enhancement] -body: - - type: markdown - attributes: - value: | - Please only use this form to submit new, well-defined work to the Unikraft project's backlog. Issues under this category have been discussed with the core team. - - If you're intending to request a feature, please [open a discussion using the "Ideas" category](https://github.com/unikraft/unikraft/discussions/new) instead so we can understand your workflow first. If you are unsure about a feature, please [check out our documentation](https://docs.unikraft.org/) which covers existing features and possibilities with Unikraft or filter existing issues labelled under [`kind/enhancement`](https://github.com/unikraft/unikraft/labels/kind/enhancement) to prevent double-posting. - - type: textarea - id: feature-request-summary - attributes: - label: Feature request summary - description: Please provide a quick summary which clearly and concisely describes the feature. For example, highlights of new functionality; proposal of a new architecture or platform; additions to documentation; etc. - validations: - required: true - - type: textarea - id: alternatives - attributes: - label: Describe alternatives - description: A clear and concise description of any alternative solutions or features considered. - validations: - required: false - - type: dropdown - id: related-architectures - attributes: - label: Related architectures - description: Please indicate whether the feature request is related to a specific architecture. If this feature is architecture agnostic or you are unsure then please do not select an architecture listed below. - multiple: false - options: - - x86_64 - - arm - - arm64 - - type: dropdown - id: related-platforms - attributes: - label: Related platforms - description: Please indicate whether the feature request is related to a specific platform. If this feature is platform agnostic or you are unsure then please do not select an platform listed below. - multiple: false - options: - - kvm - - xen - - linuxu - - type: textarea - id: additional-context - attributes: - label: Additional context - description: Add any other context, longer descriptions, screenshot/mock-ups, or links to related material about the feature request. - validations: - required: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 597240d0c0ae2780991f372f002c0a19d2f205c5..0000000000000000000000000000000000000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,46 +0,0 @@ - - -### Prerequisite checklist - - - - - [ ] Read the [contribution guidelines](https://unikraft.org/docs/contributing/) regarding submitting new changes to the project; - - [ ] Tested your changes against relevant architectures and platforms; - - [ ] Ran the [`checkpatch.uk`](https://github.com/unikraft/unikraft/blob/staging/support/scripts/checkpatch.uk) on your commit series before opening this PR; - - [ ] Updated relevant documentation. - - -### Base target - - - Architecture(s): [e.g. `x86_64` or N/A] - - Platform(s): [e.g. `kvm` or N/A] - - Application(s): [e.g. `app-python3` or N/A] - - -### Additional configuration - - - -### Description of changes - - diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 03043f4906e997db7347241cf0da0a20bee1f994..0000000000000000000000000000000000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,11 +0,0 @@ -version: 2 - -updates: - - package-ecosystem: github-actions - directory: / - schedule: - interval: monthly - day: sunday - time: '09:00' - commit-message: - prefix: ".github/workflows" diff --git a/.github/labels/arch.yaml b/.github/labels/arch.yaml deleted file mode 100644 index bc0728686e8fb8eb658f3217b31a727358b52387..0000000000000000000000000000000000000000 --- a/.github/labels/arch.yaml +++ /dev/null @@ -1,25 +0,0 @@ -labels: - - name: arch/arm - description: Issues and PRs related to ARM architecture - color: "#1d76db" - apply_on_pr_match_paths: - - arch/arm/** - - plat/common/arm/** - - plat/common/include/arm/** - - - name: arch/arm64 - description: Issues and PRs related to ARM 64-bit architecture - color: "#1d76db" - apply_on_pr_match_paths: - - arch/arm/arm64/** - - plat/common/arm/*64.S - - plat/common/arm/*64.c - - plat/common/include/arm/arm64/** - - - name: arch/x86_64 - description: Issues and PRs related to Intel x86_64 architecture - color: "#c5def5" - apply_on_pr_match_paths: - - arch/x86/** - - plat/common/x86/** - - plat/common/include/x86/** diff --git a/.github/labels/area.yaml b/.github/labels/area.yaml deleted file mode 100644 index 55488027bff50b8bdb8336d671e62b4a46f4cfa1..0000000000000000000000000000000000000000 --- a/.github/labels/area.yaml +++ /dev/null @@ -1,58 +0,0 @@ -labels: - - name: area/arch - description: Issues and PRs which affect architecture code - color: "#7ec2f7" - apply_on_pr_match_paths: - - arch/** - - - name: area/docs - description: Issues and PRs which affect documentation - color: "#db4eb8" - apply_on_pr_match_paths: - - doc/** - - README.md - - - name: area/exportsyms - description: Issue or PR relates to exporting symbols from a library - color: "#f9822c" - apply_on_pr_match_paths: - - exportsyms.uk - - - name: area/include - description: Issues and PRs which affect headers - color: "#e99695" - apply_on_pr_match_paths: - - include/** - - - name: area/kconfig - description: Issues and PRs which affect KConfig code - color: "#ed8ebd" - apply_on_pr_match_paths: - - Config.uk - - - name: area/lib - description: Issues and PRs which affect internal Unikraft libraries - color: "#ed8ebd" - match_repos: - - unikraft - apply_on_pr_match_paths: - - lib/** - - - name: area/makefile - description: Issues and PRs which affect Makefile code - color: "#ffe5c9" - apply_on_pr_match_paths: - - Makefile.uk - - Makefile - - - name: area/plat - description: Issues and PRs which affect platform code - color: "#f2daa9" - apply_on_pr_match_paths: - - plat/** - - - name: area/support - description: Issues and PRs which affect support code - color: "#bfd4f2" - apply_on_pr_match_paths: - - suuport/** diff --git a/.github/labels/arm.yaml b/.github/labels/arm.yaml deleted file mode 100644 index d7b448463f8a6890ac79925c5de2141999541097..0000000000000000000000000000000000000000 --- a/.github/labels/arm.yaml +++ /dev/null @@ -1,8 +0,0 @@ -labels: - - name: arm/smcc - description: Secure Monitor Call Calling Convention on ARM - color: "#0BA2F3" - apply_on_pr_match_paths: - - include/uk/arch/arm/smccc.h - - plat/common/arm/smccc.c - - plat/common/arm/smccc_invoke.S diff --git a/.github/labels/bug.yaml b/.github/labels/bug.yaml deleted file mode 100644 index 4748b9a63ebf6ff549570e9cc021112cf6e499c8..0000000000000000000000000000000000000000 --- a/.github/labels/bug.yaml +++ /dev/null @@ -1,16 +0,0 @@ -labels: - - name: bug/compile-time - description: Bug occurs during compile-time - color: "#ed5139" - - - name: bug/link-time - description: Bug occurs during link-time - color: "#884239" - - - name: bug/runtime - description: Bug occurs during runtime - color: "#4d2a25" - - - name: bug/fix - description: This PR fixes a bug - color: "#4bcc7a" diff --git a/.github/labels/ci.yaml b/.github/labels/ci.yaml deleted file mode 100644 index 088cd78b19b8ac242cf559aaa071da327974bed4..0000000000000000000000000000000000000000 --- a/.github/labels/ci.yaml +++ /dev/null @@ -1,8 +0,0 @@ -labels: - - name: ci/merged - description: Merged by CI - color: "#d4c5f9" - - - name: ci/wait - description: Tell the CI system to wait before performing any action. - color: "#e99695" diff --git a/.github/labels/kind.yaml b/.github/labels/kind.yaml deleted file mode 100644 index 10d5695595baf1e30a432d10a31edd736fba9199..0000000000000000000000000000000000000000 --- a/.github/labels/kind.yaml +++ /dev/null @@ -1,28 +0,0 @@ -labels: - - name: kind/bug - description: Something isn't working - color: "#d73a4a" - - - name: kind/enhancement - description: Issues and PRs related to increasing functionality - color: "#a2eeef" - - - name: kind/maintenance - description: Chores and meta-tasks - color: "#a295d6" - - - name: kind/project - description: Issue is a substantial contribution - color: "#008672" - - - name: kind/proposal - description: Issue discusses potential new feature or change - color: "#dd75c0" - - - name: kind/question - description: Issue asks a question - color: "#e99695" - - - name: kind/quick-fix - description: Issue or PR is related to a quick fix - color: "#1daf6b" diff --git a/.github/labels/lang.yaml b/.github/labels/lang.yaml deleted file mode 100644 index 4f7f2fe74863555e75275fdd85f5a5e80085f0e9..0000000000000000000000000000000000000000 --- a/.github/labels/lang.yaml +++ /dev/null @@ -1,66 +0,0 @@ -labels: - - name: lang/c - description: Issues or PRs which affect code written in C - color: "#bbbbbb" - apply_on_pr_match_paths: - - "**/*\\.c" - - - name: lang/cpp - description: Issues or PRs which affect code written in C++ - color: "#bbbbbb" - apply_on_pr_match_paths: - - "**/*\\.cpp" - - - name: lang/d - description: Issues or PRs which affect code written in Dlang - color: "#9f2725" - apply_on_pr_match_paths: - - "**/*\\.d" - - - name: lang/go - description: Issues or PRs which affect code written in Golang - color: "#58c7d6" - apply_on_pr_match_paths: - - "**/*\\.go" - - - name: lang/javascript - description: Issues or PRs which affect code written in JavaScript - color: "#e1cf27" - apply_on_pr_match_paths: - - "**/*\\.js" - - - name: lang/lua - description: Issues or PRs which affect code written in Lua - color: "#000069" - apply_on_pr_match_paths: - - "**/*\\.lua" - - - name: lang/php - description: Issues or PRs which affect code written in PHP - color: "#60619d" - apply_on_pr_match_paths: - - "**/*\\.php" - - - name: lang/python - description: Issues or PRs which affect code written in Python - color: "#2b5f95" - apply_on_pr_match_paths: - - "**/*\\.py" - - - name: lang/ruby - description: Issues or PRs which affect code written in Ruby - color: "#a80007" - apply_on_pr_match_paths: - - "**/*\\.rb" - - - name: lang/rust - description: Issues or PRs which affect code written in Rust - color: "#8a4521" - apply_on_pr_match_paths: - - "**/*\\.rs" - - - name: lang/wamr - description: Issues or PRs which affect code written in WAMR - color: "#5130ec" - apply_on_pr_match_paths: - - "**/*\\.wamr" diff --git a/.github/labels/lib.yaml b/.github/labels/lib.yaml deleted file mode 100644 index 684f2d6c5797e6ce6deb475bb82ccaa9d5ea62e2..0000000000000000000000000000000000000000 --- a/.github/labels/lib.yaml +++ /dev/null @@ -1,228 +0,0 @@ -labels: - - name: lib/9pfs - description: Issues and PRs which affect the 9p filesystem - color: "#fbca04" - apply_on_pr_match_paths: - - lib/9pfs/** - - - name: lib/devfs - description: Issues and PRs which affect the devfs file system - color: "#fbca04" - apply_on_pr_match_paths: - - lib/devfs/** - - - name: lib/fdt - description: Issues and PRs which affect Flat Device Tree manipulation - color: "#fbca04" - apply_on_pr_match_paths: - - lib/fdt/** - - - name: lib/isrlib - description: Issues and PRs which affect interrupt-safe standard routines - color: "#fbca04" - apply_on_pr_match_paths: - - lib/isrlib/** - - - name: lib/nolibc - description: Issues and PRs which affect the nolibc subset - color: "#fbca04" - apply_on_pr_match_paths: - - lib/nolibc/** - - - name: lib/posix-libdl - description: Issues and PRs which affect POSIX libdl library - color: "#fbca04" - apply_on_pr_match_paths: - - lib/posix-libdl/** - - - name: lib/posix-process - description: Issues and PRs which affect POSIX process-related functions - color: "#fbca04" - apply_on_pr_match_paths: - - lib/posix-process/** - - - name: lib/posix-sysinfo - description: Issues and PRs which affect information about system parameters - color: "#fbca04" - apply_on_pr_match_paths: - - lib/posix-sysinfo/** - - - name: lib/posix-user - description: Issues and PRs which affect POSIX user-related functions - color: "#fbca04" - apply_on_pr_match_paths: - - lib/posix-user/** - - - name: lib/ramfs - description: Issues and PRs which affect the simple RAM file system - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ramfs/** - - - name: lib/syscall_shim - description: Issues and PRs which affect the syscall shim layer - color: "#fbca04" - apply_on_pr_match_paths: - - lib/syscall_shim/** - - - name: lib/ubsan - description: Issues and PRs which affect Undefined Behavior Sanitization - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ubsan/** - - - name: lib/uk9p - description: Issues and PRs which affect the 9p client - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uk9p/** - - - name: lib/ukalloc - description: Issues and PRs which affect the binary buddy page allocator - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukalloc/** - - - name: lib/ukallocbbuddy - description: Issues and PRs which affect the abstraction for memory allocators - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukallocbbuddy/** - - - name: lib/ukallocpool - description: Issues and PRs which affect the memory pool allocator - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukallocpool/** - - - name: lib/ukallocregion - description: Issues and PRs which affect the region-based allocator - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukallocregion/** - - - name: lib/ukargparse - description: Issues and PRs which affect the simple argument parser - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukargparse/** - - - name: lib/ukblkdev - description: Issues and PRs which affect the block driver interface - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukblkdev/** - - - name: lib/ukboot - description: Issues and PRs which affect the Unikraft bootstrapping code - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukboot/** - - - name: lib/ukbus - description: Issues and PRs which affect the abstraction for device buses - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukbus/** - - - name: lib/ukcpio - description: Issues and PRs which affect CPIO archive extraction - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukcpio/** - - - name: lib/ukdebug - description: Issues and PRs which affect debugging and tracing - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukdebug/** - - - name: lib/uklibparam - description: Issues and PRs which affect the library arguments parser - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uklibparam/** - - - name: lib/uklock - description: Issues and PRs which affect multi-task synchronization primitives - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uklock/** - - - name: lib/ukmmap - description: Issues and PRs which affect mmap system call - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukmmap/** - - - name: lib/ukmpi - description: Issues and PRs which affect the Message Passing Interface - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukmpi/** - - - name: lib/uknetdev - description: Issues and PRs which affect the network driver interface - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uknetdev/** - - - name: lib/ukring - description: Issues and PRs which affect the ring buffer interface - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukring/** - - - name: lib/uksched - description: Issues and PRs which affect the abstraction for schedulers - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uksched/** - - - name: lib/ukschedcoop - description: Issues and PRs which affect the cooperative Round-Robin scheduler - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukschedcoop/** - - - name: lib/uksglist - description: Issues and PRs which affect the Scatter Gather List - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uksglist/** - - - name: lib/uksignal - description: Issues and PRs which affect Unikraft signals - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uksignal/** - - - name: lib/uksp - description: Issues and PRs which affect the stack protector - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uksp/** - - - name: lib/ukswrand - description: Issues and PRs which affect the software random number generator - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukswrand/** - - - name: lib/uktime - description: Issues and PRs which affect time functions - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uktime/** - - - name: lib/uktimeconv - description: Issues and PRs which affect time conversion functions - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uktimeconv/** - - - name: lib/vfscore - description: Issues and PRs which affect VFS Core interface - color: "#fbca04" - apply_on_pr_match_paths: - - lib/vfscore/** diff --git a/.github/labels/lifecycle.yaml b/.github/labels/lifecycle.yaml deleted file mode 100644 index 93c6bc1946886f406cf859579f5e7c201e9851f0..0000000000000000000000000000000000000000 --- a/.github/labels/lifecycle.yaml +++ /dev/null @@ -1,27 +0,0 @@ -labels: - - name: lifecycle/active - description: Indicates that an issue or PR is actively being worked on by a contributor - color: "#8ee234" - apply_after: 0s - remove_after: 720h # 30 days - do_not_remove_if_labels_exist: - - lifecycle/frozen - - - name: lifecycle/stale - description: Denotes an issue or PR has remained open with no activity and has become stale - color: "#795548" - apply_after: 720h # 30 days - remove_after: 4320h # 180 days - do_not_remove_if_labels_exist: - - lifecycle/frozen - - - name: lifecycle/rotten - description: Denotes an issue or PR that has aged beyond stale and will be auto-closed - color: "#795548" - apply_after: 4320h # 180 days - do_not_remove_if_labels_exist: - - lifecycle/frozen - - - name: lifecycle/frozen - description: Indicates that an issue or PR should not be auto-closed due to staleness - color: "#b2fff6" diff --git a/.github/labels/misc.yaml b/.github/labels/misc.yaml deleted file mode 100644 index 87653d0c91bbfa14c75c8bc7700863accc54d614..0000000000000000000000000000000000000000 --- a/.github/labels/misc.yaml +++ /dev/null @@ -1,12 +0,0 @@ -labels: - - name: good-first-issue - description: Good for newcomers - color: "#7057ff" - - - name: patchwork-backlog - description: Migrated from patchwork.unikraft.org - color: "#bfd4f2" - - - name: release-note - description: Issue or PR can aid in creating a release note - color: "#c2e0c6" diff --git a/.github/labels/needs.yaml b/.github/labels/needs.yaml deleted file mode 100644 index c782d00ed10319c569a70c8b79dac7a94c6a033e..0000000000000000000000000000000000000000 --- a/.github/labels/needs.yaml +++ /dev/null @@ -1,12 +0,0 @@ -labels: - - name: needs/documentation - description: Issue or PR needs additional documentation - color: "#d4c5f9" - - - name: needs/rebase - description: Indicates a PR cannot be merged because it has merge conflicts with HEAD - color: "#2e20c1" - apply_when: - - needs_rebase - remove_when: - - no_rebase diff --git a/.github/labels/new.yaml b/.github/labels/new.yaml deleted file mode 100644 index 57612a3626e73c195a75aa6b22ac39e3b1653be0..0000000000000000000000000000000000000000 --- a/.github/labels/new.yaml +++ /dev/null @@ -1,24 +0,0 @@ -labels: - - name: new/library - description: Issues and PRs related to a new library - color: "#7bdb48" - - - name: new/metric - description: Issues and PRs related to a new metric - color: "#7bdb48" - - - name: new/posix-function - description: Issues and PRs related to a new POSIX function - color: "#7bdb48" - - - name: new/primitive - description: Issues and PRs related to a new primitive - color: "#7bdb48" - - - name: new/syscall - description: Issues and PRs related to a new syscall - color: "#7bdb48" - - - name: new/test - description: Issues and PRs related to a new test - color: "#7bdb48" diff --git a/.github/labels/plat.yaml b/.github/labels/plat.yaml deleted file mode 100644 index 211b5e95b6386c718095fda6e71f316d16de3633..0000000000000000000000000000000000000000 --- a/.github/labels/plat.yaml +++ /dev/null @@ -1,84 +0,0 @@ -labels: - - name: plat/common - description: Issues and PRs related to all platforms - color: "#1d76db" - apply_on_pr_match_paths: - - plat/common/** - - include/uk/plat/common/** - - - name: plat/driver/tap - description: Issues and PRs related to the tap driver - color: "#750210" - apply_on_pr_match_paths: - - plat/drivers/tap/** - - plat/drivers/include/tap/** - - plat/linuxu/tap_io.c - - - name: plat/driver/virtio - description: Issues and PRs related to virtio drivers - color: "#750210" - apply_on_pr_match_paths: - - plat/drivers/virtio/** - - plat/drivers/include/virtio/** - - - name: plat/driver/ofw - description: Issues and PRs related to open firmware drivers - color: "#750210" - apply_on_pr_match_paths: - - plat/drivers/ofw/** - - plat/drivers/include/ofw/** - - - name: plat/driver/gic - description: Issues and PRs related to the GIC driver - color: "#750210" - apply_on_pr_match_paths: - - plat/drivers/gic/** - - plat/drivers/include/gic/** - - - name: plat/driver/pci - description: Issues and PRs related to PCI driver - color: "#750210" - apply_on_pr_match_paths: - - plat/common/include/pci/** - - - name: plat/driver/9p - description: Issues and PRs related to 9p driver - color: "#750210" - apply_on_pr_match_paths: - - plat/*/include/9p/** - - - name: plat/driver/net - description: Issues and PRs related to network driver - color: "#750210" - apply_on_pr_match_paths: - - plat/*/include/net/** - - - name: plat/driver/blk - description: Issues and PRs related to block driver - color: "#750210" - apply_on_pr_match_paths: - - plat/*/include/blk/** - - - name: plat/driver - description: Issues and PRs related to platform drivers - color: "#750210" - apply_on_pr_match_paths: - - plat/drivers/** - - - name: plat/kvm - description: Issues and PRs related to KVM platform - color: "#1f8aa5" - apply_on_pr_match_paths: - - plat/kvm/** - - - name: plat/linuxu - description: Issues and PRs related to Linux Userspace platform - color: "#bfdadc" - apply_on_pr_match_paths: - - plat/linux/** - - - name: plat/xen - description: ssues and PRs related to the Xen platform - color: "#4da81f" - apply_on_pr_match_paths: - - plat/xen/** diff --git a/.github/labels/priority.yaml b/.github/labels/priority.yaml deleted file mode 100644 index f769ce4ec84a25f7a3e786e18bda97e3af868814..0000000000000000000000000000000000000000 --- a/.github/labels/priority.yaml +++ /dev/null @@ -1,16 +0,0 @@ -labels: - - name: priority/high - description: Issues and PRs which have a high priority - color: "#d93f0b" - - - name: priority/medium - description: Issues and PRs which have priority - color: "#eb9e34" - - - name: priority/low - description: Issues and PRs which have a very low priority - color: "#A1CBD2" - - - name: priority/nice-to-have - description: Issues and PRs which have a very low priority - color: "#FD93AC" diff --git a/.github/labels/state.yaml b/.github/labels/state.yaml deleted file mode 100644 index 3cdbca6104cc1be5a851c4e63b3f68d0fc33d3bd..0000000000000000000000000000000000000000 --- a/.github/labels/state.yaml +++ /dev/null @@ -1,28 +0,0 @@ -labels: - - name: state/accepted - description: Issue or PR has been accepted - color: "#BBFD97" - - - name: state/action-required - description: Issue or PR requires external change to occur before proceeding - color: "#006b75" - - - name: state/changes-requested - description: Issue or PR requires a change to proceed - color: "#FA7505" - - - name: state/deferred - description: Issue or PR has been deferred - color: "#763F27" - - - name: state/not-applicable - description: Issue or PR is not applicable - color: "#52544A" - - - name: state/rejected - description: Sadly this issue or PR cannot be accepted - color: "#E93303" - - - name: state/superceded - description: Issue or PR is no longer applicable - color: "#5024E8" diff --git a/.github/labels/topic.yaml b/.github/labels/topic.yaml deleted file mode 100644 index c13561cc72676999dc097acb0d6a49b2ee194209..0000000000000000000000000000000000000000 --- a/.github/labels/topic.yaml +++ /dev/null @@ -1,60 +0,0 @@ -labels: - - name: topic/booting - description: Issue or PR pertaining to the boot process - color: "#c5def5" - - - name: topic/build - description: Issue or PR pertaining to the build system - color: "#c5def5" - - - name: topic/ci - description: Issue or PR pertaining to CI/CD - color: "#c5def5" - - - name: topic/concurrency - description: Issue or PR pertaining to concurrency - color: "#c5def5" - - - name: topic/irq - description: Issue or PR pertaining to IRQs - color: "#c5def5" - - - name: topic/metrics - description: Issue or PR pertaining to metrics - color: "#c5def5" - - - name: topic/mm - description: Issue or PR pertaining to memory management - color: "#c5def5" - - - name: topic/mpk - description: Issue or PR pertaining to Memory Protection Keys (MPKs) - color: "#c5def5" - - - name: topic/posix - description: Issue or PR pertaining to POSIX - color: "#c5def5" - - - name: topic/primitive - description: Issue or PR pertaining to Unikraft primitives - color: "#c5def5" - - - name: topic/scheduling - description: Issue or PR pertaining to scheduling - color: "#c5def5" - - - name: topic/smp - description: Issue or PR pertaining to SMP - color: "#c5def5" - - - name: topic/syscall - description: Issue or PR pertaining to syscalls - color: "#c5def5" - - - name: topic/threading - description: Issue or PR pertaining to threading - color: "#c5def5" - - - name: topic/tls - description: Issue or PR pertaining to Thread Local Storage (TLS) - color: "#c5def5" diff --git a/.github/workflows/actcheck.yaml b/.github/workflows/actcheck.yaml deleted file mode 100644 index 292fdc01745b7719e3cf439e14d9e8d522db3778..0000000000000000000000000000000000000000 --- a/.github/workflows/actcheck.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: actionlint - -on: - pull_request: - types: [opened, synchronize, reopened] - branches: [staging] - paths: - - '.github/workflows/**' - -jobs: - action-lint: - runs-on: ubuntu-latest - name: Action Lint - steps: - - uses: actions/checkout@v4 - - - name: Install action linter - run: | - mkdir -p "$HOME"/.local/bin - curl -sL https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash | bash -s -- latest "$HOME"/.local/bin - - - name: Check that all workflows are valid - run: actionlint -verbose diff --git a/.github/workflows/checkpatch.yaml b/.github/workflows/checkpatch.yaml deleted file mode 100644 index ae80c29b5caa96726e2f08a7a2f1d9a52df8d846..0000000000000000000000000000000000000000 --- a/.github/workflows/checkpatch.yaml +++ /dev/null @@ -1,29 +0,0 @@ -name: checkpatch - -on: - pull_request: - types: [opened, synchronize, reopened] - branches: [staging] - -jobs: - checkpatch: - runs-on: ubuntu-latest - name: checkpatch - steps: - - name: Install governctl - run: | - set -xe - wget -q "https://github.com/unikraft/governance/releases/download/v${GOVERN_VERSION}/governance_${GOVERN_VERSION}_linux_amd64.deb" - sudo dpkg -i "governance_${GOVERN_VERSION}_linux_amd64.deb" - env: - GOVERN_VERSION: 0.1.7 - - - name: Run checkpatch through governctl - run: governctl pr check patch --ignore ${GOVERN_IGNORES} unikraft/unikraft/${PR_NUMBER} - env: - PR_NUMBER: ${{ github.event.number }} - GOVERN_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GOVERN_GITHUB_USER: ${{ secrets.GH_CHECKPATCH_ACTOR }} - GOVERN_NO_RENDER: true - GOVERN_LOG_LEVEL: warn - GOVERN_IGNORES: FILE_PATH_CHANGES,OBSOLETE,ASSIGN_IN_IF,NEW_TYPEDEFS,EMAIL_SUBJECT diff --git a/.github/workflows/commit-format-check.yaml b/.github/workflows/commit-format-check.yaml deleted file mode 100644 index 6d50fa2f4abb448bcdfb89a787d15245efb1cc04..0000000000000000000000000000000000000000 --- a/.github/workflows/commit-format-check.yaml +++ /dev/null @@ -1,72 +0,0 @@ -name: Commits Formatting Check - -on: - push: - branches: [staging, stable] - pull_request: - types: [opened, synchronize, reopened] - branches: [staging] - -jobs: - commit: - name: Commit and PR Format Check - runs-on: ubuntu-latest - steps: - - name: Commit Lines Length Check - if: ${{ github.actor != 'dependabot' && github.actor != 'dependabot[bot]' }} - uses: gsactions/commit-message-checker@v2 - with: - pattern: '((^(?=(?:.|\n)*(?:^|\n)\[\d\]: .{69,}(?:$|\n)(?:.|\n)*)(?:.|\n)*$)|(^(?!(?:.|\n)*(?:^|\n).{74,}(?:$|\n)(?:.|\n)*)(?:.|\n)*$))' - flags: '' - error: 'The maximum line length of 74 characters is exceeded.' - excludeDescription: 'true' - excludeTitle: 'true' - checkAllCommitMessages: 'true' - accessToken: ${{ secrets.GITHUB_TOKEN }} - - - name: Signed-off-by Check - if: always() - uses: gsactions/commit-message-checker@v2 - with: - pattern: '^Signed-off-by: .+ \<.+\@.+\..+\>$' - error: 'Signed-off-by line is missing.' - excludeDescription: 'true' - excludeTitle: 'true' - checkAllCommitMessages: 'true' - accessToken: ${{ secrets.GITHUB_TOKEN }} - - - name: PR Title Check - if: always() - uses: gsactions/commit-message-checker@v2 - with: - pattern: '^((([a-z0-9\/\.\-\_\*])+)|(\{([a-z0-9\/\.\-\_\*]+, )+[a-z0-9\/\.\-\_\*]+\})){1}: [A-Z0-9].*' - error: 'The PR title must follow the conventional commits format.' - excludeDescription: 'true' - excludeTitle: 'false' - checkAllCommitMessages: 'false' - accessToken: ${{ secrets.GITHUB_TOKEN }} - - - name: PR Title Check Length - if: ${{ github.actor != 'dependabot' && github.actor != 'dependabot[bot]' }} - uses: gsactions/commit-message-checker@v2 - with: - pattern: '^(?!.{75,}).*' - flags: '' - error: 'The maximum line length of 75 characters is exceeded.' - excludeDescription: 'true' - excludeTitle: 'false' - checkAllCommitMessages: 'false' - accessToken: ${{ secrets.GITHUB_TOKEN }} - - - name: PR Description Check - if: ${{ github.actor != 'dependabot' && github.actor != 'dependabot[bot]' }} - uses: gsactions/commit-message-checker@v2 - with: - pattern: '^\S+( \S+)*$' - error: 'The PR description must not be empty.' - flags: 'gm' - excludeDescription: 'false' - excludeTitle: 'true' - checkAllCommitMessages: 'false' - accessToken: ${{ secrets.GITHUB_TOKEN }} - diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml deleted file mode 100644 index 2d31222c1a42ab5e3476d76f16cf4a1ab06803ed..0000000000000000000000000000000000000000 --- a/.github/workflows/integration.yaml +++ /dev/null @@ -1,193 +0,0 @@ -name: integration - -on: - push: - branches: [staging, stable] - paths-ignore: ['*.md'] - - pull_request: - types: [opened, synchronize, reopened] - branches: [staging] - paths-ignore: ['*.md'] - -jobs: - libc-test: - name: libc-test - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - plat: qemu - arch: x86_64 - - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - - name: Fetch helloworld - uses: actions/checkout@v3 - with: - repository: unikraft/app-helloworld - fetch-depth: 1 - path: _helloworld - - - name: Build and run libc-test via uktest - uses: unikraft/kraftkit@staging - with: - loglevel: debug - workdir: _helloworld - plat: ${{ matrix.plat }} - arch: ${{ matrix.arch }} - execute: true - kraftfile: | - specification: '0.5' - name: helloworld - unikraft: - source: ../ - kconfig: - CONFIG_LIBUKTEST: "y" - CONFIG_LIBUKTEST_ALL: "n" - CONFIG_LIBUKTEST_TEST_MYSELF: "n" - CONFIG_LIBUKTEST_LOG_STATS: "y" - CONFIG_LIBUKDEBUG_ANSI_COLOR: "y" - CONFIG_LIBUKDEBUG_PRINTK_INFO: "y" - CONFIG_LIBDEVFS: "y" - CONFIG_LIBDEVFS_DEV_STDOUT: "y" - CONFIG_LIBDEVFS_DEV_NULL_ZERO: "y" - CONFIG_LIBDEVFS_DEV_ZERO: "y" - CONFIG_STACK_SIZE_PAGE_ORDER: 4 - libraries: - libc-test: - version: staging - kconfig: - CONFIG_LIBLIBCTEST: "y" - CONFIG_LIBLIBCTEST_STRING_TESTS: "y" - CONFIG_LIBLIBCTEST_PTHREAD_TESTS: "y" - CONFIG_LIBLIBCTEST_CONVERSION_TESTS: "y" - CONFIG_LIBLIBCTEST_REGEX_TESTS: "y" - CONFIG_LIBLIBCTEST_FILE_FOLDER_TESTS: "y" - CONFIG_LIBLIBCTEST_TIME_TESTS: "y" - CONFIG_LIBLIBCTEST_NETWORK_TESTS: "y" - CONFIG_LIBLIBCTEST_SORT_TESTS: "y" - CONFIG_LIBLIBCTEST_STRUCTURE_SEARCH_TESTS: "y" - CONFIG_LIBLIBCTEST_SEMAPHORE_TESTS: "y" - CONFIG_LIBLIBCTEST_RANDOM_TESTS: "y" - CONFIG_LIBLIBCTEST_CRYPT_TESTS: "y" - CONFIG_LIBLIBCTEST_ENV_TESTS: "y" - CONFIG_LIBLIBCTEST_MALLOC_TESTS: "y" - CONFIG_LIBLIBCTEST_TGMATH_TESTS: "y" - CONFIG_LIBLIBCTEST_ICONV_TESTS: "y" - CONFIG_LIBLIBCTEST_UDIV_TESTS: "y" - CONFIG_LIBLIBCTEST_MBFUNC_TESTS: "y" - CONFIG_LIBLIBCTEST_SETJMP_TESTS: "y" - CONFIG_LIBLIBCTEST_FPCLASSIFY_TESTS: "y" - CONFIG_LIBLIBCTEST_POSIX_SPAWN_TESTS: "y" - CONFIG_LIBLIBCTEST_ACCESS_TESTS: "y" - musl: - version: staging - kconfig: - CONFIG_MUSL: "y" - CONFIG_LIBMUSL_COMPLEX: "y" - compiler-rt: - version: staging - targets: - - platform: ${{ matrix.plat }} - architecture: ${{ matrix.arch }} - - self-test: - name: self-test - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - plat: qemu - arch: x86_64 - - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - - name: Fetch helloworld - uses: actions/checkout@v3 - with: - repository: unikraft/app-helloworld - fetch-depth: 1 - path: _helloworld - - - name: Build and run all internal tests via uktest - uses: unikraft/kraftkit@staging - with: - loglevel: debug - workdir: _helloworld - plat: ${{ matrix.plat }} - arch: ${{ matrix.arch }} - execute: true - kraftfile: | - specification: '0.5' - name: helloworld - unikraft: - source: ../ - kconfig: - CONFIG_LIBUKTEST: "y" - CONFIG_LIBUKTEST_ALL: "y" - CONFIG_LIBUKTEST_TEST_MYSELF: "y" - CONFIG_LIBUKDEBUG_ANSI_COLOR: "y" - CONFIG_LIBUKDEBUG_PRINTK_INFO: "y" - CONFIG_LIBUKTEST_FAILFAST: "n" - CONFIG_LIBUKTEST_LOG_STATS: "y" - targets: - - platform: ${{ matrix.plat }} - architecture: ${{ matrix.arch }} - - helloworld: - name: helloworld - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - plat: qemu - arch: x86_64 - - plat: qemu - arch: arm64 - - plat: xen - arch: x86_64 - - plat: fc - arch: x86_64 - - plat: linuxu - arch: x86_64 - - plat: linuxu - arch: arm64 - - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - - name: Fetch helloworld - uses: actions/checkout@v3 - with: - repository: unikraft/app-helloworld - fetch-depth: 1 - path: _helloworld - - - name: Build helloworld - uses: unikraft/kraftkit@staging - with: - loglevel: debug - workdir: _helloworld - execute: false - plat: ${{ matrix.plat }} - arch: ${{ matrix.arch }} - kraftfile: | - specification: '0.5' - name: helloworld - unikraft: - source: ../ - targets: - - platform: ${{ matrix.plat }} - architecture: ${{ matrix.arch }} diff --git a/.github/workflows/label.yaml b/.github/workflows/label.yaml deleted file mode 100644 index 4c5f1f6f2478ad943b4d72609cca8aa12cc42653..0000000000000000000000000000000000000000 --- a/.github/workflows/label.yaml +++ /dev/null @@ -1,28 +0,0 @@ -name: governctl - -on: - pull_request: - types: [opened, synchronize, reopened] - branches: [staging] - -jobs: - label: - runs-on: ubuntu-latest - name: label - steps: - - name: Install governctl - run: | - set -xe - wget -q "https://github.com/unikraft/governance/releases/download/v${GOVERN_VERSION}/governance_${GOVERN_VERSION}_linux_amd64.deb" - sudo dpkg -i "governance_${GOVERN_VERSION}_linux_amd64.deb" - env: - GOVERN_VERSION: 0.1.7 - - - name: Label PR - run: governctl pr sync labels unikraft/unikraft/${PR_NUMBER} --labels-dir .github/labels - env: - PR_NUMBER: ${{ github.event.number }} - GOVERN_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GOVERN_GITHUB_USER: ${{ secrets.GH_CHECKPATCH_ACTOR }} - GOVERN_NO_RENDER: true - GOVERN_LOG_LEVEL: warn diff --git a/.github/workflows/merge.yaml b/.github/workflows/merge.yaml deleted file mode 100644 index a33d407cf50f17ba7bf19337341020c1add0406f..0000000000000000000000000000000000000000 --- a/.github/workflows/merge.yaml +++ /dev/null @@ -1,38 +0,0 @@ -name: merge - -on: - pull_request_target: - types: [labeled] - -jobs: - merge: - if: ${{ github.event.label.name == 'merged' }} - runs-on: ubuntu-latest - name: merge - steps: - - name: Get Pull Request Number - run: echo "PR_NUMBER=$(echo "$GITHUB_REF" | awk -F / '{print $3}')" >> "$GITHUB_ENV" - shell: bash - - - name: Install governctl - run: | - set -xe - wget -q "https://github.com/unikraft/governance/releases/download/v${GOVERN_VERSION}/governance_${GOVERN_VERSION}_linux_amd64.deb" - sudo dpkg -i "governance_${GOVERN_VERSION}_linux_amd64.deb" - env: - GOVERN_VERSION: 0.1.8 - - - name: Run the merge through governctl - run: | - set -xe - unset GITHUB_TOKEN - governctl pr merge --approve-states "${GOVERN_APPROVE_STATES}" --review-states "${GOVERN_REVIEW_STATES}" --base "staging" --push "unikraft/unikraft/${PR_NUMBER}" - env: - GOVERN_GITHUB_TOKEN: ${{ secrets.GH_MERGE_PAT }} - GOVERN_GITHUB_USER: ${{ secrets.GH_MERGE_ACTOR }} - GOVERN_NO_RENDER: true - GOVERN_LOG_LEVEL: warn - GOVERN_NO_CONFLICTS: true - GOVERN_REVIEW_STATES: approved - GOVERN_APPROVE_STATES: approved - diff --git a/.github/workflows/pychecks.yaml b/.github/workflows/pychecks.yaml deleted file mode 100644 index ba60ef4c5b56d8e8b6b8d0baa44e57b2db971445..0000000000000000000000000000000000000000 --- a/.github/workflows/pychecks.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: Python Checks - -on: - push: - branches: [staging, stable] - paths: - - 'support/scripts/**' - - '.github/workflows/pychecks.yaml' - - pull_request: - types: [opened, synchronize, reopened] - branches: [staging] - paths: - - 'support/scripts/**' - - '.github/workflows/pychecks.yaml' - -jobs: - lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: black - uses: psf/black@stable - with: - src: support/scripts - - - name: ruff - uses: chartboost/ruff-action@v1 - if: success() || failure() - with: - src: support/scripts \ No newline at end of file diff --git a/.github/workflows/shellcheck.yaml b/.github/workflows/shellcheck.yaml deleted file mode 100644 index fa506d535ccad38a56aa66c9e90deaf09946f3e3..0000000000000000000000000000000000000000 --- a/.github/workflows/shellcheck.yaml +++ /dev/null @@ -1,33 +0,0 @@ -name: shellcheck - -on: - push: - branches: [staging, stable] - paths: - - 'support/scripts/**' - - '.github/workflows/shellcheck.yaml' - - pull_request: - types: [opened, synchronize, reopened] - branches: [staging] - paths: - - 'support/scripts/**' - - '.github/workflows/shellcheck.yaml' - -permissions: {} - -jobs: - shellcheck: - name: Shellcheck - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Run ShellCheck - uses: ludeeus/action-shellcheck@master - env: - SHELLCHECK_OPTS: -s bash - with: - severity: warning - scandir: support/scripts - format: tty \ No newline at end of file diff --git a/defconfig b/defconfig new file mode 100644 index 0000000000000000000000000000000000000000..c93e583b54659367d0a9a0611724c5521ead34fd --- /dev/null +++ b/defconfig @@ -0,0 +1,8 @@ +CONFIG_ARCH_ARM_64=y +CONFIG_MCPU_ARM64_CORTEX_A53=y +# CONFIG_ARM64_ERRATUM_858921 is not set +CONFIG_PLAT_KVM=y +CONFIG_ARM_GENERIC_TIMER=y +CONFIG_LIBTNSYSTICK_FREQ=100 +CONFIG_ARCH_X86_64=y +CONFIG_UK_NAME="unikraft" diff --git a/drivers/Makefile.uk b/drivers/Makefile.uk index 35ae739a6a080b717dd1f8e0c913aabf0fccfd67..a7f6381b42f15f1a1e4601bcd24e1f802377f869 100644 --- a/drivers/Makefile.uk +++ b/drivers/Makefile.uk @@ -10,3 +10,4 @@ $(eval $(call import_lib,$(UK_DRIV_BASE)/ukbus)) $(eval $(call import_lib,$(UK_DRIV_BASE)/ukintctlr)) $(eval $(call import_lib,$(UK_DRIV_BASE)/uktty)) $(eval $(call import_lib,$(UK_DRIV_BASE)/virtio)) +$(eval $(call import_lib,$(UK_DRIV_BASE)/tnsysclock)) diff --git a/drivers/tnsysclock/Config.uk b/drivers/tnsysclock/Config.uk new file mode 100644 index 0000000000000000000000000000000000000000..e222f61453888f1ac75ef378c0413294f3f1be8a --- /dev/null +++ b/drivers/tnsysclock/Config.uk @@ -0,0 +1,21 @@ +menuconfig SYSCLOCK + bool "Systerm timer" + default y + depends on HAVE_SYSTICK + +config ARM_GENERIC_TIMER + bool "arm_generic_timer(used in arm cortex-a/cortex-r)" + default n + depends on SYSCLOCK + depends on ARCH_ARM_64 + +config TSC_I8254 + bool "tsc_i8254(used in x86)" + default n + depends on SYSCLOCK + depends on ARCH_X86_64 + +config SYSCLOCK_TEST + bool "Enable unit tests" + depends on (SYSCLOCK && LIBUKTEST) + default n diff --git a/drivers/tnsysclock/Makefile.uk b/drivers/tnsysclock/Makefile.uk new file mode 100644 index 0000000000000000000000000000000000000000..512d88808fa1117677c7a5d0342fff6963360c75 --- /dev/null +++ b/drivers/tnsysclock/Makefile.uk @@ -0,0 +1,16 @@ +################################################################################ +# +# Driver registrations +# +################################################################################ + +UK_DRIV_SYSCLOCK_BASE := $(UK_DRIV_BASE)/tnsysclock +$(eval $(call addlib_s,libtnsysclock,$(CONFIG_SYSCLOCK))) + +ASINCLUDES-$(CONFIG_SYSCLOCK) += -I$(UK_DRIV_SYSCLOCK_BASE)/include +CINCLUDES-$(CONFIG_SYSCLOCK) += -I$(UK_DRIV_SYSCLOCK_BASE)/include +CXXINCLUDES-$(CONFIG_SYSCLOCK) += -I$(UK_DRIV_SYSCLOCK_BASE)/include + +$(eval $(call import_lib,$(UK_DRIV_SYSCLOCK_BASE)/arm_generic_timer)) +$(eval $(call import_lib,$(UK_DRIV_SYSCLOCK_BASE)/tsc_i8254)) + diff --git a/drivers/tnsysclock/arm_generic_timer/Makefile.uk b/drivers/tnsysclock/arm_generic_timer/Makefile.uk new file mode 100644 index 0000000000000000000000000000000000000000..38d0aa060fdc01018c6470a348742ec929c0d241 --- /dev/null +++ b/drivers/tnsysclock/arm_generic_timer/Makefile.uk @@ -0,0 +1,5 @@ +$(eval $(call addlib_s,arm_generic_timer,$(CONFIG_ARM_GENERIC_TIMER))) + +ARM_GENERIC_TIMER_CINCLUDES-y += -I$(CONFIG_UK_BASE)/plat/common/include + +ARM_GENERIC_TIMER_SRCS-$(CONFIG_ARM_GENERIC_TIMER) += $(ARM_GENERIC_TIMER_BASE)/arm_generic_timer.c diff --git a/drivers/tnsysclock/arm_generic_timer/arm_generic_timer.c b/drivers/tnsysclock/arm_generic_timer/arm_generic_timer.c new file mode 100644 index 0000000000000000000000000000000000000000..357cdb7ceb01eec6ce113ce52395e1be54201123 --- /dev/null +++ b/drivers/tnsysclock/arm_generic_timer/arm_generic_timer.c @@ -0,0 +1,194 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ssANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char *sysclock_name = "arm generic timer"; +struct uk_intctlr_irq irq; +uint32_t freq; + +/* Bits definition of cntv_ctl register */ +#define ARM_GENERIC_TIMER_ENABLE 0x01 +#define ARM_GENERIC_TIMER_MASK_IRQ 0x02 +#define ARM_GENERIC_TIMER_IRQ_STATUS 0x04 + +static const char *const sysclock_list[] = {"arm,armv8-timer", + "arm,armv7-timer", NULL}; + +static inline void gtimer_enable(void) +{ + set_el0(cntv_ctl, get_el0(cntv_ctl) | GT_TIMER_ENABLE); + + /* Ensure the write of sys register is visible */ + isb(); +} + +static inline void gtimer_disable(void) +{ + set_el0(cntv_ctl, get_el0(cntv_ctl) & ~GT_TIMER_ENABLE); + + isb(); +} + +static inline void gtimer_clear_status(void) +{ + set_el0(cntv_ctl, get_el0(cntv_ctl) & ~GT_TIMER_IRQ_STATUS); + + isb(); +} + +static inline void gtimer_update_compare_value(uint64_t new_val) +{ + set_el0(cntv_cval, new_val); + + isb(); +} + +static inline void gtimer_update_timer_value(uint64_t new_val) +{ + set_el0(cntv_tval, new_val); + + isb(); +} + +static inline void gtimer_mask_irq(void) +{ + set_el0(cntv_ctl, get_el0(cntv_ctl) | GT_TIMER_MASK_IRQ); + + isb(); +} + +static inline void gtimer_unmask_irq(void) +{ + set_el0(cntv_ctl, get_el0(cntv_ctl) & ~GT_TIMER_MASK_IRQ); + + isb(); +} + +/* + * arm generic timer has a 64bit counter reg, we don't need do anything else. + */ +void tn_sysclock_isr_notify(void) {} + +void tn_sysclock_mask_irq(void) +{ + gtimer_mask_irq(); +} + +void tn_sysclock_unmask_irq(void) +{ + gtimer_unmask_irq(); +} + +#ifdef CONFIG_ARM64_ERRATUM_858921 +/* + * The errata #858921 describes that Cortex-A73 (r0p0 - r0p2) counter + * read can return a wrong value when the counter crosses a 32bit boundary. + * But newer Cortex-A73 are not affected. + * + * The workaround involves performing the read twice, compare bit[32] of + * the two read values. If bit[32] is different, keep the first value, + * otherwise keep the second value. + */ +uint64_t tn_sysclock_get_counts(void) +{ + uint64_t val_1st, val_2nd; + + val_1st = get_el0(cntvct); + val_2nd = get_el0(cntvct); + return (((val_1st ^ val_2nd) >> 32) & 1) ? val_1st : val_2nd; +} +#else +uint64_t tn_sysclock_get_counts(void) +{ + return get_el0(cntvct); +} +#endif + +void tn_sysclock_set_next(uint64_t set_counts, uint8_t is_start __unused) +{ + gtimer_clear_status(); + + gtimer_update_compare_value(set_counts); +} + +static inline uint32_t sysclock_get_frequency(int fdt_timer) +{ + int len; + const uint64_t *fdt_freq; + + /* + * On a few platforms the frequency is not configured correctly + * by the firmware. A property in the DT (clock-frequency) has + * been introduced to workaround those firmware. + */ + fdt_freq = fdt_getprop((void *)ukplat_bootinfo_get()->dtb, fdt_timer, + "clock-frequency", &len); + if (!fdt_freq || (len <= 0)) { + uk_pr_info( + "No clock-frequency found, reading from register.\n"); + + /* No workaround, get from register directly */ + return get_el0(cntfrq); + } + + return fdt32_to_cpu(fdt_freq[0]); +} + +int tn_sysclock_probe(void) +{ + int ret, offs; + + /* Currently, we only support 1 timer per system */ + offs = fdt_node_offset_by_compatible_list( + (void *)ukplat_bootinfo_get()->dtb, -1, sysclock_list); + if (unlikely(offs < 0)) { + uk_pr_crit("Could not find arch timer (%d)\n", offs); + return 1; + } + + /* Get counter frequency from DTB or register (in Hz) */ + freq = sysclock_get_frequency(offs); + + ret = uk_intctlr_irq_fdt_xlat((void *)ukplat_bootinfo_get()->dtb, offs, + 2, &irq); + if (unlikely(ret < 0)) { + uk_pr_crit("Could not get IRQ from dtb (%d)\n", ret); + return 1; + } + uk_intctlr_irq_set_trigger(&irq); + irq.id = irq.id; + irq.trigger = UK_INTCTLR_IRQ_TRIGGER_LEVEL; + + /* + * Mask IRQ before scheduler start working. Otherwise we will get + * unexpected timer interrupts when system is booting. + */ + gtimer_mask_irq(); + + tn_systick_register(sysclock_name, freq, &irq); + gtimer_enable(); + + return 0; +} diff --git a/drivers/tnsysclock/exportsyms.uk b/drivers/tnsysclock/exportsyms.uk new file mode 100644 index 0000000000000000000000000000000000000000..45921446adf2c7df3821092652b930d9171c80ea --- /dev/null +++ b/drivers/tnsysclock/exportsyms.uk @@ -0,0 +1,6 @@ +tn_sysclock_probe +tn_sysclock_get_counts +tn_sysclock_isr_notify +tn_sysclock_mask_irq +tn_sysclock_unmask_irq +tn_sysclock_set_next diff --git a/drivers/tnsysclock/include/tn/sysclock.h b/drivers/tnsysclock/include/tn/sysclock.h new file mode 100644 index 0000000000000000000000000000000000000000..c564b2c6c914a8cc69e62414485d472f72149c66 --- /dev/null +++ b/drivers/tnsysclock/include/tn/sysclock.h @@ -0,0 +1,59 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ssANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TN_SYSCLOCK_H__ +#define __TN_SYSCLOCK_H__ + +/** + * Probe and initialize the configured system clock. + * @return 0 on success, negative errno on error + */ +int tn_sysclock_probe(void); + +/** + * Get the current system clock count. + * Every system clock driver must provide a unsigned 64-bit count. + * This value can be read from the hardware timer directly or can be + * calculated based on the hardware timer. + * @return The current system clock count. + */ +uint64_t tn_sysclock_get_counts(void); + +/** + * Notify the system clock driver that a time base interrupt has occurred. + * This function is called by the system clock interrupt handler. + */ +void tn_sysclock_isr_notify(void); + +/** + * Mask the system clock interrupt. + */ +void tn_sysclock_mask_irq(void); + +/** + * Unmask the system clock interrupt. + */ +void tn_sysclock_unmask_irq(void); + +/** + * Set the next time-base interrupt occurrence. + * @param set_counts Counts for the next time-base irq occurring + * @param set_auto_reload 1 means that driver can set auto-reload mode if the + * sysclock supports it, 0 means that driver can't set auto-reload mode. + * @return void + */ +void tn_sysclock_set_next(uint64_t set_counts, uint8_t set_auto_reload); + +#endif /* __TN_SYSCLOCK_H__ */ diff --git a/drivers/tnsysclock/tests/test_sysclock.c b/drivers/tnsysclock/tests/test_sysclock.c new file mode 100644 index 0000000000000000000000000000000000000000..2ac99e062522a1255b4011b9b7be04ddf15a9fc8 --- /dev/null +++ b/drivers/tnsysclock/tests/test_sysclock.c @@ -0,0 +1,79 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "test_sysclock.h" + +/* 测试系统定时器定时功能场景 + * current_count:测试时基中断产生的时间戳 + * test_time_base_irq_handled:测试时基中断函数是否发生 + */ +static uint64_t current_count; +static uint8_t test_time_base_irq_handled; + +/* 测试时基中断函数 */ +static int test_sysclock_irq_handler(void *arg __unused) +{ + current_count = sysclock_get_counts(); + sysclock_mask_irq(); + test_time_base_irq_handled = 1; + return 1; +} + +/* TEST_TIMING_SECS:测试定时器超时时长,单位秒(s) + * TEST_TIMING_BIAS_NANOSECS:允许时间戳误差,单位纳秒(ns) + * TEST_TIMING_BIAS_COUNT:允许时间戳误差,单位count + */ +#define TEST_TIMING_SECS 2 +/* 误差设定为0.2s */ +#define TEST_TIMING_BIAS_NANOSECS 200000000ULL +#define TEST_TIMING_BIAS_COUNT \ + ((TEST_TIMING_BIAS_NANOSECS / (1000000000ULL / freq))) + +UK_TESTCASE(uk_driver_sysclock, test_driver_sysclock_timing) +{ + uint64_t last_count, delta_count, next_count; + + /* 1.初始化测试场景 */ + /* 1.1设置定时器超时时长 */ + next_count = freq * TEST_TIMING_SECS; + + /* 1.2注册测试时基中断函数 */ + uk_intctlr_irq_register(irq.id, test_sysclock_irq_handler, NULL); + + /* 2.测试系统定时器定时功能场景 */ + /* 2.1保存当前时间戳与开始系统定时器定时 */ + last_count = sysclock_get_counts(); + sysclock_set_next((uint64_t)next_count, 0); + sysclock_unmask_irq(); + + /* 2.2处理测试时基中断 */ + while (test_time_base_irq_handled != 1) + __asm__ __volatile__("wfi"); + + /* 3.计算超时时间,校验测试结果 */ + delta_count = current_count - last_count; + /* 实际超时时间预期在预设时间允许误差内(+-BIAS) */ + UK_TEST_EXPECT_SNUM_GT(delta_count, + next_count - (uint64_t)TEST_TIMING_BIAS_COUNT); + UK_TEST_EXPECT_SNUM_LT(delta_count, + next_count + (uint64_t)TEST_TIMING_BIAS_COUNT); + + /* 4.恢复环境 */ + uk_intctlr_irq_unregister(irq.id, test_sysclock_irq_handler); +} + +uk_testsuite_register(uk_driver_sysclock, NULL); diff --git a/drivers/tnsysclock/tests/test_sysclock.h b/drivers/tnsysclock/tests/test_sysclock.h new file mode 100644 index 0000000000000000000000000000000000000000..f97cadd037999b9298282c4af3be1fe141e6e0e9 --- /dev/null +++ b/drivers/tnsysclock/tests/test_sysclock.h @@ -0,0 +1,29 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TEST_SYSCLOCK_H__ +#define __TEST_SYSCLOCK_H__ + +#include + +extern struct uk_intctlr_irq irq; +extern uint32_t freq; + +uint64_t sysclock_get_counts(void); +void sysclock_unmask_irq(void); +void sysclock_mask_irq(void); +void sysclock_set_next(uint64_t set_counts, uint8_t is_start __unused); + +#endif /* __TEST_SYSCLOCK_H__ */ diff --git a/drivers/tnsysclock/tsc_i8254/Makefile.uk b/drivers/tnsysclock/tsc_i8254/Makefile.uk new file mode 100644 index 0000000000000000000000000000000000000000..c467656a899640930bc46056f33b80aede987d6c --- /dev/null +++ b/drivers/tnsysclock/tsc_i8254/Makefile.uk @@ -0,0 +1,5 @@ +$(eval $(call addlib_s,libtnsysclock_tsc_i8254,$(CONFIG_TSC_I8254))) + +LIBTNSYSCLOCK_TSC_I8254_CINCLUDES-y += -I$(CONFIG_UK_BASE)/plat/common/include + +LIBTNSYSCLOCK_TSC_I8254_SRCS-$(CONFIG_TSC_I8254) += $(LIBTNSYSCLOCK_TSC_I8254_BASE)/tsc_i8254.c diff --git a/drivers/tnsysclock/tsc_i8254/tsc_i8254.c b/drivers/tnsysclock/tsc_i8254/tsc_i8254.c new file mode 100644 index 0000000000000000000000000000000000000000..79f009def8cd037b248e382ae7d8bb1dd1d7e2a1 --- /dev/null +++ b/drivers/tnsysclock/tsc_i8254/tsc_i8254.c @@ -0,0 +1,169 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ssANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#define TIMER_CNTR 0x40 +#define TIMER_MODE 0x43 +#define TIMER_SEL0 0x00 +#define TIMER_LATCH 0x00 +#define TIMER_RATEGEN 0x04 +#define TIMER_ONESHOT 0x08 +#define TIMER_16BIT 0x30 +#define TIMER_HZ 1193182 +#define TIMER_DIVISOR_HZ 100 +#define i8254_MAX_COUNT 65535 + +static const char *sysclock_name = "tsc-i8254"; +uint64_t tsc_freq; +uint64_t i8254_set_threshold; +struct uk_intctlr_irq irq; + +static void sysclock_enable(void) +{ + outb(TIMER_MODE, TIMER_SEL0 | TIMER_ONESHOT | TIMER_16BIT); + outb(TIMER_CNTR, 0); + outb(TIMER_CNTR, 0); +} + +void tn_sysclock_isr_notify(void){} + +void tn_sysclock_mask_irq(void) +{ + uk_intctlr_irq_mask(irq.id); +} + +void tn_sysclock_unmask_irq(void) +{ + uk_intctlr_irq_unmask(irq.id); +} + +uint64_t tn_sysclock_get_counts(void) +{ + return rdtsc(); +} + +void tn_sysclock_set_next(uint64_t set_counts, uint8_t set_auto_reload __unused) +{ + uint64_t conuts; + set_counts = MIN(i8254_set_threshold, set_counts - rdtsc()); + conuts = (set_counts * TIMER_HZ) / tsc_freq; + outb(TIMER_MODE, TIMER_SEL0 | TIMER_ONESHOT | TIMER_16BIT); + outb(TIMER_CNTR, (conuts & 0xFF)); + outb(TIMER_CNTR, ((conuts >> 8) & 0xFF)); +} + +/* + * Read the current i8254 channel 0 tick count. + */ +static unsigned int i8254_gettick(void) +{ + __u16 rdval; + + outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); + rdval = inb(TIMER_CNTR); + rdval |= (inb(TIMER_CNTR) << 8); + return rdval; +} + +/* + * Delay for approximately n microseconds using the i8254 channel 0 counter. + * Timer must be programmed appropriately before calling this function. + */ +static void i8254_delay(unsigned int n) +{ + unsigned int cur_tick, initial_tick; + int remaining; + const unsigned long timer_rval = TIMER_HZ / TIMER_DIVISOR_HZ; + + initial_tick = i8254_gettick(); + + remaining = (unsigned long long)n * TIMER_HZ / 1000000; + + while (remaining > 1) { + cur_tick = i8254_gettick(); + if (cur_tick > initial_tick) + remaining -= timer_rval - (cur_tick - initial_tick); + else + remaining -= initial_tick - cur_tick; + initial_tick = cur_tick; + } +} + +uint32_t sysclock_get_frequency(void) +{ + uint64_t freq = 0, base; + uint32_t eax, ebx, ecx, edx; + + /* + * Attempt to retrieve TSC frequency via the hypervisor generic cpuid + * timing information leaf. 0x40000010 returns the (virtual) TSC + * frequency in kHz, or 0 if the feature is not supported by the + * hypervisor. + */ + cpuid(0x40000000, 0, &eax, &ebx, &ecx, &edx); + if (eax >= 0x40000010) { + uk_pr_info("Retrieving TSC clock frequency from hypervisor\n"); + base = rdtsc(); + cpuid(0x40000010, 0, &eax, &ebx, &ecx, &edx); + freq = eax * 1000; + } + + /* + * If we could not retrieve the TSC frequency from the hypervisor, + * calibrate against an 0.1s delay using the i8254 timer. This is + * undesirable as it delays the boot sequence. + */ + if (!freq) { + uk_pr_info("Calibrating TSC clock against i8254 timer\n"); + + /* + * Initialise i8254 timer channel 0 to mode 2 at + * TIMER_DIVISOR_HZ frequency + */ + outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); + outb(TIMER_CNTR, (TIMER_HZ / TIMER_DIVISOR_HZ) & 0xff); + outb(TIMER_CNTR, (TIMER_HZ / TIMER_DIVISOR_HZ) >> 8); + + base = rdtsc(); + i8254_delay(100000); + freq = (rdtsc() - base) * 10; + } + + return freq; +} + +int tn_sysclock_probe(void) +{ + irq.id = 0; + irq.trigger = UK_INTCTLR_IRQ_TRIGGER_LEVEL; + uk_intctlr_irq_set_trigger(&irq); + + tsc_freq = sysclock_get_frequency(); + i8254_set_threshold = + (MIN(i8254_MAX_COUNT * tsc_freq, UINT64_MAX)) / TIMER_HZ; + /* + * Mask IRQ before scheduler start working. Otherwise we will get + * unexpected timer interrupts when system is booting. + */ + tn_sysclock_mask_irq(); + + tn_systick_register(sysclock_name, tsc_freq, &irq); + + sysclock_enable(); + return 0; +} diff --git a/drivers/ukintctlr/bcm_intc/bcm_intc_initialize.c b/drivers/ukintctlr/bcm_intc/bcm_intc_initialize.c index 4ed040cd0441aa33137af7b03b46c638ea0e1861..aea8b71dfacac2f10ceb1afd95cba049ad2d37e2 100644 --- a/drivers/ukintctlr/bcm_intc/bcm_intc_initialize.c +++ b/drivers/ukintctlr/bcm_intc/bcm_intc_initialize.c @@ -69,7 +69,7 @@ static int fdt_xlat(const void *fdt, int nodeoffset, __u32 index, #endif /* CONFIG_LIBUKOFW */ /* 根据设备树参数来设置中断属性 */ -static int configure_irq(struct uk_intctlr_irq *irq) +static int irq_set_trigger(struct uk_intctlr_irq *irq) { if (irq->trigger != UK_INTCTLR_IRQ_TRIGGER_NONE) /* 调用函数配置irq_trigger */ @@ -101,10 +101,17 @@ init: intctlr.name = "BCM-INTC"; ops.initialize = bcm_intc->ops.initialize; ops.percpu_init = __NULL; - ops.configure_irq = configure_irq; + ops.irq_set_trigger = irq_set_trigger; ops.mask_irq = bcm_intc->ops.disable_irq; ops.unmask_irq = bcm_intc->ops.enable_irq; ops.handle = bcm_intc->ops.handle_irq; + ops.irq_set_affinity = __NULL; + ops.irq_set_priority = __NULL; +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) + ops.irq_get_priority = __NULL; + ops.spi_get_affinity = __NULL; + ops.simulate_spi = __NULL; +#endif /* reserved for software general interrupt to specified core */ ops.sgi_op = __NULL; #if CONFIG_LIBUKOFW diff --git a/drivers/ukintctlr/gic/Config.uk b/drivers/ukintctlr/gic/Config.uk index a62ae03850eee019c739262c51db1d7bdf31d00e..331fc6d1f131201d1a10cf1dad1b39f9d80e9309 100644 --- a/drivers/ukintctlr/gic/Config.uk +++ b/drivers/ukintctlr/gic/Config.uk @@ -7,7 +7,38 @@ config LIBUKINTCTLR_GICV2 depends on (HAVE_INTCTLR && ARCH_ARM_64) select LIBUKINTCTLR_GIC -config LIBUKINTCTLR_GICV3 +menuconfig LIBUKINTCTLR_GICV3 bool "Arm Generic Interrupt Controller (GICv3)" depends on (HAVE_INTCTLR && ARCH_ARM_64) select LIBUKINTCTLR_GIC + default n + +if LIBUKINTCTLR_GICV3 +choice + prompt "GICV3 max priority level" + help + Numbers of interrupt priorities supported in non-secure mode + choose from 16/32/64/128 + +config PRIORITY_MAX_16 + bool "16 non-secure priority levels" + help + The available interrupt priority is [0..15] + +config PRIORITY_MAX_32 + bool "32 non-secure priority levels" + help + The available interrupt priority is [0..31] + +config PRIORITY_MAX_64 + bool "64 non-secure priority levels" + help + The available interrupt priority is [0..63] + +config PRIORITY_MAX_128 + bool "128 non-secure priority levels" + help + The available interrupt priority is [0..127] + +endchoice +endif diff --git a/drivers/ukintctlr/gic/gic-v2.c b/drivers/ukintctlr/gic/gic-v2.c index e6278e76167c0ed71f553f9d3a070532a76e7b8b..74543aecfdd0aa06517cf04d79c152bdc8b12e5a 100644 --- a/drivers/ukintctlr/gic/gic-v2.c +++ b/drivers/ukintctlr/gic/gic-v2.c @@ -210,9 +210,11 @@ void gicv2_sgi_gen_to_list(uint32_t sgintid, uint8_t targetlist) /** * Forward the SGI to the CPU specified by cpuid. */ -static void gicv2_sgi_gen_to_cpu(uint8_t sgintid, uint32_t cpuid) +static int gicv2_sgi_gen_to_cpu(uint8_t sgintid, uint32_t cpuid, + va_list cpuid_args __unused) { gicv2_sgi_gen_to_list((uint32_t) sgintid, (uint8_t) (1 << (cpuid % 8))); + return 0; } /** @@ -507,6 +509,11 @@ static void gicv2_set_ops(void) .disable_irq = gicv2_disable_irq, .set_irq_trigger = gicv2_set_irq_trigger, .set_irq_prio = gicv2_set_irq_prio, +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) + .get_irq_prio = NULL, + .simulate_spi = NULL, + .get_spi_affinity = NULL, +#endif .set_irq_affinity = gicv2_set_irq_target, .handle_irq = gicv2_handle_irq, .gic_sgi_gen = gicv2_sgi_gen_to_cpu, diff --git a/drivers/ukintctlr/gic/gic-v3.c b/drivers/ukintctlr/gic/gic-v3.c index 7dc092ccf557e7ddb9a9f70d449636ace8831e6f..8533a1b59bff6444211e5d0e74563c0037c4985f 100644 --- a/drivers/ukintctlr/gic/gic-v3.c +++ b/drivers/ukintctlr/gic/gic-v3.c @@ -111,6 +111,11 @@ static inline void write_gicd64(uint64_t offset, uint64_t val) ioreg_write64(GIC_DIST_REG(gicv3_drv, offset), val); } +static inline uint64_t read_gicd64(uint64_t offset) +{ + return ioreg_read64(GIC_DIST_REG(gicv3_drv, offset)); +} + static inline uint32_t read_gicd32(uint64_t offset) { return ioreg_read32(GIC_DIST_REG(gicv3_drv, offset)); @@ -126,6 +131,16 @@ static inline uint32_t read_gicrd32(uint64_t offset) return ioreg_read32(GIC_RDIST_REG(gicv3_drv, offset)); } +static inline uint32_t read_gicd8(uint64_t offset) +{ + return ioreg_read8(GIC_DIST_REG(gicv3_drv, offset)); +} + +static inline uint32_t read_gicrd8(uint64_t offset) +{ + return ioreg_read8(GIC_RDIST_REG(gicv3_drv, offset)); +} + /** * Wait for a write completion in [re]distributor * @@ -160,6 +175,26 @@ static uint32_t get_cpu_affinity(void) } #endif /* CONFIG_HAVE_SMP */ +/** + * Affinitize all SPI interrupts to the current cpu + * + * @param irq_number SPI interrupt number + */ +static void affinitize_all_spi_to_current_cpu(uint32_t irq_number) +{ + uint32_t i; + uint64_t mpidr = SYSREG_READ64(MPIDR_EL1); + uint64_t aff = ((mpidr & MPIDR_AFF3_MASK) >> 8) | + (mpidr & MPIDR_AFF2_MASK) | + (mpidr & MPIDR_AFF1_MASK) | + (mpidr & MPIDR_AFF0_MASK); + /* Route all global SPIs to this CPU */ + uint64_t irouter_val = GIC_AFF_TO_ROUTER(aff, 0); + + for (i = GIC_SPI_BASE; i < irq_number; i++) + write_gicd64(GICD_IROUTER(i), irouter_val); +} + /** * Acknowledge IRQ and retrieve highest priority pending interrupt * @@ -175,6 +210,59 @@ static uint32_t gicv3_ack_irq(void) return irq; } +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) +/** + * Set pending bit to simulate specified SPI being triggered + */ +static void gicv3_simulate_spi(uint32_t irq) +{ + UK_ASSERT(irq >= GIC_SPI_BASE && irq <= GIC_MAX_IRQ); + uint32_t pending_offset; + + pending_offset = GICD_ISPENDR(irq); + dist_lock(gicv3_drv); + write_gicd32(pending_offset, 1UL << (irq % 32)); + dist_unlock(gicv3_drv); +} + +/** + * Get the interrupt priority level in non-secure mode + * @param irq irq to get priority information + * @return priority level of irq + */ +static uint8_t gicv3_get_irq_prio(uint32_t irq) +{ + uint8_t prio_level; + + dist_lock(gicv3_drv); + if (irq < GIC_SPI_BASE) /* Change in redistributor */ + prio_level = + read_gicrd8(GICR_IPRIORITYR(irq)); + else + prio_level = + read_gicd8(GICD_IPRIORITYR(irq)); + dist_unlock(gicv3_drv); + return prio_level; +} + +/** + * Get the spi affinity stats + * @param irq irq to get affinity information + * @return affinity information of irq + */ +static uint32_t gicv3_get_spi_affinity(uint32_t irq) +{ + UK_ASSERT(irq >= GIC_SPI_BASE && irq <= GIC_MAX_IRQ); + dist_lock(gicv3_drv); + uint64_t router_value = read_gicd64(GICD_IROUTER(irq)); + + uint32_t aff = (uint32_t)((router_value >> 8) & 0xFFFFFF); + + dist_unlock(gicv3_drv); + return aff; +} +#endif /* CONFIG_LIBUKINTCTLR_TEST || CONFIG_LIBUKTEST_ALL */ + /** * Signal completion of interrupt processing * @@ -186,10 +274,11 @@ static void gicv3_eoi_irq(uint32_t irq) /* Lower the priority */ SYSREG_WRITE32(ICC_EOIR1_EL1, irq); isb(); - +#ifdef CONFIG_VIRTUALIZE_PLAT /* Deactivate */ SYSREG_WRITE32(ICC_DIR_EL1, irq); isb(); +#endif } /** @@ -203,20 +292,6 @@ static void gicv3_enable_irq(uint32_t irq) dist_lock(gicv3_drv); -#ifdef CONFIG_HAVE_SMP - /* Route this IRQ to the running core, i.e., route to the CPU interface - * of the core calling this function - */ - if (irq >= GIC_SPI_BASE) { - uint64_t aff = (uint64_t)get_cpu_affinity(); - uint64_t irouter_val = GIC_AFF_TO_ROUTER(aff, 0); - - write_gicd64(GICD_IROUTER(irq), irouter_val); - uk_pr_debug("IRQ %d routed to 0x%lx (REG: 0x%lx)\n", - irq, aff, irouter_val); - } -#endif /* CONFIG_HAVE_SMP */ - if (irq >= GIC_SPI_BASE) write_gicd32(GICD_ISENABLER(irq), UK_BIT(irq % GICD_I_PER_ISENABLERn)); @@ -228,50 +303,87 @@ static void gicv3_enable_irq(uint32_t irq) } /** - * Send a software generated interrupt to the specified core. + * Send a software generated interrupt to the specified cores. * - * @sgintid the software generated interrupt id - * @cpuid the id of the targeted cpu + * @param sgintid the software generated interrupt id + * @param target_count the number of target cpus, + * zero means sending sgi to a11 PEs in the system except the current one. + * @param va_list argument list of cpuid, could be empty. type: uint32_t + * @return zero on success, negative value on failure */ -static void gicv3_sgi_gen(uint8_t sgintid, uint32_t cpuid) +static int gicv3_sgi_gen(uint8_t sgintid, + uint32_t target_count, va_list cpuid_args) { - uint64_t sgi_register = 0, control_register_rss, type_register_rss; + uint64_t sgi_register = 0, affinity_and_rs_checker = 0; + uint64_t control_register_rss, type_register_rss; uint64_t range_selector = 0, extended_cpuid; uint32_t aff0; - extended_cpuid = (uint64_t) cpuid; - /* Only INTID 0-15 allocated to sgi */ UK_ASSERT(sgintid <= GICD_SGI_MAX_INITID); + UK_ASSERT(target_count <= GICD_SGI_MAX_TARGETLIST); + sgi_register |= (sgintid << 24); - /* Set affinity fields and optional range selector */ - sgi_register |= (extended_cpuid & MPIDR_AFF3_MASK) << 48; - sgi_register |= (extended_cpuid & MPIDR_AFF2_MASK) << 32; - sgi_register |= (extended_cpuid & MPIDR_AFF1_MASK) << 16; - /** - ** For affinity 0, we need to find which group of 16 values is - ** represented by the TargetList field in ICC_SGI1R_EL1. - **/ - aff0 = extended_cpuid & MPIDR_AFF0_MASK; - if (aff0 >= 16) { - control_register_rss = SYSREG_READ64(ICC_CTLR_EL1) & (1 << 18); - type_register_rss = read_gicd32(GICD_TYPER) & (1 << 26); - if (control_register_rss == 1 && type_register_rss == 1) { - range_selector = aff0 / 16; - sgi_register |= (range_selector << 44); - } else { - uk_pr_err("Can't generate interrupt!\n"); - return; - } + if (!target_count) { + sgi_register |= ICC_SGI1R_EL1_IRM_ALL; + dist_lock(gicv3_drv); + SYSREG_WRITE64(ICC_SGI1R_EL1, sgi_register); + dist_unlock(gicv3_drv); + return 0; } - sgi_register |= (1 << (aff0 % 16)); + control_register_rss = + SYSREG_READ64(ICC_CTLR_EL1) & (1 << 18); + type_register_rss = + read_gicd32(GICD_TYPER) & (1 << 26); + + uint8_t i; + + for (i = 0; i < target_count; i++) { + extended_cpuid = (uint64_t)va_arg(cpuid_args, uint32_t); + + /* Set affinity fields and optional range selector */ + sgi_register |= + (extended_cpuid & MPIDR_AFF3_MASK) << 48; + sgi_register |= + (extended_cpuid & MPIDR_AFF2_MASK) << 32; + sgi_register |= + (extended_cpuid & MPIDR_AFF1_MASK) << 16; + + aff0 = extended_cpuid & MPIDR_AFF0_MASK; + range_selector = aff0 / 16; + sgi_register |= ((1 << (aff0 % 16)) | (range_selector << 44)); + + if (i == 0) { + if (range_selector >= 1 && + (control_register_rss != 1 || type_register_rss != 1)) { + uk_pr_err( + "send sgi to target core(s) failed: \r\n" + "mismatch cpuid(0x%lx) and rs(GICD_TYPER.RS: %lu, ICC_CTLR.RS: %lu)\n" + , extended_cpuid, + type_register_rss, + control_register_rss); + return -1; + } + + affinity_and_rs_checker = sgi_register; + continue; + } + + if ((sgi_register & MPIDR_AFFx_AND_RS_MASK) + != (affinity_and_rs_checker & MPIDR_AFFx_AND_RS_MASK)) { + uk_pr_err("send sgi to target core(s) failed: \r\n" + "there are cores having different affinity or range selector\n"); + return -1; + } + } - /* Generate interrupt */ dist_lock(gicv3_drv); SYSREG_WRITE64(ICC_SGI1R_EL1, sgi_register); dist_unlock(gicv3_drv); + + return 0; } /** @@ -315,19 +427,21 @@ static void gicv3_set_irq_affinity(uint32_t irq, uint32_t affinity) * Set priority for an interrupt * * @param irq interrupt number [0..GIC_MAX_IRQ] - * @param priority priority [0..255]. The GIC implementation may not support - * all levels. For example, if only 128 levels are supported every two levels - * (e.g., 0 and 1) map to the same effective value. Lower values correspond - * to higher priority + * @param priority Available interrupt priority range in non-secure mode, + * Lower values correspond to higher priorities + * Refer to the gic documentation for more details. */ static void gicv3_set_irq_prio(uint32_t irq, uint8_t priority) { - dist_lock(gicv3_drv); + UK_ASSERT(priority < (1 << (8 - TRANS_PRIORITY_SHIFT))); + dist_lock(gicv3_drv); if (irq < GIC_SPI_BASE) /* Change in redistributor */ - write_gicrd8(GICR_IPRIORITYR(irq), priority); + write_gicrd8(GICR_IPRIORITYR(irq), + priority << TRANS_PRIORITY_SHIFT); else - write_gicd8(GICD_IPRIORITYR(irq), priority); + write_gicd8(GICD_IPRIORITYR(irq), + priority << TRANS_PRIORITY_SHIFT); dist_unlock(gicv3_drv); } @@ -440,8 +554,7 @@ static void gicv3_init_redist(void) /* Set priority mask register */ SYSREG_WRITE32(ICC_PMR_EL1, 0xff); - /* EOI drops priority, DIR deactivates the interrupt (mode 1) */ - SYSREG_WRITE32(ICC_CTLR_EL1, GICC_CTLR_EL1_EOImode_drop); + SYSREG_WRITE32(ICC_CTLR_EL1, ICC_CTLR_EL1_EOImode); /* Enable Group 1 interrupts */ SYSREG_WRITE32(ICC_IGRPEN1_EL1, 1); @@ -475,14 +588,18 @@ static void gicv3_init_dist(void) for (i = GIC_SPI_BASE; i < irq_number; i += GICD_I_PER_IGROUPRn) write_gicd32(GICD_IGROUPR(i), GICD_DEF_IGROUPRn); + /* Check for 1 of N SPI interrupts support */ + if (val & GICD_TYPE_NO1N_MASK) { + affinitize_all_spi_to_current_cpu(irq_number); + } else { #ifdef CONFIG_HAVE_SMP - /* Route all global SPIs to this CPU */ - uint64_t aff = (uint64_t)get_cpu_affinity(); - uint64_t irouter_val = GIC_AFF_TO_ROUTER(aff, 0); - - for (i = GIC_SPI_BASE; i < irq_number; i++) - write_gicd64(GICD_IROUTER(i), irouter_val); + for (i = GIC_SPI_BASE; i < irq_number; i++) + write_gicd64(GICD_IROUTER(i), + GIC_AFF_TO_ROUTER(0ULL, 1)); +#else + affinitize_all_spi_to_current_cpu(irq_number); #endif /* CONFIG_HAVE_SMP */ + } /* Set all SPI's interrupt type to be level-sensitive */ for (i = GIC_SPI_BASE; i < irq_number; i += GICD_I_PER_ICFGRn) @@ -557,14 +674,14 @@ static int gicv3_initialize(void) } #endif /* CONFIG_HAVE_SMP */ - gicv3_drv.is_initialized = 1; - /* Initialize GICv3 distributor */ gicv3_init_dist(); /* Initialize GICv3 CPU redistributor */ gicv3_init_redist(); + gicv3_drv.is_initialized = 1; + return 0; } @@ -581,6 +698,11 @@ static inline void gicv3_set_ops(void) .set_irq_affinity = gicv3_set_irq_affinity, .handle_irq = gicv3_handle_irq, .gic_sgi_gen = gicv3_sgi_gen, +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) + .get_irq_prio = gicv3_get_irq_prio, + .simulate_spi = gicv3_simulate_spi, + .get_spi_affinity = gicv3_get_spi_affinity, +#endif }; /* Set driver functions */ diff --git a/drivers/ukintctlr/gic/include/uk/intctlr/gic-v3.h b/drivers/ukintctlr/gic/include/uk/intctlr/gic-v3.h index 0338000365f88f887e11fd3ebe7f3157525f37b0..9f9e299bf9433962750a69905663dd0ef6088d3c 100644 --- a/drivers/ukintctlr/gic/include/uk/intctlr/gic-v3.h +++ b/drivers/ukintctlr/gic/include/uk/intctlr/gic-v3.h @@ -48,6 +48,8 @@ #define MPIDR_AFF1_MASK 0x000000ff00 /** Affinity AFF0 bit mask */ #define MPIDR_AFF0_MASK 0x00000000ff +/** Affinity AFFx and range selector bit mask */ +#define MPIDR_AFFx_AND_RS_MASK 0xfffff0ffff00 /* * GIC System register assembly aliases @@ -62,10 +64,34 @@ #define ICC_SRE_EL1 S3_0_C12_C12_5 #define ICC_IGRPEN1_EL1 S3_0_C12_C12_7 +/* + * Set Group 1 SGIs routing mode + * ICC_SGI1R_EL1_IRM_ALL, SGI routed to all PEs, excluding "self". + * ICC_SGI1R_EL1_IRM, SGI routed to the PEs specified by Aff3.Aff2.Aff1. + */ +#define ICC_SGI1R_EL1_IRM_ALL (1UL << 40) +#define ICC_SGI1R_EL1_IRM (0UL << 40) + +/* + * ICC_CTLR_EL1_EOImode Controls + * whether a write to an End of Interrupt register + * also deactivates the interrupt + * ICC_CTLR_EL1_EOImode_drop provide priority drop functionality only + * ICC_CTLR_EL1_EOImode_drop_deactivation + * provide both priority drop and interrupt deactivation functionality + */ +#define ICC_CTLR_EL1_EOImode_drop (1U << 1) +#define ICC_CTLR_EL1_EOImode_drop_and_deactivation (0U << 1) + +#if defined CONFIG_VIRTUALIZE_PLAT +#define ICC_CTLR_EL1_EOImode ICC_CTLR_EL1_EOImode_drop +#else +#define ICC_CTLR_EL1_EOImode ICC_CTLR_EL1_EOImode_drop_and_deactivation +#endif + /* * Distributor and Redistributor registers */ -#define GICC_CTLR_EL1_EOImode_drop (1U << 1) /* Default size according to ARM Generic Interrupt Controller Architecture * Specification GIC Architecture version 3 and version 4 Issue H. @@ -80,6 +106,7 @@ #define GICD_IROUTER_BASE (0x6000) #define GICD_IROUTER32 (0x6100) #define GICD_IROUTER1019 (0x7FD8) +#define GICD_IROUTER_IRM (1UL << 31) #define GICD_PIDR2 (0xFFE8) #define GICD_CTLR_RWP (1UL << 31) @@ -98,6 +125,11 @@ ((((r) >> GICD_TYPE_ID_BITS_SHIFT) & 0x1f) + 1) #define GICD_TYPE_LPIS (1U << 17) +/* Indicates whether 1 of N SPI interrupts are supported. + * 0b0 1 of N SPI interrupts are supported. + * 0b1 1 of N SPI interrupts are not supported. + */ +#define GICD_TYPE_NO1N_MASK (1U << 25) #define GICR_WAKER_ProcessorSleep (1U << 1) #define GICR_WAKER_ChildrenAsleep (1U << 2) @@ -339,6 +371,7 @@ #define GICD_SGI_FILTER_SHIFT 24 #define GICD_SGI_FILTER_MASK 0x3 #define GICD_SGI_MAX_INITID 15 +#define GICD_SGI_MAX_TARGETLIST 16 #define GICD_PPI_START /* @@ -370,6 +403,22 @@ #define GICC_IAR_INTID_MASK 0x3FF #define GICC_IAR_INTID_SPURIOUS 1023 +/* + * Select the corresponding priority shift bit + * based on the number of interrupt priorities + */ +#if defined(CONFIG_PRIORITY_MAX_16) + #define TRANS_PRIORITY_SHIFT 4 +#elif defined(CONFIG_PRIORITY_MAX_32) + #define TRANS_PRIORITY_SHIFT 3 +#elif defined(CONFIG_PRIORITY_MAX_64) + #define TRANS_PRIORITY_SHIFT 2 +#elif defined(CONFIG_PRIORITY_MAX_128) + #define TRANS_PRIORITY_SHIFT 1 +#else + #define TRANS_PRIORITY_SHIFT 4 +#endif + /** * Probe device tree or ACPI for GICv3 * NOTE: First time must not be called from multiple CPUs in parallel diff --git a/drivers/ukintctlr/gic/include/uk/intctlr/gic.h b/drivers/ukintctlr/gic/include/uk/intctlr/gic.h index 6c7591a8d035281c9d8c416f4d2c042e8ba8647f..55f148679153a994f9950e8c722b15071d2817ca 100644 --- a/drivers/ukintctlr/gic/include/uk/intctlr/gic.h +++ b/drivers/ukintctlr/gic/include/uk/intctlr/gic.h @@ -68,27 +68,36 @@ typedef enum _GIC_HW_VER { /** GIC driver operations */ struct _gic_operations { - /** Initialize GIC controller */ + /* Initialize GIC controller */ int (*initialize)(void); - /** Acknowledging IRQ */ + /* Acknowledging IRQ */ uint32_t (*ack_irq)(void); - /** Finish interrupt handling */ + /* Finish interrupt handling */ void (*eoi_irq)(uint32_t irq); - /** Enable IRQ */ + /* Enable IRQ */ void (*enable_irq)(uint32_t irq); - /** Disable IRQ */ + /* Disable IRQ */ void (*disable_irq)(uint32_t irq); - /** Set IRQ trigger type */ + /* Set IRQ trigger type */ void (*set_irq_trigger)(uint32_t irq, enum uk_intctlr_irq_trigger trigger); - /** Set priority for IRQ */ + /* Set priority for IRQ */ void (*set_irq_prio)(uint32_t irq, uint8_t priority); - /** Set IRQ affinity (or "target" for GICv2) */ + /* Set IRQ affinity (or "target" for GICv2) */ void (*set_irq_affinity)(uint32_t irq, uint32_t affinity); - /** Handle IRQ */ + /* Handle IRQ */ void (*handle_irq)(struct __regs *regs); - /** Send a SGI to the specifiec core */ - void (*gic_sgi_gen)(uint8_t sgintid, uint32_t cpuid); + /* Send a SGI to the specified cores or all cores excluding "self" */ + int (*gic_sgi_gen)(uint8_t sgintid, uint32_t target_amount, + va_list cpuid_args); +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) + /* Simulate spi */ + void (*simulate_spi)(uint32_t irq); + /* Get IRQ priority level */ + uint8_t (*get_irq_prio)(uint32_t irq); + /* Get spi affinity */ + uint32_t (*get_spi_affinity)(uint32_t irq); +#endif }; /** GIC controller structure */ diff --git a/drivers/ukintctlr/gic/ukintctlr.c b/drivers/ukintctlr/gic/ukintctlr.c index 4b50c33773e0866337932bf030ad970c670c9d22..344df59a009958d40b467eb2e7eee8ddd7ea73f7 100644 --- a/drivers/ukintctlr/gic/ukintctlr.c +++ b/drivers/ukintctlr/gic/ukintctlr.c @@ -75,7 +75,7 @@ static int fdt_xlat(const void *fdt, int nodeoffset, __u32 index, } #endif /* CONFIG_LIBUKOFW */ -static int configure_irq(struct uk_intctlr_irq *irq) +static int set_irq_trigger(struct uk_intctlr_irq *irq) { if (irq->trigger != UK_INTCTLR_IRQ_TRIGGER_NONE) gic->ops.set_irq_trigger(irq->id, irq->trigger); @@ -111,9 +111,16 @@ init: if (unlikely(rc)) return rc; - ops.configure_irq = configure_irq; + ops.irq_set_trigger = set_irq_trigger; ops.mask_irq = gic->ops.disable_irq; ops.unmask_irq = gic->ops.enable_irq; + ops.irq_set_priority = gic->ops.set_irq_prio; +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) + ops.irq_get_priority = gic->ops.get_irq_prio; + ops.spi_get_affinity = gic->ops.get_spi_affinity; + ops.simulate_spi = gic->ops.simulate_spi; +#endif + ops.irq_set_affinity = gic->ops.set_irq_affinity; #if CONFIG_LIBUKOFW ops.fdt_xlat = fdt_xlat; #endif /* CONFIG_LIBUKOFW */ diff --git a/drivers/ukintctlr/xpic/ukintctlr.c b/drivers/ukintctlr/xpic/ukintctlr.c index 5581aa9d8ab1a9b5ad40529d938a6d142250fe59..33c6f8bf6826e84112b5def74177e5f54e36aa55 100644 --- a/drivers/ukintctlr/xpic/ukintctlr.c +++ b/drivers/ukintctlr/xpic/ukintctlr.c @@ -15,7 +15,7 @@ static struct uk_intctlr_desc intctlr; -static int configure_irq(struct uk_intctlr_irq *irq __unused) +static int irq_set_trigger(struct uk_intctlr_irq *irq __unused) { return 0; } @@ -56,12 +56,18 @@ int uk_intctlr_probe(void) #endif /* CONFIG_LIBUKINTCTLR_APIC */ intctlr.ops = ops; - intctlr.ops->configure_irq = configure_irq; + intctlr.ops->irq_set_trigger = irq_set_trigger; intctlr.ops->initialize = __NULL; intctlr.ops->handle = uk_intctlr_xpic_handle_irq; intctlr.ops->fdt_xlat = __NULL; intctlr.ops->sgi_op = __NULL; intctlr.ops->percpu_init = __NULL; - + intctlr.ops->irq_set_priority = __NULL; + intctlr.ops->irq_set_affinity = __NULL; +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) + intctlr.ops->irq_get_priority = __NULL; + intctlr.ops->spi_get_affinity = __NULL; + intctlr.ops->simulate_spi = __NULL; +#endif return uk_intctlr_register(&intctlr); } diff --git a/drivers/uktty/Config.uk b/drivers/uktty/Config.uk index 64f5c89b5bca4b6fa323edc0e3ddfaa168b8d8fb..aff36020971c9d14ecbb997249cd577cc7695130 100644 --- a/drivers/uktty/Config.uk +++ b/drivers/uktty/Config.uk @@ -2,5 +2,6 @@ menu "Serial console" source "$(KCONFIG_DRIV_BASE)/uktty/pl011/Config.uk" source "$(KCONFIG_DRIV_BASE)/uktty/ns16550/Config.uk" +source "$(KCONFIG_DRIV_BASE)/uktty/ns8250/Config.uk" endmenu diff --git a/drivers/uktty/Makefile.uk b/drivers/uktty/Makefile.uk index da2194ae19600771525f42533c18c26664c1ef93..18ce89dbdd92ac70d802c0570ec2720a29e67b5f 100644 --- a/drivers/uktty/Makefile.uk +++ b/drivers/uktty/Makefile.uk @@ -8,3 +8,4 @@ UK_DRIV_TTY_BASE := $(UK_DRIV_BASE)/uktty $(eval $(call import_lib,$(UK_DRIV_TTY_BASE)/ns16550)) $(eval $(call import_lib,$(UK_DRIV_TTY_BASE)/pl011)) +$(eval $(call import_lib,$(UK_DRIV_TTY_BASE)/ns8250)) diff --git a/drivers/uktty/ns16550/Config.uk b/drivers/uktty/ns16550/Config.uk index 0bffcfb822600c755c0e4716ea116fd7ef54a6a0..9bb064457417c5d8fa5245b0559a78d813336a8e 100644 --- a/drivers/uktty/ns16550/Config.uk +++ b/drivers/uktty/ns16550/Config.uk @@ -1,5 +1,5 @@ menuconfig LIBUKTTY_NS16550 - bool "NS16550 / 8250" + bool "NS16550" default n depends on ARCH_ARM_64 diff --git a/drivers/uktty/ns16550/Makefile.uk b/drivers/uktty/ns16550/Makefile.uk index 0d1645d5876830c66ed3a9fc6a6234b5c4316c26..0693daf80bda3d8fef988d82f5d43a9e44adb258 100644 --- a/drivers/uktty/ns16550/Makefile.uk +++ b/drivers/uktty/ns16550/Makefile.uk @@ -1,4 +1,4 @@ -$(eval $(call addplatlib_s,kvm,libuktty_ns16550,$(CONFIG_LIBUKTTY_NS16550))) +$(eval $(call addlib_s,libuktty_ns16550,$(CONFIG_LIBUKTTY_NS16550))) CINCLUDES-y += -I$(LIBUKTTY_NS16550_BASE)/include LIBUKTTY_NS16550_SRCS-y += $(LIBUKTTY_NS16550_BASE)/ns16550.c diff --git a/drivers/uktty/ns8250/Config.uk b/drivers/uktty/ns8250/Config.uk new file mode 100644 index 0000000000000000000000000000000000000000..206a0c7872fb353f7296b4183c17e1e97a1194bc --- /dev/null +++ b/drivers/uktty/ns8250/Config.uk @@ -0,0 +1,13 @@ +menuconfig LIBTNTTY_NS8250 + bool "NS8250" + default n + depends on ARCH_ARM_64 + +if LIBTNTTY_NS8250 +config LIBTNTTY_EARLY_PRINT_NS8250_CONSOLE_NAME + string "Description of serial in alisas node in device tree" + default "serial4" + help + uart used for kernel output + +endif diff --git a/drivers/uktty/ns8250/Makefile.uk b/drivers/uktty/ns8250/Makefile.uk new file mode 100644 index 0000000000000000000000000000000000000000..0919e780f1cbbd5a520254be2c09acc469126645 --- /dev/null +++ b/drivers/uktty/ns8250/Makefile.uk @@ -0,0 +1,4 @@ +$(eval $(call addlib_s,libuktty_ns8250,$(CONFIG_LIBTNTTY_NS8250))) + +CINCLUDES-y += -I$(LIBUKTTY_NS8250_BASE)/include +LIBUKTTY_NS8250_SRCS-y += $(LIBUKTTY_NS8250_BASE)/ns8250.c diff --git a/drivers/uktty/ns8250/exportsyms.uk b/drivers/uktty/ns8250/exportsyms.uk new file mode 100644 index 0000000000000000000000000000000000000000..eaccad20aef6d776ea0c8576f71916da9b3dea4f --- /dev/null +++ b/drivers/uktty/ns8250/exportsyms.uk @@ -0,0 +1,4 @@ +ns8250_console_init +ukplat_cink +ukplat_coutd +ukplat_coutk \ No newline at end of file diff --git a/drivers/uktty/ns8250/include/uk/tty/ns8250.h b/drivers/uktty/ns8250/include/uk/tty/ns8250.h new file mode 100644 index 0000000000000000000000000000000000000000..b4e080056c312ff5cc2d231d6aeee7afbce13c18 --- /dev/null +++ b/drivers/uktty/ns8250/include/uk/tty/ns8250.h @@ -0,0 +1,24 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __TN_TTY_NS8250_H__ +#define __TN_TTY_NS8250_H__ + +/** + * Initialize the ns8250 console driver + */ +void ns8250_console_init(void *dtb); + +#endif /* __UK_TTY_NS8250_H__ */ diff --git a/drivers/uktty/ns8250/ns8250.c b/drivers/uktty/ns8250/ns8250.c new file mode 100644 index 0000000000000000000000000000000000000000..195614b7650dab8536f99a9f9243ef4a0dd4a961 --- /dev/null +++ b/drivers/uktty/ns8250/ns8250.c @@ -0,0 +1,254 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include + +#define NS8250_THR_OFFSET 0x00U +#define NS8250_RBR_OFFSET 0x00U +#define NS8250_DLL_OFFSET 0x00U +#define NS8250_DLM_OFFSET 0x01U +#define NS8250_IER_OFFSET 0x01U +#define NS8250_IIR_OFFSET 0x02U +#define NS8250_FCR_OFFSET 0x02U +#define NS8250_LCR_OFFSET 0x03U +#define NS8250_MCR_OFFSET 0x04U +#define NS8250_LSR_OFFSET 0x05U +#define NS8250_MSR_OFFSET 0x06U + +#define NS8250_MCR_DTR 0x01U /* DTR */ +#define NS8250_MCR_RTS 0x02U /* RTS */ +#define NS8250_MCR_SET (NS8250_MCR_DTR | \ + NS8250_MCR_RTS) + +#define NS8250_LCR_8N1 0x03U +#define NS8250_LCR_DLAB 0x80U +#define NS8250_IIR_NO_INT 0x01U +#define NS8250_FCR_FIFO_EN 0x01U +#define NS8250_FCR_RXSR 0x02U /* Receiver soft reset */ +#define NS8250_FCR_TXSR 0x04U /* Transmitter soft reset */ +#define NS8250_LSR_RX_EMPTY 0x01U +#define NS8250_LSR_TX_EMPTY 0x40U +#define NS8250_FCR_DEFVAL (NS8250_FCR_FIFO_EN | \ + NS8250_FCR_RXSR | \ + NS8250_FCR_TXSR) + +static __u8 ns8250_uart_initialized; +static __u64 ns8250_uart_base; + +/* Early console node name in DTB, help to find related info */ +static char *earlycon_node_name = +CONFIG_LIBTNTTY_EARLY_PRINT_NS8250_CONSOLE_NAME; + +/* The register shift. Default is 0 (device-tree spec v0.4 Sect. 4.2.2) */ +static __u32 ns8250_reg_shift; + +/* The register width. Default is 1 (8-bit register width) */ +static __u32 ns8250_reg_width = 0x01; + +static __u32 ns8250_baudrate = 115200; + +static __u32 ns8250_mode_x_div = 16; + +/* Macros to access ns16550 registers with base address and reg shift */ +#define NS8250_REG(r) (ns8250_uart_base + (r << ns8250_reg_shift)) + +/* Macros to extract int shift/width infos */ +#define EXTRACT_HIGH_BITS(x) ((__u32)((x) & 0xFFFFFFFF) >> 24) + +static inline __u32 ns8250_reg_read(__u32 reg) +{ + __u32 ret; + + switch (ns8250_reg_width) { + case 1: + ret = ioreg_read8((__u8 *)NS8250_REG(reg)) & 0xff; + break; + case 2: + ret = ioreg_read16((__u16 *)NS8250_REG(reg)) & 0xffff; + break; + case 4: + ret = ioreg_read32((__u32 *)NS8250_REG(reg)); + break; + default: + UK_CRASH("Invalid register width: %d\n", ns8250_reg_width); + } + return ret; +} + +static inline void ns8250_reg_write(__u32 reg, __u32 value) +{ + switch (ns8250_reg_width) { + case 1: + ioreg_write8((__u8 *)NS8250_REG(reg), + (__u8)(value & 0xff)); + break; + case 2: + ioreg_write16((__u16 *)NS8250_REG(reg), + (__u16)(value & 0xffff)); + break; + case 4: + ioreg_write32((__u32 *)NS8250_REG(reg), value); + break; + default: + UK_CRASH("Invalid register width: %d\n", ns8250_reg_width); + } +} + +static void ns8250_set_baudrate(__u16 divisor) +{ + /* Enable DLAB */ + ns8250_reg_write(NS8250_LCR_OFFSET, + NS8250_LCR_DLAB | NS8250_LCR_8N1); + /* Set divisor low byte */ + ns8250_reg_write(NS8250_DLL_OFFSET, divisor & 0xff); + /* Set divisor high byte */ + ns8250_reg_write(NS8250_DLM_OFFSET, (divisor >> 8) & 0xff); + /* Set the transceiver signal bit */ + ns8250_reg_write(NS8250_LCR_OFFSET, NS8250_LCR_8N1); +} + +static void init_ns8250(__u64 base) +{ + __u16 ns8250_divisor = 0; + __u32 ns8250_uart_freq = 24000000; + + ns8250_uart_base = base; + ns8250_uart_initialized = 1; + + while (!(ns8250_reg_read(NS8250_LSR_OFFSET) & NS8250_LSR_TX_EMPTY)) + ; + + if (ns8250_baudrate) { + ns8250_divisor = + (ns8250_uart_freq) / (ns8250_mode_x_div * ns8250_baudrate); + } + + /* Disable all interrupts */ + ns8250_reg_write(NS8250_IER_OFFSET, 0x00); + /* DTR RTS */ + ns8250_reg_write(NS8250_MCR_OFFSET, NS8250_MCR_SET); + + ns8250_reg_write(NS8250_FCR_OFFSET, NS8250_FCR_DEFVAL); + /* Set baud rate */ + ns8250_set_baudrate(ns8250_divisor); + +} + +void ns8250_console_init(const void *dtb) +{ + int offset, len, val; + __u64 naddr, nsize, reg_uart_base; + const __u64 *regs; + + if (unlikely((offset = fdt_path_offset_namelen(dtb, + earlycon_node_name, strlen(earlycon_node_name))) < 0)) { + UK_CRASH("No console UART found!\n"); + } + + val = fdt_get_address(dtb, offset, 0, &naddr, &nsize); + if (val < 0) + UK_CRASH("Could not find proper address!\n"); + + reg_uart_base = naddr; + + regs = fdt_getprop(dtb, offset, "reg-shift", &len); + if (regs) + ns8250_reg_shift = EXTRACT_HIGH_BITS(*regs); + + regs = fdt_getprop(dtb, offset, "reg-io-width", &len); + if (regs) + ns8250_reg_width = EXTRACT_HIGH_BITS(*regs); + + init_ns8250(reg_uart_base); + + uk_pr_info("EARLYCON UART initialized\n"); +} + +int ukplat_coutd(const char *str, unsigned int len) +{ + return ukplat_coutk(str, len); +} + +static void _putc(char a) +{ + /* Wait until TX FIFO becomes empty */ + while (!(ns8250_reg_read(NS8250_LSR_OFFSET) & NS8250_LSR_TX_EMPTY)) + ; + + /* Reset DLAB and write to THR */ + ns8250_reg_write(NS8250_LCR_OFFSET, + ns8250_reg_read(NS8250_LCR_OFFSET) & + ~(NS8250_LCR_DLAB)); + ns8250_reg_write(NS8250_THR_OFFSET, a & 0xff); +} + +static void ns8250_putc(char a) +{ + if (a == '\n') + _putc('\r'); + _putc(a); +} + +/* Try to get data from ns16550 UART without blocking */ +static int ns8250_getc(void) +{ + /* If RX FIFO is empty, return -1 immediately */ + if (!(ns8250_reg_read(NS8250_LSR_OFFSET) & NS8250_LSR_RX_EMPTY)) + return -1; + + /* Reset DLAB and read from RBR */ + ns8250_reg_write(NS8250_LCR_OFFSET, + ns8250_reg_read(NS8250_LCR_OFFSET) & + ~(NS8250_LCR_DLAB)); + return (int)(ns8250_reg_read(NS8250_RBR_OFFSET) & 0xff); +} + +int ukplat_coutk(const char *buf, unsigned int len) +{ + /* + * Avoid using the UART before base address initialized, or + * if CONFIG_LIBTNTTY_NS8250_EARLY_CONSOLE_BASE is not enabled. + */ + if (!ns8250_uart_initialized) + return -1; + + for (unsigned int i = 0; i < len; i++) + ns8250_putc(buf[i]); + return len; +} + +int ukplat_cink(char *buf, unsigned int maxlen) +{ + int ret; + unsigned int num = 0; + + /* + * Avoid using the UART before base address initialized, or + * if CONFIG_LIBTNTTY_NS8250_EARLY_CONSOLE_BASE is not enabled. + */ + if (!ns8250_uart_initialized) + return -1; + + while (num < maxlen && (ret = ns8250_getc()) >= 0) { + *(buf++) = (char)ret; + num++; + } + + return (int)num; +} diff --git a/drivers/virtio/mmio/virtio_mmio.c b/drivers/virtio/mmio/virtio_mmio.c index 881a3181b123d9a278bd8cc8372bf389c1bca290..087e7cf8196342250c2beb839dc5ff4df2194359 100644 --- a/drivers/virtio/mmio/virtio_mmio.c +++ b/drivers/virtio/mmio/virtio_mmio.c @@ -439,7 +439,7 @@ static int virtio_mmio_probe_fdt(struct pf_device *pfdev) if (unlikely(rc < 0)) return -EINVAL; - uk_intctlr_irq_configure(&irq); + uk_intctlr_irq_set_trigger(&irq); prop = fdt_getprop(dtb, offs, "reg", &prop_len); if (unlikely(!prop)) diff --git a/include/uk/list.h b/include/uk/list.h index e5c4ab6cc1e71b630b7faa03e03c57cf069b9edb..d0fe14a4711d1259cc26036600af1ce605d5c9dc 100644 --- a/include/uk/list.h +++ b/include/uk/list.h @@ -209,6 +209,12 @@ uk_list_add_tail(struct uk_list_head *new_entry, struct uk_list_head *head) __uk_list_add(new_entry, head->prev, head); } +static inline void uk_list_add_before(struct uk_list_head *new_entry, + struct uk_list_head *old_entry) +{ + __uk_list_add(new_entry, old_entry->prev, old_entry); +} + static inline void uk_list_move(struct uk_list_head *list, struct uk_list_head *head) { diff --git a/include/uk/plat/memory.h b/include/uk/plat/memory.h index ccd93eb3bf52de7210e564eb0925f9ba5e032d7d..0d08bb73902e59801d97e0e2523444e054003db0 100644 --- a/include/uk/plat/memory.h +++ b/include/uk/plat/memory.h @@ -272,6 +272,8 @@ int ukplat_mem_init(void); * @param auxsp_len * The custom length of the auxiliary stack. If 0, then * CONFIG_UKPLAT_AUXSP_PAGE_ORDER is used instead as the default length. + * @param auxstack + * Pointer to the allocated auxiliary stack, used to store the start address. * * @return * Pointer to the allocated auxiliary stack @@ -280,7 +282,8 @@ static inline __uptr ukplat_auxsp_alloc(struct uk_alloc __maybe_unused *a, #if CONFIG_LIBUKVMEM struct uk_vas __maybe_unused *vas, #endif /* CONFIG_LIBUKVMEM */ - __sz auxsp_len) + __sz auxsp_len, + __uptr * auxstack) { __vaddr_t auxsp; @@ -331,6 +334,9 @@ static inline __uptr ukplat_auxsp_alloc(struct uk_alloc __maybe_unused *a, } #endif /* !CONFIG_LIBUKVMEM */ + if (auxstack) + *auxstack = auxsp; + /* If auxsp resulted from the previous allocations is ECTX aligned * and auxsp_len is ECTX aligned, then the function call below will * result in an ECTX aligned stack pointer. @@ -338,6 +344,48 @@ static inline __uptr ukplat_auxsp_alloc(struct uk_alloc __maybe_unused *a, return (__uptr)ukarch_gen_sp((__uptr)auxsp, auxsp_len); } +/* Free an auxiliary stack that created by ukplat_auxsp_alloc. + * The size is that given by (1 << CONFIG_AUXSP_PAGE_ORDER) * PAGE_SIZE. + * + * @param a + * The allocator to use for the auxiliary stack + * @param vas + * The virtual address space to use for the mapping of the auxiliary stack. + * This should be used in conjunction with CONFIG_LIBUKVMEM to ensure that + * accesses to the auxiliary stack do not generate page faults in more + * fragile system states. + * @param auxstack + * Pointer to the allocated auxiliary stack, used to store the start address. + * @param auxstack_len + * The custom length of the auxiliary stack. If 0, then + * CONFIG_UKPLAT_AUXSP_PAGE_ORDER is used instead as the default length. + */ +static inline void ukplat_auxsp_free(struct uk_alloc __maybe_unused *a, +#if CONFIG_LIBUKVMEM + struct uk_vas __maybe_unused *vas, +#endif /* CONFIG_LIBUKVMEM */ + __uptr auxstack, + __sz auxstack_len) +{ +#if CONFIG_LIBUKVMEM + int rc; + + /* Compitable with the behavior provided by ukplat_auxsp_alloc */ + if (!auxstack_len) + auxstack_len = + ALIGN_UP(PAGE_SIZE * (1 << CONFIG_UKPLAT_AUXSP_PAGE_ORDER), + UKARCH_ECTX_ALIGN); + + rc = uk_vma_unmap(vas, auxstack, auxstack_len, 0); + if (rc) { + uk_pr_err("Failed to unmap auxiliary stack\n"); + return; + } +#else /* !CONFIG_LIBUKVMEM */ + uk_free(a, auxstack); +#endif /* !CONFIG_LIBUKVMEM */ +} + #ifdef __cplusplus } #endif diff --git a/include/uk/plat/time.h b/include/uk/plat/time.h index 6e558d7a1f47ee305ee6e3becdbf39a642af01a0..f247a194ed681de0501463945a6dcd31931e8653 100644 --- a/include/uk/plat/time.h +++ b/include/uk/plat/time.h @@ -36,6 +36,9 @@ #include #include +#ifdef CONFIG_HAVE_SYSTICK +#include +#endif /* CONFIG_HAVE_SYSTICK */ #ifdef __cplusplus extern "C" { @@ -43,11 +46,33 @@ extern "C" { void ukplat_time_init(void); void ukplat_time_fini(void); -uint32_t ukplat_time_get_irq(void); -__nsec ukplat_time_get_ticks(void); +#ifndef CONFIG_HAVE_SYSTICK __nsec ukplat_monotonic_clock(void); +uint32_t ukplat_time_get_irq(void); +__nsec ukplat_time_get_ticks(void); __nsec ukplat_wall_clock(void); +#else +static inline __nsec ukplat_monotonic_clock(void) +{ + return tn_systick_get_monotonic(); +} + +static inline uint32_t ukplat_time_get_irq(void) +{ + return tn_systick_get_irq(); +} + +static inline __nsec ukplat_time_get_ticks(void) +{ + return (__nsec)tn_systick_get_tick(); +} + +static inline __nsec ukplat_wall_clock(void) +{ + return tn_systick_get_monotonic(); +} +#endif /* CONFIG_HAVE_SYSTICK */ /* Time tick length */ #define UKPLAT_TIME_TICK_NSEC (UKARCH_NSEC_PER_SEC / CONFIG_HZ) diff --git a/include/uk/trace_macros.h b/include/uk/trace_macros.h new file mode 100644 index 0000000000000000000000000000000000000000..29f409c32b49fadd1997156c0afb5ba0ee457e7d --- /dev/null +++ b/include/uk/trace_macros.h @@ -0,0 +1,19 @@ +#ifndef __TN_TRACE_MACROS_H__ +#define __TN_TRACE_MACROS_H__ + +#ifndef CONFIG_LIBTNTRACE + +#define TN_TRACE_FUNC(type, func, ...) do { } while (0) +#define TN_TRACE_FUNC_ENTER(type, func, ...) do { } while (0) +#define TN_TRACE_FUNC_EXIT(type, func, ...) do { } while (0) +#define TN_TRACE_OBJ_FUNC(type, func, obj, ...) do { } while (0) +#define TN_TRACE_OBJ_FUNC_ENTER(type, func, obj, ...) do { } while (0) +#define TN_TRACE_OBJ_FUNC_EXIT(type, func, obj, ...) do { } while (0) + +#else /* !CONFIG_LIBTNTRACE */ + +#include + +#endif /* CONFIG_LIBTNTRACE */ + +#endif /* __TN_TRACE_MACROS_H__ */ diff --git a/lib/Config.uk b/lib/Config.uk index 29843300f73cd861edb192951bd83a1984755f4c..2c27e1a80060614e7a5dcfd9ec4e71bf1d2e54ab 100644 --- a/lib/Config.uk +++ b/lib/Config.uk @@ -33,6 +33,10 @@ config HAVE_X86PKU bool default n +config HAVE_SYSTICK + bool + default n + ## # Compatibility entries for legacy libraries ## diff --git a/lib/Makefile.uk b/lib/Makefile.uk index 161ea305cfc6f7faa19b5cb664362c9f5698ee33..261c1931d001c389161183acd76f197b2b2fb277 100644 --- a/lib/Makefile.uk +++ b/lib/Makefile.uk @@ -56,6 +56,7 @@ $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/uknofault)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/ukring)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/uksched)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/ukschedcoop)) +$(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/tnschedprio)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/uksglist)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/uksignal)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/uksp)) @@ -69,3 +70,7 @@ $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/vfscore)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/ukrust)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/ukreloc)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/ukofw)) +$(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/tnsystick)) +$(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/tntimer)) +$(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/tntrace)) +$(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/tnperf)) diff --git a/lib/posix-time/time.c b/lib/posix-time/time.c index fbbd5c79a295d0100573c5d09d0a9d4b94da124f..b90ba63f287f07d3a1802ac9d976d012b7093f23 100644 --- a/lib/posix-time/time.c +++ b/lib/posix-time/time.c @@ -78,7 +78,7 @@ UK_SYSCALL_R_DEFINE(int, nanosleep, const struct timespec*, req, struct timespec before = ukplat_monotonic_clock(); #if CONFIG_HAVE_SCHED - uk_sched_thread_sleep(nsec); + uk_sched_thread_sleep_ns(nsec); #else __spin_wait(nsec); #endif diff --git a/lib/tnperf/Config.uk b/lib/tnperf/Config.uk new file mode 100644 index 0000000000000000000000000000000000000000..167d39d1d4c0397f250f3c4741e89df7a8a17a9f --- /dev/null +++ b/lib/tnperf/Config.uk @@ -0,0 +1,17 @@ +menuconfig LIBTNPERF + bool "tnperf: Operating System Performance Measurement Tools" + default n + +if LIBTNPERF +choice + prompt "Test Data Acquisition Method" +config LIBTNPERF_PMU + bool "PMU registers" + depends on (ARCH_ARM_64 || ARCH_ARM_32) + help + The ARM Cortex processor family in the ARM architecture has + a dedicated set of PMU registers for performance monitoring + and debugging. +endchoice + +endif diff --git a/lib/tnperf/Makefile.uk b/lib/tnperf/Makefile.uk new file mode 100644 index 0000000000000000000000000000000000000000..7d04408d10716fd5ee211d68aad2652eed72cd6e --- /dev/null +++ b/lib/tnperf/Makefile.uk @@ -0,0 +1,7 @@ +$(eval $(call addlib_s,libtnperf,$(CONFIG_LIBTNPERF))) + +CINCLUDES-$(CONFIG_LIBTNPERF) += -I$(LIBTNPERF_BASE)/include +CXXINCLUDES-$(CONFIG_LIBTNPERF) += -I$(LIBTNPERF_BASE)/include + +LIBTNPERF_SRCS-y += $(LIBTNPERF_BASE)/perf.c +LIBTNPERF_SRCS-$(CONFIG_LIBTNPERF_PMU) += $(LIBTNPERF_BASE)/pmu.c diff --git a/lib/tnperf/exportsyms.uk b/lib/tnperf/exportsyms.uk new file mode 100644 index 0000000000000000000000000000000000000000..7776f12b0070ae7bafc0802410e8037609a63f13 --- /dev/null +++ b/lib/tnperf/exportsyms.uk @@ -0,0 +1,4 @@ +tn_perf_init +tn_perf_event_register +tn_perf_event_unregister +tn_perf_read_event_counter diff --git a/lib/tnperf/include/tn/perf.h b/lib/tnperf/include/tn/perf.h new file mode 100644 index 0000000000000000000000000000000000000000..1a2def0279a5cc3a669dd653d8dcb79112b8b224 --- /dev/null +++ b/lib/tnperf/include/tn/perf.h @@ -0,0 +1,23 @@ +#ifndef __TN_PERF_H__ +#define __TN_PERF_H__ + +#include +#if CONFIG_LIBTNPERF_PMU +#include +#endif /* CONFIG_LIBTNPERF_PMU */ + +typedef int (*register_event_func)(uint8_t event_num); +typedef int (*unregister_event_func)(uint8_t event_num); +typedef uint64_t (*read_event_counter_func)(uint8_t event_num); +struct tn_perf_ops { + register_event_func event_register; + unregister_event_func event_unregister; + read_event_counter_func read_counter; +}; + +int tn_perf_init(void); +int tn_perf_event_register(uint8_t event_num); +int tn_perf_event_unregister(uint8_t event_num); +uint64_t tn_perf_read_event_counter(uint8_t event_num); + +#endif /* __TN_PERF_H__ */ diff --git a/lib/tnperf/include/tn/pmu.h b/lib/tnperf/include/tn/pmu.h new file mode 100644 index 0000000000000000000000000000000000000000..d828f102114ca6c548505da1108e56e94f779f2a --- /dev/null +++ b/lib/tnperf/include/tn/pmu.h @@ -0,0 +1,68 @@ +#ifndef __TN_PMU_H__ +#define __TN_PMU_H__ + +#define SUPPORT_EVENT_NUM 58 +#define EVENT_COUNTER_NUM 6 + +#define SW_INCR 0x00 +#define L1I_CACHE_REFILL 0x01 +#define L1I_TLB_REFILL 0x02 +#define L1D_CACHE_REFILL 0x03 +#define L1D_CACHE 0x04 +#define L1D_TLB_REFILL 0x05 +#define LD_RETIRED 0x06 +#define ST_RETIRED 0x07 +#define INST_RETIRED 0x08 +#define EXC_TAKEN 0x09 +#define EXC_RETURN 0x0A +#define CID_WRITE_RETIRED 0x0B +#define PC_WRITE_RETIRED 0x0C +#define BR_IMMED_RETIRED 0x0D +#define BR_RETURN_RETIRED 0x0E +#define UNALIGNED_LDST_RETIRED 0x0F +#define BR_MIS_PRED 0x10 +#define CPU_CYCLES 0x11 +#define BR_PRED 0x12 +#define MEM_ACCESS 0x13 +#define L1I_CACHE 0x14 +#define L1D_CACHE_WB 0x15 +#define L2D_CACHE 0x16 +#define L2D_CACHE_REFILL 0x17 +#define L2D_CACHE_WB 0x18 +#define BUS_ACCESS 0x19 +#define MEMORY_ERROR 0x1A +#define INST_SPEC 0x1B +#define TTBR_WRITE_RETIRED 0x1C +#define BUS_CYCLES 0x1D +#define CHAIN 0x1E +#define L1D_CACHE_ALLOCATE 0x1F +#define L2D_CACHE_ALLOCATE 0x20 +#define BR_RETIRED 0x21 +#define BR_MIS_PRED_RETIRED 0x22 +#define STALL_FRONTEND 0x23 +#define STALL_BACKEND 0x24 +#define L1D_TLB 0x25 +#define L1I_TLB 0x26 +#define L2I_CACHE 0x27 +#define L2I_CACHE_REFILL 0x28 +#define L3D_CACHE_ALLOCATE 0x29 +#define L3D_CACHE_REFILL 0x2A +#define L3D_CACHE 0x2B +#define L3D_CACHE_WB 0x2C +#define L2D_TLB_REFILL 0x2D +#define L2I_TLB_REFILL 0x2E +#define L2D_TLB 0x2F +#define L2I_TLB 0x30 +#define DTLB_WALK 0x34 +#define ITLB_WALK 0x35 +#define LL_CACHE_RD 0x36 +#define LL_CACHE_MISS_RD 0x37 +#define REMOTE_ACCESS_RD 0x38 +struct pmu_event { + uint8_t enable; + uint8_t counter_num; +}; + +struct tn_perf_ops *tn_pmu_init(); + +#endif /* __TN_PMU_H__ */ diff --git a/lib/tnperf/perf.c b/lib/tnperf/perf.c new file mode 100644 index 0000000000000000000000000000000000000000..9233eeb809d2c7168b65d6dad2eef14fed67087b --- /dev/null +++ b/lib/tnperf/perf.c @@ -0,0 +1,28 @@ +#include +#include +#if CONFIG_LIBTNPERF_PMU +#include +#endif /* CONFIG_LIBTNPERF_PMU */ +struct tn_perf_ops *perf_ops; + +int tn_perf_init(void) +{ +#if CONFIG_LIBTNPERF_PMU + perf_ops = tn_pmu_init(); +#endif /* CONFIG_LIBTNPERF_PMU */ + return 1; +} +int tn_perf_event_register(uint8_t event_num) +{ + return perf_ops->event_register(event_num); +} + +int tn_perf_event_unregister(uint8_t event_num) +{ + return perf_ops->event_unregister(event_num); +} + +uint64_t tn_perf_read_event_counter(uint8_t event_num) +{ + return perf_ops->read_counter(event_num); +} diff --git a/lib/tnperf/pmu.c b/lib/tnperf/pmu.c new file mode 100644 index 0000000000000000000000000000000000000000..d0e40bea6a6373b6be41b25f2ffe4517cc976efb --- /dev/null +++ b/lib/tnperf/pmu.c @@ -0,0 +1,84 @@ +#include +#include +#include + +#define VACANT_COUNTER 0 +#define BUSY_COUNTER 1 + +struct tn_perf_ops tn_pmu_ops; +uint8_t counter[EVENT_COUNTER_NUM] = { 0 }; +uint8_t pmu_event[SUPPORT_EVENT_NUM] = { 0 }; + +static int tn_pmu_event_register(uint8_t event_num) +{ + int counter_num; + + if (event_num == CPU_CYCLES) + return 0; + for (counter_num = 0; counter_num < EVENT_COUNTER_NUM; counter_num++) { + if (counter[counter_num] == BUSY_COUNTER) + continue; + counter[counter_num] = BUSY_COUNTER; + break; + } + if (counter_num == EVENT_COUNTER_NUM) { + printf("counter_num = %d\n", counter_num); + return -1; + } + pmu_event[event_num] = counter_num + 1; + __asm__ volatile("msr PMSELR_EL0, %0" : : "r"(counter_num)); + __asm__ volatile("msr PMXEVTYPER_EL0, %0" : : "r"(event_num)); + return 0; +} +static int tn_pmu_event_unregister(uint8_t event_num) +{ + int counter_num = pmu_event[event_num] - 1; + + counter[counter_num] = VACANT_COUNTER; + pmu_event[event_num] = 0; + return 0; +} +static uint64_t tn_pmu_read_event_counter(uint8_t event_num) +{ + int cnt = 0; + + if (event_num == CPU_CYCLES) { + __asm__ volatile("mrs %0, PMCCNTR_EL0" : "=r"(cnt)); + } else { + switch (pmu_event[event_num]) { + case 1: + __asm__ volatile("mrs %0, PMEVCNTR0_EL0" : "=r"(cnt)); + break; + case 2: + __asm__ volatile("mrs %0, PMEVCNTR1_EL0" : "=r"(cnt)); + break; + case 3: + __asm__ volatile("mrs %0, PMEVCNTR2_EL0" : "=r"(cnt)); + break; + case 4: + __asm__ volatile("mrs %0, PMEVCNTR3_EL0" : "=r"(cnt)); + break; + case 5: + __asm__ volatile("mrs %0, PMEVCNTR4_EL0" : "=r"(cnt)); + break; + case 6: + __asm__ volatile("mrs %0, PMEVCNTR5_EL0" : "=r"(cnt)); + break; + } + } + return cnt; +} + +struct tn_perf_ops *tn_pmu_init(void) +{ + + tn_pmu_ops.event_register = tn_pmu_event_register; + tn_pmu_ops.event_unregister = tn_pmu_event_unregister; + tn_pmu_ops.read_counter = tn_pmu_read_event_counter; + + asm volatile("msr pmcr_el0, %0" : : "r"(17)); + asm volatile("msr PMCNTENSET_EL0, %0" : : "r"(0x8000000f)); + asm volatile("msr PMOVSCLR_EL0, %0" : : "r"(0x8000000f)); + + return &tn_pmu_ops; +} diff --git a/lib/tnschedprio/Config.uk b/lib/tnschedprio/Config.uk new file mode 100644 index 0000000000000000000000000000000000000000..298d24ee7f4e5c116f29fdeac20ca462e3d39edc --- /dev/null +++ b/lib/tnschedprio/Config.uk @@ -0,0 +1,24 @@ +menuconfig LIBTNSCHEDPRIO + bool "tnschedprio: Priority scheduler with preemptive support" + default n + select LIBNOLIBC if !HAVE_LIBC + select LIBUKSCHED + select LIBUKSCHED_THREAD_PRIORITY + +if LIBTNSCHEDPRIO + config LIBTNSCHEDPRIO_ENABLE_PREEMTIVE + bool "Preemte low level thread when higher is ready" + default y + + choice LIBTNSCHEDPRIO_RUNQ + prompt "Choice runq algorithm" + default LIBTNSCHEDPRIO_RUNQ_TAILQ + config LIBTNSCHEDPRIO_RUNQ_TAILQ + depends on LIBUKSCHED_RUNQ_TAILQ + bool "Use linked queue based algorithm for run queue" + + config LIBTNSCHEDPRIO_RUNQ_LIST + depends on LIBUKSCHED_RUNQ_LIST + bool "Use double linked list based algorithm for run queue" + endchoice +endif diff --git a/lib/tnschedprio/Makefile.uk b/lib/tnschedprio/Makefile.uk new file mode 100644 index 0000000000000000000000000000000000000000..63d21ac388ab3e4ac5b8df3bdbafc63559a693f0 --- /dev/null +++ b/lib/tnschedprio/Makefile.uk @@ -0,0 +1,7 @@ +$(eval $(call addlib_s,libtnschedprio,$(CONFIG_LIBTNSCHEDPRIO))) + +CINCLUDES-$(CONFIG_LIBTNSCHEDPRIO) += -I$(LIBTNSCHEDPRIO_BASE)/include +CXXINCLUDES-$(CONFIG_LIBTNSCHEDPRIO) += -I$(LIBTNSCHEDPRIO_BASE)/include + +LIBTNSCHEDPRIO_SRCS-y += $(LIBTNSCHEDPRIO_BASE)/schedprio.c +LIBTNSCHEDPRIO_SRCS-y += $(LIBTNSCHEDPRIO_BASE)/isrwoken.c|isr diff --git a/lib/tnschedprio/exportsyms.uk b/lib/tnschedprio/exportsyms.uk new file mode 100644 index 0000000000000000000000000000000000000000..c99178f77a9ad1bf2cd28649694901999e5424bf --- /dev/null +++ b/lib/tnschedprio/exportsyms.uk @@ -0,0 +1 @@ +tn_schedprio_create diff --git a/lib/tnschedprio/include/tn/schedprio.h b/lib/tnschedprio/include/tn/schedprio.h new file mode 100644 index 0000000000000000000000000000000000000000..7d3805061cbff27a52e20932c826e73be59ec5ee --- /dev/null +++ b/lib/tnschedprio/include/tn/schedprio.h @@ -0,0 +1,35 @@ +/* Copyright 2023 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Preemptive priority scheduler. + */ + +#ifndef __TN_SCHEDPRIO_H__ +#define __TN_SCHEDPRIO_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct uk_sched *tn_schedprio_create(struct uk_alloc *a); + +#ifdef __cplusplus +} +#endif + +#endif /* __TN_SCHEDPRIO_H__ */ diff --git a/lib/tnschedprio/isrwoken.c b/lib/tnschedprio/isrwoken.c new file mode 100644 index 0000000000000000000000000000000000000000..19e764d492fb9b82b4975f8db112ba3f0934b033 --- /dev/null +++ b/lib/tnschedprio/isrwoken.c @@ -0,0 +1,27 @@ +/* Copyright 2023 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "schedprio.h" + +void schedprio_thread_woken_isr(struct uk_sched *s, struct uk_thread *t) +{ + struct schedprio *c = uksched2schedprio(s); + + UK_ASSERT(ukplat_lcpu_irqs_disabled()); + + if (uk_thread_is_queueable(t) && uk_thread_is_runnable(t)) { + _runq_add(c, t); + uk_thread_clear_queueable(t); + } +} diff --git a/lib/tnschedprio/schedprio.c b/lib/tnschedprio/schedprio.c new file mode 100644 index 0000000000000000000000000000000000000000..c0d69142a934a481905ac581df5b771274c71b3f --- /dev/null +++ b/lib/tnschedprio/schedprio.c @@ -0,0 +1,288 @@ +/* Copyright 2023 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "schedprio.h" + +static inline void schedprio_schedule(struct schedprio *c, bool yield) +{ + struct uk_thread *prev, *next; + unsigned long flags; + bool runnable; + int cmp_value; + + prev = uk_thread_current(); + flags = ukplat_lcpu_save_irqf(); + + next = _runq_best(c); + if (!next) + goto out_without_switch; + runnable = uk_thread_is_runnable(prev); + if (!runnable) { + /* Always switch when current thread is not runnable. + * idle thread will always be runnable, it's safe to do this. + */ + goto switch_thread; + } + + cmp_value = schedprio_prio_cmp(prev, next); + + /* If we have a runnable thread with higher priority than the current + * one, we switch to it. + */ + if (!yield) { +#ifdef CONFIG_LIBTNSCHEDPRIO_ENABLE_PREEMTIVE + if (cmp_value >= 0) + goto out_without_switch; + else + goto switch_thread; +#else + goto out_without_switch; +#endif + } else { + if (cmp_value > 0) + goto out_without_switch; + else + goto switch_thread; + } + +switch_thread: + if (next != prev) { + /* + * Schedule idle thread that will halt the CPU + * We select the idle thread only if we do not + * have anything else to execute + */ + _runq_remove(c, next); + if (runnable) + _runq_add(c, prev); + + /* + * Queueable is used to cover the case when during a + * context switch, the thread that is about to be + * evacuated is interrupted and woken up. + */ + uk_thread_set_queueable(prev); + uk_thread_clear_queueable(next); + + ukplat_lcpu_restore_irqf(flags); + + /* Interrupting the switch is equivalent to having the next + * thread interrupted at the return instruction. And therefore + * at safe point. + */ + uk_sched_thread_switch(next); + return; + } + +out_without_switch: + ukplat_lcpu_restore_irqf(flags); +} + +static void schedprio_yield(struct uk_sched *s) +{ + struct schedprio *c = uksched2schedprio(s); + + schedprio_schedule(c, true); +} + +static void schedprio_reschedule(struct uk_sched *s) +{ + struct schedprio *c = uksched2schedprio(s); + + schedprio_schedule(c, false); +} + +static int schedprio_thread_add(struct uk_sched *s, struct uk_thread *t) +{ + struct schedprio *c = uksched2schedprio(s); + + UK_ASSERT(t); + UK_ASSERT(!uk_thread_is_exited(t)); + + if (t->prio < UK_THREADF_LOWEST_PRIO + || t->prio > UK_THREADF_HIGHEST_PRIO) { + uk_pr_err("Thread %s has invalid priority %d\n", t->name, + t->prio); + return -EINVAL; + } + + /* Add to run queue in priority ascending order if runnable */ + if (uk_thread_is_runnable(t)) + _runq_add(c, t); + + return 0; +} + +static void schedprio_thread_remove(struct uk_sched *s, struct uk_thread *t) +{ + struct schedprio *c = uksched2schedprio(s); + + /* Remove from run_queue */ + if (t != uk_thread_current() && uk_thread_is_runnable(t)) + _runq_remove(c, t); +} + +static void schedprio_thread_blocked(struct uk_sched *s, struct uk_thread *t) +{ + struct schedprio *c = uksched2schedprio(s); + + UK_ASSERT(ukplat_lcpu_irqs_disabled()); + + if (t != uk_thread_current()) + _runq_remove(c, t); +} + +static __noreturn void idle_thread_fn(void *argp) +{ + struct schedprio *c = (struct schedprio *)argp; + unsigned long flags; + + UK_ASSERT(c); + + for (;;) { + flags = ukplat_lcpu_save_irqf(); + /* + * FIXME: We assume that `uk_sched_thread_gc()` is non-blocking + * because we implement a cooperative scheduler. However, + * this assumption may not be true depending on the + * destructor functions that are assigned to the threads + * and are called by `uk_sched_thred_gc()`. + * Also check if in the meantime we got a runnable + * thread. + * NOTE: This idle thread must be non-blocking so that the + * scheduler has always something to schedule. + */ + if (uk_sched_thread_gc(&c->sched) > 0 || !_is_runq_empty(c)) { + /* We collected successfully some garbage or there is + * a runnable thread in the queue. + * Check if something else can be scheduled now. + */ + ukplat_lcpu_restore_irqf(flags); + schedprio_schedule(c, true); + + continue; + } + ukplat_lcpu_restore_irqf(flags); + + /* Read return time set by last schedule operation */ + tn_systick_block_until(tn_systick_get_tick() + + tn_timer_next_tick()); + + /* try to schedule a thread that might now be available */ + schedprio_schedule(c, true); + } +} + +static int schedprio_start(struct uk_sched *s __maybe_unused, + struct uk_thread *main_thread __maybe_unused) +{ + UK_ASSERT(main_thread); + UK_ASSERT(main_thread->sched == s); + UK_ASSERT(uk_thread_is_runnable(main_thread)); + UK_ASSERT(!uk_thread_is_exited(main_thread)); + UK_ASSERT(uk_thread_current() == main_thread); + + /* NOTE: We do not put `main_thread` into the thread list. + * Current running threads will be added as soon as + * a different thread is scheduled. + */ + + ukplat_lcpu_enable_irq(); + + return 0; +} + +static const struct uk_thread *schedprio_idle_thread(struct uk_sched *s, + unsigned int proc_id) +{ + struct schedprio *c = uksched2schedprio(s); + + /* NOTE: We only support one processing LCPU (for now) */ + if (proc_id > 0) + return NULL; + + return &(c->idle); +} + +void schedprio_set_priority(struct uk_sched *s, + struct uk_thread *thread, + int32_t priority) +{ + struct schedprio *c = uksched2schedprio(s); + + UK_ASSERT(thread); + UK_ASSERT(thread->sched == s); + UK_ASSERT(uk_thread_is_runnable(thread)); + UK_ASSERT(!uk_thread_is_exited(thread)); + UK_ASSERT(uk_thread_current() == thread); + UK_ASSERT(priority >= UK_THREADF_LOWEST_PRIO + && priority <= UK_THREADF_HIGHEST_PRIO); + + thread->prio = priority; + + /* Remove from run_queue */ + if (thread != uk_thread_current() && uk_thread_is_runnable(thread)) { + _runq_remove(c, thread); + _runq_add(c, thread); + } +} + +struct uk_sched *tn_schedprio_create(struct uk_alloc *a) +{ + struct schedprio *c = NULL; + int rc; + + uk_pr_info("Initializing priority scheduler\n"); + c = uk_zalloc(a, sizeof(struct schedprio)); + if (!c) + goto err_out; + + _runq_init(c); + + /* Create idle thread */ + rc = uk_thread_init_fn1(&c->idle, idle_thread_fn, (void *)c, a, + STACK_SIZE, a, + 0, /* Default auxiliary stack size */ + a, false, NULL, "idle", NULL, NULL); + if (rc < 0) + goto err_free_c; + c->idle.prio = UK_THREADF_IDLE_PRIO; + c->idle.sched = &c->sched; + + uk_sched_init(&c->sched, schedprio_start, schedprio_yield, + schedprio_reschedule, schedprio_thread_add, + schedprio_thread_remove, schedprio_thread_blocked, + schedprio_thread_woken_isr, schedprio_thread_woken_isr, + schedprio_set_priority, schedprio_prio_cmp, + schedprio_idle_thread, a); + + /* Add idle thread to the scheduler's thread list */ + UK_TAILQ_INSERT_TAIL(&c->sched.thread_list, &c->idle, thread_list); + _runq_add(c, &c->idle); + + return &c->sched; + +err_free_c: + uk_free(a, c); +err_out: + return NULL; +} diff --git a/lib/tnschedprio/schedprio.h b/lib/tnschedprio/schedprio.h new file mode 100644 index 0000000000000000000000000000000000000000..c967f52ce8fa372d9e57423c9c996da7f6679b78 --- /dev/null +++ b/lib/tnschedprio/schedprio.h @@ -0,0 +1,154 @@ +/* Copyright 2023 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __TN_SCHEDPRIO_SCHEDPRIO_H__ +#define __TN_SCHEDPRIO_SCHEDPRIO_H__ + +#include +#include + +struct schedprio { + struct uk_sched sched; +#if defined(CONFIG_LIBTNSCHEDPRIO_RUNQ_TAILQ) + UK_TAILQ_HEAD(run_queue, struct uk_thread) run_queue; +#elif defined(CONFIG_LIBTNSCHEDPRIO_RUNQ_LIST) + struct uk_list_head run_queue; +#endif + + struct uk_thread idle; + __nsec idle_return_time; +}; + +#if defined(CONFIG_LIBTNSCHEDPRIO_RUNQ_TAILQ) +#define _runq_init runq_tailq_init +#define _is_runq_empty runq_tailq_is_empty +#define _runq_add runq_tailq_add +#define _runq_remove runq_tailq_remove +#define _runq_best runq_tailq_best + +#define _runq_foreach UK_TAILQ_FOREACH +#define _runq_foreach_safe UK_TAILQ_FOREACH_SAFE + +#elif defined(CONFIG_LIBTNSCHEDPRIO_RUNQ_LIST) +#define _runq_init runq_list_init +#define _is_runq_empty runq_list_is_empty +#define _runq_add runq_list_add +#define _runq_remove runq_list_remove +#define _runq_best runq_list_best + +#define _runq_foreach uk_list_for_each_entry +#define _runq_foreach_safe(var, head, field, tvar) \ + uk_list_for_each_entry_safe(var, tvar, head, field) +#endif + +static inline int schedprio_prio_cmp(struct uk_thread *t1, struct uk_thread *t2) +{ + return t1->prio - t2->prio; +} + +static inline void dump_run_queue(struct schedprio *c) +{ + struct uk_thread *t = NULL; + + uk_pr_info("Run queue: "); + _runq_foreach(t, &c->run_queue, queue) { + uk_pr_info("%s(%d) ", t->name, t->prio); + } + uk_pr_info("\n"); +} + +#if defined(CONFIG_LIBTNSCHEDPRIO_RUNQ_TAILQ) +static inline void runq_tailq_init(struct schedprio *c) +{ + UK_TAILQ_INIT(&c->run_queue); +} + +static inline bool runq_tailq_is_empty(struct schedprio *c) +{ + return UK_TAILQ_EMPTY(&c->run_queue); +} + +static inline void runq_tailq_add(struct schedprio *c, struct uk_thread *t) +{ + struct uk_thread *tmp = NULL; + + UK_TAILQ_FOREACH(tmp, &c->run_queue, queue) { + if (schedprio_prio_cmp(t, tmp) > 0) + break; + } + if (tmp) + UK_TAILQ_INSERT_BEFORE(tmp, t, queue); + else + UK_TAILQ_INSERT_TAIL(&c->run_queue, t, queue); +} + +static inline struct uk_thread *runq_tailq_best(struct schedprio *c) +{ + return UK_TAILQ_FIRST(&c->run_queue); +} + +static inline void runq_tailq_remove(struct schedprio *c, struct uk_thread *t) +{ + UK_TAILQ_REMOVE(&c->run_queue, t, queue); +} +#endif + +#if defined(CONFIG_LIBTNSCHEDPRIO_RUNQ_LIST) +static inline void runq_list_init(struct schedprio *c) +{ + UK_INIT_LIST_HEAD(&c->run_queue); +} + +static inline bool runq_list_is_empty(struct schedprio *c) +{ + return uk_list_empty(&(c->run_queue)); +} + +static inline void runq_list_add(struct schedprio *c, struct uk_thread *t) +{ + struct uk_thread *tmp = NULL; + + uk_list_for_each_entry(tmp, &c->run_queue, queue) { + if (schedprio_prio_cmp(t, tmp) > 0) { + uk_list_add_before(&t->queue, &tmp->queue); + break; + } + } + if (&tmp->queue == &c->run_queue) + uk_list_add_tail(&t->queue, &c->run_queue); +} + +static inline void runq_list_remove(struct schedprio *c __unused, + struct uk_thread *t) +{ + uk_list_del(&t->queue); +} + +static inline struct uk_thread *runq_list_best(struct schedprio *c) +{ + return uk_list_first_entry_or_null(&c->run_queue, struct uk_thread, + queue); +} +#endif + +static inline struct schedprio *uksched2schedprio(struct uk_sched *s) +{ + UK_ASSERT(s); + + return __containerof(s, struct schedprio, sched); +} + +void schedprio_thread_woken_isr(struct uk_sched *s, struct uk_thread *t); + +#endif /* __TN_SCHEDPRIO_SCHEDPRIO_H__ */ diff --git a/lib/tnsystick/Config.uk b/lib/tnsystick/Config.uk new file mode 100644 index 0000000000000000000000000000000000000000..ac4c403b99c19e1a3c14d40757fe3cf7ff565d13 --- /dev/null +++ b/lib/tnsystick/Config.uk @@ -0,0 +1,16 @@ +menuconfig LIBTNSYSTICK + bool "tnsystick: Kernel systick configuration" + default y if !(PLAT_LINUXU || PLAT_XEN) + select HAVE_SYSTICK + +if LIBTNSYSTICK + +config LIBTNSYSTICK_TICKLESS + bool "Trigger kernel systick interrupt in tickless mode" + default n + +config LIBTNSYSTICK_FREQ + int "Frequency of triggering kernel systick" + default 1000 + +endif diff --git a/lib/tnsystick/Makefile.uk b/lib/tnsystick/Makefile.uk new file mode 100644 index 0000000000000000000000000000000000000000..2576f72f2b535f30192bfadad770704a77045f42 --- /dev/null +++ b/lib/tnsystick/Makefile.uk @@ -0,0 +1,9 @@ +$(eval $(call addlib_s,libtnsystick,$(CONFIG_LIBTNSYSTICK))) + +ASINCLUDES-$(CONFIG_LIBTNSYSTICK) += -I$(LIBTNSYSTICK_BASE)/include +CINCLUDES-$(CONFIG_LIBTNSYSTICK) += -I$(LIBTNSYSTICK_BASE)/include +CXXINCLUDES-$(CONFIG_LIBTNSYSTICK) += -I$(LIBTNSYSTICK_BASE)/include + +LIBTNSYSTICK_CINCLUDES-y += -I$(CONFIG_UK_BASE)/plat/common/include + +LIBTNSYSTICK_SRCS-$(CONFIG_LIBTNSYSTICK) += $(LIBTNSYSTICK_BASE)/tnsystick.c diff --git a/lib/tnsystick/exportsyms.uk b/lib/tnsystick/exportsyms.uk new file mode 100644 index 0000000000000000000000000000000000000000..49b8294b5b1702a2018914f65fff02e8a9e7b7af --- /dev/null +++ b/lib/tnsystick/exportsyms.uk @@ -0,0 +1,10 @@ +tn_systick_get_tick +tn_systick_init +tn_systick_start +tn_systick_set_timeout +tn_systick_get_irq +tn_systick_register +tn_systick_block_until +tn_systick_get_monotonic +ticks_to_ns +ns_to_ticks \ No newline at end of file diff --git a/lib/tnsystick/include/tn/systick.h b/lib/tnsystick/include/tn/systick.h new file mode 100644 index 0000000000000000000000000000000000000000..cbbdb4fe2b9c1b2f590dd8b684dda000aead11a6 --- /dev/null +++ b/lib/tnsystick/include/tn/systick.h @@ -0,0 +1,104 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TN_LIBTNSYSTICK_H__ +#define __TN_LIBTNSYSTICK_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**< Maximum number of UINT32 */ +#define TICK_UINT32_MAX 0xffffffff +/**< Maximum number of UINT64 */ +#define TICK_UINT64_MAX 0xffffffffffffffff +#define TICK_MAX TICK_UINT64_MAX + +typedef uint64_t systick_t; + +/* sysclock oprations */ +struct sysclock_desc { + /* Name of the system timer */ + const char *name; + uint32_t freq; + struct uk_intctlr_irq *irq; +}; + +/** + * Initialise system tick + * + * This function initialises the system clock driver and systick. + * + */ +int tn_systick_init(void); + +/** + * Get current systick value + * + * @return current systick value + */ +systick_t tn_systick_get_tick(void); + +/** + * Get systick irq number + * + * Irq number was initialised during tn_systick_init. + * + * @return systick irq number + */ +uint32_t tn_systick_get_irq(void); + +/** + * Start systick irq + * + * This function does only one thing: unmasks the interrupt of systick. + * + */ +void tn_systick_start(void); + +/** + * Set the timeout as the next systick irq. + * @param ticks: The ticks need to set. + */ +void tn_systick_set_timeout(systick_t ticks); + +/** + * Wait and halt until the specified systick. + */ +void tn_systick_block_until(systick_t ticks); + +/** + * ticks_to_ns - Convert systicks to ns. + * @param ticks: The ticks need to convert. + */ +__nsec ticks_to_ns(systick_t ticks); + +/** + * ticks_to_ns - Convert ns to systicks. + * @param ns: The ns need to convert. + */ +systick_t ns_to_ticks(__nsec ns); + +__nsec tn_systick_get_monotonic(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __TN_LIBTNSYSTICK_H__ */ diff --git a/lib/tnsystick/include/tn/systick_impl.h b/lib/tnsystick/include/tn/systick_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..7080c5c79019c1babed419b2f58560f9a1569045 --- /dev/null +++ b/lib/tnsystick/include/tn/systick_impl.h @@ -0,0 +1,74 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TN_LIBTNSYSTICK_IMPL_H__ +#define __TN_LIBTNSYSTICK_IMPL_H__ + +#include +#include +#include +#include + +#define __MAX_CONVERT_SECS 3600UL +#define __MAX_CONVERT_NS (__MAX_CONVERT_SECS * ukarch_time_sec_to_nsec(1)) + +/* + * Calculate multiplier/shift factors for scaled math. + */ +static inline void calculate_mult_shift(uint32_t *mult, uint8_t *shift, + uint64_t from, uint64_t to) +{ + uint64_t tmp; + uint32_t sft, sftacc = 32; + + /* + * Calculate the shift factor which is limiting the conversion + * range: + */ + tmp = ((uint64_t)__MAX_CONVERT_SECS * from) >> 32; + while (tmp) { + tmp >>= 1; + sftacc--; + } + + /* + * Calculate shift factor (S) and scaling multiplier (M). + * + * (S) needs to be the largest shift factor (<= max_shift) where + * the result of the M calculation below fits into uint32_t + * without truncation. + * + * multiplier = (target << shift) / source + */ + for (sft = 32; sft > 0; sft--) { + tmp = (uint64_t)to << sft; + + /* Ensuring we round to nearest when calculating the + * multiplier + */ + tmp += from / 2; + tmp /= from; + if ((tmp >> sftacc) == 0) + break; + } + *mult = tmp; + *shift = sft; +} + +void tn_systick_register(const char *name, + uint32_t freq, + struct uk_intctlr_irq *irq); + +#endif /* __TN_LIBTNSYSTICK_IMPL_H__ */ diff --git a/lib/tnsystick/tnsystick.c b/lib/tnsystick/tnsystick.c new file mode 100644 index 0000000000000000000000000000000000000000..a5be6739d8ed9790f0313e7c451c79b19e6a5770 --- /dev/null +++ b/lib/tnsystick/tnsystick.c @@ -0,0 +1,245 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ssANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +/* current tick value */ +static systick_t cur_systick; +/* Last count recoreded when systick is updated*/ +static uint64_t last_count; +/* Number of system clock counts per tick */ +static uint32_t counts_per_tick; +/* Flag indicating systick library initialized */ +static uint8_t initialized; + +struct sysclock_desc sysclock; +static uint32_t systick_freq; + +/* Shift factor for converting ticks to ns */ +static uint8_t shift_tick_to_ns; +/* Shift factor for converting ns to ticks */ +static uint8_t shift_ns_to_tick; +/* Multiplier for converting ticks to nsecs */ +static uint32_t ns_per_tick; +/* Multiplier for converting nsecs to ticks */ +static uint32_t tick_per_ns; +/* Total (absolute) number of nanoseconds per tick */ +static uint64_t tot_ns_per_tick; + +static uint64_t max_convert_ticks; + +/* elapsed_tick returns ticks elasped from last tick interrupt occurred */ +static inline uint32_t elapsed_tick(void) +{ + return (unsigned long)(tn_sysclock_get_counts() - last_count) + / counts_per_tick; +} + +static inline void systick_update(void) +{ + uint32_t diff_tick = elapsed_tick(); + + cur_systick += diff_tick; + last_count += diff_tick * counts_per_tick; +} + +int sys_timer_irq_handler(void *arg __unused) +{ + /* 1. Let sysclock do per isr ops */ + tn_sysclock_isr_notify(); + + /* 2. Update cur_systick and last_count */ + systick_update(); + + /* 3. Set next tick for non-tickless mode */ +#ifdef CONFIG_LIBTNSYSTICK_TICKLESS + /* Let set_timeout call from timer unmask clock irq. */ + tn_sysclock_mask_irq(); +#else + tn_sysclock_set_next(last_count + counts_per_tick, 0); + tn_sysclock_unmask_irq(); +#endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ + + /* 4. Check timer */ + tn_timer_announce(); + + /* 5. TODO: schedprio to check timeout threads */ + + /* todo: Interrupt processing temporarily returns 0 */ + return 0; +} + +systick_t tn_systick_get_tick(void) +{ +#ifdef CONFIG_LIBTNSYSTICK_TICKLESS + /* It's hard to restrict other library(such as logger) not to call this + * method before init is called, althrough other RTOS did this. + */ + if (unlikely(!initialized)) + return 0; + return cur_systick + elapsed_tick(); +#else + return cur_systick; +#endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ +} + +static void systick_convert_init(void) +{ + /* Absolute number of ns per tick */ + tot_ns_per_tick = ukarch_time_sec_to_nsec(1) / CONFIG_LIBTNSYSTICK_FREQ; + + /* Absolute number of counts per tick */ + counts_per_tick = sysclock.freq / CONFIG_LIBTNSYSTICK_FREQ; + + /* + * Calculate the shift factor and scaling multiplier for + * converting ticks to ns. + */ + calculate_mult_shift(&ns_per_tick, &shift_tick_to_ns, + CONFIG_LIBTNSYSTICK_FREQ, + ukarch_time_sec_to_nsec(1)); + + /* We disallow zero ns_per_tick */ + UK_BUGON(!ns_per_tick); + + /* + * Calculate the shift factor and scaling multiplier for + * converting ns to ticks. + */ + calculate_mult_shift(&tick_per_ns, &shift_ns_to_tick, + ukarch_time_sec_to_nsec(1), + CONFIG_LIBTNSYSTICK_FREQ); + + /* We disallow zero tick_per_ns */ + UK_BUGON(!tick_per_ns); + + max_convert_ticks = TICK_MAX / 2 / counts_per_tick; +} + +int tn_systick_init(void) +{ + int ret; + + ret = tn_sysclock_probe(); + if (ret != 0) + return ret; + + systick_freq = CONFIG_LIBTNSYSTICK_FREQ; + if ((systick_freq == 0) || (systick_freq > sysclock.freq)) { + uk_pr_err( + "invalid system tick frequency, set it default : %d\n", + sysclock.freq); + systick_freq = sysclock.freq; + } + counts_per_tick = sysclock.freq / CONFIG_LIBTNSYSTICK_FREQ; + + /* initialize cur_systick convert value */ + systick_convert_init(); + /* register time base irq */ + uk_pr_debug("sysclock.irq->id : %d\n", sysclock.irq->id); + uk_intctlr_irq_register(sysclock.irq->id, sys_timer_irq_handler, NULL); + + tn_sysclock_mask_irq(); + systick_update(); + tn_sysclock_set_next(last_count + counts_per_tick, 1); + + initialized = 1; + return 0; +} + +void tn_systick_start(void) +{ + tn_sysclock_unmask_irq(); +} + +uint32_t tn_systick_get_irq(void) +{ + return sysclock.irq->id; +} + +void tn_systick_set_timeout(systick_t ticks __maybe_unused) +{ +#ifdef CONFIG_LIBTNSYSTICK_TICKLESS + ticks = MIN(ticks, max_convert_ticks); + ticks = MIN(ticks, TICK_UINT32_MAX / 2); + uint64_t next_count = + (cur_systick + elapsed_tick() + ticks) * counts_per_tick; + + tn_sysclock_set_next(next_count, 0); + tn_sysclock_unmask_irq(); +#endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ +} + +void tn_systick_register(const char *name, + uint32_t freq, + struct uk_intctlr_irq *irq) +{ + sysclock.name = name; + sysclock.freq = freq; + sysclock.irq = irq; +} + +__nsec ticks_to_ns(systick_t ticks) +{ + if (ticks > max_convert_ticks) { + /* We have reached the maximum number of ticks to convert using + * the shift factor + */ + return (ticks * tot_ns_per_tick); + } else { + return (ns_per_tick * ticks) >> shift_tick_to_ns; + } +} + +systick_t ns_to_ticks(__nsec ns) +{ + systick_t isceil = 0; + + if (ns % tot_ns_per_tick) + isceil = 1; + if (ns > __MAX_CONVERT_NS) { + /* We have reached the maximum number of ns to convert using the + * shift factor + */ + return (ns / tot_ns_per_tick + isceil); + } else { + return ((tick_per_ns * ns) >> shift_ns_to_tick) + isceil; + } +} + +/* return ns which based on ticks */ +__nsec tn_systick_get_monotonic(void) +{ + return ticks_to_ns((uint64_t)tn_systick_get_tick()); +} + +void tn_systick_block_until(systick_t until) +{ + unsigned long flags; + + while (tn_systick_get_tick() < until) { + flags = ukplat_lcpu_save_irqf(); + + ukplat_lcpu_halt_irq(); + + ukplat_lcpu_restore_irqf(flags); + ukplat_lcpu_enable_irq(); + } +} diff --git a/lib/tntimer/Config.uk b/lib/tntimer/Config.uk new file mode 100644 index 0000000000000000000000000000000000000000..f1149715dd16c8daa2760391eedff45217090056 --- /dev/null +++ b/lib/tntimer/Config.uk @@ -0,0 +1,15 @@ +menuconfig LIBTNTIMER + bool "timer: Kernel timer configuration" + select LIBTNSYSTICK + default n + + +if LIBTNTIMER + config LIBTNTIMER_TEST + bool "Enable unit tests" + default n + select LIBUKTEST + config LIBTNTIMER_TRACE + bool "Enable timer trace" + default n +endif diff --git a/lib/tntimer/Makefile.uk b/lib/tntimer/Makefile.uk new file mode 100644 index 0000000000000000000000000000000000000000..05db071cdb1a325d78521795fc5242ed140284a6 --- /dev/null +++ b/lib/tntimer/Makefile.uk @@ -0,0 +1,18 @@ +$(eval $(call addlib_s,libtntimer,$(CONFIG_LIBTNTIMER))) + +ASINCLUDES-$(CONFIG_LIBTNTIMER) += -I$(LIBTNTIMER_BASE)/include +CINCLUDES-$(CONFIG_LIBTNTIMER) += -I$(LIBTNTIMER_BASE)/include +CXXINCLUDES-$(CONFIG_LIBTNTIMER) += -I$(LIBTNTIMER_BASE)/include +LIBTNTIMER_ASINCLUDES-y += -I$(UK_PLAT_COMMON_BASE)/include +LIBTNTIMER_CINCLUDES-y += -I$(UK_PLAT_COMMON_BASE)/include + +LIBTNTIMER_SRCS-$(CONFIG_LIBTNTIMER) += $(LIBTNTIMER_BASE)/tntimer.c + + +ifneq ($(filter y,$(CONFIG_LIBTNTIMER_TEST) $(CONFIG_LIBUKTEST_ALL)),) +LIBTNTIMER_SRCS-y += $(LIBTNTIMER_BASE)/tests/test_tntimer.c +endif + +ifneq ($(filter y,$(CONFIG_LIBTNTIMER_TRACE) $(CONFIG_LIBTNTRACE_ALL)),) +LIBTNTIMER_SRCS-y += $(LIBTNTIMER_BASE)/trace/trace_timer.c +endif diff --git a/lib/tntimer/exportsyms.uk b/lib/tntimer/exportsyms.uk new file mode 100644 index 0000000000000000000000000000000000000000..6d3652acd3611e23645fbb4cb8dda872377b3b1a --- /dev/null +++ b/lib/tntimer/exportsyms.uk @@ -0,0 +1,7 @@ +tn_timer_create +tn_timer_start +tn_timer_delete +tn_timer_init +tn_timer_add +tn_timer_next_tick +tn_timer_announce \ No newline at end of file diff --git a/lib/tntimer/include/tn/timer.h b/lib/tntimer/include/tn/timer.h new file mode 100644 index 0000000000000000000000000000000000000000..2e22a3dd630e5d2c8b03ed554d0132deca6d0f7d --- /dev/null +++ b/lib/tntimer/include/tn/timer.h @@ -0,0 +1,141 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TN_TIMER_H__ +#define __TN_TIMER_H__ + +#include +#include +#include + + +#define TN_TIMER_FLAG_PERIODIC 0x01 +#define TN_TIMER_FLAG_ONE_SHOT 0x02 + + + +struct timer { + /*List node which contains pointers for traversing prev and next*/ + struct uk_list_head list; + + /* + * The relative difference in timeout occurs. + * The tick passed as a parameter when the external component is + * invoked for creation will modify this value + */ + systick_t init_tick; + /* + * an absolute time and is not subject to external modification; + * it can only be altered during 'start' (added to the list). + */ + systick_t timeout_tick; + /* + * Timeout callback function. + * When this timeout expires, this function will be executed. + */ + void (*timeout_func)(void *parameter); + /*Parameters of the timeout callback function.*/ + void *parameter; + /*Timer flag*/ + unsigned long flag; +}; + +/** + * tn_timer_create - Creates a new timer object. + * + * @param init_tick The initial tick count for the timer. + * @param timeout_func: The function to be called upon timer timeout. + * @param parameter: The parameter to be passed to the timeout function. + * @param flag Timer flags (e.g., periodic or one-shot). + * @return timer a pointer to the newly created timer + * Allocates memory for a new timer and initializes its members. + * Returns a pointer to the newly created timer or NULL + * if memory allocation fails. + */ +struct timer *tn_timer_create( + systick_t init_tick, + void (*timeout_func)(void *parameter), + void *parameter, + unsigned long flag); + + +/** + * tn_timer_start - Starts a timer and schedules it in the active timer list. + * @param t: The timer object to start. + * + * Calculates the timeout tick based on the current systick + * value and the timer's initial tick.Adds the timer to the appropriate + * list based on whether an overflow has occurred. + */ +void tn_timer_start(struct timer *timer); + + +/** + * tn_timer_delete - Removes a timer from the active timer list. + * @param t: The timer object to be removed. + * + * Removes the specified timer from the list and handles cleanup if necessary. + */ +void tn_timer_delete(struct timer *timer); + +/** + * tn_timer_init - Initializes a timer object. + * @param t The timer object to initialize. + * @param init_tick: The initial tick count for the timer. + * @param timeout_func: The function to be called upon timer timeout. + * @param parameter: The parameter to be passed to the timeout function. + * @param flag: Timer flags (e.g., periodic or one-shot). + * + * Initializes the members of a timer object. + */ +void tn_timer_init( + struct timer *t, + systick_t init_tick, + void (*timeout_func)(void *parameter), + void *parameter, + unsigned long flag); + +/** + * tn_timer_add - Adds a timer to the specified list based on its timeout tick. + * @param in: The timer object to be added. + * @param head: The list head where the timer will be added. + * + * Iterates through the specified list and inserts + * the timer in the correct position + * based on its timeout tick value. + */ +void tn_timer_add(struct timer *in, struct uk_list_head *head); + +/* + * tn_timer_next_tick - Retrieves the tick value of the soonest expiring timer. + * + * Returns the tick value of the soonest expiring timer or + * TICK_MAX if no timers are active. + */ +systick_t tn_timer_next_tick(void); + + +/* + * tn_timer_announce - Handles timer timeouts and executes associated functions. + * + * Retrieves the current systick value and iterates through + * the active timer list.For each timer with a timeout tick + * less than or equal to the current systick,the associated + * timeout function is called, and the timer is removed from the list. + * If the timer is periodic, it is restarted. + */ +void tn_timer_announce(void); + +#endif /* __TN_TIMER_H__ */ diff --git a/lib/tntimer/tests/internal_timer.h b/lib/tntimer/tests/internal_timer.h new file mode 100644 index 0000000000000000000000000000000000000000..c63817e8095aeae9da49eb1ff1df8bcf4c54a11f --- /dev/null +++ b/lib/tntimer/tests/internal_timer.h @@ -0,0 +1,29 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TN_INTERNAL_TIMER_H__ +#define __TN_INTERNAL_TIMER_H__ + +void tn_timer_list_switch(void); + +struct uk_list_head *tn_timer_get_overflow_list(void); + +/* + * tn_timer_get_list - Retrieves the global timer list. + * + * Returns a pointer to the head of the timer list. + */ +struct uk_list_head *tn_timer_get_list(void); +#endif /* __TN_INTERNAL_TIMER_H__ */ diff --git a/lib/tntimer/tests/test_tntimer.c b/lib/tntimer/tests/test_tntimer.c new file mode 100644 index 0000000000000000000000000000000000000000..71303369cd4cc1670f9064271b62e09de6287b28 --- /dev/null +++ b/lib/tntimer/tests/test_tntimer.c @@ -0,0 +1,219 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "internal_timer.h" + +#define pr_info(fmt, ...) \ + _uk_printk(KLVL_INFO, __NULL, __NULL, 0x0, fmt, ##__VA_ARGS__) + + +int excution; + +void timeout_func1(void *parameter) +{ + pr_info("timeout func1\n"); +} + +void timeout_func3(void *parameter) +{ + pr_info("timeout func3\n"); +} + +void timeout_func2(void *parameter) +{ + excution++; +} + +void dump_timer(void) +{ + struct timer *node; + struct uk_list_head *timer_list_head; + + timer_list_head = tn_timer_get_list(); + UK_ASSERT(timer_list_head != NULL); + uk_list_for_each_entry(node, timer_list_head, list) { + pr_info("node timeout is %x,flag is %d\n", + node->timeout_tick, node->flag); + }; +} + + + +UK_TESTCASE(tntimer, test_tn_timer_list_operations) +{ + systick_t t1 = 0x100000; + systick_t t2 = 0x200000; + systick_t t3 = 0x300000; + systick_t t4 = 0x260000; + systick_t t5 = 0x50000; + + struct timer *temp; + + struct timer *timer1 = tn_timer_create( + t1, *timeout_func1, NULL, TN_TIMER_FLAG_PERIODIC); + + + struct timer *timer2 = tn_timer_create( + t2, *timeout_func1, NULL, TN_TIMER_FLAG_ONE_SHOT); + struct timer *timer3 = tn_timer_create( + t3, *timeout_func1, NULL, TN_TIMER_FLAG_ONE_SHOT); + struct timer *timer4 = tn_timer_create( + t4, *timeout_func1, NULL, TN_TIMER_FLAG_ONE_SHOT); + struct timer *timer5 = tn_timer_create( + t5, *timeout_func1, NULL, TN_TIMER_FLAG_ONE_SHOT); + + UK_TEST_EXPECT_NOT_NULL(timer1); + UK_TEST_EXPECT_NOT_NULL(timer2); + UK_TEST_EXPECT_NOT_NULL(timer3); + UK_TEST_EXPECT_NOT_NULL(timer4); + + tn_timer_init(timer1, t1, *timeout_func1, NULL, TN_TIMER_FLAG_ONE_SHOT); + UK_TEST_EXPECT(timer1->flag == TN_TIMER_FLAG_ONE_SHOT); + + tn_timer_start(timer1); + tn_timer_start(timer2); + tn_timer_start(timer3); + tn_timer_start(timer4); + tn_timer_start(timer5); + + struct timer *node; + struct uk_list_head *timer_list_head = tn_timer_get_list(); + + + tn_timer_delete(timer2); + timer2 = tn_timer_create( + t2, *timeout_func1, NULL, TN_TIMER_FLAG_ONE_SHOT); + tn_timer_start(timer2); + + systick_t last_tick = tn_timer_next_tick() + tn_systick_get_tick(); + + temp = uk_list_first_entry_or_null(timer_list_head, struct timer, list); + UK_TEST_EXPECT_NOT_NULL(temp); + UK_TEST_EXPECT_SNUM_LT(temp->timeout_tick - last_tick, 20); + tn_timer_delete(temp); + + temp = uk_list_first_entry_or_null(timer_list_head, struct timer, list); + UK_TEST_EXPECT_NOT_NULL(temp); + UK_TEST_EXPECT_SNUM_LT(temp->timeout_tick - last_tick-0xB0000, + 20); + tn_timer_delete(temp); + + temp = uk_list_first_entry_or_null(timer_list_head, struct timer, list); + UK_TEST_EXPECT_NOT_NULL(temp); + UK_TEST_EXPECT_SNUM_LT(temp->timeout_tick - last_tick - 0x1B0000, + 20); + tn_timer_delete(temp); + + + temp = uk_list_first_entry_or_null(timer_list_head, struct timer, list); + UK_TEST_EXPECT_NOT_NULL(temp); + UK_TEST_EXPECT_SNUM_LT(temp->timeout_tick - last_tick - 0x210000, + 20); + tn_timer_delete(temp); + + temp = uk_list_first_entry_or_null(timer_list_head, struct timer, list); + UK_TEST_EXPECT_NOT_NULL(temp); + UK_TEST_EXPECT_SNUM_LT(temp->timeout_tick - last_tick - 0x2B0000, + 20); + tn_timer_delete(temp); + + UK_INIT_LIST_HEAD(tn_timer_get_list()); + +} + + + +UK_TESTCASE(tntimer, test_tn_timer_announce) +{ + systick_t t1 = 100; + systick_t t2 = 200; + systick_t t3 = 200; + systick_t t4 = 300; + systick_t t5 = 302; + + struct timer *node; + struct uk_list_head *timer_list_head = tn_timer_get_list(); + + struct timer *timer1 = tn_timer_create( + t1, *timeout_func2, NULL, TN_TIMER_FLAG_ONE_SHOT); + struct timer *timer2 = tn_timer_create( + t2, *timeout_func2, NULL, TN_TIMER_FLAG_ONE_SHOT); + struct timer *timer3 = tn_timer_create( + t3, *timeout_func2, NULL, TN_TIMER_FLAG_ONE_SHOT); + struct timer *timer4 = tn_timer_create( + t4, *timeout_func2, NULL, TN_TIMER_FLAG_ONE_SHOT); + struct timer *timer5 = tn_timer_create( + t5, *timeout_func2, NULL, TN_TIMER_FLAG_ONE_SHOT); + + UK_TEST_EXPECT_NOT_NULL(timer1); + UK_TEST_EXPECT_NOT_NULL(timer2); + UK_TEST_EXPECT_NOT_NULL(timer3); + + systick_t cur = tn_systick_get_tick(); + + tn_timer_start(timer1); + tn_timer_start(timer2); + tn_timer_start(timer3); + tn_timer_start(timer4); + tn_timer_start(timer5); + + while (excution < 1) { + asm volatile("" ::: "memory"); + /* + *do nothing,wait for timeout func + */ + } + UK_TEST_EXPECT_SNUM_LT(tn_systick_get_tick() - cur - 100, 20); + while (excution < 2) { + asm volatile("" ::: "memory"); + /* + *do nothing,wait for timeout func + */ + } + UK_TEST_EXPECT_SNUM_LT(tn_systick_get_tick() - cur - 200, 20); + UK_TEST_EXPECT_SNUM_EQ(excution, 3); + while (excution < 4) { + asm volatile("" ::: "memory"); + /* + *do nothing,wait for timeout func + */ + } + UK_TEST_EXPECT_SNUM_LT(tn_systick_get_tick() - cur - 300, 20); + while (excution < 5) { + asm volatile("" ::: "memory"); + /* + *do nothing,wait for timeout func + */ + } + UK_TEST_EXPECT_SNUM_LT(tn_systick_get_tick() - cur - 302, 20); + dump_timer(); + UK_TEST_EXPECT_SNUM_EQ(excution, 5); + + UK_INIT_LIST_HEAD(tn_timer_get_list()); + +} + + +uk_testsuite_register(tntimer, NULL); diff --git a/lib/tntimer/tntimer.c b/lib/tntimer/tntimer.c new file mode 100644 index 0000000000000000000000000000000000000000..dfd59aae21d8ab2ad54a9a5efecaa0cfd89e80f3 --- /dev/null +++ b/lib/tntimer/tntimer.c @@ -0,0 +1,202 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ssANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include + +static UK_LIST_HEAD(timer_list_head); +static UK_LIST_HEAD(overflow_timer_list_head); +static uint8_t timoutListsOverflowed; + +static systick_t last_tick; +/* + * tn_timer_get_list - Retrieves the global timer list. + * + * Returns a pointer to the head of the timer list. + */ +struct uk_list_head *tn_timer_get_list(void) +{ + return &timer_list_head; +} + +struct uk_list_head *tn_timer_get_overflow_list(void) +{ + return &overflow_timer_list_head; +} + +struct timer *tn_timer_create(systick_t init_tick, + void (*timeout_func)(void *parameter), + void *parameter, unsigned long flag) +{ + struct timer *t; + + t = uk_malloc(uk_alloc_get_default(), sizeof(struct timer)); + if (!t) + return NULL; + + t->timeout_func = timeout_func; + t->parameter = parameter; + t->init_tick = init_tick; + t->flag = flag; + + return t; +} + +void tn_timer_init(struct timer *t, systick_t init_tick, + void (*timeout_func)(void *parameter), void *parameter, + unsigned long flag) +{ + UK_ASSERT(t); + + t->timeout_func = timeout_func; + t->parameter = parameter; + t->init_tick = init_tick; + t->flag = flag; +} + +static inline struct timer *get_next_timer(void) +{ + struct timer *t; + + t = uk_list_first_entry_or_null(&timer_list_head, struct timer, list); + if (!t && timoutListsOverflowed) + t = uk_list_first_entry(&overflow_timer_list_head, struct timer, + list); + return t; +} + +systick_t tn_timer_next_tick(void) +{ + struct timer *t; + systick_t cur; + + cur = tn_systick_get_tick(); + + t = get_next_timer(); + + if (t) + return t->timeout_tick - cur; + return TICK_MAX; +} + +/* + * tn_timer_list_switch + * Handles timer list overflow by switching the active list. + * + * This function is called when the timer list has overflowed + * and needs to switch to the overflow list to maintain + * correct ordering of timers. + */ +void tn_timer_list_switch(void) +{ + UK_ASSERT(!uk_list_empty(&overflow_timer_list_head)); + + timer_list_head.next = overflow_timer_list_head.next; + overflow_timer_list_head.next->prev = &timer_list_head; + UK_INIT_LIST_HEAD(&overflow_timer_list_head); + timoutListsOverflowed = 0; +} + +void tn_timer_delete(struct timer *t) +{ + TN_TRACE_OBJ_FUNC(timer, delete, t); + + UK_ASSERT(t); + + uk_list_del_init(&t->list); + if (timoutListsOverflowed && uk_list_empty(&timer_list_head)) + tn_timer_list_switch(); +} + +void tn_timer_start(struct timer *t) +{ + TN_TRACE_OBJ_FUNC(timer, start, t); + + systick_t cur; + systick_t sum; + + cur = tn_systick_get_tick(); + sum = cur + MAX((systick_t)1, t->init_tick); + t->timeout_tick = sum; + if (sum < cur || sum < t->init_tick) { + // 发生了溢出 + tn_timer_add(t, &overflow_timer_list_head); + timoutListsOverflowed = 1; + } else { + tn_timer_add(t, &timer_list_head); + } + last_tick = cur; +} + +void tn_timer_add(struct timer *in, struct uk_list_head *head) +{ + struct timer *t; + + uk_list_for_each_entry(t, head, list) { + if (t->timeout_tick <= in->timeout_tick) + continue; + + uk_list_add(&(in)->list, t->list.prev); + goto update_next_tick; + } + uk_list_add_tail(&in->list, head); + +update_next_tick: +#ifdef CONFIG_LIBTNSYSTICK_TICKLESS + if (in == get_next_timer()) + tn_systick_set_timeout(tn_timer_next_tick()); +#endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ +} + +void tn_timer_announce(void) +{ + struct timer *t; + systick_t cur; + + cur = tn_systick_get_tick(); + + //current tick overflowed,clean the first list + if (cur < last_tick) { + while (!uk_list_empty(&timer_list_head)) { + t = uk_list_first_entry( + &timer_list_head, struct timer, list); + + uk_list_del_init(&t->list); + t->timeout_func(t->parameter); + if (t->flag & TN_TIMER_FLAG_PERIODIC) + tn_timer_start(t); + } + if (uk_list_empty(&timer_list_head) && timoutListsOverflowed) + tn_timer_list_switch(); + } + + while (!uk_list_empty(&timer_list_head)) { + t = uk_list_first_entry( + &timer_list_head, struct timer, list); + if (t->timeout_tick <= cur) { + uk_list_del_init(&t->list); + t->timeout_func(t->parameter); + if (t->flag & TN_TIMER_FLAG_PERIODIC) + tn_timer_start(t); + } else{ + break; + } + } + + tn_systick_set_timeout(tn_timer_next_tick()); + last_tick = cur; +} diff --git a/lib/tntimer/trace/trace_timer.c b/lib/tntimer/trace/trace_timer.c new file mode 100644 index 0000000000000000000000000000000000000000..33b7782ecea6ab4041037db0800cb8143d79bcf9 --- /dev/null +++ b/lib/tntimer/trace/trace_timer.c @@ -0,0 +1,19 @@ +#include + +#if defined(CONFIG_LIBTNTRACE_FORMAT) +void tn_trace_timer_delete_format(struct timer *timer) +{ + printf("%s: %p\n", __func__, timer); +} + +void tn_trace_timer_start_format(struct timer *timer) +{ + printf("%s: %p\n", __func__, timer); +} + +#elif defined(CONFIG_LIBTNTRACE_CUSTOM) + +void __weak tn_trace_timer_delete_custom(struct timer *timer) {} +void __weak tn_trace_timer_start_custom(struct timer *timer) {} + +#endif /* CONFIG_LIBTNTRACE_CUSTOM */ diff --git a/lib/tntrace/Config.uk b/lib/tntrace/Config.uk new file mode 100644 index 0000000000000000000000000000000000000000..9eabf162502829988e99126d6ed79fe2f07e4d8b --- /dev/null +++ b/lib/tntrace/Config.uk @@ -0,0 +1,22 @@ +menuconfig LIBTNTRACE + bool "tntrace: enable trace service" + default n + select LIBNOLIBC if !HAVE_LIBC + +if LIBTNTRACE + +choice LIBTNTRACE_OUTPUT + prompt "Chooce output method for tracing" + default LIBTNTRACE_FORMAT + config LIBTNTRACE_FORMAT + bool "Use format output" + + config LIBTNTRACE_CUSTOM + bool "Use custome function" +endchoice + +config LIBTNTRACE_ALL + bool "Enable all trace across all libraries" + default y + +endif diff --git a/lib/tntrace/Makefile.uk b/lib/tntrace/Makefile.uk new file mode 100644 index 0000000000000000000000000000000000000000..f99d5d915d068c9ed40f2aa718a5a6699c8121ab --- /dev/null +++ b/lib/tntrace/Makefile.uk @@ -0,0 +1,5 @@ +$(eval $(call addlib_s,libtntrace,$(CONFIG_LIBTNTRACE))) + +CINCLUDES-$(CONFIG_LIBTNTRACE) += -I$(LIBTNTRACE_BASE)/include + +CXXINCLUDES-$(CONFIG_LIBTNTRACE) += -I$(LIBTNTRACE_BASE)/include diff --git a/lib/tntrace/include/tn/trace.h b/lib/tntrace/include/tn/trace.h new file mode 100644 index 0000000000000000000000000000000000000000..6e824f1283538f34a6e13604293b2b2c24f0a8b7 --- /dev/null +++ b/lib/tntrace/include/tn/trace.h @@ -0,0 +1,37 @@ +#ifndef __TN_TRACE_H__ +#define __TN_TRACE_H__ + +#if defined(CONFIG_LIBTNTRACE_FORMAT) +#define TN_TRACE_FUNC(name, func, ...) \ + tn_trace_ ## name ## _ ## func ## _format(__VA_ARGS__) +#define TN_TRACE_FUNC_ENTER(name, func, ...) \ + tn_trace_ ## name ## _ ## func ## _enter_format(__VA_ARGS__) +#define TN_TRACE_FUNC_EXIT(name, func, ...) \ + tn_trace_ ## name ## _ ## func ## _exit_format(__VA_ARGS__) +#define TN_TRACE_OBJ_FUNC(name, func, obj, ...) \ + tn_trace_ ## name ## _ ## func ## _format(obj, ##__VA_ARGS__) +#define TN_TRACE_OBJ_FUNC_ENTER(name, func, obj, ...) \ + tn_trace_ ## name ## _ ## func ## _enter_format(obj, ##__VA_ARGS__) +#define TN_TRACE_OBJ_FUNC_EXIT(name, func, obj, ...) \ + tn_trace_ ## name ## _ ## func ## _exit_format(obj, ##__VA_ARGS__) + + +#elif defined(CONFIG_LIBTNTRACE_CUSTOM) + +#define TN_TRACE_FUNC(name, func, ...) \ + tn_trace_ ## name ## _ ## func ## _custom(__VA_ARGS__) +#define TN_TRACE_FUNC_ENTER(name, func, ...) \ + tn_trace_ ## name ## _ ## func ## _enter_custom(__VA_ARGS__) +#define TN_TRACE_FUNC_EXIT(name, func, ...) \ + tn_trace_ ## name ## _ ## func ## _exit_custom(__VA_ARGS__) +#define TN_TRACE_OBJ_FUNC(name, func, obj, ...) \ + tn_trace_ ## name ## _ ## func ## _custom(obj, ##__VA_ARGS__) +#define TN_TRACE_OBJ_FUNC_ENTER(name, func, obj, ...) \ + tn_trace_ ## name ## _ ## func ## _enter_custom(obj, ##__VA_ARGS__) +#define TN_TRACE_OBJ_FUNC_EXIT(name, func, obj, ...) \ + tn_trace_ ## name ## _ ## func ## _exit_custom(obj, ##__VA_ARGS__) + + +#endif /* CONFIG_LIBTNTRACE_CUSTOM */ + +#endif /* __TN_TRACE_H__ */ diff --git a/lib/ukboot/Config.uk b/lib/ukboot/Config.uk index 3d14dba06af171ef84c82674f08eb5ba20c0c435..73e2a62f4369cf031db73b606aaec8ae82fa60cd 100644 --- a/lib/ukboot/Config.uk +++ b/lib/ukboot/Config.uk @@ -149,6 +149,12 @@ if LIBUKBOOT help Initialize ukschedcoop as cooperative scheduler on the boot CPU. + config LIBUKBOOT_INITSCHEDPRIO + bool "Priority scheduler" + select LIBTNSCHEDPRIO + help + Initialize tnschedprio as priority scheduler on the boot CPU. + config LIBUKBOOT_NOSCHED bool "None" diff --git a/lib/ukboot/boot.c b/lib/ukboot/boot.c index 2e0208ea273a1c75baf81564c6964afa4067e990..bf422786ab93e263afd1085c62efb0f9d826fdb4 100644 --- a/lib/ukboot/boot.c +++ b/lib/ukboot/boot.c @@ -69,6 +69,8 @@ #endif /* CONFIG_LIBUKSCHED */ #if CONFIG_LIBUKBOOT_INITSCHEDCOOP #include +#elif CONFIG_LIBUKBOOT_INITSCHEDPRIO +#include #endif /* CONFIG_LIBUKBOOT_INITSCHEDCOOP */ #include #include @@ -349,12 +351,20 @@ void ukplat_entry(int argc, char *argv[]) /* On most platforms the timer depend on an initialized IRQ subsystem */ uk_pr_info("Initialize platform time...\n"); +#if CONFIG_HAVE_SYSTICK + rc = tn_systick_init(); + if (unlikely(rc)) + UK_CRASH("Could not initialize the systick\n"); +#else ukplat_time_init(); +#endif /* CONFIG_HAVE_SYSTICK */ #if !CONFIG_LIBUKBOOT_NOSCHED uk_pr_info("Initialize scheduling...\n"); #if CONFIG_LIBUKBOOT_INITSCHEDCOOP s = uk_schedcoop_create(a); +#elif CONFIG_LIBUKBOOT_INITSCHEDPRIO + s = tn_schedprio_create(a); #endif if (unlikely(!s)) UK_CRASH("Failed to initialize scheduling\n"); @@ -375,6 +385,9 @@ void ukplat_entry(int argc, char *argv[]) /* Enable interrupts before starting the application */ ukplat_lcpu_enable_irq(); +#if CONFIG_HAVE_SYSTICK + tn_systick_start(); +#endif /* CONFIG_HAVE_SYSTICK */ /** * Run init table */ @@ -508,6 +521,7 @@ static inline int do_main(int argc, char *argv[]) uk_pr_info("])\n"); #endif /* CONFIG_LIBUKDEBUG_PRINTK_INFO */ + ret = main(argc, argv); uk_pr_info("main returned %d\n", ret); return ret; diff --git a/lib/ukintctlr/Config.uk b/lib/ukintctlr/Config.uk index 05edee73bcdc629d42e6c813d336bf691c6b9546..5676c94f613dd06de08d28e0aac22537b176e607 100644 --- a/lib/ukintctlr/Config.uk +++ b/lib/ukintctlr/Config.uk @@ -20,4 +20,8 @@ config LIBUKINTCTLR_TEST default n select LIBUKTEST +config LIBUKINTCTLR_TRACE + bool "Enable isr trace" + default n + endif diff --git a/lib/ukintctlr/Makefile.uk b/lib/ukintctlr/Makefile.uk index 543e152046a6a6d2e532a0c7b2790ea2b776aa41..f2953ab80b0f59898eca501e84004d56570417f0 100644 --- a/lib/ukintctlr/Makefile.uk +++ b/lib/ukintctlr/Makefile.uk @@ -10,3 +10,7 @@ ifneq ($(filter y,$(CONFIG_LIBUKINTCTLR_TEST) $(CONFIG_LIBUKTEST_ALL)),) LIBUKINTCTLR_CINCLUDES-y += -I$(CONFIG_UK_BASE)/plat/common/include LIBUKINTCTLR_SRCS-y += $(LIBUKINTCTLR_BASE)/tests/test_intctlr.c endif + +ifneq ($(filter y,$(CONFIG_LIBUKINTCTLR_TRACE) $(CONFIG_LIBTNTRACE_ALL)),) +LIBUKINTCTLR_SRCS-y += $(LIBUKINTCTLR_BASE)/trace/trace_intctrl.c +endif diff --git a/lib/ukintctlr/exportsyms.uk b/lib/ukintctlr/exportsyms.uk index 80ce0e8b0a7f8323f924a466011bbd65ab6cc6a2..6779082ed4116fc6bbac8bb7715caa787cff03a4 100644 --- a/lib/ukintctlr/exportsyms.uk +++ b/lib/ukintctlr/exportsyms.uk @@ -1,13 +1,22 @@ uk_intctlr -uk_intctlr_init -uk_intctlr_irq_configure -uk_intctlr_irq_fdt_xlat +uk_intctlr_handle uk_intctlr_irq_alloc +uk_intctlr_irq_fdt_xlat uk_intctlr_irq_free +uk_intctlr_irq_get_priority uk_intctlr_irq_handle -uk_intctlr_handle -uk_intctlr_sgi_op -uk_intctlr_percpu_init uk_intctlr_irq_register +uk_intctlr_irq_set_affinity +uk_intctlr_irq_set_priority +uk_intctlr_irq_set_trigger uk_intctlr_irq_unregister +uk_intctlr_init +uk_intctlr_percpu_init uk_intctlr_register +uk_intctlr_simulate_spi +uk_intctlr_sgi_op +uk_intctlr_spi_get_affinity +uk_intctlr_irq_mask +uk_intctlr_irq_unmask +tn_trace_isr_enter +tn_trace_isr_exit diff --git a/lib/ukintctlr/include/uk/intctlr.h b/lib/ukintctlr/include/uk/intctlr.h index c49eb62d02eb73fec733ce84624d59398c35ea9b..4c47e77e356086e23a8c80812366d69ff739931d 100644 --- a/lib/ukintctlr/include/uk/intctlr.h +++ b/lib/ukintctlr/include/uk/intctlr.h @@ -8,7 +8,7 @@ #define __UK_INTCTLR_H__ #ifdef __cplusplus -export "C" { +extern "C" { #endif #ifndef __ASSEMBLY__ @@ -54,15 +54,74 @@ struct uk_intctlr_irq { * These must be implemented by the interrupt controller */ struct uk_intctlr_driver_ops { - int (*configure_irq)(struct uk_intctlr_irq *irq); + /** + * Configure trigger type for an interrupt + * + * @param irq Interrupt configuration + * @return zero on success or negative value on error + */ + int (*irq_set_trigger)(struct uk_intctlr_irq *irq); int (*fdt_xlat)(const void *fdt, int nodeoffset, __u32 index, struct uk_intctlr_irq *irq); void (*mask_irq)(unsigned int irq); void (*unmask_irq)(unsigned int irq); void (*initialize)(void); void (*handle)(struct __regs *regs); - void (*sgi_op)(uint8_t sgintid, uint32_t cpuid); int (*percpu_init)(void); + + /** + * Send a SGI to the specified core(s). + * + * @param sgintid the software generated interrupt id + * @param target_count the number of target cpus, + * zero means sending sgi to all PEs in the system except "self". + * @param cpuid_args argument list of cpuid, + * could be empty. type: uint32_t + * @return zero on success , negative value on failure + */ + int (*sgi_op)(uint8_t sgintid, uint32_t target_count, + va_list cpuid_args); + + /** + * set priority for interrupt + * + * @param irq IRQ to set priority + * @param priority priority number value [0..GIC_MAX_IRQ] + * smaller priority number indicates a higher priority + */ + void (*irq_set_priority)(unsigned int irq, uint8_t priority); + + /** + * set affinity for SPI interrupt + * + * @param irq IRQ to set affinity + * @param cpuid target CPU id to cope with SPI + */ + void (*irq_set_affinity)(unsigned int irq, uint32_t cpuid); +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) + /** + * Get IRQ priority level in non-secure mode + * + * @param irq IRQ to get priority + * @return IRQ priority level + */ + uint8_t (*irq_get_priority)(unsigned int irq); + + /** + * Get spi affinity status + * + * @param irq spi to get affinity + * @return spi affinity status + */ + uint32_t (*spi_get_affinity)(unsigned int irq); + + /** + * Set pending bit to simulate spi being triggered + * + * @param irq spi to set pending status + */ + void (*simulate_spi)(unsigned int irq); +#endif }; /** Interrupt controller descriptor */ @@ -96,12 +155,12 @@ int uk_intctlr_probe(void); void uk_intctlr_irq_handle(struct __regs *regs, unsigned int irq); /** - * Configure an interrupt + * Configure trigger type for an interrupt * * @param irq Interrupt configuration * @return zero on success or negative value on error */ -int uk_intctlr_irq_configure(struct uk_intctlr_irq *irq); +int uk_intctlr_irq_set_trigger(struct uk_intctlr_irq *irq); /** * Register interrupt controller driver with the uk_intctlr subsystem @@ -198,19 +257,65 @@ int uk_intctlr_irq_fdt_xlat(const void *fdt, int nodeoffset, __u32 index, void uk_intctlr_handle(struct __regs *regs); /** - * Handle function for interrupt controller + * Send a SGI to the specified core(s). * * @param sgintid the software generated interrupt id - * @param cpuid the id of the targeted cpu - * @return zero on success , error code on failure + * @param target_count the number of target cpus, + * zero means sending sgi to all PEs in the system except the current one. + * @param ... optional argument list of cpuid,type:uint32_t + * @return zero on success, negative value on failure */ -int uk_intctlr_sgi_op(uint8_t sgintid, uint32_t cpuid); +int uk_intctlr_sgi_op(uint8_t sgintid, uint32_t target_count, ...); /** * extra initialize function for each cpu core * @return zero on success , error code on failure */ int uk_intctlr_percpu_init(void); + +/** + * set priority for interrupt + * + * @param irq IRQ to set priority + * @param priority priority number value [0..GIC_MAX_IRQ] + * smaller priority number indicates a higher priority + */ +void uk_intctlr_irq_set_priority(unsigned int irq, uint8_t priority); + +/** + * set affinity for SPI interrupt + * + * @param irq SPI Interrupt to set affinity + * @param cpuid target CPU id to cope with SPI + */ +void uk_intctlr_irq_set_affinity(unsigned int irq, uint32_t cpuid); + +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) +/** + * Get IRQ priority level in non-secure mode + * + * @param irq irq to get priority information + * @return irq priority level + */ +uint8_t uk_intctlr_irq_get_priority(unsigned int irq); + +/** + * Get spi affinity status + * + * @param irq spi to get affinity + * @return spi affinity status + */ +uint32_t uk_intctlr_spi_get_affinity(unsigned int irq); + +/** + * sets the status of the corresponding + * peripheral interrupt to pending status + * + * @param irq spi to set pending + */ +void uk_intctlr_simulate_spi(unsigned int irq); +#endif + #endif /* __ASSEMBLY__ */ #ifdef __cplusplus diff --git a/lib/ukintctlr/tests/test_intctlr.c b/lib/ukintctlr/tests/test_intctlr.c index c10e3c54edae07551e9a9deab0783e197817a51f..b0418bbbc15d486520a66ff1fa61afe5a2263892 100644 --- a/lib/ukintctlr/tests/test_intctlr.c +++ b/lib/ukintctlr/tests/test_intctlr.c @@ -17,199 +17,145 @@ #include #include -static struct uk_intctlr_desc *ori_intctlr; -static struct uk_intctlr_desc test_intctlr; -struct uk_intctlr_driver_ops test_ops; -static int ret; - -enum ukintctlr_test_ret { - TEST_DEFAULT, - TEST_CONFIGURE_IRQ_SUCCESS, - TEST_FDT_XLAT_SUCCESS, - TEST_MASK_IRQ_SUCCESS, - TEST_UNMASK_IRQ_SUCCESS, - TEST_INITIALIZE_SUCCESS, - TEST_HANDLE_SUCCESS, - TEST_SGI_OP_SUCCESS, - TEST_PERCPU_INIT_SUCCESS, -}; - -static int test_configure_irq(struct uk_intctlr_irq *irq __unused) -{ - ret = TEST_CONFIGURE_IRQ_SUCCESS; - return 0; -} - -static int test_fdt_xlat(const void *fdt __unused, int nodeoffset __unused, - __u32 index __unused, - struct uk_intctlr_irq *irq __unused) -{ - ret = TEST_FDT_XLAT_SUCCESS; - return 0; -} -static void test_mask_irq(unsigned int irq __unused) -{ - ret = TEST_MASK_IRQ_SUCCESS; -} +#ifdef CONFIG_LIBUKINTCTLR_GICV3 +#include -static void test_unmask_irq(unsigned int irq __unused) -{ - ret = TEST_UNMASK_IRQ_SUCCESS; -} +static uint32_t global_current_cpu; -static void test_handle(struct __regs *regs __unused) +static int spi_handler(void *args __unused) { - ret = TEST_HANDLE_SUCCESS; -} - -static void test_sgi_op(uint8_t sgintid __unused, uint32_t cpuid __unused) -{ - ret = TEST_SGI_OP_SUCCESS; -} - -static int test_percpu_init(void) -{ - ret = TEST_PERCPU_INIT_SUCCESS; - + printf("spi handler start.\n"); + uint64_t mpidr = SYSREG_READ64(MPIDR_EL1); + uint64_t aff = ((mpidr & MPIDR_AFF3_MASK) >> 8) | + (mpidr & MPIDR_AFF2_MASK) | + (mpidr & MPIDR_AFF1_MASK) | + (mpidr & MPIDR_AFF0_MASK); + + global_current_cpu = (uint32_t)aff; return 0; } -static inline void test_intctlr_init(void) +UK_TESTCASE_DESC(ukintctlr, set_spi_pendings_test_affx_api, + "Affinity irq40 to the current cpu") { - ori_intctlr = uk_intctlr; - ret = 0; - - test_intctlr.name = "TEST_INTCTLR"; - test_ops.configure_irq = test_configure_irq; - test_ops.fdt_xlat = test_fdt_xlat; - test_ops.mask_irq = test_mask_irq; - test_ops.unmask_irq = test_unmask_irq; - test_ops.handle = test_handle; - test_ops.sgi_op = test_sgi_op; - test_ops.percpu_init = test_percpu_init; - test_intctlr.ops = &test_ops; - - uk_intctlr_register(&test_intctlr); -} - -/* 测试configure_irq接口 */ -UK_TESTCASE(ukintctlr, call_intctlr_configure_irq) -{ - struct uk_intctlr_irq irq = {0}; - struct uk_intctlr_irq *p_irq = &irq; - - /* 1.备份原有uk_intctlr,初始化测试环境 */ - test_intctlr_init(); - - /* 2.通过统一接口调用configure_irq,并校验调用结果 */ - (void)uk_intctlr_irq_configure(p_irq); - UK_TEST_EXPECT_SNUM_EQ(ret, TEST_CONFIGURE_IRQ_SUCCESS); + /* 中断号40,亲和至当前cpu */ + uint32_t original_cpu_affinity = uk_intctlr_spi_get_affinity(40); - /* 3.恢复环境 */ - uk_intctlr_register(ori_intctlr); -} + uint64_t current_cpu = SYSREG_READ64(MPIDR_EL1); + uint64_t aff = ((current_cpu & MPIDR_AFF3_MASK) >> 8) | + (current_cpu & MPIDR_AFF2_MASK) | + (current_cpu & MPIDR_AFF1_MASK) | + (current_cpu & MPIDR_AFF0_MASK); -/* 测试fdt_xlat接口 */ -UK_TESTCASE(ukintctlr, call_fdt_xlat) -{ - struct uk_intctlr_irq irq = {0}; - struct uk_intctlr_irq *p_irq = &irq; - const char *fdt = "FDT"; - int nodeoffset = 0; - __u32 index = 0; + uk_intctlr_irq_set_affinity(40, (uint32_t)aff); + uk_intctlr_irq_register(40, spi_handler, NULL); + isb(); - /* 1.备份原有uk_intctlr,初始化测试环境 */ - test_intctlr_init(); + uk_intctlr_simulate_spi(40); + __asm__ __volatile__("wfi"); - /* 2.通过统一接口调用fdt_xlat,并校验调用结果 */ - (void)uk_intctlr_irq_fdt_xlat(fdt, nodeoffset, index, p_irq); - UK_TEST_EXPECT_SNUM_EQ(ret, TEST_FDT_XLAT_SUCCESS); + UK_TEST_EXPECT_SNUM_EQ((uint32_t)aff, global_current_cpu); - /* 3.恢复环境 */ - uk_intctlr_register(ori_intctlr); + /* 恢复现场 */ + uk_intctlr_irq_unregister(40, spi_handler); + uk_intctlr_irq_set_affinity(40, original_cpu_affinity); } -/* 测试mask_irq接口 */ -UK_TESTCASE(ukintctlr, call_mask_irq) -{ - int irq = 0; - - /* 1.备份原有uk_intctlr,初始化测试环境 */ - test_intctlr_init(); - - /* 2.通过统一接口调用mask_irq,并校验调用结果 */ - uk_intctlr_irq_mask(irq); - UK_TEST_EXPECT_SNUM_EQ(ret, TEST_MASK_IRQ_SUCCESS); - - /* 3.恢复环境 */ - uk_intctlr_register(ori_intctlr); -} -/* 测试unmask_irq接口 */ -UK_TESTCASE(ukintctlr, call_unmask_irq) +UK_TESTCASE_DESC(ukintctlr, verify_spi_priority_level_setting, + "Compare the priority of interrupt 60/70") { - int irq = 0; - - /* 1.备份原有uk_intctlr,初始化测试环境 */ - test_intctlr_init(); - - /* 2.通过统一接口调用unmask_irq,并校验调用结果 */ - uk_intctlr_irq_unmask(irq); - UK_TEST_EXPECT_SNUM_EQ(ret, TEST_UNMASK_IRQ_SUCCESS); - - /* 3.恢复环境 */ - uk_intctlr_register(ori_intctlr); + uint8_t irq60_original_prio_level = + uk_intctlr_irq_get_priority(60) >> TRANS_PRIORITY_SHIFT; + uint8_t irq70_original_prio_level = + uk_intctlr_irq_get_priority(70) >> TRANS_PRIORITY_SHIFT; + + +#if defined(CONFIG_PRIORITY_MAX_16) + uk_intctlr_irq_set_priority(60, 15); + uk_intctlr_irq_set_priority(70, 14); + isb(); + UK_TEST_EXPECT_SNUM_GT(uk_intctlr_irq_get_priority(60), + uk_intctlr_irq_get_priority(70)); +#elif defined(CONFIG_PRIORITY_MAX_32) + uk_intctlr_irq_set_priority(60, 30); + uk_intctlr_irq_set_priority(70, 31); + isb(); + UK_TEST_EXPECT_SNUM_GT(uk_intctlr_irq_get_priority(60), + uk_intctlr_irq_get_priority(70)); +#elif defined(CONFIG_PRIORITY_MAX_64) + uk_intctlr_irq_set_priority(60, 62); + uk_intctlr_irq_set_priority(70, 63); + isb(); + UK_TEST_EXPECT_SNUM_GT(uk_intctlr_irq_get_priority(60), + uk_intctlr_irq_get_priority(70)); +#elif defined(CONFIG_PRIORITY_MAX_128) + uk_intctlr_irq_set_priority(60, 126); + uk_intctlr_irq_set_priority(70, 127); + isb(); + UK_TEST_EXPECT_SNUM_GT(uk_intctlr_irq_get_priority(60), + uk_intctlr_irq_get_priority(70)); +#endif + + /*恢复现场*/ + uk_intctlr_irq_set_priority(60, irq60_original_prio_level); + uk_intctlr_irq_set_priority(70, irq70_original_prio_level); } -/* 测试handle接口 */ -UK_TESTCASE(ukintctlr, call_handler) +/* 测试sgi生成接口uk_intctlr_sgi_op + * 场景: 向当前cpu发送/向除自己外的所有cpu发送 + */ +UK_TESTCASE_DESC(ukintctlr, send_sgi_to_bsp_or_all, + "Send a SGI to current cpu/all cpu excluding self") { - struct __regs *regs = NULL; - - /* 1.备份原有uk_intctlr,初始化测试环境 */ - test_intctlr_init(); - - /* 2.通过统一接口调用handle,并校验调用结果 */ - uk_intctlr_handle(regs); - UK_TEST_EXPECT_SNUM_EQ(ret, TEST_HANDLE_SUCCESS); + int r; - /* 3.恢复环境 */ - uk_intctlr_register(ori_intctlr); -} + uint64_t current_cpu = SYSREG_READ64(MPIDR_EL1); + uint64_t aff = ((current_cpu & MPIDR_AFF3_MASK) >> 8) | + (current_cpu & MPIDR_AFF2_MASK) | + (current_cpu & MPIDR_AFF1_MASK) | + (current_cpu & MPIDR_AFF0_MASK); -/* 测试sgi_op接口 */ -UK_TESTCASE(ukintctlr, call_sgi_op) -{ - uint8_t sgintid = 0; - uint32_t cpuid = 0; + /* 将sgi亲和到当前cpu */ + r = uk_intctlr_sgi_op(5, 1, (uint32_t)aff); - /* 1.备份原有uk_intctlr,初始化测试环境 */ - test_intctlr_init(); + UK_TEST_EXPECT_ZERO(r); - /* 2.通过统一接口调用sgi_op,并校验调用结果 */ - (void)uk_intctlr_sgi_op(sgintid, cpuid); - UK_TEST_EXPECT_SNUM_EQ(ret, TEST_SGI_OP_SUCCESS); + /* 将sgi亲和到除自己外的所有cpu */ + r = uk_intctlr_sgi_op(5, 0); - /* 3.恢复环境 */ - uk_intctlr_register(ori_intctlr); + UK_TEST_EXPECT_ZERO(r); } -/* 测试percpu_init接口 */ -UK_TESTCASE(ukintctlr, call_percpu_init) +/* 测试sgi生成接口uk_intctlr_sgi_op + * 场景: cpulist中含有range_selector不同/亲和属性不同/id > 15的cpu + */ +UK_TESTCASE_DESC(ukintctlr, affx_and_rs_check, +"Send a SGI to cpu list with 4 cases: different rs/affx, cpuid>15, normal") { int r; + /* 检测接口是否会检查出targetlist AFFx属性及 + * range selector 不同并报错 + */ - /* 1.备份原有uk_intctlr,初始化测试环境 */ - test_intctlr_init(); + /* 检查是否支持发送至idx 16 及以上的cpu */ + r = uk_intctlr_sgi_op(4, 4, 19, 1, 2, 0); + UK_TEST_EXPECT_SNUM_EQ(r, -1); - /* 2.通过统一接口调用percpu_init,并校验调用结果 */ - r = uk_intctlr_percpu_init(); - UK_TEST_EXPECT_SNUM_EQ(ret, TEST_PERCPU_INIT_SUCCESS); - UK_TEST_EXPECT_ZERO(r); + /* 不同的range selector */ + r = uk_intctlr_sgi_op(4, 4, 0, 1, 2, 19); + UK_TEST_EXPECT_SNUM_EQ(r, -1); + + /* 不同的affx */ + r = uk_intctlr_sgi_op(4, 4, 0, 1, 2, 132000); + UK_TEST_EXPECT_SNUM_EQ(r, -1); - /* 3.恢复环境 */ - uk_intctlr_register(ori_intctlr); + /* affx/rs 相同*/ + r = uk_intctlr_sgi_op(4, 3, 0, 1, 2); + UK_TEST_EXPECT_ZERO(r); } +#endif + uk_testsuite_register(ukintctlr, NULL); diff --git a/lib/ukintctlr/trace/trace_intctrl.c b/lib/ukintctlr/trace/trace_intctrl.c new file mode 100644 index 0000000000000000000000000000000000000000..8ced5924eea690bfec04d2279b8595cd4f3a00b1 --- /dev/null +++ b/lib/ukintctlr/trace/trace_intctrl.c @@ -0,0 +1,19 @@ +#include > + +#if defined(CONFIG_LIBTNTRACE_FORMAT) +void tn_trace_isr_handle_enter_format(unsigned int irq) +{ + printf("%s %u\n", __func__, irq); +} + +void tn_trace_isr_handle_exit_format(unsigned int irq) +{ + printf("%s %u\n", __func__, irq); +} + +#elif defined(CONFIG_LIBTNTRACE_CUSTOM) + +void __weak tn_trace_isr_handle_enter_custom(void) {} +void __weak tn_trace_isr_handle_exit_custom(void) {} + +#endif /* CONFIG_LIBTNTRACE_CUSTOM */ diff --git a/lib/ukintctlr/ukintctlr.c b/lib/ukintctlr/ukintctlr.c index 5b470587ff2afb804240562659eec631c94772aa..aa7b841675dd4633fb22888e3258a75ec4930108 100644 --- a/lib/ukintctlr/ukintctlr.c +++ b/lib/ukintctlr/ukintctlr.c @@ -38,6 +38,7 @@ #include #include #include +#include #if CONFIG_LIBUKINTCTLR_ISR_ECTX_ASSERTIONS #include #endif /* CONFIG_LIBUKINTCTLR_ISR_ECTX_ASSERTIONS */ @@ -147,14 +148,9 @@ recheck: return 0; } -/* - * TODO: This is a temporary solution used to identify non TSC clock - * interrupts in order to stop waiting for interrupts with deadline. - */ -extern unsigned long sched_have_pending_events; - void uk_intctlr_irq_handle(struct __regs *regs, unsigned int irq) { + TN_TRACE_FUNC_ENTER(isr, handle, irq); struct irq_handler *h; int i; int rc; @@ -186,19 +182,6 @@ void uk_intctlr_irq_handle(struct __regs *regs, unsigned int irq) if (irq_handlers[irq][i].func == NULL) break; h = &irq_handlers[irq][i]; - if (irq != ukplat_time_get_irq()) - /* ukplat_time_get_irq() gives the IRQ reserved for a timer, - * responsible to wake up cpu from halt, so it can check if - * it has something to do. Effectively it is OS ticks. - * - * If interrupt comes not from the timer, the - * chances are some work have just - * arrived. Let's kick the scheduler out of - * the halting loop, and let it take care of - * that work. - */ - __uk_test_and_set_bit(0, &sched_have_pending_events); - if (h->func(h->arg) == 1) goto exit; } @@ -210,6 +193,8 @@ void uk_intctlr_irq_handle(struct __regs *regs, unsigned int irq) */ trace_uk_intctlr_unhandled_irq(irq); + TN_TRACE_FUNC_EXIT(isr, handle, irq); + exit: #if CONFIG_LIBUKINTCTLR_ISR_ECTX_ASSERTIONS ukarch_ectx_assert_equal(ectx); @@ -232,12 +217,12 @@ void uk_intctlr_irq_unmask(unsigned int irq) return uk_intctlr->ops->unmask_irq(irq); } -int uk_intctlr_irq_configure(struct uk_intctlr_irq *irq) +int uk_intctlr_irq_set_trigger(struct uk_intctlr_irq *irq) { - UK_ASSERT(uk_intctlr && uk_intctlr->ops->configure_irq); + UK_ASSERT(uk_intctlr && uk_intctlr->ops->irq_set_trigger); UK_ASSERT(irq); - return uk_intctlr->ops->configure_irq(irq); + return uk_intctlr->ops->irq_set_trigger(irq); } int uk_intctlr_irq_fdt_xlat(const void *fdt, int nodeoffset, __u32 index, @@ -318,13 +303,16 @@ void uk_intctlr_handle(struct __regs *regs) return uk_intctlr->ops->handle(regs); } -int uk_intctlr_sgi_op(uint8_t sgintid, uint32_t cpuid) +int uk_intctlr_sgi_op(uint8_t sgintid, uint32_t target_count, ...) { - UK_ASSERT(uk_intctlr->ops->sgi_op); - - uk_intctlr->ops->sgi_op(sgintid, cpuid); - - return 0; + UK_ASSERT(uk_intctlr && uk_intctlr->ops->sgi_op); + va_list cpuid_args; + int ret; + + va_start(cpuid_args, target_count); + ret = uk_intctlr->ops->sgi_op(sgintid, target_count, cpuid_args); + va_end(cpuid_args); + return ret; } int uk_intctlr_percpu_init(void) @@ -334,3 +322,40 @@ int uk_intctlr_percpu_init(void) /* initialize interrupt controller of specified cpu core */ return uk_intctlr->ops->percpu_init(); } + +void uk_intctlr_irq_set_priority(unsigned int irq, uint8_t priority) +{ + UK_ASSERT(uk_intctlr && uk_intctlr->ops->irq_set_priority); + + return uk_intctlr->ops->irq_set_priority(irq, priority); +} + +void uk_intctlr_irq_set_affinity(unsigned int irq, uint32_t cpuid) +{ + UK_ASSERT(uk_intctlr && uk_intctlr->ops->irq_set_affinity); + + return uk_intctlr->ops->irq_set_affinity(irq, cpuid); +} + +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) +uint8_t uk_intctlr_irq_get_priority(unsigned int irq) +{ + UK_ASSERT(uk_intctlr && uk_intctlr->ops->irq_get_priority); + + return uk_intctlr->ops->irq_get_priority(irq); +} + +uint32_t uk_intctlr_spi_get_affinity(unsigned int irq) +{ + UK_ASSERT(uk_intctlr && uk_intctlr->ops->spi_get_affinity); + + return uk_intctlr->ops->spi_get_affinity(irq); +} + +void uk_intctlr_simulate_spi(unsigned int irq) +{ + UK_ASSERT(uk_intctlr && uk_intctlr->ops->simulate_spi); + + return uk_intctlr->ops->simulate_spi(irq); +} +#endif diff --git a/lib/uklock/Config.uk b/lib/uklock/Config.uk index e4ba3e0ba2888401bffc6fd467fc2a542b6866f2..ab0c90641ea06f782e7cb61955921443d087beff 100644 --- a/lib/uklock/Config.uk +++ b/lib/uklock/Config.uk @@ -45,4 +45,8 @@ if LIBUKLOCK default y help Enable reader-writer based synchronization + + config LIBUKLOCK_TRACE + bool "Enable trace" + default n endif diff --git a/lib/uklock/Makefile.uk b/lib/uklock/Makefile.uk index 8e4c1c50f95d467a9d1ecbf6504ba27fbd626b19..95f76af384c92a3bf81a22fd4a31f474d91bf281 100644 --- a/lib/uklock/Makefile.uk +++ b/lib/uklock/Makefile.uk @@ -6,3 +6,7 @@ CXXINCLUDES-$(CONFIG_LIBUKLOCK) += -I$(LIBUKLOCK_BASE)/include LIBUKLOCK_SRCS-$(CONFIG_LIBUKLOCK_SEMAPHORE) += $(LIBUKLOCK_BASE)/semaphore.c LIBUKLOCK_SRCS-$(CONFIG_LIBUKLOCK_MUTEX) += $(LIBUKLOCK_BASE)/mutex.c LIBUKLOCK_SRCS-$(CONFIG_LIBUKLOCK_RWLOCK) += $(LIBUKLOCK_BASE)/rwlock.c + +ifneq ($(filter y,$(CONFIG_LIBUKLOCK_TRACE) $(CONFIG_LIBTNTRACE_ALL)),) +LIBUKLOCK_SRCS-y += $(LIBUKLOCK_BASE)/trace/trace_lock.c +endif diff --git a/lib/uklock/exportsyms.uk b/lib/uklock/exportsyms.uk index 39d223684c93785dc71ff037206abce5909d15e1..d4a1ffc363935e3d714882f047db677c97952fe9 100644 --- a/lib/uklock/exportsyms.uk +++ b/lib/uklock/exportsyms.uk @@ -10,3 +10,31 @@ uk_rwlock_runlock uk_rwlock_wunlock uk_rwlock_upgrade uk_rwlock_downgrade +tn_trace_uk_semaphore_up_enter_format +tn_trace_uk_semaphore_up_exit_format +tn_trace_uk_semaphore_down_enter_format +tn_trace_uk_semaphore_down_exit_format +tn_trace_uk_semaphore_down_try_enter_format +tn_trace_uk_semaphore_down_try_exit_format +tn_trace_uk_semaphore_down_to_enter_format +tn_trace_uk_semaphore_down_to_exit_format +tn_trace_uk_mutex_lock_enter_format +tn_trace_uk_mutex_lock_exit_format +tn_trace_uk_mutex_trylock_enter_format +tn_trace_uk_mutex_trylock_exit_format +tn_trace_uk_mutex_unlock_enter_format +tn_trace_uk_mutex_unlock_exit_format +tn_trace_uk_semaphore_up_enter_custom +tn_trace_uk_semaphore_up_exit_custom +tn_trace_uk_semaphore_down_enter_custom +tn_trace_uk_semaphore_down_exit_custom +tn_trace_uk_semaphore_down_try_enter_custom +tn_trace_uk_semaphore_down_try_exit_custom +tn_trace_uk_semaphore_down_to_enter_custom +tn_trace_uk_semaphore_down_to_exit_custom +tn_trace_uk_mutex_lock_enter_custom +tn_trace_uk_mutex_lock_exit_custom +tn_trace_uk_mutex_trylock_enter_custom +tn_trace_uk_mutex_trylock_exit_custom +tn_trace_uk_mutex_unlock_enter_custom +tn_trace_uk_mutex_unlock_exit_custom diff --git a/lib/uklock/include/uk/mutex.h b/lib/uklock/include/uk/mutex.h index 57303ac1e66fb5b4d10cbade19280443ef64c9a5..2b62caf2f5bfcd370361463b0dde56e9e8ca3684 100644 --- a/lib/uklock/include/uk/mutex.h +++ b/lib/uklock/include/uk/mutex.h @@ -49,6 +49,8 @@ #include #endif /* CONFIG_LIBUKLOCK_MUTEX_METRICS */ +#include + #ifdef __cplusplus extern "C" { #endif @@ -116,6 +118,8 @@ static inline void uk_mutex_lock(struct uk_mutex *m) UK_ASSERT(m); + TN_TRACE_OBJ_FUNC_ENTER(uk_mutex, lock, m); + cur = uk_thread_current(); /* If the owner is the current thread, just increment the lock count */ @@ -145,6 +149,8 @@ static inline void uk_mutex_lock(struct uk_mutex *m) _uk_mutex_metrics.total_locks++; ukarch_spin_unlock(&_uk_mutex_metrics_lock); #endif /* CONFIG_LIBUKLOCK_MUTEX_METRICS */ + + TN_TRACE_OBJ_FUNC_EXIT(uk_mutex, lock, m); } static inline int uk_mutex_trylock(struct uk_mutex *m) @@ -153,6 +159,8 @@ static inline int uk_mutex_trylock(struct uk_mutex *m) UK_ASSERT(m); + TN_TRACE_OBJ_FUNC_ENTER(uk_mutex, trylock, m); + cur = uk_thread_current(); /* If the owner is the current thread, just increment the lock count */ @@ -183,6 +191,7 @@ static inline int uk_mutex_trylock(struct uk_mutex *m) _uk_mutex_metrics.total_ok_trylocks++; ukarch_spin_unlock(&_uk_mutex_metrics_lock); #endif /* CONFIG_LIBUKLOCK_MUTEX_METRICS */ + TN_TRACE_OBJ_FUNC_EXIT(uk_mutex, trylock, m); return 1; } @@ -193,6 +202,7 @@ static inline int uk_mutex_trylock(struct uk_mutex *m) _uk_mutex_metrics.total_failed_trylocks++; ukarch_spin_unlock(&_uk_mutex_metrics_lock); #endif /* CONFIG_LIBUKLOCK_MUTEX_METRICS */ + TN_TRACE_OBJ_FUNC_EXIT(uk_mutex, trylock, m); return 0; } @@ -209,6 +219,8 @@ static inline void uk_mutex_unlock(struct uk_mutex *m) UK_ASSERT(m->lock_count > 0); UK_ASSERT(m->owner == uk_thread_current()); + TN_TRACE_OBJ_FUNC_ENTER(uk_mutex, unlock, m); + if (--m->lock_count == 0) { /* Make sure lock_count is visible before resetting the * owner. The lock can be acquired afterwards. @@ -225,6 +237,8 @@ static inline void uk_mutex_unlock(struct uk_mutex *m) _uk_mutex_metrics.total_unlocks++; ukarch_spin_unlock(&_uk_mutex_metrics_lock); #endif /* CONFIG_LIBUKLOCK_MUTEX_METRICS */ + + TN_TRACE_OBJ_FUNC_EXIT(uk_mutex, unlock, m); } #define uk_waitq_wait_event_mutex(wq, condition, mutex) \ diff --git a/lib/uklock/include/uk/semaphore.h b/lib/uklock/include/uk/semaphore.h index 0564a8befd6967ad53a8f2b281c2742f5173e881..e40d4d6f25a9879096a5edc160a2da257c56a6ec 100644 --- a/lib/uklock/include/uk/semaphore.h +++ b/lib/uklock/include/uk/semaphore.h @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -59,6 +60,8 @@ static inline void uk_semaphore_down(struct uk_semaphore *s) UK_ASSERT(s); + TN_TRACE_OBJ_FUNC_ENTER(uk_semaphore, down, s); + for (;;) { uk_waitq_wait_event(&s->wait, s->count > 0); uk_spin_lock_irqsave(&(s->sl), irqf); @@ -71,6 +74,8 @@ static inline void uk_semaphore_down(struct uk_semaphore *s) uk_pr_debug("Decreased semaphore %p to %ld\n", s, s->count); #endif uk_spin_unlock_irqrestore(&(s->sl), irqf); + + TN_TRACE_OBJ_FUNC_EXIT(uk_semaphore, down, s); } static inline int uk_semaphore_down_try(struct uk_semaphore *s) @@ -80,6 +85,8 @@ static inline int uk_semaphore_down_try(struct uk_semaphore *s) UK_ASSERT(s); + TN_TRACE_OBJ_FUNC_ENTER(uk_semaphore, down_try, s); + uk_spin_lock_irqsave(&(s->sl), irqf); if (s->count > 0) { ret = 1; @@ -90,6 +97,8 @@ static inline int uk_semaphore_down_try(struct uk_semaphore *s) #endif } uk_spin_unlock_irqrestore(&(s->sl), irqf); + + TN_TRACE_OBJ_FUNC_EXIT(uk_semaphore, down_try, s, ret); return ret; } @@ -103,6 +112,8 @@ static inline __nsec uk_semaphore_down_to(struct uk_semaphore *s, UK_ASSERT(s); + TN_TRACE_OBJ_FUNC_ENTER(uk_semaphore, down_to, s, timeout); + deadline = then + timeout; for (;;) { @@ -120,6 +131,7 @@ static inline __nsec uk_semaphore_down_to(struct uk_semaphore *s, s, s->count); #endif uk_spin_unlock_irqrestore(&(s->sl), irqf); + TN_TRACE_OBJ_FUNC_EXIT(uk_semaphore, down_to, s, timeout); return ukplat_monotonic_clock() - then; } @@ -127,6 +139,8 @@ static inline __nsec uk_semaphore_down_to(struct uk_semaphore *s, #ifdef UK_SEMAPHORE_DEBUG uk_pr_debug("Timed out while waiting for semaphore %p\n", s); #endif + +TN_TRACE_OBJ_FUNC_EXIT(uk_semaphore, down_to, s, timeout); return __NSEC_MAX; } @@ -136,14 +150,19 @@ static inline void uk_semaphore_up(struct uk_semaphore *s) UK_ASSERT(s); + TN_TRACE_OBJ_FUNC_ENTER(uk_semaphore, up, s); + uk_spin_lock_irqsave(&(s->sl), irqf); ++s->count; + #ifdef UK_SEMAPHORE_DEBUG uk_pr_debug("Increased semaphore %p to %ld\n", s, s->count); #endif uk_waitq_wake_up(&s->wait); uk_spin_unlock_irqrestore(&(s->sl), irqf); + + TN_TRACE_OBJ_FUNC_EXIT(uk_semaphore, up, s); } #ifdef __cplusplus diff --git a/lib/uklock/trace/trace_lock.c b/lib/uklock/trace/trace_lock.c new file mode 100644 index 0000000000000000000000000000000000000000..eb2215305b62196390d3bb172498d1ee1e94ddb4 --- /dev/null +++ b/lib/uklock/trace/trace_lock.c @@ -0,0 +1,110 @@ +#include + +#if defined(CONFIG_LIBTNTRACE_FORMAT) +void tn_trace_uk_semaphore_up_enter_format(struct uk_semaphore *semaphore) +{ + printf("%s: %p\n", __func__, semaphore); +} + +void tn_trace_uk_semaphore_up_exit_format(struct uk_semaphore *semaphore) +{ + printf("%s: %p\n", __func__, semaphore); +} + +void tn_trace_uk_semaphore_down_enter_format(struct uk_semaphore *semaphore) +{ + printf("%s: %p\n", __func__, semaphore); +} + +void tn_trace_uk_semaphore_down_exit_format(struct uk_semaphore *semaphore) +{ + printf("%s: %p\n", __func__, semaphore); +} + +void tn_trace_uk_semaphore_down_try_enter_format(struct uk_semaphore *semaphore) +{ + printf("%s: %p\n", __func__, semaphore); +} + +void tn_trace_uk_semaphore_down_try_exit_format(struct uk_semaphore *semaphore, + int ret) +{ + printf("%s: %p %d\n", __func__, semaphore, ret); +} + +void tn_trace_uk_semaphore_down_to_enter_format(struct uk_semaphore *semaphore, + __nsec timeout) +{ + printf("%s: %p %lu\n", __func__, semaphore, timeout); +} + +void tn_trace_uk_semaphore_down_to_exit_format(struct uk_semaphore *semaphore, + __nsec timeout) +{ + printf("%s: %p %lu\n", __func__, semaphore, timeout); +} + +void tn_trace_uk_mutex_lock_enter_format(struct uk_mutex *mutex) +{ + printf("%s: %p\n", __func__, mutex); +} + +void tn_trace_uk_mutex_lock_exit_format(struct uk_mutex *mutex) +{ + printf("%s: %p\n", __func__, mutex); +} + +void tn_trace_uk_mutex_trylock_enter_format(struct uk_mutex *mutex) +{ + printf("%s: %p\n", __func__, mutex); +} + +void tn_trace_uk_mutex_trylock_exit_format(struct uk_mutex *mutex) +{ + printf("%s: %p\n", __func__, mutex); +} + +void tn_trace_uk_mutex_unlock_enter_format(struct uk_mutex *mutex) +{ + printf("%s: %p\n", __func__, mutex); +} + +void tn_trace_uk_mutex_unlock_exit_format(struct uk_mutex *mutex) +{ + printf("%s: %p\n", __func__, mutex); +} + +#elif defined(CONFIG_LIBTNTRACE_CUSTOM) + +void __weak tn_trace_uk_semaphore_up_enter_custom( + struct uk_semaphore *semaphore) +{} +void __weak tn_trace_uk_semaphore_up_exit_custom( + struct uk_semaphore *semaphore) +{} +void __weak tn_trace_uk_semaphore_down_enter_custom( + struct uk_semaphore *semaphore) +{} +void __weak tn_trace_uk_semaphore_down_exit_custom( + struct uk_semaphore *semaphore) +{} +void __weak tn_trace_uk_semaphore_down_try_enter_custom( + struct uk_semaphore *semaphore) +{} +void __weak tn_trace_uk_semaphore_down_try_exit_custom( + struct uk_semaphore *semaphore, int ret) +{} +void __weak tn_trace_uk_semaphore_down_to_enter_custom( + struct uk_semaphore *semaphore, __nsec timeout) +{} +void __weak tn_trace_uk_semaphore_down_to_exit_custom( + struct uk_semaphore *semaphore, __nsec timeout) +{} +void __weak tn_trace_uk_mutex_lock_enter_custom(struct uk_mutex *mutex) {} +void __weak tn_trace_uk_mutex_lock_exit_custom(struct uk_mutex *mutex) {} +void __weak tn_trace_uk_mutex_trylock_enter_custom(struct uk_mutex *mutex) {} +void __weak tn_trace_uk_mutex_trylock_exit_custom(struct uk_mutex *mutex) {} +void __weak tn_trace_uk_mutex_unlock_enter_custom(struct uk_mutex *mutex) {} +void __weak tn_trace_uk_mutex_unlock_exit_custom(struct uk_mutex *mutex) {} + +#endif /* CONFIG_LIBTNTRACE_CUSTOM */ diff --git a/lib/uksched/Config.uk b/lib/uksched/Config.uk index d0b1751c94a13647e3db8b9910aca3c7fb11dc2b..4b19aeaa03cf191fa457ff1ec355c9188994c55f 100644 --- a/lib/uksched/Config.uk +++ b/lib/uksched/Config.uk @@ -5,8 +5,53 @@ menuconfig LIBUKSCHED select LIBUKDEBUG select LIBUKALLOC select HAVE_SCHED + select LIBTNSYSTICK + select LIBTNTIMER if LIBUKSCHED + config LIBUKSCHED_THREAD_PRIORITY + bool "Enable thread priority" + default n + select LIBUKSCHED_WAITQ_LIST + select LIBUKSCHED_RUNQ_LIST + + if LIBUKSCHED_THREAD_PRIORITY + config LIBUKSCHED_PRIORITY_LEVEL + int "Max priority level for all thread" + default 256 + help + Increase this value will use more resource, espacially for + some wait_q and ready_q algorithm. + config LIBUKSCHED_LOWEST_PRIORITY + int "Lowest priority number" + default 0 + endif + + choice LIBUKSCHED_RUNQ + prompt "Choice runq algorithm" + default LIBUKSCHED_RUNQ_TAILQ + config LIBUKSCHED_RUNQ_TAILQ + bool "Use linked tail queue based algorithm" + + config LIBUKSCHED_RUNQ_LIST + bool "Use double linked list based algorithm" + depends on LIBUKSCHED_THREAD_PRIORITY + endchoice + + choice LIBUKSCHED_WAITQ + prompt "Choice waitq algorithm" + default LIBUKSCHED_WAITQ_STAILQ + config LIBUKSCHED_WAITQ_STAILQ + depends on !LIBUKSCHED_THREAD_PRIORITY + bool "Use singly-linked tail queue without priority support" + + config LIBUKSCHED_WAITQ_LIST + bool "Use priority double linked list based algorithm as wait queue" + depends on LIBUKSCHED_THREAD_PRIORITY + help + Support thread priority scheduler. + endchoice + # Invisible symbol to enable TCB initialization config LIBUKSCHED_TCB_INIT bool @@ -17,4 +62,7 @@ if LIBUKSCHED config LIBUKSCHED_TEST bool "Enable unit tests" default n + config LIBUKSCHED_TRACE + bool "Enable trace" + default n endif diff --git a/lib/uksched/Makefile.uk b/lib/uksched/Makefile.uk index 9ebf733732f6c8e4c2d72908ac67b4e5c8dcd83a..df905d0a44ba9bf3f27b0eeccd928a6b70bd30c6 100644 --- a/lib/uksched/Makefile.uk +++ b/lib/uksched/Makefile.uk @@ -24,3 +24,7 @@ ifneq ($(filter y,$(CONFIG_LIBUKSCHED_TEST) $(CONFIG_LIBUKTEST_ALL)),) LIBUKSCHED_SRCS-y += $(LIBUKSCHED_BASE)/tests/test_sched.c endif + +ifneq ($(filter y,$(CONFIG_LIBUKSCHED_TRACE) $(CONFIG_LIBTNTRACE_ALL)),) +LIBUKSCHED_SRCS-y += $(LIBUKSCHED_BASE)/trace/trace_sched.c +endif diff --git a/lib/uksched/exportsyms.uk b/lib/uksched/exportsyms.uk index 2a3f0da0e2db3cfe9058bf5546d1ad9fb53af0d4..38a3bb048f0d3a34bcfd83809f2be8c84128d586 100644 --- a/lib/uksched/exportsyms.uk +++ b/lib/uksched/exportsyms.uk @@ -7,11 +7,13 @@ uk_sched_thread_create_fn2 uk_sched_thread_add uk_sched_thread_remove uk_sched_thread_terminate -uk_sched_thread_sleep +uk_sched_thread_sleep_ns +uk_sched_thread_sleep_tick uk_sched_thread_exit uk_sched_thread_exit2 uk_sched_dumpk_threads uk_sched_thread_gc +uk_sched_thread_set_priority uk_thread_init_bare uk_thread_init_bare_fn0 uk_thread_init_bare_fn1 @@ -22,6 +24,7 @@ uk_thread_init_fn2 uk_thread_create_bare uk_thread_create_container uk_thread_create_container2 +uk_thread_prio_create_container uk_thread_container_init_bare uk_thread_container_init_fn0 uk_thread_container_init_fn1 @@ -29,11 +32,13 @@ uk_thread_container_init_fn2 uk_thread_create_fn0 uk_thread_create_fn1 uk_thread_create_fn2 +uk_thread_prio_create_fn1 uk_thread_set_exited uk_thread_release uk_thread_block_until uk_thread_block_timeout uk_thread_block +uk_thread_timeout uk_thread_wake uk_thread_wake_isr __uk_sched_thread_current @@ -46,3 +51,7 @@ sched_getaffinity uk_syscall_e_sched_setaffinity uk_syscall_r_sched_setaffinity sched_setaffinity +tn_trace_uk_thread_yield_format +tn_trace_uk_thread_switch_format +tn_trace_uk_thread_yield_custom +tn_trace_uk_thread_switch_custom diff --git a/lib/uksched/include/uk/isr/wait.h b/lib/uksched/include/uk/isr/wait.h index f244137562215d7ef5c26943e9690ce2be034498..a64f138cc834ca407eff9fd140ebd7c06576f0f0 100644 --- a/lib/uksched/include/uk/isr/wait.h +++ b/lib/uksched/include/uk/isr/wait.h @@ -19,6 +19,10 @@ static inline void uk_waitq_wake_up_isr(struct uk_waitq *wq) UK_STAILQ_FOREACH_SAFE(curr, &wq->wait_list, thread_list, tmp) uk_thread_wake_isr(curr->thread); ukplat_spin_unlock_irqrestore(&wq->sl, flags); + + // TODO: Uncomment the following line when scheduler know whether in isr + // context. + // uk_sched_reschedule(); } #endif /* __UK_SCHED_WAIT_ISR_H__ */ diff --git a/lib/uksched/include/uk/sched.h b/lib/uksched/include/uk/sched.h index 8d5ee4d2f66beb3e9db1d8503da905a4626670a9..15fd5d192b741f568ac1b8ee7233e289c7b0ca41 100644 --- a/lib/uksched/include/uk/sched.h +++ b/lib/uksched/include/uk/sched.h @@ -43,6 +43,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -63,6 +64,7 @@ static inline struct uk_sched *uk_sched_current(void) typedef void (*uk_sched_yield_func_t) (struct uk_sched *s); +typedef void (*uk_sched_reschedule_func_t)(struct uk_sched *s); typedef int (*uk_sched_thread_add_func_t) (struct uk_sched *s, struct uk_thread *t); typedef void (*uk_sched_thread_remove_func_t) @@ -72,6 +74,13 @@ typedef void (*uk_sched_thread_blocked_func_t) typedef void (*uk_sched_thread_woken_func_t) (struct uk_sched *s, struct uk_thread *t); +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY +typedef void (*uk_sched_thread_set_prio_func_t)(struct uk_sched *s, + struct uk_thread *thread, + int32_t priority); +typedef int (*uk_sched_prio_cmp_func_t)(struct uk_thread *thread_1, + struct uk_thread *thread_2); +#endif typedef const struct uk_thread * (*uk_sched_idle_thread_func_t) (struct uk_sched *s, unsigned int proc_id); @@ -79,12 +88,17 @@ typedef int (*uk_sched_start_t)(struct uk_sched *s, struct uk_thread *main); struct uk_sched { uk_sched_yield_func_t yield; + uk_sched_reschedule_func_t reschedule; uk_sched_thread_add_func_t thread_add; uk_sched_thread_remove_func_t thread_remove; uk_sched_thread_blocked_func_t thread_blocked; uk_sched_thread_woken_func_t thread_woken; uk_sched_thread_woken_func_t thread_woken_isr; +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY + uk_sched_thread_set_prio_func_t thread_set_prio; + uk_sched_prio_cmp_func_t prio_cmp; +#endif uk_sched_idle_thread_func_t idle_thread; uk_sched_start_t sched_start; @@ -106,6 +120,8 @@ static inline void uk_sched_yield(void) struct uk_sched *s; struct uk_thread *current = uk_thread_current(); + TN_TRACE_OBJ_FUNC(uk_thread, yield, current); + UK_ASSERT(current); s = current->sched; @@ -113,6 +129,23 @@ static inline void uk_sched_yield(void) s->yield(s); } +/** + * Tell the scheduler may need to reschedule. + * The scheduler will decide if a reschedule is needed. + * This is only wrapper functions over scheduler callbacks + */ +static inline void uk_sched_reschedule(void) +{ + struct uk_sched *s; + struct uk_thread *current = uk_thread_current(); + + UK_ASSERT(current); + + s = current->sched; + UK_ASSERT(s); + s->reschedule(s); +} + /** * Add thread to a scheduler * @@ -347,6 +380,8 @@ struct uk_thread *uk_sched_thread_create_fn2(struct uk_sched *s, */ void uk_sched_dumpk_threads(int klvl, struct uk_sched *s); +/* used to maintain forward compatibility */ +#define uk_sched_thread_sleep uk_sched_thread_sleep_ns /** * Sleep current thread * @@ -355,7 +390,17 @@ void uk_sched_dumpk_threads(int klvl, struct uk_sched *s); * @return * NULL */ -void uk_sched_thread_sleep(__nsec nsec); +void uk_sched_thread_sleep_ns(__nsec nsec); + +/** + * Sleep current thread + * + * @param tick + * tick period to sleep + * @return + * NULL + */ +void uk_sched_thread_sleep_tick(systick_t tick); /** * Exits the current thread context @@ -385,6 +430,42 @@ void uk_sched_thread_exit2(uk_thread_gc_t gc_fn, void *gc_argp) __noreturn; */ void uk_sched_thread_terminate(struct uk_thread *thread); +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY +/** + * Sets the priority of the given thread, do not reschedule + * @param thread + * Thread to be set (required) + * @param priority + * Priority to be set + * @return + * NULL + */ +void uk_sched_thread_set_priority(struct uk_thread *thread, int32_t priority); + +/** + * Compares the priority of two threads + * @param thread_1 + * First thread to be compared + * @param thread_2 + * Second thread to be compared + * @return + * - (0): The two threads have the same priority + * - (>0): The first thread has a higher priority + * - (<0): The second thread has a higher priority + */ +static inline int uk_sched_prio_cmp(struct uk_thread *thread_1, + struct uk_thread *thread_2) +{ + struct uk_sched *s; + + s = thread_1->sched; + + UK_ASSERT(s && s == thread_2->sched); + + return s->prio_cmp(thread_1, thread_2); +} +#endif + #ifdef __cplusplus } #endif diff --git a/lib/uksched/include/uk/sched_impl.h b/lib/uksched/include/uk/sched_impl.h index 2aca7c4bad030c12c4d4ed32190f848e60afbe60..37218fa320c5850d074755c990df8cbf60a92bb1 100644 --- a/lib/uksched/include/uk/sched_impl.h +++ b/lib/uksched/include/uk/sched_impl.h @@ -60,29 +60,56 @@ extern struct uk_sched *uk_sched_head; */ int uk_sched_register(struct uk_sched *s); -#define uk_sched_init(s, start_func, yield_func, \ - thread_add_func, thread_remove_func, \ - thread_blocked_func, thread_woken_func, \ - thread_woken_isr_func, idle_thread_func, \ - def_allocator) \ - do { \ - (s)->sched_start = start_func; \ - (s)->yield = yield_func; \ - (s)->thread_add = thread_add_func; \ - (s)->thread_remove = thread_remove_func; \ - (s)->thread_blocked = thread_blocked_func; \ - (s)->thread_woken = thread_woken_func; \ - (s)->thread_woken_isr = thread_woken_isr_func; \ - (s)->idle_thread = idle_thread_func; \ - uk_sched_register((s)); \ - \ - (s)->a = (def_allocator); \ - (s)->a_stack = (def_allocator); \ - (s)->a_auxstack = (def_allocator); \ - (s)->a_uktls = (def_allocator); \ - UK_TAILQ_INIT(&(s)->thread_list); \ - UK_TAILQ_INIT(&(s)->exited_threads); \ +#if defined(CONFIG_LIBUKSCHED_THREAD_PRIORITY) +#define uk_sched_init(s, start_func, yield_func, reschedule_func, \ + thread_add_func, thread_remove_func, \ + thread_blocked_func, thread_woken_func, \ + thread_woken_isr_func, prio_set_func, prio_cmp_func, \ + idle_thread_func, def_allocator) \ + do { \ + (s)->sched_start = start_func; \ + (s)->yield = yield_func; \ + (s)->reschedule = reschedule_func; \ + (s)->thread_add = thread_add_func; \ + (s)->thread_remove = thread_remove_func; \ + (s)->thread_blocked = thread_blocked_func; \ + (s)->thread_woken = thread_woken_func; \ + (s)->thread_woken_isr = thread_woken_isr_func; \ + (s)->thread_set_prio = prio_set_func; \ + (s)->prio_cmp = prio_cmp_func; \ + (s)->idle_thread = idle_thread_func; \ + uk_sched_register((s)); \ + (s)->a = (def_allocator); \ + (s)->a_stack = (def_allocator); \ + (s)->a_auxstack = (def_allocator); \ + (s)->a_uktls = (def_allocator); \ + UK_TAILQ_INIT(&(s)->thread_list); \ + UK_TAILQ_INIT(&(s)->exited_threads); \ } while (0) +#else +#define uk_sched_init(s, start_func, yield_func, reschedule_func, \ + thread_add_func, thread_remove_func, \ + thread_blocked_func, thread_woken_func, \ + thread_woken_isr_func, idle_thread_func, def_allocator) \ + do { \ + (s)->sched_start = start_func; \ + (s)->yield = yield_func; \ + (s)->reschedule = reschedule_func; \ + (s)->thread_add = thread_add_func; \ + (s)->thread_remove = thread_remove_func; \ + (s)->thread_blocked = thread_blocked_func; \ + (s)->thread_woken = thread_woken_func; \ + (s)->thread_woken_isr = thread_woken_isr_func; \ + (s)->idle_thread = idle_thread_func; \ + uk_sched_register((s)); \ + (s)->a = (def_allocator); \ + (s)->a_stack = (def_allocator); \ + (s)->a_auxstack = (def_allocator); \ + (s)->a_uktls = (def_allocator); \ + UK_TAILQ_INIT(&(s)->thread_list); \ + UK_TAILQ_INIT(&(s)->exited_threads); \ + } while (0) +#endif /* CONFIG_LIBUKSCHED_THREAD_PRIORITY */ /** * Releases self-exited threads (garbage collection) @@ -97,6 +124,8 @@ unsigned int uk_sched_thread_gc(struct uk_sched *sched); static inline void uk_sched_thread_switch(struct uk_thread *next) { + TN_TRACE_OBJ_FUNC(uk_thread, switch, next); + struct uk_thread *prev; prev = ukplat_per_lcpu_current(__uk_sched_thread_current); diff --git a/lib/uksched/include/uk/thread.h b/lib/uksched/include/uk/thread.h index 5bc71e8bcb4956dc5e908f0757818b6d039ecbaa..f72183f2b7b9c325ba770c6961aa04955412312c 100644 --- a/lib/uksched/include/uk/thread.h +++ b/lib/uksched/include/uk/thread.h @@ -40,6 +40,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -61,9 +62,14 @@ struct uk_thread { __uptr uktlsp; /**< Unikraft TLS pointer */ __uptr auxsp; /**< Unikraft Auxiliary Stack Pointer */ +#if defined(CONFIG_LIBUKSCHED_RUNQ_TAILQ) UK_TAILQ_ENTRY(struct uk_thread) queue; +#elif defined(CONFIG_LIBUKSCHED_RUNQ_LIST) + struct uk_list_head queue; +#endif + uint32_t flags; - __snsec wakeup_time; + struct timer timer; struct uk_sched *sched; struct { @@ -74,10 +80,14 @@ struct uk_thread { struct uk_alloc *uktls_a; void *auxstack; struct uk_alloc *auxstack_a; + __sz auxstack_len; } _mem; /**< Associated allocs (internal!) */ uk_thread_gc_t _gc_fn; /**< Extra gc function (internal!) */ void *_gc_argp; /**< Argument for gc fn (internal!) */ +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY + int32_t prio; /**< Thread priority */ +#endif uk_thread_dtor_t dtor; /**< User provided destructor */ void *priv; /**< Private field, free for use */ @@ -155,6 +165,19 @@ struct uk_thread *uk_thread_current(void) */ #define UK_THREADF_QUEUEABLE (0x010) +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY +#define UK_THREADF_LOWEST_PRIO CONFIG_LIBUKSCHED_LOWEST_PRIORITY +#define UK_THREADF_HIGHEST_PRIO \ + (CONFIG_LIBUKSCHED_PRIORITY_LEVEL + UK_THREADF_LOWEST_PRIO - 1) +#define UK_THREADF_IDLE_PRIO UK_THREADF_LOWEST_PRIO +#define UK_THREADF_DEFAULT_PRIO (UK_THREADF_IDLE_PRIO + 1) +#else +#define UK_THREADF_LOWEST_PRIO 0 +#define UK_THREADF_HIGHEST_PRIO 0 +#define UK_THREADF_IDLE_PRIO 0 +#define UK_THREADF_DEFAULT_PRIO 0 +#endif + #define uk_thread_is_exited(t) ((t)->flags & UK_THREADF_EXITED) #define uk_thread_is_runnable(t) (!uk_thread_is_exited(t) \ && ((t)->flags & UK_THREADF_RUNNABLE)) @@ -903,6 +926,110 @@ struct uk_thread *uk_thread_create_fn2(struct uk_alloc *a, void *priv, uk_thread_dtor_t dtor); +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY +/** + * Allocates a raw uk_thread structure with priority. Such a thread can then be + * assigned to a scheduler. When the thread starts, the general-purpose + * registers are reset. + * + * @param a + * Reference to an allocator (required) + * @param fn + * Thread entry function (required) + * @param argp + * Thread entry function argument(required) + * @param a_stack + * Reference to an allocator for allocating a stack (required) + * @param stack_len + * Size of the thread stack. If set to 0, a default stack size is used + * for the stack allocation. + * @param a_uktls + * Reference to an allocator for allocating (Unikraft) thread local storage. + * If `NULL` is passed, a thread without TLS is allocated. + * @param no_ectx + * If set, no memory is allocated for saving/restoring extended CPU + * context state (e.g., floating point, vector registers). In such a + * case, no extended context is saved nor restored on thread switches. + * Executed functions must be ISR-safe. + * @param name + * Optional name for the thread + * @param prio + * Priority of the thread + * @param priv + * Reference to external data that corresponds to this thread + * @param dtor + * Destructor that is called when this thread is released + * @return + * - (NULL): Allocation failed + * - Reference to initialized uk_thread + */ +struct uk_thread *uk_thread_prio_create_fn1(struct uk_alloc *a, + uk_thread_fn1_t fn, + void *argp, + struct uk_alloc *a_stack, + size_t stack_len, + struct uk_alloc *a_auxstack, + size_t auxstack_len, + struct uk_alloc *a_uktls, + bool no_ectx, + const char *name, + int32_t prio, + void *priv, + uk_thread_dtor_t dtor); + +/** + * Allocates a uk_thread container with stack, TLS and priority. The entry point + * is not set and the thread is not marked as runnable. Such a thread should + * only be assigned to a scheduler after an entry point is configured + * (`thread->ctx`) and the thread was marked as runnable. + * + * @param a + * Reference to an allocator (required) + * @param a_stack + * Reference to an allocator for allocating a stack + * Set to `NULL` to continue without a stack. + * @param stack_len + * Size of the thread stack. If set to 0, a default stack size is used + * for the stack allocation. + * @param a_auxstack + * Reference to an allocator for allocating an auxiliary stack + * @param auxstack_len + * Size of the thread auxiliary stack. If set to 0, a default stack size is + * used for the allocation. + * @param a_uktls + * Reference to an allocator for allocating (Unikraft) thread local storage. + * If `NULL` is passed, a thread without TLS is allocated. + * @param no_ectx + * If set, no memory is allocated for saving/restoring extended CPU + * context state (e.g., floating point, vector registers). In such a + * case, no extended context is saved nor restored on thread switches. + * Executed functions must be ISR-safe. + * @param name + * Optional name for the thread + * @param prio + * Priority of the thread + * @param priv + * Reference to external data that corresponds to this thread + * @param dtor + * Destructor that is called when this thread is released + * @return + * - (NULL): Allocation failed + * - Reference to initialized uk_thread + */ +struct uk_thread *uk_thread_prio_create_container(struct uk_alloc *a, + struct uk_alloc *a_stack, + size_t stack_len, + struct uk_alloc *a_auxstack, + size_t auxstack_len, + struct uk_alloc *a_uktls, + bool no_ectx, + const char *name, + int32_t prio, + void *priv, + uk_thread_dtor_t dtor); + +#endif /* CONFIG_LIBUKSCHED_THREAD_PRIORITY */ + /* Release a thread,set as exited and free memory * @param t * Thread to be released @@ -919,7 +1046,7 @@ void uk_thread_release(struct uk_thread *t); * @return * NULL */ -void uk_thread_block_until(struct uk_thread *thread, __snsec until); +void uk_thread_block_until(struct uk_thread *thread, __nsec until); /* Set the thread as blocked and assign a timeout * @param thread @@ -947,6 +1074,14 @@ void uk_thread_block(struct uk_thread *thread); */ void uk_thread_wake(struct uk_thread *thread); +/* The callback of thread timeout + * @param thread + * Thread to be blocked + * @return + * NULL + */ +void uk_thread_timeout(void *thread); + /** * Macro to access a Unikraft thread-local (UKTLS) variable of a * (foreign) thread. @@ -1047,6 +1182,13 @@ struct uk_thread_inittab_entry { UK_THREAD_INIT_PRIO_FLAGS(init_fn, term_fn, UK_PRIO_LATEST, \ (UK_THREAD_INITF_ALL)) +#define TN_THREAD_TIMER_START(thread, init_tick) \ + do { \ + tn_timer_init(&(thread->timer), init_tick, \ + uk_thread_timeout, thread, TN_TIMER_FLAG_ONE_SHOT);\ + tn_timer_start(&(thread->timer)); \ + } while (0) + #ifdef __cplusplus } #endif diff --git a/lib/uksched/include/uk/wait.h b/lib/uksched/include/uk/wait.h index aeaa5a804e65a2f6ea8b2835f1fda6ca4dd2f5e7..0b370b818cbab0ddd77fabbf87586312c45821df 100644 --- a/lib/uksched/include/uk/wait.h +++ b/lib/uksched/include/uk/wait.h @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -40,7 +41,7 @@ static inline void uk_waitq_init(struct uk_waitq *wq) { ukarch_spin_init(&(wq->sl)); - UK_STAILQ_INIT(&(wq->wait_list)); + __WAIT_QUEUE_INIT(wq); } static inline @@ -54,7 +55,7 @@ void uk_waitq_entry_init(struct uk_waitq_entry *entry, static inline int uk_waitq_empty(struct uk_waitq *wq) { - return UK_STAILQ_EMPTY(&(wq->wait_list)); + return _is_waitq_empty(wq); } static inline @@ -62,7 +63,7 @@ void uk_waitq_add(struct uk_waitq *wq, struct uk_waitq_entry *entry) { if (!entry->waiting) { - UK_STAILQ_INSERT_TAIL(&(wq->wait_list), entry, thread_list); + _waitq_add(wq, entry); entry->waiting = 1; } } @@ -72,8 +73,7 @@ void uk_waitq_remove(struct uk_waitq *wq, struct uk_waitq_entry *entry) { if (entry->waiting) { - UK_STAILQ_REMOVE(&(wq->wait_list), entry, - struct uk_waitq_entry, thread_list); + _waitq_remove(wq, entry); entry->waiting = 0; } } @@ -95,77 +95,82 @@ do { \ ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ } while (0) -#define __wq_wait_event_deadline(wq, condition, deadline, deadline_condition, \ - lock_fn, unlock_fn, lock) \ -({ \ - struct uk_thread *__current; \ - unsigned long flags; \ - int timedout = 0; \ - DEFINE_WAIT(__wait); \ - if (!(condition)) { \ - __current = uk_thread_current(); \ - for (;;) { \ - /* protect the list */ \ - ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ - if (condition) { \ - ukplat_spin_unlock_irqrestore(&((wq)->sl), \ - flags); \ - break; \ - } \ - uk_waitq_add(wq, &__wait); \ - __current->wakeup_time = deadline; \ - uk_thread_set_blocked(__current); \ - uk_sched_thread_blocked(__current); \ - ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ - if (lock) \ - unlock_fn(lock); \ - uk_sched_yield(); \ - if (lock) \ - lock_fn(lock); \ - if (condition) \ - break; \ - if (deadline_condition) { \ - timedout = 1; \ - break; \ - } \ - } \ - ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ - /* need to wake up */ \ - uk_thread_wake(__current); \ - uk_waitq_remove(wq, &__wait); \ - ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ - } \ - timedout; \ -}) - -#define uk_waitq_wait_deadline(wq, lock_fn, unlock_fn, lock, deadline, \ - deadline_condition) \ -({ \ - struct uk_thread *__current; \ - unsigned long flags; \ - int timedout = 0; \ - DEFINE_WAIT(__wait); \ - __current = uk_thread_current(); \ - ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ - uk_waitq_add(wq, &__wait); \ - __current->wakeup_time = deadline; \ - uk_thread_set_blocked(__current); \ - uk_sched_thread_blocked(__current); \ - ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ - if (lock) \ - unlock_fn(lock); \ - uk_sched_yield(); \ - if (lock) \ - lock_fn(lock); \ - if (deadline_condition) \ - timedout = 1; \ - ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ - /* need to wake up */ \ - uk_thread_wake(__current); \ - uk_waitq_remove(wq, &__wait); \ - ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ - timedout; \ -}) +#define __wq_wait_event_deadline(wq, condition, deadline, deadline_condition, \ + lock_fn, unlock_fn, lock) \ + ({ \ + struct uk_thread *__current; \ + unsigned long flags; \ + int timedout = 0; \ + DEFINE_WAIT(__wait); \ + if (!(condition)) { \ + __current = uk_thread_current(); \ + for (;;) { \ + /* protect the list */ \ + ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ + if (condition) { \ + ukplat_spin_unlock_irqrestore( \ + &((wq)->sl), flags); \ + break; \ + } \ + uk_waitq_add(wq, &__wait); \ + if (deadline) \ + TN_THREAD_TIMER_START( \ + __current, \ + ns_to_ticks( \ + deadline \ + - ukplat_monotonic_clock())); \ + uk_thread_set_blocked(__current); \ + uk_sched_thread_blocked(__current); \ + ukplat_spin_unlock_irqrestore(&((wq)->sl), \ + flags); \ + if (lock) \ + unlock_fn(lock); \ + uk_sched_yield(); \ + if (lock) \ + lock_fn(lock); \ + if (condition) \ + break; \ + if (deadline_condition) { \ + timedout = 1; \ + break; \ + } \ + } \ + ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ + uk_waitq_remove(wq, &__wait); \ + ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ + } \ + timedout; \ + }) + +#define uk_waitq_wait_deadline(wq, lock_fn, unlock_fn, lock, deadline, \ + deadline_condition) \ + ({ \ + struct uk_thread *__current; \ + unsigned long flags; \ + int timedout = 0; \ + DEFINE_WAIT(__wait); \ + __current = uk_thread_current(); \ + ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ + uk_waitq_add(wq, &__wait); \ + if (deadline) \ + TN_THREAD_TIMER_START( \ + __current, \ + ns_to_ticks(deadline - ukplat_monotonic_clock())); \ + uk_thread_set_blocked(__current); \ + uk_sched_thread_blocked(__current); \ + ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ + if (lock) \ + unlock_fn(lock); \ + uk_sched_yield(); \ + if (lock) \ + lock_fn(lock); \ + if (deadline_condition) \ + timedout = 1; \ + ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ + uk_waitq_remove(wq, &__wait); \ + ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ + timedout; \ + }) #define uk_waitq_wait_locked(wq, lock_fn, unlock_fn, lock) \ uk_waitq_wait_deadline(wq, lock_fn, unlock_fn, lock, 0, 0) @@ -199,10 +204,16 @@ void uk_waitq_wake_up(struct uk_waitq *wq) struct uk_waitq_entry *curr, *tmp; unsigned long flags; + /* TODO: Optimize lock range */ ukplat_spin_lock_irqsave(&(wq->sl), flags); - UK_STAILQ_FOREACH_SAFE(curr, &(wq->wait_list), thread_list, tmp) + _waitq_foreach_safe(curr, &(wq->wait_list), thread_list, tmp) + { uk_thread_wake(curr->thread); + tn_timer_delete(&curr->thread->timer); + } ukplat_spin_unlock_irqrestore(&(wq->sl), flags); + + uk_sched_reschedule(); } static inline @@ -212,10 +223,14 @@ void uk_waitq_wake_up_one(struct uk_waitq *wq) unsigned long flags; ukplat_spin_lock_irqsave(&(wq->sl), flags); - head = UK_STAILQ_FIRST(&wq->wait_list); - if (head) + head = _waitq_best(wq); + if (head) { uk_thread_wake(head->thread); + tn_timer_delete(&head->thread->timer); + } ukplat_spin_unlock_irqrestore(&(wq->sl), flags); + if (head) + uk_sched_reschedule(); } #ifdef __cplusplus diff --git a/lib/uksched/include/uk/wait_queue.h b/lib/uksched/include/uk/wait_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..fda5fbd41428a1c809ff4a15a7039209417831d2 --- /dev/null +++ b/lib/uksched/include/uk/wait_queue.h @@ -0,0 +1,135 @@ +/* Copyright 2023 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __UK_SCHED_WAIT_QUEUE_H__ +#define __UK_SCHED_WAIT_QUEUE_H__ + +#include +#include +#include + +/** + * _is_waitq_empty - check if the wait queue is empty + * _waitq_add - add a waiter to the wait queue + * _waitq_remove - remove a waiter from the wait queue + * __waitq_first - get the first waiter from the wait queue + */ + +#if defined(CONFIG_LIBUKSCHED_WAITQ_STAILQ) +#define _is_waitq_empty waitq_stailq_is_empty +#define _waitq_add waitq_stailq_add +#define _waitq_remove waitq_stailq_remove +#define _waitq_best waitq_stailq_first + +#define _waitq_foreach_safe UK_STAILQ_FOREACH_SAFE + +#elif defined(CONFIG_LIBUKSCHED_WAITQ_LIST) +#define _is_waitq_empty waitq_list_is_empty +#define _waitq_add waitq_list_add +#define _waitq_remove waitq_list_remove +#define _waitq_best waitq_list_best + +#define _waitq_foreach_safe(var, head, field, tvar) \ + uk_list_for_each_entry_safe(var, tvar, head, field) +#endif + +#ifdef CONFIG_LIBUKSCHED_WAITQ_STAILQ +static inline int waitq_stailq_is_empty(struct uk_waitq *wq) +{ + return UK_STAILQ_EMPTY(&(wq->wait_list)); +} + +static inline void waitq_stailq_add(struct uk_waitq *wq, + struct uk_waitq_entry *entry) +{ + UK_STAILQ_INSERT_TAIL(&(wq->wait_list), entry, thread_list); +} + +static inline void waitq_stailq_remove(struct uk_waitq *wq, + struct uk_waitq_entry *entry) +{ + UK_STAILQ_REMOVE(&(wq->wait_list), entry, struct uk_waitq_entry, + thread_list); +} + +static inline struct uk_waitq_entry *waitq_stailq_first(struct uk_waitq *wq) +{ + return UK_STAILQ_FIRST(&(wq->wait_list)); +} + +#elif defined(CONFIG_LIBUKSCHED_WAITQ_LIST) + +static inline int waitq_list_is_empty(struct uk_waitq *wq) +{ + return uk_list_empty(&(wq->wait_list)); +} + +static inline void waitq_list_add(struct uk_waitq *wq, + struct uk_waitq_entry *entry) +{ + struct uk_waitq_entry *tmp = NULL; + + uk_list_for_each_entry(tmp, &wq->wait_list, thread_list) { + if (uk_sched_prio_cmp(entry->thread, tmp->thread) > 0) { + uk_list_add_before(&entry->thread_list, + &tmp->thread_list); + break; + } + } + if (&tmp->thread_list == &wq->wait_list) + uk_list_add_tail(&entry->thread_list, &wq->wait_list); +} + +static inline void waitq_list_remove(struct uk_waitq *wq __unused, + struct uk_waitq_entry *entry) +{ + uk_list_del(&entry->thread_list); +} + +static inline struct uk_waitq_entry *waitq_list_best(struct uk_waitq *wq) +{ + return uk_list_first_entry_or_null(&wq->wait_list, + struct uk_waitq_entry, thread_list); +} +#endif + +// Dump non-priority wait queue +#ifdef CONFIG_LIBUKSCHED_WAITQ_STAILQ +static inline void dump_wait_queue(struct uk_waitq *wq) +{ + struct uk_waitq_entry *t = NULL, *tmp = NULL; + + uk_pr_info("Wait queue: "); + _waitq_foreach_safe(t, &(wq->wait_list), thread_list, tmp) { + uk_pr_info("%s ", t->thread->name); + } + uk_pr_info("\n"); +} + +// Dump priority wait queue +#else +static inline void dump_wait_queue(struct uk_waitq *wq) +{ + struct uk_waitq_entry *t = NULL, *tmp = NULL; + + uk_pr_info("Wait queue: "); + _waitq_foreach_safe(t, &(wq->wait_list), thread_list, tmp) { + uk_pr_info("%s(%d) ", t->thread->name, t->thread->prio); + } + uk_pr_info("\n"); +} +#endif + +#endif /* __UK_SCHED_WAIT_QUEUE_H__ */ diff --git a/lib/uksched/include/uk/wait_types.h b/lib/uksched/include/uk/wait_types.h index 2b0a3e6bc4e8400fcb3030d9121692b2652e86c9..c7676359d09ddd798acf97c9705751e81cce76e1 100644 --- a/lib/uksched/include/uk/wait_types.h +++ b/lib/uksched/include/uk/wait_types.h @@ -36,20 +36,38 @@ extern "C" { struct uk_waitq_entry { int waiting; struct uk_thread *thread; +#if defined(CONFIG_LIBUKSCHED_WAITQ_STAILQ) UK_STAILQ_ENTRY(struct uk_waitq_entry) thread_list; +#elif defined(CONFIG_LIBUKSCHED_WAITQ_LIST) + struct uk_list_head thread_list; +#endif }; struct uk_waitq { __spinlock sl; +#if defined(CONFIG_LIBUKSCHED_WAITQ_STAILQ) UK_STAILQ_HEAD(wait_list, struct uk_waitq_entry) wait_list; +#elif defined(CONFIG_LIBUKSCHED_WAITQ_LIST) + struct uk_list_head wait_list; +#endif }; +#if defined(CONFIG_LIBUKSCHED_WAITQ_STAILQ) #define __WAIT_QUEUE_INITIALIZER(name) \ { \ UKARCH_SPINLOCK_INITIALIZER(), \ UK_STAILQ_HEAD_INITIALIZER(name.wait_list) \ } +#define __WAIT_QUEUE_INIT(name) UK_STAILQ_INIT(&(name->wait_list)) + +#elif defined(CONFIG_LIBUKSCHED_WAITQ_LIST) +#define __WAIT_QUEUE_INITIALIZER(name) \ + { UKARCH_SPINLOCK_INITIALIZER(), UK_LIST_HEAD_INIT(name.wait_list) } + +#define __WAIT_QUEUE_INIT(name) UK_INIT_LIST_HEAD(&(name->wait_list)) +#endif + #define UK_WAIT_QUEUE_INITIALIZER(name) __WAIT_QUEUE_INITIALIZER(name) #define DEFINE_WAIT_QUEUE(name) \ diff --git a/lib/uksched/isrwake.c b/lib/uksched/isrwake.c index 279ba885694070f651bbf32865bc76893f38766c..d318bfdaaa8f91bf64648032d48ccc13953e9ba4 100644 --- a/lib/uksched/isrwake.c +++ b/lib/uksched/isrwake.c @@ -16,6 +16,5 @@ void uk_thread_wake_isr(struct uk_thread *thread) if (thread->sched) uk_sched_thread_woken_isr(thread); } - thread->wakeup_time = 0LL; ukplat_lcpu_restore_irqf(flags); } diff --git a/lib/uksched/sched.c b/lib/uksched/sched.c index a656da755a9504bf723722b5ccb1b231cefa1b30..a5ae6fc783fb42a8a0ae3f0875b5850b282a7254 100644 --- a/lib/uksched/sched.c +++ b/lib/uksched/sched.c @@ -41,6 +41,7 @@ #include #include #include +#include struct uk_sched *uk_sched_head; @@ -221,6 +222,9 @@ int uk_sched_start(struct uk_sched *s) ret = -ENOMEM; goto err_out; } +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY + main_thread->prio = UK_THREADF_DEFAULT_PRIO; +#endif main_thread->sched = s; /* Because `main_thread` acts as container for storing the current @@ -311,7 +315,7 @@ void uk_sched_thread_terminate(struct uk_thread *thread) thread_list); /* leave this thread */ - sched->yield(sched); /* we won't return */ + sched->reschedule(sched); /* we won't return */ UK_CRASH("Unexpectedly returned to exited thread %p\n", thread); } else { /* free thread resources immediately */ @@ -324,10 +328,14 @@ void uk_sched_thread_exit2(uk_thread_gc_t gc_fn, void *gc_argp) { struct uk_thread *t = uk_thread_current(); + TN_TRACE_OBJ_FUNC_ENTER(uk_thread, exit, t); + t->_gc_fn = gc_fn; t->_gc_argp = gc_argp; uk_sched_thread_terminate(t); UK_CRASH("Unexpectedly returned to exited thread %p\n", t); + + TN_TRACE_OBJ_FUNC_EXIT(uk_thread, exit, t); } /* This function has the __noreturn attribute set */ @@ -336,12 +344,27 @@ void uk_sched_thread_exit(void) uk_sched_thread_exit2(NULL, NULL); } -void uk_sched_thread_sleep(__nsec nsec) +void uk_sched_thread_sleep_ns(__nsec nsec) +{ + struct uk_thread *thread; + + thread = uk_thread_current(); + + TN_TRACE_OBJ_FUNC(uk_thread, sleep_ns, thread, nsec); + + uk_thread_block_timeout(thread, ns_to_ticks(nsec)); + uk_sched_yield(); +} + +void uk_sched_thread_sleep_tick(systick_t tick) { struct uk_thread *thread; thread = uk_thread_current(); - uk_thread_block_timeout(thread, nsec); + + TN_TRACE_OBJ_FUNC(uk_thread, sleep_tick, thread, tick); + + uk_thread_block_timeout(thread, tick); uk_sched_yield(); } @@ -354,16 +377,23 @@ int uk_sched_thread_add(struct uk_sched *s, struct uk_thread *t) UK_ASSERT(t); UK_ASSERT(!t->sched); + TN_TRACE_OBJ_FUNC(uk_thread, add, t); + flags = ukplat_lcpu_save_irqf(); rc = s->thread_add(s, t); - if (rc < 0) - goto out; + if (rc < 0) { + ukplat_lcpu_restore_irqf(flags); + return rc; + } t->sched = s; UK_TAILQ_INSERT_TAIL(&s->thread_list, t, thread_list); -out: ukplat_lcpu_restore_irqf(flags); + + if (uk_sched_current() == s) + s->reschedule(s); + return rc; } @@ -375,12 +405,17 @@ int uk_sched_thread_remove(struct uk_thread *t) UK_ASSERT(t); UK_ASSERT(t->sched); + TN_TRACE_OBJ_FUNC_ENTER(uk_thread, remove, t); + flags = ukplat_lcpu_save_irqf(); s = t->sched; s->thread_remove(s, t); t->sched = NULL; UK_TAILQ_REMOVE(&s->thread_list, t, thread_list); ukplat_lcpu_restore_irqf(flags); + + TN_TRACE_OBJ_FUNC_EXIT(uk_thread, remove, t); + return 0; } @@ -442,3 +477,15 @@ UK_SYSCALL_R_DEFINE(int, sched_setaffinity, int, pid, long, cpusetsize, UK_WARN_STUBBED(); return 0; } + +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY +void uk_sched_thread_set_priority(struct uk_thread *thread, int32_t priority) +{ + UK_ASSERT(thread); + UK_ASSERT(thread->sched); + + thread->sched->thread_set_prio(thread->sched, thread, priority); + + TN_TRACE_OBJ_FUNC(uk_thread, set_priority, thread, priority); +} +#endif diff --git a/lib/uksched/tests/test_sched.c b/lib/uksched/tests/test_sched.c index cc469bdc0748b62da02430853cff789b182b8bf9..dc540dd3c51738085b09e529794370bafa33a0a1 100644 --- a/lib/uksched/tests/test_sched.c +++ b/lib/uksched/tests/test_sched.c @@ -25,7 +25,12 @@ #include #include #include +#include +#ifdef CONFIG_LIBUKSCHEDCOOP #include +#elif CONFIG_LIBTNSCHEDPRIO +#include +#endif #if CONFIG_LIBUKBOOT_INITBBUDDY #include #define uk_alloc_init uk_allocbbuddy_init @@ -48,8 +53,14 @@ UK_TESTCASE(uksched, test_sched_register) /*初始化返回值*/ int ret; struct uk_alloc *a = uk_alloc_get_default(); +#ifdef CONFIG_LIBUKSCHEDCOOP struct uk_sched *node1 = uk_schedcoop_create(a); struct uk_sched *node2 = uk_schedcoop_create(a); +#endif +#ifdef CONFIG_LIBTNSCHEDPRIO + struct uk_sched *node1 = tn_schedprio_create(a); + struct uk_sched *node2 = tn_schedprio_create(a); +#endif ret = uk_sched_register(node1); // when the list is empty @@ -122,7 +133,7 @@ UK_TESTCASE(uksched, test_thread_block_no_timeout_then_wake) uk_thread_wake(main_thread); // TODO:add test for irq-safe operation。 UK_TEST_EXPECT_SNUM_EQ(uk_thread_is_runnable(main_thread), 1); - UK_TEST_EXPECT_SNUM_EQ(main_thread->wakeup_time, 0LL); + UK_TEST_EXPECT_SNUM_EQ(main_thread->timer.init_tick, 0LL); } UK_TESTCASE(uksched, test_thread_set_exited) @@ -147,6 +158,7 @@ UK_TESTCASE(uksched, test_sched_thread_sleep) int ret; struct uk_sched *s = uk_sched_current(); uintptr_t tlsp; + systick_t begin_t, end_t; tlsp = ukplat_tlsp_get(); @@ -155,13 +167,17 @@ UK_TESTCASE(uksched, test_sched_thread_sleep) false, "test_sleep", NULL, NULL); ret = uk_sched_thread_add(s, main_thread); - time_t begin = ukplat_monotonic_clock(); + begin_t = tn_systick_get_tick(); + uk_sched_thread_sleep_tick(100); + end_t = tn_systick_get_tick(); - uk_sched_thread_sleep(10000); + UK_TEST_EXPECT_SNUM_EQ(end_t-begin_t, 100); - time_t end = ukplat_monotonic_clock(); + begin_t = tn_systick_get_tick(); + uk_sched_thread_sleep_ns(10000); + end_t = tn_systick_get_tick(); - UK_TEST_EXPECT_SNUM_NQ(end-begin, 0); + UK_TEST_EXPECT_SNUM_EQ(end_t-begin_t, ns_to_ticks(10000)); } static __noreturn void idle_thread_fn(void *argp) diff --git a/lib/uksched/thread.c b/lib/uksched/thread.c index fff25e87827a48760c938ee0a29ffb0767830fe9..fec74fb707b645855f812035d787ea4e4bc9f382 100644 --- a/lib/uksched/thread.c +++ b/lib/uksched/thread.c @@ -45,6 +45,9 @@ #include #include #include +#include +#include + #if CONFIG_LIBUKSCHED_TCB_INIT && !CONFIG_UKARCH_TLS_HAVE_TCB #error CONFIG_LIBUKSCHED_TCB_INIT requires that a TLS contains reserved space for a TCB @@ -230,6 +233,7 @@ static void _uk_thread_struct_init(struct uk_thread *t, bool is_uktls, struct ukarch_ectx *ectx, const char *name, + int32_t prio, void *priv, uk_thread_dtor_t dtor) { @@ -244,14 +248,28 @@ static void _uk_thread_struct_init(struct uk_thread *t, t->priv = priv; t->dtor = dtor; t->exec_time = 0; + UK_INIT_LIST_HEAD(&t->timer.list); + +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY + t->prio = prio; +#endif - if (!auxsp) + if (!auxsp) { + /* These seems to be compatible code block, we should store + * necessary staff to free aux stack when release thread. + */ + __uptr auxstack = 0x0; auxsp = ukplat_auxsp_alloc(uk_alloc_get_default(), #if CONFIG_LIBUKVMEM uk_vas_get_active(), -#endif /* CONFIG_LIBUKVMEM */ - 0); /* Default auxsp size */ - +#endif /* CONFIG_LIBUKVMEM */ + 0, /* Default auxsp size */ + &auxstack); + if (auxsp && auxstack) { + t->_mem.auxstack = (void *)auxstack; + t->_mem.auxstack_a = uk_alloc_get_default(); + } + } t->auxsp = auxsp; if (tlsp && is_uktls) { @@ -282,8 +300,8 @@ int uk_thread_init_bare(struct uk_thread *t, UK_ASSERT(t); UK_ASSERT(t != uk_thread_current()); - _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, priv, - dtor); + _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, + UK_THREADF_DEFAULT_PRIO, priv, dtor); ukarch_ctx_init_bare(&t->ctx, sp, ip); if (ip) @@ -308,8 +326,8 @@ int uk_thread_init_bare_fn0(struct uk_thread *t, UK_ASSERT(sp); /* stack pointer is required for ctx_entry */ UK_ASSERT(fn); - _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, priv, - dtor); + _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, + UK_THREADF_DEFAULT_PRIO, priv, dtor); ukarch_ctx_init_entry0(&t->ctx, sp, 0, (ukarch_ctx_entry0) fn); uk_thread_set_runnable(t); @@ -334,8 +352,8 @@ int uk_thread_init_bare_fn1(struct uk_thread *t, UK_ASSERT(sp); /* stack pointer is required for ctx_entry */ UK_ASSERT(fn); - _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, priv, - dtor); + _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, + UK_THREADF_DEFAULT_PRIO, priv, dtor); ukarch_ctx_init_entry1(&t->ctx, sp, 0, (ukarch_ctx_entry1) fn, (long) argp); @@ -361,8 +379,8 @@ int uk_thread_init_bare_fn2(struct uk_thread *t, UK_ASSERT(sp); /* stack pointer is required for ctx_entry */ UK_ASSERT(fn); - _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, priv, - dtor); + _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, + UK_THREADF_DEFAULT_PRIO, priv, dtor); ukarch_ctx_init_entry2(&t->ctx, sp, 0, (ukarch_ctx_entry2) fn, (long) argp0, (long) argp1); @@ -381,12 +399,14 @@ static int _uk_thread_struct_init_alloc(struct uk_thread *t, bool custom_ectx, struct ukarch_ectx *ectx, const char *name, + int32_t prio, void *priv, uk_thread_dtor_t dtor) { void *stack = NULL; void *tls = NULL; - void *auxstack = 0x0; + __uptr auxstack = 0x0; + __uptr auxsp = 0x0; uintptr_t tlsp = 0x0; int rc; @@ -399,12 +419,12 @@ static int _uk_thread_struct_init_alloc(struct uk_thread *t, } if (a_auxstack && auxstack_len) { - auxstack = (void *)ukplat_auxsp_alloc(a_auxstack, + auxsp = ukplat_auxsp_alloc(a_auxstack, #if CONFIG_LIBUKVMEM - uk_vas_get_active(), + uk_vas_get_active(), #endif /* CONFIG_LIBUKVMEM */ - auxstack_len); - if (unlikely(!auxstack)) { + auxstack_len, &auxstack); + if (unlikely(!auxsp || !auxstack)) { rc = -ENOMEM; goto err_free_stack; } @@ -441,8 +461,7 @@ static int _uk_thread_struct_init_alloc(struct uk_thread *t, tlsp = ukarch_tls_tlsp(tls); } - _uk_thread_struct_init(t, (__uptr)auxstack, tlsp, !(!tlsp), ectx, - name, priv, + _uk_thread_struct_init(t, auxsp, tlsp, !(!tlsp), ectx, name, prio, priv, dtor); /* Set uk_thread fields related to stack and TLS */ @@ -451,9 +470,10 @@ static int _uk_thread_struct_init_alloc(struct uk_thread *t, t->_mem.stack_a = a_stack; } - if (auxstack) { - t->_mem.auxstack = auxstack; + if (auxsp && auxstack) { + t->_mem.auxstack = (void *)auxstack; t->_mem.auxstack_a = a_auxstack; + t->_mem.auxstack_len = auxstack_len; } if (tls) { @@ -505,9 +525,15 @@ void _uk_thread_struct_free_alloc(struct uk_thread *t) t->_mem.stack = NULL; } if (t->auxsp) { - uk_free(t->_mem.auxstack_a, t->_mem.auxstack); + ukplat_auxsp_free(t->_mem.auxstack_a, +#if CONFIG_LIBUKVMEM + uk_vas_get_active(), +#endif /* CONFIG_LIBUKVMEM */ + (__uptr)t->_mem.auxstack, + t->_mem.auxstack_len); t->_mem.auxstack_a = NULL; t->_mem.auxstack = NULL; + t->_mem.auxstack_len = 0; } } @@ -530,11 +556,9 @@ int uk_thread_init_fn0(struct uk_thread *t, UK_ASSERT(t != uk_thread_current()); UK_ASSERT(fn); - ret = _uk_thread_struct_init_alloc(t, - a_stack, stack_len, - a_auxstack, auxstack_len, - a_uktls, custom_ectx, ectx, name, - priv, dtor); + ret = _uk_thread_struct_init_alloc( + t, a_stack, stack_len, a_auxstack, auxstack_len, a_uktls, + custom_ectx, ectx, name, UK_THREADF_DEFAULT_PRIO, priv, dtor); if (ret < 0) goto err_out; @@ -574,11 +598,9 @@ int uk_thread_init_fn1(struct uk_thread *t, UK_ASSERT(t != uk_thread_current()); UK_ASSERT(fn); - ret = _uk_thread_struct_init_alloc(t, - a_stack, stack_len, - a_auxstack, auxstack_len, - a_uktls, custom_ectx, ectx, name, - priv, dtor); + ret = _uk_thread_struct_init_alloc( + t, a_stack, stack_len, a_auxstack, auxstack_len, a_uktls, + custom_ectx, ectx, name, UK_THREADF_DEFAULT_PRIO, priv, dtor); if (ret < 0) goto err_out; @@ -618,11 +640,9 @@ int uk_thread_init_fn2(struct uk_thread *t, UK_ASSERT(t != uk_thread_current()); UK_ASSERT(fn); - ret = _uk_thread_struct_init_alloc(t, - a_stack, stack_len, - a_auxstack, auxstack_len, - a_uktls, custom_ectx, ectx, name, - priv, dtor); + ret = _uk_thread_struct_init_alloc( + t, a_stack, stack_len, a_auxstack, auxstack_len, a_uktls, + custom_ectx, ectx, name, UK_THREADF_DEFAULT_PRIO, priv, dtor); if (ret < 0) goto err_out; @@ -680,16 +700,18 @@ struct uk_thread *uk_thread_create_bare(struct uk_alloc *a, /** Allocates `struct uk_thread` along with stack and TLS but do not initialize * the architecture context with an entry function (set to NULL) */ -struct uk_thread *uk_thread_create_container(struct uk_alloc *a, - struct uk_alloc *a_stack, - size_t stack_len, - struct uk_alloc *a_auxstack, - size_t auxstack_len, - struct uk_alloc *a_uktls, - bool no_ectx, - const char *name, - void *priv, - uk_thread_dtor_t dtor) +static inline struct uk_thread * +_uk_thread_create_container(struct uk_alloc *a, + struct uk_alloc *a_stack, + size_t stack_len, + struct uk_alloc *a_auxstack, + size_t auxstack_len, + struct uk_alloc *a_uktls, + bool no_ectx, + const char *name, + int32_t prio, + void *priv, + uk_thread_dtor_t dtor) { struct uk_thread *t; size_t t_size; @@ -718,13 +740,10 @@ struct uk_thread *uk_thread_create_container(struct uk_alloc *a, ((1 << CONFIG_UKPLAT_AUXSP_PAGE_ORDER) * PAGE_SIZE); - if (_uk_thread_struct_init_alloc(t, - a_stack, stack_len, - a_auxstack, auxstack_len, - a_uktls, - !(!ectx), - ectx, - name, priv, dtor) < 0) + if (_uk_thread_struct_init_alloc(t, a_stack, stack_len, a_auxstack, + auxstack_len, a_uktls, !(!ectx), ectx, + name, prio, priv, dtor) + < 0) goto err_free_thread; t->_mem.t_a = a; @@ -750,6 +769,41 @@ err_out: return NULL; } +struct uk_thread *uk_thread_create_container(struct uk_alloc *a, + struct uk_alloc *a_stack, + size_t stack_len, + struct uk_alloc *a_auxstack, + size_t auxstack_len, + struct uk_alloc *a_uktls, + bool no_ectx, + const char *name, + void *priv, + uk_thread_dtor_t dtor) +{ + return _uk_thread_create_container(a, a_stack, stack_len, a_auxstack, + auxstack_len, a_uktls, no_ectx, name, + UK_THREADF_DEFAULT_PRIO, priv, dtor); +} + +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY +struct uk_thread *uk_thread_prio_create_container(struct uk_alloc *a, + struct uk_alloc *a_stack, + size_t stack_len, + struct uk_alloc *a_auxstack, + size_t auxstack_len, + struct uk_alloc *a_uktls, + bool no_ectx, + const char *name, + int32_t prio, + void *priv, + uk_thread_dtor_t dtor) +{ + return _uk_thread_create_container(a, a_stack, stack_len, a_auxstack, + auxstack_len, a_uktls, no_ectx, name, + prio, priv, dtor); +} +#endif + /** Allocates `struct uk_thread` along with ectx (if requested), take stack * and TLS from caller but do not initialize the architecture context with * an entry function (set to NULL) @@ -786,8 +840,8 @@ struct uk_thread *uk_thread_create_container2(struct uk_alloc *a, + sizeof(*t), ukarch_ectx_align()); - _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, priv, - dtor); + _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, + UK_THREADF_DEFAULT_PRIO, priv, dtor); t->_mem.t_a = a; /* Minimal context initialization where the stack pointer @@ -927,6 +981,40 @@ err_out: return NULL; } +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY +struct uk_thread *uk_thread_prio_create_fn1(struct uk_alloc *a, + uk_thread_fn1_t fn, + void *argp, + struct uk_alloc *a_stack, + size_t stack_len, + struct uk_alloc *a_auxstack, + size_t auxstack_len, + struct uk_alloc *a_uktls, + bool no_ectx, + const char *name, + int32_t prio, + void *priv, + uk_thread_dtor_t dtor) +{ + struct uk_thread *t; + + UK_ASSERT(fn); + UK_ASSERT(a_stack); /* A stack is required for ctx initialization */ + + t = uk_thread_prio_create_container(a, a_stack, stack_len, a_auxstack, + auxstack_len, a_uktls, no_ectx, + name, prio, priv, dtor); + if (!t) + goto err_out; + + uk_thread_container_init_fn1(t, fn, argp); + return t; + +err_out: + return NULL; +} +#endif + struct uk_thread *uk_thread_create_fn2(struct uk_alloc *a, uk_thread_fn2_t fn, void *argp0, void *argp1, @@ -969,6 +1057,7 @@ void uk_thread_release(struct uk_thread *t) void *stack; void *auxstack; void *tls; + __sz auxstack_len; UK_ASSERT(t); UK_ASSERT(t != uk_thread_current()); @@ -985,6 +1074,7 @@ void uk_thread_release(struct uk_thread *t) stack = t->_mem.stack; auxstack_a = t->_mem.auxstack_a; auxstack = t->_mem.auxstack; + auxstack_len = t->_mem.auxstack_len; tls_a = t->_mem.uktls_a; tls = t->_mem.uktls; @@ -1001,45 +1091,59 @@ void uk_thread_release(struct uk_thread *t) if (stack_a && stack) uk_free(stack_a, stack); if (auxstack_a && auxstack) - uk_free(auxstack_a, auxstack); + ukplat_auxsp_free(auxstack_a, +#if CONFIG_LIBUKVMEM + uk_vas_get_active(), +#endif /* CONFIG_LIBUKVMEM */ + (__uptr)auxstack, auxstack_len); if (a) uk_free(a, t); } -void uk_thread_block_until(struct uk_thread *thread, __snsec until) +void uk_thread_block_timeout(struct uk_thread *thread, systick_t tick) { unsigned long flags; UK_ASSERT(thread); flags = ukplat_lcpu_save_irqf(); - thread->wakeup_time = until; if (uk_thread_is_runnable(thread)) { uk_thread_set_blocked(thread); + TN_THREAD_TIMER_START(thread, tick); if (thread->sched) uk_sched_thread_blocked(thread); } ukplat_lcpu_restore_irqf(flags); } -void uk_thread_block_timeout(struct uk_thread *thread, __nsec nsec) +void uk_thread_block_until(struct uk_thread *thread, __nsec until) { - __snsec until = (__snsec) ukplat_monotonic_clock() + nsec; - UK_ASSERT(thread); - uk_thread_block_until(thread, until); + __nsec nsec = until - ukplat_monotonic_clock(); + + uk_thread_block_timeout(thread, ns_to_ticks(nsec)); } void uk_thread_block(struct uk_thread *thread) { + unsigned long flags; + UK_ASSERT(thread); - uk_thread_block_until(thread, (__nsec) 0); + flags = ukplat_lcpu_save_irqf(); + if (uk_thread_is_runnable(thread)) { + uk_thread_set_blocked(thread); + if (thread->sched) + uk_sched_thread_blocked(thread); + } + ukplat_lcpu_restore_irqf(flags); } void uk_thread_wake(struct uk_thread *thread) { + TN_TRACE_OBJ_FUNC(uk_thread, wake, thread); + unsigned long flags; flags = ukplat_lcpu_save_irqf(); @@ -1048,6 +1152,13 @@ void uk_thread_wake(struct uk_thread *thread) if (thread->sched) uk_sched_thread_woken(thread); } - thread->wakeup_time = 0LL; ukplat_lcpu_restore_irqf(flags); } + +void uk_thread_timeout(void *thread) +{ + uk_thread_wake((struct uk_thread *)thread); + + /* TODO: oepn reschedule when reschedule support interrupt ctx*/ + // uk_sched_reschedule(); +} diff --git a/lib/uksched/trace/trace_sched.c b/lib/uksched/trace/trace_sched.c new file mode 100644 index 0000000000000000000000000000000000000000..2dfe2c786e90db7d84e3548a1fc9e61e8f97e5b0 --- /dev/null +++ b/lib/uksched/trace/trace_sched.c @@ -0,0 +1,91 @@ +#include +#include + +#if defined(CONFIG_LIBTNTRACE_FORMAT) +void tn_trace_uk_thread_wake_format(struct uk_thread *thread) +{ + printf("%s: %p\n", __func__, thread); +} + +void tn_trace_uk_thread_yield_format(struct uk_thread *current) +{ + printf("%s: %p\n", __func__, current); +} + +void tn_trace_uk_thread_switch_format(struct uk_thread *next) +{ + struct uk_thread *thread = uk_thread_current(); + + printf("%s: switch from %p to %p\n", __func__, thread, next); +} + +void tn_trace_uk_thread_switch_exit_format(void) +{ + struct uk_thread *thread = uk_thread_current(); + + printf("%s: %p\n", __func__, thread); +} + +void tn_trace_uk_thread_set_priority_format( + struct uk_thread *thread, int32_t priority) +{ + printf("%s: %p %d\n", __func__, thread, priority); +} + +void tn_trace_uk_thread_exit_enter_format(struct uk_thread *thread) +{ + printf("%s: %p\n", __func__, thread); +} + +void tn_trace_uk_thread_exit_exit_format(struct uk_thread *thread) +{ + printf("%s: %p\n", __func__, thread); +} + +void tn_trace_uk_thread_sleep_ns_format(struct uk_thread *thread, __nsec nsec) +{ + printf("%s: %p %lu\n", __func__, thread, nsec); +} + +void tn_trace_uk_thread_sleep_tick_format( + struct uk_thread *thread, systick_t tick) +{ + printf("%s: %p %llu\n", __func__, thread, tick); +} + +void tn_trace_uk_thread_add_format(struct uk_thread *thread) +{ + printf("%s: %p\n", __func__, thread); +} + +void tn_trace_uk_thread_remove_enter_format(struct uk_thread *thread) +{ + printf("%s: %p\n", __func__, thread); +} + +void tn_trace_uk_thread_remove_exit_format(struct uk_thread *thread) +{ + printf("%s: %p\n", __func__, thread); +} + +#elif defined(CONFIG_LIBTNTRACE_CUSTOM) + +void __weak tn_trace_uk_thread_wake_custom(struct uk_thread *thread) {} +void __weak tn_trace_uk_thread_yield_custom(struct uk_thread *current) {} +void __weak tn_trace_uk_thread_switch_custom(struct uk_thread *next) {} +void __weak tn_trace_uk_thread_set_priority_custom( + struct uk_thread *thread, int32_t priority) +{} +void __weak tn_trace_uk_thread_exit_enter_custom(struct uk_thread *thread) {} +void __weak tn_trace_uk_thread_exit_exit_custom(struct uk_thread *thread) {} +void __weak tn_trace_uk_thread_sleep_ns_custom( + struct uk_thread *thread, __nsec nsec) +{} +void __weak tn_trace_uk_thread_sleep_tick_custom( + struct uk_thread *thread, systick_t tick) +{} +void __weak tn_trace_uk_thread_add_custom(struct uk_thread *thread) {} +void __weak tn_trace_uk_thread_remove_enter_custom(struct uk_thread *thread) {} +void __weak tn_trace_uk_thread_remove_exit_custom(struct uk_thread *thread) {} + +#endif /* CONFIG_LIBTNTRACE_CUSTOM */ diff --git a/lib/ukschedcoop/isrwoken.c b/lib/ukschedcoop/isrwoken.c index 7ef783a557141202b058bec80949bbf1ba1fdf7a..2e573f1f54b0ae6035425955704e0aec60801ebc 100644 --- a/lib/ukschedcoop/isrwoken.c +++ b/lib/ukschedcoop/isrwoken.c @@ -11,8 +11,6 @@ void schedcoop_thread_woken_isr(struct uk_sched *s, struct uk_thread *t) UK_ASSERT(ukplat_lcpu_irqs_disabled()); - if (t->wakeup_time > 0) - UK_TAILQ_REMOVE(&c->sleep_queue, t, queue); if (uk_thread_is_queueable(t) && uk_thread_is_runnable(t)) { UK_TAILQ_INSERT_TAIL(&c->run_queue, t, queue); uk_thread_clear_queueable(t); diff --git a/lib/ukschedcoop/schedcoop.c b/lib/ukschedcoop/schedcoop.c index 47e63f83b7c44cb91b13a7262a1dbb8987982293..0086f1b2d2ae02ad524c8c8f71e5c46e7b725f19 100644 --- a/lib/ukschedcoop/schedcoop.c +++ b/lib/ukschedcoop/schedcoop.c @@ -36,20 +36,22 @@ #include #include #include +#include #include "schedcoop.h" -static void schedcoop_schedule(struct uk_sched *s) +static inline void schedcoop_schedule(struct uk_sched *s, bool yield) { struct schedcoop *c = uksched2schedcoop(s); struct uk_thread *prev, *next, *thread, *tmp; - __snsec now, min_wakeup_time; + __snsec now; unsigned long flags; - if (unlikely(ukplat_lcpu_irqs_disabled())) - UK_CRASH("Must not call %s with IRQs disabled\n", __func__); - now = ukplat_monotonic_clock(); + prev = uk_thread_current(); + if (!yield && uk_thread_is_runnable(prev)) + return; + flags = ukplat_lcpu_save_irqf(); #if 0 //TODO @@ -65,21 +67,6 @@ static void schedcoop_schedule(struct uk_sched *s) prev->exec_time += now - c->ts_prev_switch; c->ts_prev_switch = now; - /* Examine all sleeping threads. - * Wake up expired ones and find the time when the next timeout expires. - */ - min_wakeup_time = 0; - UK_TAILQ_FOREACH_SAFE(thread, &c->sleep_queue, - queue, tmp) { - if (likely(thread->wakeup_time)) { - if (thread->wakeup_time <= now) - uk_thread_wake(thread); - else if (!min_wakeup_time - || thread->wakeup_time < min_wakeup_time) - min_wakeup_time = thread->wakeup_time; - } - } - next = UK_TAILQ_FIRST(&c->run_queue); if (next) { UK_ASSERT(next != prev); @@ -103,7 +90,6 @@ static void schedcoop_schedule(struct uk_sched *s) * We select the idle thread only if we do not have anything * else to execute */ - c->idle_return_time = min_wakeup_time; next = &c->idle; } @@ -126,6 +112,16 @@ static void schedcoop_schedule(struct uk_sched *s) uk_sched_thread_switch(next); } +static void schedcoop_reschedule(struct uk_sched *s) +{ + schedcoop_schedule(s, false); +} + +static void schedcoop_yield(struct uk_sched *s) +{ + schedcoop_schedule(s, true); +} + static int schedcoop_thread_add(struct uk_sched *s, struct uk_thread *t) { struct schedcoop *c = uksched2schedcoop(s); @@ -158,14 +154,11 @@ static void schedcoop_thread_blocked(struct uk_sched *s, struct uk_thread *t) if (t != uk_thread_current()) UK_TAILQ_REMOVE(&c->run_queue, t, queue); - if (t->wakeup_time > 0) - UK_TAILQ_INSERT_TAIL(&c->sleep_queue, t, queue); } static __noreturn void idle_thread_fn(void *argp) { - struct schedcoop *c = (struct schedcoop *) argp; - __nsec now, wake_up_time; + struct schedcoop *c = (struct schedcoop *)argp; unsigned long flags; UK_ASSERT(c); @@ -191,26 +184,18 @@ static __noreturn void idle_thread_fn(void *argp) * Check if something else can be scheduled now. */ ukplat_lcpu_restore_irqf(flags); - schedcoop_schedule(&c->sched); + schedcoop_schedule(&c->sched, true); continue; } + ukplat_lcpu_restore_irqf(flags); /* Read return time set by last schedule operation */ - wake_up_time = (volatile __nsec) c->idle_return_time; - now = ukplat_monotonic_clock(); - - if (!wake_up_time || wake_up_time > now) { - if (wake_up_time) - ukplat_lcpu_halt_irq_until(wake_up_time); - else - ukplat_lcpu_halt_irq(); - } - - ukplat_lcpu_restore_irqf(flags); + tn_systick_block_until(tn_systick_get_tick() + + tn_timer_next_tick()); /* try to schedule a thread that might now be available */ - schedcoop_schedule(&c->sched); + schedcoop_schedule(&c->sched, true); } } @@ -263,7 +248,6 @@ struct uk_sched *uk_schedcoop_create(struct uk_alloc *a) goto err_out; UK_TAILQ_INIT(&c->run_queue); - UK_TAILQ_INIT(&c->sleep_queue); /* Create idle thread */ rc = uk_thread_init_fn1(&c->idle, @@ -280,16 +264,11 @@ struct uk_sched *uk_schedcoop_create(struct uk_alloc *a) c->idle.sched = &c->sched; - uk_sched_init(&c->sched, - schedcoop_start, - schedcoop_schedule, - schedcoop_thread_add, - schedcoop_thread_remove, - schedcoop_thread_blocked, - schedcoop_thread_woken_isr, - schedcoop_thread_woken_isr, - schedcoop_idle_thread, - a); + uk_sched_init(&c->sched, schedcoop_start, schedcoop_yield, + schedcoop_reschedule, schedcoop_thread_add, + schedcoop_thread_remove, schedcoop_thread_blocked, + schedcoop_thread_woken_isr, schedcoop_thread_woken_isr, + schedcoop_idle_thread, a); /* Add idle thread to the scheduler's thread list */ UK_TAILQ_INSERT_TAIL(&c->sched.thread_list, &c->idle, thread_list); diff --git a/lib/ukschedcoop/schedcoop.h b/lib/ukschedcoop/schedcoop.h index d07ca7cc6c1135f489251b5096fbfac20db9c67f..9af50ae9f3188aaaceafb69af3bd777266ec4798 100644 --- a/lib/ukschedcoop/schedcoop.h +++ b/lib/ukschedcoop/schedcoop.h @@ -11,10 +11,8 @@ struct schedcoop { struct uk_sched sched; struct uk_thread_list run_queue; - struct uk_thread_list sleep_queue; struct uk_thread idle; - __nsec idle_return_time; __nsec ts_prev_switch; }; diff --git a/lib/ukvmem/arch/arm/pagefault64.c b/lib/ukvmem/arch/arm/pagefault64.c index 6e3d56b2a236c78ee228dc1b43bb488854e74272..65a51be712826bc3e30b8aa7ecd6c990d5a7a47b 100644 --- a/lib/ukvmem/arch/arm/pagefault64.c +++ b/lib/ukvmem/arch/arm/pagefault64.c @@ -40,7 +40,7 @@ static int vmem_arch_pagefault(void *data) rc = vmem_pagefault(vaddr, faulttype, ctx->regs); if (unlikely(rc < 0)) { uk_pr_debug("Cannot handle %s page fault at 0x%"__PRIvaddr - " (ec: 0x%x): %d\n", + " (ec: 0x%lx): %d\n", faultstr[faulttype & UK_VMA_FAULT_ACCESSTYPE], vaddr, ctx->esr, rc); diff --git a/lib/vfscore/dentry.c b/lib/vfscore/dentry.c index b236d1ef71ff7f2173c57647b81c1792061967c9..6f657ec21cdc556c74763c982304bd1ba93c98ff 100644 --- a/lib/vfscore/dentry.c +++ b/lib/vfscore/dentry.c @@ -97,6 +97,7 @@ dentry_alloc(struct dentry *parent_dp, struct vnode *vp, const char *path) uk_mutex_unlock(&parent_dp->d_lock); } dp->d_parent = parent_dp; + uk_mutex_init(&dp->d_lock); vn_add_name(vp, dp); diff --git a/plat/Config.uk b/plat/Config.uk index 1ef6e042cfb946afb41137eddc324e15a454ee81..af2692194c63282afc73e560127cdd1c9598a6f2 100644 --- a/plat/Config.uk +++ b/plat/Config.uk @@ -86,6 +86,13 @@ config HAVE_PAGING default y if PAGING default n +config VIRTUALIZE_PLAT + bool + default n + depends on PLAT_KVM + help + The virtualization platform is currently being used + config HAVE_PAGING_DIRECTMAP bool default y if PAGING && ARCH_X86_64 diff --git a/plat/common/arm/lcpu.c b/plat/common/arm/lcpu.c index 927989f47b9991ec82afa5493ed8146df9bdce51..8e14691c7b208a550ea6403d57d504bd072add19 100644 --- a/plat/common/arm/lcpu.c +++ b/plat/common/arm/lcpu.c @@ -341,17 +341,15 @@ int lcpu_arch_run(struct lcpu *lcpu, const struct ukplat_lcpu_func *fn, if (unlikely(rc)) return rc; - uk_intctlr_sgi_op(*lcpu_run_irqv, lcpu->id); + return uk_intctlr_sgi_op(*lcpu_run_irqv, 1, lcpu->id); - return 0; } int lcpu_arch_wakeup(struct lcpu *lcpu) { UK_ASSERT(lcpu->id != lcpu_arch_id()); - uk_intctlr_sgi_op(*lcpu_wakeup_irqv, lcpu->id); + return uk_intctlr_sgi_op(*lcpu_wakeup_irqv, 1, lcpu->id); - return 0; } #endif /* CONFIG_HAVE_SMP */ diff --git a/plat/common/arm/time.c b/plat/common/arm/time.c index 8d89036a098581217ee5e8246a86669a7def487a..b720883f50952e3d46d6a82c2c3dbce1b17c1a63 100644 --- a/plat/common/arm/time.c +++ b/plat/common/arm/time.c @@ -88,14 +88,10 @@ uint32_t generic_timer_get_frequency(int fdt_timer) return fdt32_to_cpu(fdt_freq[0]); } -unsigned long sched_have_pending_events; - void time_block_until(__nsec until) { while (ukplat_monotonic_clock() < until) { generic_timer_cpu_block_until(until); - if (__uk_test_and_clear_bit(0, &sched_have_pending_events)) - break; } } @@ -131,7 +127,7 @@ void ukplat_time_init(void) if (unlikely(rc < 0)) UK_CRASH("Could not get IRQ from dtb (%d)\n", rc); - uk_intctlr_irq_configure(&irq); + uk_intctlr_irq_set_trigger(&irq); rc = uk_intctlr_irq_register(irq.id, generic_timer_irq_handler, NULL); if (unlikely(rc < 0)) diff --git a/plat/common/bootinfo_fdt.c b/plat/common/bootinfo_fdt.c index 64f75587d8a0bce8a815b61dd871c2f877046395..ee734c2b2565d61e5cff89a08645659fb90f237e 100644 --- a/plat/common/bootinfo_fdt.c +++ b/plat/common/bootinfo_fdt.c @@ -15,6 +15,8 @@ static void fdt_bootinfo_mem_mrd(struct ukplat_bootinfo *bi, void *fdtp) { struct ukplat_memregion_desc mrd = {0}; __u64 mem_base, mem_sz; + int len, ranges, range_index; + int parent_offset, naddr, nsize; int nmem; int rc; @@ -30,42 +32,77 @@ static void fdt_bootinfo_mem_mrd(struct ukplat_bootinfo *bi, void *fdtp) * For now, we only support one memory bank. * TODO: Support more than one memory@ node/regs/ranges properties. */ - rc = fdt_get_address(fdtp, nmem, 0, &mem_base, &mem_sz); - if (unlikely(rc)) - ukplat_bootinfo_crash("Get memory device address/size failed"); - if (unlikely(!RANGE_CONTAIN(mem_base, mem_sz, - __BASE_ADDR, __END - __BASE_ADDR))) - ukplat_bootinfo_crash("Image outside of RAM"); - - /* Check that we are not placed at the top of the memory region */ - mrd.len = __BASE_ADDR - mem_base; - if (!mrd.len) - goto end_mrd; - - mrd.vbase = (__vaddr_t)mem_base; - mrd.pbase = (__paddr_t)mem_base; - mrd.type = UKPLAT_MEMRT_FREE; - mrd.flags = UKPLAT_MEMRF_READ | UKPLAT_MEMRF_WRITE; - - rc = ukplat_memregion_list_insert(&bi->mrds, &mrd); - if (unlikely(rc < 0)) - ukplat_bootinfo_crash("Could not add free memory descriptor"); + parent_offset = fdt_parent_offset(fdtp, nmem); + naddr = fdt_address_cells(fdtp, parent_offset); + nsize = fdt_size_cells(fdtp, parent_offset); + + fdt_getprop(fdtp, nmem, "reg", &len); + ranges = len / (sizeof(fdt32_t) * (nsize + naddr)); + + for (range_index = 0; range_index < ranges; range_index++) { + rc = fdt_get_address(fdtp, nmem, range_index, + &mem_base, &mem_sz); + if (unlikely(rc)) + ukplat_bootinfo_crash( + "Get memory device address/size failed"); + + if (unlikely(!RANGE_CONTAIN(mem_base, mem_sz, + __BASE_ADDR, __END - __BASE_ADDR))){ + mrd.len = mem_sz; + if (!mrd.len) + continue; + mrd.vbase = (__vaddr_t)mem_base; + mrd.pbase = (__paddr_t)mem_base; + mrd.type = UKPLAT_MEMRT_FREE; + mrd.flags = UKPLAT_MEMRF_READ | UKPLAT_MEMRF_WRITE; + rc = ukplat_memregion_list_insert(&bi->mrds, &mrd); + + if (unlikely(rc < 0)) + ukplat_bootinfo_crash( + "Could not add free memory descriptor"); + + continue; + + } + + /* + * Check that we are not placed at the top of + * the memory region + */ + mrd.len = __BASE_ADDR - mem_base; + if (!mrd.len) + goto end_mrd; + + mrd.vbase = (__vaddr_t)mem_base; + mrd.pbase = (__paddr_t)mem_base; + mrd.type = UKPLAT_MEMRT_FREE; + mrd.flags = UKPLAT_MEMRF_READ | UKPLAT_MEMRF_WRITE; + + rc = ukplat_memregion_list_insert(&bi->mrds, &mrd); + if (unlikely(rc < 0)) + ukplat_bootinfo_crash( + "Could not add free memory descriptor"); end_mrd: - /* Check that we are not placed at the end of the memory region */ - mrd.len = mem_base + mem_sz - __END; - if (!mrd.len) - return; - - mrd.vbase = (__vaddr_t)__END; - mrd.pbase = (__paddr_t)__END; - mrd.type = UKPLAT_MEMRT_FREE; - mrd.flags = UKPLAT_MEMRF_READ | UKPLAT_MEMRF_WRITE; - - rc = ukplat_memregion_list_insert(&bi->mrds, &mrd); - if (unlikely(rc < 0)) - ukplat_bootinfo_crash("Could not add free memory descriptor"); + /* + * Check that we are not placed at the end of + * the memory region + */ + mrd.len = mem_base + mem_sz - __END; + if (!mrd.len) + return; + + mrd.vbase = (__vaddr_t)__END; + mrd.pbase = (__paddr_t)__END; + mrd.type = UKPLAT_MEMRT_FREE; + mrd.flags = UKPLAT_MEMRF_READ | UKPLAT_MEMRF_WRITE; + + rc = ukplat_memregion_list_insert(&bi->mrds, &mrd); + if (unlikely(rc < 0)) + ukplat_bootinfo_crash( + "Could not add free memory descriptor"); + } } static void fdt_bootinfo_cmdl_mrd(struct ukplat_bootinfo *bi, void *fdtp) diff --git a/plat/common/include/uk/plat/common/_time.h b/plat/common/include/uk/plat/common/_time.h index 31a2c9a90cb266d032020a7d6feeb325c0dbb6c4..71cfb6a9e515638f7899e0ab50ca91818286821e 100644 --- a/plat/common/include/uk/plat/common/_time.h +++ b/plat/common/include/uk/plat/common/_time.h @@ -35,6 +35,14 @@ #include +#ifndef CONFIG_HAVE_SYSTICK void time_block_until(__snsec until); +#else +#include +static inline void time_block_until(__snsec until) +{ + tn_systick_block_until(ns_to_ticks(until)); +} +#endif /* CONFIG_HAVE_SYSTICK */ #endif /* __PLAT_CMN_TIME_H__ */ diff --git a/plat/common/lcpu.c b/plat/common/lcpu.c index a2c006916d00f347700671446748242741ce36c0..130b51f9a6d9c9e8128a971c916aef291ba869aa 100644 --- a/plat/common/lcpu.c +++ b/plat/common/lcpu.c @@ -191,8 +191,6 @@ void __noreturn ukplat_lcpu_halt(void) void ukplat_lcpu_halt_irq_until(__nsec until) { - UK_ASSERT(ukplat_lcpu_irqs_disabled()); - time_block_until(until); } diff --git a/plat/drivers/rtc/pl031.c b/plat/drivers/rtc/pl031.c index 805085df5da4893d0a668f0afd14ec026e4927d9..12a1b22344030504273fe46cb6300bfe79abe4ff 100644 --- a/plat/drivers/rtc/pl031.c +++ b/plat/drivers/rtc/pl031.c @@ -181,7 +181,7 @@ int pl031_init_rtc(void *dtb) if (unlikely(rc)) return rc; - uk_intctlr_irq_configure(&irq); + uk_intctlr_irq_set_trigger(&irq); pl031_irq = irq.id; diff --git a/plat/kvm/Config.uk b/plat/kvm/Config.uk index c628487d7de98f9d41c7d1d5cfaa256be0bb6d72..ef8b104baa96f6e3afe687e81a591453483f42dd 100644 --- a/plat/kvm/Config.uk +++ b/plat/kvm/Config.uk @@ -5,6 +5,7 @@ menuconfig PLAT_KVM select LIBUKDEBUG select LIBUKALLOC select LIBUKTIMECONV + select VIRTUALIZE_PLAT select LIBNOLIBC if !HAVE_LIBC select HAVE_FDT if ARCH_ARM_64 imply LIBFDT if ARCH_ARM_64 @@ -14,6 +15,8 @@ menuconfig PLAT_KVM select HAVE_INTCTLR select HAVE_APIC if ARCH_X86_64 select LIBUKINTCTLR_XPIC if ARCH_X86_64 + select ARM_GENERIC_TIMER if ARCH_ARM_64 + select TSC_I8254 if ARCH_X86_64 imply LIBUKBUS_PLATFORM if ARCH_ARM_64 imply LIBVIRTIO_9P if LIBUK9P imply LIBVIRTIO_NET if LIBUKNETDEV diff --git a/plat/kvm/Makefile.uk b/plat/kvm/Makefile.uk index 64b1bfa9126cdd317595bf0e1abfdeb5f61ff9c7..be062819168cfffa2bd2193973daec0f0fef2497 100644 --- a/plat/kvm/Makefile.uk +++ b/plat/kvm/Makefile.uk @@ -64,8 +64,10 @@ LIBKVMPLAT_SRCS-$(CONFIG_ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/setup.c LIBKVMPLAT_SRCS-$(CONFIG_ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/console.c LIBKVMPLAT_SRCS-$(CONFIG_ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/lcpu.c LIBKVMPLAT_SRCS-$(CONFIG_ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/lcpu_start.S +ifneq ($(CONFIG_HAVE_SYSTICK),y) LIBKVMPLAT_SRCS-$(CONFIG_ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/tscclock.c LIBKVMPLAT_SRCS-$(CONFIG_ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/time.c +endif ifeq ($(findstring y,$(CONFIG_KVM_KERNEL_VGA_CONSOLE) $(CONFIG_KVM_DEBUG_VGA_CONSOLE)),y) LIBKVMPLAT_SRCS-$(CONFIG_ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/vga_console.c endif @@ -89,8 +91,10 @@ LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/cpu_native.c LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/cache64.S|common LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/smccc.c|common LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/smccc_invoke.S|common +ifneq ($(CONFIG_HAVE_SYSTICK),y) LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/time.c|common LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/generic_timer.c|common +endif LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/lcpu.c|arm64_common LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/traps_arm64.c|isr LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/tls.c|common diff --git a/plat/kvm/x86/tscclock.c b/plat/kvm/x86/tscclock.c index 53bccb5e3b85cfbb7306d5230ac35f61d52c5555..491850a49dd79a93e6dc2e20fcf389ba24cb2293 100644 --- a/plat/kvm/x86/tscclock.c +++ b/plat/kvm/x86/tscclock.c @@ -382,14 +382,9 @@ static void tscclock_cpu_block(__u64 until) ukplat_lcpu_halt_irq(); } -unsigned long sched_have_pending_events; - void time_block_until(__snsec until) { while ((__snsec) ukplat_monotonic_clock() < until) { tscclock_cpu_block(until); - - if (__uk_test_and_clear_bit(0, &sched_have_pending_events)) - break; } }