Stage 4. Further init

Previously we successfully survived fmtquoteinstall, lets check ipaq1110 port to see what do we have next:

  • confinit - our part
  • xinit - inferno part
  • mmuinit - we don't need this because we have no MMU
  • poolinit - inferno part
  • poolsizeinit - our part
  • trapinit - not needed for now
  • clockinit - we already have basic implementation of this
  • printinit - inferno part
  • screeninit - we don't have screen
  • procinit - inferno part
  • links - inferno part
  • chandevreset - inferno part
  • archconsole - our part
  • kbdinit - we have no keyboard to init
  • userinit - our part
  • schedinit - here we finally jump to inferno

Substage 1. confinit

Lets take a look at ipaq1110's confinit:

void
confinit(void)
{
    ulong base;

    archconfinit();

    base = PGROUND((ulong)end);
    conf.base0 = base;

    conf.base1 = 0;
    conf.npage1 = 0;

    conf.npage0 = (conf.topofmem - base)/BY2PG;

    conf.npage = conf.npage0 + conf.npage1;
    conf.ialloc = (((conf.npage*(main_pool_pcnt))/100)/2)*BY2PG;

    conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
    conf.nmach = 1;

}

archconfinit inits ipaq-specific things, so we dont need this. This procedure initializes alloc memory params. Lets convert it to our case:

void
confinit(void)
{
    ulong base;

    conf.topofmem = 0xa0000000+16*MB;
    m->cpuhz = 57600000;

    base = PGROUND((ulong)end);
    conf.base0 = base;

    conf.base1 = 0;
    conf.npage1 = 0;

    conf.npage0 = (conf.topofmem - base)/BY2PG;

    conf.npage = conf.npage0 + conf.npage1;
    conf.ialloc = (((conf.npage*(main_pool_pcnt))/100)/2)*BY2PG;

    conf.nproc = 20;
    conf.nmach = 1;

}

And add to the main.c:

#include <stdbool.h>

#include "u.h"
#include "../port/lib.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include "mem.h"

#include "uart.h"
#include "../port/uart.h"

PhysUart* physuart[1];

Mach *m = (Mach*)MACHADDR;
Conf conf;
Proc *up = 0;

extern int main_pool_pcnt;
extern int heap_pool_pcnt;
extern int image_pool_pcnt;
extern int kernel_pool_pcnt;

void
confinit(void)
{
    ulong base;

    conf.topofmem = 0xa0000000+16*MB;
    m->cpuhz = 57600000;

    base = PGROUND((ulong)end);
    conf.base0 = base;

    conf.base1 = 0;
    conf.npage1 = 0;

    conf.npage0 = (conf.topofmem - base)/BY2PG;

    conf.npage = conf.npage0 + conf.npage1;
    conf.ialloc = (((conf.npage*(main_pool_pcnt))/100)/2)*BY2PG;

    conf.nproc = 20;
    conf.nmach = 1;

}

int main(void) {
  memset(m, 0, sizeof(Mach));   /* clear the mach struct */
  conf.nmach = 1;
  uart0_puts("memset Mach\r\n");
  archreset();
  uart0_puts("archreset\r\n");
  quotefmtinstall();
  confinit();
  uart0_puts("confinit\r\n");

  while(true) {

  }
  return 0;
}

void
setpanic(void) {
  uart0_puts("Infernal panic\r\n");
  while (1);
}

uint32_t
__swp(uint32_t x, volatile uint32_t *p) {
  uint32_t ret;
  __asm__ __volatile__ (
    "swp %[ret], %[x], [%[m]]\n"
    : [ret] "=&r" (ret)
    : [m] "r" (p), [x] "r" (x)
    );
  return ret;
}

ulong
_tas(ulong* u) {
  return __swp(0xDEADDEAD, u);
}

int
islo(void) {
  register uint32_t ret;
  uint32_t val = PsrDirq;

  __asm__ __volatile__
  (
    "mrs %[r0], CPSR\n\t"
    "and %[r0], %[val]\n\t"
    "eor %[r0], %[val]\n\t"
    : [r0] "=r"(ret)
    : [val] "r" (val)
  );

  return ret;
}

int
splhi(void) { 
  register uint32_t ret, tmp;

  __asm__ __volatile__
  (
    "mrs %[r0], CPSR" "\n\t"
    "orr %[r1], %[r0], #0x80" "\n\t"
    "msr CPSR_c, %[r1]" "\n\t"
    "mov %[dst], lr\n"
    : [dst] "=&r" (m->splpc), [r0] "=r"(ret), [r1] "=r"(tmp)
  );

  return ret;
}

void
splxpc(int i) {
  register uint32_t ret;

  __asm__ __volatile__
  (
    "mrs %[r0], CPSR" "\n\t"
    "msr CPSR_c, %[r1]" "\n\t"
    : [r0] "=r"(ret)
    : [r1] "r"(i)
  );

  return;
}

void
splx(int i)
{
  __asm__ __volatile__ (
    "mov %[dst], lr\n"
    : [dst] "=&r" (m->splpc)
    );
}

int
spllo(void) {
  register uint32_t ret, tmp;
  uint32_t val = PsrDirq | PsrDfiq;

  __asm__ __volatile__
  (
    "mrs %[r0], CPSR\n\t"
    "bic %[r1], %[r0], %[val]\n\t"
    "msr CPSR_c, %[r1]\n\t"
    : [r0] "=r"(ret), [r1] "=r"(tmp)
    : [val] "r" (val)
  );

  return ret;
}

void
idlehands(void) {
  uart0_puts("bsp::idlehands\r\n");
    idle();
}

int
setlabel(Label* l) {
  __asm__ __volatile__ (
    "mov %[dstsp], sp\n"
    "mov %[dstpc], lr\n"
    : [dstsp] "=&r" (l->sp), [dstpc] "=&r" (l->pc)
    );

  return 0;
}

void
gotolabel(Label* l) {
  __asm__ __volatile__ (
    "mov sp, %[srcsp]\n"
    "mov lr, %[srcpc]\n"
    "bx lr"
    :
    : [srcsp] "r" (l->sp), [srcpc] "r" (l->pc)
    );
}

void
reboot(void) {
  uart0_puts("reboot\r\n");
  return;
  }

void
halt(void) {
  uart0_puts("halt\r\n");
  return;
}

int
segflush(void* v, ulong u) {
  return 1;
}

void
fpinit(void) {
}

void
FPsave(void* v) {
}

void
FPrestore(void* v) {
}

static void
linkproc(void) {
    spllo();
    if (waserror())
        print("error() underflow: %r\n");
    else
        (*up->kpfun)(up->arg);
    pexit("end proc", 1);
}

void
kprocchild(Proc *p, void (*func)(void*), void *arg) {
    p->sched.pc = (ulong)linkproc;
    p->sched.sp = (ulong)p->kstack+KSTACK-8;

    p->kpfun = func;
    p->arg = arg;
}

void
exit(int status) {
}

Build:

main.c:36:31: error: 'main_pool_pcnt' undeclared (first use in this function)
  conf.ialloc = (((conf.npage*(main_pool_pcnt))/100)/2)*BY2PG;
                               ^
main.c:36:31: note: each undeclared identifier is reported only once for each function it appears in
mk: arm-none-eabi-gcc -O0 -std=c1x ...  : exit status=exit(1)

Add the following to the code section is lpc-e2468:

    int kernel_pool_pcnt = 10;
    int main_pool_pcnt = 33;
    int heap_pool_pcnt = 34;
    int image_pool_pcnt = 33;

Add the end symbol definition in lpc_e2468.ld:

ENTRY(_start)

MEMORY 
{
    ram             : ORIGIN = 0xa0008000, LENGTH = 16M-0x8000
}

_stack_end = 0xa0000000 + 16M;
_vStackTop = _stack_end;

