Skip to content

Commit 7defb1f

Browse files
committed
openkal-opensbi 0.1.0 —— RISC-V SBI 上的 openkal 实现
⭐ **可移植的那个 RISC-V 后端,与板级的那个并列。** 板级后端往设备地址写,而那个地址是板级事实:同一个二进制换到第二台 RISC-V 机器上 写到的不是 UART —— 能编、能链、能跑、什么都不打印。 SBI 没有这个性质:控制台是对**已经知道机器是什么**的固件的一次调用。因此同一个镜像 在 QEMU virt 的 OpenSBI 下与真实板子上都能跑,不必重新构建。两种后端都正当,工程按 需要哪种性质来选 —— SBI 要求底下有固件,板级后端不要求。 ## 实现 core 三件 ⚠️ **time 是刻意缺席的,尽管 SBI 有定时器扩展。** SBI 能装一次定时器中断,那是给内核 的机制而不是程序能读的时钟;报告一个不前进的时钟会让每一次定时等待静默地错 —— 这正是规范里「模拟」的定义,它会取消一个 interface 被提供的资格。 ## 堆是 bump 分配器,这是**边界**而不是遗漏 SBI 不提供分配器。规范的判别式接纳它:能耗尽的实现**限定**了可用量,而让调用方静默 出错的才是模拟。耗尽是有定义的结果(返回空),每个调用方本来就要处理。 ## 两处实测而非假设 * **DBCN 要探测。** 该扩展在 SBI v2.0 才有,更旧的固件返回 NOT_SUPPORTED, 届时每次写都会静默地什么都不传。legacy 单字符扩展是回退路径。 * ⚠️ **不用函数局部 static。** 带守卫的局部 static 会编成 __cxa_guard_acquire/__cxa_guard_release,而 freestanding 没有运行时提供它们。 实测:链接失败并点名两者。-fno-threadsafe-statics 也能压下去,但**一个必须记住的 flag 弱于一个根本不会要求运行时的构造**。 ## 验证 examples/hello 在 QEMU -bios default(即真实 OpenSBI)下跑通: hello from openkal over SBI / heap ok。镜像不带 C 库(sysroot = "")也不带板级包, 装载于 0x80200000 —— OpenSBI 自身占据 RAM 起始。
0 parents  commit 7defb1f

10 files changed

Lines changed: 656 additions & 0 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
target/
2+
.mcpp/
3+
compile_commands.json
4+
mcpp.lock

