A New Period of ARM Operations--Anomalies and Interruptions

Keywords: Linux C

Catalog

describe

Answer

describe

  • 1

014_und_exception_014_004/001 has a BUG. Add one more character to the following string to see if the program can run. (Try to analyze disassembly and find out why)

und_string:
    .string "undefined instruction exception"

 

  • 2

014_und_exception_014_004/002 has a BUG. Remove "bl print1" from start.S to see if undefined instruction exceptions occur.

 

  • 3

In fact, functions such as open and read called by app in LINUX system trigger exceptions by executing swi command, and realize the functions of opening, reading and writing files in exception handling function. We can implement similar functions by writing a led_ctrl assembly function:
a. It can receive one parameter
_b. It saves parameters in the stack
_c. It calls swi val, which comes from the received parameter
_d. Recovery parameters, return
Modify the swi exception handling function.
e. Lighting and extinguishing lights according to val.
Modify main function, call led_ctrl(0),led_ctrl(1)

 

  • 4

For button S2, use fast interrupt to support it.
_a. Writing FIQ interrupt processing function to realize the function of saving and restoring environment
_b. Writing interrupt processing function of keys to realize lighting and extinguishing functions
c. Modify the interrupt controller and set the INTMOD corresponding to S2 to FIQ


  • 5

The last program uses the concepts of function pointer, registered interrupt and so on. This is more and more demanding for C language. These three initialization functions are used in main function, led_init();interrupt_init();key_eint_init(). Put them in an array of function pointers and call them one by one with a for loop

 

Answer

  • 1

When the string is "undefined instruction exception", assembly code and serial output (normal operation):

 

When the string is "undefined instruction", assembler code and serial output (error operation):

 

In the first assembly segment code, the string length is just 32 bytes, assembly instructions can be automatically aligned according to 4 bytes, and the first address of reset segment is 4 bytes aligned, so there is no problem; in the second assembly segment code, the string length problem (22 bytes), resulting in assembly instructions can not be automatically aligned according to 4 bytes. The first address of the reset segment is not 4-byte alignment, resulting in an error in the call.

 

  • 2

Reference to the ARM instruction set:

In the start.S assembly code:

und_code:
	.word 0xdeadc0de   /* Undefined instructions */

In this instruction, the high 4 bit[31:28]=1101 corresponds to the yellow block in the graph, which is executed only when Z = 1 or N!= V, and the bl uart0_init above changes the status bit, making the condition not valid, failing to execute this instruction, and no undefine d exception occurs.

 

und_code:
	.word 0xe3000000  /* Undefined instructions */

Modify bit[31:28] = 1110, corresponding to the red block in the graph, that is, unconditional execution statement, undefine exception can occur.

 

  • 3

Write led_ctrl segment in start.S assembly code