SECTIONS 
{
    . = 0xa0008000;

  .start : { *(.start)} >ram

  .text :  ALIGN(16) SUBALIGN(16)
    { 
        _text = .;
        KEEP(*(vectors))
        *(.text)
        *(.text.*)
        *(.rodata)
        *(.rodata.*)
        *(.glue_7t)
        *(.glue_7)
        *(.gcc*)
        *(.ctors)
        *(.dtors)
    } > ram

    .ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)}

    __exidx_start = .;
    .ARM.exidx : {*(.ARM.exidx* .gnu.linkonce.armexidx.*)} > ram
    __exidx_end = .;

    .eh_frame_hdr : {*(.eh_frame_hdr)}

    .eh_frame : ONLY_IF_RO {*(.eh_frame)}

    . = ALIGN(4);
    _etext = .;
    _textdata = _etext;

    .data :
    {
        _data = .;
        *(.data)
        . = ALIGN(4);
        *(.data.*)
        . = ALIGN(4);
        *(.ramtext)
        . = ALIGN(4);
        _edata = .;
    } > ram AT > ram

    .bss :
    {
        _bss_start = .;
        *(.bss)
        . = ALIGN(4);
        *(.bss.*)
        . = ALIGN(4);
        *(COMMON)
        . = ALIGN(4);
        _bss_end = .;
    } > ram    

    . = ALIGN(4);
    _bss_end = . ;
    _end = .;
    end = .;
}

Rebuild and run on hardware:

TFTP from server 10.218.35.27; our IP address is 10.218.35.61
Filename 'iarmtest'.
Load address: 0xa0008000
Loading: T T T T T T T ########################
done
Bytes transferred = 352124 (55f7c hex)
## Starting application at 0xA0008000 ...
memset Mach
Inferno OS compiled by GCC
archreset
confinit

Substage 2. xinit

Lets just add it right after confinit:

    confinit();
    xinit();
    uart0_puts("xinit\r\n");

Rebuild and flash:

FTP from server 10.218.35.27; our IP address is 10.218.35.61
Filename 'iarmtest'.
Load address: 0xa0008000
Loading: T T ########################
done
Bytes transferred = 352124 (55f7c hex)
## Starting application at 0xA0008000 ...
memset Mach
Inferno OS compiled by GCC
archreset
xinit

Substage 3. poolinit

Add poolinit after xinit:

    xinit();
    poolinit();
    uart0_puts("poolinit\r\n");

Rebuild and run:

TFTP from server 10.218.35.27; our IP address is 10.218.35.61
Filename 'iarmtest'.
Load address: 0xa0008000
Loading: ########################
done
Bytes transferred = 352124 (55f7c hex)
## Starting application at 0xA0008000 ...
memset Mach
Inferno OS compiled by GCC
archreset
poolinit

Substage 4. poolsizeinit

Lets check ipaq1110 implementation of poolsizeinit:

static void
poolsizeinit(void)
{
    ulong nb;

    nb = conf.npage*BY2PG;
    poolsize(mainmem, (nb*main_pool_pcnt)/100, 0);
    poolsize(heapmem, (nb*heap_pool_pcnt)/100, 0);
    poolsize(imagmem, (nb*image_pool_pcnt)/100, 1);
}

just copy it to our main.c and add call to main procedure:

...
static void
poolsizeinit(void)
{
    ulong nb;

    nb = conf.npage*BY2PG;
    poolsize(mainmem, (nb*main_pool_pcnt)/100, 0);
    poolsize(heapmem, (nb*heap_pool_pcnt)/100, 0);
    poolsize(imagmem, (nb*image_pool_pcnt)/100, 1);
}

int main(void) {
  memset(m, 0, sizeof(Mach));   /* clear the mach struct */
  conf.nmach = 1;
  uart0_puts("memset Mach\r\n");
  archreset();
  uart0_puts("archreset\r\n");
  quotefmtinstall();
  confinit();
  xinit();
  poolinit();
  poolsizeinit();
  uart0_puts("poolsizeinit\r\n");

  while(true) {

  }
  return 0;
}
...

Rebuild and run:

TFTP from server 10.218.35.27; our IP address is 10.218.35.61
Filename 'iarmtest'.
Load address: 0xa0008000
Loading: #########################
done
Bytes transferred = 352364 (5606c hex)
## Starting application at 0xA0008000 ...
memset Mach
Inferno OS compiled by GCC
archreset
poolsizeinit

Substage 5. clockinit

We already have a basic implementation of this procedure in clock.c, so just add a call to main procedure:

...
    poolsizeinit();
    clockinit();
    uart0_puts("clockinit\r\n");
...

Rebuild and run:

TFTP from server 10.218.35.27; our IP address is 10.218.35.61
Filename 'iarmtest'.
Load address: 0xa0008000
Loading: #########################
done
Bytes transferred = 352364 (5606c hex)
## Starting application at 0xA0008000 ...
memset Mach
Inferno OS compiled by GCC
archreset
clockinit

Substage 6. printinit

It is a part of Inferno, we have to add the call to main proc:

...
    clockinit();
    printinit();
    uart0_puts("printinit\r\n");
...

Rebuild and run:

TFTP from server 10.218.35.27; our IP address is 10.218.35.61
Filename 'iarmtest'.
Load address: 0xa0008000
Loading: #########################
done
Bytes transferred = 352364 (5606c hex)
## Starting application at 0xA0008000 ...
memset Mach
Inferno OS compiled by GCC
archreset
printinit

Substage 7. procinit

Another part of inferno, as usual: add call to main proc:

...
    printinit();
    procinit();
    uart0_puts("procinit\r\n");
...

Rebuild and run:

TFTP from server 10.218.35.27; our IP address is 10.218.35.61
Filename 'iarmtest'.
Load address: 0xa0008000
Loading: #########################
done
Bytes transferred = 352364 (5606c hex)
## Starting application at 0xA0008000 ...
memset Mach
Inferno OS compiled by GCC
archreset
procinit

Substage 8. links

Eh that gets predictable. Add call to main proc:

...
    procinit();
    links();
    uart0_puts("links\r\n");
...

Rebuild and run:

TFTP from server 10.218.35.27; our IP address is 10.218.35.61
Filename 'iarmtest'.
Load address: 0xa0008000
Loading: #########################
done
Bytes transferred = 352380 (5607c hex)
## Starting application at 0xA0008000 ...
memset Mach
Inferno OS compiled by GCC
archreset
links

Substage 9. chandevreset

Add call to main proc:

...
    links();
    chandevreset();
    uart0_puts("chandevreset\r\n");
...

Rebuild and run:

TFTP from server 10.218.35.27; our IP address is 10.218.35.61
Filename 'iarmtest'.
Load address: 0xa0008000
Loading: #########################
done
Bytes transferred = 352380 (5607c hex)
## Starting application at 0xA0008000 ...
memset Mach
Inferno OS compiled by GCC
archreset
chandevreset

Substage 10. archconsole

Lets examine archconsole from ipaq1110:

void
archconsole(void)
{
    uartspecial(0, 115200, 'n', &kbdq, &printq, kbdcr2nl);
}

Seems ok, copy that to main.c.

Add call to main proc:

...
    chandevreset();
    archconsole();
    uart0_puts("archconsole\r\n");
...

Rebuild:

main.o: In function `archconsole':
main.c:(.text+0x214): undefined reference to `uartspecial'
collect2: error: ld returned 1 exit status
mk:    ...  : exit status=exit(1)

uartspecial belongs to port-specific devuart.c and does some UART mumbo-jumbo for inferno os. Lets copy and rewrite devuart.c:

#include    "u.h"
#include    "../port/lib.h"
#include    "mem.h"
#include    "dat.h"
#include    "fns.h"
#include    "io.h"
#include    "../port/error.h"
#include    "../port/netif.h"

/*
 * currently no DMA or flow control (hardware or software)
 */

enum
{
    Stagesize= 1024,
    Dmabufsize=Stagesize/2,
    Nuart=7,        /* max per machine */

    CTLS= 023,
    CTLQ= 021,
};

typedef struct Uart Uart;
struct Uart
{
    QLock;

    int opens;

    int enabled;

    int frame;      /* framing errors */
    int overrun;    /* rcvr overruns */
    int soverrun;   /* software overruns */
    int perror;     /* parity error */
    int bps;        /* baud rate */
    uchar   bits;
    char    parity;

    int inters;     /* total interrupt count */
    int rinters;    /* interrupts due to read */
    int winters;    /* interrupts due to write */

    int rcount;     /* total read count */
    int wcount;     /* total output count */

    int xonoff;     /* software flow control on */
    int blocked;        /* output blocked */

    /* buffers */
    int (*putc)(Queue*, int);
    Queue   *iq;
    Queue   *oq;

    int port;

    /* staging areas to avoid some of the per character costs */
    uchar   *ip;
    uchar   *ie;
    uchar   *op;
    uchar   *oe;

