Quick Start

Last updated: August 13th, 2018

Download

To get started fast, download the Hermes example project linked below. This has a pre-configured project with a stable version of the Hermes hypervisor running some demo guests.

To get the newest version of Hermes with custom drivers, you can follow the steps below in the Project Setup section.

Download Example Project

Project Setup

Creating a project from scratch that uses the Hermes hypervisor isn't too hard — it should only take about 30 minutes. This is the best way to start from a clean slate with up-to-date drivers and other software.

Create New Project

Create a new ASF C project in Atmel Studio.

elegant icons

Pick the right MCU/board. I'm using the SAME70 Xplained. Click OK to get the standard blank project setup with a main.c file and a bunch of other junk in it, including the ASF drivers.

elegant icons

Clone Hermes Source

Go back to Atmel Studio, right click on the src directory in the Solution Explorer (usually on the right side of screen), and click Add → New Folder.

elegant icons

Now right-click on the new hermes folder you created and click Open Folder. This will open up the folder in Windows Explorer. Right-click inside the hermesfolder that this opens up and click Git Clone.

elegant icons

In the Tortoise Git dialog box, paste in the URL for the Hermes repo source. You will need to edit the directory that the repo will be checked out to. In the screenshot below, Tortoise Git wants to check the repo out to C:\...\test\src\hermes\hermes. Be sure to remove the second hermes from the checkout path. See screenshots below for the correct checkout path. Click OK and check out the source into your project folder.

elegant icons elegant icons You'll probably also want to check out the most recent Hermes code. Right-click in your hermes directory and choose TortoiseGit → Switch/Checkout. Then choose the development branch and click OK.

elegant icons

Add Files to Project

Go back to Atmel Studio, right click on the hermes directory in the Solution Explorer, and click Add → Existing Files. elegant icons

Now select all the files you checked out in the hermes directory. You now have all the files in place, but you need to make some modifications to the startup code.

Set Up a Guest

We will now configure the vector table to boot into Hermes and initialize the project's main() function as a guest inside Hermes. In the Solution Explorer, search for a file called startup_same70.c. This is the startup code for the example project that contains the vector table and the startup code. Open this file up.

elegant icons

About Startup Code

A project can contain more than one guest. Each guest needs four components:

  • Vector table (startup_same70.c)
  • Stack
  • Startup code (startup_same70.c)
  • Program code (main.c)
This section explains how to set these components up for a guest, and these steps can be replicated to add new guests by duplicating startup_same70.c.

First, find the vector table in startup_same70.c and comment out the line __attribute__ ((section(".vectors"))) . This should be on or about line 190 of the unmodified C-file.

This line tells the C compiler to put the vector table at a specific address in memory where the CPU will look for it on boot. In order to make the CPU boot into Hermes, we need to put the Hermes vector table at that address, hence commenting this line out. We still need to keep this vector table, but we just don't want it to be located at the vector table address on boot.

Next, we will statically allocate a stack for this guest as a C array. Just above the beginning of exception_table, define char guest1_stack[GUEST1_STACK_SIZE] as in the code example below. A stack size of 4k usually works well, but this will be application-dependent. You may want to move the #define for the stack size to a different location.

Vector Table

/* Exception Table */
//__attribute__ ((section(".vectors")))
#define GUEST1_STACK_SIZE 4096
char guest1_stack[GUEST1_STACK_SIZE];
const DeviceVectors exception_table = {

        /* Configure Initial Stack Pointer, using linker-generated symbols */
        .pvStack = (void*) (&guest1_stack[0]+GUEST1_STACK_SIZE),

        .pfnReset_Handler      = (void*) Reset_Handler,
        .pfnNMI_Handler        = (void*) NMI_Handler,
        .pfnHardFault_Handler  = (void*) HardFault_Handler,
        .pfnMemManage_Handler  = (void*) MemManage_Handler,
        .pfnBusFault_Handler   = (void*) BusFault_Handler,
                                    

The last thing that needs to be done is to comment out some lines in the guest's startup code. These lines initialize some of the variables in memory on boot. This will be handled by Hermes, and it does not need to be replicated here. The lines to comment out are shown in the code snippet below. They start at or about line 392 of startup_same70.c. Comment out code starting at the beginning of Reset_Handler up to the call to __libc_init_array().

The last thing we need to do is to set the guest's vector table offset register (VTOR). This sets the address of the virtual machine's vector table. The stock startup code uses a method of setting the vector table that is incompatible with Hermes, so we will need to change it. After the commented code (which contains with the VTOR assignment) add SCB->VTOR = ((uint32_t)&exception_table); followed by asm("isb"); This explicitly sets the VM's VTOR to the address of exception_table (which we modified above).

Startup Code


/**
 * \brief This is the code that gets_g2 called on processor reset.
 * To initialize the device, and call the main_g2() routine.
 */
void Reset_Handler(void)
{
        uint32_t *pSrc, *pDest;
#if 0
        /* Initialize the relocate segment */
        pSrc = &_etext;
        pDest = &_srelocate;

        if (pSrc != pDest) {
                for (; pDest < &_erelocate;) {
                        *pDest++ = *pSrc++;
                }
        }

        /* Clear the zero segment */
        for (pDest = &_szero; pDest < &_ezero;) {
                *pDest++ = 0;
        }
        /* Set the vector table base address */
        pSrc = (uint32_t *) & _sfixed;
        SCB->VTOR = ((uint32_t) pSrc & SCB_VTOR_TBLOFF_Msk);

        /* Initialize the C library */
        __libc_init_array();
#endif

        SCB->VTOR = ((uint32_t)&exception_table);
        asm("isb");

                                    

DONE!!! This modified file contains (1) a stack, (2) a vector table, and (3) a call to the guest's main() function (just below the startup code snippet we commented out). You can write whatever code you want in main(), compile and run.

To make a new guest

  1. Duplicate the modified startup_same70.c
  2. Change the name of the exception_table, Reset_Handler, guest1_stack, and Dummy_Handler (at the end of startup_same70.c) so those symbols don't collide when linking. The compiler won't let you have two functions both called Reset_Handler in the same binary.
  3. Change the call at the end of Reset_Handler to the new guest's main() function. You'll have to rename that function too, something like main_g2() so it doesn't collide when linking.

Any questions?

Instance Theme

If you're running into problems, get in touch.

naklingensmi at wisc dot edu