《30天自制操作系统》17_day_学习笔记

harib14a:

  接着上一天的内容,我们来思考一个问题:当所有的LEVEL中都没有任务的时候怎么办?采用前面定时器链表中加入“哨兵”的思路,我们加入一个idle任务,去执行HLT。接下来我们只需要将这个闲置任务idle放在最下层的LEVEL就行了。之后修改一下HariMain测试一下结果。

void task_idle(void)//限制任务idle
{
    for (;;) {
        io_hlt();//让CPU不断的HLT等待中断的到来
    }
}
struct TASK *task_init(struct MEMMAN *memman)
{
    struct TASK *task, *idle;
    //.....
    idle = task_alloc();//为dile分配空间
    idle->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024;
    idle->tss.eip = (int) &task_idle;//dile任务做的事,执行这个函数
    idle->tss.es = 1 * 8;
    idle->tss.cs = 2 * 8;
    idle->tss.ss = 1 * 8;
    idle->tss.ds = 1 * 8;
    idle->tss.fs = 1 * 8;
    idle->tss.gs = 1 * 8;
    //idle放在最后一层,FLAG置1
    task_run(idle, MAX_TASKLEVELS - 1, 1);
    return task;
}

harib14b:
  这里我们尝试创建一个命令行窗口。首先对任务B的程序进行一些修改,并将任务A的一部分融合进去,把计数代码从任务B中删除;然后单独创建一个新的任务

void HariMain(void)
{    //.....
    /* sht_cons */
    sht_cons = sheet_alloc(shtctl);//命令行窗口图层、缓冲区
    buf_cons = (unsigned char *) memman_alloc_4k(memman, 256 * 165);
    sheet_setbuf(sht_cons, buf_cons, 256, 165, -1);/* 设置缓冲区,将CMD窗口图层写到缓冲区中 */
    make_window8(buf_cons, 256, 165, "console", 0);//用CMD缓冲区的内容画窗口
    make_textbox8(sht_cons, 8, 28, 240, 128, COL8_000000);//CMD图层下的文本框
    task_cons = task_alloc();             //CMD窗口的任务、分配空间
    task_cons->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 8;
    task_cons->tss.eip = (int) &console_task;    //任务执行的函数(内容)
    task_cons->tss.es = 1 * 8;
    task_cons->tss.cs = 2 * 8;
    task_cons->tss.ss = 1 * 8;
    task_cons->tss.ds = 1 * 8;
    task_cons->tss.fs = 1 * 8;
    task_cons->tss.gs = 1 * 8;
    *((int *) (task_cons->tss.esp + 4)) = (int) sht_cons;//将CMD图层地址放到CMD任务块首部
    task_run(task_cons, 2, 2);   /* 设置LEVEL和优先级level=2, priority=2 */
    //.....
    sheet_slide(sht_back,  0,  0);//图层开始显示的位置
    sheet_slide(sht_cons, 32,  4);
    sheet_slide(sht_win,  64, 56);
    sheet_slide(sht_mouse, mx, my);
    sheet_updown(sht_back,  0);  //设置图层的高度
    sheet_updown(sht_cons,  1);
    sheet_updown(sht_win,   2);
    sheet_updown(sht_mouse, 3);
    //.....
}
void console_task(struct SHEET *sheet)
{
    struct FIFO32 fifo;       //闪烁定时器缓冲区
    struct TIMER *timer;       //闪烁定时器
    struct TASK *task = task_now();//当前运行中任务地址

    int i, fifobuf[128], cursor_x = 8, cursor_c = COL8_000000;
    fifo32_init(&fifo, 128, fifobuf, task);//当前任务写到缓冲区

    timer = timer_alloc();          //闪烁定时器设置
    timer_init(timer, &fifo, 1);
    timer_settime(timer, 50);

    for (;;) {
        io_cli();       //禁止中断
        if (fifo32_status(&fifo) == 0) {
            task_sleep(task);//缓冲区没有内容,让当前运行中的任务睡眠
            io_sti();允许中断
        } else {
            i = fifo32_get(&fifo);
            io_sti();
            if (i <= 1) { /* 光标闪烁定时器超时 */
                if (i != 0) {
                    timer_init(timer, &fifo, 0);  /* i=1;此时重新设置光标定时器,写入FIFO中改为0 */
                    cursor_c = COL8_FFFFFF;    //黑色背景
                } else {
                    timer_init(timer, &fifo, 1);  /* i=1;此时重新设置光标定时器,写入FIFO中改为0 */
                    cursor_c = COL8_000000;    //白色背景
                }
                timer_settime(timer, 50);     //50个count计数的时间、文本显示框
                boxfill8(sheet->buf, sheet->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43);
                sheet_refresh(sheet, cursor_x, 28, cursor_x + 8, 44);//刷新显示
            }
        }
    }
}