    /* put large buffers last to aid register-offset optimizations: */
    char    name[KNAMELEN];
    uchar   istage[Stagesize];
    uchar   ostage[Stagesize];
};

static Uart *uart[Nuart];
static int nuart;
static int uartspcl;
int redirectconsole;

static void
uartset(Uart *p)
{
    ulong ocr3;
    ulong brdiv;
    int n;

    /* brdiv = CLOCKFREQ/16/p->bps - 1; */
    /* ocr3 = reg->utcr3; */
    /* reg->utcr3 = ocr3&~(UTCR3_RXE|UTCR3_TXE); */
    /* reg->utcr1 = brdiv >> 8; */
    /* reg->utcr2 = brdiv & 0xff; */
    /* /\* set PE and OES appropriately for o/e/n: *\/ */
    /* reg->utcr0 = ((p->parity&3)^UTCR0_OES)|(p->bits&UTCR0_DSS); */
    /* reg->utcr3 = ocr3; */

  uart0_init();

    /* set buffer length according to speed, to allow
     * at most a 200ms delay before dumping the staging buffer
     * into the input queue
     */
    n = p->bps/(10*1000/200);
    p->ie = &p->istage[n < Stagesize ? n : Stagesize];
}

/*
 *  send break
 */
static void
uartbreak(Uart *p, int ms)
{
    if(ms == 0)
        ms = 200;
    /* reg->utcr3 |= UTCR3_BRK; */
  uart0_setbreak();
    tsleep(&up->sleep, return0, 0, ms);
  uart0_unsetbreak();
    /* reg->utcr3 &= ~UTCR3_BRK; */
}

/*
 *  turn on a port
 */
static void
uartenable(Uart *p)
{
    if(p->enabled)
        return;

    /* archuartpower(p->port, 1); */
    uartset(p);
    /* reg->utsr0 = 0xff;       // clear all sticky status bits */
    /* // enable receive, transmit, and receive interrupt: */
    /* reg->utcr3 = UTCR3_RXE|UTCR3_TXE|UTCR3_RIM; */
    p->blocked = 0;
    p->xonoff = 0;
    p->enabled = 1;
}

/*
 *  turn off a port
 */
static void
uartdisable(Uart *p)
{
//  p->reg->utcr3 = 0;      // disable TX, RX, and ints
    p->blocked = 0;
    p->xonoff = 0;
    p->enabled = 0;
//  archuartpower(p->port, 0);
}

/*
 *  put some bytes into the local queue to avoid calling
 *  qconsume for every character
 */
static int
stageoutput(Uart *p)
{
    int n;
    Queue *q = p->oq;

    if(q == nil)
        return 0;
    n = qconsume(q, p->ostage, Stagesize);
    if(n <= 0)
        return 0;
    p->op = p->ostage;
    p->oe = p->ostage + n;
    return n;
}

static void
uartxmit(Uart *p)
{
    ulong e = 0;

    if(!p->blocked) {
        while(p->op < p->oe || stageoutput(p)) {    
            if(uart0_txready()) {
        uart0_putc(*(p->op++));
//              reg->utdr = *(p->op++);
                p->wcount++;
            }
        }
    }
}

static void
uartrecvq(Uart *p)
{
    uchar *cp = p->istage;
    int n = p->ip - cp;

    if(n == 0)
        return;
    if(p->putc)
        while(n-- > 0) 
            p->putc(p->iq, *cp++);
    else if(p->iq) 
        if(qproduce(p->iq, p->istage, n) < n){
            /* if xonoff, should send XOFF when qwindow(p->iq) < threshold */
            p->soverrun++;
            //print("qproduce flow control");
        }
    p->ip = p->istage;
}

static void
uartrecv(Uart *p)
{
    /* UartReg *reg = p->reg; */
    /* ulong n; */
    /* while(reg->utsr1 & UTSR1_RNE) { */
    /*  int c; */
    /*  n = reg->utsr1; */
    /*  c = reg->utdr; */
    /*  if(n & (UTSR1_PRE|UTSR1_FRE|UTSR1_ROR)) { */
    /*      if(n & UTSR1_PRE)  */
    /*          p->perror++; */
    /*      if(n & UTSR1_FRE)  */
    /*          p->frame++; */
    /*      if(n & UTSR1_ROR)  */
    /*          p->overrun++; */
    /*      continue; */
    /*  } */
    /*  if(p->xonoff){ */
    /*      if(c == CTLS){ */
    /*          p->blocked = 1; */
    /*      }else if (c == CTLQ){ */
    /*          p->blocked = 0; */
    /*      } */
    /*  } */
    /*  *p->ip++ = c; */
    /*  if(p->ip >= p->ie) */
    /*      uartrecvq(p); */
    /*  p->rcount++; */
    /* } */
    /* if(reg->utsr0 & UTSR0_RID) { */
    /*  reg->utsr0 = UTSR0_RID; */
    /*  uartrecvq(p); */
    /* } */
}

static void
uartclock(void)
{
    Uart *p;
    int i;

    for(i=0; i<nuart; i++){
        p = uart[i];
        if(p != nil)
            uartrecvq(p);
    }
}

static void
uartkick(void *a)
{
    Uart *p = a;
    int x;

    x = splhi();
    uartxmit(p);
    splx(x);
}

/*
 *  UART Interrupt Handler
 */
static void
uartintr(Ureg* ur, void* arg)
{
    /* Uart *p = arg;            */
    /* UartReg *reg = p->reg; */
    /* ulong m = reg->utsr0; */
    /* int dokick; */

    /* dokick = p->blocked; */
    /* p->inters++; */
    /* if(m & (UTSR0_RFS|UTSR0_RID|UTSR0_EIF)) { */
    /*  p->rinters++; */
    /*  uartrecv(p); */
    /* } */
    /* if(p->blocked) */
    /*  dokick = 0; */
    /* if((m & UTSR0_TFS) && (reg->utcr3&UTCR3_TIM || dokick)) { */
    /*  p->winters++; */
    /*  uartxmit(p); */
    /* } */

    /* if(m & (UTSR0_RBB|UTSR0_REB)) { */
    /*  //print("<BREAK>"); */
    /*  /\* reg->utsr0 = UTSR0_RBB|UTSR0_REB; *\/ */
    /*  reg->utsr0 = m & (UTSR0_RBB|UTSR0_REB); */
    /*  /\* what to do? if anything *\/ */
    /* } */
}

static void
uartsetup(ulong port, char *name)
{
    Uart *p;

    if(nuart >= Nuart)
        return;

    p = xalloc(sizeof(Uart));
    uart[nuart++] = p;
    strcpy(p->name, name);

    p->port = port;
//  p->reg = UARTREG(port);
    p->bps = 115200;
    p->bits = 8;
    p->parity = 'n';

    p->iq = qopen(4*1024, 0, 0 , p);
    p->oq = qopen(4*1024, 0, uartkick, p);

    p->ip = p->istage;
    p->ie = &p->istage[Stagesize];
    p->op = p->ostage;
    p->oe = p->ostage;
    /* if(port == 1) */
    /*  GPCLKREG->gpclkr0 |= 1; /\* SUS=1 for uart on serial 1 *\/ */

//  intrenable(UARTbit(port), uartintr, p, BusCPU, name);
}

static void
uartinstall(void)
{
    static int already;

    if(already)
        return;
    already = 1;

    uartsetup(3, "eia0");
    uartsetup(1, "eia1");
    addclock0link(uartclock, 22);
}

/*
 *  called by main() to configure a duart port as a console or a mouse
 */
void
uartspecial(int port, int bps, char parity, Queue **in, Queue **out, int (*putc)(Queue*, int))
{
    Uart *p;

    uartinstall();
    if(port >= nuart) 
        return;
    p = uart[port];
    if(bps) 
        p->bps = bps;
    if(parity)
        p->parity = parity;
    uartenable(p);
    p->putc = putc;
    if(in)
        *in = p->iq;
    if(out)
        *out = p->oq;
    p->opens++;
    uartspcl = 1;
}

Dirtab *uartdir;
int ndir;

static void
setlength(int i)
{
    Uart *p;

    if(i > 0){
        p = uart[i];
        if(p && p->opens && p->iq)
            uartdir[1+3*i].length = qlen(p->iq);
    } else for(i = 0; i < nuart; i++){
        p = uart[i];
        if(p && p->opens && p->iq)
            uartdir[1+3*i].length = qlen(p->iq);
    }
}

