您的位置:首页 > 其它

(3)从零开始的操作系统开发日记

2016-07-29 16:00 190 查看
所谓的日记,只不过是间隔快一周才发的冗长的资料堆砌orz

关于80386的硬件:

段页式内存机制

分段机制启动、分页机制未启动:逻辑地址—>段机制处理—>线性地址=物理地址

分段机制和分页机制都启动:逻辑地址—>段机制处理—>线性地址—>页机制处理—>物理地址

物理内存地址空间是处理器提交到总线上用于访问计算机系统中的内存和外设的最终地址。一个计算机系统中只有一个物理地址空间。

线性地址空间是80386处理器通过段(Segment)机制控制下的形成的地址空间。

段寄存器:

全部都是16位,较8086多增加FS,GS作附加段

标志寄存器:

IF(Interrupt Flag):中断允许标志位,由CLI,STI两条指令来控制;设置IF位使CPU可识别外部(可屏蔽)中断请求,复位IF位则禁止中断,IF位对不可屏蔽外部中断和故障中断的识别没有任何作用;

IOPL(I/O Privilege Level):I/O特权级字段,它的宽度为2位,它指定了I/O指令的特权级。如果当前的特权级别在数值上小于或等于IOPL,那么I/O指令可执行。否则,将发生一个保护性故障中断;【越小越高级】

NT(Nested Task):控制中断返回指令IRET,它宽度为1位。若NT=0,则用堆栈中保存的值恢复EFLAGS,CS和EIP从而实现中断返回;若NT=1,则通过任务切换实现中断返回。在ucore中,设置NT为0。【在保护模式下,指示当前执行的任务嵌套于另一任务中。当任务被嵌套时,NT=1,否则NT=0。即ucore不使用嵌套式的中断请求?】

关于双向链表:

为了实现数据结构的通用性,采用了接口的思想,将双向链表的结点加入到被管理的结构体当中,并内联实现双向链表的访问操作,减少这些操作的函数调用时间。访问成员则利用了很特别的技巧,下面稍微分析一下:

struct S0{
int member_data;
int* list_node;
}


上结构体在汇编中大概是这样:

DD member_data
DD list_node


我们已知的是list_node的地址,则可以通过list_node-4求得member_data的地址。

如果我们的结构体有多个成员:

struct S1{
int member_data1;
int member_data2;
....
int member_datan;
int* list_node;
}


如何对敌?【都督脸】

我们不可能每创建一个用到双向链表的数据结构就积累一个成员表,这多不科学,于是ucore使用了以下办法:

任意宿主数据结构中memberN成员的地址=(list_node的地址-list_node在宿主数据结构中的偏移量).memberN


用S1作为例子来讲,(list_node的地址-list_node在宿主数据结构中的偏移量)==this,所以可以用这种方法,在仅有list_node的情况下计算出其他成员的访问地址。那么问题来了,list_node的偏移量应该怎么算?讲到这里,讲义中的宏应该已经很好理解了:

#define offsetof(type, member)                                    \
((size_t)(&((type *)0)->member))


将0进行类型强制转换,转换成type型的结构体指针,然后访问这个“指针”的member成员,就可以自动计算得到member的地址,又因为宿主结构的地址的值为0,所以这时候的&((type *)0)->member)即member在宿主数据结构【比如S1,S0】中的偏移值,而这个偏移值是不变的,所以在任意时刻可以通过O(1)时间算出其他成员的地址。

不过说实话,这代码我也是看不懂,这种指针使用技巧真是神,原文的说法是gcc编译器技术的技巧,真可怕。不过只要知道大概处理过程是什么,还是能理解的。

附相关完整源码:

//free_area是空闲块管理结构,free_area.free_list是空闲块链表头
free_area_t free_area;
list_entry_t * le = &free_area.free_list;  //le是空闲块链表头指针
while((le=list_next(le)) != &free_area.free_list) { //从第一个节点开始遍历
struct Page *p = le2page(le, page_link); //获取节点所在基于Page数据结构的变量
……
}

//宏:le2page
// convert list entry to page
#define le2page(le, member)              \
to_struct((le), struct Page, member)

//宏:to_struct()
/* Return the offset of 'member' relative to the beginning of a struct type */
#define offsetof(type, member)                         \
((size_t)(&((type *)0)->member))

//宏 offsetof()
/* *
* to_struct - get the struct from a ptr
* @ptr:    a struct pointer of member
* @type:   the type of the struct this is embedded in
* @member: the name of the member within the struct
* */
#define to_struct(ptr, type, member)                         \
((type *)((char *)(ptr) - offsetof(type, member)))


日常吹水:

不知不觉已经29号了,暑假剩下1个月,时间好像已经很紧张了,然而我好想浪QWQ,上次大佬带我去吃博多拉面真心棒,第一次喝到可以称谓“猪骨汤底”的汤,看母上生日有没有空带她去请他们吃好了【好贵,钱包君哭哭】
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: