Simplest project Hello World

Submitted by Sergey Worm on Sun, 05/06/2018 - 12:46

The best way to learn WrmOS is to use it. So, this article provide step-by-step manual how to build and run your own project Hello World. At first we will build Hello project from WrmOS examples. Then we will create new external project.

Contents
1. Hello World example
2. Create new external project

1. Hello World example [up]


Step 1.1. Get cross-platform toolchain

See the article How to get toolchain for detail.

Step 1.2. Get WrmOS sources

Clone repository from github:

git clone https://github.com/wrmlab/wrmos.git

or download zip archive.

Step 1.3. Build example project Hello

Run building of example project Hello for architecture ARM and platform Versatile Express Cortex-A9:

cd wrmos
make build P=cfg/prj/hello-qemu-veca9.prj B=../build/hello-qemu-veca9 -j

As result we will get bootloader image with RAMFS containing hello.elf:

ls ../build/hello-qemu-veca9/ldr/bootloader.elf

Step 1.4. Run WrmOS on QEMU virtual machine

qemu-system-arm -M vexpress-a9 -display none -serial stdio \
                -kernel ../build/hello-qemu-veca9/ldr/bootloader.elf

As result we will see output:

[ldr]   _    _ ___ __  __   ___  ___ 
[ldr]  | |  | | _ \  \/  | / _ \/ __|
[ldr]  | |/\| |   / |\/| || (_) \__ \
[ldr]  |__/\__|_|_\_|  |_(_)___/|___/
[ldr]          From Russia with love!
[ldr]
[ldr]  cpu #0/1 ready, sp=0x60341a78.
[ldr]
[ldr]  hello:   13:39:09  Jun  5 2018.
[ldr]  gccver:  7.3.0.
[ldr]  hware:   arm, cortex_a9, vexpress_a9, qemu_vexpress_a9.
[ldr]  ram:     [0x60000000 - 0x60800000)       8 MB.
[ldr]  ramfs:   [0x6028d000 - 0x60338000)     684 KB.
[ldr]  ##  name                    data      size  content
[ldr]   1  kernel.elf        0x6028e000    443148  'ELF ...'
[ldr]   2  sigma0.elf        0x602fa30c     41120  'ELF ...'
[ldr]   3  roottask.elf      0x603043ac    144704  'ELF ...'
[ldr]   4  config.alph       0x603278ec       516  '# config ...'
[ldr]   5  hello.elf         0x60328000     64204  'ELF ...'
[ldr]
[ldr]  elf:  foreach:  elf=0x6028e000, sz=0x6c30c.
[ldr]    app=kernel, va=0x60000000, pa=0x60000000, sz=0x00014000, load=1.
[ldr]    app=kernel, va=0xf0020000, pa=0x60020000, sz=0x001f9000, load=1.
[ldr]    app=kernel, va=0x00000000, pa=0x00000000, sz=0x00000000, load=0.
[ldr]  elf:  foreach:  elf=0x602fa30c, sz=0xa0a0.
[ldr]    app=sigma0, addr=0x00000000, sz=0x00000000, acc=0, progbits=0, name=.
[ldr]    app=sigma0, addr=0x60219000, sz=0x00005000, acc=5, progbits=1, name=.text.
[ldr]    app=sigma0, addr=0x6021e000, sz=0x00001000, acc=4, progbits=1, name=.rodata.
[ldr]    app=sigma0, addr=0x6021f000, sz=0x00001000, acc=6, progbits=1, name=.data.
[ldr]    app=sigma0, addr=0x60220000, sz=0x00004000, acc=6, progbits=1, name=.bss.
[ldr]    app=sigma0, addr=0x00000000, sz=0x00000039, acc=0, progbits=0, name=.ARM.attributes.
[ldr]    app=sigma0, addr=0x00000000, sz=0x00001240, acc=0, progbits=0, name=.symtab.
[ldr]    app=sigma0, addr=0x00000000, sz=0x00000c76, acc=0, progbits=0, name=.strtab.
[ldr]    app=sigma0, addr=0x00000000, sz=0x00000044, acc=0, progbits=0, name=.shstrtab.
[ldr]    app=sigma0, va=0x60219000, pa=0x60219000, sz=0x0000b000, load=1.
[ldr]  elf:  foreach:  elf=0x603043ac, sz=0x23540.
[ldr]    app=roottask, addr=0x00000000, sz=0x00000000, acc=0, progbits=0, name=.
[ldr]    app=roottask, addr=0x60224000, sz=0x00018000, acc=5, progbits=1, name=.text.
[ldr]    app=roottask, addr=0x6023c000, sz=0x00004000, acc=4, progbits=1, name=.rodata.
[ldr]    app=roottask, addr=0x60240000, sz=0x00001000, acc=6, progbits=1, name=.data.
[ldr]    app=roottask, addr=0x60241000, sz=0x0004c000, acc=6, progbits=1, name=.bss.
[ldr]    app=roottask, addr=0x00000000, sz=0x00000039, acc=0, progbits=0, name=.ARM.attributes.
[ldr]    app=roottask, addr=0x00000000, sz=0x00002600, acc=0, progbits=0, name=.symtab.
[ldr]    app=roottask, addr=0x00000000, sz=0x00002d58, acc=0, progbits=0, name=.strtab.
[ldr]    app=roottask, addr=0x00000000, sz=0x00000044, acc=0, progbits=0, name=.shstrtab.
[ldr]    app=roottask, va=0x60224000, pa=0x60224000, sz=0x00069000, load=1.
[ldr]  memory regions:
[ldr]    [60000000 - 60014000)  sz=0x00014000,  kernel.
[ldr]    [60020000 - 60219000)  sz=0x001f9000,  kernel.
[ldr]    [60219000 - 60224000)  sz=0x0000b000,  sigma0.
[ldr]    [60224000 - 6028d000)  sz=0x00069000,  roottask.
[ldr]    [60338000 - 60342000)  sz=0x0000a000,  bootloader.
[ldr]    [60342000 - 60800000)  sz=0x004be000,  free.
[ldr]  elf:  foreach:  elf=0x6028e000, sz=0x6c30c.
[ldr]    load:  loc=0x60292000, pa=0x60000000, sz=0x00014000, load=1.
[ldr]    load:  loc=0x602a6000, pa=0x60020000, sz=0x001f9000, load=1.
[ldr]    load:  loc=0x6028e000, pa=0x00000000, sz=0x00000000, load=0.
[ldr]  elf:  foreach:  elf=0x602fa30c, sz=0xa0a0.
[ldr]    load:  loc=0x602fb30c, pa=0x60219000, sz=0x0000b000, load=1.
[ldr]  elf:  foreach:  elf=0x603043ac, sz=0x23540.
[ldr]    load:  loc=0x603053ac, pa=0x60224000, sz=0x00069000, load=1.
[ldr]  KIP found at 0x60020000.
[ldr]  Go to kernel.

