POSIX COMPLIANT OPERATING SYSTEM FOR WIXEL

Hlynur Hansen T-404-LOKA December 2016 School of Science Reykjavík University Project report ii POSIX compliant operating system for Wixel

Hlynur Hansen

December 2016

Abstract

There did not exist an operating system with threading and scheduler for Wixel, therefore I ported RIOT-OS to the MCS51 architecture featured on the Wixel. I have included a scheduler, threads, and a POSIX compliant API for a subset of the supported functions. We use the SDCC version 3.6.0 toolchain for our implementation, that only fully supports C89 for the MCS51 architecture, whereas RIOT-OS is written for C11 and GCC toolchain. I describe how code is stored in memory and how memory allocations are done. Then I go into how memory size restrictions and the instruction architecture of the Wixel complicated this development. iv v

Contents

Contents v

1 Introduction 1 1.1 The OS implementation ...... 1 1.2 Background ...... 2

2 Methods 3 2.1 Research ...... 3 2.1.1 The Wixel ...... 3 2.1.1.1 Memory layout ...... 3 2.1.2 The Development kits ...... 5 2.1.2.1 Wixel SDK ...... 5 2.1.2.2 RIOT-OS ...... 5 2.2 Tools of the trade ...... 5

3 Results 7 3.1 Contribution and difficulties ...... 7 3.1.1 Bricking ...... 7 3.1.2 C89 standardization and MCS51/SDCC changes ...... 8 3.1.3 CPU and board specifications ...... 10 3.1.4 Size restrictions ...... 10 3.2 Using the Operating System ...... 11 3.2.1 RIOT-OS using the generic board ...... 11 3.2.2 Testing and application development ...... 12

4 Conclusion 15 4.1 Summary ...... 15 4.2 Future work ...... 15

Bibliography 17 vi 1

Chapter 1

Introduction

Reykjavik University uses a test-bed to research signal propagation[1], which is a network of Wixels[2] that communicates using radio signals in a closed environment in the basement. In this test-bed, each app is written on bare metal, that is without using any software abstraction for accessing devices or services. Providing an operating system with a known API would make it easier to work on this test-bed. The operating system would handle program executions, system failures, and other device specific functions more gracefully and in such manner that the resource limitation becomes less of thought to the , We are talking about things like resource control, memory allocation and all handling. My project was to create an operating system for those devices, the motivation is to make everything more convenient for the programmers to use those devices. The less that they had to implement in resource handling the more they could think about what the program should do, in functionality, speaking.

1.1 The OS implementation

The defining features of an OS are a scheduler, and event handling. After some consideration and meetings with my advisor dr. Marcel Kyas, we decided to port an operat- ing system that is publicly available, possible Operating Systems are Contiki[3], Tiny OS[4], [5], and RIOT-OS[6] we need to have a compiler that targets Wixels, the only - piler available is SDCC so the operating system must support the c language, that eliminates Contiki and Tiny OS from the consideration. The generated image has to fit into 26 KiB including all applications. Linux image already uses 1 MiB least which eliminates its use, which leaves only RIOT-OS[7], it offers all features that operating systems need and should have, they claim that their operating system should be able to fit on devices with ROM size as low as 5KiB and RAM size as low as 1.5 KiB. This port will be available for public use on GitHub, under LGPLv2.1[8]. Here I focus on problems or barriers and successes regarding this implementation and whether the 6LoWPAN[9] implementation is a real option for these devices. To summarize the implement and research questions: • Implement an operating system kernel with notation of interrupt and event handling • Implement a Network stack, including 6LoWPAN • Implement a support library modeled after the C standard library and the POSIX spec- ification 2 CHAPTER 1. INTRODUCTION

• Test the implementation in a test bed and gather the data of that test on packet delivery, ratio and average round-trip times

1.2 Background

