Tuesday, 30 June 2020

Bare Metal program test

Previously we have managed to implement terminal i/o and libraries into our bare metal environment but as yet there is no breakthrough on setting up stdin, stdout or file i/o.  I will write more if / when problems are resolved but in the meantime we should try some programs.

Our simple starting point is to check whether a number is prime.
The first cut was to loop round trying all possible divisors upto the square root of the subject number.
The program was written on an RPi running linux first.  Then it was transferred to WSL where we compile using arm-none-eabi-gcc for bare metal.  In its simplest form it was quick to implement and test.
The bare metal programs we previously had working were re-organised so that the initial program (notmain.c) sets up uart i/o.  It calls a function jmain.c, which is intentionally not called main to avoid the compiler misinterpreting it.  jmain.c contains our program code with printf statements replaced by uart_puts to output strings to the serial terminal.

The second iteration improves the algorithm slightly, don't test even divisors, make test_prime() a function.  We also loop to ask the user for prime numbers.  We change the linux version of the program so it is easy to convert:
  use sprintf(buffer,.......); printf(buffer); if variable values need to be output for uart_puts convesion
  use gets(buffer); sscanf(buffer,.....) for input so uart_gets can be added on conversion.
Now we can easily enter and test programs under linux before a minimal conversion to run bare metal.


It is much more appropriate to calculate lots of prime numbers.  The program was amended to ask the user now many primes are required.  These are then calculated and printed.  To allow a flexible number of primes malloc is used to create an array of upto 1,000,000 primes which can then be calculated and printed on the screen.  
Previously I had no luck in implementing printf but for some unknown reason this started working so I updated my program to use printf and scanf, which makes life simpler.

To calculate 1,000,000 takes approximately 30 minutes on bare metal RPI 1B.



Monday, 15 June 2020

Bare Metal C - libraries

Introduction

In my last bare metal C post I was able to complete a hello world program so that our RPI1B can do terminal input /output.  It was quite an achievement to dispense with our operating system and establish communications with the program running on hardware.

Now I could carry on in that direction and write everything else I need in C, it would include memory management, device drivers, utility functions and all the other things that C programmers can usually take for granted.  Life is too short for that so I recognise what I really need is a library, in particular the C-Library which provides so many basic necessities of C life.

However the C library makes operating system calls to the linux (or other) kernel whenever it need assistance in completing functions and I decided I didn't want an Operating System!  I didn't want the large amounts of useful and useless code that comes with it.  So our mission is to provide, ie write, the code needed by the C library.

C runtime


We also need to initialise the C environment which is the function of C-runtime (crt0.o). This is fairly easy and we deal with  it first. Brian Sidebothan provide an excellent description in part 2 of his Valvers Bare Metal C tutorial.  At its simplest we just have to setup a stack pointer so that C can use a stack.  This is set to the program load address 0x8000 on RPI1B.  The program is loaded in addresses from 0x8000 upwards and the stack uses memory downwards towards 0x0000. A second job that is required is to initialise variables to 0, which is a C standard requirement.  The variables are stored in the BSS segment and a small C program (cstartup) can be written to set values in the segment.

Library stubs


The tutorial goes on to explain how we can start using library functions and uses malloc (memory allocation) function to demonstrate.  Compiling a C program containing malloc functions gives an error "_sbrk" not found.  This is a low level function which we need to provide ourselves.  Luckily we can use a working example from newlib.  We copy this to a file c-stubs.c, compile without errors, and we can request / use memory allocated to our program.  In fact newlib contains a list of system calls which the C library expects.  Many of these are just dummy stubs with the function call and no code so you still have to do some work yourself.

Test Program


To demonstrate that I now have a working C library capability I use malloc and strcpy (string copy) in my "Hello World" program.  The program is based on David Welch's UART tutorial example with Valvers additions to use libraries.  The linker script and bss initialisation was a little difficult to write but David Welch comes to the rescue with his explanation of linking requirements.  RPI has simplified linking requirements as all code and data is incorporated into kernel.img and loaded into memory.  Initialising BSSS is not required - although I tested the program successfully both with and without initialisation.


Saturday, 13 June 2020

FreeRTOS Tutorial

Background

I am always on the look out for simpler Operating Systems I can try.  I often see references to FreeRTOS in passing and was excited to see an Elektor article which shows how to run FreeRTOS on an ESP32.  My current ESP32 is happy running a micropython setup with its own firmware so I promptly ordered another. In the meantime I looked around for learning resources so that I can learn more.