LICENSE

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
Copyright (c) 2026-present mcpp community, speakshen@163.com
2+
3+
---
4+
5+
Apache License
6+
Version 2.0, January 2004
7+
http://www.apache.org/licenses/
8+
9+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
10+
11+
1. Definitions.
12+
13+
"License" shall mean the terms and conditions for use, reproduction,
14+
and distribution as defined by Sections 1 through 9 of this document.
15+
16+
"Licensor" shall mean the copyright owner or entity authorized by
17+
the copyright owner that is granting the License.
18+
19+
"Legal Entity" shall mean the union of the acting entity and all
20+
other entities that control, are controlled by, or are under common
21+
control with that entity. For the purposes of this definition,
22+
"control" means (i) the power, direct or indirect, to cause the
23+
direction or management of such entity, whether by contract or
24+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
25+
outstanding shares, or (iii) beneficial ownership of such entity.
26+
27+
"You" (or "Your") shall mean an individual or Legal Entity
28+
exercising permissions granted by this License.
29+
30+
"Source" form shall mean the preferred form for making modifications,
31+
including but not limited to software source code, documentation
32+
source, and configuration files.
33+
34+
"Object" form shall mean any form resulting from mechanical
35+
transformation or translation of a Source form, including but
36+
not limited to compiled object code, generated documentation,
37+
and conversions to other media types.
38+
39+
"Work" shall mean the work of authorship, whether in Source or
40+
Object form, made available under the License, as indicated by a
41+
copyright notice that is included in or attached to the work
42+
(an example is provided in the Appendix below).
43+
44+
"Derivative Works" shall mean any work, whether in Source or Object
45+
form, that is based on (or derived from) the Work and for which the
46+
editorial revisions, annotations, elaborations, or other modifications
47+
represent, as a whole, an original work of authorship. For the purposes
48+
of this License, Derivative Works shall not include works that remain
49+
separable from, or merely link (or bind by name) to the interfaces of,
50+
the Work and Derivative Works thereof.
51+
52+
"Contribution" shall mean any work of authorship, including
53+
the original version of the Work and any modifications or additions
54+
to that Work or Derivative Works thereof, that is intentionally
55+
submitted to Licensor for inclusion in the Work by the copyright owner
56+
or by an individual or Legal Entity authorized to submit on behalf of
57+
the copyright owner. For the purposes of this definition, "submitted"
58+
means any form of electronic, verbal, or written communication sent
59+
to the Licensor or its representatives, including but not limited to
60+
communication on electronic mailing lists, source code control systems,
61+
and issue tracking systems that are managed by, or on behalf of, the
62+
Licensor for the purpose of discussing and improving the Work, but
63+
excluding communication that is conspicuously marked or otherwise
64+
designated in writing by the copyright owner as "Not a Contribution."
65+
66+
"Contributor" shall mean Licensor and any individual or Legal Entity
67+
on behalf of whom a Contribution has been received by Licensor and
68+
subsequently incorporated within the Work.
69+
70+
2. Grant of Copyright License. Subject to the terms and conditions of
71+
this License, each Contributor hereby grants to You a perpetual,
72+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
73+
copyright license to reproduce, prepare Derivative Works of,
74+
publicly display, publicly perform, sublicense, and distribute the
75+
Work and such Derivative Works in Source or Object form.
76+
77+
3. Grant of Patent License. Subject to the terms and conditions of
78+
this License, each Contributor hereby grants to You a perpetual,
79+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
80+
(except as stated in this section) patent license to make, have made,
81+
use, offer to sell, sell, import, and otherwise transfer the Work,
82+
where such license applies only to those patent claims licensable
83+
by such Contributor that are necessarily infringed by their
84+
Contribution(s) alone or by combination of their Contribution(s)
85+
with the Work to which such Contribution(s) was submitted. If You
86+
institute patent litigation against any entity (including a
87+
cross-claim or counterclaim in a lawsuit) alleging that the Work
88+
or a Contribution incorporated within the Work constitutes direct
89+
or contributory patent infringement, then any patent licenses
90+
granted to You under this License for that Work shall terminate
91+
as of the date such litigation is filed.
92+
93+
4. Redistribution. You may reproduce and distribute copies of the
94+
Work or Derivative Works thereof in any medium, with or without
95+
modifications, and in Source or Object form, provided that You
96+
meet the following conditions:
97+
98+
(a) You must give any other recipients of the Work or
99+
Derivative Works a copy of this License; and
100+
101+
(b) You must cause any modified files to carry prominent notices
102+
stating that You changed the files; and
103+
104+
(c) You must retain, in the Source form of any Derivative Works
105+
that You distribute, all copyright, patent, trademark, and
106+
attribution notices from the Source form of the Work,
107+
excluding those notices that do not pertain to any part of
108+
the Derivative Works; and
109+
110+
(d) If the Work includes a "NOTICE" text file as part of its
111+
distribution, then any Derivative Works that You distribute must
112+
include a readable copy of the attribution notices contained
113+
within such NOTICE file, excluding those notices that do not
114+
pertain to any part of the Derivative Works, in at least one
115+
of the following places: within a NOTICE text file distributed
116+
as part of the Derivative Works; within the Source form or
117+
documentation, if provided along with the Derivative Works; or,
118+
within a display generated by the Derivative Works, if and
119+
wherever such third-party notices normally appear. The contents
120+
of the NOTICE file are for informational purposes only and
121+
do not modify the License. You may add Your own attribution
122+
notices within Derivative Works that You distribute, alongside
123+
or as an addendum to the NOTICE text from the Work, provided
124+
that such additional attribution notices cannot be construed
125+
as modifying the License.
126+
127+
You may add Your own copyright statement to Your modifications and
128+
may provide additional or different license terms and conditions
129+
for use, reproduction, or distribution of Your modifications, or
130+
for any such Derivative Works as a whole, provided Your use,
131+
reproduction, and distribution of the Work otherwise complies with
132+
the conditions stated in this License.
133+
134+
5. Submission of Contributions. Unless You explicitly state otherwise,
135+
any Contribution intentionally submitted for inclusion in the Work
136+
by You to the Licensor shall be under the terms and conditions of
137+
this License, without any additional terms or conditions.
138+
Notwithstanding the above, nothing herein shall supersede or modify
139+
the terms of any separate license agreement you may have executed
140+
with Licensor regarding such Contributions.
141+
142+
6. Trademarks. This License does not grant permission to use the trade
143+
names, trademarks, service marks, or product names of the Licensor,
144+
except as required for reasonable and customary use in describing the
145+
origin of the Work and reproducing the content of the NOTICE file.
146+
147+
7. Disclaimer of Warranty. Unless required by applicable law or
148+
agreed to in writing, Licensor provides the Work (and each
149+
Contributor provides its Contributions) on an "AS IS" BASIS,
150+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
151+
implied, including, without limitation, any warranties or conditions
152+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
153+
PARTICULAR PURPOSE. You are solely responsible for determining the
154+
appropriateness of using or redistributing the Work and assume any
155+
risks associated with Your exercise of permissions under this License.
156+
157+
8. Limitation of Liability. In no event and under no legal theory,
158+
whether in tort (including negligence), contract, or otherwise,
159+
unless required by applicable law (such as deliberate and grossly
160+
negligent acts) or agreed to in writing, shall any Contributor be
161+
liable to You for damages, including any direct, indirect, special,
162+
incidental, or consequential damages of any character arising as a
163+
result of this License or out of the use or inability to use the
164+
Work (including but not limited to damages for loss of goodwill,
165+
work stoppage, computer failure or malfunction, or any and all
166+
other commercial damages or losses), even if such Contributor
167+
has been advised of the possibility of such damages.
168+
169+
9. Accepting Warranty or Additional Liability. While redistributing
170+
the Work or Derivative Works thereof, You may choose to offer,
171+
and charge a fee for, acceptance of support, warranty, indemnity,
172+
or other liability obligations and/or rights consistent with this
173+
License. However, in accepting such obligations, You may act only
174+
on Your own behalf and on Your sole responsibility, not on behalf
175+
of any other Contributor, and only if You agree to indemnify,
176+
defend, and hold each Contributor harmless for any liability
177+
incurred by, or claims asserted against, such Contributor by reason
178+
of your accepting any such warranty or additional liability.
179+
180+
END OF TERMS AND CONDITIONS
181+
182+
APPENDIX: How to apply the Apache License to your work.
183+
184+
To apply the Apache License to your work, attach the following
185+
boilerplate notice, with the fields enclosed by brackets "[]"
186+
replaced with your own identifying information. (Don't include
187+
the brackets!) The text should be enclosed in the appropriate
188+
comment syntax for the file format. We also recommend that a
189+
file or class name and description of purpose be included on the
190+
same "printed page" as the copyright notice for easier
191+
identification within third-party archives.
192+
193+
Copyright [yyyy] [name of copyright owner]
194+
195+
Licensed under the Apache License, Version 2.0 (the "License");
196+
you may not use this file except in compliance with the License.
197+
You may obtain a copy of the License at
198+
199+
http://www.apache.org/licenses/LICENSE-2.0
200+
201+
Unless required by applicable law or agreed to in writing, software
202+
distributed under the License is distributed on an "AS IS" BASIS,
203+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
204+
See the License for the specific language governing permissions and
205+
limitations under the License.