The first operating system was LEO[10] I and was created in 1951 for the use on, it was so called single stream batch processing system where programs and/or data were submitted in batches[11], around 1961 CTSS was created and it was for the first a time share operating system was developed. General purpose Operating systems are used by every computer user today, systems like Windows, Linux, and MacOS-X. Those systems are in use to make it more convenient for the user and to interact and make use of their , in most cases, the user has no knowledge about the implementation of their operating system and does not need to know. Real-time operating systems, on the other hand, are used for specific tasks and specific systems, they provide the programmer the convenience not to think about how he should handle memory locations, device I/O and other . RIOT-OS implements a microkernel architecture inherited from FireKernel[12]. It was created for the use on Internet Of Things(IOT) devices, which very often are low resource devices and therefore the size of the operating system matters. It runs on a wide spectrum of devices powered by small MCUs. Devices available include the ARM, ATmega and MSP430 family MCUs. It also includes a native option for testing, where RIOT-OS runs as a process in Linux. RIOT-OS features schedule, multi-threading and real-time capabilities, it is modular and includes support for C and C++ programming languages. The first was the 4-bit 4004 released in 1971, with intel 8008 ar- chitecture becoming available over the next years[13]. MCUs1 Are used for many pur- poses, from simple calculators to embedded devices like the Wixel. The Wixel uses Texas CC2511F32 that contains 8051 architecture, 2.4ghz wireless radio module, and full- speed USB . It has very limited resources for storage, more about that in Section 3.2 Difficulties. We use the SDCC compiler which is the only freely available c compiler that supports the MCS51 architecture. It supports the ANSI/C89 programming language, it includes an assembler and linker.

1Micro Controller Units 3

Chapter 2

Methods

2.1 Research

For me to be able to implement this project I had to research kernel implementations and what are the standard feature set in operating systems. The research list was as follows:

• Operating system implementation

• Operating systems on low powered devices

• CC2511 diagram and implementation

• 8051 architecture, functions and assembly

• memory management in low powered devices

• C89 standards for SDCC compiler use

In this time-frame, I had to a lot of in a very limited time, while the best reading was the book Understanding the [14]. The book explains the implementation of the Linux kernel and was used as a model for our own features.

2.1.1 The Wixel Wixel uses Texas Instrumental CC2511 and transceiver. it is a cost effective controller that includes 2.4 GHz transceiver with maximum data rate of 350 Kbps and a wire- less range of about 15 meters. The CC2511 implements the MCS51 architecture, both the processing unit and the accumulator use 8-bit implementation and uses bit-level addressing that is instructions can change individual bits of some registers. There are 88 Special func- tion Registers, 22 radio registers, 15 common USB registers, 10 indexed endpoint registers and 6 endpoint FIFO registers.

2.1.1.1 Memory layout The memory layout was a bit of problem in this project, where the compiler did put the function arguments and variable declarations into the same location on the Wixels paged memory segment. This caused the memory to overflow and the compiler to fail. To be able to align everything in the right place I had to use memory alignment attributes for all of 4 CHAPTER 2. METHODS

Figure 2.1: Memory layout

my variable declarations. The following attributes define where in the address space the variables should be stored.

DATA Direct accessible memory (256 Bytes) Here pointers to the functions are stored.

IDATA Indirectly accessible memory segment (128 Bytes) Mostly for storing stack locations of variables passed to functions.

PDATA Paged memory segment (first 256 bytes of XDATA) For variables that need to be on the top of the stack, usually something that controls some of the devices periphs.

XDATA External memory segment (size 4 KiB) This is the stack segment for all variables that can change and to store stack-frames for functions while they are working.

CODE Code segment (Read only) Here in this segment all code and constants that do not change are stored.

For memory layout see Figure 2.1 and the Wixel is displayed in Figure 2.2. For the Wixels specification see Table 2.1. 2.2. TOOLS OF THE TRADE 5

Processor CC2511F32 @ 24 mhz Ram size 4096 bytes Program memory size 29 KiB User I/O lines 15 Minimum operating voltage: 2.7V Maximum operating voltage: 6.5V Reverse voltage protection: Y External programmer required: N

Table 2.1: Wixel specs

Figure 2.2: The Wixel

2.1.2 The Development kits 2.1.2.1 Wixel SDK The Wixels development bundle is available on their homepage https://www.pololu. com/product/1336/resources. It includes a few example standard applications that run on the Wixel for experiment purposes.It also contains libraries for all of the device’s peripherals, like the USB port, the radio transceiver, and I/O pins, to which we can connect arbitrary devices.

2.1.2.2 RIOT-OS RIOT-OS is a free open-source operating system and it is publicly available online from their homepage https://riot-os.org/.

2.2 Tools of the trade

The compiler was the best debugging tool available for me, the compiler created few files that could help me with debugging memory allocations, multiple definitions, and code lay- out.

Assembly code Files ending with .lst hold the assembly code generated by the compiler, this code helped me refining variables and to see how pointer arithmetics were done within the compiler, with their help I could create pointers which were assigned to functions, for example, to use the threading portion of the operating system.

Memory map Files ending with .map, hold the memory layout for the given compiled code, there I could see which variable is allocated at what location, also I could debug func- tion and function attributes. 6 CHAPTER 2. METHODS

