To support a GDB stub, it will be necessary to trap various exceptions which will be used to implement breakpoints, single stepping, etc. BUG=None TEST=Built and booted on Link with hooks installed and saw that they triggered when exceptions occurred. Built and booted on nyan. BRANCH=None Original-Change-Id: Iab659365864a3055159a50b8f6e5c44290d3ba2b Original-Signed-off-by: Gabe Black <gabeblack@google.com> Original-Reviewed-on: https://chromium-review.googlesource.com/179602 Original-Reviewed-by: Gabe Black <gabeblack@chromium.org> Original-Tested-by: Gabe Black <gabeblack@chromium.org> Original-Commit-Queue: Gabe Black <gabeblack@chromium.org> (cherry picked from commit 8db0897b1ddad600e247cb4df147c757a8187626) Signed-off-by: Marc Jones <marc.jones@se-eng.com> Change-Id: I5e7f724b99988cd259909dd3bd01166fa52317ec Reviewed-on: http://review.coreboot.org/7656 Tested-by: build bot (Jenkins) Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net> Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
		
			
				
	
	
		
			297 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			297 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| /*
 | |
|  * This file is part of the libpayload project.
 | |
|  *
 | |
|  * Copyright 2013 Google Inc.
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions
 | |
|  * are met:
 | |
|  * 1. Redistributions of source code must retain the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer.
 | |
|  * 2. Redistributions in binary form must reproduce the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer in the
 | |
|  *    documentation and/or other materials provided with the distribution.
 | |
|  * 3. The name of the author may not be used to endorse or promote products
 | |
|  *    derived from this software without specific prior written permission.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 | |
|  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | |
|  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | |
|  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 | |
|  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | |
|  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | |
|  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | |
|  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | |
|  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | |
|  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | |
|  * SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| 	.align 4
 | |
| 	.global exception_stack_end
 | |
| exception_stack_end:
 | |
| 	.long 0
 | |
| 	.global exception_handler_state_handoff
 | |
| exception_handler_state_handoff:
 | |
| 	.long 0
 | |
| 
 | |
| /* Some temporary variables which are used while saving exception state. */
 | |
| vector:
 | |
| 	.long 0
 | |
| error_code:
 | |
| 	.long 0
 | |
| old_esp:
 | |
| 	.long 0
 | |
| old_eax:
 | |
| 	.long 0
 | |
| 
 | |
| 	.align 8
 | |
| 
 | |
| /*
 | |
|  * Each exception vector has a small stub associated with it which sets aside
 | |
|  * the error code, if any, records which vector we entered from, and calls
 | |
|  * the common exception entry point. Some exceptions have error codes and some
 | |
|  * don't, so we have a macro for each type.
 | |
|  */
 | |
| 
 | |
| 	.macro stub num
 | |
| exception_stub_\num:
 | |
| 	movl	$0, error_code
 | |
| 	movl	$\num, vector
 | |
| 	jmp	exception_common
 | |
| 	.endm
 | |
| 
 | |
| 	.macro stub_err num
 | |
| exception_stub_\num:
 | |
| 	popl	error_code
 | |
| 	movl	$\num, vector
 | |
| 	jmp	exception_common
 | |
| 	.endm
 | |
| 
 | |
| 	stub 0
 | |
| 	stub 1
 | |
| 	stub 2
 | |
| 	stub 3
 | |
| 	stub 4
 | |
| 	stub 5
 | |
| 	stub 6
 | |
| 	stub 7
 | |
| 	stub_err 8
 | |
| 	stub 9
 | |
| 	stub_err 10
 | |
| 	stub_err 11
 | |
| 	stub_err 12
 | |
| 	stub_err 13
 | |
| 	stub_err 14
 | |
| 	stub 15
 | |
| 	stub 16
 | |
| 	stub_err 17
 | |
| 	stub 18
 | |
| 	stub 19
 | |
| 	stub 20
 | |
| 	stub 21
 | |
| 	stub 22
 | |
| 	stub 23
 | |
| 	stub 24
 | |
| 	stub 25
 | |
| 	stub 26
 | |
| 	stub 27
 | |
| 	stub 28
 | |
| 	stub 29
 | |
| 	stub_err 30
 | |
