5 第一个应用程序(harib16e)

好,既然现在我们已经可以读取文件的内容,那么运行应用程序也就不难实现了。

作为头一次尝试,我们要挑战什么样的应用程序呢?当然还是从简单的开始啦。唔,最简单的应用程序是……到底哪个比较好呢?哦,有了,就选那个吧。

因此,请大家把书一口气翻回到3.5节,那里有一个非常简单的操作系统程序,只有3个字节。可能有些人连翻书都懒得翻,好吧,我们就再次来个那3个字节程序的大公开吧!(笑)

3个字节的应用程序

  1. [BITS 32]
  2. fin:
  3. HLT
  4. JMP fin

将上面这段代码保存为hlt.nas,然后用nask进行汇编,生成hlt.hrb。可能大家会问,这个扩展名.hrb是啥?这个嘛,其实是haribote的缩写。如果我们命名为.exe文件的话,就会和Windows的可执行文件产生混淆,因此这里我们用了个自定义的扩展名。

■■■■■

那么,要怎样才能运行文件的内容呢?像type命令一样,我们用file_loadfile将文件的内容读到内存中,问题是后面要怎么办?

应用程序不知道自己被读到哪个内存地址,这里暂且由ORG 0来生成。因此,为了应用程序能够顺利运行,我们需要为其创建一个内存段。

段创建好之后,接下来只要goto到该段中的程序,程序应该就会开始运行了。要goto到其他的内存段,在汇编语言中用farjmp指令。话说,这个指令我们在任务切换的时候已经用过了嘛。因此,这次我们不需要改动naskfunc.nas中的函数就可以运行hlt.hrb了,撒花。

■■■■■

写好的程序如下。

本次的console.c节选

  1. void console_task(struct SHEET *sheet, unsigned int memtotal)
  2. {
  3. (中略)
  4. struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
  5. (中略)
  6. for (;;) {
  7. io_cli();
  8. if (fifo32_status(&task->fifo) == 0) {
  9. (中略)
  10. } else {
  11. (中略)
  12. if (256 <= i && i <= 511) { /*键盘数据(通过任务A) */
  13. if (i == 8 + 256) {
  14. (中略)
  15. } else if (i == 10 + 256) {
  16. (中略)
  17. if (strcmp(cmdline, "mem") == 0) {
  18. (中略)
  19. } else if (strcmp(cmdline, "cls") == 0) {
  20. (中略)
  21. } else if (strcmp(cmdline, "dir") == 0) {
  22. (中略)
  23. } else if (strncmp(cmdline, "type ", 5) == 0) {
  24. (中略)
  25. } else if (strcmp(cmdline, "hlt") == 0) {
  26. /*从此开始*/ /*启动应用程序hlt.hrb */
  27. for (y = 0; y < 11; y++) {
  28. s[y] = ' ';
  29. }
  30. s[0] = 'H';
  31. s[1] = 'L';
  32. s[2] = 'T';
  33. s[8] = 'H';
  34. s[9] = 'R';
  35. s[10] = 'B';
  36. for (x = 0; x < 224; ) {
  37. if (finfo[x].name[0] == 0x00) {
  38. break;
  39. }
  40. if ((finfo[x].type & 0x18) == 0) {
  41. for (y = 0; y < 11; y++) {
  42. if (finfo[x].name[y] != s[y]) {
  43. goto hlt_next_file;
  44. }
  45. }
  46. break; /*找到文件*/
  47. }
  48. hlt_next_file:
  49. x++;
  50. }
  51. if (x < 224 && finfo[x].name[0] != 0x00) {
  52. /*找到文件的情况*/
  53. p = (char *) memman_alloc_4k(memman, finfo[x].size);
  54. file_loadfile(finfo[x].clustno, finfo[x].size, p, fat, (char *)
  55. (ADR_DISKIMG + 0x003e00));
  56. set_segmdesc(gdt + 1003, finfo[x].size - 1, (int) p, AR_CODE32_ER);
  57. farjmp(0, 1003 * 8);
  58. memman_free_4k(memman, (int) p, finfo[x].size);
  59. } else {
  60. /*没有找到文件的情况*/
  61. putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, "File not found.", 15);
  62. cursor_y = cons_newline(cursor_y, sheet);
  63. }
  64. /*到此结束*/ cursor_y = cons_newline(cursor_y, sheet);
  65. } else if (cmdline[0] != 0) {
  66. (中略)
  67. }
  68. (中略)
  69. } else {
  70. (中略)
  71. }
  72. }
  73. (中略)
  74. }
  75. }
  76. }

这次添加的hlt命令,是用来启动hlt.hrb这个应用程序的,前半部分和type命令的代码非常类似。

hlt.hrb成功读入内存之后,将其注册为GDT的1003号。为什么要用1003号呢?100号或者12号不行吗?还真不行,因为1~2号由dsctbl.c使用,而3~1002号由mtask.c使用,所以我们用了1003号,因此如果把1003号换成1234号之类的还是没问题的哦。

随后,当内存段创建完成后,用farjmp跳转并运行。

■■■■■

我们来试试看吧,“make run”,然后在命令行窗口中运行hlt命令,这是“纸娃娃系统”历史上首次运行应用程序,我们的心情无比激动。咦?程序停止了。

5 第一个应用程序(harib16e) - 图1

运行时的样子

糟糕,难道是bug?转念一想,这个程序本来就是执行HTL,这样才是正常的嘛。因为程序不会执行任何操作,因此看上去好像是停止了一样。对了,其实(看上去)停止了的只有命令行窗口而已,如果按下Tab键的话,还是可以切换回task_a的哦。

唔,不过这样一来,我们就没办法判断命令行窗口的停止到底是因为运行了hlt.hrb呢,还是由于另外一些原因不明的bug导致的。我们还是要再确认一下才行。

该怎么办呢?我们用个巧办法吧:

改造版的第一个应用程序

  1. [BITS 32]
  2. CLI
  3. fin:
  4. HLT
  5. JMP fin

我们在开头加上了一个CLI指令,这样整个程序变成了4个字节。如果应用程序正常运行的话,中断处理会被禁止,因此即便按下Tab键也无法切换回task_a,鼠标应该也停止不动了。

那么我们来试验一下。哇,真的停止了耶!太棒了,果然我们的应用程序成功运行了。话说回来,冷静下来一想,自己制作的操作系统明明死机了却还开心得不得了,真是个奇怪的家伙(笑)。总之,撒花。

好了,今天的内容就到这里。明天我们继续加油哦!