andl $0xfffff000, %eax # 有点多余,但写上还算明白一点
movl %eax, %cr3
- /* 开启分页与地址转换 (CR0.PG=1, PG.WP=1) */
movl %cr0, %eax
- orl $0x80010000, %eax
+ orl $0x80010000, %eax /* 开启分页与地址转换 (CR0.PG=1, CR0.WP=1) */
+ andl $0xfffffffb, %eax
+ orl $0x2, %eax /* 启用x87 FPU (CR0.MP=1, CR0.EM=0) */
movl %eax, %cr0
+ movl %cr4, %eax
+ orl $0x600, %eax
+ movl %eax, %cr4 /* CR4.OSFXSR=1, CR4.OSXMMEXCPT=1 */
+ /* x87 FPU 已配置 */
+
addl $16, %esp
/* 进入高半核! */
struct mm_region regions;
};
+struct proc_sigstate
+{
+ isr_param proc_regs;
+ char fxstate[512] __attribute__((aligned(16)));
+};
+
struct proc_sig
{
void* signal_handler;
int sig_num;
- isr_param prev_context;
-};
-
-#define PROC_SIG_SIZE sizeof(struct proc_sig) // size=84
+ struct proc_sigstate prev_context;
+} __attribute__((packed));
struct proc_info
{
/* ---- critical section start ---- */
- pid_t pid;
- struct proc_info* parent;
- isr_param intr_ctx; // size=76
- uintptr_t ustack_top;
- void* page_table;
+ pid_t pid; // offset = 0
+ struct proc_info* parent; // offset = 4
+ isr_param intr_ctx; // offset = 8
+ uintptr_t ustack_top; // offset = 84
+ void* page_table; // offset = 88
+ void* fxstate; // offset = 92
/* ---- critical section end ---- */
# 保存用户栈顶指针。这是因为我们允许系统调用内进行上下文切换,而这样一来,我们就失去了用户栈的信息,
# 这样一来,就无法设置信号上下文。这主要是为了实现了pause()而做的准备
- movl (__current), %eax
+ movl (__current), %eax
+
+ # 保存x87FPU的状态
+ movl 92(%eax), %ebx
+ fxsave (%ebx)
+
movl 68(%esp), %ebx # 取出esp
movl %ebx, 84(%eax) # 存入__current->ustack_top
movl 56(%esp), %eax
movl %eax, (debug_resv + 4)
#endif
+ movl (__current), %eax
+ movl 92(%eax), %eax
+ fxrstor (%eax)
popl %eax
popl %ebx
# 注意2:handle_signal在调用之前,须确保proc_sig已经写入用户栈!
leal 8(%eax), %ebx # arg1 in %eax: addr of proc_sig structure in user stack
- pushl $UDATA_SEG # proc_sig->prev_context.ss
+ pushl $UDATA_SEG # proc_sig->prev_context.proc_regs.ss
pushl %eax # esp
- pushl 64(%ebx) # proc_sig->prev_context.eflags
+ pushl 64(%ebx) # proc_sig->prev_context.proc_regs.eflags
pushl $UCODE_SEG # cs
pushl $sig_wrapper # eip for sig wrapper
proc->created = clock_systime();
proc->pgid = proc->pid;
proc->fdtable = vzalloc(sizeof(struct v_fdtable));
+ proc->fxstate =
+ vzalloc_dma(512); // FXSAVE需要十六位对齐地址,使用DMA块(128位对齐)
llist_init_head(&proc->mm.regions.head);
llist_init_head(&proc->tasks);
}
vfree(proc->fdtable);
+ vfree_dma(proc->fxstate);
struct mm_region *pos, *n;
llist_for_each(pos, n, &proc->mm.regions.head, head)
+#include <klibc/string.h>
#include <lunaix/lunistd.h>
#include <lunaix/lxsignal.h>
#include <lunaix/process.h>
[_SIGINT] = default_sighandler_term,
};
-volatile isr_param __temp_save;
+volatile struct proc_sigstate __temp_save;
// Referenced in kernel/asm/x86/interrupt.S
void*
signal_dispatch()
解决办法就是先吧intr_ctx拷贝到一个静态分配的区域里,然后再注入到用户栈。
*/
- __temp_save = __current->intr_ctx;
+ __temp_save.proc_regs = __current->intr_ctx;
+ memcpy(__temp_save.fxstate, __current->fxstate, 512);
+
sig_ctx->prev_context = __temp_save;
sig_ctx->sig_num = sig_selected;
__DEFINE_LXSYSCALL1(int, sigreturn, struct proc_sig, *sig_ctx)
{
- __current->intr_ctx = sig_ctx->prev_context;
+ memcpy(__current->fxstate, sig_ctx->prev_context.fxstate, 512);
+ __current->intr_ctx = sig_ctx->prev_context.proc_regs;
__current->flags &= ~PROC_FINPAUSE;
__SIGCLEAR(__current->sig_inprogress, sig_ctx->sig_num);
schedule();