[PATCH 07/11] ARM: Add KGDB/KDB FIQ debugger generic code

Russell King - ARM Linux linux at arm.linux.org.uk
Mon Jul 30 10:07:24 EDT 2012


On Mon, Jul 30, 2012 at 04:58:16AM -0700, Anton Vorontsov wrote:
> +	.align	5
> +__fiq_svc:
> +	svc_entry
> +	fiq_handler
> +	svc_exit r5				@ return from exception
> + UNWIND(.fnend		)
> +ENDPROC(__fiq_svc)
> +	.ltorg
> +
> +	.align	5
> +__fiq_usr:
> +	usr_entry
> +	kuser_cmpxchg_check
> +	fiq_handler
> +	get_thread_info tsk
> +	mov	why, #0
> +	b	ret_to_user_from_irq
> + UNWIND(.fnend		)
> +ENDPROC(__fiq_usr)
> +	.ltorg
> +
> +	.global kgdb_fiq_handler
> +kgdb_fiq_handler:
> +
> +	vector_stub	fiq, FIQ_MODE, 4
> +
> +	.long	__fiq_usr			@  0  (USR_26 / USR_32)
> +	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
> +	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
> +	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
> +	.long	__fiq_svc			@  4
> +	.long	__fiq_svc			@  5
> +	.long	__fiq_svc			@  6
> +	.long	__fiq_svc			@  7
> +	.long	__fiq_svc			@  8
> +	.long	__fiq_svc			@  9
> +	.long	__fiq_svc			@  a
> +	.long	__fiq_svc			@  b
> +	.long	__fiq_svc			@  c
> +	.long	__fiq_svc			@  d
> +	.long	__fiq_svc			@  e
> +	.long	__fiq_svc			@  f

I am not convinced that this does not cause loss of state from the parent
context.  Let's review what happens when a FIQ is received from SVC mode
with the above code.

- The CPU will be in SVC mode.
- FIQ received.
- CPU saves CPSR into SPSR_fiq and PC into LR_fiq, and jumps to the FIQ
  vector.
- We apply the 4 byte correction to LR_fiq, and store r0, LR_fiq and
  SPSR_fiq to the FIQ 'stack'
- We switch to SVC mode and jump to __fiq_svc
- svc_entry:
  - adjusts the SVC stack pointer down, and saves r1 - r12
  - loads r0, LR_fiq and SPSR_fiq and saves them as ARM_r0, ARM_pc, ARM_cpsr
    into the pt_regs
  - the original value of the SVC stack pointer is saved as ARM_r13
  - LR_svc is saved as ARM_r14

At this point, we have saved everything *except* for the SPSR_svc register.

Now, when we return from the above, we use svc_exit:
- write SPSR_svc with ARM_cpsr (from SPSR_fiq)
- load r0-pc from the pt_regs and load CPSR from SPSR_svc

Now the thing here is that even if we did preserve SPSR_svc, with the
above exit sequence, there is _no_ way to preserve the value of SPSR_svc.
Normally, this doesn't matter because we know that the regions we care
about this have IRQs disabled.

However, what this means, if we receive an FIQ and use this path from any
part of the kernel which expects SPSR_svc to be preserved (eg, the exit
path from any exception) the kernel will blow up.

I guess you could do something like this instead:
- disable FIQs
- load SPSR_svc with a saved value of it from entry.
- load r1-r14 from ARM_r1..ARM_lr
- switch to FIQ mode
- load SPSR_fiq from saved ARM_cpsr
- load r0 from ARM_r0
- load pc from ARM_pc

So, maybe something like this for the svc return path:

	cpsid	f
	ldr	r1, [saved_spsr_svc]
	mov	r0, sp
	mrs	spsr_cxsf, r1
	ldmib	r0, {r1 - r14}
	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
	add	r7, r0, #S_PC
	ldr	r8, [r0, #S_CPSR]
	mrs	spsr_cxsf, r8
	ldr	r0, [r0, #S_R0]
	ldmia	r7, {pc}^



More information about the linux-arm-kernel mailing list