Full .NET 8 on an embedded device

Thread Starter

Vidget

Joined Feb 16, 2024
4
Brand new device that runs FULL .NET 8 right out of the box.

 
Last edited by a moderator:

ApacheKid

Joined Jan 12, 2015
1,612
Thanks. Most of use expect something like this on the hardware documentation side: https://ww1.microchip.com/downloads...0A-WFI32-IoT-Board-Users-Guide-DS50003262.pdf
https://www.st.com/resource/en/refe...ed-armbased-32bit-mpus-stmicroelectronics.pdf

I will say that I am not clear yet on exactly how these STM32 devices are meant to be leveraged here. There are some abstractions available in the Iot namespaces of some MS libraries but these to not seem to map to specific MCU capabilities. I also tried to access raw peripheral memory but could not, I suspect that the .Net CLR is being hosted as a Linux process and so Linux is running on the board and limiting access to the physical device.

.Net supports "unsafe" pointer access to memory but this is not being permitted in the tests I have done.
 
Last edited:

nsaspook

Joined Aug 27, 2009
13,291
https://www.st.com/resource/en/refe...ed-armbased-32bit-mpus-stmicroelectronics.pdf

I will say that I am not clear yet on exactly how these STM32 devices are meant to be leveraged here. There are some abstractions available in the Iot namespaces of some MS libraries but these to not seem to map to specific MCU capabilities. I also tried to access raw peripheral memory but could not, I suspect that the .Net CLR is being hosted as a Linux process and so Linux is running on the board and limiting access to the physical device.

.Net supports "unsafe" pointer access to memory but this is not being permitted in the tests I have done.
Yes, it's a MS-Linux sandbox. They should be required to release the Linux source port to the hardware platform. From that most of the hardware interfaces can be reversed-engineered easily as it looks to be rather nice for the price.
 

ApacheKid

Joined Jan 12, 2015
1,612
Yes, it's a MS-Linux sandbox. They should be required to release the Linux source port to the hardware platform. From that most of the hardware interfaces can be reversed-engineered easily as it looks to be rather nice for the price.
It's very interesting but not clear to me. The OS has no need to concern itself with the peripherals at all, so the peripheral memory need not be restricted to kernel mode code particular when using managed code (where illegal pointers are impossible).

On the other hand restricting access to that memory is fine if there's another means to access the registers which is where an more low level abstraction is called for.

Perhaps it'll make more sense after I've spent more time with it...
 

nsaspook

Joined Aug 27, 2009
13,291
It's very interesting but not clear to me. The OS has no need to concern itself with the peripherals at all, so the peripheral memory need not be restricted to kernel mode code particular when using managed code (where illegal pointers are impossible).

On the other hand restricting access to that memory is fine if there's another means to access the registers which is where an more low level abstraction is called for.

Perhaps it'll make more sense after I've spent more time with it...
The Linux OS is likely doing the standard things of abstracting the actual IC level hardware to the standard Linux device and protocol API for things like GPIO, SPI, CAN, timers, counters, etc ... Those peripherals and peripheral memory need to privileged at the OS kernel level to prevent a host of easily exploited security vectors and hacks known for decades. Like Windows, Linux does not allow an arbitrary application program to access I/O ports as it pleases.
 

ApacheKid

Joined Jan 12, 2015
1,612
The Linux OS is likely doing the standard things of abstracting the actual IC level hardware to the standard Linux device and protocol API for things like GPIO, SPI, CAN, timers, counters, etc ... Those peripherals and peripheral memory need to privileged at the OS kernel level to prevent a host of easily exploited security vectors and hacks known for decades. Like Windows, Linux does not allow an arbitrary application program to access I/O ports as it pleases.
Right, but this should ideally be optional. Running managed code on an MCU should not mean we have to rely on an OS to oversee peripheral usage.

I should be able to manipulate device registers in C# as easily as I can in C or C++, that's what I'm getting at here. They likely need an OS in order for the CLR to exist, so I understand that, but the OS should provide only what's necessary for the CLR to work (threads primarily) and nothing more.

Besides the managed code indirectly accesses device memory through .Net interop, it relies on an open source library coded in C++ named "libgpiod". Somewhere inside that native library is a call that enables R/W access to the memory that contains the registers...I don't think Unix/Linux as such ordinarily manage GPIO, ADC, etc as formal OS devices but I could be wrong (Windows does not)
 
Last edited:

nsaspook

Joined Aug 27, 2009
13,291
Right, but this should ideally be optional. Running managed code on an MCU should not mean we have to rely on an OS to oversee peripheral usage.

I should be able to manipulate device registers in C# as easily as I can in C or C++, that's what I'm getting at here. They likely need an OS in order for the CLR to exist, so I understand that, but the OS should provide only what's necessary for the CLR to work (threads primarily) and nothing more.