/*
 *  all uarts must be uartsetup() by this point or inside of uartinstall()
 */
static void
uartreset(void)
{
    int i;
    Dirtab *dp;

    uartinstall();

    ndir = 1+3*nuart;
    uartdir = xalloc(ndir * sizeof(Dirtab));
    dp = uartdir;
    strcpy(dp->name, ".");
    mkqid(&dp->qid, 0, 0, QTDIR);
    dp->length = 0;
    dp->perm = DMDIR|0555;
    dp++;
    for(i = 0; i < nuart; i++){
        /* 3 directory entries per port */
        strcpy(dp->name, uart[i]->name);
        dp->qid.path = NETQID(i, Ndataqid);
        dp->perm = 0660;
        dp++;
        sprint(dp->name, "%sctl", uart[i]->name);
        dp->qid.path = NETQID(i, Nctlqid);
        dp->perm = 0660;
        dp++;
        sprint(dp->name, "%sstatus", uart[i]->name);
        dp->qid.path = NETQID(i, Nstatqid);
        dp->perm = 0444;
        dp++;
    }
}

static Chan*
uartattach(char *spec)
{
    return devattach('t', spec);
}

static Walkqid*
uartwalk(Chan *c, Chan *nc, char **name, int nname)
{
    return devwalk(c, nc, name, nname, uartdir, ndir, devgen);
}

static int
uartstat(Chan *c, uchar *dp, int n)
{
    if(NETTYPE(c->qid.path) == Ndataqid)
        setlength(NETID(c->qid.path));
    return devstat(c, dp, n, uartdir, ndir, devgen);
}

static Chan*
uartopen(Chan *c, int omode)
{
    Uart *p;

    c = devopen(c, omode, uartdir, ndir, devgen);

    switch(NETTYPE(c->qid.path)){
    case Nctlqid:
    case Ndataqid:
        p = uart[NETID(c->qid.path)];
        qlock(p);
        if(p->opens++ == 0){
            uartenable(p);
            qreopen(p->iq);
            qreopen(p->oq);
        }
        qunlock(p);
        break;
    }

    return c;
}

static void
uartclose(Chan *c)
{
    Uart *p;

    if(c->qid.type & QTDIR)
        return;
    if((c->flag & COPEN) == 0)
        return;
    switch(NETTYPE(c->qid.path)){
    case Ndataqid:
    case Nctlqid:
        p = uart[NETID(c->qid.path)];
        qlock(p);
        if(--(p->opens) == 0){
            uartdisable(p);
            qclose(p->iq);
            qclose(p->oq);
            p->ip = p->istage;
        }
        qunlock(p);
        break;
    }
}

static long
uartstatus(Chan *c, Uart *p, void *buf, long n, long offset)
{
    char str[256];
    USED(c);

    str[0] = 0;
    snprint(str, sizeof(str),
            "b%d l%d p%c s- x%d\n"
            "opens %d ferr %d oerr %d perr %d baud %d parity %c"
            " intr %d rintr %d wintr %d"
            " rcount %d wcount %d",
        p->bps, p->bits, p->parity, p->xonoff,
        p->opens, p->frame, p->overrun+p->soverrun, p->perror, p->bps, p->parity,
        p->inters, p->rinters, p->winters,
        p->rcount, p->wcount);

    strcat(str, "\n");
    return readstr(offset, buf, n, str);
}

static long
uartread(Chan *c, void *buf, long n, vlong offset)
{
    Uart *p;

    if(c->qid.type & QTDIR){
        setlength(-1);
        return devdirread(c, buf, n, uartdir, ndir, devgen);
    }

    p = uart[NETID(c->qid.path)];
    switch(NETTYPE(c->qid.path)){
    case Ndataqid:
        return qread(p->iq, buf, n);
    case Nctlqid:
        return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE);
    case Nstatqid:
        return uartstatus(c, p, buf, n, offset);
    }

    return 0;
}

static void
uartctl(Uart *p, char *cmd)
{
    int i, n;

    /* let output drain for a while (up to 4 secs) */
    /* for(i = 0; i < 200 && (qlen(p->oq) || p->reg->utsr1 & UTSR1_TBY); i++) */
    /*  tsleep(&up->sleep, return0, 0, 20); */

    if(strncmp(cmd, "break", 5) == 0){
        uartbreak(p, 0);
        return;
    }

    n = atoi(cmd+1);
    switch(*cmd){
    case 'B':
    case 'b':
        if(n <= 0) 
            error(Ebadarg);
        p->bps = n;
        uartset(p);
        break;
    case 'f':
    case 'F':
        qflush(p->oq);
        break;
    case 'H':
    case 'h':
        qhangup(p->iq, 0);
        qhangup(p->oq, 0);
        break;
    case 'L':
    case 'l':
        if(n < 7 || n > 8)
            error(Ebadarg);
        p->bits = n;
        uartset(p);
        break;
    case 'n':
    case 'N':
        qnoblock(p->oq, n);
        break;
    case 'P':
    case 'p':
        p->parity = *(cmd+1);
        uartset(p);
        break;
    case 'K':
    case 'k':
        uartbreak(p, n);
        break;
    case 'Q':
    case 'q':
        qsetlimit(p->iq, n);
        qsetlimit(p->oq, n);
        break;
    case 'X':
    case 'x':
        p->xonoff = n;
        break;
    }
}

static long
uartwrite(Chan *c, void *buf, long n, vlong offset)
{
    Uart *p;
    char cmd[32];

    USED(offset);

    if(c->qid.type & QTDIR)
        error(Eperm);

    p = uart[NETID(c->qid.path)];

    switch(NETTYPE(c->qid.path)){
    case Ndataqid:
        return qwrite(p->oq, buf, n);
    case Nctlqid:

        if(n >= sizeof(cmd))
            n = sizeof(cmd)-1;
        memmove(cmd, buf, n);
        cmd[n] = 0;
        uartctl(p, cmd);
        return n;
    default:
        error(Egreg);
        return 0;
    }
}

static int
uartwstat(Chan *c, uchar *dp, int n)
{
    Dir d;
    Dirtab *dt;

    if(!iseve())
        error(Eperm);
    if(c->qid.type & QTDIR)
        error(Eperm);
    if(NETTYPE(c->qid.path) == Nstatqid)
        error(Eperm);

    dt = &uartdir[1+3 * NETID(c->qid.path)];
    n = convM2D(dp, n, &d, nil);
    if(d.mode != ~0UL){
        d.mode &= 0666;
        dt[0].perm = dt[1].perm = d.mode;
    }
    return n;
}

void
uartpower(int on)
{
    Uart *p;
    int i;

    for(i=0; i<nuart; i++){
        p = uart[i];
        if(p != nil && p->opens){
            if(on && !p->enabled){
                p->enabled = 0;
                uartenable(p);
                uartkick(p);
            }else{
                if(p->port != 3)    /* leave the console */
                    uartdisable(p);
                p->enabled = 0;
            }
        }
    }
}

Dev uartdevtab = {
    't',
    "uart",

    uartreset,
    devinit,
    devshutdown,
    uartattach,
    uartwalk,
    uartstat,
    uartopen,
    devcreate,
    uartclose,
    uartread,
    devbread,
    uartwrite,
    devbwrite,
    devremove,
    uartwstat,
    uartpower,
};

/*
 * for use by iprint
 */
void
uartputc(int c)
{

    if(!uartspcl && !redirectconsole)
        return;
    if(c == 0)
        return;
  uart0_putc(c);
//  r = UARTREG(3);
    /* while((r->utsr1 & UTSR1_TNF) == 0) */
    /*  {} */
    /* r->utdr = c; */
    /* if(c == '\n') */
    /*  while(r->utsr1 & UTSR1_TBY) /\* flush xmit fifo *\/ */
    /*      {} */
}

void
uartputs(char *data, int len)
{
    int s;

    if(!uartspcl && !redirectconsole)
        return;
    clockpoll();
//  s = splfhi();
    while(--len >= 0){
        if(*data == '\n')
            uartputc('\r');
        uartputc(*data++);
    }
//  splx(s);
}

/* /\* */
/*  * for use by debugger */
/*  *\/ */
/* int */
/* uartgetc(void) */
/* { */
/*  UartReg *r; */

/*  if(!uartspcl) */
/*      return -1; */
/*  clockcheck(); */
/*  r = UARTREG(3); */
/*  while(!(r->utsr1 & UTSR1_RNE)) */
/*      clockcheck(); */
/*  return r->utdr; */
/* } */