harib14c:
  到这里我们已经有两个窗口了,下面我们一步一步实现按下TAB的时候切换输入的窗口的功能,这里我们先修改窗口标题栏的颜色
  1、改写make_windows8()

//我们将描绘窗口标题栏的代码和描绘窗口文本框的代码区分开来
void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act)
{   //这一部分是描绘窗口输入文本框的代码
    //第一步:将设置的文本框的信息写到缓存中
    boxfill8(buf, xsize, COL8_C6C6C6, 0,         0,         xsize - 1, 0        );
    boxfill8(buf, xsize, COL8_FFFFFF, 1,         1,         xsize - 2, 1        );
    boxfill8(buf, xsize, COL8_C6C6C6, 0,         0,         0,         ysize - 1);
    boxfill8(buf, xsize, COL8_FFFFFF, 1,         1,         1,         ysize - 2);
    boxfill8(buf, xsize, COL8_848484, xsize - 2, 1,         xsize - 2, ysize - 2);
    boxfill8(buf, xsize, COL8_000000, xsize - 1, 0,         xsize - 1, ysize - 1);
    boxfill8(buf, xsize, COL8_C6C6C6, 2,         2,         xsize - 3, ysize - 3);
    boxfill8(buf, xsize, COL8_848484, 1,         ysize - 2, xsize - 2, ysize - 2);
    boxfill8(buf, xsize, COL8_000000, 0,         ysize - 1, xsize - 1, ysize - 1);
    //第二步:调用这个函数,将缓存中的内容写到VRAM中
    make_wtitle8(buf, xsize, title, act);
    return;
}
void make_wtitle8(unsigned char *buf, int xsize, char *title, char act)
{   //这里是描绘窗口标题栏的代码,这里没有什么可讲的。
    //就是把两部分代码区分开,便于设置标题的颜色(用ACT参数)
    static char closebtn[14][16] = {
        "[email protected]",
        "[email protected]",
        "[email protected]",
        "[email protected]@[email protected]@[email protected]",
        "[email protected]@[email protected]@[email protected]",
        "[email protected]@@@[email protected]",
        "[email protected]@[email protected]",
        "[email protected]@@@[email protected]",
        "[email protected]@[email protected]@[email protected]",
        "[email protected]@[email protected]@[email protected]",
        "[email protected]",
        "[email protected]",
        "[email protected]",
        "@@@@@@@@@@@@@@@@"
    };
    int x, y;
    char c, tc, tbc;
    if (act != 0) {
        tc = COL8_FFFFFF;
        tbc = COL8_000084;
    } else {
        tc = COL8_C6C6C6;
        tbc = COL8_848484;
    }
    boxfill8(buf, xsize, tbc, 3, 3, xsize - 4, 20);
    putfonts8_asc(buf, xsize, 24, 4, tc, title);
    for (y = 0; y < 14; y++) {
        for (x = 0; x < 16; x++) {
            c = closebtn[y][x];
            if (c == ‘@‘) {
                c = COL8_000000;
            } else if (c == ‘$‘) {
                c = COL8_848484;
            } else if (c == ‘Q‘) {
                c = COL8_C6C6C6;
            } else {
                c = COL8_FFFFFF;
            }
            buf[(5 + y) * xsize + (xsize - 21 + x)] = c;
        }
    }
    return;
}

  2、修改HariMain