[----:0.000000]  kernel:  cpu #0 hello, sp=0xf0065f88.
[sgm0:0.007522]  inf:  hello.
[sgm0:0.009770]  inf:  free memory = 0x4c8000.
[alph:0.064399]  inf:  hello.
[alph:0.068992]  inf:  get memory from sigma0.
[alph:0.089952]  inf:  got memory:  0x4c8000 bytes.
[alph:0.093330]  inf:  Project config:
[alph:0.093521]  inf:    Board config:
[alph:0.093698]  inf:      ##  device    paddr        size        irq
[alph:0.093953]  inf:    Memory config:
[alph:0.094143]  inf:      ##  name       size        cached  contig
[alph:0.094370]  inf:    Apps config:
[alph:0.094616]  inf:      [0]
[alph:0.094787]  inf:        name:             hello
[alph:0.094999]  inf:        short_name:       hell
[alph:0.095207]  inf:        file:             ramfs:/hello.elf
[alph:0.095448]  inf:        stack_sz:         0x1000
[alph:0.095670]  inf:        heap_sz:          0x0
[alph:0.095898]  inf:        max_aspaces:      1
[alph:0.096101]  inf:        max_threads:      3
[alph:0.096304]  inf:        max_prio:         100
[alph:0.096512]  inf:        fpu:              0
[alph:0.096725]  inf:        malloc_strategy:  on_startup
[alph:0.096942]  inf:        devices:          
[alph:0.097149]  inf:        memory:           
[alph:0.097351]  inf:        args:             arg1=123, arg2=345
[alph:0.097614]  inf:  get iospace from sigma0.
[alph:0.097827]  inf:  got iospace from sigma0.
[alph:0.098519]  inf:  prepare named memory regions for apps.
[alph:0.098777]  inf:  prepared named memory regions for apps.
[alph:0.099028]  inf:  create app=hello.
hello.
argc=0x3, argv=0xff2000.
arg[0] = hello.
arg[1] = arg1=123.
arg[2] = arg2=345.
hello:  I'm alive.
hello:  I'm alive.
hello:  I'm alive.
hello:  I'm alive.
hello:  I'm alive.
hello:  bye-bye.