| 	stub 31
 | |
| 
 | |
| exception_common:
 | |
| 	/*
 | |
| 	 * Save off the stack pointer and old eax value and install the
 | |
| 	 * exception stack. eax points to the old stack which has the
 | |
| 	 * exception ip, cs, and flags.
 | |
| 	 */
 | |
| 	mov	%esp, old_esp
 | |
| 	addl	$12, old_esp
 | |
| 	mov	%eax, old_eax
 | |
| 	mov	%esp, %eax
 | |
| 	mov	exception_stack_end, %esp
 | |
| 
 | |
| 	/*
 | |
| 	 * Push values onto the top of the exception stack to form an
 | |
| 	 * exception state structure.
 | |
| 	 */
 | |
| 	pushl	vector
 | |
| 	pushl	error_code
 | |
| 	pushl	%gs
 | |
| 	pushl	%fs
 | |
| 	pushl	%es
 | |
| 	pushl	%ds
 | |
| 	pushl	%ss
 | |
| 	pushl	4(%eax)
 | |
| 	pushl	8(%eax)
 | |
| 	pushl	(%eax)
 | |
| 	pushl	%edi
 | |
| 	pushl	%esi
 | |
| 	pushl	%ebp
 | |
| 	pushl	old_esp
 | |
| 	pushl	%ebx
 | |
| 	pushl	%edx
 | |
| 	pushl	%ecx
 | |
| 	pushl	old_eax
 | |
| 
 | |
| 	/*
 | |
| 	 * Call the C exception handler. It will find the exception state
 | |
| 	 * using the exception_handler_state_handoff global pointer. Not
 | |
| 	 * passing parameters means we don't have to worry about what ABI
 | |
| 	 * is being used.
 | |
| 	 */
 | |
| 	mov	%esp, exception_handler_state_handoff
 | |
| 	call	exception_dispatch
 | |
| 
 | |
| 	/*
 | |
| 	 * Restore state from the exception state structure, including any
 | |
| 	 * changes that might have been made.
 | |
| 	 */
 | |
| 	popl	old_eax
 | |
| 	popl	%ecx
 | |
| 	popl	%edx
 | |
| 	popl	%ebx
 | |
| 	popl	old_esp
 | |
| 
 | |
| 	mov	old_esp, %eax
 | |
| 	subl	$12, %eax
 | |
| 
 | |
| 	popl	%ebp
 | |
| 	popl	%esi
 | |
| 	popl	%edi
 | |
| 	popl	(%eax)
 | |
| 	popl	8(%eax)
 | |
| 	popl	4(%eax)
 | |
| 	popl	%ss
 | |
| 	popl	%ds
 | |
| 	popl	%es
 | |
| 	popl	%fs
 | |
| 	popl	%gs
 | |
| 
 | |
| 	mov	%eax, %esp
 | |
| 	mov	old_eax, %eax
 | |
| 
 | |
| 	/* Return from the exception. */
 | |
| 	iretl
 | |
| 
 | |
| /*
 | |
|  * We need segment selectors for the IDT, so we need to know where things are
 | |
|  * in the GDT. We set one up here which is pretty standard and largely copied
 | |
|  * from coreboot.
 | |
|  */
 | |
| 	.align 8
 | |
| gdt:
 | |
| 	/* selgdt 0, unused */
 | |
| 	.word 0x0000, 0x0000
 | |
| 	.byte 0x00, 0x00, 0x00, 0x00
 | |
| 
 | |
| 	/* selgdt 8, unused */
 | |
| 	.word 0x0000, 0x0000
 | |
| 	.byte 0x00, 0x00, 0x00, 0x00
 | |
| 
 | |
| 	/* selgdt 0x10, flat 4GB code segment */
 | |
|         .word 0xffff, 0x0000
 | |
| 	.byte 0x00, 0x9b, 0xcf, 0x00
 | |
| 
 | |
| 	/* selgdt 0x18, flat 4GB data segment */
 | |
| 	.word 0xffff, 0x0000
 | |
| 	.byte 0x00, 0x93, 0xcf, 0x00
 | |
| gdt_end:
 | |
| 
 | |
| /* GDT pointer for use with lgdt */
 | |
| gdt_ptr:
 | |