//加入TAB键的判断,调用make_wtitle8并修改两个窗口标题的颜色
void HariMain(void)
{                    //.....i为从FIFO中获得中断的数据
    if (256 <= i && i <= 511) { /* 如果获得的是键盘中断的数据 */
        //......
        if (i == 256 + 0x0f) {  /* 键盘中断的键值是TAB键 */
            if (key_to == 0) {  //这里的原理和光标闪烁是一样的
                key_to = 1;   //发送到CMD窗口
                make_wtitle8(buf_win,  sht_win->bxsize,  "task_a",  0);
                make_wtitle8(buf_cons, sht_cons->bxsize, "console", 1);
            } else {
                key_to = 0;   //发送到任务A
                make_wtitle8(buf_win,  sht_win->bxsize,  "task_a",  1);
                make_wtitle8(buf_cons, sht_cons->bxsize, "console", 0);
            }           //接着刷新CMD和窗口图层
            sheet_refresh(sht_win,  0, 0, sht_win->bxsize,  21);
            sheet_refresh(sht_cons, 0, 0, sht_cons->bxsize, 21);
        }
    }
    //.....
}

harib14d:
  我们虽然让窗口的颜色从灰色变成了蓝色,下面我们实现向CMD窗口中输入字符串。只要在键盘被按下的时候,往CMD任务的FIFO中发送数据即可。考虑到很多任务都需要用到缓冲区,我们将FIFO加到任务结构体TASK中。
  1、将FIFO加到任务结构体TASK中。

struct TASK {
    int sel, flags; /* sel表示GDT的编号 */
    int level, priority;
    struct FIFO32 fifo;//任务的缓冲区
    struct TSS32 tss;//任务段的内容
};

  2、修改HariMain

//判断key_to的值,并向FIFO发送数据。
void HariMain(void)
{    //....
    for (;;) {
        //...
            if (256 <= i && i <= 511) {     /* 键盘数据 */
                sprintf(s, "%02X", i - 256); //在背景图层显示按下的 键值
                putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);
                if (i < 0x54 + 256 && keytable[i - 256] != 0) { /* 在keytable表中找到一般字符 */
                    if (key_to == 0) {      /* 把获得的字符发送给任务A的缓冲区 */
                        if (cursor_x < 128) {//窗口的最大长度128像素
                            /* 每输入一个字符,光标向后移动8个像素 */
                            s[0] = keytable[i - 256];
                            s[1] = 0;
                            //在窗口(任务A)图层显示字符
                            putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, s, 1);
                            cursor_x += 8;
                        }
                    } else {/* 发送到CMD窗口(任务)的缓冲区 */
                        fifo32_put(&task_cons->fifo, keytable[i - 256] + 256);
                    }
                }
                if (i == 256 + 0x0e) {    /* Backspace键 */
                    if (key_to == 0) {    /* 发送信息到A任务 */
                        if (cursor_x > 8) {
                                    /* 闪烁光标向左移动8个像素 */
                            putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1);
                            cursor_x -= 8;
                        }
                    } else {          /* 发送到任务CMD窗口 */
                        fifo32_put(&task_cons->fifo, 8 + 256);
                    }
                }
        //......
        }
    }
    //...
}

harib14e:
  这里我们来实现“!”和“%”的输入,我们先来看看Shift键的编码:
         按下    抬起
  左Shift   0x2a   0xaa
  右Shift   0x36   0xb6
  因此我们准备一个key_shift变量,当左Shift按下时置为1,当右Shift按下时置为2,两个都不按时置为0,两个都按下的时候就置为3。当key_shift为0时,我们用keytable0[]进行字符编码转换,当key_shift不为0时,我们使用keytable1[]进行转换。

