From d4f3de93a23e4bd4f000a3663768d47d094bf188 Mon Sep 17 00:00:00 2001 From: login Date: Sat, 31 Dec 2022 17:26:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E7=94=A8Rust=E9=87=8D=E6=9E=84CFS?= =?UTF-8?q?=E8=B0=83=E5=BA=A6=E5=99=A8=20(#131)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 新建调度器的文件 * 把softirq vector移动到c文件中(原来在.h) * 将进程切换方式改为“中断返回时切换” * new:使用rust重构CFS * 删除已经在smp中废弃的HPET中断转发函数 * 代码格式化 * 删除多余的dunce依赖 --- Makefile | 1 + kernel/Cargo.toml | 2 +- kernel/build.rs | 5 +- kernel/cbindgen.toml | 626 ------------------------ kernel/src/arch/x86_64/Makefile | 1 + kernel/src/arch/x86_64/context.rs | 19 + kernel/src/arch/x86_64/mm/barrier.rs | 23 + kernel/src/arch/x86_64/mm/mod.rs | 28 ++ kernel/src/arch/x86_64/mod.rs | 5 +- kernel/src/arch/x86_64/sched.rs | 10 + kernel/src/driver/disk/ahci/ahci.c | 3 +- kernel/src/driver/interrupt/apic/apic.c | 3 +- kernel/src/driver/video/video.c | 3 +- kernel/src/exception/entry.S | 43 +- kernel/src/exception/softirq.c | 1 + kernel/src/exception/softirq.h | 13 +- kernel/src/exception/trap.c | 1 + kernel/src/libs/mutex.c | 3 +- kernel/src/libs/semaphore.c | 1 + kernel/src/libs/spinlock.rs | 3 +- kernel/src/main.c | 2 +- kernel/src/mm/mod.rs | 2 +- kernel/src/process/kthread.c | 10 +- kernel/src/process/proc-types.h | 2 + kernel/src/process/process.h | 3 +- kernel/src/process/process.rs | 7 +- kernel/src/process/ptrace.h | 10 +- kernel/src/sched/cfs.c | 163 ------ kernel/src/sched/cfs.rs | 201 ++++++++ kernel/src/sched/core.c | 14 + kernel/src/sched/core.rs | 82 +++- kernel/src/sched/mod.rs | 3 +- kernel/src/sched/sched.c | 95 ---- kernel/src/sched/sched.h | 91 ++-- kernel/src/smp/smp.c | 10 - kernel/src/syscall/syscall.c | 1 - kernel/src/syscall/syscall.h | 1 - 37 files changed, 464 insertions(+), 1027 deletions(-) delete mode 100644 kernel/cbindgen.toml create mode 100644 kernel/src/arch/x86_64/context.rs create mode 100644 kernel/src/arch/x86_64/mm/barrier.rs create mode 100644 kernel/src/arch/x86_64/mm/mod.rs create mode 100644 kernel/src/arch/x86_64/sched.rs delete mode 100644 kernel/src/sched/cfs.c create mode 100644 kernel/src/sched/cfs.rs create mode 100644 kernel/src/sched/core.c delete mode 100644 kernel/src/sched/sched.c diff --git a/Makefile b/Makefile index d7f425a2..2cb010d0 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,7 @@ export CC=$(DragonOS_GCC)/x86_64-elf-gcc export LD=ld export AS=$(DragonOS_GCC)/x86_64-elf-as export NM=$(DragonOS_GCC)/x86_64-elf-nm +export AR=$(DragonOS_GCC)/x86_64-elf-ar export OBJCOPY=$(DragonOS_GCC)/x86_64-elf-objcopy diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index bb0ae067..acd294d8 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -15,5 +15,5 @@ x86_64 = "0.14.10" # 构建时依赖项 [build-dependencies] bindgen = "0.61.0" -cbindgen = "0.24.3" + diff --git a/kernel/build.rs b/kernel/build.rs index bc41e28e..4587d988 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -1,7 +1,4 @@ extern crate bindgen; - -extern crate cbindgen; - // use ::std::env; use std::path::PathBuf; @@ -21,7 +18,7 @@ fn main() { let bindings = bindgen::Builder::default() .clang_arg("-I./src") .clang_arg("-I./src/include") - .clang_arg("-I./src/arch/x86_64/include") // todo: 当引入多种架构之后,需要修改这里,对于不同的架构编译时,include不同的路径 + .clang_arg("-I./src/arch/x86_64/include") // todo: 当引入多种架构之后,需要修改这里,对于不同的架构编译时,include不同的路径 // The input header we would like to generate // bindings for. .header("src/include/bindings/wrapper.h") diff --git a/kernel/cbindgen.toml b/kernel/cbindgen.toml deleted file mode 100644 index 4980771d..00000000 --- a/kernel/cbindgen.toml +++ /dev/null @@ -1,626 +0,0 @@ -# The language to output bindings in -# -# possible values: "C", "C++", "Cython" -# -# default: "C++" -language = "C" - - - - -# Options for wrapping the contents of the header: - -# 在文件头部添加的注释信息 -# An optional string of text to output at the beginning of the generated file -# default: doesn't emit anything -header = "/* DragonOS's C FFI for rust. This file is licensed under GPLv2 */" - -# 在文件尾部添加的信息 -# An optional string of text to output at the end of the generated file -# default: doesn't emit anything -# trailer = "/* Text to put at the end of the generated file */" - -# An optional name to use as an include guard -# default: doesn't emit an include guard -# include_guard = "mozilla_wr_bindings_h" - -# 是否生成一个 `#pragma once` -pragma_once = true - -# An optional string of text to output between major sections of the generated -# file as a warning against manual editing -# -# default: doesn't emit anything -autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" - -# Whether to include a comment with the version of cbindgen used to generate the file -# default: false -# include_version = true - -# An optional namespace to output around the generated bindings -# default: doesn't emit a namespace -namespace = "ffi" - -# An optional list of namespaces to output around the generated bindings -# default: [] -# namespaces = ["mozilla", "wr"] - -# An optional list of namespaces to declare as using with "using namespace" -# default: [] -# using_namespaces = ["mozilla", "wr"] - -# A list of sys headers to #include (with angle brackets) -# default: [] -sys_includes = ["stdint.h"] - -# 生成的binding文件要include的头文件 -# A list of headers to #include (with quotes) -# default: [] -includes = [] - -# Whether cbindgen's default C/C++ standard imports should be suppressed. These -# imports are included by default because our generated headers tend to require -# them (e.g. for uint32_t). Currently, the generated imports are: -# -# * for C: , , , , -# -# * for C++: , , , , (depending on config) -# -# default: false -no_includes = true - -# Whether to make a C header C++ compatible. -# These will wrap generated functions into a `extern "C"` block, e.g. -# -# #ifdef __cplusplus -# extern "C" { -# #endif // __cplusplus -# -# // Generated functions. -# -# #ifdef __cplusplus -# } // extern "C" -# #endif // __cplusplus -# -# If the language is not C this option won't have any effect. -# -# default: false -cpp_compat = false - -# A list of lines to add verbatim after the includes block -#after_includes = "#define VERSION 1" - - - -# Code Style Options - -# The style to use for curly braces -# -# possible values: "SameLine", "NextLine" -# -# default: "SameLine" -braces = "NextLine" - -# The desired length of a line to use when formatting lines -# default: 100 -line_length = 120 - -# The amount of spaces to indent by -# default: 2 -tab_width = 4 - -# Include doc comments from Rust as documentation -documentation = true - -# How the generated documentation should be commented. -# -# possible values: -# * "c": /* like this */ -# * "c99": // like this -# * "c++": /// like this -# * "doxy": like C, but with leading *'s on each line -# * "auto": "c++" if that's the language, "doxy" otherwise -# -# default: "auto" -documentation_style = "doxy" - -# How much of the documentation for each item is output. -# -# possible values: -# * "short": Only the first line. -# * "full": The full documentation. -# -# default: "full" -documentation_length = "short" - - - - -# Codegen Options - -# When generating a C header, the kind of declaration style to use for structs -# or enums. -# -# possible values: -# * "type": typedef struct { ... } MyType; -# * "tag": struct MyType { ... }; -# * "both": typedef struct MyType { ... } MyType; -# -# default: "both" -style = "both" - -# If this option is true `usize` and `isize` will be converted into `size_t` and `ptrdiff_t` -# instead of `uintptr_t` and `intptr_t` respectively. -usize_is_size_t = true - -# A list of substitutions for converting cfg's to ifdefs. cfgs which aren't -# defined here will just be discarded. -# -# e.g. -# `#[cfg(target = "freebsd")] ...` -# becomes -# `#if defined(DEFINE_FREEBSD) ... #endif` -[defines] -"target_os = freebsd" = "DEFINE_FREEBSD" -"feature = serde" = "DEFINE_SERDE" - - - - - -[export] -# A list of additional items to always include in the generated bindings if they're -# found but otherwise don't appear to be used by the public API. -# -# default: [] -include = ["MyOrphanStruct", "MyGreatTypeRename"] - -# A list of items to not include in the generated bindings -# default: [] -exclude = ["Bad"] - -# 生成的内容的前缀 -# A prefix to add before the name of every item -# default: no prefix is added -# prefix = "CAPI_" - -# Types of items that we'll generate. If empty, then all types of item are emitted. -# -# possible items: (TODO: explain these in detail) -# * "constants": -# * "globals": -# * "enums": -# * "structs": -# * "unions": -# * "typedefs": -# * "opaque": -# * "functions": -# -# default: [] -item_types = ["enums", "structs", "opaque", "functions"] - -# Whether applying rules in export.rename prevents export.prefix from applying. -# -# e.g. given this toml: -# -# [export] -# prefix = "capi_" -# [export.rename] -# "MyType" = "my_cool_type" -# -# You get the following results: -# -# renaming_overrides_prefixing = true: -# "MyType" => "my_cool_type" -# -# renaming_overrides_prefixing = false: -# "MyType => capi_my_cool_type" -# -# default: false -renaming_overrides_prefixing = true - -# Table of name conversions to apply to item names (lhs becomes rhs) -[export.rename] -"MyType" = "my_cool_type" -"my_function" = "BetterFunctionName" - -# Table of things to prepend to the body of any struct, union, or enum that has the -# given name. This can be used to add things like methods which don't change ABI, -# mark fields private, etc -[export.pre_body] -"MyType" = """ - MyType() = delete; -private: -""" - -# Table of things to append to the body of any struct, union, or enum that has the -# given name. This can be used to add things like methods which don't change ABI. -[export.body] -"MyType" = """ - void cppMethod() const; -""" - -# Configuration for name mangling -[export.mangle] -# Whether the types should be renamed during mangling, for example -# c_char -> CChar, etc. -rename_types = "PascalCase" -# Whether the underscores from the mangled name should be omitted. -remove_underscores = false - -[layout] -# A string that should come before the name of any type which has been marked -# as `#[repr(packed)]`. For instance, "__attribute__((packed))" would be a -# reasonable value if targeting gcc/clang. A more portable solution would -# involve emitting the name of a macro which you define in a platform-specific -# way. e.g. "PACKED" -# -# default: `#[repr(packed)]` types will be treated as opaque, since it would -# be unsafe for C callers to use a incorrectly laid-out union. -packed = "PACKED" - -# A string that should come before the name of any type which has been marked -# as `#[repr(align(n))]`. This string must be a function-like macro which takes -# a single argument (the requested alignment, `n`). For instance, a macro -# `#define`d as `ALIGNED(n)` in `header` which translates to -# `__attribute__((aligned(n)))` would be a reasonable value if targeting -# gcc/clang. -# -# default: `#[repr(align(n))]` types will be treated as opaque, since it -# could be unsafe for C callers to use a incorrectly-aligned union. -aligned_n = "ALIGNED" - - -[fn] -# 函数开头要加入的内容 -# An optional prefix to put before every function declaration -# default: no prefix added -# prefix = "WR_START_FUNC" - -# 函数声明的结尾要加入的内容 -# An optional postfix to put after any function declaration -# default: no postix added -# postfix = "WR_END_FUNC" - -# How to format function arguments -# -# possible values: -# * "horizontal": place all arguments on the same line -# * "vertical": place each argument on its own line -# * "auto": only use vertical if horizontal would exceed line_length -# -# default: "auto" -args = "horizontal" - -# An optional string that should prefix function declarations which have been -# marked as `#[must_use]`. For instance, "__attribute__((warn_unused_result))" -# would be a reasonable value if targeting gcc/clang. A more portable solution -# would involve emitting the name of a macro which you define in a -# platform-specific way. e.g. "MUST_USE_FUNC" -# default: nothing is emitted for must_use functions -must_use = "MUST_USE_FUNC" - -# An optional string that will be used in the attribute position for functions -# that don't return (that return `!` in Rust). -# -# For instance, `__attribute__((noreturn))` would be a reasonable value if -# targeting gcc/clang. -no_return = "NO_RETURN" - -# An optional string that, if present, will be used to generate Swift function -# and method signatures for generated functions, for example "CF_SWIFT_NAME". -# If no such macro is available in your toolchain, you can define one using the -# `header` option in cbindgen.toml -# default: no swift_name function attributes are generated -# swift_name_macro = "CF_SWIFT_NAME" - -# A rule to use to rename function argument names. The renaming assumes the input -# is the Rust standard snake_case, however it accepts all the different rename_args -# inputs. This means many options here are no-ops or redundant. -# -# possible values (that actually do something): -# * "CamelCase": my_arg => myArg -# * "PascalCase": my_arg => MyArg -# * "GeckoCase": my_arg => aMyArg -# * "ScreamingSnakeCase": my_arg => MY_ARG -# * "None": apply no renaming -# -# technically possible values (that shouldn't have a purpose here): -# * "SnakeCase": apply no renaming -# * "LowerCase": apply no renaming (actually applies to_lowercase, is this bug?) -# * "UpperCase": same as ScreamingSnakeCase in this context -# * "QualifiedScreamingSnakeCase" => same as ScreamingSnakeCase in this context -# -# default: "None" -rename_args = "PascalCase" - -# This rule specifies the order in which functions will be sorted. -# -# "Name": sort by the name of the function -# "None": keep order in which the functions have been parsed -# -# default: "None" -sort_by = "Name" - -[struct] -# A rule to use to rename struct field names. The renaming assumes the input is -# the Rust standard snake_case, however it acccepts all the different rename_args -# inputs. This means many options here are no-ops or redundant. -# -# possible values (that actually do something): -# * "CamelCase": my_arg => myArg -# * "PascalCase": my_arg => MyArg -# * "GeckoCase": my_arg => mMyArg -# * "ScreamingSnakeCase": my_arg => MY_ARG -# * "None": apply no renaming -# -# technically possible values (that shouldn't have a purpose here): -# * "SnakeCase": apply no renaming -# * "LowerCase": apply no renaming (actually applies to_lowercase, is this bug?) -# * "UpperCase": same as ScreamingSnakeCase in this context -# * "QualifiedScreamingSnakeCase" => same as ScreamingSnakeCase in this context -# -# default: "None" -rename_fields = "PascalCase" - -# An optional string that should come before the name of any struct which has been -# marked as `#[must_use]`. For instance, "__attribute__((warn_unused))" -# would be a reasonable value if targeting gcc/clang. A more portable solution -# would involve emitting the name of a macro which you define in a -# platform-specific way. e.g. "MUST_USE_STRUCT" -# -# default: nothing is emitted for must_use structs -must_use = "MUST_USE_STRUCT" - -# Whether a Rust type with associated consts should emit those consts inside the -# type's body. Otherwise they will be emitted trailing and with the type's name -# prefixed. This does nothing if the target is C, or if -# [const]allow_static_const = false -# -# default: false -# associated_constants_in_body: false - -# Whether to derive a simple constructor that takes a value for every field. -# default: false -derive_constructor = true - -# Whether to derive an operator== for all structs -# default: false -derive_eq = false - -# Whether to derive an operator!= for all structs -# default: false -derive_neq = false - -# Whether to derive an operator< for all structs -# default: false -derive_lt = false - -# Whether to derive an operator<= for all structs -# default: false -derive_lte = false - -# Whether to derive an operator> for all structs -# default: false -derive_gt = false - -# Whether to derive an operator>= for all structs -# default: false -derive_gte = false - - - - - -[enum] -# A rule to use to rename enum variants, and the names of any fields those -# variants have. This should probably be split up into two separate options, but -# for now, they're the same! See the documentation for `[struct]rename_fields` -# for how this applies to fields. Renaming of the variant assumes that the input -# is the Rust standard PascalCase. In the case of QualifiedScreamingSnakeCase, -# it also assumed that the enum's name is PascalCase. -# -# possible values (that actually do something): -# * "CamelCase": MyVariant => myVariant -# * "SnakeCase": MyVariant => my_variant -# * "ScreamingSnakeCase": MyVariant => MY_VARIANT -# * "QualifiedScreamingSnakeCase": MyVariant => ENUM_NAME_MY_VARIANT -# * "LowerCase": MyVariant => myvariant -# * "UpperCase": MyVariant => MYVARIANT -# * "None": apply no renaming -# -# technically possible values (that shouldn't have a purpose for the variants): -# * "PascalCase": apply no renaming -# * "GeckoCase": apply no renaming -# -# default: "None" -rename_variants = "None" - -# Whether an extra "sentinel" enum variant should be added to all generated enums. -# Firefox uses this for their IPC serialization library. -# -# WARNING: if the sentinel is ever passed into Rust, behaviour will be Undefined. -# Rust does not know about this value, and will assume it cannot happen. -# -# default: false -add_sentinel = false - -# Whether enum variant names should be prefixed with the name of the enum. -# default: false -prefix_with_name = false - -# Whether to emit enums using "enum class" when targeting C++. -# default: true -enum_class = true - -# Whether to generate static `::MyVariant(..)` constructors and `bool IsMyVariant()` -# methods for enums with fields. -# -# default: false -derive_helper_methods = false - -# Whether to generate `const MyVariant& AsMyVariant() const` methods for enums with fields. -# default: false -derive_const_casts = false - -# Whether to generate `MyVariant& AsMyVariant()` methods for enums with fields -# default: false -derive_mut_casts = false - -# The name of the macro/function to use for asserting `IsMyVariant()` in the body of -# derived `AsMyVariant()` cast methods. -# -# default: "assert" (but also causes `` to be included by default) -cast_assert_name = "MOZ_RELEASE_ASSERT" - -# An optional string that should come before the name of any enum which has been -# marked as `#[must_use]`. For instance, "__attribute__((warn_unused))" -# would be a reasonable value if targeting gcc/clang. A more portable solution -# would involve emitting the name of a macro which you define in a -# platform-specific way. e.g. "MUST_USE_ENUM" -# -# Note that this refers to the *output* type. That means this will not apply to an enum -# with fields, as it will be emitted as a struct. `[struct]must_use` will apply there. -# -# default: nothing is emitted for must_use enums -must_use = "MUST_USE_ENUM" - -# Whether enums with fields should generate destructors. This exists so that generic -# enums can be properly instantiated with payloads that are C++ types with -# destructors. This isn't necessary for structs because C++ has rules to -# automatically derive the correct constructors and destructors for those types. -# -# Care should be taken with this option, as Rust and C++ cannot -# properly interoperate with eachother's notions of destructors. Also, this may -# change the ABI for the type. Either your destructor-full enums must live -# exclusively within C++, or they must only be passed by-reference between -# C++ and Rust. -# -# default: false -derive_tagged_enum_destructor = false - -# Whether enums with fields should generate copy-constructor. See the discussion on -# derive_tagged_enum_destructor for why this is both useful and very dangerous. -# -# default: false -derive_tagged_enum_copy_constructor = false -# Whether enums with fields should generate copy-assignment operators. -# -# This depends on also deriving copy-constructors, and it is highly encouraged -# for this to be set to true. -# -# default: false -derive_tagged_enum_copy_assignment = false - -# Whether enums with fields should generate an empty, private destructor. -# This allows the auto-generated constructor functions to compile, if there are -# non-trivially constructible members. This falls in the same family of -# dangerousness as `derive_tagged_enum_copy_constructor` and co. -# -# default: false -private_default_tagged_enum_constructor = false - - - - - -[const] -# Whether a generated constant can be a static const in C++ mode. I have no -# idea why you would turn this off. -# -# default: true -allow_static_const = true - -# Whether a generated constant can be constexpr in C++ mode. -# -# default: true -allow_constexpr = false - -# This rule specifies the order in which constants will be sorted. -# -# "Name": sort by the name of the constant -# "None": keep order in which the constants have been parsed -# -# default: "None" -sort_by = "Name" - - - - -[macro_expansion] -# Whether bindings should be generated for instances of the bitflags! macro. -# default: false -bitflags = true - - - - - - -# Options for how your Rust library should be parsed - -[parse] -# Whether to parse dependent crates and include their types in the output -# default: false -parse_deps = true - -# A white list of crate names that are allowed to be parsed. If this is defined, -# only crates found in this list will ever be parsed. -# -# default: there is no whitelist (NOTE: this is the opposite of []) -include = ["webrender", "webrender_traits"] - -# A black list of crate names that are not allowed to be parsed. -# default: [] -exclude = ["libc"] - -# Whether to use a new temporary target directory when running `rustc -Zunpretty=expanded`. -# This may be required for some build processes. -# -# default: false -clean = false - -# Which crates other than the top-level binding crate we should generate -# bindings for. -# -# default: [] -# extra_bindings = ["my_awesome_dep"] - -[parse.expand] -# A list of crate names that should be run through `cargo expand` before -# parsing to expand any macros. Note that if a crate is named here, it -# will always be parsed, even if the blacklist/whitelist says it shouldn't be. -# -# default: [] -crates = ["euclid"] - -# If enabled, use the `--all-features` option when expanding. Ignored when -# `features` is set. For backwards-compatibility, this is forced on if -# `expand = ["euclid"]` shorthand is used. -# -# default: false -all_features = false - -# When `all_features` is disabled and this is also disabled, use the -# `--no-default-features` option when expanding. -# -# default: true -default_features = true - -# A list of feature names that should be used when running `cargo expand`. This -# combines with `default_features` like in your `Cargo.toml`. Note that the features -# listed here are features for the current crate being built, *not* the crates -# being expanded. The crate's `Cargo.toml` must take care of enabling the -# appropriate features in its dependencies -# -# default: [] -# features = ["cbindgen"] - -[ptr] -# An optional string to decorate all pointers that are -# required to be non null. Nullability is inferred from the Rust type: `&T`, -# `&mut T` and `NonNull` all require a valid pointer value. -non_null_attribute = "_Nonnull" - -# Options specific to Cython bindings. - diff --git a/kernel/src/arch/x86_64/Makefile b/kernel/src/arch/x86_64/Makefile index 60215816..9e6ce066 100644 --- a/kernel/src/arch/x86_64/Makefile +++ b/kernel/src/arch/x86_64/Makefile @@ -18,5 +18,6 @@ $(kernel_arch_x86_64_subdirs): ECHO all: $(kernel_arch_x86_64_objs) $(kernel_arch_x86_64_subdirs) + clean: echo "Done." \ No newline at end of file diff --git a/kernel/src/arch/x86_64/context.rs b/kernel/src/arch/x86_64/context.rs new file mode 100644 index 00000000..60444a28 --- /dev/null +++ b/kernel/src/arch/x86_64/context.rs @@ -0,0 +1,19 @@ +use crate::include::bindings::bindings::{process_control_block, switch_proc}; + +use core::sync::atomic::compiler_fence; + +/// @brief 切换进程的上下文(没有切换页表的动作) +/// +/// @param next 下一个进程的pcb +/// @param trap_frame 中断上下文的栈帧 +#[inline(always)] +pub fn switch_process( + prev: &'static mut process_control_block, + next: &'static mut process_control_block, +) { + compiler_fence(core::sync::atomic::Ordering::SeqCst); + unsafe { + switch_proc(prev, next); + } + compiler_fence(core::sync::atomic::Ordering::SeqCst); +} diff --git a/kernel/src/arch/x86_64/mm/barrier.rs b/kernel/src/arch/x86_64/mm/barrier.rs new file mode 100644 index 00000000..bd211435 --- /dev/null +++ b/kernel/src/arch/x86_64/mm/barrier.rs @@ -0,0 +1,23 @@ +#![allow(dead_code)] +use core::arch::asm; + +#[inline(always)] +pub fn mfence(){ + unsafe{ + asm!("mfence"); + } +} + +#[inline(always)] +pub fn lfence(){ + unsafe{ + asm!("lfence"); + } +} + +#[inline(always)] +pub fn sfence(){ + unsafe{ + asm!("sfence"); + } +} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/mm/mod.rs b/kernel/src/arch/x86_64/mm/mod.rs new file mode 100644 index 00000000..ee97f2e3 --- /dev/null +++ b/kernel/src/arch/x86_64/mm/mod.rs @@ -0,0 +1,28 @@ +pub mod barrier; +use crate::include::bindings::bindings::process_control_block; + +use core::arch::asm; +use core::ptr::read_volatile; + +use self::barrier::mfence; + +/// @brief 切换进程的页表 +/// +/// @param 下一个进程的pcb。将会把它的页表切换进来。 +/// +/// @return 下一个进程的pcb(把它return的目的主要是为了归还所有权) +#[inline(always)] +#[allow(dead_code)] +pub fn switch_mm( + next_pcb: &'static mut process_control_block, +) -> &'static mut process_control_block { + mfence(); + // kdebug!("to get pml4t"); + let pml4t = unsafe { read_volatile(&next_pcb.mm.as_ref().unwrap().pgd) }; + + unsafe { + asm!("mov cr3, {}", in(reg) pml4t); + } + mfence(); + return next_pcb; +} diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index cfb7aaf5..3c028dd8 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -1,4 +1,7 @@ #[macro_use] pub mod asm; pub mod cpu; -pub mod interrupt; \ No newline at end of file +pub mod interrupt; +pub mod mm; +pub mod context; +pub mod sched; \ No newline at end of file diff --git a/kernel/src/arch/x86_64/sched.rs b/kernel/src/arch/x86_64/sched.rs new file mode 100644 index 00000000..e723f571 --- /dev/null +++ b/kernel/src/arch/x86_64/sched.rs @@ -0,0 +1,10 @@ +use crate::include::bindings::bindings::{enter_syscall_int, SYS_SCHED}; + +/// @brief 若内核代码不处在中断上下文中,那么将可以使用本函数,发起一个sys_sched系统调用,然后运行调度器。 +/// 由于只能在中断上下文中进行进程切换,因此需要发起一个系统调用SYS_SCHED。 +#[no_mangle] +pub extern "C" fn sched() { + unsafe { + enter_syscall_int(SYS_SCHED.into(), 0, 0, 0, 0, 0, 0, 0, 0); + } +} diff --git a/kernel/src/driver/disk/ahci/ahci.c b/kernel/src/driver/disk/ahci/ahci.c index 172af9b0..e3e1e0fd 100644 --- a/kernel/src/driver/disk/ahci/ahci.c +++ b/kernel/src/driver/disk/ahci/ahci.c @@ -403,7 +403,7 @@ static bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t port->ci = 1 << slot; // Issue command current_pcb->flags |= PF_NEED_SCHED; - sched(); + int retval = AHCI_SUCCESS; // Wait for completion while (1) @@ -483,7 +483,6 @@ static bool ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_ port->ci = 1; // Issue command current_pcb->flags |= PF_NEED_SCHED; - sched(); int retval = AHCI_SUCCESS; while (1) diff --git a/kernel/src/driver/interrupt/apic/apic.c b/kernel/src/driver/interrupt/apic/apic.c index 63c5cd61..78c493e3 100644 --- a/kernel/src/driver/interrupt/apic/apic.c +++ b/kernel/src/driver/interrupt/apic/apic.c @@ -1,4 +1,5 @@ #include "apic.h" +#include "apic_timer.h" #include #include #include @@ -458,7 +459,7 @@ void do_IRQ(struct pt_regs *rsp, ul number) kBUG("current_pcb->preempt_count<0! pid=%d", current_pcb->pid); // should not be here // 检测当前进程是否可被调度 - if (current_pcb->flags & PF_NEED_SCHED) + if (current_pcb->flags & PF_NEED_SCHED && number == APIC_TIMER_IRQ_NUM) { io_mfence(); sched(); diff --git a/kernel/src/driver/video/video.c b/kernel/src/driver/video/video.c index 626f569b..0756203a 100644 --- a/kernel/src/driver/video/video.c +++ b/kernel/src/driver/video/video.c @@ -70,7 +70,8 @@ int video_refresh_daemon(void *unused) } video_refresh_expire_jiffies = cal_next_n_ms_jiffies(REFRESH_INTERVAL << 1); } - video_daemon_pcb->flags &= ~PROC_RUNNING; + video_daemon_pcb->state &= ~PROC_RUNNING; + video_daemon_pcb->flags |= PF_NEED_SCHED; sched(); } diff --git a/kernel/src/exception/entry.S b/kernel/src/exception/entry.S index 999da529..ee1c7e4f 100644 --- a/kernel/src/exception/entry.S +++ b/kernel/src/exception/entry.S @@ -21,6 +21,7 @@ ES = 0x78 RAX = 0x80 FUNC = 0x88 ERRCODE = 0x90 +// 以下几个字段,在中断产生时,由处理器压入栈内 RIP = 0x98 CS = 0xa0 RFLAGS = 0xa8 @@ -111,51 +112,11 @@ Err_Code: callq *%rdx //调用服务程序 带*号表示调用的是绝对地址 jmp ret_from_exception -// 系统调用入口 -// 保存寄存器 -ENTRY(system_call) - - // 由于sysenter指令会禁用中断,因此要在这里手动开启中断 - subq $0x38, %rsp - - cld; - - pushq %rax - movq %es, %rax - pushq %rax - movq %ds, %rax - pushq %rax - pushq %rbp - pushq %rdi - pushq %rsi - pushq %rdx - pushq %rcx - pushq %rbx - pushq %r8 - pushq %r9 - pushq %r10 - pushq %r11 - pushq %r12 - pushq %r13 - pushq %r14 - pushq %r15 - - movq $0x10, %rdx - movq %rdx, %ds - movq %rdx, %es - // 将rsp作为参数传递给system_call_function - movq %rsp, %rdi - - - callq system_call_function - // 从系统调用中返回 ENTRY(ret_from_system_call) jmp Restore_all - - // 0 #DE 除法错误 ENTRY(divide_error) @@ -323,7 +284,7 @@ ENTRY(virtualization_exception) - +// 系统调用入口 // 0x80 系统调用门 ENTRY(syscall_int) pushq $0 diff --git a/kernel/src/exception/softirq.c b/kernel/src/exception/softirq.c index dc141a8e..81a0938c 100644 --- a/kernel/src/exception/softirq.c +++ b/kernel/src/exception/softirq.c @@ -4,6 +4,7 @@ #include #include +static struct softirq_t softirq_vector[MAX_SOFTIRQ_NUM] = {0}; static spinlock_t softirq_modify_lock; // 软中断状态(status) static volatile uint64_t softirq_pending = 0; static volatile uint64_t softirq_running = 0; diff --git a/kernel/src/exception/softirq.h b/kernel/src/exception/softirq.h index 816d81e9..a003f852 100644 --- a/kernel/src/exception/softirq.h +++ b/kernel/src/exception/softirq.h @@ -21,23 +21,18 @@ * @brief 发起软中断 * */ -#define raise_softirq(sirq_num) \ - do \ - { \ - set_softirq_pending(1 << sirq_num); \ +#define raise_softirq(sirq_num) \ + do \ + { \ + set_softirq_pending(1 << sirq_num); \ } while (0); - - - struct softirq_t { void (*action)(void *data); // 软中断处理函数 void *data; }; -struct softirq_t softirq_vector[MAX_SOFTIRQ_NUM] = {0}; - /** * @brief 软中断注册函数 * diff --git a/kernel/src/exception/trap.c b/kernel/src/exception/trap.c index 45e31ead..08e86daa 100644 --- a/kernel/src/exception/trap.c +++ b/kernel/src/exception/trap.c @@ -176,6 +176,7 @@ void do_stack_segment_fault(struct pt_regs *regs, unsigned long error_code) kerror("do_stack_segment_fault(12),\tError Code:%#18lx,\tRSP:%#18lx,\tRIP:%#18lx\t CPU:%d\n", error_code, regs->rsp, regs->rip, proc_current_cpu_id); + // kinfo("cs=%#04x, ds=%#04x, ss=%#04x", regs->cs, regs->ds, regs->ss); traceback(regs); current_pcb->state = PROC_STOPPED; sched(); diff --git a/kernel/src/libs/mutex.c b/kernel/src/libs/mutex.c index a67e4695..88acf81a 100644 --- a/kernel/src/libs/mutex.c +++ b/kernel/src/libs/mutex.c @@ -17,6 +17,7 @@ void mutex_init(mutex_t *lock) static void __mutex_sleep() { current_pcb->state = PROC_UNINTERRUPTIBLE; + current_pcb->flags |= PF_NEED_SCHED; sched(); } @@ -71,7 +72,7 @@ void mutex_unlock(mutex_t *lock) { if (unlikely(!mutex_is_locked(lock))) return; - + spin_lock(&lock->wait_lock); struct mutex_waiter_t *wt = NULL; if (mutex_is_locked(lock)) diff --git a/kernel/src/libs/semaphore.c b/kernel/src/libs/semaphore.c index 88e5a0b0..62863920 100644 --- a/kernel/src/libs/semaphore.c +++ b/kernel/src/libs/semaphore.c @@ -18,6 +18,7 @@ void semaphore_down(semaphore_t *sema) list_append(&sema->wait_queue.wait_list, &wait.wait_list); // 执行调度 + current_pcb->flags |= PF_NEED_SCHED; sched(); } } diff --git a/kernel/src/libs/spinlock.rs b/kernel/src/libs/spinlock.rs index a0ee8757..71c51122 100644 --- a/kernel/src/libs/spinlock.rs +++ b/kernel/src/libs/spinlock.rs @@ -57,11 +57,12 @@ pub fn spin_unlock_irq(lock: *mut spinlock_t) { sti(); } +#[derive(Debug)] pub struct RawSpinlock(AtomicBool); impl RawSpinlock { /// @brief 初始化自旋锁 - const INIT: RawSpinlock = RawSpinlock(AtomicBool::new(false)); + pub const INIT: RawSpinlock = RawSpinlock(AtomicBool::new(false)); /// @brief 加锁 pub fn lock(&mut self) { diff --git a/kernel/src/main.c b/kernel/src/main.c index 0ada4ee9..58ccf7ad 100644 --- a/kernel/src/main.c +++ b/kernel/src/main.c @@ -130,7 +130,7 @@ void system_initialize() syscall_init(); io_mfence(); // 再初始化进程模块。顺序不能调转 - sched_init(); + // sched_init(); io_mfence(); timer_init(); diff --git a/kernel/src/mm/mod.rs b/kernel/src/mm/mod.rs index 20f94e7f..70dfdc49 100644 --- a/kernel/src/mm/mod.rs +++ b/kernel/src/mm/mod.rs @@ -1,2 +1,2 @@ pub mod allocator; -pub mod gfp; \ No newline at end of file +pub mod gfp; diff --git a/kernel/src/process/kthread.c b/kernel/src/process/kthread.c index 22361c78..3d3b50d6 100644 --- a/kernel/src/process/kthread.c +++ b/kernel/src/process/kthread.c @@ -90,7 +90,7 @@ static struct process_control_block *__kthread_create_on_node(int (*thread_fn)(v int len = vsnprintf(pcb_name, name_fmt, PCB_NAME_LEN, get_args); if (len >= PCB_NAME_LEN) { - //名字过大 放到full_name字段中 + // 名字过大 放到full_name字段中 struct kthread_info_t *kthread = to_kthread(pcb); char *full_name = kzalloc(1024, 0); vsprintf(full_name, name_fmt, get_args); @@ -173,7 +173,7 @@ static int kthread(void *_create) // 将当前pcb返回给创建者 create->result = current_pcb; - current_pcb->state &= ~PROC_RUNNING; // 设置当前进程不是RUNNING态 + current_pcb->state &= ~PROC_RUNNING; // 设置当前进程不是RUNNING态 io_mfence(); // 发起调度,使得当前内核线程休眠。直到创建者通过process_wakeup将当前内核线程唤醒 @@ -200,6 +200,8 @@ static void __create_kthread(struct kthread_create_info_t *create) } } +#pragma GCC push_options +#pragma GCC optimize("O0") /** * @brief kthread守护线程 * @@ -208,6 +210,7 @@ static void __create_kthread(struct kthread_create_info_t *create) */ int kthreadd(void *unused) { + barrier(); kinfo("kthread daemon started!"); struct process_control_block *pcb = current_pcb; kthreadd_pcb = current_pcb; @@ -237,8 +240,11 @@ int kthreadd(void *unused) } spin_unlock(&__kthread_create_lock); } + barrier(); } +#pragma GCC pop_options + /** * @brief 内核线程调用该函数,检查自身的标志位,判断自己是否应该执行完任务后退出 * diff --git a/kernel/src/process/proc-types.h b/kernel/src/process/proc-types.h index 71b6b384..d6c4ba11 100644 --- a/kernel/src/process/proc-types.h +++ b/kernel/src/process/proc-types.h @@ -3,6 +3,7 @@ #include #include #include +#include "ptrace.h" // 进程最大可拥有的文件描述符数量 #define PROC_MAX_FD_NUM 16 @@ -128,6 +129,7 @@ struct process_control_block sigset_t sig_blocked; // 正在等待的信号的标志位,表示某个信号正在等待处理 struct sigpending sig_pending; + }; // 将进程的pcb和内核栈融合到一起,8字节对齐 diff --git a/kernel/src/process/process.h b/kernel/src/process/process.h index cbe7fd1c..7317beee 100644 --- a/kernel/src/process/process.h +++ b/kernel/src/process/process.h @@ -219,4 +219,5 @@ extern int process_try_to_wake_up(struct process_control_block *_pcb, uint64_t _ * @return true 唤醒成功 * @return false 唤醒失败 */ -extern int process_wake_up_state(struct process_control_block *pcb, uint64_t state); \ No newline at end of file +extern int process_wake_up_state(struct process_control_block *pcb, uint64_t state); +void __switch_to(struct process_control_block *prev, struct process_control_block *next); \ No newline at end of file diff --git a/kernel/src/process/process.rs b/kernel/src/process/process.rs index 25d1cc0d..8fbcd248 100644 --- a/kernel/src/process/process.rs +++ b/kernel/src/process/process.rs @@ -3,9 +3,9 @@ use core::ptr::{read_volatile, write_volatile}; use crate::{ arch::asm::current::current_pcb, include::bindings::bindings::{ - process_control_block, sched_enqueue, PROC_RUNNING, PROC_STOPPED, + process_control_block, PROC_RUNNING, PROC_STOPPED, }, - sched::core::cpu_executing, + sched::core::{cpu_executing, sched_enqueue}, smp::core::{smp_get_processor_id, smp_send_reschedule}, }; @@ -76,7 +76,6 @@ pub extern "C" fn process_wake_up_state(pcb: *mut process_control_block, state: return process_try_to_wake_up(pcb, state, 0); } - /// @brief 让一个正在cpu上运行的进程陷入内核 pub fn process_kick(pcb: *mut process_control_block) { preempt_disable(); @@ -99,5 +98,5 @@ pub fn process_cpu(pcb: *const process_control_block) -> u32 { /// @param pcb 进程的pcb #[inline] pub fn process_is_executing(pcb: *const process_control_block) -> bool { - return cpu_executing(process_cpu(pcb)) == pcb; + return cpu_executing(process_cpu(pcb)) as *const process_control_block == pcb; } diff --git a/kernel/src/process/ptrace.h b/kernel/src/process/ptrace.h index 4d0c5d8d..7e26e4d6 100644 --- a/kernel/src/process/ptrace.h +++ b/kernel/src/process/ptrace.h @@ -2,10 +2,6 @@ #define __PTRACE_H__ -/* - -*/ - struct pt_regs { unsigned long r15; @@ -36,9 +32,9 @@ struct pt_regs /** * @brief 判断pt_regs是否来自用户态 - * - * @param regs - * @return __always_inline + * + * @param regs + * @return __always_inline */ static inline int user_mode(struct pt_regs *regs) { diff --git a/kernel/src/sched/cfs.c b/kernel/src/sched/cfs.c deleted file mode 100644 index 1ffb07a6..00000000 --- a/kernel/src/sched/cfs.c +++ /dev/null @@ -1,163 +0,0 @@ -#include "cfs.h" -#include -#include -#include - -struct sched_queue_t sched_cfs_ready_queue[MAX_CPU_NUM]; // 就绪队列 - -/** - * @brief 从就绪队列中取出PCB - * - * @return struct process_control_block* - */ -struct process_control_block *sched_cfs_dequeue() -{ - if (list_empty(&sched_cfs_ready_queue[proc_current_cpu_id].proc_queue.list)) - { - // kdebug("list empty, count=%d", sched_cfs_ready_queue[proc_current_cpu_id].count); - return &initial_proc_union.pcb; - } - - struct process_control_block *proc = container_of( - list_next(&sched_cfs_ready_queue[proc_current_cpu_id].proc_queue.list), struct process_control_block, list); - - list_del(&proc->list); - --sched_cfs_ready_queue[proc_current_cpu_id].count; - return proc; -} - -/** - * @brief 将PCB加入就绪队列 - * - * @param pcb - */ -void sched_cfs_enqueue(struct process_control_block *pcb) -{ - if (pcb == initial_proc[proc_current_cpu_id]) - return; - struct process_control_block *proc = container_of( - list_next(&sched_cfs_ready_queue[proc_current_cpu_id].proc_queue.list), struct process_control_block, list); - if ((list_empty(&sched_cfs_ready_queue[proc_current_cpu_id].proc_queue.list)) == 0) - { - while (proc->virtual_runtime < pcb->virtual_runtime) - { - proc = container_of(list_next(&proc->list), struct process_control_block, list); - } - } - list_append(&proc->list, &pcb->list); - ++sched_cfs_ready_queue[proc_current_cpu_id].count; -} - -/** - * @brief 调度函数 - * - */ -void sched_cfs() -{ - - cli(); - - current_pcb->flags &= ~PF_NEED_SCHED; - // kdebug("current_pcb pid= %d", current_pcb->pid); - struct process_control_block *proc = sched_cfs_dequeue(); - // kdebug("sched_cfs_ready_queue[proc_current_cpu_id].count = %d", - // sched_cfs_ready_queue[proc_current_cpu_id].count); - if (current_pcb->virtual_runtime >= proc->virtual_runtime || - !(current_pcb->state & PROC_RUNNING)) // 当前进程运行时间大于了下一进程的运行时间,进行切换 - { - - // kdebug("current_pcb->virtual_runtime = %d,proc->vt= %d", current_pcb->virtual_runtime, - // proc->virtual_runtime); - if (current_pcb->state & - PROC_RUNNING) // 本次切换由于时间片到期引发,则再次加入就绪队列,否则交由其它功能模块进行管理 - sched_cfs_enqueue(current_pcb); - // kdebug("proc->pid=%d, count=%d", proc->pid, sched_cfs_ready_queue[proc_current_cpu_id].count); - if (sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies <= 0) - { - switch (proc->priority) - { - case 0: - case 1: - sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies = - 4 / sched_cfs_ready_queue[proc_current_cpu_id].count; - break; - case 2: - default: - sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies = - (4 / sched_cfs_ready_queue[proc_current_cpu_id].count) << 2; - break; - } - } - - barrier(); - switch_proc(current_pcb, proc); - barrier(); - } - else // 不进行切换 - { - // kdebug("not switch."); - sched_cfs_enqueue(proc); - - if (sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies <= 0) - { - switch (proc->priority) - { - case 0: - case 1: - sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies = - 4 / sched_cfs_ready_queue[proc_current_cpu_id].count; - break; - case 2: - default: - - sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies = - (4 / sched_cfs_ready_queue[proc_current_cpu_id].count) << 2; - break; - } - } - } - - sti(); -} - -/** - * @brief 当时钟中断到达时,更新时间片 - * - */ -void sched_update_jiffies() -{ - - switch (current_pcb->priority) - { - case 0: - case 1: - --sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies; - ++current_pcb->virtual_runtime; - break; - case 2: - default: - sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies -= 2; - current_pcb->virtual_runtime += 2; - break; - } - // 时间片耗尽,标记可调度 - if (sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies <= 0) - current_pcb->flags |= PF_NEED_SCHED; -} - -/** - * @brief 初始化CFS调度器 - * - */ -void sched_cfs_init() -{ - memset(&sched_cfs_ready_queue, 0, sizeof(struct sched_queue_t) * MAX_CPU_NUM); - for (int i = 0; i < MAX_CPU_NUM; ++i) - { - - list_init(&sched_cfs_ready_queue[i].proc_queue.list); - sched_cfs_ready_queue[i].count = 1; // 因为存在IDLE进程,因此为1 - sched_cfs_ready_queue[i].cpu_exec_proc_jiffies = 5; - sched_cfs_ready_queue[i].proc_queue.virtual_runtime = 0x7fffffffffffffff; - } -} \ No newline at end of file diff --git a/kernel/src/sched/cfs.rs b/kernel/src/sched/cfs.rs new file mode 100644 index 00000000..399e9c77 --- /dev/null +++ b/kernel/src/sched/cfs.rs @@ -0,0 +1,201 @@ +use core::{ + ptr::null_mut, + sync::atomic::compiler_fence, +}; + +use alloc::{boxed::Box, vec::Vec}; + +use crate::{ + arch::{ + asm::current::current_pcb, + context::switch_process, + }, + include::bindings::bindings::{ + initial_proc_union, process_control_block, MAX_CPU_NUM, PF_NEED_SCHED, + PROC_RUNNING, + }, + kBUG, + libs::spinlock::RawSpinlock, +}; + +use super::core::Scheduler; + +/// 声明全局的cfs调度器实例 + +pub static mut CFS_SCHEDULER_PTR: *mut SchedulerCFS = null_mut(); + +/// @brief 获取cfs调度器实例的可变引用 +#[inline] +pub fn __get_cfs_scheduler() -> &'static mut SchedulerCFS { + return unsafe { CFS_SCHEDULER_PTR.as_mut().unwrap() }; +} + +/// @brief 初始化cfs调度器 +pub unsafe fn sched_cfs_init() { + if CFS_SCHEDULER_PTR.is_null() { + CFS_SCHEDULER_PTR = Box::leak(Box::new(SchedulerCFS::new())); + } else { + kBUG!("Try to init CFS Scheduler twice."); + panic!("Try to init CFS Scheduler twice."); + } +} + +/// @brief CFS队列(per-cpu的) +#[derive(Debug)] +struct CFSQueue { + /// 当前cpu上执行的进程,剩余的时间片 + cpu_exec_proc_jiffies: i64, + /// 队列的锁 + lock: RawSpinlock, + /// 进程的队列 + queue: Vec<&'static mut process_control_block>, +} + +impl CFSQueue { + pub fn new() -> CFSQueue { + CFSQueue { + cpu_exec_proc_jiffies: 0, + lock: RawSpinlock::INIT, + queue: Vec::new(), + } + } + + /// @brief 将进程按照虚拟运行时间的升序进行排列 + /// todo: 换掉这个sort方法,因为它底层是归并很占内存,且时间复杂度为nlogn,(遍历然后插入的方法,时间复杂度最坏是n) + pub fn sort(&mut self) { + self.queue + .sort_by(|a, b| (*a).virtual_runtime.cmp(&(*b).virtual_runtime)); + } + + /// @brief 将pcb加入队列 + pub fn enqueue(&mut self, pcb: &'static mut process_control_block) { + self.lock.lock(); + + // 如果进程是IDLE进程,那么就不加入队列 + if pcb.pid == 0 { + self.lock.unlock(); + return; + } + self.queue.push(pcb); + self.sort(); + self.lock.unlock(); + } + + /// @brief 将pcb从调度队列中弹出,若队列为空,则返回IDLE进程的pcb + pub fn dequeue(&mut self) -> &'static mut process_control_block { + let res: &'static mut process_control_block; + self.lock.lock(); + if self.queue.len() > 0 { + // 队列不为空,返回下一个要执行的pcb + res = self.queue.pop().unwrap(); + } else { + // 如果队列为空,则返回IDLE进程的pcb + res = unsafe { &mut initial_proc_union.pcb }; + } + self.lock.unlock(); + return res; + } +} + +/// @brief CFS调度器类 +pub struct SchedulerCFS { + cpu_queue: Vec<&'static mut CFSQueue>, +} + +impl SchedulerCFS { + pub fn new() -> SchedulerCFS { + // 暂时手动指定核心数目 + // todo: 从cpu模块来获取核心的数目 + let mut result = SchedulerCFS { + cpu_queue: Default::default(), + }; + + // 为每个cpu核心创建队列 + for _ in 0..MAX_CPU_NUM { + result.cpu_queue.push(Box::leak(Box::new(CFSQueue::new()))); + } + + return result; + } + + /// @brief 更新这个cpu上,这个进程的可执行时间。 + #[inline] + fn update_cpu_exec_proc_jiffies(_priority: i64, cfs_queue: &mut CFSQueue) -> &mut CFSQueue { + // todo: 引入调度周期以及所有进程的优先权进行计算,然后设置分配给进程的可执行时间 + cfs_queue.cpu_exec_proc_jiffies = 10; + + return cfs_queue; + } + + /// @brief 时钟中断到来时,由sched的core模块中的函数,调用本函数,更新CFS进程的可执行时间 + pub fn timer_update_jiffies(&mut self) { + let current_cpu_queue: &mut CFSQueue = self.cpu_queue[current_pcb().cpu_id as usize]; + // todo: 引入调度周期以及所有进程的优先权进行计算,然后设置进程的可执行时间 + + // 更新进程的剩余可执行时间 + current_cpu_queue.lock.lock(); + current_cpu_queue.cpu_exec_proc_jiffies -= 1; + // 时间片耗尽,标记需要被调度 + if current_cpu_queue.cpu_exec_proc_jiffies <= 0 { + current_pcb().flags |= PF_NEED_SCHED as u64; + } + current_cpu_queue.lock.unlock(); + + // 更新当前进程的虚拟运行时间 + current_pcb().virtual_runtime += 1; + } +} + +impl Scheduler for SchedulerCFS { + /// @brief 在当前cpu上进行调度。 + /// 请注意,进入该函数之前,需要关中断 + fn sched(&mut self) { + // kdebug!("cfs:sched"); + current_pcb().flags &= !(PF_NEED_SCHED as u64); + let current_cpu_id = current_pcb().cpu_id as usize; + let current_cpu_queue: &mut CFSQueue = self.cpu_queue[current_cpu_id]; + let proc: &'static mut process_control_block = current_cpu_queue.dequeue(); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + // 如果当前不是running态,或者当前进程的虚拟运行时间大于等于下一个进程的,那就需要切换。 + if (current_pcb().state & (PROC_RUNNING as u64)) == 0 + || current_pcb().virtual_runtime >= proc.virtual_runtime + { + compiler_fence(core::sync::atomic::Ordering::SeqCst); + // 本次切换由于时间片到期引发,则再次加入就绪队列,否则交由其它功能模块进行管理 + if current_pcb().state & (PROC_RUNNING as u64) != 0 { + // kdebug!("cfs:sched->enqueue"); + current_cpu_queue.enqueue(current_pcb()); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + } + + compiler_fence(core::sync::atomic::Ordering::SeqCst); + // 设置进程可以执行的时间 + if current_cpu_queue.cpu_exec_proc_jiffies <= 0 { + SchedulerCFS::update_cpu_exec_proc_jiffies(proc.priority, current_cpu_queue); + } + + compiler_fence(core::sync::atomic::Ordering::SeqCst); + + switch_process(current_pcb(), proc); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + } else { + // 不进行切换 + + // 设置进程可以执行的时间 + compiler_fence(core::sync::atomic::Ordering::SeqCst); + if current_cpu_queue.cpu_exec_proc_jiffies <= 0 { + SchedulerCFS::update_cpu_exec_proc_jiffies(proc.priority, current_cpu_queue); + } + + compiler_fence(core::sync::atomic::Ordering::SeqCst); + current_cpu_queue.enqueue(proc); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + } + compiler_fence(core::sync::atomic::Ordering::SeqCst); + } + + fn enqueue(&mut self, pcb: &'static mut process_control_block) { + let cpu_queue = &mut self.cpu_queue[pcb.cpu_id as usize]; + cpu_queue.enqueue(pcb); + } +} diff --git a/kernel/src/sched/core.c b/kernel/src/sched/core.c new file mode 100644 index 00000000..8f7a86f5 --- /dev/null +++ b/kernel/src/sched/core.c @@ -0,0 +1,14 @@ +#include "sched.h" + +/** + * @brief 切换进程上下文。请注意,只能在中断上下文内调用本函数 + * TODO:使用Rust重构这里 + * @param prev 前一个进程的pcb + * @param proc 后一个进程的pcb + */ +void switch_proc(struct process_control_block *prev, struct process_control_block *proc) +{ + process_switch_mm(proc); + io_mfence(); + switch_to(prev, proc); +} \ No newline at end of file diff --git a/kernel/src/sched/core.rs b/kernel/src/sched/core.rs index 7a544e0f..2d805999 100644 --- a/kernel/src/sched/core.rs +++ b/kernel/src/sched/core.rs @@ -1,13 +1,85 @@ -use crate::{include::bindings::bindings::process_control_block, process::process::process_cpu, arch::asm::current::current_pcb}; +use core::sync::atomic::compiler_fence; + +use crate::{ + arch::asm::{current::current_pcb, ptrace::user_mode}, + include::bindings::bindings::{process_control_block, pt_regs, EPERM, SCHED_NORMAL}, + process::process::process_cpu, +}; + +use super::cfs::{sched_cfs_init, SchedulerCFS, __get_cfs_scheduler}; /// @brief 获取指定的cpu上正在执行的进程的pcb #[inline] -pub fn cpu_executing(cpu_id:u32) -> *const process_control_block{ +pub fn cpu_executing(cpu_id: u32) -> &'static mut process_control_block { // todo: 引入per_cpu之后,该函数真正执行“返回指定的cpu上正在执行的pcb”的功能 - if cpu_id == process_cpu(current_pcb()){ + if cpu_id == process_cpu(current_pcb()) { return current_pcb(); - }else { + } else { todo!() } -} \ No newline at end of file +} + +/// @brief 具体的调度器应当实现的trait +pub trait Scheduler { + /// @brief 使用该调度器发起调度的时候,要调用的函数 + fn sched(&mut self); + + /// @brief 将pcb加入这个调度器的调度队列 + fn enqueue(&mut self, pcb: &'static mut process_control_block); +} + +fn __sched() { + compiler_fence(core::sync::atomic::Ordering::SeqCst); + let cfs_scheduler: &mut SchedulerCFS = __get_cfs_scheduler(); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + + cfs_scheduler.sched(); + + compiler_fence(core::sync::atomic::Ordering::SeqCst); +} + +/// @brief 将进程加入调度队列 +#[allow(dead_code)] +#[no_mangle] +pub extern "C" fn sched_enqueue(pcb: &'static mut process_control_block) { + let cfs_scheduler = __get_cfs_scheduler(); + cfs_scheduler.enqueue(pcb); +} + +/// @brief 初始化进程调度器模块 +#[allow(dead_code)] +#[no_mangle] +pub extern "C" fn sched_init() { + unsafe { + sched_cfs_init(); + } +} + +/// @brief 当时钟中断到达时,更新时间片 +/// 请注意,该函数只能被时钟中断处理程序调用 +#[allow(dead_code)] +#[no_mangle] +pub extern "C" fn sched_update_jiffies() { + match current_pcb().policy { + SCHED_NORMAL => { + __get_cfs_scheduler().timer_update_jiffies(); + } + _ => { + todo!() + } + } +} + +/// @brief 让系统立即运行调度器的系统调用 +/// 请注意,该系统调用不能由ring3的程序发起 +#[allow(dead_code)] +#[no_mangle] +pub extern "C" fn sys_sched(regs: &'static mut pt_regs) -> u64 { + // 进行权限校验,拒绝用户态发起调度 + if user_mode(regs) { + return (-(EPERM as i64)) as u64; + } + __sched(); + 0 +} diff --git a/kernel/src/sched/mod.rs b/kernel/src/sched/mod.rs index 689cad34..f714a594 100644 --- a/kernel/src/sched/mod.rs +++ b/kernel/src/sched/mod.rs @@ -1 +1,2 @@ -pub mod core; \ No newline at end of file +pub mod core; +pub mod cfs; \ No newline at end of file diff --git a/kernel/src/sched/sched.c b/kernel/src/sched/sched.c deleted file mode 100644 index 8b177591..00000000 --- a/kernel/src/sched/sched.c +++ /dev/null @@ -1,95 +0,0 @@ -#include "sched.h" -#include -#include -#include -#include -#include - -/** - * @brief - * - * @param p pcb - * @param attr 调度属性 - * @param user 请求是否来自用户态 - * @param pi - * @return int - */ -static int __sched_setscheduler(struct process_control_block *p, const struct sched_attr *attr, bool user, bool pi) -{ - int policy = attr->sched_policy; -recheck:; - // 这里policy的设置小于0是因为,需要在临界区内更新值之后,重新到这里判断 - if (!IS_VALID_SCHED_POLICY(policy)) - { - return -EINVAL; - } - // 修改成功 - p->policy = policy; - return 0; -} - -static int _sched_setscheduler(struct process_control_block *p, int policy, const struct sched_param *param, bool check) -{ - struct sched_attr attr = {.sched_policy = policy}; - - return __sched_setscheduler(p, &attr, check, true); -} - -/** - * sched_setscheduler -设置进程的调度策略 - * @param p 需要修改的pcb - * @param policy 需要设置的policy - * @param param structure containing the new RT priority. 目前没有用 - * - * @return 成功返回0,否则返回对应的错误码 - * - */ -int sched_setscheduler(struct process_control_block *p, int policy, const struct sched_param *param) -{ - return _sched_setscheduler(p, policy, param, true); -} - -/** - * @brief 包裹shced_cfs_enqueue(),将PCB加入就绪队列 - * - * @param pcb - */ -void sched_enqueue(struct process_control_block *pcb) -{ - sched_cfs_enqueue(pcb); -} - -/** - * @brief 该函数只能由sys_sched调用 - * - */ -static void __sched() -{ - sched_cfs(); -} - -void sched_init() -{ - sched_cfs_init(); -} - -uint64_t sys_sched(struct pt_regs *regs) -{ - if(user_mode(regs)){ - return -EPERM; - } - __sched(); -} - -void sched() -{ - - enter_syscall_int(SYS_SCHED, 0, 0, 0, 0, 0, 0, 0, 0); -} - -void switch_proc(struct process_control_block *prev, struct process_control_block *proc) -{ - process_switch_mm(proc); - io_mfence(); - switch_to(prev, proc); -} diff --git a/kernel/src/sched/sched.h b/kernel/src/sched/sched.h index f2098696..965b801c 100644 --- a/kernel/src/sched/sched.h +++ b/kernel/src/sched/sched.h @@ -17,64 +17,61 @@ #define IS_VALID_SCHED_POLICY(_policy) ((_policy) > 0 && (_policy) <= SCHED_MAX_POLICY_NUM) -struct sched_param -{ - int sched_priority; -}; -struct sched_attr -{ - uint32_t size; - uint32_t sched_policy; - uint64_t sched_flags; - /* SCHED_NORMAL, SCHED_BATCH */ - int32_t sched_nice; +// struct sched_param +// { +// int sched_priority; +// }; +// struct sched_attr +// { +// uint32_t size; - /* SCHED_FIFO, SCHED_RR */ - uint32_t sched_priority; +// uint32_t sched_policy; +// uint64_t sched_flags; - /* SCHED_DEADLINE */ - uint64_t sched_runtime; - uint64_t sched_deadline; - uint64_t sched_period; +// /* SCHED_NORMAL, SCHED_BATCH */ +// int32_t sched_nice; - /* Utilization hints */ - uint32_t sched_util_min; - uint32_t sched_util_max; -}; +// /* SCHED_FIFO, SCHED_RR */ +// uint32_t sched_priority; + +// /* SCHED_DEADLINE */ +// uint64_t sched_runtime; +// uint64_t sched_deadline; +// uint64_t sched_period; + +// /* Utilization hints */ +// uint32_t sched_util_min; +// uint32_t sched_util_max; +// }; + +// static int __sched_setscheduler(struct process_control_block *p, const struct sched_attr *attr, bool user, bool pi); +// static int _sched_setscheduler(struct process_control_block *p, int policy, const struct sched_param *param, +// bool check); +// /** +// * sched_setscheduler -设置进程的调度策略 +// * @param p 需要修改的pcb +// * @param policy 需要设置的policy +// * @param param structure containing the new RT priority. 目前没有用 +// * +// * @return 成功返回0,否则返回对应的错误码 +// * +// */ +// int sched_setscheduler(struct process_control_block *p, int policy, const struct sched_param *param); -static int __sched_setscheduler(struct process_control_block *p, const struct sched_attr *attr, bool user, bool pi); -static int _sched_setscheduler(struct process_control_block *p, int policy, const struct sched_param *param, - bool check); -/** - * sched_setscheduler -设置进程的调度策略 - * @param p 需要修改的pcb - * @param policy 需要设置的policy - * @param param structure containing the new RT priority. 目前没有用 - * - * @return 成功返回0,否则返回对应的错误码 - * - */ -int sched_setscheduler(struct process_control_block *p, int policy, const struct sched_param *param); /** * @brief 包裹sched_enqueue(),将PCB加入就绪队列 * * @param pcb */ -void sched_enqueue(struct process_control_block *pcb); -/** - * @brief 包裹sched_cfs(),调度函数 - * - */ -void sched(); -void sched_init(); +// ================= Rust 实现 ============= +extern void sched_update_jiffies(); +extern void sched_init(); +extern void sched(); +extern void sched_enqueue(struct process_control_block *pcb); +extern void sched(); -/** - * @brief 当时钟中断到达时,更新时间片 - * - */ -void sched_update_jiffies(); +void switch_proc(struct process_control_block *prev, struct process_control_block *proc); -void switch_proc(struct process_control_block *prev, struct process_control_block *proc); \ No newline at end of file diff --git a/kernel/src/smp/smp.c b/kernel/src/smp/smp.c index 1d023ae6..f13ab91b 100644 --- a/kernel/src/smp/smp.c +++ b/kernel/src/smp/smp.c @@ -12,8 +12,6 @@ #include "ipi.h" -void ipi_0xc8_handler(uint64_t irq_num, uint64_t param, struct pt_regs *regs); // 由BSP转发的HPET中断处理函数 - static spinlock_t multi_core_starting_lock = {1}; // 多核启动锁 static struct acpi_Processor_Local_APIC_Structure_t *proc_local_apic_structs[MAX_SUPPORTED_PROCESSOR_NUM]; @@ -47,8 +45,6 @@ void smp_init() io_mfence(); - // 注册接收bsp处理器的hpet中断转发的处理函数 - ipi_regiserIPI(0xc8, NULL, &ipi_0xc8_handler, NULL, NULL, "IPI 0xc8"); io_mfence(); ipi_send_IPI(DEST_PHYSICAL, IDLE, ICR_LEVEL_DE_ASSERT, EDGE_TRIGGER, 0x00, ICR_INIT, ICR_ALL_EXCLUDE_Self, 0x00); @@ -193,9 +189,3 @@ void smp_ap_start() while (1) // 这里要循环hlt,原因是当收到中断后,核心会被唤醒,处理完中断之后不会自动hlt hlt(); } - -// 由BSP转发的HPET中断处理函数 -void ipi_0xc8_handler(uint64_t irq_num, uint64_t param, struct pt_regs *regs) -{ - sched_update_jiffies(); -} diff --git a/kernel/src/syscall/syscall.c b/kernel/src/syscall/syscall.c index e7a41ba0..53807602 100644 --- a/kernel/src/syscall/syscall.c +++ b/kernel/src/syscall/syscall.c @@ -12,7 +12,6 @@ #include #include