* along with Corax. If not, see <http://www.gnu.org/licenses/>.
*/
+#define __ASSEMBLY_SOURCE
+
#include <config.h>
#include "defs.h"
.global _int_entry_common
.global _int_restore
+.extern _cpu
+.extern _kernel_cr3
+
.extern _exc_handle
.extern _int_handle
.extern _sys_handle
movw %ax, %fs
movw %ax, %gs
+ /* switch to the kernel page directory, if we're not already using it */
+ movl (_kernel_cr3), %eax
+ movl %cr3, %ebx
+ cmpl %eax, %ebx
+ je _already_in_kernel
+
+ movl %eax, %cr3
+
+ /*
+ * When the privilege level changes during an interrupt, the kernel
+ * automatically performs a stack switch, however it does not switch page
+ * directories, meaning we have no choice but to map the per-task kernel
+ * stack into the task's page directory and save the context there. We
+ * then manually switch to the kernel page directory. However, the task's
+ * kernel stack is at a different location in the kernel's page directory
+ * (i.e. its linear address), so we have to adjust the stack pointer before
+ * we can use the stack.
+ */
+
+ cpuidx %ecx
+ movl $_cpu, %eax
+0: subl $1, %ecx
+ js 1f
+ addl $CPU_SIZE, %eax
+ jmp 0b
+
+ /* reduce esp to the offset into the stack, then add the linear stack base */
+1: movl OFFSET_CPU_CTASK(%eax), %eax
+ subl $CONFIG_KERNEL_STACK_BASE, %esp
+ addl OFFSET_TASK_KSTACK(%eax), %esp
+
+ /* do the same with ebp */
+ subl $CONFIG_KERNEL_STACK_BASE, %ebp
+ addl OFFSET_TASK_KSTACK(%eax), %ebp
+
+ /* we can now use the stack */
+
+_already_in_kernel:
cmp $EXC_MAX, 36(%esp)
jl 0f
proc->p_tasks->t_sp = (u32_t)(CONFIG_KERNEL_STACK_BASE +
((u32_t)proc->p_tasks->t_sp - (u32_t)kstack));
+ proc->p_tasks->t_kstack = kstack;
proc->p_tasks->t_tslice = 50;
proc->p_tasks->t_rslice = 50;