Besides the managed code indirectly accesses device memory through .Net interop, it relies on an open source library coded in C++ named "libgpiod". Somewhere inside that native library is a call that enables R/W access to the memory that contains the registers...
Thinking like that is why there is an S for Security in IoT.

I don't have a problem with bare-metal access and programming. That's why I'm asking for the hardware details and release of the Linux source for this board.
 
Last edited:

ApacheKid

Joined Jan 12, 2015
1,612
I'm finding this platform, extremely interesting. The full C# language is very expressive and well suited to control-like code. That board though uses "standard" IoT libraries that abstract stuff like GPIO, UART etc but I can also see those libraries are reliant on interop (into C functions) and rely on Linux for "driver" support.

C# has support for "references" akin to pointers but not dangerous in the way pointers can be (invalid addresses can be generated much more easily with pointers).

So I wrote some basic test code akin to some of the stuff I was doing in C recently and I can do bit banging at about 200 time the rate a basic conventional IoT library can do it.

C# lets me define structures that also expose properties (get/set methods) so a struct can expose methods and properties that abstract registers. I can generate a reference to the structure type, from a register address and then easily modify/read register fields by using these accessors.

Extremely interesting stuff!
 

nsaspook

Joined Aug 27, 2009
13,291
I'm finding this platform, extremely interesting. The full C# language is very expressive and well suited to control-like code. That board though uses "standard" IoT libraries that abstract stuff like GPIO, UART etc but I can also see those libraries are reliant on interop (into C functions) and rely on Linux for "driver" support.

C# has support for "references" akin to pointers but not dangerous in the way pointers can be (invalid addresses can be generated much more easily with pointers).

So I wrote some basic test code akin to some of the stuff I was doing in C recently and I can do bit banging at about 200 time the rate a basic conventional IoT library can do it.

C# lets me define structures that also expose properties (get/set methods) so a struct can expose methods and properties that abstract registers. I can generate a reference to the structure type, from a register address and then easily modify/read register fields by using these accessors.

Extremely interesting stuff!
Standard vanilla cake stuff with a fluffy IoT topping on the top.

Thanks for reminding me about this thread. I'm still waiting for a response for hardware and Linux source info.
 

ApacheKid

Joined Jan 12, 2015
1,612
Standard vanilla cake stuff with a fluffy IoT topping on the top.

Thanks for reminding me about this thread. I'm still waiting for a response for hardware and Linux source info.
Well look at this, a simple bit banging example:

C#:
public static void PulseViaDirect()
{
    using var rcc   = Peripheral.CreateRcc(RccAddress.RCC);
    using var gpioa = Peripheral.CreateGpio(GpioAddress.GPIOA);

    rcc.MP_AHB4ENSETR[0] = true;

    gpioa.MODER[4] = ModerMode.Output;
    gpioa.OSPEEDR[4] = SpeedMode.VeryHigh;

    while (true)
    {
        gpioa.BSRR = 0x00000010;
        gpioa.BSRR = 0x00100000;
    }
}
Here's the native equivalent:


C#:
int32_t wave(uint32_t addr)
{
    uint32_t * ptr = (uint32_t*)(addr);

    while (1)
    {
        *ptr = 0x00000010;
        *ptr = 0x00100000;
    }

    return 0;
}
Each of these generates the same frequency signal:

1709823789761.png

C# has changed over the years and has seen increasing support for low level code. The C# code uses no explicit pointers, and has various optimizations there really is no difference between those two code fragments in terms of execution speed. The top code is the beginning of a small library I'm working on, one that makes maximum use of C# features yet doesn't compromise on performance.

Of course you need more resources to host the CLR (and in this case Linux).
 

Attachments

nsaspook

Joined Aug 27, 2009
13,291
Well look at this, a simple bit banging example:

C#:
public static void PulseViaDirect()
{
    using var rcc   = Peripheral.CreateRcc(RccAddress.RCC);
    using var gpioa = Peripheral.CreateGpio(GpioAddress.GPIOA);

    rcc.MP_AHB4ENSETR[0] = true;

    gpioa.MODER[4] = ModerMode.Output;
    gpioa.OSPEEDR[4] = SpeedMode.VeryHigh;

    while (true)
    {
        gpioa.BSRR = 0x00000010;
        gpioa.BSRR = 0x00100000;
    }
}
Here's the native equivalent:


C#:
int32_t wave(uint32_t addr)
{
    uint32_t * ptr = (uint32_t*)(addr);

    while (1)
    {
        *ptr = 0x00000010;
        *ptr = 0x00100000;
    }

    return 0;
}
Each of these generates the same frequency signal:

View attachment 317069

C# has changed over the years and has seen increasing support for low level code. The C# code uses no explicit pointers, and has various optimizations there really is no difference between those two code fragments in terms of execution speed. The top code is the beginning of a small library I'm working on, one that makes maximum use of C# features yet doesn't compromise on performance.

