Base classes for managing x86 architecture

Now that we know how to compile our C++ kernel and boot the binary using GRUB, we can start to do some cool things in C/C++.

Printing to the screen console

We are going to use VGA default mode (03h) to display some text to the user. The screen can be directly accessed using the video memory at 0xB8000. The screen resolution is 80x25 and each character on the screen is defined by 2 bytes: one for the character code, and one for the style flag. This means that the total size of the video memory is 4000B (80B25B2B).

In the IO class (io.cc),:

  • x,y: define the cursor position on the screen

  • real_screen: define the video memory pointer

  • putc(char c): print a unique character on the screen and manage cursor position

  • printf(char* s, ...): print a string

We add a method putc to the IO Class to put a character on the screen and update the (x,y) position.

/* put a byte on screen */
void Io::putc(char c){
    kattr = 0x07;
    unsigned char *video;
    video = (unsigned char *) (real_screen+ 2 * x + 160 * y);
    // newline
    if (c == '\n') {
        x = 0;
        y++;
    // back space
    } else if (c == '\b') {
        if (x) {
            *(video + 1) = 0x0;
            x--;
        }
    // horizontal tab
    } else if (c == '\t') {
        x = x + 8 - (x % 8);
    // carriage return
    } else if (c == '\r') {
        x = 0;
    } else {
        *video = c;
        *(video + 1) = kattr;

        x++;
        if (x > 79) {
            x = 0;
            y++;
        }
    }
    if (y > 24)
        scrollup(y - 24);
}

We also add a useful and very known method: printf

/* put a string in screen */
void Io::print(const char *s, ...){
    va_list ap;

    char buf[16];
    int i, j, size, buflen, neg;

    unsigned char c;
    int ival;
    unsigned int uival;

    va_start(ap, s);

    while ((c = *s++)) {
        size = 0;
        neg = 0;

        if (c == 0)
            break;
        else if (c == '%') {
            c = *s++;
            if (c >= '0' && c <= '9') {
                size = c - '0';
                c = *s++;
            }

            if (c == 'd') {
                ival = va_arg(ap, int);
                if (ival < 0) {
                    uival = 0 - ival;
                    neg++;
                } else
                    uival = ival;
                itoa(buf, uival, 10);

                buflen = strlen(buf);
                if (buflen < size)
                    for (i = size, j = buflen; i >= 0;
                         i--, j--)
                        buf[i] =
                            (j >=
                             0) ? buf[j] : '0';

                if (neg)
                    print("-%s", buf);
                else
                    print(buf);
            }
             else if (c == 'u') {
                uival = va_arg(ap, int);
                itoa(buf, uival, 10);

                buflen = strlen(buf);
                if (buflen < size)
                    for (i = size, j = buflen; i >= 0;
                         i--, j--)
                        buf[i] =
                            (j >=
                             0) ? buf[j] : '0';

                print(buf);
            } else if (c == 'x' || c == 'X') {
                uival = va_arg(ap, int);
                itoa(buf, uival, 16);

                buflen = strlen(buf);
                if (buflen < size)
                    for (i = size, j = buflen; i >= 0;
                         i--, j--)
                        buf[i] =
                            (j >=
                             0) ? buf[j] : '0';

                print("0x%s", buf);
            } else if (c == 'p') {
                uival = va_arg(ap, int);
                itoa(buf, uival, 16);
                size = 8;

                buflen = strlen(buf);
                if (buflen < size)
                    for (i = size, j = buflen; i >= 0;
                         i--, j--)
                        buf[i] =
                            (j >=
                             0) ? buf[j] : '0';

                print("0x%s", buf);
            } else if (c == 's') {
                print((char *) va_arg(ap, int));
            }
        } else
            putc(c);
    }

    return;
}

Assembly interface

A large number of instructions are available in Assembly but there is not equivalent in C (like cli, sti, in and out), so we need an interface to these instructions.

In C, we can include Assembly using the directive "asm()", gcc use gas to compile the assembly.

Caution: gas uses the AT&T syntax.

/* output byte */
void Io::outb(u32 ad, u8 v){
    asmv("outb %%al, %%dx" :: "d" (ad), "a" (v));;
}
/* output word */
void Io::outw(u32 ad, u16 v){
    asmv("outw %%ax, %%dx" :: "d" (ad), "a" (v));
}
/* output word */
void Io::outl(u32 ad, u32 v){
    asmv("outl %%eax, %%dx" : : "d" (ad), "a" (v));
}
/* input byte */
u8 Io::inb(u32 ad){
    u8 _v;       \
    asmv("inb %%dx, %%al" : "=a" (_v) : "d" (ad)); \
    return _v;
}
/* input word */
u16    Io::inw(u32 ad){
    u16 _v;            \
    asmv("inw %%dx, %%ax" : "=a" (_v) : "d" (ad));    \
    return _v;
}
/* input word */
u32    Io::inl(u32 ad){
    u32 _v;            \
    asmv("inl %%dx, %%eax" : "=a" (_v) : "d" (ad));    \
    return _v;
}

Last updated