三十天自制操作系统(11)

第23天

操作系统的可执行文件中0x0000存放数据段的大小,0x0020位置存放malloc空间的起始地址这两个我们这一节中要用起来。为了能让应用程序自己分配空间而不是一开始就定义一个很大的数组。我们在目标文件进行链接的时候指定操作系统应该为应用程序分配多少空间,这个空间会与应用程序栈的大小相加写入可执行文件的0x0000位置。

我们目前malloc的策略是这样的,生成目标文件的时候指定malloc的大小,并且把起始位置存放在可执行文件的0x0020位置。如果应用程序需要malloc一段内存空间那么调用api_malloc函数,操作系统从本来就分配给应用程序使用的空间中分一部分给应用程序使用。

接下来我们要开始做一系列的画图API了。

我们设计一个在窗口中画点的API

  • edx = 11
  • ebx = 窗口句柄
  • esi = 显示位置的x坐标
  • edi = 显示位置的y坐标
  • eax = 色号
else if (edx == 11) {
  sht = (struct SHEET *) ebx;
  sht->buf[sht->bxsize * edi + esi] = eax;
  sheet_refresh(sht, esi, edi, esi + 1, edi + 1);
}

画点的api有一个问题,就是每次画一个点都会刷新画面,导致执行效率低下,如果要画很多点,还不如一次把点都画好了,然后刷新一次窗口。我们把所有关于窗口绘图命令设置一个不自动刷新的选项,然后再编写新的用来刷新的API。

刷新窗口这么设计:

  • edx = 12
  • ebx = 窗口句柄
  • eax = x0
  • ecx = y0
  • esi = x1
  • edi = y1

如何设置刷新不刷新的选项呢?之前说过所谓的窗口句柄实际上就是SHEET结构体的指针,肯定是一个偶数也就是说我们可以对窗口句柄与1取与,如果为0则刷新,如果不为0则不刷新。

在窗口上画线API

  • edx = 13
  • ebx = 窗口句柄
  • eax = x0
  • ecx = y0
  • esi = x1
  • edi = y1
  • ebp = 色号

现在我们还无法关闭打开的窗口,比如刚才画线的应用程序,当应用程序结束的时候,调用了api_end函数,然后返回了命令行窗口,但是窗口还是显示在屏幕上,并没有消失。我们为留在画面上的窗口分配了应用程序的空间作为存放图层的内存空间,但是当应用程序结束之后,其数据段的内存空间就被释放,拱操作系统及其他应用程序来使用,因此我们在结束应用程序之前应该先关闭窗口。

设计一下关闭窗口的api

  • edx = 14
  • ebx = 窗口句柄
else if (edx == 14) {
  sheet_free((struct SHEET *) ebx);
}

API是很简单,只要在api_end之前调用api_closewin窗口就会关闭。

但是如果不让应用程序接受键盘输入,那么应用程序的窗口只会有屏幕上一闪而过。接下来写键盘输入的API

  • edx = 15
  • eax = 0 没有键盘输入时返回-1, 不休眠;1休眠直到发生键盘输入
  • eax = 输入的字符编码

这个API接收一个参数,如果参数为0,表示马上查询现在是否有键盘输入,如果没有则返回-1,不休眠。如果参数为1,则表示如果没有键盘输入那么任务将体眠,直到有键盘输入后返回键盘输入值。

else if (edx == 15) {
  for (;;) {
    io_cli();
    if (fifo32_status(&task->fifo) == 0) {
      if (eax != 0) {
        task_sleep(task);   /* FIFO为空,休眠并等待 */
      } else {
        io_sti();
        reg[7] = -1;
        return 0;
      }
    }
    i = fifo32_get(&task->fifo);
    io_sti();
    if (i <= 1) { /* 光标用定时器 */
    /* 应用程序运行时不需要显示光标,因此总是将下次显示用的值置为1 */
      timer_init(cons->timer, &task->fifo, 1); /* 下次置为1 */
      timer_settime(cons->timer, 50);
    }
    if (i == 2) {   /* 光标ON */
      cons->cur_c = COL8_FFFFFF;
    }
    if (i == 3) {   /* 光标OFF */
      cons->cur_c = -1;
    }
    if (256 <= i && i <= 511) { /* 键盘数据(通过任务A获得) */
    reg[7] = i - 256;
    return 0;
    }
  }
}

在窗口还没有关闭的时候,命令行窗口的光标不需要闪烁。实现这个功能的思路是这样:我们用定时器控制光标的闪烁,定时器超时产生中断如果消息队列接收的消息是0,则将光标置为白色,再设置定时器,接收到的消息为1.当接收到消息1时,则将光标置为黑色,再设置定时器,接收到的消息为0。当暂时不需要光标闪烁时,可以将定时器接收到的数据全部置为1。

顺便看下应用程序如何写:

int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
void api_initmalloc(void);
char *api_malloc(int size);
void api_refreshwin(int win, int x0, int y0, int x1, int y1);
void api_linewin(int win, int x0, int y0, int x1, int y1, int col);
void api_closewin(int win);
int api_getkey(int mode);
void api_end(void);

void HariMain(void)
{
  char *buf;
  int win, i;
  api_initmalloc();
  buf = api_malloc(160 * 100);
  win = api_openwin(buf, 160, 100, -1, "lines");
  for (i = 0; i < 8; i++) {
    api_linewin(win + 1,  8, 26, 77, i * 9 + 26, i);
    api_linewin(win + 1, 88, 26, i * 9 + 88, 89, i);
  }
  api_refreshwin(win,  6, 26, 154, 90);
  for (;;) {
    if (api_getkey(1) == 0x0a) {
      break; /* 按下回车break; */
    }
  }
  api_closewin(win);
  api_end();
 }

之前我们写了按下shift + f1会强会关闭应用程序的功能。这段功能是在task_a任务中实现的的

if (i == 256 + 0x3b && key_shift != 0 && task_cons->tss.ss0 != 0) { /* Shift+F1 */
  cons = (struct CONSOLE *) *((int *) 0x0fec);
  cons_putstr0(cons, "\nBreak(key) :\n");
  io_cli(); 
  task_cons->tss.eax = (int) &(task_cons->tss.esp0);
  task_cons->tss.eip = (int) asm_end_app;
  io_sti();
 }

也就是说强制强束应用程序的时候只是把task_console任务重新回到应用程序结束之前的寄存器状态。内存空间已经被收回,但是窗口却还在屏幕上。

我们可以在SHEET结构体中添加一个用来存放task的成员变量,当应用程序结束时,查询所有的图层,如果图层的task为将要结束的应用程序任务时,则关闭该图层。

shtctl = (struct SHTCTL *) *((int *) 0x0fe4);
for (i = 0; i < MAX_SHEETS; i++) {
  sht = &(shtctl->sheets0[i]);
  if (sht->flags != 0 && sht->task == task) {
    sheet_free(sht);    
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容