RISC-V target for ChipWhisperer bringup

For quite a while now, we’ve been interested in running side-channel analysis against RISC-V core. RISC-V is the new child on the block not only in the world of microcontrollers, but also full-blown application processors and softcores. We finally got a hold of a custom-built RISC-V-based target board for ChipWhisperer UFO Target Board (CW308) based on SiFive FE310 microcontroller.

What’s on board?

The board fits the standard CW308T form factor. It features SiFive FE310-000 microcontroller, FT2232HL for easier external JTAG access and 128 MBit of external Flash (ISSI IS25LP128-JBLE). A pair of jumpers lets you select whether RX/TX is connected to GPIO1/2 pins or to FT2232HL. The central jumper header allows to either connect external debug probe or use the onboard FT2232HL. Board schematics can be found on it’s author’s github (https://github.com/adamws/cw-fe310-target).

The board closely resembles HiFive1 development board by SiFive. For initial bringup we’ve chosen to use SiFive’s Freedom E SDK targeting that board.

Setting up the environment

The process of setting up Freedom E SDK on Linux was quite straightforward and basically boiled down to cloning recursively a common git repository from GitHub (https://github.com/sifive/freedom-e-sdk.git). In the past revisions, however, the procedure changed slightly and the SDK does not contain the required tooling, instead leaving this setup to the user. In our case, we used an older clone based on revision baeeb8fd497a99b3c141d7494309ec2e64f19bdf.

Note: the following is based on old revision of Freedom E SDK. We may update the post later to reflect recent changes, including steps to setup standalone RISC-V tooling.

# To clone the whole Freedom E SDK simply use:
git clone --recursive https://github.com/sifive/freedom-e-sdk.git

# Alternatively, to clone a specific revision, first clone only the main repository, checkout the revision and then initialize subrepos:
git clone https://github.com/sifive/freedom-e-sdk.git
git checkout master baeeb8fd497a99b3c141d7494309ec2e64f19bdf
git submodule update --init --recursive

All the tools can be built relatively easily (note this may take some time):

make tools

Fading LED

This custom target board connects to CW308 pins for LED1-3 using FE300 GPIO pins 19, 22 and 21 accordingly, which correspond to GREEN, RED and BLUE LEDs on the HiFive1 board, so the led_fadeexample should work out-of-the-box. The caveat though is that the example uses the external 16MHz clock, which is not present on the target board (it’s connected to the CW308 CLKIN port). Therefore, for the first run, I have adapted the example to run from the internal PLL instead:

  // Make sure the HFROSC is on before the next line:
PRCI_REG(PRCI_HFROSCCFG) |= ROSC_EN(1);

// Set the HFROSC to run at 8MHz (72MHz default)
uint32_t trim = PRCI_REG(PRCI_HFROSCCFG) & 0x001F0000;
PRCI_REG(PRCI_HFROSCCFG) = ROSC_EN(1) | ROSC_DIV(8) | trim;

// Ensure the PLL is bypassed and uses HFROSC at output
PRCI_REG(PRCI_PLLCFG) = (PRCI_REG(PRCI_PLLCFG) & ~PLL_SEL(1)) | PLL_BYPASS(1);

// Configure UART to print
GPIO_REG(GPIO_OUTPUT_VAL) |= IOF0_UART0_MASK;
GPIO_REG(GPIO_OUTPUT_EN) |= IOF0_UART0_MASK;
GPIO_REG(GPIO_IOF_SEL) &= ~IOF0_UART0_MASK;
GPIO_REG(GPIO_IOF_EN) |= IOF0_UART0_MASK;

// 115200 Baud Rate
UART0_REG(UART_REG_DIV) = 69;
UART0_REG(UART_REG_TXCTRL) = UART_TXEN;
UART0_REG(UART_REG_RXCTRL) = UART_RXEN;

After building and uploading the software to the board, I noticed all the LEDs started shining , but they were not fading as they were supposed to. After some detailed debugging, it turned out that they were simply too bright to notice the difference and simply negating their PWM outputs was sufficient to get a similar result as on the HiFive1 board:

GPIO_REG(GPIO_OUTPUT_XOR) |= ( (1 << GREEN_LED_OFFSET) | (1 << BLUE_LED_OFFSET));
GPIO_REG(GPIO_OUTPUT_XOR) &= ~( (1 << RED_LED_OFFSET) );

With those modifications, I got the led_fade example working properly:


Fading LEDs on CW308 and FE310 target.

The example also uses serial interface to demonstrate the I/O capabilities. I used a simple Jupyter notebook with ChipWhisperer to try and communicate with the board, but surprisingly it did not work out of the box., the selected baudrate of 115200 was not correct.

The first issue was that the RX/TX are swapped on board (easy mistake to make and fix in software, but nonetheless annoying). The second was, the selected baudrate of 115200 was not correct. A simple brute force search allowed to detect a range of baudrates that was working, in this case about 95000 bauds.

Using the formula f_baud = f_in / (div + 1) I computed that the f_in, which was supposed to be around 8000000 (8MHz) was actually around 6650000 (6.65MHz). After some digging, it turned out that HFROSC trim value was not properly set!

According to the default OTP contents on the chip, the address 0x1FEC should contain the default trim value for 72MHz oscilator:

0x1FEC  |  Varies  |  HFROSC Trim Setting for 72MHz

Meanwhile, the value in HFROSC config register was 0:

(gdb) p/x *0x00021FEC
$3 = 0x8
(gdb) p/x *0x10008000
$5 = 0xc0000008

I modified the initial code to get the default trim value from OTP instead of the HFROSC register, by reading from 0x00021FEC. The results were promising, but the difference between expected and actual baud rate still persisted. I selected a different base baudrate and divider to simply make it easier to debug. By setting the divider to 63 (64 actually, as the formula takes div + 1) I selected baudrate of 125000.

The results were still off from expected, but not as much as before. By taking the exhaustive search approach again, I found out that the actual baudrate was actually about 115200-120000. This hinted that the actual frequency of HFROSC is about 7.37 – 7.68 MHz. The differences may be caused by e.g. too low voltage on the 1.8 rail (I measured the voltage on the 1.8V, shunt low and shunt high pins, the results are shown below), temperature, or something entirely different (the default value is estimated for 1.8V at 25°C).

VCC1.8  |  1.796
SHUNTL | 1.680
SHUNTH | 1.759

As a result, it turns out that when using the internal clock source, we will need to use smaller baudrates, or develop a system to adapt to such differences.

Fading LED (again)

After connecting to ChipWhisperer software, using external clock source is very easy to adapt. In theory, the original led_fade example should work out-of-the-box, but recall we had to flip the PWM outputs to see the changes on CW308 diodes.

#if USE_INTERNAL_CLKSRC
// Make sure the HFROSC is on before the next line:
PRCI_REG(PRCI_HFROSCCFG) |= ROSC_EN(1);

// Set the HFROSC to run at 8MHz (72MHz default)
uint32_t trim = _REG32(OTP_MEM_ADDR, 0x1FEC);
PRCI_REG(PRCI_HFROSCCFG) = ROSC_EN(1) | ROSC_DIV(8) | ROSC_TRIM(trim);

// Ensure the PLL is bypassed and uses HFROSC at output
PRCI_REG(PRCI_PLLCFG) = (PRCI_REG(PRCI_PLLCFG) & ~PLL_SEL(1)) | PLL_BYPASS(1);
#else
// Make sure the HFROSC is on before the next line:
PRCI_REG(PRCI_HFROSCCFG) |= ROSC_EN(1);
// Run off external clock source (expected 8MHz)
PRCI_REG(PRCI_PLLCFG) = (PLL_REFSEL(1) | PLL_BYPASS(1));
PRCI_REG(PRCI_PLLCFG) |= (PLL_SEL(1));
// Turn off HFROSC to save power
PRCI_REG(PRCI_HFROSCCFG) &= ~(ROSC_EN(1));
#endif

// ...

// 38400 Baud Rate (assuming 8MHz)
UART0_REG(UART_REG_DIV) = 207;
UART0_REG(UART_REG_TXCTRL) = UART_TXEN;
UART0_REG(UART_REG_RXCTRL) = UART_RXEN;

Last touches

The board doesn’t come with a bootloader flashed and therefore resetting it involves a jump to an invalid instruction 0xffffffff at 0x20000000. We plan on writing a custom bootloader, which is a topic for a future blog post. The easiest way to restart the board is to either connect to it via gdb and reset $pc to main, or by reflashing (the upload procedure end with a jump to 0x20400000 which is the start of the program).

This, however, does not properly reset UART and may corrupt the RX buffer with previously received data. The following snippet briefly disables and re-enables UART to ensure the buffers are cleared.

  // 38400 Baud Rate (assuming 8MHz)
UART0_REG(UART_REG_DIV) = 207;
// Reset TX/RX
UART0_REG(UART_REG_TXCTRL) = 0;
UART0_REG(UART_REG_RXCTRL) = 0;
volatile int i=0;
while(i < 100){i++;}
UART0_REG(UART_REG_TXCTRL) = UART_TXEN;
UART0_REG(UART_REG_RXCTRL) = UART_RXEN;

Below are the standard commands for building, flashing and running debugger, used for this project:

# Build led_fade_internal_clk with freedom-e-sdk
make software PROGRAM=led_fade_internal_clk BOARD=freedom-e300-hifive1

# Flash the target board
make upload PROGRAM=led_fade_internal_clk BOARD=freedom-e300-hifive1

# Run OpenOCD for debugging
make run_openocd PROGRAM=led_fade_internal_clk BOARD=freedom-e300-hifive1

# Run GDB (in a separate terminal, while OpenOCD is running) for debugging
make run_gdb PROGRAM=led_fade_internal_clk BOARD=freedom-e300-hifive1

Porting SimpleSerial environment

Right after the initial bringup, I’ve ported a “simple-serial”-like environment to Freedom E SDK using their examples as a base. The serial communication with ChipWhisperer and external clock source seemed to be working just fine for this purpose.

I ended up essentially rewriting the SimpleSerial environment from scratch, conforming to the API s.t. porting e.g. the simpleserial-aestarget from CW only required minor changes, such as changing a couple of includes. One major caveat is that simple write/read functions had to be rewritten because they added \r following every \n which was breaking the protocol.

With the knowledge gathered during debugging the Fading LED example, rewriting the SimpleSerial framework was a piece of cake. The initialization procedure is basically the same as in our led_fade, trigger setup simply enables GPIO 23 (which is pin 7 on the HiFive1 and GPIO4 on our target board) in output mode. Trigger high/low boil down to flipping a single bit in GPIO_REG(GPIO_OUTPUT_VAL) register.

A more detailed description of our SimpleSerial for FE310 fork will be published in the near future.

Future plans

In the next post, I will use standard side-channel techniques such as CPA, DPA and Template Attacks on traces gathered from the board, running tiny-AES128-C implementation (and potentially others as well).

In another post, I will focus on the inner workings of the SimpleSerial port and caveats encountered during porting.

As a next milestone, we will design and implement a custom bootloader, akin to the STM32F bootloaders used to flash the targets directly from CW capture board, without the need for a separate USB connection and OpenOCD/external debugger setup.

Leave a Reply

Close Menu