void HariMain(void)
{
    static char keytable0[0x80] = {
        0,   0,   ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘, ‘0‘, ‘-‘, ‘^‘, 0,   0,
        ‘Q‘, ‘W‘, ‘E‘, ‘R‘, ‘T‘, ‘Y‘, ‘U‘, ‘I‘, ‘O‘, ‘P‘, ‘@‘, ‘[‘, 0,   0,   ‘A‘, ‘S‘,
        ‘D‘, ‘F‘, ‘G‘, ‘H‘, ‘J‘, ‘K‘, ‘L‘, ‘;‘, ‘:‘, 0,   0,   ‘]‘, ‘Z‘, ‘X‘, ‘C‘, ‘V‘,
        ‘B‘, ‘N‘, ‘M‘, ‘,‘, ‘.‘, ‘/‘, 0,   ‘*‘, 0,   ‘ ‘, 0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   ‘7‘, ‘8‘, ‘9‘, ‘-‘, ‘4‘, ‘5‘, ‘6‘, ‘+‘, ‘1‘,
        ‘2‘, ‘3‘, ‘0‘, ‘.‘, 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0x5c, 0,  0,   0,   0,   0,   0,   0,   0,   0,   0x5c, 0,  0
    };
    static char keytable1[0x80] = {
        0,   0,   ‘!‘, 0x22, ‘#‘, ‘$‘, ‘%‘, ‘&‘, 0x27, ‘(‘, ‘)‘, ‘~‘, ‘=‘, ‘~‘, 0,   0,
        ‘Q‘, ‘W‘, ‘E‘, ‘R‘, ‘T‘, ‘Y‘, ‘U‘, ‘I‘, ‘O‘, ‘P‘, ‘`‘, ‘{‘, 0,   0,   ‘A‘, ‘S‘,
        ‘D‘, ‘F‘, ‘G‘, ‘H‘, ‘J‘, ‘K‘, ‘L‘, ‘+‘, ‘*‘, 0,   0,   ‘}‘, ‘Z‘, ‘X‘, ‘C‘, ‘V‘,
        ‘B‘, ‘N‘, ‘M‘, ‘<‘, ‘>‘, ‘?‘, 0,   ‘*‘, 0,   ‘ ‘, 0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   ‘7‘, ‘8‘, ‘9‘, ‘-‘, ‘4‘, ‘5‘, ‘6‘, ‘+‘, ‘1‘,
        ‘2‘, ‘3‘, ‘0‘, ‘.‘, 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   ‘_‘, 0,   0,   0,   0,   0,   0,   0,   0,   0,   ‘|‘, 0,   0
    };
    //.....
    for (;;) {
            //......
            if (256 <= i && i <= 511) { /* 获得的是键盘的数据 */
                sprintf(s, "%02X", i - 256);
                putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);
                if (i < 0x80 + 256) { /* 按照键盘的编码进行转换 */
                    if (key_shift == 0) {
                        s[0] = keytable0[i - 256];
                    } else {
                        s[0] = keytable1[i - 256];
                    }
                } else {
                    s[0] = 0;
                }
                if (s[0] != 0) { /* 一般字符 */
                    if (key_to == 0) {    /* 想任务A中写 */
                        if (cursor_x < 128) {
                            /* 光标后移 */
                            s[1] = 0;
                            putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, s, 1);
                            cursor_x += 8;
                        }
                    } else {    /* 向CMD窗口中写 */
                        fifo32_put(&task_cons->fifo, s[0] + 256);
                    }
                }
                //........
                if (i == 256 + 0x2a) {    /* 左shift ON */
                    key_shift |= 1;
                }
                if (i == 256 + 0x36) {    /* 右shift ON */
                    key_shift |= 2;
                }
                if (i == 256 + 0xaa) {    /* 左shift OFF */
                    key_shift &= ~1;
                }
                if (i == 256 + 0xb6) {    /* 右shift OFF */
                    key_shift &= ~2;
                }
            //./.....
            }
        }
    }//.....
}

harib14f:
  接下来我们要实现大写、小写字母的输入,要区分字母的大小写,我们必须同时判断Shift键的状态以及CapsLock的状态。这里笔者总结出小写字母的条件:Shift和CapsLock的状态相同(同为ON或者OFF)我们从BIOS中获取CapsLock的状态
    binfo->leds的第四位->ScrollLock的状态
    binfo->leds的第五位->NumLock 的状态
    binfo->leds的第六位->CapsLock 的状态
  我们使用上述的数据和规则来处理大小写字母的输入问题:

void HariMain(void)
{    //......这里只取binfo->leds4-6位的数据。
    int key_to = 0, key_shift = 0, key_leds = (binfo->leds >> 4) & 7;
    //......
    if (‘A‘ <= s[0] && s[0] <= ‘Z‘) {    /* 大写字母A-Z之间 */
        if (((key_leds & 4) == 0 && key_shift == 0) ||  //自行在草稿纸上推算
                ((key_leds & 4) != 0 && key_shift != 0)) {
            s[0] += 0x20;    /* 字符值0x20变为小写字母的值 */
        }
    }
    //......
}

harib14g:
  对键盘上锁定键的支持,我们在上面已经实现了锁定键的切换,但是有时候指示灯并不进行相应的切换,下面我们来解决这个问题。先来看看常用三个锁定键的键值:
      0x3a : CapsLock
      0x45 : NumLock
      0x46 : ScrollLock
  对于键盘上锁定键LED的控制,可采用以下方法想键盘发送指令和数据;

    1. 读取状态寄存器,等待bit1的值变为0
    2. 向数据输出(0060)写入要发送的1个字节的数据
    3. 等待键盘返回1个字节的信息,这和等待键盘输入采用的方法相同(用IRQ等待或者用轮询状态寄存器bit1的值知道变为0都可以)
    4. 返回的信息如果是0xfa,表示1个字节的数据已经成功发送给键盘了。如果为0xfe则表示发送失败,返回 1 步重新发送

  要控制LED的状态,需要按照上述方法执行两次,向键盘发送EDxx数据,其中,xx的bit0(ScrollLock)bit1(NumLock)bit2(CapsLock),0表示熄灭,1表示点亮。

void HariMain(void)
{

    struct FIFO32 fifo, keycmd;
    int fifobuf[128], keycmd_buf[32];
    //keycmd_wait表示键盘向控制器发送数据的状态。
    // ==-1:通常状态可以发送指令
    //!=-1:键盘控制器正在等待发送的数据(保存在keycmd_wait)
    //key_leds设置指示灯的状态,这个数据是要送到键盘控制器的

    int key_to = 0, key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1;
    //初始化KEYCMD任务A想键盘发送数据的缓冲区
    fifo32_put(&keycmd, KEYCMD_LED);
    fifo32_put(&keycmd, key_leds);
    //.....
    for (;;) {
        if (fifo32_status(&keycmd) > 0 && keycmd_wait < 0) {
            /* 如果存在想键盘控制器发送的数据,则发送它 */
            keycmd_wait = fifo32_get(&keycmd);//从KEYCMD缓冲区中获得要向键盘发送的数据
            wait_KBC_sendready();        //等待ACK;等待键盘准备好
            io_out8(PORT_KEYDAT, keycmd_wait);//将keycmd_wait的值送到键盘控制器
        }
        io_cli();
        if (fifo32_status(&fifo) == 0) {
            task_sleep(task_a);  //任务A中没有信息,没有从键盘接收的数据,休眠
            io_sti();
        } else {            //任务A有信息
            i = fifo32_get(&fifo);//从任务A的缓冲区得到信息
            io_sti();
            if (256 <= i && i <= 511) {/* 得到键盘数据 */
                //.....
                if (i == 256 + 0x3a) { /* CapsLock */
                    key_leds ^= 4;   //设置CapsLock指示灯亮(ley_leds的第2位为1)
                    fifo32_put(&keycmd, KEYCMD_LED);//先送入默认的KEYCMD_LED是为了下一次获得ACK(0xfa)
                    fifo32_put(&keycmd, key_leds);  //接着再送入设置的指示灯状态信息
                }
                if (i == 256 + 0x45) {          /* NumLock */
                    key_leds ^= 2;            //设置NumLock 指示灯亮(ley_leds的第1位为1)
                    fifo32_put(&keycmd, KEYCMD_LED);//同上
                    fifo32_put(&keycmd, key_leds);
                }
                if (i == 256 + 0x46) {          /* ScrollLock */
                    key_leds ^= 1;            //设置ScrollLock 指示灯亮(ley_leds的第0位为1)
                    fifo32_put(&keycmd, KEYCMD_LED);//同上
                    fifo32_put(&keycmd, key_leds);
                }
                if (i == 256 + 0xfa) {          /* 键盘成功接收数据返回一个ACK(0xfa) */
                    keycmd_wait = -1;         //这是又可以继续向键盘控制器发送数据了
                }
                if (i == 256 + 0xfe) {          /* 键盘接收数据失败返回ACK(0xfe) */
                    wait_KBC_sendready();       //等着(0xfa)键盘准备好
                    io_out8(PORT_KEYDAT, keycmd_wait);//重新把keycmd_wait的值发送到键盘控制器
                }
                //.......
            }
        }
    }
}
时间: 2025-01-19 06:12:23

《30天自制操作系统》17_day_学习笔记的相关文章

《30天自制操作系统》学习笔记-第1天

为了加深对操作系统的理解,我决定照着<30天自制操作系统>这本书实践一下.项目的github链接是https://github.com/YatesXu/YatesOSASK/ 关于十六进制编辑器 第一个问题就是书中给的十六进制编辑器是日文的,在我的电脑上打开之后是一片乱码,于是我比较之后选用了这个十六进制编辑器wxMEdit,链接是https://wxmedit.github.io/. 另外,visual studio也可以,但是express版不能用,所以还是选用免费开源的软件吧(笑) (伪

《30天自制操作系统》读书笔记(3) 引入C语言

这一次的学习相当曲折, 主要是因为粗心, Makefile里面的错误导致了文件生成出现各种奇奇怪怪的问题, 弄得心力交瘁, 因此制作过程还是尽量按着作者的路子来吧. 作者提供的源码的注释在中文系统下是乱码, 而且代码的分隔用了两个Tab, 在这里要处理一下: :%s/;.*//g 删除所有的注释; :%s/\t\t/\t 把两个Tab替换为一个Tab; 要让作者的nas文件和asm文件拥有相同的语法规则, 在_vimrc文件的最后一行添加 au BufNewFile,BufRead *.nas

《30天自制操作系统》读书笔记(2)hello, world

让系统跑起来 要写一个操作系统,我们首先要有一个储存系统的介质,原版书似乎是06年出版的,可惜那时候没有电脑,没想到作者用的还是软盘,现在的电脑谁有软驱?不得已我使用一张128M的SD卡来代替,而事实上你用的是U盘还是软盘对我们的操作系统没有影响,缺点是你的U盘刷入系统后容量只能是1440 MB,即当年流行的3.5英寸软盘的大小,当然不用担心,再格式化一次(用DiskGeniu),就可以恢复. 我做事情的话,总是怕自己的努力的结果白费了,害怕辛辛苦苦看完这本书但是发现做出来的东西现在根本没法用,

《30天自制操作系统》读书笔记(4) 绘图

暑假果然是滋生懒散的温床. (╯‵□′)╯︵┻━┻ 好久不动都忘记之前做到哪里了, 上次好像做到了C语言的引入, 这一节所做的东西都相当轻松, 将会绘制出操作系统的基本界面. 绘图的原理 按照书中所说, 将值写入到显存中就能在屏幕上显示相应的像素, 在asmhead.nas 中有这一段: 1 CYLS EQU 0x0ff0 ; 设定启动区 2 LEDS EQU 0x0ff1 3 VMODE EQU 0x0ff2 ; 关于颜色数目的信息,颜色的位数 4 SCRNX EQU 0x0ff4 ; 分辨率

《30天自制操作系统》读书笔记(1)读前感

做一个自己的操作系统, 在我看来一直是不可以思议的,而且奇妙的,像是吉他手亲手打造一把自己的吉他? 似乎这个比喻不太恰当, 但是,感觉是一样的. <30天自制操作系统> 为日本的川和秀实先生所著, 有人说他是 "<XX天学会XXX>之类的书中为数不多的几本好书之一." 这本书的优点非常明显,通俗生趣,甚至于有点啰嗦:而且作者无私地提供了源代码而且允许你以任何方式使用,也提供了编译的所有工具,所有东西都是"开箱即用",不容易出问题. 作为后生我

《30天自制操作系统》读书笔记(5) GDT&amp;IDT

梳理项目结构 项目做到现在, 前头的好多东西都忘了, 还是通过Makefile重新理解一下整个项目是如何编译的: 现在我们拥有这么9个文件: ipl10.nas    InitialProgramLoader, 占用了软盘的第一个扇区并符合启动盘的规范, 默认被载入地址是0x7c00 到 0x7e00, 负责将10个柱面读入到0x8200到0x34fff (10个柱面共10*2*18 = 360 个扇区但是第一个没有被读入); asmhead.nas     包含一些暂时未知的设定; naskf

多定时器处理1(30天自制操作系统--读书笔记)

自认为写过很多MCU程序,但总是回头想想,我所了解的MCU编程思想大体有两种,其中具体的想法我得再找时间写下来. 总想总结出一个可扩展的,易移植的写法,但能力还没到这个层次.但<30天自制操作系统>这本书确实给我了一个思路,就像我已经写过的两篇读书笔记. 将两个独立的内容--FIFO和内存动态管理做到高度模块化,尤其是其中数据结构模型的设计更是我学习的好例子. 今天要学习的设计内容是多定时器处理.原书对这部分的处理讲的很详细,由浅入深,看得我由衷佩服作者,也可能是因为我水平低,稍稍看出点门道来

单字节的FIFO缓存(30天自制操作系统--读书笔记)

从今天起,写一些读书笔记.最近几个月都在看<30天自制操作系统这本书>,书虽说看的是电子书,但可以花钱买的正版书,既然花费了金钱,就总得有些收获. 任何人都不能总是固步自封,想要进步就得学习别人的知识,对于程序员而言,最简单的方法即是学习别人的代码. 今天的标题是“单字节的FIFO缓存”,其实就是做一个FIFO,看名字就知道了.也就4个函数和1个相关结构体,这样的小代码在嵌入式系统中很常用,也会很好用. 1.相关数据结构体 struct FIFO8 { unsigned char *buf;

《30天自制操作系统》笔记(12)——多任务入门

<30天自制操作系统>笔记(12)——多任务入门 进度回顾 上一篇介绍了设置显示器高分辨率的方法.本篇讲一下操作系统实现多任务的方法. 什么是多任务 对程序员来说,也许这是废话,不过还是说清楚比较好. 多任务就是让电脑同时运行多个程序(如一边写代码一边听音乐一边下载电影). 电脑的CPU只有固定有限的那么一个或几个,不可能真的同时运行多个程序.所以就用近似的方式,让多个程序轮换着运行.当轮换速度够快(0.01秒),给人的感觉就是"同时"运行了. 多任务之不实用版 我们首先从

《30天自制操作系统》笔记(03)——使用Vmware

<30天自制操作系统>笔记(03)--使用Vmware 进度回顾 在上一篇,实现了用IPL加载OS程序到内存,然后JMP到OS程序这一功能:并且总结出下一步的OS开发结构.但是遇到了真机测试和U盘启动的一些问题.本篇就来解决之. 遇到的问题 物理机测试 简单来说,把软盘(U盘)做成启动盘后,自然想要用来启动物理机器.毕竟这才是真正的测试.(用QEMU总没多大的成就感)但物理机测试的麻烦在于太慢了,每次都要关掉Windows,重启,测试,然后再重启Windows.而且还没办法截图. 而用Vmwa