I decided that a udemy course "Arduino FreeRTOS from the Ground up" fitted the bill and as it was cheap (£13) I gave it a try.  It turned out to be somewhat superficial and very slow paced but it does get you up and running and actually using FreeRTOS.  FreeRTOS can run on any Arduino so I quickly gave it a try.
Circuit Digests Arduino FreeRTOS tutorial would be a better place to start 

Task Creation


FreeRTOS is centred around tasks (threads) which run independently.  The OS simply arranges for a mix of tasks to run on the available hardware.  In the Arduino IDE you define a setup function which is run once to initialise the system and a loop function which carries out the repeated activities on the system (e.g. lighting LEDs, reading sensors, outputting results).  One of the headaches is making sure that all the activities are carried out when you need them.  For example you may have a sensor you want to read every 100 milliseconds, and a webpage which you want to send out whenever a suitable http request arrives.

FreeRTOS eliminates use of the loop function.  You simply create all the tasks in the setup function, provide details of their priorities and let FreeRTOS decide which one needs to run.  To use FreeRTOS you simple start the sketch with:
 #include <Arduino_FreeRTOS.h>

The task creation function takes the form: 
  xTaskCreate(functionName, label, stacksize, priority, handle);
For example:
 xTaskCreate(flashRedLed,"Flash",100, NULL,1,redHandle);
Now, within the function flashRedLed, you write standard blink code, it can even be copied from the blink example.
When compiled and uploaded the LED blinks. Each of the programs functions can be added in a similar manner and will work independently.  You can simply copy and paste working functions and FreeRTOS will take care of them.

The handle is a variable which allows reference to and control of the task, for example to suspend / resume the task you write:
xTaskSuspend(redHandle);
.... do something ....
xTaskResume(redHandle);

Passing Information between tasks


Tasks usually need to communicate with each other, for example a user input task would pass details of processing to a processing task which could then send results to an output task.
Queues are used to pass information.  In setup a queue is created allowing a certain number of entries.  Functions can then add an item to the queue.  The item is usually a structure to allow all necessary details to be included within the single parameter.
Queues can be grouped into queuesets so that tasks can easily process information from a number of queues.

Synchronising Tasks


Timers start and stop tasks based on clock ticks or milliseconds. Event groups are defined to set specific bits allowing tasks to wait for something to happen before taking action.
Semaphores prevent tasks conflicting for shared resources by flagging when they are in use.
Mutex semaphores allow a single task to control a specific resource.

Interrupts weren't covered much, but of course are important in Arduino programming.  There is a special function xQueueReceiveFromISR so that functions can process ISR follow-up.


Summary

FreeRTOS provides a simple view of an Operating Systems "responsibilities".  Its job is to facilitate tasks to carry out their work.  The Arduino implementation provides this in a very simple manner by replacing the loop with a powerful task mechanism.  Other "responsibilites" such as providing hardware drivers and a user interface are (rightly) left to the existing Arduino environment.
I am not convinced that the udemy tutorial was better than blog tutorials on this subject but it did achieve basic understanding for me.






Tuesday, 9 June 2020

RPi Bare Metal C - Hello World

Background

Bare metal programming has a back to nature feel about it.  We have unimagineable amounts of software, interacting in complex ways when we want to use computer hardware.
On 8-bit processors such as PIC or Atmega you are very close.  A processor chip has a data sheet which you can use to see how you place instructions in memory so they will execute.  You add your own peripheral devices and are responsible for programming them.
The Arduino IDE allows you to program in C on small systems like Uno or ESP8266.  They are not far removed from the hardware, but have thorny implementation details removed and a simple setup/loop framework provided for your C programs.
For "real computers",32-bit or 64-bit devices which run linux (or Windows),  and are capable of running many tasks simultaneously you are far, far removed from the hardware.

Bare Metal computing on RPi allows you to rediscover the hardware in all its gory glory.
Programming in assembler is a mugs game but in fact only a tiny amount of standard assembler code is required.  Once the C environment is setup and you have a cross comiler to hand, you can write C programs without an OS.

Environment


My starting point is a RPi 1B.  RPI2 or RPI3 would be suitable but I don't need their extra power or complexity.
Not all startup steps on RPi devices are open source, we do know that after initialising hardware an RPi1B loads a program kernel.img from a FAT formatted SD card and starts the ARM processor.
Our focus is to compile an appropriate program, name it kernel.img and place it on an SD card so that it will execute.

