现在,我们知道如何编译c++内核和使用GRUB引导二进制程序了, 我们可以开始用C/C++做一些很酷的东西了.
我们将使用VGA默认模式(03h)向用户显示一些文本. 利用0xB8000视频内存, 屏幕可以被直接访问. 屏幕分辨率是80x25, 在屏幕上的每个字符被定义为2字节: 一个字符代码, 和一个格式标志. 这意味着视频内存的总大小是4000B(80B25B2B).
在IO类(io.cc),:
我们在IO Class中添加一个方法putc来在屏幕上放置一个字符, 并更新(x, y)位置.
/* 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);
}
我们也添加了一个有用且有名的方法: 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;
}
大量的指令在汇编层可用, 但在C(像cli, sti, in, out)中没有等效的方法. 所以我们需要这一个这些指令的接口.
在C中, 我们用指令"asm()"来内联汇编, gcc用gas编译汇编.
注意: gas使用AT&T语法.
/* 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;
}