.global led_ctrl
led_ctrl:
	mov	ip, sp						  /* IP=SP;Save SP */
	stmdb	sp!, {fp, ip, lr, pc}	  /* First subtract 4 from SP, then fp, ip, lr, pc stack */
	sub	fp, ip, #4) /* fp=ip-4; at this point FP points to the "fp" in the stack*/
	sub	sp, sp, #4. /* Open up an int memory*/
	str	r0, [fp, #- 16] /* parameter stack, -16 skips ip/lr/pc to the fourth position*/
	ldr	r3, [fp, #- 16] /* Take out the parameters just pressed in*/
	cmp r3, #Comparison of /* r3 and 0*/
	beq swi_zero					  /* If equal, trigger swi interrupt, pass parameter 0 */
swi_one:
	swi 0x1
	b ctrl_flag
swi_zero:
	swi 0x0
ctrl_flag:
	ldmia	sp, {r3,fp, sp, pc}	

 

Add bl led_set in do_swi section

mrs r0,cpsr					/* Passage 1 */
ldr r1,=swi_string			/* Passage 2 */
bl print_exception			/* Handling exceptions */
mov r0, r4					/* Biography */
bl led_set

 

Add the led_set() function to led.c

void led_set(unsigned int *p_swi)
{
    unsigned int val = *p_swi & ~0xff000000;
    if(val == 0)
        GPFDAT &= ~(1<<2);
    else
        GPFDAT |= 1<<2;
}

_First take out the swi call number, then switch the LED according to the number. In the main() function, call led_ctrl(1) to turn on the LED, and led_ctrl(0) to turn off the LED.

 

  • 4

Setting keys and adding do_fiq in start.S

mrs	r0,cpsr					/* Read out the cpsr status register of the current mode */
bic r0,r0,#0xf /* Low 4-bit clear 0*/
bic r0,r0,#(1 < 7) /* Clear IRQ 0 and turn on CPU interrupt master switch*/
bic r0,r0,#(1 < 6) /* Clear FIQ 0 and turn on CPU interrupt master switch*/
msr cpsr,r0					/* Store new values in cpsr */
ldr sp,=0x33f00000			/* Setup stack */
do_fiq:	
	ldr sp, =0x33c00000			/* sp_fiq Set stack first */
	sub lr, lr, #4. /* According to the manual, the return address lr needs to be reduced by 4.*/
	stmdb sp!, {r0-r12,lr}		/* It is possible to modify r0~r12 and save the return address lr first in the save field exception handling*/
	mrs r0, cpsr				/* Passage 1 */
	ldr r1, =fiq_string			/* Passage 2 */
	bl handle_fiq				/* Handling exceptions */
	ldmia sp!, {r0-r12,pc}^		/* Restoring site ^ will restore spsr to cpsr*/
fiq_string:
	.string "fiq instruction exception"
.align 4						/* For 4 bytes alignment of subsequent programs */

 

Modify the interrupt_init() function in interrupt.c:

//Set key s2 to FIQ mode	
INTMOD = 0x01;				

 

Add handle_fiq() function in key_interrupt.c:

void handle_fiq(unsigned int cpsr, char* str)
{
	unsigned int val = GPFDAT;

	//You need to read SRCPND. Because under FIQ, INTOFFSET and INTPND will not be affected.
	int bit = SRCPND;

	//1. Information Output
	puts("[FALSE] Exception instruction!\n\r");
	puts("CPSR=");
	printHex(cpsr);
	puts(" ");
	puts(str);
	puts("\n\r");

	//2.FIQ has only one interrupt source
	//Handling interrupts, clearing interrupt source EINTPEND
	if (val & (1<<0)) /* s2 --> gpf6 */
	{
		GPFDAT |= (1<<6);   /* Release */
	}
	else
	{
		GPFDAT &= ~(1<<6);  /* Press down */
	}

	//3. Clearance, INTPND will not be affected by FQI, starting from the source of clearance
	SRCPND = (1<<(bit-1));
}

 

  • 5

Define and initialize arrays in main.c

//Initialization function pointer array
typedef void(*init_func)(void);
irq_func init_array[32];
unsigned char num_init = 0;

//global variable
char g_c1 = 'A';
int g_c2 = 0;

//Key interruption
int main(void)
{
	int i;

        //Call with for loop
	init_array[num_init++] = key_eint_init;
	init_array[num_init++] = leds_init;
	init_array[num_init++] = timer0_init;
	for(i = 0; i<num_init; i++)
		init_array[i]();
	
	while(1)
	{
		puts("g_c1=");
		putchar(g_c1);
		puts(" ");
		printHex(g_c1);
		puts("\n\r");
		
		puts("g_c2=");
		putchar(g_c2);
		puts(" ");
		printHex(g_c2);
		puts("\n\r");
		
		g_c1++;
		g_c2++;
		delay(1000000);
	}
	return 0;
}

 

Posted by ixalmida on Mon, 12 Aug 2019 01:52:49 -0700