We need a cross-compiler that will generate ARM code so I find it most practical to use GCC on Windows under WSL.

A variety of like-minded people have kindly provided tutorials.  They include valversJake Sandler, osdevS Matyukevich, BZT and David Welch have put a lot of work into explaining the intracacies to help you get started.
For RPI1B David Welch's tutorial is absolutely perfect.  His writeups are short but packed with pertinent details and his examples work faultlessly.

Blinking LEDs

Our first problem, as we start our program is that our bare RPIB has no software drivers.  As is traditional on embedded systems our objective will be to make an LED blink.

David Welch's example blinker01 provides an assembler code stub and linking script so that the program is loaded at location x8000 and initialises stack pointers and registers for C.  The C program then takes over and initialises GPIO16 (connected to "OK ACT" LED on board).
GPIO header details need to be included in the program to provide appropriate addresses for controlling the GPIO sub-system.  Finally GPIO16 is configured, enabled and set to 0/1 causing the LED to blink.

This is a huge step forward; we are running a program without any external threads or libraries, directly controlling the hardware.  In fact the executable kernel.img is only 148 bytes.  

Hello World

This is the traditional first program for most environments, printing out a message on the screen.  It is so much easier to develop programs when you have a method of communicating back to the user what is happening.  Flashing LEDs quickly lose their sparkle when they are the only way you have of understanding what the processor is doing.
Of course we don't have a screen to write output to.  We certainly don't want to delve into controlling the RPI HDMI output and GPU at this stage, but luckily we can use the RPI inbuilt UART (GPIO14/GPIO15) to send to a terminal/minicom/Putty session.  The GPIO TX/RX and GND pins were connected to an FTDI connector with a USB cable attached to Putty on the PC.

My first attempts at programming the UARt failed to work,  I don't know why.  I tried different tutorials, RPIs, compiler options, terminal connections, all without success.
On reading that the mini-UART is easier to program I tried this instead.  I was relieved and amazed when I put David Welch's UART01.bin on the SDcard and started it up to find it works perfectly, displaying digits as fast as it can.  The C program includes UART headers and initialises the UART.  It then has a simple putc function to output characters.
It is a small extra job to read input from the terminal session and echo characters out to the screen.  We can now do terminal I/O, another huge step forward.

Bootloader

Each time I want to test a program I have to take it out of the RPI, copy across a new kernel.img, replace in RPI and restart.  This quickly becomes irritating.  The marvellous David Welch has written a simple bootloader program.
To use this you put bootloader06.bin as kernel.img on the SDcard.  Now whenever you power up RPI a bootloader is started.  The bootloader waits for a program to be transferred across the serial link using xmodem file transfer.  I used minicom or ExtraPutty to transfer the file.  Pressing 'g' causes the program to run.  To use a different program simply power cycle the RPI and load another executable.
This is another huge step forward for me.  It gives me a practical environment to work in.


Saturday, 6 June 2020

Linux AV

In May I had a note from Virgin Media, my ISP, to say that azorult, some malware, was present on a device using my internet connection. It was helpful of them to provide this but not specific enough for me to isolate the problem.

azorult is malware often spread by phishing, infection could occur from clicking on bad links. Information on the internet doesn't pin it down particular types of device.  My devices include PCs, ipads, android phones, rpi, music devices, ip cameras.  There are also visitors with other devices.

My first step was to warn home users to stay alert as a warning has been received.  I then needed to check virus protection on my systems is uptodate.  For hardware devices, there isn't much I can do.  Virus checking on phones is done automatically and Windows devices have updates applied automatically.  That means my main effort was geared towards Linux.

I don't generally virus check RPi systems as they have very limited external connectivity.  In this case, since infection is potentially inside the LAN I need to review them.  There dont appear to be many virus scanners appropriate to linux, Clamav, which is owned by Cisco seemed to be good and widely used.

On installation the software runs freshclam to download virus signature database files.  You then use clamscan on a file selection to check for viruses.   I ran a complete check on RPi SD cards and saved the results.  Mostly the checks worked well.  I had problems with the newest RPi 3+ running buster and split the scan down into chunks to narrow down the problem, which then "went away".  RPI 1+ had insufficient memory for a scan so I created a samba share for the root drive and successfully scanned from RPI 3+.

Results were encouraging, no viruses were found.  That leaves me with some confidence that I don't currently have a problem and have taken responsible efforts to protect us.