-fno-cse-follow-jumps\
-fno-cse-skip-blocks\
-fno-optimize-strlen\
- -fno-tree-builtin-call-dce
+ -fno-inline-functions-called-once \
+ -fno-inline-functions \
+ -fno-inline-small-functions \
+ -fno-indirect-inlining
CFLAGS := -std=gnu99 -ffreestanding $(O) $(OFLAGS) $(W) $(ARCH_OPT)
LDFLAGS := -ffreestanding $(O) -nostdlib -lgcc
\ No newline at end of file
char c;
if (sdbg_state == SDBG_STATE_WAIT_BRK) {
- (param)->eflags &= ~(1 << 8);
+ (param)->execp->eflags &= ~(1 << 8);
sdbg_state = SDBG_STATE_INSESSION;
- sdbg_printf("[%p:%p] Break point reached.\n", param->cs, param->eip);
+ sdbg_printf("[%p:%p] Break point reached.\n",
+ param->execp->cs,
+ param->execp->eip);
}
while (1) {
switch (c) {
case SDBG_CLNT_HI:
if (sdbg_state == SDBG_STATE_START) {
- sdbg_printf(
- "[%p:%p] Session started.\n", param->cs, param->eip);
+ sdbg_printf("[%p:%p] Session started.\n",
+ param->execp->cs,
+ param->execp->eip);
sdbg_state = SDBG_STATE_INSESSION;
} else {
- sdbg_printf(
- "[%p:%p] Session resumed.\n", param->cs, param->eip);
+ sdbg_printf("[%p:%p] Session resumed.\n",
+ param->execp->cs,
+ param->execp->eip);
}
break;
case SDBG_CLNT_RREG:
serial_tx_buffer(SERIAL_COM1, (char*)param, sizeof(isr_param));
break;
case SDBG_CLNT_STEP:
- ((isr_param*)param)->eflags |= (1 << 8); // set TF flags
+ ((isr_param*)param)->execp->eflags |= (1 << 8); // set TF flags
sdbg_state = SDBG_STATE_WAIT_BRK;
return;
case SDBG_CLNT_BRKP:
gdbstub_loop(isr_param* param)
{
/* Translate vector to signal */
- switch (param->vector) {
+ switch (param->execp->vector) {
case 1:
gdb_state.signum = 5;
break;
gdb_state.registers[GDB_CPU_I386_REG_ECX] = param->registers.ecx;
gdb_state.registers[GDB_CPU_I386_REG_EDX] = param->registers.edx;
gdb_state.registers[GDB_CPU_I386_REG_EBX] = param->registers.ebx;
- gdb_state.registers[GDB_CPU_I386_REG_ESP] = param->registers.esp;
+ gdb_state.registers[GDB_CPU_I386_REG_ESP] = param->esp;
gdb_state.registers[GDB_CPU_I386_REG_EBP] = param->registers.ebp;
gdb_state.registers[GDB_CPU_I386_REG_ESI] = param->registers.esi;
gdb_state.registers[GDB_CPU_I386_REG_EDI] = param->registers.edi;
- gdb_state.registers[GDB_CPU_I386_REG_PC] = param->eip;
- gdb_state.registers[GDB_CPU_I386_REG_CS] = param->cs;
- gdb_state.registers[GDB_CPU_I386_REG_PS] = param->eflags;
- gdb_state.registers[GDB_CPU_I386_REG_SS] = param->ss;
+ gdb_state.registers[GDB_CPU_I386_REG_PC] = param->execp->eip;
+ gdb_state.registers[GDB_CPU_I386_REG_CS] = param->execp->cs;
+ gdb_state.registers[GDB_CPU_I386_REG_PS] = param->execp->eflags;
+ gdb_state.registers[GDB_CPU_I386_REG_SS] = param->execp->ss;
gdb_state.registers[GDB_CPU_I386_REG_DS] = param->registers.ds;
gdb_state.registers[GDB_CPU_I386_REG_ES] = param->registers.es;
gdb_state.registers[GDB_CPU_I386_REG_FS] = param->registers.fs;
param->registers.ecx = gdb_state.registers[GDB_CPU_I386_REG_ECX];
param->registers.edx = gdb_state.registers[GDB_CPU_I386_REG_EDX];
param->registers.ebx = gdb_state.registers[GDB_CPU_I386_REG_EBX];
- param->registers.esp = gdb_state.registers[GDB_CPU_I386_REG_ESP];
+ param->esp = gdb_state.registers[GDB_CPU_I386_REG_ESP];
param->registers.ebp = gdb_state.registers[GDB_CPU_I386_REG_EBP];
param->registers.esi = gdb_state.registers[GDB_CPU_I386_REG_ESI];
param->registers.edi = gdb_state.registers[GDB_CPU_I386_REG_EDI];
- param->eip = gdb_state.registers[GDB_CPU_I386_REG_PC];
- param->cs = gdb_state.registers[GDB_CPU_I386_REG_CS];
- param->eflags = gdb_state.registers[GDB_CPU_I386_REG_PS];
- param->ss = gdb_state.registers[GDB_CPU_I386_REG_SS];
+ param->execp->eip = gdb_state.registers[GDB_CPU_I386_REG_PC];
+ param->execp->cs = gdb_state.registers[GDB_CPU_I386_REG_CS];
+ param->execp->eflags = gdb_state.registers[GDB_CPU_I386_REG_PS];
+ param->execp->ss = gdb_state.registers[GDB_CPU_I386_REG_SS];
param->registers.ds = gdb_state.registers[GDB_CPU_I386_REG_DS];
param->registers.es = gdb_state.registers[GDB_CPU_I386_REG_ES];
param->registers.fs = gdb_state.registers[GDB_CPU_I386_REG_FS];
// synchronized way. And we don't want these irq queue up at our APIC and
// confuse the CPU after ACK with APIC.
serial_disable_irq(SERIAL_COM1);
- if (param->vector == 1 || param->vector == 3) {
+ struct exec_param* execp = param->execp;
+ if (execp->vector == 1 || execp->vector == 3) {
goto cont;
}
void
sdbg_imm(const isr_param* param)
{
+ struct exec_param* execp = param->execp;
kprintf(KDEBUG "Quick debug mode\n");
kprintf(KDEBUG "cs=%p eip=%p eax=%p ebx=%p\n",
- param->cs,
- param->eip,
+ execp->cs,
+ execp->eip,
param->registers.eax,
param->registers.ebx);
kprintf(KDEBUG "ecx=%p edx=%p edi=%p esi=%p\n",
param->registers.edi,
param->registers.esi);
kprintf(KDEBUG "u.esp=%p k.esp=%p ebp=%p ps=%p\n",
- param->registers.esp,
param->esp,
+ execp->esp,
param->registers.ebp,
- param->eflags);
+ execp->eflags);
kprintf(KDEBUG "ss=%p ds=%p es=%p fs=%p gs=%p\n",
- param->ss,
+ execp->ss,
param->registers.ds,
param->registers.es,
param->registers.fs,
struct ahci_driver *pos, *n;
llist_for_each(pos, n, &ahcis, ahci_drvs)
{
- if (pos->id == param->vector) {
+ if (pos->id == param->execp->vector) {
hba = &pos->hba;
goto proceed;
}
#ifndef __ASM__
#include <hal/cpu.h>
+
+struct exec_param;
+
typedef struct
{
+ unsigned int depth;
struct
{
reg32 eax;
reg32 es;
reg32 fs;
reg32 gs;
- reg32 esp;
} __attribute__((packed)) registers;
+ union
+ {
+ reg32 esp;
+ volatile struct exec_param* execp;
+ };
+} __attribute__((packed)) isr_param;
+
+struct exec_param
+{
+ isr_param saved_prev_ctx;
unsigned int vector;
unsigned int err_code;
unsigned int eip;
unsigned int eflags;
unsigned int esp;
unsigned int ss;
-} __attribute__((packed)) isr_param;
+} __attribute__((packed));
+
+#define ISR_PARAM_SIZE sizeof(isr_param)
void
intr_handler(isr_param* param);
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
+ uintptr_t ustack_top; // offset = 84 -> 56 -> 60
+ void* page_table; // offset = 88 -> 60 -> 64
+ void* fxstate; // offset = 92 -> 64 -> 68
/* ---- critical section end ---- */
.global debug_resv
debug_resv:
.skip 16
+ tmp_store:
+ .skip 4
#endif
.section .bss
interrupt_wrapper:
/*
Stack layout (layout of struct isr_param)
- msa: [ss]
- [esp]
- eflags > offset = 48 + 16 = 64
- cs
- eip
- err_code
- vector > offset = 28 + 16 + 4 = 48
+ msa: [ss] > 76
+ [esp] > 72
+ eflags > 68
+ cs > 64
+ eip > 60
+ err_code > 56
+ vector > offset = 52
+ [saved_prev_ctx] > offset = 0
+ ---
esp
gs
fs
es
- ds > offset = 7 * 4 = 28
+ ds > offset = 7 * 4 = 28 + 4
esi
ebp
edi
edx
ecx
ebx
- lsa: eax > offset = 0
+ eax
+ lsa: depth > offset = 0
las: Least Significant Address
msa: Most Significant Address
*/
cld
+
+ subl $52, %esp
pushl %esp
subl $16, %esp
pushl %ebx
pushl %eax
- movl 60(%esp), %eax /* 取出 %cs */
+ movl __current, %eax
+ movl 8(%eax), %eax
+ incl %eax
+ pushl %eax # nested intr: current depth
+
+ movl 116(%esp), %eax /* 取出 %cs */
andl $0x3, %eax /* 判断 RPL */
jz 1f
# 保存用户栈顶指针。这是因为我们允许系统调用内进行上下文切换,而这样一来,我们就失去了用户栈的信息,
# 这样一来,就无法设置信号上下文。这主要是为了实现了pause()而做的准备
- movl (__current), %eax
+ movl __current, %eax
# 保存x87FPU的状态
- movl 92(%eax), %ebx
+ movl 68(%eax), %ebx
fxsave (%ebx)
- movl 68(%esp), %ebx # 取出esp
- movl %ebx, 84(%eax) # 存入__current->ustack_top
+ movl 124(%esp), %ebx # 取出esp
+ movl %ebx, 60(%eax) # 存入__current->ustack_top
1:
movl %esp, %eax
#ifdef __ASM_INTR_DIAGNOSIS
movl %eax, (debug_resv + 8)
- movl 56(%esp), %eax
- movl %eax, (debug_resv + 4)
+ movl 48(%esp), %eax
+ movl 60(%eax), %eax
+ movl %eax, (debug_resv + 4) # eip
#endif
- movl (__current), %eax
- movl 92(%eax), %eax
+ movl __current, %eax
+ movl 68(%eax), %eax
test %eax, %eax # do we have stored x87 context?
jz 1f
fxrstor (%eax)
1:
+ popl %eax # discard isr_param::depth
popl %eax
popl %ebx
popl %ecx
movl 16(%esp), %esp
+ movl %eax, tmp_store
+ movl __current, %eax
+ # nested intr: restore saved context
+ popl 8(%eax) # depth
+ popl 12(%eax) # eax
+ popl 16(%eax) # ebx
+ popl 20(%eax) # ecx
+ popl 24(%eax) # edx
+ popl 28(%eax) # edi
+ popl 32(%eax) # ebp
+ popl 36(%eax) # esi
+ popl 40(%eax) # ds
+ popl 44(%eax) # es
+ popl 48(%eax) # fs
+ popl 52(%eax) # gs
+ popl 56(%eax) # esp
+
addl $8, %esp
- pushl %eax
#ifdef __ASM_INTR_DIAGNOSIS
- movl 4(%esp), %eax
+ movl (%esp), %eax
movl %eax, debug_resv
#endif
# 处理TSS.ESP的一些边界条件。如果是正常iret(即从内核模式*优雅地*退出)
# 那么TSS.ESP0应该为iret进行弹栈后,%esp的值。
# 所以这里的边界条件是:如返回用户模式,iret会额外弹出8个字节(ss,esp)
- movl 8(%esp), %eax
+ movl 4(%esp), %eax
andl $3, %eax
setnz %al
shll $3, %eax
- addl $16, %eax
+ addl $12, %eax
addl %esp, %eax
movl %eax, (_tss + 4)
- popl %eax
+ movl tmp_store, %eax
iret
.global switch_to
popl %ebx # next
movl __current, %eax
- movl 88(%eax), %ecx # __current->pagetable
- movl 88(%ebx), %eax # next->pagetable
+ movl 64(%eax), %ecx # __current->pagetable
+ movl 64(%ebx), %eax # next->pagetable
cmpl %ecx, %eax # if(next->pagtable != __current->pagetable) {
jz 1f
pushl $UDATA_SEG # proc_sig->prev_context.proc_regs.ss
pushl %eax # esp
- pushl 64(%ebx) # proc_sig->prev_context.proc_regs.eflags
+ movl 48(%ebx), %ebx
+ pushl 68(%ebx) # proc_sig->prev_context.proc_regs.execp->eflags
pushl $UCODE_SEG # cs
pushl $sig_wrapper # eip for sig wrapper
pushl %eax # Addr to proc_sig structure
pushl 4(%eax) # proc_sig->sig_num ---- 16 bytes aligned
- call (%eax) # invoke signal handler
+ call *(%eax) # invoke signal handler
# invoke the sigreturn syscall to exit the signal wrapper
movl $__SYSCALL_sigreturn, %eax
void
intr_handler(isr_param* param)
{
+ param->execp->saved_prev_ctx = __current->intr_ctx;
__current->intr_ctx = *param;
- isr_param* lparam = &__current->intr_ctx;
+ volatile struct exec_param* execp = __current->intr_ctx.execp;
- if (lparam->vector <= 255) {
- isr_cb subscriber = isrm_get(lparam->vector);
+ if (execp->vector <= 255) {
+ isr_cb subscriber = isrm_get(execp->vector);
subscriber(param);
goto done;
}
kprint_panic("INT %u: (%x) [%p: %p] Unknown",
- lparam->vector,
- lparam->err_code,
- lparam->cs,
- lparam->eip);
+ execp->vector,
+ execp->err_code,
+ execp->cs,
+ execp->eip);
done:
// for all external interrupts except the spurious interrupt
// this is required by Intel Manual Vol.3A, section 10.8.1 & 10.8.5
- if (lparam->vector >= IV_EX && lparam->vector != APIC_SPIV_IV) {
+ if (execp->vector >= IV_EX && execp->vector != APIC_SPIV_IV) {
apic_done_servicing();
}
void
__print_panic_msg(const char* msg, const isr_param* param)
{
+ struct exec_param* execp = param->execp;
kprint_panic(" INT %u: (%x) [%p: %p] %s",
- param->vector,
- param->err_code,
- param->cs,
- param->eip,
+ execp->vector,
+ execp->err_code,
+ execp->cs,
+ execp->eip,
msg);
}
goto segv_term;
}
- if (!SEL_RPL(param->cs)) {
+ if (!SEL_RPL(param->execp->cs)) {
// 如果是内核页错误……
if (do_kernel(&mapping)) {
return;
kprintf(KERROR "(pid: %d) Segmentation fault on %p (%p:%p)\n",
__current->pid,
ptr,
- param->cs,
- param->eip);
+ param->execp->cs,
+ param->execp->eip);
__SIGSET(__current->sig_pending, _SIGSEGV);
schedule();
// should not reach
.section .text
syscall_hndlr:
pushl %ebp
- movl 8(%esp), %ebp
+ movl 8(%esp), %ebp // isr_param*
- movl (%ebp), %eax /* eax: call code as well as the return value from syscall */
- cmpl $__SYSCALL_MAX, %eax
+ addl $4, %ebp
+ movl (%ebp), %eax /* eax: call code as well as the return value from syscall */
+ cmpl $__SYSCALL_MAX, %eax
jae 2f
shll $2, %eax
proc0->intr_ctx = (isr_param){ .registers = { .ds = KDATA_SEG,
.es = KDATA_SEG,
.fs = KDATA_SEG,
- .gs = KDATA_SEG },
- .cs = KCODE_SEG,
- .eip = (void*)__proc0,
- .ss = KDATA_SEG,
- .eflags = cpu_reflags() };
+ .gs = KDATA_SEG } };
proc0->parent = proc0;
// 方案1:必须在读取eflags之后禁用。否则当进程被调度时,中断依然是关闭的!
VMAP_NULL);
}
- // 手动设置进程上下文:用于第一次调度
- asm volatile("movl %%esp, %%ebx\n"
- "movl %1, %%esp\n"
- "pushf\n"
- "pushl %2\n"
- "pushl %3\n"
- "pushl $0\n"
- "pushl $0\n"
- "movl %%esp, %0\n"
- "movl %%ebx, %%esp\n"
- : "=m"(proc0->intr_ctx.registers.esp)
- : "i"(KSTACK_TOP), "i"(KCODE_SEG), "r"(proc0->intr_ctx.eip)
- : "%ebx", "memory");
+ struct exec_param* execp =
+ (struct exec_param*)(KSTACK_TOP - sizeof(struct exec_param));
+
+ *execp = (struct exec_param){ .cs = KCODE_SEG,
+ .eip = (void*)__proc0,
+ .ss = KDATA_SEG,
+ .eflags = cpu_reflags() };
+ proc0->intr_ctx.execp = execp;
// 加载x87默认配置
asm volatile("fninit\n"
extern void my_dummy();
static char dummy_stack[DUMMY_STACK_SIZE] __attribute__((aligned(16)));
- // memset to 0
- dummy_proc = (struct proc_info){};
- dummy_proc.intr_ctx = (isr_param){
- .registers = { .ds = KDATA_SEG,
- .es = KDATA_SEG,
- .fs = KDATA_SEG,
- .gs = KDATA_SEG,
- .esp = (void*)dummy_stack + DUMMY_STACK_SIZE - 20 },
+ struct exec_param* execp =
+ (void*)dummy_stack + DUMMY_STACK_SIZE - sizeof(struct exec_param);
+
+ *execp = (struct exec_param){
.cs = KCODE_SEG,
+ .eflags = cpu_reflags() | 0x0200,
.eip = (void*)my_dummy,
.ss = KDATA_SEG,
- .eflags = cpu_reflags() | 0x0200
};
- *(u32_t*)(&dummy_stack[DUMMY_STACK_SIZE - 4]) = dummy_proc.intr_ctx.eflags;
- *(u32_t*)(&dummy_stack[DUMMY_STACK_SIZE - 8]) = KCODE_SEG;
- *(u32_t*)(&dummy_stack[DUMMY_STACK_SIZE - 12]) = dummy_proc.intr_ctx.eip;
+ // memset to 0
+ dummy_proc = (struct proc_info){};
+ dummy_proc.intr_ctx = (isr_param){ .registers = { .ds = KDATA_SEG,
+ .es = KDATA_SEG,
+ .fs = KDATA_SEG,
+ .gs = KDATA_SEG },
+ .execp = execp };
dummy_proc.page_table = cpu_rcr3();
dummy_proc.state = PS_READY;
由于这中间没有进行地址空间的交换,所以第二次跳转使用的是同一个内核栈,而之前默认tss.esp0的值是永远指向最顶部
这样一来就有可能会覆盖更早的上下文信息(比如嵌套的信号捕获函数)
*/
- tss_update_esp(proc->intr_ctx.registers.esp);
+ tss_update_esp(proc->intr_ctx.esp);
apic_done_servicing();