README.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# openkal-opensbi
2+
3+
An implementation of [openkal][kal] on the RISC-V Supervisor Binary Interface.
4+
5+
```toml
6+
[dependencies]
7+
openkal = "0.5.1"
8+
openkal-opensbi = "0.1.0"
9+
```
10+
11+
## ⭐ The portable RISC-V backend, as distinct from a board's own
12+
13+
A board-supplied backend writes to a device address, and that address is a board
14+
fact. The same binary on a second RISC-V machine writes to something that is not
15+
a UART: it compiles, links, runs, and prints nothing.
16+
17+
SBI has no such property. The console here is a call into firmware that already
18+
knows the machine, so one image runs under OpenSBI on QEMU's `virt` and on a real
19+
board without being rebuilt.
20+
21+
Both kinds are legitimate, and a project chooses by which property it needs: SBI
22+
requires firmware beneath it, a board backend does not.
23+
24+
## What is implemented
25+
26+
`abort`, `stream` and `memory` — openkal's core set. An implementation provides
27+
an interface in whole or not at all, so the absence of `fs`, `process`, `task`,
28+
`env` and `time` is not a deviation; `import openkal.task;` simply does not
29+
resolve.
30+
31+
⚠️ **`time` is absent deliberately, and SBI does have a timer.** SBI can arm a
32+
timer interrupt, which is a mechanism for a kernel rather than a clock a program
33+
can read. Reporting a clock that does not advance would make every timed wait
34+
silently wrong — the specification's own example of a simulation that
35+
disqualifies an interface from being provided at all.
36+
37+
## The heap is a bump allocator, and that is a bound rather than an omission
38+
39+
SBI provides no allocator, so this one hands out from a static region and
40+
`kal_free` does nothing. openkal's criterion admits it: an implementation that
41+
can be exhausted **bounds** what is available, whereas one that makes its callers
42+
silently wrong is a simulation. Exhaustion is a defined outcome — `kal_alloc`
43+
returns null — and every caller already handles it.
44+
45+
The region is 64 KiB by default. A project that needs another figure overrides
46+
`OPENKAL_OPENSBI_HEAP_BYTES` rather than editing this package. A program whose
47+
allocation pattern needs reuse should place a real allocator above this one;
48+
that is policy, and openkal carries mechanism.
49+
50+
## Two details that were measured rather than assumed
51+
52+
**DBCN is probed, not assumed.** The Debug Console extension arrived in SBI
53+
v2.0, and older firmware answers `SBI_ERR_NOT_SUPPORTED` — on which every write
54+
would silently transfer nothing. The legacy one-character extension is the
55+
fallback.
56+
57+
⚠️ **No function-local `static`.** A guarded local static compiles to
58+
`__cxa_guard_acquire`/`__cxa_guard_release`, which a freestanding target has no
59+
runtime to supply. Measured: the link fails naming both. `-fno-threadsafe-statics`
60+
would also silence it, but a flag that has to be remembered is weaker than a
61+
construct that cannot require the runtime in the first place.
62+
63+
## Verified
64+
65+
`examples/hello` runs under QEMU with `-bios default`, which is real OpenSBI:
66+
67+
```
68+
hello from openkal over SBI
69+
heap ok
70+
```
71+
72+
The image carries no C library (`[target.<triple>].sysroot = ""`) and no board
73+
package. It is loaded at `0x80200000`, because OpenSBI itself occupies the start
74+
of RAM.
75+
76+
[kal]: https://github.com/mcpplibs/openkal

examples/hello/build.mcpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import mcpp;
2+
int main() {
3+
// A relative path in `ldflags` would resolve against the build directory;
4+
// `link-script` resolves against the package root.
5+
mcpp::link_script("link.ld");
6+
mcpp::rerun_if_changed("link.ld");
7+
return 0;
8+
}

examples/hello/link.ld

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* OpenSBI hands control to the next stage at 0x80200000: the firmware itself
2+
* occupies 0x80000000 upward, which is why this differs from the `-bios none`
3+
* arrangement where the image is the first thing in RAM. */
4+
ENTRY(_start)
5+
SECTIONS {
6+
. = 0x80200000;
7+
.text : { *(.text.entry) *(.text*) }
8+
.rodata : { *(.rodata*) }
9+
.data : { *(.data*) }
10+
.bss : { __bss_start = .; *(.bss*) *(COMMON) __bss_end = .; }
11+
. = ALIGN(16); . = . + 0x4000; __stack_top = .;
12+
}

examples/hello/mcpp.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "hello"
3+
version = "0.1.0"
4+
5+
[build]
6+
target = "riscv64-none-elf"
7+
8+
# No board package: SBI is the whole environment this program needs, and the
9+
# firmware is what QEMU loads with `-bios default`.
10+
[target.riscv64-none-elf]
11+
sysroot = ""
12+
runner = ["qemu-system-riscv64", "-machine", "virt", "-nographic",
13+
"-no-reboot", "-bios", "default", "-kernel"]
14+
15+
[dependencies]
16+
openkal = "0.5.1"
17+
openkal-opensbi = { path = "../.." }

examples/hello/src/main.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// openkal over SBI, with no C library and no board package beneath it.
2+
//
3+
// ⚠️ The entry point is `_start` and not `main`: nothing here supplies a C
4+
// runtime, so there is no crt0 to call one. OpenSBI hands control to the image
5+
// at its load address in supervisor mode with a stack that the linker script
6+
// below establishes.
7+
import openkal.stream;
8+
import openkal.abort;
9+
import openkal.memory;
10+
11+
namespace {
12+
13+
void say(const char* s) {
14+
kal_uintptr n = 0;
15+
while (s[n]) ++n;
16+
kal_stream_write(kal_stdout(), s, n);
17+
}
18+
19+
} // namespace
20+
21+
extern "C" void kmain() {
22+
say("hello from openkal over SBI\n");
23+
24+
void* p = kal_alloc(64, 16);
25+
say(p ? "heap ok\n" : "heap exhausted\n");
26+
kal_free(p, 64, 16);
27+
28+
// Reaches the host as QEMU's exit status, because SRST is a real shutdown
29+
// rather than a spin.
30+
kal_exit(p ? 0 : 1);
31+
}
32+
33+
asm(".section .text.entry\n.globl _start\n_start:\n"
34+
" la sp, __stack_top\n call kmain\n1: j 1b\n");

0 commit comments

Comments
 (0)