The code section is 32 KiB where the first 1024 Bytes and the last 2048 Bytes of the code segment are reserved for the USB bootloader. The remaining 29 KiB of the code segment is known as application segment. The $Home section where the main function should be is located at the first byte of the application segment or at address 0x0400. It is hard to have the generated code fit into the available memory, as is explained in Section 3.1.4. 7

Chapter 3

Results

I have implemented a functional OS for wixel, with scheduler and threading, an interactive shell and a python driver for shell interaction.

3.1 Contribution and difficulties

3.1.1 Bricking Bricking means that the Wixel is in a state where it does not react to any external inputs and commands. Then the Wixel is as useful as a brick. Sometimes the Wixel was bricked when it was flashed. This happened when flashing the Wixel with the new application I had created and contained errors. To make it possible to flash it again I had to short pin 2_2 with the GND and the 3V3 pins, then release the GND, see Figure 3.1 for the pin layout. The best solution is to have a breadboard lying around and connect the pin-out with buttons for quicker resetting. The schematics for this are available on the Wixels homepage.

Figure 3.1: The Wixels pinout 8 CHAPTER 3. RESULTS

3.1.2 C89 standardization and MCS51/SDCC changes The second problem domain is porting the code of RIOT-OS to the Wixel and the SDCC toolchain. Because of limitations of the SDCC, all code needed to be converted from C99/C11 to C89. In C99 inline functions are inserted into each function that calls the given inline function, while in C89 multiple definitions are created for each of the inline function. Thus we have to prevent multiple definitions of inline functions in the compiler output. The solution was in 2 parts, if the type of the argument inserted into given inline function did not matter then I created normal functions that could be called, if the type mattered then I inserted the algorithm/code from the inline function into a block in the calling functions.

Function Macros According to ANSI/C89 function macros are expanded to their bodies at each point they are used. In SDCC they are treated like inline functions that are each use creates a definition of a function. Consequently, the same solution for inline functions was used. Here below is an example of how macro functions were changed to prevent multiple definitions of them. Note: offsetof function is declared within SDCC compiler suite. //macro function container_of(PTR, TYPE, MEMBER) //created multiple definitions # define container_of(PTR, TYPE, MEMBER) \ ((TYPE *) ((char *) (PTR) - offsetof(TYPE, MEMBER))) //moved into code where applicable //f.ex //RIOT-OS implementation thread_t *list_entry = container_of((clist_node_t*)list->next, thread_t, rq_entry);

//MY implementation thread_t *list_entry = ((thread_t*) ((char*) ((clist_node_t*)list->next) - offsetof(thread_t, rq_entry)));

//NOTE: //offsetof() is declared within SDCC as offsetof(TYPE, MEMBER).

Constant Macros Constant macros can be of the max size of 16 bits, if larger macros are defined they are reduced down to 0 also if signed macros are used then some undefined behavior will occur. For example if I define the macro KL to 32700 then 32700 will be printed, see Figure 3.2, if KL would be defined to larger value then 16 bits can hold then 0 would be printed, see Figure 3.3, then if KL would be defined as signed integer, for example -1 then the output can be unexpected, something like printing the output for the second time, see Figure 3.4. The declaration of variables had to be moved to the start of each block because they cannot be declared after the first statement of a block unlike in C99/C11. An aggregate value is the value of an array or a structure. In C99/C11 values can be assigned to aggregates in one assignment by enumerating the values in braces. Let’s give a short example. typedef struct list_node { 3.1. CONTRIBUTION AND DIFFICULTIES 9

Figure 3.2: 16 bit macro

Figure 3.3: More than 16 bit macro

Figure 3.4: Signed macro 10 CHAPTER 3. RESULTS

Name Address space pointer or value Function declaration DATA pointer Variables passed to functions IDATA pointer Global variables XDATA value Local variables XDATA value Aggregates/structs IDATA/XDATA pointer to value

Table 3.1: Memory address space layout

struct list_node *next; /**< pointer to next list entry */ } list_node_t; list_node_t some_list = { node };

This is not possible in SDCC. The solution is to use pointers to the aggregates as function arguments instead of a copy of the aggregate itself. An assignment inside a block is replaced with a sequence of assign- ments of scalar fields of the aggregates.

3.1.3 CPU and board specifications CPU and board specific input and definitions created, mostly derived straight from the Wix- els libraries, some changes made for riot-OS compliance. All header and code files were copied from the wixels library into the RIOT-OS port board and CPU directories. When using UART(USB) specific code I saw that they used some macro functions that were only called once, so there was no need to have it inline the solution was to move them into the functions that called each of them to save space on the directly accessible memory segment.

