movw %ax, %fs
movw %ax, %gs
- /* switch to the kernel page directory, if we're not already using it */
- movl (_kernel_cr3), %eax
+ /* push the current page directory onto the stack */
movl %cr3, %ebx
+ pushl %ebx
+
+ /* switch to the kernel pagedir, if necessary */
+ movl (_kernel_cr3), %eax
cmpl %eax, %ebx
je _already_in_kernel
-
movl %eax, %cr3
/*
/* we can now use the stack */
_already_in_kernel:
- cmp $EXC_MAX, 36(%esp)
+ cmp $EXC_MAX, 40(%esp)
jl 0f
- cmp $INT_MAX, 36(%esp)
+ cmp $INT_MAX, 40(%esp)
jl 1f
call _sys_handle
call _int_handle
_int_restore:
+ /* pop the page directory from the stack */
+ popl %eax
+
+ /*
+ * Check if the destination of the iret is in the kernel or user-space.
+ * In the former case, we can skip rebasing the stack and restoring the
+ * page directory.
+ */
+ cmpl %eax, (_kernel_cr3)
+ je _return_to_kernel
+
+ /* switch page directory first since we'll need the register */
+ movl %eax, %cr3
+
+ cpuidx %ecx
+ movl $_cpu, %eax
+0: subl $1, %ecx
+ js 1f
+ addl $CPU_SIZE, %eax
+ jmp 0b
+
+ /* rebase the stack pointers to the task's page directory */
+1: movl OFFSET_CPU_CTASK(%eax), %eax
+
+ subl OFFSET_TASK_KSTACK(%eax), %esp
+ addl $CONFIG_KERNEL_STACK_BASE, %esp
+ subl OFFSET_TASK_KSTACK(%eax), %ebp
+ addl $CONFIG_KERNEL_STACK_BASE, %ebp
+
+_return_to_kernel:
popl %eax
movw %ax, %ds
movw %ax, %es
* task = 4(%esp)
*/
- movl 4(%esp), %edi
+#define ARG_PRIV 24
+#define ARG_ESP 20
+#define ARG_ESP0 16
+#define ARG_EIP 12
+#define ARG_CR3 8
+#define ARG_TASK 4
+
+ movl ARG_TASK(%esp), %edi
/* store cr3 in task structure */
- movl 8(%esp), %eax
+ movl ARG_CR3(%esp), %eax
movl %eax, OFFSET_TASK_CR3(%edi)
/* store privilege level in task structure */
- movl 24(%esp), %eax
+ movl ARG_PRIV(%esp), %eax
movl %eax, OFFSET_TASK_PRIVL(%edi)
/* calculate stack start (since it grows down) */
- movl 16(%esp), %eax
+ movl ARG_ESP0(%esp), %eax
/*
* We will use _int_restore (the lower half of the interrupt handler)
* iret instruction. This is why we need the following stack layout.
*
* +--------+
- * | SS | 60(%eax) \
- * | ESP | 56(%eax) |
- * | EFLAGS | 52(%eax) > for iret
- * | CS | 48(%eax) |
- * | EIP | 44(%eax) /
+ * | SS | 64(%eax) \
+ * | ESP | 60(%eax) |
+ * | EFLAGS | 56(%eax) > for iret
+ * | CS | 52(%eax) |
+ * | EIP | 48(%eax) /
* +--------+
- * | error | 40(%eax) \ error pushed by _int_entryNN
- * | intr | 36(%eax) / int number pushed by _int_entryNN
+ * | error | 44(%eax) \ error pushed by _int_entryNN
+ * | intr | 40(%eax) / int number pushed by _int_entryNN
* +--------+
- * | EDI | 32(%eax) \
- * | ESI | 28(%eax) |
- * | EBP | 24(%eax) |
- * | unused | 20(%eax) |
- * | EBX | 16(%eax) > for popa
- * | EDX | 12(%eax) |
- * | ECX | 8(%eax) |
- * | EAX | 4(%eax) /
+ * | EDI | 36(%eax) \
+ * | ESI | 32(%eax) |
+ * | EBP | 28(%eax) |
+ * | unused | 24(%eax) |
+ * | EBX | 20(%eax) > for popa
+ * | EDX | 16(%eax) |
+ * | ECX | 12(%eax) |
+ * | EAX | 8(%eax) /
* +--------+
- * | DS | (%eax) > data segment registers
+ * | DS | 4(%eax) > data segment registers
+ * | CR3 | (%eax) > page directory base
* +--------+
*
- * In total, there are 16 dwords to be put on the stack, so we will
- * start by adding 64 to %eax and then use the addresses above.
+ * In total, there are 17 dwords to be put on the stack, so we will
+ * start by adding 68 to %eax and then use the addresses above.
*/
- subl $64, %eax
+#define STK_SS 64
+#define STK_ESP0 60
+#define STK_EFLAGS 56
+#define STK_CS 52
+#define STK_EIP 48
+#define STK_ERROR 44
+#define STK_INTR 40
+#define STK_EDI 36
+#define STK_ESI 32
+#define STK_EBP 28
+#define STK_ESP 24
+#define STK_EBX 20
+#define STK_EDX 16
+#define STK_ECX 12
+#define STK_EAX 8
+#define STK_DS 4
+#define STK_CR3 0
+
+ subl $68, %eax
/* calculate DS from priv and put it on the new stack */
- movl 24(%esp), %ecx
+ movl ARG_PRIV(%esp), %ecx
shll $4, %ecx
addl $16, %ecx
- orl 24(%esp), %ecx
- movl %ecx, (%eax)
+ orl ARG_PRIV(%esp), %ecx
+ movl %ecx, STK_DS(%eax)
/* Clear general purpose registers (and error/intr) */
- movl $0, 4(%eax)
- movl $0, 8(%eax)
- movl $0, 12(%eax)
- movl $0, 16(%eax)
- movl $0, 20(%eax)
- movl $0, 24(%eax)
- movl $0, 28(%eax)
- movl $0, 32(%eax)
- movl $0, 36(%eax)
- movl $0, 40(%eax)
+ movl $0, STK_EAX(%eax)
+ movl $0, STK_ECX(%eax)
+ movl $0, STK_EDX(%eax)
+ movl $0, STK_EBX(%eax)
+ movl $0, STK_ESP(%eax)
+ movl $0, STK_EBP(%eax)
+ movl $0, STK_ESI(%eax)
+ movl $0, STK_EDI(%eax)
+ movl $0, STK_INTR(%eax)
+ movl $0, STK_ERROR(%eax)
/* put EIP on the new stack */
- movl 12(%esp), %ecx
- movl %ecx, 44(%eax)
+ movl ARG_EIP(%esp), %ecx
+ movl %ecx, STK_EIP(%eax)
/* calculate CS from priv and put it on the new stack */
- movl 24(%esp), %ecx
+ movl ARG_PRIV(%esp), %ecx
shll $4, %ecx
addl $8, %ecx
- orl 24(%esp), %ecx
- movl %ecx, 48(%eax)
+ orl ARG_PRIV(%esp), %ecx
+ movl %ecx, STK_CS(%eax)
/* put EFLAGS on the new stack */
- movl $USER_EFLAGS, 52(%eax)
+ movl $USER_EFLAGS, STK_EFLAGS(%eax)
/* put the stack pointer on the stack */
- movl 20(%esp), %ecx
- movl %ecx, 56(%eax)
+ movl ARG_ESP(%esp), %ecx
+ movl %ecx, STK_ESP0(%eax)
/* put the stack segment on the new stack - use the value from DS */
- movl (%eax), %ecx
- movl %ecx, 60(%eax)
+ movl STK_DS(%eax), %ecx
+ movl %ecx, STK_SS(%eax)
+
+ /* put cr3 onto the stack */
+ movl ARG_CR3(%esp), %ecx
+ movl %ecx, STK_CR3(%eax)
/* put EAX into the task structure - task pointer is still in EDI */
movl %eax, OFFSET_TASK_ESP0(%edi)
1: movl OFFSET_CPU_CTASK(%eax), %esi
movl 4(%esp), %edi
- cmpl %esi, %edi
- jne 2f
- /* FIXME: Return -EALREADY instead */
- movl $-1, %eax
- ret
+ /* update the task pointer */
+ movl %edi, OFFSET_CPU_CTASK(%eax)
+
+ /*
+ * Get the address of the task's ESP0 for its own page directory
+ * and store it in the current CPU's TSS
+ */
+ movl OFFSET_TASK_ESP0(%edi), %ecx
+ subl OFFSET_TASK_KSTACK(%edi), %ecx
+ addl $CONFIG_KERNEL_STACK_BASE, %ecx
- /* put the task's ESP0 into the TSS */
-2: movl OFFSET_TASK_ESP0(%edi), %ecx
movl %ecx, CPU_ESP0(%eax)
movl $KERNEL_DATA, CPU_SS0(%eax)
movl %ecx, CPU_GS(%eax)
movl %ecx, CPU_SS(%eax)
- movl OFFSET_TASK_CR3(%edi), %ecx
+ /* write ESP to the previous TCB, if any */
+ test %esi, %esi
+ jz 2f
+ movl %esp, OFFSET_TASK_ESP0(%esi)
/*
* Clear interrupts, since we won't have a valid stack until the
* iret instruction in _int_restore is executed
*/
- cli
+2: cli
- /* switch to the task's page directory since the kernel uses a separate one */
- movl %ecx, %cr3
-
- movl %edi, OFFSET_CPU_CTASK(%eax)
-
- /* write ESP to the previous TCB, if any */
- test %esi, %esi
- jz 3f
- movl %esp, OFFSET_TASK_ESP0(%esi)
-
- /* load new ESP */
-3: movl OFFSET_TASK_ESP0(%edi), %esp
+ /*
+ * Load ESP0 from the task structure, but don't adjust it since we need the
+ * linear address while we're in the context of the kernel
+ */
+ movl OFFSET_TASK_ESP0(%edi), %esp
/*
* If this is a new task, we have to use _int_restore to return,
movl OFFSET_TASK_STATE(%edi), %eax
test %eax, %eax
- jz 4f
+ jz 3f
xorl %eax, %eax
/*
*/
ret
-4: movl $1, OFFSET_TASK_STATE(%edi)
+3: movl $1, OFFSET_TASK_STATE(%edi)
/*
* In the previous line, the task state is set to TASK_STATE_RUNNING.
* This is the only place where a transition from NEW to any other state