devuart.c is already contained in port directory, so we cant just add it to OBJ in mkfile. We should write our own recipe for it:

diff -r 032133444775 os/lpc-e2468-olimex/mkfile
--- a/os/lpc-e2468-olimex/mkfile    Sun May 31 06:37:02 2015 +0300
+++ b/os/lpc-e2468-olimex/mkfile    Sun May 31 07:34:32 2015 +0300
@@ -55,4 +55,7 @@
     $CP -O binary ilpc-e2468.elf ilpc-e2468.bin
     arm-none-eabi-size ./ilpc-e2468.elf

+devuart.$O:    devuart.c
+   $CC $CFLAGS devuart.c
+
 <../port/portmkfile

Rebuild and run:

TFTP from server 10.218.35.27; our IP address is 10.218.35.61
Filename 'iarmtest'.
Load address: 0xa0008000
Loading: ########################
done
Bytes transferred = 350092 (5578c hex)
## Starting application at 0xA0008000 ...
memset Mach
Inferno OS compiled by GCC
archreset
archconsole

Substage 11. printing!

Add these lines right after archconsole:

    print("%ld MHz id %8.8lux\n", (m->cpuhz)/1000000, getcpuid());
    print("\nInferno %s\n", VERSION);
    print("Vita Nuova\n");
    print("conf %s (%lud) jit %d\n\n",conffile, kerndate, cflag);

Include version.h file:

#include "uart.h"
#include "../port/uart.h"
+#include "version.h"

PhysUart* physuart[1];

Add this procedure to main.c:

uint32_t
getcpuid(void) {
  return 0xabcdef;
}

Add these externs in main.c:

extern ulong kerndate;
extern int cflag;

Rebuild and run:

TFTP from server 10.218.35.27; our IP address is 10.218.35.61
Filename 'iarmtest'.
Load address: 0xa0008000
Loading: ########################
done
Bytes transferred = 350332 (5587c hex)
## Starting application at 0xA0008000 ...
memset Mach
Inferno OS compiled by GCC
archreset
57 MHz id 00abcdef

Inferno Fourth Edition (20150328)
Vita Nuova
conf lpc-e2468 (1433047336) jit 0

This means that print is working :)

After all these additions my main.c looks like this:

#include <stdbool.h>

#include "u.h"
#include "../port/lib.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include "mem.h"
#include "uart.h"
#include "../port/uart.h"
#include "version.h"

PhysUart* physuart[1];

Mach *m = (Mach*)MACHADDR;
Conf conf;
Proc *up = 0;

extern ulong kerndate;
extern int cflag;
extern int main_pool_pcnt;
extern int heap_pool_pcnt;
extern int image_pool_pcnt;
extern int kernel_pool_pcnt;

uint32_t
getcpuid(void) {
  return 0xabcdef;
}

void
confinit(void)
{
    ulong base;

    conf.topofmem = 0xa0000000+16*MB;
    m->cpuhz = 57600000;

    base = PGROUND((ulong)end);
    conf.base0 = base;

    conf.base1 = 0;
    conf.npage1 = 0;

    conf.npage0 = (conf.topofmem - base)/BY2PG;

    conf.npage = conf.npage0 + conf.npage1;
    conf.ialloc = (((conf.npage*(main_pool_pcnt))/100)/2)*BY2PG;

    conf.nproc = 20;
    conf.nmach = 1;
}

static void
poolsizeinit(void)
{
    ulong nb;

    nb = conf.npage*BY2PG;
    poolsize(mainmem, (nb*main_pool_pcnt)/100, 0);
    poolsize(heapmem, (nb*heap_pool_pcnt)/100, 0);
    poolsize(imagmem, (nb*image_pool_pcnt)/100, 1);
}

void
archconsole(void)
{
    uartspecial(0, 115200, 'n', &kbdq, &printq, kbdcr2nl);
}

int main(void) {
  memset(m, 0, sizeof(Mach));   /* clear the mach struct */
  conf.nmach = 1;
  uart0_puts("memset Mach\r\n");
  archreset();
  uart0_puts("archreset\r\n");
  quotefmtinstall();
  confinit();
  xinit();
  poolinit();
  poolsizeinit();
  clockinit();
  printinit();
  procinit();
  links();
  chandevreset();
  archconsole();
  print("%ld MHz id %8.8lux\n", (m->cpuhz)/1000000, getcpuid());
    print("\nInferno %s\n", VERSION);
    print("Vita Nuova\n");
    print("conf %s (%lud) jit %d\n\n",conffile, kerndate, cflag);

  while(true) {

  }
  return 0;
}

void
setpanic(void) {
  uart0_puts("Infernal panic\r\n");
  while (1);
}

uint32_t
__swp(uint32_t x, volatile uint32_t *p) {
  uint32_t ret;
  __asm__ __volatile__ (
    "swp %[ret], %[x], [%[m]]\n"
    : [ret] "=&r" (ret)
    : [m] "r" (p), [x] "r" (x)
    );
  return ret;
}

ulong
_tas(ulong* u) {
  return __swp(0xDEADDEAD, u);
}

int
islo(void) {
  register uint32_t ret;
  uint32_t val = PsrDirq;

  __asm__ __volatile__
  (
    "mrs %[r0], CPSR\n\t"
    "and %[r0], %[val]\n\t"
    "eor %[r0], %[val]\n\t"
    : [r0] "=r"(ret)
    : [val] "r" (val)
  );

  return ret;
}

int
splhi(void) { 
  register uint32_t ret, tmp;

  __asm__ __volatile__
  (
    "mrs %[r0], CPSR" "\n\t"
    "orr %[r1], %[r0], #0x80" "\n\t"
    "msr CPSR_c, %[r1]" "\n\t"
    "mov %[dst], lr\n"
    : [dst] "=&r" (m->splpc), [r0] "=r"(ret), [r1] "=r"(tmp)
  );

  return ret;
}

void
splxpc(int i) {
  register uint32_t ret;

  __asm__ __volatile__
  (
    "mrs %[r0], CPSR" "\n\t"
    "msr CPSR_c, %[r1]" "\n\t"
    : [r0] "=r"(ret)
    : [r1] "r"(i)
  );

  return;
}

void
splx(int i)
{
  __asm__ __volatile__ (
    "mov %[dst], lr\n"
    : [dst] "=&r" (m->splpc)
    );
}

int
spllo(void) {
  register uint32_t ret, tmp;
  uint32_t val = PsrDirq | PsrDfiq;

  __asm__ __volatile__
  (
    "mrs %[r0], CPSR\n\t"
    "bic %[r1], %[r0], %[val]\n\t"
    "msr CPSR_c, %[r1]\n\t"
    : [r0] "=r"(ret), [r1] "=r"(tmp)
    : [val] "r" (val)
  );

  return ret;
}

void
idlehands(void) {
  uart0_puts("bsp::idlehands\r\n");
    idle();
}

int
setlabel(Label* l) {
  __asm__ __volatile__ (
    "mov %[dstsp], sp\n"
    "mov %[dstpc], lr\n"
    : [dstsp] "=&r" (l->sp), [dstpc] "=&r" (l->pc)
    );

  return 0;
}

void
gotolabel(Label* l) {
  __asm__ __volatile__ (
    "mov sp, %[srcsp]\n"
    "mov lr, %[srcpc]\n"
    "bx lr"
    :
    : [srcsp] "r" (l->sp), [srcpc] "r" (l->pc)
    );
}

void
reboot(void) {
  uart0_puts("reboot\r\n");
  return;
  }

void
halt(void) {
  uart0_puts("halt\r\n");
  return;
}

int
segflush(void* v, ulong u) {
  return 1;
}

void
fpinit(void) {
}

void
FPsave(void* v) {
}

void
FPrestore(void* v) {
}

static void
linkproc(void) {
    spllo();
    if (waserror())
        print("error() underflow: %r\n");
    else
        (*up->kpfun)(up->arg);
    pexit("end proc", 1);
}

void
kprocchild(Proc *p, void (*func)(void*), void *arg) {
    p->sched.pc = (ulong)linkproc;
    p->sched.sp = (ulong)p->kstack+KSTACK-8;

    p->kpfun = func;
    p->arg = arg;
}

void
exit(int status) {
}

Substage 12. userinit

Put typical userinit in main.c:

void
userinit(void) {
    Proc *p;
    Osenv *o;

    p = newproc();
    o = p->env;

    o->fgrp = newfgrp(nil);
    o->pgrp = newpgrp();
    o->egrp = newegrp();
    kstrdup(&o->user, eve);

    strcpy(p->text, "interp");
    p->fpstate = FPINIT;

    /*
     * Kernel Stack
     *
     * N.B. The -12 for the stack pointer is important.
     *  4 bytes for gotolabel's return PC
     */
    p->sched.pc = (ulong)init0;
    p->sched.sp = (ulong)p->kstack+KSTACK-8;

    ready(p);
}

Here is init0:

void
init0(void)
{
    Osenv *o;
    char buf[2*KNAMELEN];
    char *buf;
    up->nerrlab = 0;
    spllo();
    if(waserror())
        panic("init0 %r");
    /*
     * These are o.k. because rootinit is null.
     * Then early kproc's will have a root and dot.
     */
    o = up->env;
    o->pgrp->slash = namec("#/", Atodir, 0, 0);
    cnameclose(o->pgrp->slash->name);
    o->pgrp->slash->name = newcname("/");
    o->pgrp->dot = cclone(o->pgrp->slash);

    chandevinit();

    if(!waserror()){
        ksetenv("cputype", "arm", 0);
        snprint(buf, sizeof(buf), "arm %s", conffile);
        ksetenv("terminal", buf, 0);
        poperror();
    }

    poperror();
    disinit("/osinit.dis");
}

Add userinit call to main proc:

...
  print("conf %s (%lud) jit %d\n\n",conffile, kerndate, cflag);
  userinit();
  uart0_puts("userinit\r\n");
...

Rebuild and run:

TFTP from server 10.218.35.27; our IP address is 10.218.35.61
Filename 'iarmtest'.
Load address: 0xa0008000
Loading: ########################
done
Bytes transferred = 351148 (55bac hex)
## Starting application at 0xA0008000 ...
memset Mach
Inferno OS compiled by GCC
archreset
57 MHz id 00abcdef

Inferno Fourth Edition (20150328)
Vita Nuova
conf lpc-e2468 (1433048146) jit 0

userinit

Substage 13. schedinit

Finally. Add schedinit to main proc:

...
  userinit();
  schedinit();
  uart0_puts("userinit\r\n");
...

Rebuild and run:

TFTP from server 10.218.35.27; our IP address is 10.218.35.61
Filename 'iarmtest'.
Load address: 0xa0008000
Loading: ########################
done
Bytes transferred = 351148 (55bac hex)
## Starting application at 0xA0008000 ...
memset Mach
Inferno OS compiled by GCC
archreset
57 MHz id 00abcdef

Inferno Fourth Edition (20150328)
Vita Nuova
conf lpc-e2468 (1433048291) jit 0

Infernal panic

Oops =)

First of all check lpc-e2468.root.s file. It should be empty, which is wrong state for it. Turns out that it is generated by some inferno utility, which fails to generate the code for our asm, as expected. But there is a tool to generate a c-file instead. Why would anyone want .s file then? Lets add file os/lpc-e2468-olimex/mkroot:

$AWK '
BEGIN{
        if (ARGC < 2)
            exit "usage";

        conf = ARGV[1];
        infernoroot = ENVIRON["ROOT"];
        init = ENVIRON["INIT"];
        data2c = ENVIRON["DATA2C"];
        nroot = 0;
}
/^$/{
        next;
}
/^#/{
        next;
}
collect && /^[^ \t]/{
        collect = 0;
}
collect && section ~ "root"{
        dst[nroot] = $1;
        if (NF > 1)
            src[nroot] = infernoroot $2;
        else if (dst[nroot] == "/osinit.dis")
            src[nroot] = infernoroot "/os/init/" init ".dis";
        else
            src[nroot] = infernoroot $1;
        for(i=0; i<nroot; i++)
            if(dst[i] == dst[nroot])
                break;
        if(i == nroot)
            nroot++;
}
$0 ~ /^[^ \t]/{
        if($0 ~ "(code|dev|ether|ip|lib|link|mod|misc|port|root|vga)"){
            section = $0;
            collect = 1;
        }
        next;
}
END{
        rootdata = conf ".root.c";
        system("rm -f " rootdata);
        print("/* Generated by ./mkroot */") >rootdata;
        close(rootdata);
        isdir[0] = 1;
        dotdot[0] = 0;
        qid = 1;
        for (i = 0; i < nroot; i++) {
            ncomp = split(dst[i], comp, "/");
            if (comp[1] != "" || ncomp < 2)
                continue;
            q = 0;
            for (j = 2; j <= ncomp; j++) {
                key = q "/" comp[j];
                if (walk[key] == 0) {
                    walk[key] = qid;
                    dotdot[qid] = q;
                    q = qid++;
                    name[q] = comp[j];
                    if (j < ncomp)
                        isdir[q] = 1;
                }
                else
                    q = walk[key];
            }
            if (system("test -d " src[i]) == 0)
                isdir[q] = 1;
            else {
                if (system(data2c " root" q " <" src[i] " >>" rootdata) != 0)
                    exit 1;
                print("extern unsigned char root" q "code[];");
                print("extern int root" q "len;");
            }
        }

        x = 1;
        sort[0] = 0;
        unsort[0] = 0;
        for (q = 0; q < qid; q++) {
            if (isdir[q]) {
                nchild[q] = 0;
                for (q2 = 1; q2 < qid; q2++) {
                    if (dotdot[q2] == q) {
                        if (nchild[q]++ == 0)
                            child0[q] = x;
                        sort[q2] = x++;
                        unsort[sort[q2]] = q2;
                    }
                }
            }
        }

        print("int rootmaxq = " qid ";");

        print("Dirtab roottab[" qid "] = {");
        for (oq = 0; oq < qid; oq++) {
            q = unsort[oq];
            if (!isdir[q])
                print("\t\"" name[q] "\",\t{" oq ", 0, QTFILE},\t", "0,\t0444,");
            else
                print("\t\"" name[q] "\",\t{" oq ", 0, QTDIR},\t", "0,\t0555,");
        }
        print("};");

        print("Rootdata rootdata[" qid "] = {");
        for (oq = 0; oq < qid; oq++) {
            q = unsort[oq];
            if (!isdir[q])
                print("\t" sort[dotdot[q]] ",\t", "root" q "code,\t", "0,\t", "&root" q "len,");
            else if (nchild[q])
                print("\t" sort[dotdot[q]] ",\t", "&roottab[" child0[q] "],\t", nchild[q] ",\tnil,");
            else
                print("\t" sort[dotdot[q]] ",\t", "nil,\t", "0,\t", "nil,");
        }
        print("};");
}
' $1 >$1.root.h

Add os/lpc-e2468-olimex/portmkfile:

PORTHFILES=\
    ../port/error.h\
    ../port/lib.h\
    ../port/portdat.h\
    ../port/portfns.h\

LIBFILES=${LIBS:%=$ROOT/Inferno/$OBJTYPE/lib/lib%.a}

CLEANEXTRA=

%.$O:   %.s
    $AS $ASFLAGS $stem.s

%.$O:   %.c
    $CC $CFLAGS $stem.c

%.$O:       ../port/%.c
        $CC $CFLAGS -I. ../port/$stem.c

%.$O:       ../ip/%.c
        $CC $CFLAGS -I. ../ip/$stem.c

&.$O:       $HFILES $PORTHFILES

$INSTALLDIR/%: %
    cp $stem $INSTALLDIR/$stem

installall:V:   install-$SHELLTYPE
all:V:      default-$SHELLTYPE

acid:V: i$CONF.acid
i$CONF.acid:V: $SHELLTYPE-i$CONF.acid

LIBHDIRS= -I$ROOT/libmp/port -I$ROOT/libsec/port


