Bare Metal Tutorial

Is there a detailed bare metal tutorial anywhere?

The links and YouTube videos seems to be a little vague in details.

Thank you!

Maybe I should give more details…

I was able to make a project in SoftConsole

and I was able to make a config.yaml file

I’m having problems with the HSS Payload Generator and I’m trying to understand how things work in regards to loading specific functions to their respective harts/cores, e.g.- u54_1(), u54_2(), etc.

Hey @MisterHemi

Unfortunately the YouTube videos and Webinar series are what we have in terms of demos/tutorials.

To try and give you a bit of information (let me know if you need more) there are a few things that happen / need to be done:

  1. IMAGE_LOADED_BY_BOOTLOADER needs to be defined in the mss_sw_config.h file - this will tell the payload application its being loaded by a bootloader and doesn’t need to do any hardware configuration (e.g DDR training, setting up clocks and setting up the MSS I/O).
  2. MPFS_HAL_FIRST_HART and MPFS_HAL_LAST_HART need to be set correctly for your application depending on the harts being used.
  3. Once you’ve done this and you build your application you can include it in your yaml file
  4. Once you’ve generated a payload and programmed it to storage, when the HSS starts up it will configure the hardware and the copy the payload to its desired memory
  5. Once the payload copy is completed the owner harts of the payload (specified in the .yaml file) will jump to the start of the payload and start executing the code contained in it.

This basically gets you to this initialization code in the MPFS HAL which will initialize memory and then jump to main of the application.

I hope this has helped a bit, let me know if you need more detail :slight_smile:

1 Like

First, thank you for your reply!

Ok… that clarifies a few things…

A few questions:

  1. For each hart to have it’s own payload, I’d have to make a separate project for each one in SoftConsole so there are individual .ELF files for each one.

I suppose these projects would share a common root directory so they can be found easily when using the HSS Payload Generator and in the .YAML file it would look something like this:

<hart 1 project><Binaries>\hart1.elf
<hart 2 project><Binaries>\hart2.elf
<hart 3 project><Binaries>\hart3.elf
<hart 4 project><Binaries>\hart4.elf

Correct???

  1. When using the HSS Payload Generator the config.yaml file should be in the and the output.bin file once it’s generated will also be in the same directory?

  2. I’ve noticed in some of the examples there are source files such as:
    e51.c with a function “void e51(void)” rather than “void main(void)”
    and the same u54_1.c, u54_2.c, u54_3.c and u54_4.c

So is a “main()” function necessary or just a function titled the same as the hart? e.g.- void u54_1(void)

My assumption is if each hart’s software is in different projects then a main() function would be necessary, correct?

  1. For each hart to have it’s own payload, I’d have to make a separate project for each one in SoftConsole so there are individual .ELF files for each one.

Yes you’ll need a separate project for each one - you could be sneaky and do all of the individual applications (if they’re bare metal) in the same SoftConsole project and have them operate independently but this could be more confusing then just having individual projects.

  1. When using the HSS Payload Generator the config.yaml file should be in the and the output.bin file once it’s generated will also be in the same directory?

You can pass paths to the payload generator (I can’t remember off the top of my head but it should support full or relative paths) so if everythings in the same directory you could do:

$ ./hss-payload-generator -c config.yaml output.bin

(You can also use paths in the config.yaml file)

or if things are being stored elsewhere you could do:

$ ./hss-payload-generator -c /home/user/blah/config.yaml /home/user/blah/output.bin

paths in the .yaml are set when you define the payload:

**test/baremetal.elf**: {exec-addr: '0xB0000000', owner-hart: u54_3, priv-mode: prv_m, skip-opensbi: true}

So is a “main()” function necessary or just a function titled the same as the hart? e.g.- void u54_1(void)

The e51() and u54_x() functions are the equivalent to main - theres a webinar running through the system startup here its a bit out of date but still gets the key points across. Basically the main first hart will end up in system_startup.c and then if there are other harts in the payload it’ll wake them up and then they’ll jump to the functions named after them based on their hart ID and so will the main first hart.

My assumption is if each hart’s software is in different projects then a main() function would be necessary, correct?

You should really be ok to just use the functions named after each hart (even if you just use 1) as they’ll check their hart ID and then jump to that function. You could put in a main if you want but you’d have to jump to it from the U54_x function or link it in place of the U54_x function.

Thank you!

That explains a lot and I’ll check out the webinar too.