Of course you need more resources to host the CLR (and in this case Linux).


With likely the same backend optimizer is hard for them not to produce the same ASM for the actual loop. I just want the hardware and Linux details for some bare-metal probing info.
 

ApacheKid

Joined Jan 12, 2015
1,612
With likely the same backend optimizer is hard for them not to produce the same ASM for the actual loop.
Possibly but that C# is managed code, running in the CLR VM and the compiler and Jitter created by Microsoft is distinct from the one I used to compile the C code (that's arm-none-linux-gnueabihf) Those assignments to gpioa.BSRR are not to a field either, they are to a C# set property that encapsulates the access to the specific bits in that register (well, in that example it's all bits for BSRR).

The capabilities of this language go far beyond C++ and Java too. Look at those square brackets:

C#:
clock.MP_AHB4ENSETR[GpioPort.A] = true;
That's not an array, it's an indexer setter property and can only be indexed by an enum member for that specific enum. Some of the fields in some of the registers are read only, so we can use getter properties only, then it is impossible to write to the field.

Look at this too:
C#:
gpioa.EditRegister(ref gpioa.OSPEEDR, (ref OSPEEDR reg) =>
                   {
                       reg[2] = Speed.Medium;
                       reg[3] = Speed.VeryHigh;
                   }
                  );
That passes a reference to the OSPEEDR register as well as lambda function, inside EditRegister we copy the register's value, call the caller's edit lambda method to manipulate that copy and then take that final value and write it to the original register, so all bits get updated in a single write. So the pattern of copying a reg an updating its bits in distinct steps then writing that final result to the register in one blast, is nicely encapsulated.

I'm designing this as I sit here, it's the first time I've had a powerful language like C# able to directly manipulate MCI registers so there are lots of ideas coming up (like EditRegister).

I just want the hardware and Linux details for some bare-metal probing info.
Nobody has answered you? I have a terminal session logged into the board, is there anything I can find out for you? e.g.

1709838229096.png
 
Last edited:

nsaspook

Joined Aug 27, 2009
13,291
Possibly but that C# is managed code, running in the CLR VM and the compiler and Jitter created by Microsoft is distinct from the one I used to compile the C code (that's arm-none-linux-gnueabihf) Those assignments to gpioa.BSRR are not to a field either, they are to a C# set property that encapsulates the access to the specific bits in that register (well, in that example it's all bits for BSRR).

The capabilities of this language go far beyond C++ and Java too. Look at those square brackets:

C#:
clock.MP_AHB4ENSETR[GpioPort.A] = true;
That's not an array, it's an indexer setter property and can only be indexed by an enum member for that specific enum. Some of the fields in some of the registers are read only, so we can use getter properties only, then it is impossible to write to the field.

Look at this too:
C#:
gpioa.EditRegister(ref gpioa.OSPEEDR, (ref OSPEEDR reg) =>
                   {
                       reg[2] = Speed.Medium;
                       reg[3] = Speed.VeryHigh;
                   }
                  );
That passes a reference to the OSPEEDR register as well as lambda function, inside EditRegister we copy the register's value, call the caller's edit lambda method to manipulate that copy and then take that final value and write it to the original register, so all bits get updated in a single write. So the pattern of copying a reg an updating its bits in distinct steps then writing that final result to the register in one blast, is nicely encapsulated.

I'm designing this as I sit here, it's the first time I've had a powerful language like C# able to directly manipulate MCI registers so there are lots of ideas coming up (like EditRegister).



Nobody has answered you? I have a terminal session logged into the board, is there anything I can find out for you? e.g.

View attachment 317117
You're explaining that like the compiler/linker optimizer gives a damn about the source level code presentation of the ASM statements needed to execute that fundamental set of code requirements to load/store X datum in X memory location and goto X location. I would be shocked if there was a difference for such a simple to reduce to ASM task with decent HLL build tools.


Nope, I want their source code build diffs for that SoC hardware and a real schematic of the board so I can built the (or a custom version of) kernel. That's a must have for serious embedded using similar platforms in a zero trust environment.
https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-207.pdf
 
Last edited:

ApacheKid

Joined Jan 12, 2015
1,612
You're explaining that like the compiler/linker optimizer gives a damn about the source level code presentation of the ASM statements needed to execute that fundamental set of code requirements to load/store X datum in X memory location and goto X location. I would be shocked if there was a difference for such a simple to reduce to ASM task with decent HLL build tools.


Nope, I want their source code build diffs for that SoC hardware and a real schematic of the board so I can built the (or a custom version of) kernel. That's a must have for serious embedded using similar platforms in a zero trust environment.
https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-207.pdf
The C# compiler doesn't produce CPU specific instructions, it produces IL, abstract instructions that are consumed by the .net runtime which has a JIT code generator for whatever target.

https://en.wikipedia.org/wiki/Common_Intermediate_Language
 
Top