XV6の入出力

inb, outb

◆入出力の方法

  1. CPU が持つ入出力命令を使うもの。 どのデバイスをアクセスするかは、ポート番号で指定する。
  2. 通常のメモリアクセスの命令を使うもの(memory mapped I/O)。 どのデバイスをアクセスするかは、番地で指定する。

x86ではポートマップドのIN, OUT命令セットが存在する。

Linux における入出力命令を使った入出力は、inb() と outb() で行われる。

outb(unsigned char value, int port)
  ポート番号 port に 1 バイトの value を出力する

unsigned char inb(int port)
  ポート番号 port から 1 バイトの value を入力してその値を返す

x86では、IDEやUARTはinbやoutb命令で操作できるが(つまりポートマップドI/O)、MIPSRISC-Vではそうはいかない。メモリマップに、これらのモジュールを定義しておかなければならない。 http://msyksphinz.hatenablog.com/?page=1461085200

xv6

オリジナル (port-mapped I/O)

/uart.c

void
uartputc(int c)
{
  int i;

  if(!uart)
    return;
  for(i = 0; i < 128 && !(inb(COM1+5) & 0x20); i++)
    microdelay(10);
  outb(COM1+0, c);
}

/mips.h

static inline void
outb(ushort port, uchar data)
{
  asm volatile("out %0,%1" : : "a" (data), "d" (port));
}

xv6/uart.c at ff2783442ea2801a4bf6c76f198f36a6e985e7dd · guilleiguaran/xv6 · GitHub

nyuichi/xv6 (memory-mapped I/O)

/uart.c

uartputc(int c)
{
  int i;
  if(!uart)
    return;
  while(*(int*)SERIALWE == 0) microdelay();
  *(int*)SERIAL = c;
}

/memorylayout.c

#define SERIAL     0x80001000

https://github.com/nyuichi/xv6/blob/94d02ecb2b9492365574f2166cf29ce5a170abf5/uart.c#L34

nullpo-head/xv6-mips (memory-mapped I/O)

/uart.c

#define COM1    0x3f8
.....
.....
void
uartputc(int c)
{
  int i;

  if(!uart)
    return;
  for(i = 0; i < 128 && !(inb(COM1+5) & 0x20); i++)
    microdelay(10);
  outb(COM1+0, c);
}

/mips.h

static int io_port_base = 0xb4000000;
.....
.....
static inline void
outb(ushort port, uchar data)
{
  *((uchar *) (io_port_base + port)) = data;
}

GitHub - nullpo-head/xv6-mips: A MIPS port of xv6

呼び出し

console.printf() --> console.consputc(c) --> uart.uartputc(c)
                                         --> uart.cgaputc(c)

uart.cgaputc(c) は、オリジナル以外ではコメントアウトMIPS) or 削除(GAIA)されている