Set the maximum time (in seconds) spent in kernel before considered
to be stalled.
"""
- require(check_stall)
+ require (check_stall)
return 10
Setting it to 0 disable this check
"""
- require(check_stall)
+ require (check_stall)
return 0
-# LunaixOS 源代码
+# Luniax Kernel
-我知道这个目录结构看起来相当的劝退。特别是并没有像初代Linux那种一个文件夹里就只是一堆文件的简单朴素。但至少,就我而言,把结构细分一点儿总是好的。
+This is the source code tree for lunaix kernel.
-## 目录结构
+## Organisation
+
+| Directory | Description |
+| ------- | ------ |
+| `arch` | ISA specific code |
+| `hal` | drivers |
+| `includes`| headers |
+| `kernel` | kernel source files |
+| `link` | linker scripts |
+| `libs` | kernel library |
+| `makeinc` | includes for makefile |
+| `scripts` | auxiliary scripts |
+| `tests` | kernel test cases |
+| `usr` | stock user space environment (debug only) |
+
+## Build System
+
+See: [Build system of Lunaix](./scripts/build-tools/README.md)
-+ `arch` 平台,CPU架构相关代码。
-+ `hal` 硬件抽象层,包含了平台设备基本驱动的实现。
-+ `includes` 所有头文件
-+ `makeinc` makefile配置文件
-+ `kernel` 这里就是内核了
- + `block` 块IO抽象层
- + `debug` 内核调试服务器
- + `device` 设备(通用)抽象层
- + `ds` 提供一些基本的数据结构支持。
- + `exe` 可执行文件的解析与加载。
- + `fs` 文件系统。
- + `mm` 各类内存管理器。
- + `peripheral` 外部设备驱动(如键盘)。
- + `process` 进程相关
- + `time` 为内核提供基本的时间,计时服务。
- + `tty` 提供基本的,CGA服务。
-+ `libs` 一些内核使用的运行时库,主要提供是内核模式下的一些C标准库里的实现。
-+ `link` 链接器脚本
-+ `scripts` 其他脚本(如:用于代码生成)
-+ `usr` 用户空间代码库,包含了一些实用的用户程序,编译过程独立与内核。
@(parent := architecture_support)
def x86_configurations():
- require(arch_x86)
+ require (arch_x86)
@flag
def x86_bl_mb() -> bool:
devicetree might be mandatory and perhaps the only
way.
"""
- require(not arch_x86)
+ require (not arch_x86)
return False
"""
Maximum size for a firmware provided device tree blob
"""
- require(use_devicetree)
+ require (use_devicetree)
return 256
\ No newline at end of file
@"Enable AHCI support"
def ahci_enable() -> bool:
""" Enable the support of SATA AHCI.
- Must require PCI at current stage """
- require(pci_enable)
+ Must require PCI at current stage """
+ require (pci_enable)
return True
@"PCI Express"
def pcie_ext() -> bool:
""" Enable support of PCI-Express extension """
- require(pci_enable)
+ require (pci_enable)
return False
@"Use PMIO for PCI"
def pci_pmio() -> bool:
""" Use port-mapped I/O interface for controlling PCI """
- require(not pcie_ext and pci_enable)
- require(arch_x86)
+ require (not pcie_ext and pci_enable)
+ require (arch_x86)
return True
@"16x50 XT-Compat"
def xt_16x50() -> bool:
""" Enable the 16x50 for PC-compatible platform """
- require(arch_x86)
+ require (arch_x86)
return True
@(parent := file_system)
def ext2_fs():
- require(fs_ext2)
+ require (fs_ext2)
@"Debug Messages"
def ext2_debug_msg() -> bool:
@"PMalloc Thresholds"
def pmalloc_simple_po_thresholds():
- require (pmalloc_method_simple)
+ require (pmalloc_method_simple)
@"Maximum cached order-0 free pages"
def pmalloc_simple_max_po0() -> int:
LunaBuild is programmable source file selection tool. It does not build things
by itself, rather, it selects which source file should be feed as input to
other tranditional build tools such as make. The selection logic is completely
-programmable and convey through `LBuild` file which is essentially a python
-script. As the primary design goal for LunaBuild is simple, lightweight and
-standalone. It just plain python, with some extra predefined functions and
-automatic variables, so does not force user to learn some other weird domain
-specific language (yes, that's you, CMake!).
+programmable and convey through `LBuild` using python syntax.
+Since the primary design goal for LunaBuild is simple, lightweight and
+standalone. It introduce minimal customisations on the python syntax for better
+readbility and it is essentially modified python.
-## Usage
+## Functionalities
-Invoke `./luna_build.py <root_lbuild> -o <out_dir>`. It will output two file
-to the `<out_dir>`: `sources.list` and `headers.list`. Contains all the source
-files and header files to be used by the build process.
+### Native Python Environment
-## Core Functions
+LunaBuild is a superset of python, meaning that all existing functionalities of
+python language is still intacted and supported.
-LunaBuild provide following function to help user select source files.
+This will gives you maximum flexibility on defining your build logic.
-### [func] `use(lbuild_path)`
+### Import other `LBuild`
-Include another LBuild file. `lbuild_path` is the path relative to current
-directory, pointed to the file. It can be also pointed to a directory, for
-which the LBuild file is inferred as `$lbuild_path/LBuild`.
+Multiple `LBuild`s may be defined across different sub-directory in large scale
+project for better maintainability
-For example:
+LunaBuild allow you to import content of other LBuild using python's relative import
+feature:
```py
-use("dir")
-use("dir/LBuild")
+from . import subdirectory
```
-both are equivalent.
+This import mechanism works like `#include` directive in C preprocessor,
+the `from . import` construct will automatically intercepted by the LBuild interpreter and
+be replaced with the content from `./subdirectory/LBuild`
-### [func] `sources(src_list)`
-
-Select a list of source files, all paths used are relative to current
-directory. For example,
+You can also address file in the deeper hierarchy of the directory tree, for example
```py
-sources([ "a.c", "b.c", "c.c" ])
+from .sub1.sub2 import sub3
```
-### [func] `headers(src_list)`
+This will be translated into `./sub1/sub2/sub3/LBuild`
-Select a list of header file or include directory, all paths used are
-relative to current directory. For example,
+It can also be used in any valid python conditional branches to support
+conditional import
```py
-headers([ "includes/", "includes/some.h" ])
+if feature1_enabled:
+ from . import feature1
+elif feature3_enabled
+ from . import feature3
```
-### [func] `configured(name)`
-
-Check whether a configuration is present, the name for the configuration
-is defined by external configuration provider.
-
-### [func] `config(name)`
-
-Read the value of a configuration, raise exception is not exists.
-### [var] `_script`
+### Scoped Data Banks
-Automatic variable, a path to the current build file.
+Almost every build systems is evolved around the list data structure, as its
+main task is to collect all interested source files, headers or other build
+process relative information. This is also true for LunaBuild.
-## Short-hands
+To better represent this in a more readable way, LunaBuild introduce the concept
+of scoped data banks, represented as a automatic global object in the script.
-LunaBuild provide some useful short-hand notations
-
-### Conditional Select
-
-Suppose you have two source files `src_a.c` and `src_b.c`, for which
-their selection will be depends on the value of a configuration
-`WHICH_SRC`. A common way is to use `if-else` construct
+Take a look in the example:
```py
-if config("WHICH_SRC") == "select_a":
- sources("src_a.c")
-elif config("WHICH_SRC") == "select_b":
- sources("src_b.c")
+src.c += "source1.c", "source2.c"
```
-LunaBuild allow you to short hand it as such:
+This will append `"source1.c"` and `"source2.c"` into the list named `c` under
+the scope of `src`. Which can be clearly interpreted as "collection of c source files"
-```py
-sources({
- config("WHICH_SRC"): {
- "select_a": "src_a.c",
- "select_b": "src_b.c",
- # more...
- }
-})
-```
+It is also important to notice that not all databanks are in the forms of list.
+Some data banks served special purpose, as we will see below.
-It can also be extended easily for multiple choices and allow nesting.
+LunaBuild defines the following databanks and scope:
-You may also notice we no longer wrap the parameter with square bracket,
-this is also another short-hand, the array notation is not needed when
-there is only one element to add.
++ `src` (source files):
+ + `c` (c files, type: `[]`)
+ + `h` (headers or include directories, type: `[]`)
++ `flag` (source files):
+ + `cc` (compiler flags, type: `[]`)
+ + `ld` (linker flags, type: `[]`)
++ `config` (configuration options from `LConfig`)
+ + `CONFIG_<OptionName>` (any valid config name, type: `Any`)
++ `env` (environmental variables)
+ + `<Name>` (any valid env variable name, type: `Any`)
--- /dev/null
+# LunaConfig
+
+LunaConfig is a configuration language build on top of python. It allows user
+to define options and the dependencies then reuse these options in their source
+code for customisable build.
+
+Lunaix use LunaConfig to toggle various optional modules, subsystems or features
+and allow parameterised kernel build.
+
+
+## Design Motivation
+
+LunaConfig is designed to be an improvement over the old-school Kconfig, which in
+particular to address the issue of lacking hierchical representation. This is
+because Kconfig organise options into a big flat list, while the options are
+organised into menu which is hierachical in nature. It is very difficult to
+identify membership of a config without diving into menuconfig.
+
+## Basic Concepts
+
+LunaConfig is presented as a file named `LConfig` and thus limited to one LConfig per directory. This is because LunaConfig enforce user to organise each directory to be a module or logical packaging of set of relavent functionalities.
+
+In each LunaConfig files, these major concepts you will usually seen.
+
+1. Config Component: `Terms` and `Groups`
+2. Config Import
+3. Native Python
+
+We will describe them in details in the following sections
+
+### Terms
+
+> The object that hold the value for customisation
+
+```py
+def feature1() -> bool:
+ return True
+```
+
+This defined an option named `feature1` with type of `bool` and the default
+value of `True`.
+
+### Groups
+
+> The logical object that is used to organise the `terms` or other `groups`
+
+A group is similar to term but without return type indication and return statement
+
+And it is usually nested with other groups or terms.
+
+```py
+def group1():
+ def feature1() -> bool:
+ return True
+```
+
+### LunaConfig Import
+
+Multiple `LConfig`s may be defined across different sub-directory in large scale
+project for better maintainability
+
+LunaConfig allow you to import content of other LBuild using python's relative import
+feature:
+
+```py
+from . import module
+```
+
+This import mechanism works like `#include` directive in C preprocessor,
+the `from . import` construct will automatically intercepted by the LBuild interpreter and
+be replaced with the content from `./module/LConfig`
+
+You can also address file in the deeper hierarchy of the directory tree, for example
+
+```py
+from .sub1.sub2 import module
+```
+
+This will be translated into `./sub1/sub2/module/LConfig`
+
+It can also be used in any valid python conditional branches to support
+conditional import
+
+```py
+if condition_1:
+ from . import module1
+elif condition_2:
+ from . import module2
+```
+
+### Native Python
+
+Native Python code is fully supported in LunaConfig, this include everything like packages import, functions, and class definitions. LunaConfig has the ability to distinguish these code transparently from legitimate config code.
+
+However, there is one exception for this ability. Since LunaConfig treat function definition as declaration of config component, to define a python native function you will need to decorate it with `@native`. For example:
+
+```py
+@native
+def add(a, b):
+ return a + b
+
+def feature1() -> int:
+ return add(1, 2)
+```
+
+If a native function is nested in a config component, it will not be affected by the scope and still avaliable globally. But this is not the case if it is nested by another native function.
+
+If a config component is nested in a native function, then it is ignored by LunaConfig
+
+## Term Typing
+
+A config term require it's value type to be specified explicitly. The type can be a literal type, primitive type or composite type
+
+### Literal Typing
+
+A term can take a literal as it's type, doing this will ensure the value taken by the term to be exactly same as the given type
+
+```py
+# OK
+def feature1() -> "value":
+ return "value"
+ # return "value2"
+
+# Error
+def feature1() -> "value":
+ return "abc"
+```
+
+### Primitive Typing
+
+A term can take any python's primitive type, the value taken by the term will be type checked rather than value checked
+
+```py
+# OK
+def feature1() -> int:
+ return 123
+
+# Error
+def feature1() -> int:
+ return "abc"
+```
+
+### Composite Typing
+
+Any literal type or primitive type can be composite together via some structure to form composite type. The checking on these type is depends on the composite structure used.
+
+#### Union Structure
+
+A Union structure realised through binary disjunctive connector `|`. The term value must satisfy the type check against one of the composite type:
+
+```py
+def feature1() -> "a" | "b" | int
+ # value can be either:
+ # "a" or "b" or any integer
+ return "a"
+```
+
+## Component Attributes
+
+Each component have set of attributes to modify its behaviour and apperance, these
+attributes are conveyed through decorators
+
+### Labels
+
+> usage: `Groups` and `Terms`
+
+Label provide a user friendly name for a component, which will be the first choice
+of the name displayed by the interactive configuration tool
+
+```py
+@"This is feature 1"
+def feature1() -> bool:
+ return True
+```
+
+### Readonly
+
+> usage: `Terms`
+
+Marking a term to be readonly prevent explicit value update, that is, manual update by user. Implicit value update initiated by `constrains` (more on this later) is still allowed.
+
+```py
+@readonly
+def feature1() -> bool:
+ return True
+```
+
+### Visibility
+
+> usage: `Groups` and `Terms`
+
+A component can be marked to be hidden thus prevent it from displayed by the configuration tool, it does not affect the visibility in the code.
+
+If the decorated target is a group, then it is inheritated by all it's subordinates.
+
+```py
+@hidden
+def feature1() -> bool:
+ return True
+```
+
+### Flag
+
+> usage: `Terms`
+
+This is a short hand of both `@hidden` and `@readonly`
+
+```py
+@flag
+def feature1() -> bool:
+ return True
+```
+
+is same as
+
+```py
+@hidden
+@readonly
+def feature1() -> bool:
+ return True
+```
+
+### Parent
+
+> usage: `Groups` and `Terms`
+
+Any component can be defined outside of the logical hierachial structure (i.e., the nested function) but still attached to it's physical hierachial structure.
+
+```py
+@parent := parent_group
+def feature1() -> bool:
+ return True
+
+def parent_group():
+ def feature2() -> bool:
+ return False
+```
+
+This will assigned `feature1` to be a subordinate of `parent_group`. Note that the reference to `parent_group` does not required to be after the declaration.
+
+It is equivalent to
+
+```py
+def parent_group():
+ def feature2() -> bool:
+ return False
+
+ def feature1() -> bool:
+ return True
+```
+
+### Help Message
+
+> usage: `Groups` and `Terms`
+
+A help message will provide explainantion or comment of a component, to be used and displayed by the configuration tool.
+
+The form of message is expressed using python's doc-string
+
+```py
+def feature1() -> bool:
+ """
+ This is help message for feature1
+ """
+
+ return True
+```
+
+## Directives
+
+There are builtin directives that is used inside the component.
+
+### Dependency
+
+> usage: `Groups` and `Terms`
+
+The dependency between components is described by various `require(...)` directives.
+
+This directive follows the python function call syntax and accept one argument of a boolean expression as depedency predicate.
+
+Multiple `require` directives will be chainned together with logical conjunction (i.e., `and`)
+
+```py
+def feature1() -> bool:
+ require (feature2 or feature3)
+ require (feature5)
+
+ return True
+```
+
+This composition is equivalent to `feature5 and (feature2 or feature3)`, indicate that the `feature1` require presences of both `feature5` and at least one of `feature2` or `feature3`.
+
+If a dependency can not be satisfied, then the feature is disabled. This will cause it neither to be shown in configuration tool nor referencable in source code.
+
+Note that the dependency check only perform on the enablement of the node but not visibility.
+
+### Auto Toggling
+
+> usage: `Terms` with `bool` value type
+
+The `when(...)` directive allow changing the default value based on the predicate evaluation on the value of other terms. Therefore, it can be only used by `Terms` with `bool` as value type.
+
+Similar to `require`, it is based on the function call syntax and takes one argument of conjunctive expression (i.e., boolean expression with only `and` connectors).
+
+Multiple `when` will be chained together using logical disjunction (i.e., `or`)
+
+```py
+def feature1() -> bool:
+ when (feature2 is "value1" and feature5 is "value1")
+ when (feature3)
+```
+
+Which means `feature1` will takes value of `True` if one of the following is satisfied:
+ + both `feature2` and `feature5` has value of `"value1"`
+ + `feature3` has value of True
+
+Notice that we do not have `return` statement at the end as the precense of `when` will add a return automatically (or replace it if one exists)
+
+
+## Validation
+
+For configuration language being a python superset will have a risk of abusing due to the high flexibility. This include complex logic, non-trivial operation being used in a component to derive the final value. Thus shifting the style from declarative to imperative and greatly reduce the overall reability.
+
+For prevention of this potential drawback, LunaConfig implemented a syntactical validator to identify these possible bad-practice and issue warning (or rise a fatal-error depending on the user setting).
+
+Currently, LunaConfig detect the misuses based on these rule rules:
+
++ `dynamic-logic`: The presence of conditional branching that could lead to complex logic. However, pattern matching is allowed.
++ `while-loop`, `for-loop`: The presence of any loop structure.
++ `class-def`: The presence of class definition
++ `complex-struct`: The present of complicated data structure such as `dict`.
++ `side-effect`: The presence of dynamic assignment of other config terms value.
++ `non-trivial-value`: The presence of non-trivial value being used as default value. This include every things other than:
+ + constant
+ + variable reference
+ + comparison between constant or variable
+ + single boolean operation
+ + ternary operator with constant/refernece and trivial boolean operation
+
--- /dev/null
+# Lunaix Build System
+
+The build system used by Lunaix is a hybird approach, with:
+
++ [LunaConfig](./README.lconfig.md) as compile-time configuration and build parameterisation
++ [LunaBuild](./README.lbuild.md) as soruce file collection and compiler/linker flags setting
++ Makefile for the file dependency check, auto-updating and other top-level managements.
+
Enabled = PropertyAccessor("$enabled")
Status = PropertyAccessor("$status")
Dependency = PropertyAccessor("$depends")
- WhenToggle = PropertyAccessor("$when")
Hidden = PropertyAccessor("hidden")
Parent = PropertyAccessor("parent")
Label = PropertyAccessor("label")
def terms(self):
for node in self.__node_table.values():
if isinstance(node, TermNode):
- yield node
-
-import json
\ No newline at end of file
+ yield node
\ No newline at end of file
self.__cfg_node = cfg_node
+ self.__when_epxr = None
+
def __subscript_accessor(self, name, ctx, token):
return ast.Subscript(
value=ast.Name("__lzLut__", ctx=ast.Load()),
op=ast.And(),
values=[ast.Constant(True), *and_list])
- expr = NodeProperty.WhenToggle[cfgn]
+ expr = self.__when_epxr
if expr:
assert isinstance(expr, ast.expr)
current = ast.BoolOp(op=ast.Or(), values=[expr, current])
- NodeProperty.WhenToggle[cfgn] = current
+ self.__when_epxr = current
def visit_Attribute(self, node):
return self.__gen_accessor(node)
assert isinstance(node, ast.Module)
node = self.visit(node)
- expr = NodeProperty.WhenToggle[self.__cfg_node]
+ expr = self.__when_epxr
if not expr:
return node
-
- del NodeProperty.WhenToggle[self.__cfg_node]
-
+
node.body.append(ast.Return(expr, lineno=0, col_offset=0))
return node
ctx=ast.Store)
TrivialValue = Schema(Schema.Union(
ast.Constant,
- ast.Name,
- Schema(ast.Subscript,
- value=Schema(ast.Name, id='__lzLut__'),
- slice=ast.Constant)
+ ast.Name
))
BoolOperators = Schema(Schema.Union(ast.Or, ast.And))
TrivialTest = Schema(ast.Compare,
left=TrivialValue,
- ops=[Schema.Union(ast.Eq, ast.In)],
- comparators=[Schema.Union(
- ast.Constant,
- Schema(ast.List, elts=Schema.List(ast.Constant))
- )])
+ ops=[Schema.Union(ast.Eq)],
+ comparators=[ast.Constant])
InlineIf = Schema(ast.IfExp,
test=Schema.Union(TrivialTest, TrivialValue),
TrivialReturn = Schema(Schema.Union(
TrivialValue,
+ TrivialTest,
InlineIf,
- TrivialLogic,
ast.JoinedStr
))