2. Create new external project [up]


The usual use case of WrmOS is work with external projects. It allows to do not modifying original WrmOS sources.

Step 2.1. Get cross-platform toolchain

See the article How to get toolchain for detail.

Step 2.2. Get WrmOS sources

Clone repository from github:

git clone https://github.com/wrmlab/wrmos.git

or download zip archive.

Step 2.3. Create external project directory

mkdir my_project

Step 2.4. Create application directory

mkdir -p my_project/app/my_hello

Step 2.5. Create application source file my_project/app/my_hello/main.cpp

#include <stdio.h>
#include <unistd.h>

int main(int argc, const char* argv[])
{
    printf("hello.\n");
    printf("argc=0x%x, argv=0x%p.\n", argc, argv);

    for (int i=0; i<argc; i++)
    {
        printf("arg[%d] = %s.\n", i, argv[i]);
    }

    const char* app_name = argv[0];
    for (int i=0; i<5; ++i)
    {
        printf("%s:  I'm alive.\n", app_name);
        sleep(1);
    }

    printf("%s:  bye-bye.\n", app_name);
    return 0;
}

Step 2.6. Create application make file my_project/app/my_hello/Makefile

objs       := main.o
incflags   := -I$(cfgdir)
baseflags  := -O2 -Wall -Werror
cxxflags   := -std=c++11 -fno-rtti -fno-exceptions
ldflags    :=
libs       := $(rtblddir)/lib/l4/libl4.a
libs       += $(rtblddir)/lib/wrmos/libwrmos.a
libs       += $(rtblddir)/lib/wlibc/libwlibc.a
libs       += $(rtblddir)/lib/wstdc++/libwstdc++.a

ifeq ($(dbg),1)
  baseflags += -DDEBUG
else
  baseflags += -DNDEBUG
endif

include $(wrmdir)/mk/base.mk

Step 2.7. Create project configuration directory

mkdir -p my_project/cfg/prj

Step 2.8. Create project configuration file my_project/cfg/prj/hello.prj

# platform parameters
plt_file     = $(wrmdir)/cfg/plt/arm-qemu-veca9.plt

# toolchain
gccprefix    = arm-linux-

# debug flags
usr_lib_dbg  = 1
usr_krn_dbg  = 1
usr_krn_log  = 1
usr_app_dbg  = 1
usr_ldr_dbg  = 0

# files to put in the ramfs
usr_ramfs    = config.alph:$(extdir)/cfg/alph/hello.alph
usr_ramfs   += hello.elf:$(blddir)/app/hello/hello.elf

# base file to set all project params
include $(wrmdir)/cfg/base.cfg

Step 2.9. Create Alpha configuration directory

mkdir -p my_project/cfg/alph

Step 2.10. Create Alpha's run-time configuration file my_project/cfg/alph/hello.alph

APPLICATIONS
	{
		name:             myhello
		short_name:       myhl
		file_path:        ramfs:/hello.elf
		stack_size:       0x1000
		heap_size:        0x0
		aspaces_max:      1
		threads_max:      3
		prio_max:         100
		fpu:              off
		malloc_strategy:  on_startup
		devices:
		memory:
		args:             arg1=xxx, arg2=yyy
	}

