rink.nu / projects / ananas / kernel/arch/i386/interrupts.S@1374b6733ab0
kernel/arch/i386/interrupts.S
author Rink Springer <rink@rink.nu>
Mon Jan 23 08:57:24 2012 +0100 (3 months ago ago)
changeset 1334 1374b6733ab0
parent 1331 17f6e1bc8a69
child 1342 7c4f300504ea
permissions -rw-r--r--
i386: Remove two exported symbols that don't exist anymore
     1 /*
     2  * Low-level assembly code to pass an interrupt to a higher-level handler.
     3  */
     4 .text
     5 .globl exception0, exception1, exception2, exception3, exception4, exception5
     6 .globl exception6, exception7, exception8, exception9, exception10, exception11
     7 .globl exception12, exception13, exception14, exception16, exception17
     8 .globl exception18, exception19
     9 .globl irq0, irq1, irq2, irq3, irq4, irq5, irq6, irq7, irq8, irq9
    10 .globl irq10, irq11, irq12, irq13, irq14, irq15
    11 .globl syscall_int
    12 .globl clone_return
    13 .globl userland_trampoline, kthread_trampoline
    15 #include "options.h"
    16 #include "machine/param.h"
    17 #include "machine/vm.h"
    18 #include "asmsyms.h"
    20 #define SANITY_CHECKS
    22 #define SAVE_REGISTERS \
    23 	movl	%eax, SF_EAX(%esp); \
    24 	movl	%ebx, SF_EBX(%esp); \
    25 	movl	%ecx, SF_ECX(%esp); \
    26 	movl	%edx, SF_EDX(%esp); \
    27 	movl	%ebp, SF_EBP(%esp); \
    28 	movl	%esp, SF_ESP(%esp); \
    29 	movl	%edi, SF_EDI(%esp); \
    30 	movl	%esi, SF_ESI(%esp);
    32 #define SAVE_SEGS \
    33 	xorl	%eax, %eax; \
    34 	movw	%ds, %ax; \
    35 	movl	%eax, SF_DS(%esp); \
    36 	movw	%es, %ax; \
    37 	movl	%eax, SF_ES(%esp); \
    38 	movw	%fs, %ax; \
    39 	movl	%eax, SF_FS(%esp); \
    40 	movw	%gs, %ax; \
    41 	movl	%eax, SF_GS(%esp);
    43 #define RESTORE_REGISTERS \
    44 	movl	SF_EAX(%esp), %eax; \
    45 	movl	SF_EBX(%esp), %ebx; \
    46 	movl	SF_ECX(%esp), %ecx; \
    47 	movl	SF_EDX(%esp), %edx; \
    48 	movl	SF_EBP(%esp), %ebp; \
    49 	/* movl	SF_ESP(%esp), %esp; */ \
    50 	movl	SF_EDI(%esp), %edi; \
    51 	movl	SF_ESI(%esp), %esi;
    53 #define RESTORE_SEGS \
    54 	movl	SF_DS(%esp), %eax; \
    55 	movw	%ax, %ds; \
    56 	movl	SF_ES(%esp), %eax; \
    57 	movw	%ax, %es; \
    58 	movl	SF_FS(%esp), %eax; \
    59 	movw	%ax, %fs; \
    60 	movl	SF_GS(%esp), %eax; \
    61 	movw	%ax, %gs;
    63 do_irq:
    64 	SAVE_REGISTERS
    65 	SAVE_SEGS
    67 	/* Set up kernel data */
    68 	movl	$GDT_SEL_KERNEL_DATA, %eax
    69 	movw	%ax, %ds
    70 	movw	%ax, %es
    72 	/* Ensure per-cpu stuff works */
    73 	movl	$GDT_SEL_KERNEL_PCPU, %eax
    74 	movw	%ax, %fs
    76 	/* Increment the nested IRQ count */
    77 	incl	%fs:(PCPU_NESTEDIRQ)
    79 	/* Restore the interrupt flag */
    80 	movl	SF_EFLAGS(%esp), %eax
    81 	testl	$0x200, %eax
    82 	jz	1f
    84 	sti
    86 1:	/* Call the interrupt handler */
    87 	pushl	%esp
    88 	call	interrupt_handler
    89 	addl	$4, %esp
    91 	/* Restore previous state */
    92 	RESTORE_SEGS
    93 	RESTORE_REGISTERS
    94 	addl	$SF_EIP, %esp
    95 	iret
    97 do_exception:
    98 	SAVE_REGISTERS
    99 	SAVE_SEGS
   101 	/* Set up kernel data */
   102 	movl	$GDT_SEL_KERNEL_DATA, %eax
   103 	movw	%ax, %ds
   104 	movw	%ax, %es
   106 	/* Ensure per-cpu stuff works */
   107 	movl	$GDT_SEL_KERNEL_PCPU, %eax
   108 	movw	%ax, %fs
   110 	/* Call the exception handler */
   111 	pushl	%esp
   112 	call	exception_handler
   113 	addl	$4, %esp
   115 	/* Restore previous state */
   116 	RESTORE_SEGS
   117 	RESTORE_REGISTERS
   118 	addl	$SF_EIP, %esp
   119 	iret
   121 /*
   122  * There exist two versions of exceptions: those with an error code, and those
   123  * without one. Our handler code expects to be called with an error code, so
   124  * we add a fake zero one if needed for those exceptions that don't have one.
   125  */
   126 #define EXCEPTION_HANDLER_ERRORCODE(num) \
   127 exception ## num: \
   128 	subl	$SF_ERRNUM, %esp; \
   129 	movl	$num, SF_TRAPNO(%esp); \
   130 	jmp	do_exception
   132 #define EXCEPTION_HANDLER(num) \
   133 exception ## num: \
   134 	subl	$SF_EIP, %esp; \
   135 	movl	$num, SF_TRAPNO(%esp); \
   136 	movl	$0, SF_ERRNUM(%esp); \
   137 	jmp	do_exception
   139 /* IRQ handlers are a lot simpler: they come in a single easy flavour */
   140 #define IRQ_HANDLER(num) \
   141 irq ## num: \
   142 	subl	$SF_EIP, %esp; \
   143 	movl	$num, SF_TRAPNO(%esp); \
   144 	jmp	do_irq
   146 /*
   147  * System call interrupt; system call number should be placed in %eax, all
   148  * arguments are expected to be placed on the stack.  Note that we only
   149  * preserve what's needed by the System V ABI because that's what everyone
   150  * seems to use anyway.
   151  */
   152 syscall_int:
   153 	/*
   154 	 * System V ABI for Intel386 Architecture says we only have to
   155 	 * preserve %ebx, %esi, %edi, %ebp and %esp (the latter is done
   156 	 * implicitely by the hardware).
   157 	 */
   158 	pushl	%ebp
   159 	pushl	%ebx
   160 	pushl	%esi
   161 	pushl	%edi
   163 	/* Save segment registers as well; we only use ds/es/fs */
   164 	pushl	%ds
   165 	pushl	%es
   166 	pushl	%fs
   168 #ifdef SANITY_CHECKS
   169 	/*
   170 	 * Sanity check: a system call must be made from userland, thus %ds
   171 	 * must be userland version
   172 	 */
   173 	movw	%ds, %bx
   174 	cmpw	$(GDT_SEL_USER_DATA + 3), %bx
   175 	je	syscall_start_dsok
   177 	int 	$3
   179 syscall_start_dsok:
   180 	/* Sanity check: interrupts must be enabled when entering */
   181 	movl	36(%esp), %ebx
   182 	andl	$0x200, %ebx
   183 	orl	%ebx, %ebx
   184 	jne	syscall_start_ifok
   186 	int	$3
   188 syscall_start_ifok:
   189 #endif
   191 	/*
   192 	 * Switch to kernel segment register context (ds/es/fs); this ensures
   193 	 * the stores below will work (%esi uses %ds implicitely)
   194 	 */
   195 	movw	$GDT_SEL_KERNEL_DATA, %bx
   196 	movw	%bx, %ds
   197 	movw	%bx, %es
   198 	movw	$GDT_SEL_KERNEL_PCPU, %bx
   199 	movw	%bx, %fs
   201 	/*
   202 	 * Fetch the caller's stack pointer; this will be saved at our
   203 	 * current stack - but note that we have already created a
   204 	 * stackframe, so we just use that as base.
   205 	 *
   206 	 * The 40 comes from stored fs es ds edi esi ebx ebp eip cs flg esp ss
   207 	 * as they occur on offsets 0  4  8  12  16  20  24  28 32  36  40  44
   208 	 */
   209 	movl 40(%esp), %esi
   211 	/*
   212 	 * Set up a pointer to the structure, and copy 6 arguments
   213 	 * in place. Note that the stack grows backward, so we need
   214 	 * to place them in reverse order.
   215 	 */
   216 	pushl	20(%esi)
   217 	pushl	16(%esi)
   218 	pushl	12(%esi)
   219 	pushl	 8(%esi)
   220 	pushl	 4(%esi)
   221 	pushl	%eax
   223 	/*
   224 	 * Invoke the generic syscall hander; return values will be passed in
   225 	 * %eax, so we cannot thrash that. Note that our argument is pushed
   226 	 * beforehand, which simply points to the syscall values.
   227 	 */
   228 	pushl	%esp
   229 	call	syscall
   230 	addl	$28, %esp	/* 6 regs + esp */
   232 syscall_return:
   234 	/* Restore registers */
   235 	popl	%fs
   236 	popl	%es
   237 	popl	%ds
   239 #ifdef SANITY_CHECKS
   240 	/*
   241 	 * Sanity check: we must have restored an userland ds; if we don't,
   242 	 * iret will reset %ds to null because it can't be accessed in ring 3,
   243 	 * leading to hard-to-debug problems. Best to verify it here.
   244 	 */
   245 	movw	%ds, %bx
   246 	cmpw	$(GDT_SEL_USER_DATA + 3), %bx
   247 	je	syscall_end_dsok
   249 	int	$3
   251 syscall_end_dsok:
   252 	/* Sanity check: interrupts must be enabled when a syscall is done */
   253 	movl	24(%esp), %ebx
   254 	andl	$0x200, %ebx
   255 	orl	%ebx, %ebx
   256 	jne	syscall_end_ifok
   258 	int	$3
   260 syscall_end_ifok:
   261 #endif
   263 	popl	%edi
   264 	popl	%esi
   265 	popl	%ebx
   266 	popl	%ebp
   267 	iret
   269 clone_return:
   270 	/*
   271 	 * Once here, the to-be-cloned thread is scheduled to be
   272 	 * resumed. We are returning to a new thread, so we'll
   273 	 * need to restore the context exactly as it were when
   274 	 * the thread did the syscall.
   275 	 *
   276 	 * However, the top of the kernel stack will still have
   277 	 * the stackframe set up by our syscall routine (as there
   278 	 * is no other way to do a clone) - we can use that
   279 	 * information to restore the caller.
   280 	 *
   281 	 * Note that the ABI dictates that %eax is used to return
   282 	 * a value to the new thread, so we'll have to restore it.
   283 	 */
   285 	/* Rewind the stack as created by syscall_int */
   286 	movl	%fs:(PCPU_CURTHREAD), %ebx
   287 	movl	T_ESP0(%ebx), %esp
   288 	subl	$48, %esp
   290 	/* Fetch return value */
   291 	movl	T_ARG1(%ebx), %eax
   293 	/* And terminate the system call */
   294 	jmp	syscall_return
   296 #ifdef OPTION_SMP
   297 spurious_irq:
   298 	iret
   299 #endif
   301 /* Now we just need to list the exception handlers */
   302 EXCEPTION_HANDLER(0)
   303 EXCEPTION_HANDLER(1)
   304 EXCEPTION_HANDLER(2)
   305 EXCEPTION_HANDLER(3)
   306 EXCEPTION_HANDLER(4)
   307 EXCEPTION_HANDLER(5)
   308 EXCEPTION_HANDLER(6)
   309 EXCEPTION_HANDLER(7)
   310 EXCEPTION_HANDLER_ERRORCODE(8)
   311 EXCEPTION_HANDLER(9)
   312 EXCEPTION_HANDLER_ERRORCODE(10)
   313 EXCEPTION_HANDLER_ERRORCODE(11)
   314 EXCEPTION_HANDLER_ERRORCODE(12)
   315 EXCEPTION_HANDLER_ERRORCODE(13)
   316 EXCEPTION_HANDLER_ERRORCODE(14)
   317 EXCEPTION_HANDLER(16)
   318 EXCEPTION_HANDLER_ERRORCODE(17)
   319 EXCEPTION_HANDLER(18)
   320 EXCEPTION_HANDLER(19)
   322 /* ...and the IRQ handlers */
   323 IRQ_HANDLER(0)
   324 IRQ_HANDLER(1)
   325 IRQ_HANDLER(2)
   326 IRQ_HANDLER(3)
   327 IRQ_HANDLER(4)
   328 IRQ_HANDLER(5)
   329 IRQ_HANDLER(6)
   330 IRQ_HANDLER(7)
   331 IRQ_HANDLER(8)
   332 IRQ_HANDLER(9)
   333 IRQ_HANDLER(10)
   334 IRQ_HANDLER(11)
   335 IRQ_HANDLER(12)
   336 IRQ_HANDLER(13)
   337 IRQ_HANDLER(14)
   338 IRQ_HANDLER(15)
   340 kthread_trampoline:
   341 	/* Fetch arguments; arg1 is the %eip and arg2 is the argument */
   342 	movl	%fs:(PCPU_CURTHREAD), %ebx
   343 	movl	T_ARG1(%ebx), %eax		/* eax = eip */
   344 	pushl	T_ARG2(%ebx)
   346 	/* Call the kthread code with interrupts enabled */
   347 	pushl	$0x200
   348 	pushl	$GDT_SEL_KERNEL_CODE
   349 	pushl	%eax
   350 	iret
   352 userland_trampoline:
   353 	/* Fetch arguments; arg1 is the %eip and arg2 is the argument */
   354 	movl	%fs:(PCPU_CURTHREAD), %ebx
   355 	movl	T_ARG1(%ebx), %eax		/* eax = eip */
   356 	movl	T_ARG2(%ebx), %esi		/* esi = arg */
   358 	/* Set up %ds/%es to point to the userland segments */
   359 	movl	$(GDT_SEL_USER_DATA + 3), %edx
   360 	movl	%dx, %ds
   361 	movl	%dx, %es
   363 	pushl	$(GDT_SEL_USER_DATA + 3)			/* ss */
   364 	pushl	$(USERLAND_STACK_ADDR + THREAD_STACK_SIZE)	/* esp */
   365 	pushl	$0x200					/* eflags */
   366 	pushl	$(GDT_SEL_USER_CODE + 3)		/* cs */
   367 	pushl	%eax					/* eip */
   368 	iret
Powered by FreeBSD, PostgreSQL and Perl
© 2001 - 2011 Rink Springer