3.1.4 Size restrictions Memory size restrictions within the wixel prevented some function and variable declara- tions, both globally declared variables and variables passed to functions were sent to the direct accessible portion of the memory, this was a problem. Here I needed to use the in- trinsic named address space assignation, that is the XDATA, IDATA, DATA, and CODE, instead of using extern or static. This allowed me to align the Memory and prevent it from overflowing during compile time.

Code section as stated earlier is only 29 KiB with 3 KiB or the USB bootloader. It al- locates only 26 KiB for programs to be flashed onto the Wixel, in addition the program memory is read-only. For me to be able to create this OS, I needed to fit the OS within the 26 KiB size. This part was very hard as the original RIOT-OS implementation created multiple definitions for all of the inline functions and macros, where I needed to move all the constant macros into their respected place of calling within each function, and the in- line functions were either moved into functions as part of their functionality or non-inline function were created, as an example the linked list insert/remove algorithm. In this code example below, I show how I use XDATA to reallocate the variable within the external memory instead of within the constant code section or directly accessible segment of the memory, this variable needs to be able to change according to the output from the irq_disable function. 3.2. USING THE OPERATING SYSTEM 11

And how declarations of variables differ from C11 to C89, I move the declaration of ünsigned state¨to the very start of the block. \\Riot OS implementation void thread_sleep(void) { if (irq_is_in()){ return; } unsigned state = irq_disable(); sched_set_status((thread_t *)sched_active_thread, STATUS_SLEEPING); irq_restore(state); thread_yield_higher(); }

\\My implementation \\Here XDATA put state into the external memory instead \\of the read-only program memory \\STATUS_SLEEPING changed from const macro to enumerator void thread_sleep(void) { unsigned XDATA state = 0; if (irq_is_in()) { return; } state = irq_disable(); sched_set_status((thread_t *)sched_active_thread, STATUS_SLEEPING); irq_restore(irq_disable()); thread_yield_higher(); }

3.2 Using the Operating System

3.2.1 RIOT-OS using the generic board Before I started to port the RIOT-OS to MCS51 architecture, I tested the RIOT-OS with the native board from the RIOT-OS board list, this is the CPU implementation for use on the development machine. By doing this I could see what the expected input, output, and behavior was. I saw the need for test applications early in the development process so that I was able to create a list of what should be tested. In Table 3.2 the column Module name refers to modules within the core system, column functionality refers to what the modules do and test availability refers to whether there are tests available for those modules. 12 CHAPTER 3. RESULTS

Module name Functionality Test availability Bit arithmetics Helper functions for bit arithmetics Yes, within thread yield function Network byte-order Device to network byte order arithmetics No Kernel initialization Kernel initialization functions Yes, within apps directory Kernel panic Handles all kernel panics No Schedule Scheduler for processes Yes, within test directory Threads Functions to create and manage threads Yes, within test directory

Table 3.2: Modules within RIOT-OS to test

Figure 3.5: Wixel thread example

3.2.2 Testing and application development It is very important to show demonstrate functionality by creating testing algorithms, frame- works, programs or other types of testing abstractions. Each test program was defined after the implementation of each module within the core system. To be able to test if the code that I ported was working the way it should be working, I needed to create test applications, those applications are located inside a sub-folders, located inside the RIOT-OS folder structure, all sub-folders begin with the suffix wixel_{name}.

The testing programs are the following: wixel_thread_basic This test application is to create a basic thread and then call thread yield, by calling thread yield it will yield the higher priority threads that were created. This is a standardized test from the RIOT-OS original implementation and ported for use on the Wixel. With this test program, I was able to show the existence of threads within the RIOT-OS implementation for the Wixel. See Figure 3.5. wixel_shell This test application is to make it possible to test the shell implementation of the RIOT-OS. This implementation includes a python interactive shell driver to be able 3.2. USING THE OPERATING SYSTEM 13

Figure 3.6: Wixel shell example

to talk to the shell on the Wixel. With this program I show that it is possible to have an interactive shell session by using USB to serial connection, this is very helpful when applications that are created for the Wixel need to be able to get user input. See Figure 3.6. wixel_sched_testing This test application was created to show the schedule implementation of the RIOT-OS, where threads are created and the schedule processes those threads during run-time. 14 15

Chapter 4

Conclusion

4.1 Summary

With this project, I have created an operational operating system for the use on Wixels. It includes threading, scheduler, and POSIX compliance. Interrupt handling has still to be implemented. We want to track the RIOT-OS development which depends on improvements to the C11 support in SDCC.