Step 2.11. Build external project

cd my_project
make -C ../wrmos build P=$(pwd)/cfg/prj/hello.prj E=$(pwd) B=$(pwd)/../build/my_hello -j

Step 2.12. Run project on QEMU virtual machine

qemu-system-arm -M vexpress-a9 -display none -serial stdio \
                -kernel ../build/my_hello/ldr/bootloader.elf

As result we will see output:

[ldr]   _    _ ___ __  __   ___  ___ 
[ldr]  | |  | | _ \  \/  | / _ \/ __|
[ldr]  | |/\| |   / |\/| || (_) \__ \
[ldr]  |__/\__|_|_\_|  |_(_)___/|___/
[ldr]          From Russia with love!
[ldr]
[ldr]  cpu #0/1 ready, sp=0x60340518.
[ldr]
[ldr]  hello:   13:46:59  Jun  5 2018.
[ldr]  gccver:  7.3.0.
[ldr]  hware:   arm, cortex_a9, vexpress_a9, qemu_vexpress_a9.
[ldr]  ram:     [0x60000000 - 0x60800000)       8 MB.
[ldr]  ramfs:   [0x6028d000 - 0x60338000)     684 KB.
[ldr]  ##  name                    data      size  content
[ldr]   1  kernel.elf        0x6028e000    443140  'ELF ...'
[ldr]   2  sigma0.elf        0x602fa304     41112  'ELF ...'
[ldr]   3  roottask.elf      0x6030439c    144696  'ELF ...'
[ldr]   4  config.alph       0x603278d4       343  'APPLICAT ...'
[ldr]   5  hello.elf         0x60328000     64204  'ELF ...'
[ldr]
[ldr]  KIP found at 0x60020000.
[ldr]  Go to kernel.

[----:0.000000]  kernel:  cpu #0 hello, sp=0xf0065f88.
[sgm0:0.007362]  inf:  hello.
[sgm0:0.009624]  inf:  free memory = 0x4c8000.
[alph:0.064424]  inf:  hello.
[alph:0.069014]  inf:  get memory from sigma0.
[alph:0.089183]  inf:  got memory:  0x4c8000 bytes.
[alph:0.092560]  inf:  Project config:
[alph:0.092771]  inf:    Board config:
[alph:0.092962]  inf:      ##  device    paddr        size        irq
[alph:0.093224]  inf:    Memory config:
[alph:0.093421]  inf:      ##  name       size        cached  contig
[alph:0.093684]  inf:    Apps config:
[alph:0.093936]  inf:      [0]
[alph:0.094115]  inf:        name:             myhello
[alph:0.094352]  inf:        short_name:       myhl
[alph:0.094570]  inf:        file:             ramfs:/hello.elf
[alph:0.094812]  inf:        stack_sz:         0x1000
[alph:0.095046]  inf:        heap_sz:          0x0
[alph:0.095255]  inf:        max_aspaces:      1
[alph:0.095450]  inf:        max_threads:      3
[alph:0.095647]  inf:        max_prio:         100
[alph:0.095846]  inf:        fpu:              0
[alph:0.096047]  inf:        malloc_strategy:  on_startup
[alph:0.096255]  inf:        devices:          
[alph:0.096452]  inf:        memory:           
[alph:0.096640]  inf:        args:             arg1=xxx, arg2=yyy
[alph:0.096895]  inf:  get iospace from sigma0.
[alph:0.097101]  inf:  got iospace from sigma0.
[alph:0.097748]  inf:  prepare named memory regions for apps.
[alph:0.097992]  inf:  prepared named memory regions for apps.
[alph:0.098221]  inf:  create app=myhello.
hello.
argc=0x3, argv=0xff2000.
arg[0] = myhello.
arg[1] = arg1=xxx.
arg[2] = arg2=yyy.
myhello:  I'm alive.
myhello:  I'm alive.
myhello:  I'm alive.
myhello:  I'm alive.
myhello:  I'm alive.
myhello:  bye-bye.