天衣有缝

冠盖满京华,斯人独憔悴~
posts - 35, comments - 115, trackbacks - 0, articles - 0
   :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

jinix内核虚拟控制台实现(原创)

Posted on 2007-07-10 20:15 天衣有缝 阅读(1942) 评论(2)  编辑 收藏 引用 所属分类: os stuff

jinix是小弟正在实现的一个c++ kernel,因为调试缘故,所以早早的把控制台部分调出来了,以便于后来的调试。代码使用c++写的,如果使用c写内核也很容易移植过去。转载请保留原 创:http://www.cppblog.com/jinglexymail & msn: jinglexy at yahoo dot com dot cn。这部分代码是在内存管理之前实现的,所以没有做到任意个数虚拟控制台(内核在编译时候确定个数),并且每个控制台显存地址固定起来了。如果要实现也 比较简单:启动时候初始化一个控制台,在MM初始化完后初始化其他控制台,每个控制台包含自己的显存缓冲区,切换控制台的时候将该缓冲区拷贝到显存中即 可。

文件:textio.h, textio.cpp, ostream.h, ostream.cpp
textio.h
源文件如下:

     1: #ifndef __JINIX_TEXTIO_H 
2: #define __JINIX_TEXTIO_H
3: #include <jinix/types.h>
4:
5: /* 在字符模式下,适配器使用0xB8000-0xBF000作为视频内存。
6: * 通常我们处于80x25大小屏幕,有16种颜色。
7: * 由于一个屏幕只需要80x25x2个字节,即4k,所以该视频内存可以分为多个页。
8: * 我们使用所有的页,但是当前只能有一个页面可见。
9: * 为了显示一个字符,将用到2个字节,一个字节是字符值(地址为N),
10: * 另一个字节是字符属性(即颜色,地址为N + 1)。属性字节定义如下:
11: *
12: * Bit 7 闪烁
13: * Bits 6-4 背景色
14: * Bit 3 明亮模式(0为暗,1为亮)
15: * Bit3 2-0 前景色:分别是黑,兰,绿,青,洋红,深粉,深黄,灰色
16: *
17: * 操作端口基址:0x3d4h, 0x3d5h
18: * 参考资料:osd文档中的osd/cons/index.htm
19: * CGA显示模式,显存从0xB8000开始一共32kb字节,在jinix中每个虚拟控制台只使用4k字节(80x25x2),
20: * 且不考虑滚屏操作(为了简单处理),所以最多可以有8个控制台
21: */

22: typedef enum {
23: BLACK, BLUE, GREEN, CYAN,
24: RED, MAGENTA, BROWN, GRAY,
25: DARKGRAY, LIGHTBLUE, LIGHTGREEN, LIGHTCYAN,
26: LIGHTRED, LIGHTMAGENTA, YELLOW, WHITE
27: } TextColor;
28:
29: const int CGA_VIDEO_PTR = 0xB8000;
30: const int CGA_CONSOLE_SIZE = 4000;
31: const char BLANK_CHAR = ' ';
32:
33: class TextIO
34: {
35: public:
36: TextIO() ;
37: ~TextIO() ;
38: void init_page(int page); /* must call first!!! */
39: void move_cursor(void);
40: void move_page(void);
41: void setxy(int newx, int newy);
42:
43: int getx() { return x; }
44: int gety() { return y; }
45:
46: void scrollup();
47: void clear();
48:
49: void set_fg(TextColor fg);
50: void set_bg(TextColor bg);
51:
52: void putstr(char *s);
53: /* inline */void putchar(char c);
54:
55: private:
56: int x, y;
57: char colors;
58: char *pvideo_start; /* 虚拟控制台显存首地址 */
59: /* struct termios termios; posix compatible later... */
60: };
61:
62: #endif
63:
64:


这个文件完成显存的一些字符操作,及显存页面切换,滚屏也很简单。没有加入posix兼容的一些特性,
还没有想好是否加在这里。rs232也会使用终端特性,所以考虑后期将字符设备驱动抽象成一个基类,
作为textio类的父类。有什么好的想法可以和我讨论:http://www.cppblog.com/jinglexy

ostream.h
源文件:

1: #ifndef __JINIX_OSTREAM_H
2: #define __JINIX_OSTREAM_H
3: #include <jinix/textio.h>
4:
5: /* format flags */
6: #define boolalpha 0x0001 /* 未实现 */
7: #define showbase 0x0002
8: #define showpoint 0x0004 /* 未实现 */
9: #define showpos 0x0008 /* 未实现 */
10: #define skipws 0x0010 /* 未实现 */
11: #define unitbuf 0x0020 /* 未实现 */
12: #define uppercase 0x0040 /* 未实现 */
13: #define dec 0x0080
14: #define hex 0x0100
15: #define oct 0x0200
16: #define bin 0x0400
17: #define internal 0x0800 /* 未实现 */
18: #define left 0x1000 /* 未实现 */
19: #define right 0x2000 /* 未实现 */
20:
21: class OStream : public TextIO
22: {
23: public:
24: OStream();
25: OStream& operator <<(char *str);
26: OStream& operator <<(char c);
27: OStream& operator <<(unsigned char *str);
28: OStream& operator <<(unsigned char c);
29: OStream& operator <<(int i);
30: OStream& operator <<(unsigned int i);
31: OStream& operator <<(long i);
32: OStream& operator <<(unsigned long i);
33: OStream& operator <<(long long i);
34: OStream& operator <<(unsigned long long i);
35: void flags(int f);
36:
37: private:
38: int current_flags; /* 显示模式: 进制数, 对齐形式等 */
39: };
40:
41: #define cout __vconsole[__cur_console]
42: void switch_console(int console);
43:
44: /* 单元测试 */
45: void ostream_dotest(void);
46:
47: /* 不要使用下面两个全局变量 */
48: extern class OStream __vconsole[];
49: extern int __cur_console;
50: #endif
51:
52:

不熟悉设计模式,所以结构比较混乱,好的模式应该可以规避这些不雅的代码吧,呵呵

textio.cpp
源文件:

1: #include <asm/portio.h>
2: #include <asm/system.h>
3: #include <jinix/tty.h>
4: #include <jinix/textio.h>
5:
6: TextIO::TextIO()
7: {
8: x = 0;
9: y = 0;
10: colors = TTY_CHAR_ATTRIBUTE;
11: pvideo_start = (char*)NULL;
12: }
13:
14: TextIO::~TextIO()
15: {
16: }
17:
18: void TextIO::init_page(int page)
19: {
20: if (page < 0 || page > VIRTUAL_CONSOLE_COUNT - 1)
21: return;
22:
23: /* after init, console[0].pvideo_start is 0xb8000;
24: * console[1].pvideo_start is 0xb8fa0
25: * console[2].pvideo_start is 0xb9f40
26: * console[3].pvideo_start is 0xbaee0
27: */

28: pvideo_start = (char*)CGA_VIDEO_PTR + page * CGA_CONSOLE_SIZE;
29: /* debug(if not, gdb fly out): */ page++;
30: }
31:
32: void TextIO::move_cursor(void)
33: {
34: int temp;
35: temp = y * TTY_COLUMNS_NR + x;
36:
37: /* disable interrupt */
38: __cli();
39: PortIO::outportb(0x3D4, 14);
40: PortIO::outportb(0x3D5, temp >> 8);
41: PortIO::outportb(0x3D4, 15);
42: PortIO::outportb(0x3D5, temp);
43: /* enable interrupt */
44: __sti();
45: }
46:
47: void TextIO::move_page(void)
48: {
49: int temp;
50: temp = (int)(pvideo_start - CGA_VIDEO_PTR) / 2;
51:
52: /* disable interrupt */
53: __cli();
54: PortIO::outportb(0x3D4, 12);
55: PortIO::outportb(0x3D5, temp >> 8);
56: PortIO::outportb(0x3D4, 13);
57: PortIO::outportb(0x3D5, temp);
58: /* enable interrupt */
59: __sti();
60: }
61:
62: void TextIO::setxy(int newx, int newy)
63: {
64: if (newx >= 0 && newx < TTY_COLUMNS_NR)
65: x = newx;
66:
67: if (newy >= 0 && newy < TTY_LINES_NR)
68: y = newy;
69: }
70:
71: /* it will scroll only one line */
72: void TextIO::scrollup()
73: {
74: char *src, *dst;
75: int i, j;
76:
77: dst = pvideo_start;
78: src = pvideo_start + TTY_COLUMNS_NR * 2;
79:
80: for (i = 0; i < TTY_LINES_NR - 1; i++)
81: for (j = 0; j < TTY_COLUMNS_NR * 2; j++) /* every char 2 bytes */
82: *dst++ = *src++;
83:
84: /* new line */
85: for (i = 0; i < TTY_COLUMNS_NR; i++) {
86: *dst++ = BLANK_CHAR;
87: *dst++ = colors;
88: }
89: }
90:
91: void TextIO::clear(void)
92: {
93: int i;
94: char *src;
95:
96: src = pvideo_start;
97: for (i = 0; i < TTY_COLUMNS_NR * TTY_LINES_NR; i++) {
98: *src++ = BLANK_CHAR;
99: *src++ = colors;
100: }
101:
102: setxy(0, 0);
103: move_cursor();
104: }
105:
106: void TextIO::set_fg(TextColor fg)
107: {
108: colors = (colors & 0xf0) | (fg & 0x0f);
109: }
110:
111: void TextIO::set_bg(TextColor bg)
112: {
113: colors = (colors & 0x0f) | ((bg << 4) & 0xf0);
114: }
115:
116: void TextIO::putstr(char *s)
117: {
118: while (*s)
119: putchar(*s++);
120: }
121:
122: /* extern inline */void TextIO::putchar(char c)
123: {
124: int t;
125:
126: switch(c) {
127: case '\r':
128: {
129: int i;
130: x = 0;
131:
132: /* 清除一行 */
133: t = ((x + y * TTY_COLUMNS_NR) << 1);
134: for(i = 0 ; i < TTY_COLUMNS_NR; i++) {
135: *(pvideo_start + t + (i << 1)) = BLANK_CHAR;
136: *(pvideo_start + t + (i << 1) + 1) = colors;
137: }
138: break;
139: }
140:
141: case '\n':
142: {
143: x = 0;
144: y++;
145: break;
146: }
147:
148: case '\t':
149: {
150: if (x + TTY_TABWIDTH >= TTY_COLUMNS_NR) {
151: x = (x + TTY_TABWIDTH - TTY_COLUMNS_NR);
152: y++;
153: } else {
154: x += TTY_TABWIDTH;
155: }
156:
157: break;
158: }
159:
160: case '\b':
161: {
162: t = x + y * TTY_COLUMNS_NR;
163:
164: if (t <= 0)
165: break;
166: t--;
167:
168: if (x > 0) {
169: x--;
170: } else {
171: y--;
172: x = TTY_COLUMNS_NR - 1;
173: }
174:
175: *(pvideo_start + (t << 1)) = BLANK_CHAR;
176: *(pvideo_start + (t << 1) + 1) = colors;
177: break;
178: }
179:
180: default:
181: {
182: if(c < ' ') break; /* only print visible char */
183: t = x + y * TTY_COLUMNS_NR;
184:
185: *(pvideo_start + (t << 1)) = c;
186: *(pvideo_start + (t << 1) + 1) = colors;
187: x++;
188:
189: if(x == 80) {
190: x = 0;
191: y++;
192: }
193: break;
194: }
195: }
196:
197: if (TTY_LINES_NR == y) {
198: scrollup();
199: y--;
200: }
201: move_cursor();
202: }
203:
204:

需要注意的是多个端口同时操作需要关闭中断,否则一旦在多任务中被调度出去,后果很严重,呵呵

1: #include <jinix/tty.h>
2: #include <jinix/ostream.h>
3: #include <asm/string.h>
4:
5: class OStream __vconsole[VIRTUAL_CONSOLE_COUNT];
6: int __cur_console; /* 当前控制台 */
7:
8: OStream::OStream()
9: {
10: current_flags = dec;
11: }
12:
13: OStream& OStream::operator <<(char *str)
14: {
15: putstr(str);
16: return *this;
17: }
18:
19: OStream& OStream::operator <<(char c)
20: {
21: putchar(c);
22: return *this;
23: }
24:
25: OStream& OStream::operator <<(unsigned char *str)
26: {
27: putstr((char *)str);
28: return *this;
29: }
30:
31: OStream& OStream::operator <<(unsigned char c)
32: {
33: putchar((char)c);
34: return *this;
35: }
36:
37: OStream& OStream::operator <<(int i)
38: {
39: char buf[33]; /* 2进制支持 */
40:
41: if (current_flags & dec)
42: itoa(buf, 10, i);
43: else if (current_flags & hex)
44: itoa(buf, 16, i);
45: else if (current_flags & oct)
46: itoa(buf, 8, i);
47: else if (current_flags & bin)
48: itoa(buf, 2, i);
49:
50: if (current_flags & hex && current_flags & showbase)
51: putstr("0x");
52:
53: putstr(buf);
54: return *this;
55: }
56:
57: OStream& OStream::operator <<(unsigned int i)
58: {
59: *this << (int)i;
60: return *this;
61: }
62:
63: OStream& OStream::operator <<(long i)
64: {
65: *this << (int)i;
66: return *this;
67: }
68:
69: OStream& OStream::operator <<(unsigned long i)
70: {
71: *this << (int)i;
72: return *this;
73: }
74:
75: OStream& OStream::operator <<(long long i)
76: {
77: char buf[65]; /* 2进制支持 */
78:
79: if (current_flags & dec)
80: itoa(buf, 10, i);
81: else if (current_flags & hex)
82: itoa(buf, 16, i);
83: else if (current_flags & oct)
84: itoa(buf, 8, i);
85: else if (current_flags & bin)
86: itoa(buf, 2, i);
87:
88: if (current_flags & hex && current_flags & showbase)
89: putstr("0x");
90:
91: putstr(buf);
92: return *this;
93: }
94:
95: OStream& OStream::operator <<(unsigned long long i)
96: {
97: *this << (long long)i;
98: return *this;
99: }
100:
101: void OStream::flags(int f)
102: {
103: current_flags = f;
104: }
105:
106: void switch_console(int console)
107: {
108: if (console < 0 || console > VIRTUAL_CONSOLE_COUNT - 1)
109: return;
110:
111: /* set current console */
112: __cur_console = console;
113:
114: /* move page */
115: cout.move_page();
116:
117: /* move cursor */
118: cout.move_cursor();
119: }
120:
121: /* only call when init */
122: void __kernel_init_switch_console(int console)
123: {
124: if (console < 0 || console > VIRTUAL_CONSOLE_COUNT - 1)
125: return;
126:
127: /* set current console */
128: __cur_console = console;
129: }
130:
131: void ostream_dotest(void)
132: {
133: int i;
134:
135: i = 0;
136: {
137: /* 虚拟控制台切换测试 */
138: for(i = 0; i < VIRTUAL_CONSOLE_COUNT; i++) {
139: switch_console(i);
140: cout.putstr("0123456789abcdefghijklmnoprfdsafdieqxzcvaeax");
141: }
142:
143: for(i = 0; i < VIRTUAL_CONSOLE_COUNT; i++) {
144: switch_console(i);
145: cout.putstr("0123456789abcdefghijklmnoprfdsafdieqxzcvaeax");
146: }
147:
148: switch_console(0);
149: cout.putstr("00000000000000000000000");
150: switch_console(1);
151: cout.putstr("11111111111111111111111");
152: switch_console(2);
153: cout.putstr("22222222222222222222222");
154: switch_console(3);
155: cout.putstr("33333333333333333333333");
156: }
157:
158: {
159: /* 复杂字符串输出测试 */
160: switch_console(0);
161: for(i = 0; i < 20; i++) {
162: cout.putstr("++++++++++++++++++++");
163: cout.putstr("++++++++++++++++++++");
164: cout.putstr("++++++++++++++++++++");
165: cout.putstr("++++++++++++++++++++");
166: }
167:
168: cout.putstr("\r");
169: cout.putstr("00000000000000000000000\n");
170: cout.putstr("0\t0\t0\t0\t0\t0\t0\t0\t0\t0\ta\n");
171: cout.putstr("+_+_+_+_+_+_+_+_+_+_+_");
172: cout.putstr("\b\b\b\b\b*&*&*&*&*&*&*&*&");
173: i++;
174: }
175:
176: {
177: /* 清屏,滚屏,及滚屏对切换虚拟控制台的影响测试 */
178: cout.clear();
179: for(i = 0; i < 24; i++) {
180: cout.putstr("++++++++++++++++++++");
181: cout.putstr("++++++++++++++++++++");
182: cout.putstr("++++++++++++++++++++");
183: cout.putstr("++++++++++++++++++++");
184: }
185: cout.putstr("_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+");
186: switch_console(1);
187: cout.putstr("in console 1 now\n");
188: switch_console(0);
189: cout.putstr("aaa");
190: i++;
191: }
192:
193: {
194: /* 颜色测试 */
195: /*
196: BLACK, BLUE, GREEN, CYAN,
197: RED, MAGENTA, BROWN, GRAY,
198: DARKGRAY, LIGHTBLUE, LIGHTGREEN, LIGHTCYAN,
199: LIGHTRED, LIGHTMAGENTA, YELLOW, WHITE
200: */

201: switch_console(0);
202: cout.set_fg(GREEN);
203: /* cout.set_fg(LIGHTBLUE); */
204: /* cout.set_bg(GREEN); */
205: cout.putstr("bad boy, y you goto here?\n");
206: cout.putstr("sorry, sir, never again\n");
207: i++;
208: }
209:
210: {
211: /* ostream类测试 */
212: switch_console(0);
213: cout << "hi, " << "Welcome use cout object.\n";
214: extern unsigned int multiboot_magic;
215: cout.flags(hex | showbase);
216: multiboot_magic = 0x1BADB002;
217: cout << "after boot, the magic is " << multiboot_magic << "\n";
218: cout << "are you satisfaction with cout?\n";
219: i++;
220: }
221: }
222:
223:

上面代码包含了测试用例,现在我们的c++ 内核也可以用cout 对象了,是不是很有成就感?

Feedback

# re: jinix内核虚拟控制台实现(原创)  回复  更多评论   

2007-07-12 10:54 by 天衣有缝
修正了一个bug:
cout << __func__ << endl;
上面语句编译不能通过,给出的提示似是而非,一番search得到的:
static const char __func__[] = "function-name";

解决方法是重载<<运算符以支持const char *的输出:

OStream& OStream::operator <<(const char *str)
{
putstr(str);
return *this;
}

当然,putstr也要加const修饰:
void TextIO::putstr(const char *s)
{
…………
}

# re: jinix内核虚拟控制台实现(原创)  回复  更多评论   

2007-07-15 12:39 by se
学习

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理