OS on Wixel It is possible to create an operating system for devices with limited resources like the Wixel. Threads It is possible to run simple threads on the Wixel with this RIOT-OS implementa- tion. With good interrupt implementation, this will become the best running option for this device.

4.2 Future work

RIOT-OS is implemented using C11, in order to be able to use their implementation and not have to backport the standards it would be better if SDCC had support for C11. According to future improvement list for SDCC version 3.7.0[15] they have added to the list structure value assigning and passing structures as function arguments. List of possible future improvements to this port

• Make the code more readable and remove code that has been commented out. This is an important step to get more people to work on this development. By improving the code readability all future ports and improvements would make easier for the person that is working on the development. • Add better timing functionality for the MCS51 implementations. Good timing imple- mentation for the architecture would allow the scheduler to be more efficient, this is very important for hard real-time scheduling. • Create a common implementation for the MCS51 architecture CPU to make it easier to add more implementations of boards featuring that CPU. Common implementa- tion for the MCS51 architecture would allow others using this architecture from other manufacturers to use that implementation for their own work, that is there can be some differences between architecture for example with the count of registers. 16 CHAPTER 4. CONCLUSION

• Implement context saving and restoring It is very important to save the registers that are in use when you do a context switch, to be able to pick up where you left off next time the switching happens.

• Add more debug options for application creation It is very important to be able to de- bug your applications before deploying them onto a platform, by including a docker or emulator for the MCS51 architecture the debugging would be done within the de- velopment system. We want to be able to debug applications as closely to the actual implementation as possible without the overhead of instrumentation code. 17

Bibliography

[1] H. Guðmundsdóttir, E. I. Ásgeirsson, M. H. L. Bodlaender, J. T. Foley, M. M. Halldórs- son, and Ý. Vigfússon., Wireless scheduling algorithms in complex environments. in proc. 17th acm international conference on modeling, analysis and simulation of wireless and mobile systems (mswim), Sep. 2014. [2] Pololu, Pololu Wixel user’s guide, https://www.pololu.com/docs/0J46, Accessed on 06.01.2017. [3] Contiki, Contiki: The Open Source OS for the Internet of Things, http://www. contiki-os.org/. [4] TinyOS, http://www.tinyos.net. [5] E. Brown, Open source operating systems for iot, https://www.linux.com/ news/open-source-operating-systems-iot. [6] RIOT-OS, RIOT: The friendly Operating System for the Internet of Things, http: //www.riot-os.net, Accessed on 06.01.2017. [7] O. Hahm, E. Baccelli, M. Günes, M. Wählisch, and T. C. Schmidt, RIOT OS: Towards an OS for the internet of things, http://riot-os.org/docs/riot-infoc om2013-abstract.pdf, Accessed on 06.01.2017. [8] GNU, GNU lesser general public license, version 2.1. [Online]. Available: https: //www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html. [9] N. Kushalnagar, G. Montenegro, and C. Schumacher, “IPv6 over low-power wireless personal area networks (6LoWPANs): Overview, assumptions, problem statement, and goals”, RFC Editor, RFC 4919, Aug. 2007, http://www.rfc- editor. org/rfc/rfc4919.txt. [Online]. Available: http://www.rfc-editor. org/rfc/rfc4919.txt. [10] F. Land, The story of leo – the world’s first business computer, http://www2.wa rwick.ac.uk/services/library/mrc/explorefurther/digital/ leo/story/, Accessed on 06.01.2017. [11] P. Krzyzanowski, Operating systems, https://www.cs.rutgers.edu/~pxk /416/notes/01-intro.html, Accessed on 06.01.2017. [12] RIOT-OS, RIOT-OS documentation, https://riot-os.org/api/, Accessed on 06.01.2017, 2016. [13] Wikipedia, Microcontroller, https://en.wikipedia.org/wiki/Microco ntroller, Accessed on 06.01.2017, 2016. [14] D. P. Bovet and M. Cesati, Understanding the Linux kernel third edition. O’Reilly Media Inc, 2006, ISBN: 9780596005658. 18 BIBLIOGRAPHY

[15] SDCC, Sdcc 3.7.0 release, http://sdcc.sourceforge.net/mediawiki/ index.php/SDCC_3.7.0_Release, Accessed on 06.01.2017.

School of Computer Science Reykjavík University Menntavegur 1 101 Reykjavík, Iceland Tel. +354 599 6200 Fax +354 599 6201 www.ru.is