rc-i$CONF.acid nt-i$CONF.acid:V: i$CONF
    {
        x=i$CONF; test -e i$CONF.p9 && x=i$CONF.p9
        for (i in `{srclist -ec -r $ROOT/ $x}) {
            echo '//FILE: ' $i
            $CC -I. $CFLAGS $LIBHDIRS '-DKERNDATE='$KERNDATE -a $i
        }
        echo 'include ("inferno");'
    } >i$CONF.acid

sh-i$CONF.acid:V: i$CONF
    x=i$CONF; test -e i$CONF.p9 && x=i$CONF.p9
    for i in `srclist -ec -r $ROOT/ $x`
    do
        echo '//FILE: ' $i
        $CC -I. $CFLAGS $LIBHDIRS '-DKERNDATE='$KERNDATE -a $i
    done >i$CONF.acid
    echo 'include ("inferno");' >> i$CONF.acid

lib%.a:V:   $SHELLTYPE-lib%.a

rc-lib%.a nt-lib%.a:VQ:
        echo '@{builtin cd' $ROOT/lib$stem ';' mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE install'}'
        @{builtin cd $ROOT/lib$stem; mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE install}

sh-lib%.a:VQ:
        echo "(cd $ROOT/lib$stem ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE install)"
        (cd $ROOT/lib$stem; mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE install)

%-rc %-nt:V:
        for(i in $CONFLIST)
            mk 'CONF='$i $stem

%-sh:V:
        for i in $CONFLIST
        do
            mk 'CONF='$i $stem
        done

clean:V:    cleanconf-$SHELLTYPE
        rm -f *.[$OS] *.root.[sh] errstr.h *.out $CLEANEXTRA

cleanconf-sh:V:
        for i in $CONFLIST $CLEANCONFLIST
        do
            rm -f $i.c i$i i$i.* $i.ver
        done

cleanconf-rc cleanconf-nt:V:
        for(i in $CONFLIST $CLEANCONFLIST)
            rm -f $i.c i$i i$i.* $i.ver

nuke-sh:QV:
        for i in $LIBDIRS
        do
            echo "(cd $ROOT/lib$i ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE nuke)"
            (cd $ROOT/lib$i; mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE nuke)
        done

nuke-rc nuke-nt:QV:
        for (i in $LIBDIRS)
        {
            echo '@{cd $ROOT/lib$i ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE nuke}'
            @{cd $ROOT/lib$i; mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE nuke}
        }

nuke:V:     clean nuke-$SHELLTYPE

$CONF.c:    ../port/mkdevc $CONF
        $SHELLNAME ../port/mkdevc $CONF > $CONF.c

errstr.h:   ../port/error.h
        sed 's/extern //;s,;.*/\* , = ",;s, \*/,";,' < ../port/error.h > errstr.h

../init/%.dis:  ../init/%.b
        cd ../init; mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE $stem.dis

$ROOT/libinterp/runt.h:
        cd $ROOT/libinterp
        mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE runt.h

RUNT=$ROOT/libinterp/runt.h     # for culling dependencies
INTERP=$ROOT/include/interp.h

alloc.$O:   $INTERP
devdbg.$O:  $INTERP

devmnt.$O:  $ROOT/include/fcall.h
devns16552.$O:  ../port/netif.h
devns16552.$O:  ns16552.h
devpipe.$O: $INTERP
devprof.$O: $RUNT $INTERP
devprog.$O: $RUNT $INTERP
devroot.$O: errstr.h
devsign.$O: $RUNT $INTERP
devsrv.$O:  $RUNT   $INTERP
dis.$O: $INTERP
discall.$O: $INTERP
exception.$O:   $RUNT   $INTERP
inferno.$O: $RUNT   $INTERP
latin1.$O:  ../port/latin1.h
main.$O:    ../port/error.h
netif.$O:   ../port/netif.h
proc.$O:    errstr.h    $INTERP
screen.$O:  screen.h
trap.$O:    $ROOT/Inferno/$OBJTYPE/include/ureg.h

devroot.$O: $CONF.root.h
$CONF.$O:   $CONF.root.h
$CONF.root.c $CONF.root.h: $CONF ../init/$INIT.dis ./mkroot $ROOTFILES
    AWK=awk DATA2C=data2c INIT=lpcinit ROOT=../.. $SHELLNAME ./mkroot $CONF

%.$O:   $ROOT/Inferno/$OBJTYPE/include/u.h ../port/lib.h mem.h dat.h fns.h io.h ../port/error.h ../port/portdat.h ../port/portfns.h

Now edit os/lpc-e2468-olimex/mkfile:

diff -r 95350fc490f7 os/lpc-e2468-olimex/mkfile
--- a/os/lpc-e2468-olimex/mkfile    Sun May 31 07:59:37 2015 +0300
+++ b/os/lpc-e2468-olimex/mkfile    Sun May 31 08:08:04 2015 +0300
@@ -58,4 +58,4 @@
 devuart.$O:    devuart.c
    $CC $CFLAGS devuart.c

-<../port/portmkfile
+<./portmkfile

Edit lpc-e2468:

diff -r 95350fc490f7 os/lpc-e2468-olimex/lpc-e2468
--- a/os/lpc-e2468-olimex/lpc-e2468 Sun May 31 07:59:37 2015 +0300
+++ b/os/lpc-e2468-olimex/lpc-e2468 Sun May 31 08:12:40 2015 +0300
@@ -1,4 +1,5 @@
 dev
+  root
    cons
   env
   mnt
@@ -48,4 +49,13 @@
    bootinit

 root
-  /dev /
\ No newline at end of file
+   /chan   /
+   /dev    /
+   /dis    /
+   /env    /
+   /fd     /
+   /net    /
+   /prog   /
+   /dis/lib
+   /dis/disk
+   /osinit.dis

Remove the old lpc-e2468.root.s and rebuild.

inferno-os-lpc2468/os/lpc-e2468-olimex$ mk
AWK=awk DATA2C=data2c INIT=lpcinit ROOT=../.. /bin/sh ./mkroot lpc-e2468
sh: 1: cannot open ../../os/init/lpcinit.dis: No such file
mk: AWK=awk DATA2C=data2c INIT=lpcinit ...  : exit status=exit(1)

Ok, lets write simple os/init/lpcinit.b:

implement Init;

include "sys.m";
    sys:    Sys;

Bootpreadlen: con 128;

Init: module
{
    init:   fn();
};

init()
{
    sys = load Sys Sys->PATH;
    sys->print("Hey, this is Hello World from Dis!\n\n");
}

Rebuild. If you have something like this as a result:

AWK=awk DATA2C=data2c INIT=lpcinit ROOT=../.. /bin/sh ./mkroot lpc-e2468
sh: 1: cannot open ../../os/init/lpcinit.dis: No such file
mk: AWK=awk DATA2C=data2c INIT=lpcinit ...  : exit status=exit(1)

then go to os/init and run limbo lpcinit.b there. Check that lpcinit.dis now exists and go back to os/lpc-e2468-olimex.

Run mk and check lpc-e2468.root.c:

/* Generated by ./mkroot */
unsigned char root10code[] = {
0xc0,0xc,0x80,0x30,0x80,0x40,0x81,0x90,0x6,0x10,0x3,0x1,0,0x1,0x8,0x40,
0,0,0xc,0x5,0x11,0x2,0x24,0x29,0x5,0x4,0x24,0x20,0x27,0xd,0x20,0x24,
0x10,0x9,0x48,0,0x24,0xc,0xc,0x1b,0,0x10,0x1,0xf0,0x1,0x28,0,0x2,
0x28,0x2,0,0x80,0x34,0,0x24,0x53,0x79,0x73,0x30,0x24,0x4,0x48,0x65,0x79,
0x2c,0x20,0x74,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x48,0x65,0x6c,0x6c,0x6f,0x20,
0x57,0x6f,0x72,0x6c,0x64,0x20,0x66,0x72,0x6f,0x6d,0x20,0x44,0x69,0x73,0x21,0xa,
0xa,0,0x49,0x6e,0x69,0x74,0,0,0x1,0x9c,0xd7,0x1c,0x5e,0x69,0x6e,0x69,
0x74,0,0x1,0x1,0xac,0x84,0x90,0x33,0x70,0x72,0x69,0x6e,0x74,0,0,0x2f,
0x6f,0x73,0x2f,0x69,0x6e,0x69,0x74,0x2f,0x6c,0x70,0x63,0x69,0x6e,0x69,0x74,0x2e,
0x62,0,
};
int root10len = 146;

This looks fine. Lets run it on hardware.

TFTP from server 10.218.35.27; our IP address is 10.218.35.61
Filename 'iarmtest'.
Load address: 0xa0008000
Loading: T T T ########################
done
Bytes transferred = 352076 (55f4c hex)
## Starting application at 0xA0008000 ...
memset Mach
Inferno OS compiled by GCC
archreset
57 MHz id 00abcdef

Inferno Fourth Edition (20150328)
Vita Nuova
conf lpc-e2468 (1433049494) jit 0

Infernal panic

Still panic.

This is weird. Really. It took a long time to understand what is going on inside. Somehow gcc build has lock/unlock problems. To fix this we will have to make some changes in inferno's internals.

We have to add incref call in os/port/chan.c and in os/port/sysfile.c:

diff -r 95350fc490f7 os/port/chan.c
--- a/os/port/chan.c    Sun May 31 07:59:37 2015 +0300
+++ b/os/port/chan.c    Sun May 31 08:27:28 2015 +0300
@@ -1055,6 +1055,7 @@
        if(t == -1)
            error(Ebadsharp);
        c = devtab[t]->attach(up->genbuf+n);
+       incref(c);
        break;

    default:
diff -r 95350fc490f7 os/port/sysfile.c
--- a/os/port/sysfile.c Sun May 31 07:59:37 2015 +0300
+++ b/os/port/sysfile.c Sun May 31 08:27:28 2015 +0300
@@ -48,6 +48,7 @@
    if(i > f->maxfd)
        f->maxfd = i;
    f->fd[i] = c;
+   incref(c);
    unlock(f);
    return i;
 }

This still fails with infernal panic =\

Ok, lets add pipe to dev section and rebuild:

inferno-os-lpc2468/os/lpc-e2468-olimex$ mk
AWK=awk DATA2C=data2c INIT=lpcinit ROOT=../.. /bin/sh ./mkroot lpc-e2468
    arm-none-eabi-gcc -O0 -std=c1x -fno-builtin -fplan9-extensions -fms-extensions -DUSED(...)=void -DSET(...) -c -mcpu=arm7tdmi-s -I/home/snegovick/dev/inferno/inferno-os-lpc2468/Inferno/arm-gcc/include -I/home/snegovick/dev/inferno/inferno-os-lpc2468/include -I/home/snegovick/dev/inferno/inferno-os-lpc2468/libinterp -I./ -DLINUX_ARM -I. ../port/devpipe.c
../port/devpipe.c: In function 'pipegen':
../port/devpipe.c:111:1: error: parameter name omitted
 pipegen(Chan *c, char *, Dirtab *tab, int ntab, int i, Dir *dp)
 ^
../port/devpipe.c: In function 'piperead':
../port/devpipe.c:297:1: error: parameter name omitted
 piperead(Chan *c, void *va, long n, vlong)
 ^
../port/devpipe.c: In function 'pipewrite':
../port/devpipe.c:338:1: error: parameter name omitted
 pipewrite(Chan *c, void *va, long n, vlong)
 ^
../port/devpipe.c: In function 'pipebwrite':
../port/devpipe.c:379:2: warning: useless type name in empty declaration [enabled by default]
  USED(junk);
  ^
mk:  arm-none-eabi-gcc -O0 ...  : exit status=exit(1)

Eh I've almost forgot about this. Fix:

diff -r 95350fc490f7 os/port/devpipe.c
--- a/os/port/devpipe.c Sun May 31 07:59:37 2015 +0300
+++ b/os/port/devpipe.c Sun May 31 08:34:39 2015 +0300
@@ -108,7 +108,7 @@
 }

 static int
-pipegen(Chan *c, char *, Dirtab *tab, int ntab, int i, Dir *dp)
+pipegen(Chan *c, char *ch, Dirtab *tab, int ntab, int i, Dir *dp)
 {
    int id, len;
    Qid qid;
@@ -294,7 +294,7 @@
 }

 static long
-piperead(Chan *c, void *va, long n, vlong)
+piperead(Chan *c, void *va, long n, vlong v)
 {
    Pipe *p;

@@ -335,7 +335,7 @@
  *  the prog.
  */
 static long
-pipewrite(Chan *c, void *va, long n, vlong)
+pipewrite(Chan *c, void *va, long n, vlong v)
 {
    Pipe *p;
    Prog *r;

Add dup to dev section and rebuild:

port/devdup.c
../port/devdup.c: In function 'dupgen':
../port/devdup.c:11:1: error: parameter name omitted
 dupgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp)
 ^
../port/devdup.c:11:1: error: parameter name omitted
../port/devdup.c:11:1: error: parameter name omitted
../port/devdup.c: In function 'dupclose':
../port/devdup.c:95:1: error: parameter name omitted
 dupclose(Chan*)
 ^
../port/devdup.c: In function 'dupwrite':
../port/devdup.c:126:1: error: parameter name omitted
 dupwrite(Chan*, void*, long, vlong)
 ^
../port/devdup.c:126:1: error: parameter name omitted
../port/devdup.c:126:1: error: parameter name omitted
../port/devdup.c:126:1: error: parameter name omitted
mk:  arm-none-eabi-gcc -O0 ...  : exit status=exit(1)

Fix:

diff -r 95350fc490f7 os/port/devdup.c
--- a/os/port/devdup.c  Sun May 31 07:59:37 2015 +0300
+++ b/os/port/devdup.c  Sun May 31 08:37:20 2015 +0300
@@ -8,7 +8,7 @@
 /* Qid is (2*fd + (file is ctl))+1 */

 static int
-dupgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp)
+dupgen(Chan *c, char *ch, Dirtab *dt, int i, int s, Dir *dp)
 {
    Fgrp *fgrp = up->env->fgrp;
    Chan *f;
@@ -92,7 +92,7 @@
 }

 static void
-dupclose(Chan*)
+dupclose(Chan* c)
 {
 }

@@ -123,7 +123,7 @@
 }

 static long
-dupwrite(Chan*, void*, long, vlong)
+dupwrite(Chan* c, void* v, long l, vlong vl)
 {
    panic("dupwrite");
    return 0;       /* not reached */

No success, still panic.

Add discall to port section

Add mod section to lpc-e2468:

mod
    math
    sys

Rebuild:

   arm-none-eabi-objcopy -O binary ilpc-e2468.elf ilpc-e2468.bin
   arm-none-eabi-size ./ilpc-e2468.elf
/home/snegovick/dev/inferno/inferno-os-lpc2468/Inferno/arm-gcc/lib/libinterp.a(math.o): In function `Math_isnan':
math.c:(.text+0x698): undefined reference to `isNaN'
/home/snegovick/dev/inferno/inferno-os-lpc2468/Inferno/arm-gcc/lib/libkern.a(pow.o): In function `pow':
pow.c:(.text+0x190): undefined reference to `NaN'
/home/snegovick/dev/inferno/inferno-os-lpc2468/Inferno/arm-gcc/lib/libkern.a(sqrt.o): In function `sqrt':
sqrt.c:(.text+0x48): undefined reference to `NaN'
sqrt.c:(.text+0x5c): undefined reference to `isInf'
/home/snegovick/dev/inferno/inferno-os-lpc2468/Inferno/arm-gcc/lib/libkern.a(exp.o): In function `exp':
exp.c:(.text+0x64): undefined reference to `Inf'
/home/snegovick/dev/inferno/inferno-os-lpc2468/Inferno/arm-gcc/lib/libkern.a(log.o): In function `log':
log.c:(.text+0x24): undefined reference to `NaN'
/home/snegovick/dev/inferno/inferno-os-lpc2468/Inferno/arm-gcc/lib/libkern.a(log.o): In function `log10':
log.c:(.text+0x2a8): undefined reference to `NaN'
collect2: error: ld returned 1 exit status
mk:    ...  : exit status=exit(1)

copy libkern/mkfile-arm to libkern/mkfile-arm-gcc and edit its contents:

#
#   arm-specific files
#
TARGFILES=\
    frexp-arm.$O\
    nan-arm.$O\
    vlrt-arm.$O\

Rebuild, still failing.

Turned out that in my case the lpc-e2468.c was not generated properly. I solved this by replacing all double spaces with tabs in lpc-e2468 conf file.

Rebuilding and running gives this output:

TFTP from server 10.218.35.27; our IP address is 10.218.35.61
Filename 'iarmtest'.
Load address: 0xa0008000
Loading: ##############################
done
Bytes transferred = 437376 (6ac80 hex)
## Starting application at 0xA0008000 ...
memset Mach
Inferno OS compiled by GCC
archreset
57 MHz id 00abcdef

Inferno Fourth Edition (20150328)
Vita Nuova
conf lpc-e2468 (1433084364) jit 0

userinit
Initial Dis: "/osinit.dis"
Hey, this is Hello World from Dis!

bsp::idlehands