| 	.word	gdt_end - gdt - 1
 | |
| 	.long	gdt
 | |
| 
 | |
| 	/*
 | |
| 	 * Record the target and construct the actual entry at init time. This
 | |
| 	 * is necessary because the linker doesn't want to construct the entry
 | |
| 	 * for us.
 | |
| 	 */
 | |
| 	.macro interrupt_gate target
 | |
| 	.long \target
 | |
| 	.long \target
 | |
| 	.endm
 | |
| 
 | |
| 	.align 8
 | |
| 	.global	idt
 | |
| idt:
 | |
| 	interrupt_gate exception_stub_0
 | |
| 	interrupt_gate exception_stub_1
 | |
| 	interrupt_gate exception_stub_2
 | |
| 	interrupt_gate exception_stub_3
 | |
| 	interrupt_gate exception_stub_4
 | |
| 	interrupt_gate exception_stub_5
 | |
| 	interrupt_gate exception_stub_6
 | |
| 	interrupt_gate exception_stub_7
 | |
| 	interrupt_gate exception_stub_8
 | |
| 	interrupt_gate exception_stub_9
 | |
| 	interrupt_gate exception_stub_10
 | |
| 	interrupt_gate exception_stub_11
 | |
| 	interrupt_gate exception_stub_12
 | |
| 	interrupt_gate exception_stub_13
 | |
| 	interrupt_gate exception_stub_14
 | |
| 	interrupt_gate exception_stub_15
 | |
| 	interrupt_gate exception_stub_16
 | |
| 	interrupt_gate exception_stub_17
 | |
| 	interrupt_gate exception_stub_18
 | |
| 	interrupt_gate exception_stub_19
 | |
| 	interrupt_gate exception_stub_20
 | |
| 	interrupt_gate exception_stub_21
 | |
| 	interrupt_gate exception_stub_22
 | |
| 	interrupt_gate exception_stub_23
 | |
| 	interrupt_gate exception_stub_24
 | |
| 	interrupt_gate exception_stub_25
 | |
| 	interrupt_gate exception_stub_26
 | |
| 	interrupt_gate exception_stub_27
 | |
| 	interrupt_gate exception_stub_28
 | |
| 	interrupt_gate exception_stub_29
 | |
| 	interrupt_gate exception_stub_30
 | |
| 	interrupt_gate exception_stub_31
 | |
| idt_end:
 | |
| 
 | |
| /* IDT pointer for use with lidt */
 | |
| idt_ptr:
 | |
| 	.word idt_end - idt - 1
 | |
| 	.long idt
 | |
| 
 | |
| 	.global exception_init_asm
 | |
| exception_init_asm:
 | |
| 	/* Save eax so we can use it as a temporary variable. */
 | |
| 	pushl	%eax
 | |
| 
 | |
| 	/* Install the GDT. */
 | |
| 	lgdt	gdt_ptr
 | |
| 	/* Load the segment registers from it. */
 | |
| 	ljmp	$0x10, $1f
 | |
| 1:	movl	$0x18, %eax
 | |
| 	movl	%eax, %ds
 | |
| 	movl	%eax, %es
 | |
| 	movl	%eax, %ss
 | |
| 	movl	%eax, %fs
 | |
| 	movl	%eax, %gs
 | |
| 
 | |
| 	/*
 | |
| 	 * Loop over the entries which start out as two copies of the target
 | |
| 	 * address. We can turn them into real interrupt gates by selectively
 | |
| 	 * replacing certain bit fields.
 | |
| 	 */
 | |
| 	movl	$idt, %eax
 | |
| 1:
 | |
| 	andl	$0x0000ffff, (%eax)
 | |
| 	orl	$0x00100000, (%eax)
 | |
| 	andl	$0xffff0000, 4(%eax)
 | |
| 	orl	$0x0000ee00, 4(%eax)
 | |
| 	addl	$8, %eax
 | |
| 	cmp	$idt_end, %eax
 | |
| 	jne	1b
 | |
| 
 | |
| 	/* Install the IDT. */
 | |
| 	lidt	idt_ptr
 | |
| 
 | |
| 	/* Restore eax and return to the caller. */
 | |
| 	popl	%eax
 | |
| 	ret
 |