\documentclass{article} \usepackage{graphicx} \usepackage{listings} \lstset { % language=C++ } \title{WG01: C++ for Kernel Development} \author{Amlal El Mahrouss\\NeKernel.org} \date{\today} \begin{document} \maketitle \section{Abstract} { Many and most kernels have been shipped using the C programming language.\\ And some of them like EKA2 uses the C++ programming language. Although notoriously difficult, one may still adapt to those constraints in order to deliver one such operating system kernel. \\ That is the reason that most production-grade kernels (Linux, XNU, and NT) are mostly written in C. With a higher-level subset in C++. \\ However, when correctly applying C++ principles to kernel development, one makes the development much more easier to pull off. } \section{The Three Principles of Kernel C++} \subsection{Part One: The C++ Runtime} { The problem mostly lies in the C++ runtime. Which assumes an existing host. A host is the contrary of a freestanding target, that is a program which expects a runtime to be present and linked to the program. \\ A C++ Kernel may instead make use of compile-time features of C++ alongside a tiny C++ runtime to make sure that no issues arise because of this host/freestanding difference. } \subsection{Part Two: Constexpr and Friends} { One may avoid v-tables and runtime dependent features as much as possible. \\ While focusing instead on meta-programming and compile-time features offered by C++. For example one may use templates to implement a scheduling policy algorithm. \\ One example of such implementation may be: \\ (Keep in mind that the code has not been tested on production systems, use it at your own risk!) \begin{lstlisting} /// Reference Implementation: https://github.com /// /nekernel-org/nekernel/blob/stable/src/kernel/ /// KernelKit/CoreProcessScheduler.h#L51-L76 /// AND: https://github.com/nekernel-org/nekernel/blob/stable/src/kernel /// /KernelKit/CoreProcessScheduler.h#L78-L105 struct FileTree final { static constexpr bool is_virtual_memory = false; static constexpr bool is_memory = false; static constexpr bool is_file = true; /// ... }; struct MemoryTree final { static constexpr bool is_virtual_memory = false; static constexpr bool is_memory = true; static constexpr bool is_file = false; /// ... }; \end{lstlisting} As you can see these two structures leverages the `constexpr' keyword to make sure no bugs or panic occur at runtime because of a misuse of a system resource. \\ Which is why the constexpr keyword is very powerful here, we avoid the many pitfalls of writing (and hoping) that the C version will be well-thought enough so that we can catch such bugs later. \subsection{Bonus: Using Concepts and the DDK.} { This bonus subsection intends to show how properly applied C++\\ Can solve issues related to driver validation. The following example shows how powerful C++ can be when combining it with Device Driver development as well. \begin{lstlisting} /// Reference implementation: /// https://github.com/nekernel-org /// /nekernel/blob/stable/src/libDDK/DriverKit /// /c%2B%2B/driver_base.h /// @brief This concept requires the driver /// to be IDriverBase compliant. template concept IsValidDriver = requires(T a) { { a.IsActive() && a.Type() > 0 }; }; /// @brief Consteval helper to detect /// whether a template is truly based on IDriverBase. /// @note This helper is consteval only. template consteval void ce_ddk_is_valid(T) {} \end{lstlisting} } } \subsection{Part Three: Memory and C++ Classes} { This last part treats about the final and most important part of this paper so far. Memory. As you may already have known, the C++ language uses a class lookup system (also called v-table) in order to refer to a base method in case if the instance has it missing. \begin{lstlisting} /// Link: https://godbolt.org/z/q3Wceannr /// /std:c++20 /Wall #include class A { public: explicit A() = default; virtual ~A() = default; virtual void doImpl() { std::cout << "doImpl\n"; } }; class B : public A { public: explicit B() = default; ~B() override = default; }; int main() { B* callImpl = new B(); callImpl->doImpl(); } \end{lstlisting} \subsection{Addressing V-Tables in a C++ Kernel.} Now the problem with kernel development is that we want to avoid such feature as much as possible, and we'd do that by following the Prong on Inheritance: \subsection{The Three Prongs on Inheritance:} Consider the following questions: \begin{itemize} \item[A:] Is this a protocol/concept that can be extended to other similar protocols/concepts? \item[B:] Can I do this without too much trade-off costs? \item[C:] Can I do this without using V-Tables? \end{itemize} } When 2/3 of those questions fail, you should consider finding another solution to your problem, as it surely has an equivalent without V-Tables. \section{Final Words and Conclusion} { We can now conclude that C++ in Kernel Development is indeed possible under strict conditions of C++ Development. \\ Breaking those conditions would lead to system quirks and instability. A reference implementation of this paper exists, It's called NeKernel.org, available under the same internet address. \\ I am looking forward to any questions or inquiries at: amlal@nekernel.org \\\\Yours truly, \\ Amlal El Mahrouss } \section{References} { \begin{itemize} \item[EKA2:] https://en.wikipedia.org/wiki/EKA2 \item[NeKernel.org:] https://nekernel.org \end{itemize} } \end{document}