Linux 0.12 OS. math - CR0

从这篇文章开始算是正式进入math模块的学习,前期我花了大量的时间来储备必要的知识,这个工作早在今年年初就进行了,可是被各种原因耽搁,我也寄希望于接下来能顺利进行。

这里得说一下,我是一边学习一边做的笔记,因此非常大可能出现错误。如果在文章发表后发现错误,我会及时更新上去,希望尽可能不给大家的理解造成困扰。

一 CR0控制寄存器


- NE

浮点处理器操作模式,0为MS-DOS compatibility mode(Vector 45, IRQ13),1为Native mode(Vector 16, Coprocessor error)

- ET (Extension Type)

协处理器类型,0表示80287协处理器或者没有协处理器,1表示80387协处理器。

- TS (Task Switched)

任务已切换标志,0表示任务没有被切换,1表示任务已切换成功。它可以延迟保存任务切换时协处理器的内容(系统通过触发一个DNA(Device Not Available, Vector 7, device not available)异常来让你保存任务切换时协处理器的内容),直到新任务开始执行协处理器指令。一个直观的事实是如果新任务一直没有执行协处理器指令,那么保存之前任务的协处理器内容的操作就会一直被延迟,试想,如果在切回原任务前都没有任务执行协处理器指令,那么当前的协处理器内容就是原任务协处理器的内容,省去了协处理器内容的互换操作。

- EM (EMulation)

仿真标志,0表示系统有协处理器,1表示系统没有协处理器。对于EM和TS,EM=1系统没有协处理器或者EM=0 & TS=1任务已切换,一旦遇到协处理器指令就会触发DNA异常。

- MP (Math Present)

协处理器监控标志,0表示不监控,1表示开始监控。对于MP和TS,MP=1 & TS=1任务已切换被监控到,一旦遇到WAIT or FWAIT指令就会触发DNA异常。


二 Code部分

- boot/head.s (check x87)

/*
 * NOTE! 486 should set bit 16, to check for write-protect in supervisor
 * mode. Then it would be unnecessary with the "verify_area()"-calls.
 * 486 users probably want to set the NE (#5) bit also, so as to use
 * int 16 for math errors.
 */
	movl %cr0,%eax		# check math chip
	andl $0x80000011,%eax	# Save PG,PE,ET, reset NE,TS,EM,MP
/* "orl $0x10020,%eax" here for 486 might be good */
	orl $2,%eax		# set MP
	movl %eax,%cr0
	call check_x87
	jmp after_page_tables

/*
 * We depend on ET to be correct. This checks for 287/387.
 */
check_x87:
	fninit    /* initialize swd,cwd,twd */
	fstsw %ax   /* store swd to ax register, 
all is 0 except for that the condition code of swd is indeterminte */
	cmpb $0,%al  /* 如果al为0(al初始不为0),则表示协处理器有将swd初始化 */
	je 1f			/* no coprocessor: have to set bits */
	movl %cr0,%eax
	xorl $6,%eax		/* reset MP, set EM , 此时EM=1,没有协处理器,MP=0,不会监控TS标志 */
	movl %eax,%cr0
	ret
.align 4
1:	.byte 0xDB,0xE4		/* fnsetpm(not 'fsetpm') for 287, ignored by 387,对于80287需要设定为保护模式 */
	ret

- kernel/asm.s (IRQ13)

irq13:
	pushl %eax        
	xorb %al,%al
	outb %al,$0xF0     /* 0xF0是协处理器端口,用于清忙锁存器 */
	movb $0x20,%al
	outb %al,$0x20     /* 向8259主中断控制器发送EOI(中断结束)信号 */
	jmp 1f
1:	jmp 1f
1:	outb %al,$0xA0   /* 向8259从中断控制器发送EOI(中断结束)信号 */
	popl %eax
	jmp coprocessor_error   /* 异常转移 */

- kernel/sys_call.s (Coprocessor error)

coprocessor_error:              /* 目前没有任何功能 */
	push %ds
	push %es
	push %fs
	pushl $-1		# fill in -1 for orig_eax
	pushl %edx
	pushl %ecx
	pushl %ebx
	pushl %eax
	movl $0x10,%eax
	mov %ax,%ds
	mov %ax,%es
	movl $0x17,%eax
	mov %ax,%fs
	pushl $ret_from_sys_call
	jmp math_error          

- kernel/sys_call.s (Device Not Available)

device_not_available:   /* '大名鼎鼎'的DNA异常 */
	push %ds
	push %es
	push %fs
	pushl $-1		# fill in -1 for orig_eax
	pushl %edx
	pushl %ecx
	pushl %ebx
	pushl %eax
	movl $0x10,%eax
	mov %ax,%ds
	mov %ax,%es
	movl $0x17,%eax
	mov %ax,%fs
	pushl $ret_from_sys_call   /* 以上为标准的system call writing */
	clts				/* clear TS so that we can use math, 注意TS只在EM=0时才有意义 */
	movl %cr0,%eax
	testl $0x4,%eax			# EM (math emulation bit)
	je math_state_restore /* EM=0表示系统有协处理器,那么按正常flow跑即可,去执行协处理器内容的互换操作 */
	pushl %ebp
	pushl %esi
	pushl %edi
	pushl $0		# temporary storage for ORIG_EIP
	call math_emulate   /* 看来系统没有协处理器,开始协处理器的模拟 */
	addl $4,%esp
	popl %edi
	popl %esi
	popl %ebp
	ret

- include/linux/sched.h (Task Switched)

/*
 *	switch_to(n) should switch tasks to task nr n, first
 * checking that n isn't the current task, in which case it does nothing.
 * This also clears the TS-flag if the task we switched to has used
 * tha math co-processor latest.
 */
#define switch_to(n) {\
struct {long a,b;} __tmp; \
__asm__("cmpl %%ecx,current\n\t" \
	"je 1f\n\t" \
	"movw %%dx,%1\n\t" \
	"xchgl %%ecx,current\n\t" \
	"ljmp *%0\n\t" \
	"cmpl %%ecx,last_task_used_math\n\t" \
/* 如果说返回原任务前没有其他任务去执行协处理器指令,那么清掉TS标志,无需进行协处理器内容的互换操作 */
	"jne 1f\n\t" \
	"clts\n" \
	"1:" \
	::"m" (*&__tmp.a),"m" (*&__tmp.b), \
	"d" (_TSS(n)),"c" ((long) task[n])); \
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值