Experimental patch for core::sync::atomic on RISCV32I

master
WangRunji 6 years ago
parent a09be9cc40
commit 87b7ea523b

@ -144,6 +144,10 @@ build/user/%.o: user/%.img
@mkdir -p $(shell dirname $@) @mkdir -p $(shell dirname $@)
@$(ld) -r -b binary $< -o $@ @$(ld) -r -b binary $< -o $@
# patch Rust core for RISCV32I atomic
patch-core:
@patch -p0 /rust/rust-riscv-rust-1.26.0-1-dev/src/libcore/sync/atomic.rs src/arch/riscv32/atomic.patch
# used by docker_* targets # used by docker_* targets
docker_image ?= blog_os docker_image ?= blog_os
tag ?= 0.1 tag ?= 0.1

@ -9,27 +9,39 @@
## Rust-RISCV ## Rust-RISCV
### 目标指令集RISCV32IMA ### 目标指令集RISCV32IM
target: riscv32ima_unknown_none target: riscv32im_unknown_none
由于工具链二进制版本尚未内置此target因此需提供配置文件`riscv32-blog_os.json`。 由于工具链二进制版本尚未内置此target因此需提供配置文件`riscv32-blog_os.json`。
理想情况下目标指令集应为RISCV32G即使用全部扩展。但考虑到要把它跑在我们自己实现的CPU上指令集应该尽量精简即最好是RISCV32I。此外 理想情况下目标指令集应为RISCV32G即使用全部扩展。但考虑到要把它跑在我们自己实现的CPU上指令集应该尽量精简即最好是RISCV32I。此外
* 为什么用原子指令扩展? * 为什么用乘除指令扩展?
RustOS依赖的库中大部分都使用了Rust核心库的原子操作core::sync::atomic Rust核心库中fmt模块会使用乘除运算若不使用乘除指令则会依赖LLVM提供的内置函数进行软计算导致链接错误。这一问题理论上可以通过在xargo中设置依赖compiler-builtin解决。但如此操作后仍有一个函数`__mulsi3`缺失32×32。经查compiler-builtin中实现了类似的`__muldi3`函数64×64),所以理论上可以用它手动实现前者。但如此操作后,还是不对,实验表明`__muldi3`本身也是不正确的
如果目标指令集不支持原子操作,会导致无法编译。 总之没有成功配置不使用M扩展的编译环境不过日后解决这一问题并不困难。
### 原子操作支持
然而LLVM后端尚不完全支持原子指令扩展因此这条路可能走不通需要魔改Rust标准库。 配置文件中与原子操作相关的有两处:
* 为什么用乘除指令扩展? * `feature`中`+a`使用A指令扩展
* `max-atomic-width`决定能否使用core中的atomic模块设为0不可以设为32可以
Rust核心库中fmt模块会使用乘除运算若不使用乘除指令则会依赖LLVM提供的内置函数进行软计算导致链接错误。这一问题理论上可以通过在xargo中设置依赖compiler-builtin解决。但如此操作后仍有一个函数`__mulsi3`缺失32×32。经查compiler-builtin中实现了类似的`__muldi3`函数64×64),所以理论上可以用它手动实现前者。但如此操作后,还是不对,实验表明`__muldi3`本身也是不正确的 二者是否相关,还不能确定
总之没有成功配置不使用M扩展的编译环境不过日后解决这一问题并不困难。 * 一方面,`riscv-rust/rust`官方配置中,二者是相关的。
* 另一方面即使不使用A指令扩展设置`max-atomic-width=32`也可以编译通过。经检查生成的代码中包含了fence指令。这说明RISCV32I也可以用实现基本同步操作
然而由于LLVM后端对RISCV原子操作支持不完善无论是否`+a`当使用Mutex时它会调用core中的`atomic_compare_exchange`函数LLVM会发生错误。
鉴于更改上层实现替换Mutex工程难度较大我尝试直接修改core代码将上述问题函数手动实现。
思路是在关中断环境下,用多条指令完成目标功能。这对于单核环境应该是正确的。
我做了个[补丁](../src/arch/riscv32/atomic.patch)在进入docker环境后可运行`make patch-core`应用补丁确保clear后再build。
## BootLoader ## BootLoader

@ -7,7 +7,7 @@
"os": "none", "os": "none",
"arch": "riscv", "arch": "riscv",
"cpu": "generic-rv32", "cpu": "generic-rv32",
"features": "+m,+a", "features": "+m",
"max-atomic-width": "32", "max-atomic-width": "32",
"linker": "ld.lld", "linker": "ld.lld",
"linker-flavor": "ld", "linker-flavor": "ld",

@ -0,0 +1,52 @@
--- atomic_backup.rs 2018-07-10 00:29:48.000000000 +0800
+++ atomic.rs 2018-07-10 00:49:04.000000000 +0800
@@ -1618,29 +1618,29 @@
}
#[inline]
-unsafe fn atomic_compare_exchange<T>(dst: *mut T,
+#[cfg(target_arch = "riscv")]
+unsafe fn atomic_compare_exchange<T: PartialEq>(dst: *mut T,
old: T,
new: T,
- success: Ordering,
- failure: Ordering)
+ _success: Ordering,
+ _failure: Ordering)
-> Result<T, T> {
- let (val, ok) = match (success, failure) {
- (Acquire, Acquire) => intrinsics::atomic_cxchg_acq(dst, old, new),
- (Release, Relaxed) => intrinsics::atomic_cxchg_rel(dst, old, new),
- (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel(dst, old, new),
- (Relaxed, Relaxed) => intrinsics::atomic_cxchg_relaxed(dst, old, new),
- (SeqCst, SeqCst) => intrinsics::atomic_cxchg(dst, old, new),
- (Acquire, Relaxed) => intrinsics::atomic_cxchg_acq_failrelaxed(dst, old, new),
- (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_failrelaxed(dst, old, new),
- (SeqCst, Relaxed) => intrinsics::atomic_cxchg_failrelaxed(dst, old, new),
- (SeqCst, Acquire) => intrinsics::atomic_cxchg_failacq(dst, old, new),
- (__Nonexhaustive, _) => panic!("invalid memory ordering"),
- (_, __Nonexhaustive) => panic!("invalid memory ordering"),
- (_, AcqRel) => panic!("there is no such thing as an acquire/release failure ordering"),
- (_, Release) => panic!("there is no such thing as a release failure ordering"),
- _ => panic!("a failure ordering can't be stronger than a success ordering"),
- };
- if ok { Ok(val) } else { Err(val) }
+ let sstatus: usize;
+ asm!("csrrs $0, 0x100, x0" : "=r"(sstatus) ::: "volatile");
+ // Disable interrupt: sstatus::clear_sie()
+ asm!("csrrc x0, 0x100, $0" :: "r"(1) :: "volatile");
+
+ let ret = atomic_load(dst, Ordering::Relaxed);
+ if ret == old {
+ atomic_store(dst, new, Ordering::Relaxed);
+ }
+
+ let sie = sstatus & 1 != 0;
+ if sie {
+ // Enable interrupt: sstatus::set_sie()
+ asm!("csrrs x0, 0x100, $0" :: "r"(1) :: "volatile");
+ }
+ Ok(ret)
}
#[inline]
Loading…
Cancel
Save