setup.s并没有打开页功能,当前cpu只支持32位保护模式,这意味着访问的都是实际的物理地址。
前面1M的内容不好乱动,所以内存都是从1M即:0x100000处开始分配使用。等网卡驱动的时候再考虑这个事情。现在先把任务调度功能跑起来再说。
任务调度基本原理是:定时器触发中断,对应的中断相应函数保留当前现场(即:记录所有寄存器的值)后恢复之前的现场(即:加载上次记录的所有寄存器的值)。现场的内容都记录在esp对应的内存地址中。
当前的定时器为8253,8253的原理和使用baidu都有详细介绍可以参考。
linux代码对8253的配置是这样的:
outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */
outb_p(LATCH & 0xff , 0x40); /* LSB */
outb(LATCH >> 8 , 0x40); /* MSB */
可以直接拿来用,0x43 和0x40端口是用命令查到的:cat /proc/ioports。
任务调度顾名思义不只一个任务,所以要造一个任务表的全局变量来记录所有的任务。先构造一个数据结构来描述任务:
typedef struct task_tbl_s{
unsigned char task_id; //任务ID
unsigned int *task_func_p; //任务的主函数指针
unsigned int *task_stk;//任务当前堆栈地址,这个地方就是用来保存寄存器用的
int counter;//计数器,调度的时候要用到
unsigned int current_esp; //当前任务的esp地址
unsigned int sleep_time;//任务还要sleep多久才能被调度
}task_tbl_t;
参考linux做法,kernel_start()中要有个最原始的task,用这个task把其他的task启动起来。这个最原始的task用iret模仿中断返回来实现。