Add ARMv5 and NUC980 support#66
Conversation
|
Please target development branch. |
|
I am not sure I like the overrides and linkhwinit0 flag (the less build flags there are the better), I will ponder a cleaner (at least to me) approach. Go has the GOARM variable which maybe is exposed by runtime to have better conditionals in both .go and .s files? It should be set differently for this target I think. I will check this and propose a different layout. Ideally I would like to keep the current ARMv8 code as identical as possible to the current tested one. |
|
Yes, I was also wondering if there is a better approach to split of the ARMv5 quirks and I'm not fully contempt with this solution either. It does compile fine and I do get code execution. It still gets stuck somewhere on my board so I'm currently debugging this with JTAG but the development pipeline of using JTAG with Go code is still a bit tricky. It was easier to get working on my other port than on this one here. |
|
It looks like there are somewhat underdocumented build tags I could use, so instead of adding new tags I would simply rely on |
|
Added two commits to experiment with that existing build tag |
|
Good news: I got everything working on real hardware now and got TamaGo talking to me on the UART! I did run into an issue with upstream Go though regarding ARMv5 atomics. Might be worth fixing downstream first I guess. I assume I can open a PR to tamago-go so we can discuss if this should go upstream or not? Hello from TamaGo on NUC980!
Runtime : go1.26.1 tamago/arm
Board : NuMaker-IIoT-NUC980G2
SoC : NUC980 PDID 0x0
CPU : ARM926EJ-S MIDR 0x41069265
impl : 0x41 (ARM)
variant : 0x0
arch : 0x6
part : 0x926
rev : 0x5
RAM : 128 MB @ 0x00000000
tick 0
tick 1
tick 2
tick 3
tick 4EDIT: This was the needed fix for ARMv5: MDr164/tamago-go@14103fd |
Any tamago-go contribution must be good for potential upstreaming inclusion, to accept it I'd ask:
As it stands your patch is not suitable as it is too specific to hardware and the Go upstream implementation has been designed to be agnostic. As Go already supports ARM5 I'd like to understand what is the issue that you are trying to solve. Thanks! |
|
Thanks for the review, I updated the toolchain patch here now: MDr164/tamago-go@5aef39e
Done
Good idea, done
I updated the commit message as well. I ran into some undefined instructions on my target as it's ARMv5 and TamaGo is non-linux so it ran into the TODO item I previously removed. Are you suggesting rewriting the interrupt handlers instead?
I suppose it did not really support the situation of having ARMv5 under a non-linux OS working 100%. There was just this one spot in the atomics assembly which was only working for ARMv6+. |
Looks much better thanks. The interrupt handler should not run Go code which requires the runtime, please see the current pattern used in tamago and tamago-go. In fact I am working on riscv64 interrupt handling as we speak for other RV64 targets which have just been included, so allow to me finish that and you can leverage on it. Thanks! |
|
Please see d7cf6ac, 1ad5e0c for interrupt handling. An example implementation is at https://github.com/usbarmory/kotama/blob/5ea39b280fc7b3939d6d93132d276c1e043354fc/cmd/sifive_u.go#L64 |
|
I'm not yet 100% certain the newly added buildtags for either arm.5 or arm.6 are the best way to do this. Other than that I suppose the port is working pretty well now. |
|
Btw I created a small CLI tool that is able to create images that can directly be flashed to the onboard flash or an sd-card. This board does require some DDR2 training data to be present. I pulled that data from their GitHub. |
|
Thanks, I'll start my review next week! |
|
Haven't forgotten about this, just a little swamped but I promise I'll get to it. |
|
No worries, I just noticed a merge conflict with the development branch so I just updated the code to match the past commits. I can at least report that the code has been working well so far and I'm right now working on more drivers and the other PR so I'm also busy in the meantime :) |
|
This week I have time to work on this, can you see and address the pending comments? There have been also some changes that need sync up. Thanks! |
|
Quick summary once you get around reviewing it: I currently use a patched tamago-go toolchain based on your 1.26.2 tag with one commit on top: MDr164/tamago-go@f4bcfd4 Additionally I created a small script that I run locally to create correctly formatted sd-card images for this platform. I have not tested booting it from its internal NAND flash yet but that should work with the current code just fine I assume. I did not push the script into this PR as it felt to be out of scope to me. One thing that tripped me up about GOARM buildtags is that they are apparently cumulative which the doc.go file they are described in doesn't claim. So: That's why I opted for using !arm.6 instead of going for the arm.5 buildtag. |
|
I'll update the code by moving everything to a common place for drivers inside the nuvoton package. I assume if there are other nuvoton chips using different IP cores we can still move things around. Do you think the one commit I got for the Go toolchain is worth adding to tamago-go? I guess if I send it upstream there would be confusion about why I run into this edgecase as it only really affects baremetal targets which aren't upstream yet. |
|
Yes, for starters we can add that commit to tamago-go, I'll ponder it a little more but in time for v1.26.3. |
|
Sorry for the delay, I am testing your tamago-go patch for inclusion, however it fails to pass this test (it hangs): |
|
I think the issue spawns from the fact that the testsuite is not designed for single-core processors without atomic operations, I had to workaround this issue here to enable lack of atomics on smaller RISC-V targets for kotama. I think a similar workaround is needed though I am slightly uncomfortable in having the same approach for upstreaming it as I'd favor a conditional patch which is never touched on other architectures. |
|
Thanks for the feedback, I applied your suggestions and also reorganized the asm as mentioned by moving everything out of the board pkg except the pinmux which is specific to this board. For some reason doing the pinmux and the EarlyClockInit not via asm it fails to apply correctly. The new code has also been validated on my board here. |
|
|
|
I can change pinmux.s to use constants, sure. For the seed value of the PRNG peripheral of the soc I don't think it is worth using the UID. It is not really unique in that sense as all NUC980 chips share the same value from what I read in the datasheet. The closely related NUC970 would have the same peripheral but a different ID for that matter but I'm not sure if having a chip sku specific seed provide any benefit over simply using the timer value. I think even better would be to query one of the ADCs but I think those are also connected on the pinmux only and not internally to some temp sensor of the chip itself. |
Signed-off-by: Marvin Drees <marvin.drees@9elements.com>
I don't quite understand if the PRNG becomes predictable with the same Seed or not. If so we might want to consider panicking if Seed is empty and delegate that decision to board packages. |
I looked deeper into this and found an instruction that is available on real hardware as well as on Qemu that doesn't cause issues. This commit here now works on the actual board and on Qemu. I added the rational in the code as a lenghty comment which you're not a fan of so feel free to strip it out: MDr164/tamago-go@b32a132 |
The datasheet is not really very descriptive to be honest so maybe it is.
I think that would be a fair compromise I'm willing to make, just have the user provide something (e.g. an ADC readout if they know their board as the pinux set with ADC inputs). |
Please use Go assembly for the Please make a PR against https://github.com/usbarmory/tamago-go/tree/tamago1.26.4 for testing and inclusion in the next release, also please consider making an upstream PR to Go given that |
For now I'd simply use |
|
Additionally I think PRNG should allow re-seeding at runtime, so probably |
Yes, it's an upstream issue but as my commit message mentioned it current doesn't show up upstream as Linux has a helper to mitigate the problem. Tamago/baremetal would be the first user of this path. While I agree that it should land upstream for sure I'm not 100% certain if it's accepted if there are not situations upstream where this assembly fixes an issue other than in baremetal environments. I can try though. |
Makes sense, the vendors Linux driver simply uses the kernel jiffies as a seed with no way to change/override it. So in some sense we got parity but I agree that we could do better. |
Then let us keep it as part of our upstreaming proposal given that it's only specific to us. Thanks for clarifying. I assume there are no !Linux GOARM=5 supported platforms upstream then? |
By the way FIPS mode is implemented under TamaGo, just like in Go, and uses memory jiffies for entropy. Though this is for compliance and I cannot comment on its security, still an option for users to enable. |
Well it's specific to non-linux armv5 which tamago seems to be the first candidate.
Looks like it, or other operating systems also install helpers to catch the instructions that wouldn't work standalone but I only saw Linux mentioned upstream in the source. |
|
Added a commit to allow calling |
c73df52 to
ce9a19f
Compare
Signed-off-by: Marvin Drees <marvin.drees@9elements.com>
|
Merged, thanks for your patience in addressing my review and this contribution overall! |
Likewise thanks for the reviews and patience with my iterations. With the learnings I'll make sure the next ports will be much more smooth :) |
|
We broke GoTEE by initializing features after the vector table. Can you test if this patch doesn't break ARMv5/NUC980 please, it fixes GoTEE and it seems to me the best way to go about this: diff --git a/arm/arm.go b/arm/arm.go
index cbae403..a82e4ba 100644
--- a/arm/arm.go
+++ b/arm/arm.go
@@ -86,8 +86,8 @@ func (cpu *CPU) Init() {
goos.Exit = exit
goos.Idle = cpu.DefaultIdleGovernor
- cpu.initVectorTable()
cpu.initFeatures()
+ cpu.initVectorTable()
}
// Mode returns the processor mode.
diff --git a/arm/features.go b/arm/features.go
index da6781b..491ecb9 100644
--- a/arm/features.go
+++ b/arm/features.go
@@ -22,6 +22,11 @@ const (
ID_PFR1_GENERIC_TIMER_MASK = 0xf0000
)
+// ARM architecture versions
+const (
+ MIDR_ARCH_ARMV6 = 0b0111
+)
+
// defined in features.s
func read_midr() uint32
func read_idpfr0() uint32
@@ -36,7 +41,7 @@ func (cpu *CPU) MIDR() uint32 {
func (cpu *CPU) initFeatures() {
// Do not set read features on cores with fixed exception vectors (e.g.
// ARMv5) which have no CP15 feature ID registers.
- if cpu.vbar == 0 {
+ if read_midr() < MIDR_ARCH_ARMV6 {
return
}
|
|
The MIDR call returns a value that is higher for some reason on the NUC980. Let me quickly try to create a better comparison check in EDIT ok found it, the MIDR value contains several fields and we only need to compare bits 16 to 19 and not all of them: https://arm.jonpalmisc.com/latest_sysreg/AArch32-midr |
This adds the Nuvoton NUC980 and one of its reference boards the NuMaker-IIoT-NUC980 which is a low cost ARM9 (ARMv5) based SoC used in some iBMC aka industrial or 'edge' BMC solutions by several manufacturers. The datasheet and software (u-boot + Linux) are publicly available from Nuvoton. I'll add a guide on how to test this on hardware including logs a bit later once everything works as intended. Opening a draft PR for initial discussion.