ARM Integrator-CP IRQTimerAndPICAndTaskSwitch: Difference between revisions

[unchecked revision][unchecked revision]
Content deleted Content added
Pancakes (talk | contribs)
m oops... pulled in wrong source (that included memory management)
add more maintenance templates
 
(10 intermediate revisions by 3 users not shown)
Line 1:
{{FirstPerson}}
{{You}}
{{Sole Editor}}
 
== ARM Integrator-CP IRQ, Timer, PIC, And Task Switching ==
This demonstrates initializing the exceptions vector table, timer 0, and the programmable interrupt controller. Then performing task switching between different tasks. It shows a simple method to switch
between different tasks.
 
=== Author ===
I [[User:Pancakes|Pancakes]] wrote this to help jump start you into developing for the ARM using QEMU or even a real piece of hardware. I have wrote software for both emulators and real hardware, but this has only been tested on QEMU so far. Please make any needed changes if you find problems. Also let me know at [mailto:kmcg3413@gmail.com kmcg3413@gmail.com] if you find this useful, have comments, or suggestions.
 
=== Notes ===
On ARM the SWI instruction disables IRQ interrupts on entry which is what I am using for task switching. So no switching occurs during an SWI which keeps the code simpler, and easy to understand. When the CPU switches into IRQ mode (interrupt) it is non-re-entrant unless an FIQ happens. I use no FIQ interrupts below.
 
The following points should be taken into account, and I think it would be good to leave it as an exercise to the reader. The fixes are simple, but I just wanted to make it clear what trouble you will run into when improving it to suit your needs.
 
''Also, the SWI instruction can not handle the same routine for swapping the thread state. It does not push the SPSR onto the stack like the KEXP_TOP3 and KEXP_BOT3 macros. So you will have to make the change there to allow it to save and restore the SPSR to change tasks during an SWI.''
 
''And, when I switch modes to grab the hidden registers I have it hard coded to switch back to IRQ mode which will be incorrect when switching from an SWI exception. So you need to save the current mode then restore it.''
 
=== Tools ===
Line 24 ⟶ 37:
 
=== Source ===
<sourcesyntaxhighlight lang="c">
#ifdef B64
typedef unsigned long long uintptr;
Line 275 ⟶ 288:
typedef struct _KTHREAD {
uint8 valid;
uint32 ksp; /* kernel stack pointer */
uint32 r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, sp, lr, cpsr, pc;
} KTHREAD;
Line 328 ⟶ 340:
kt = &ks->threads[ks->threadndx];
kt->pc = ((uint32*)KSTACKEXC)[-1];
kt->r0r12 = ((uint32*)KSTACKEXC)[-2];
kt->r1r11 = ((uint32*)KSTACKEXC)[-3];
kt->r2r10 = ((uint32*)KSTACKEXC)[-4];
kt->r3r9 = ((uint32*)KSTACKEXC)[-5];
kt->r4r8 = ((uint32*)KSTACKEXC)[-6];
kt->r5r7 = ((uint32*)KSTACKEXC)[-7];
kt->r6 = ((uint32*)KSTACKEXC)[-8];
kt->r7r5 = ((uint32*)KSTACKEXC)[-9];
kt->r8r4 = ((uint32*)KSTACKEXC)[-10];
kt->r9r3 = ((uint32*)KSTACKEXC)[-11];
kt->r10r2 = ((uint32*)KSTACKEXC)[-12];
kt->r11r1 = ((uint32*)KSTACKEXC)[-13];
kt->r12r0 = ((uint32*)KSTACKEXC)[-14];
kt->cpsr = ((uint32*)KSTACKEXC)[-15];
/*
Line 353 ⟶ 365:
kserdbg_puts(buf);
/* switch to system mode get registers then switch back */
asm(" mrs r0, cpsr \n\
lslbic r0, r0, #50x1f \n\
orr r0, r0, #0x1f \n\
msr cpsr, r0 \n\
mov %[sp], sp \n\
mov %[lr], lr \n\
lsrbic r0, r0, #50x1f \n\
lsl r0, r0, #5 \n\
orr r0, r0, #0x12 \n\
msr cpsr, r0 \n\
Line 386 ⟶ 398:
*/
((uint32*)KSTACKEXC)[-1] = kt->pc;
((uint32*)KSTACKEXC)[-2] = kt->r0r12;
((uint32*)KSTACKEXC)[-3] = kt->r1r11;
((uint32*)KSTACKEXC)[-4] = kt->r2r10;
((uint32*)KSTACKEXC)[-5] = kt->r3r9;
((uint32*)KSTACKEXC)[-6] = kt->r4r8;
((uint32*)KSTACKEXC)[-7] = kt->r5r7;
((uint32*)KSTACKEXC)[-8] = kt->r6;
((uint32*)KSTACKEXC)[-9] = kt->r7r5;
((uint32*)KSTACKEXC)[-10] = kt->r8r4;
((uint32*)KSTACKEXC)[-11] = kt->r9r3;
((uint32*)KSTACKEXC)[-12] = kt->r10r2;
((uint32*)KSTACKEXC)[-13] = kt->r11r1;
((uint32*)KSTACKEXC)[-14] = kt->r12r0;
((uint32*)KSTACKEXC)[-15] = kt->cpsr;
/* switch into system mode restore hidden registers then switch back */
asm(" mrs r0, cpsr \n\
bic r0, r0, #0x1f \n\
orr r0, r0, #0x1f \n\
msr cpsr, r0 \n\
mov sp, %[sp] \n\
mov lr, %[lr] \n\
lsl bic r0, r0, #50x1f \n\
lsr r0, r0, #5 \n\
orr r0, r0, #0x12 \n\
msr cpsr, r0 \n\
Line 553 ⟶ 565:
for(;;);
}
</syntaxhighlight>
</source>
 
=== Linker Script (file: link.ld) ===
This is saved in a file named ''link.ld'' which is referenced by the linker. QEMU loads the image to 0x10000, but on a real piece of hardware it might be different. This load position by QEMU may have something to do with the integrator-cp board, but I am not sure. Most ARM code is actually position independent code because the branch instructions do not address 32-bits and this is because of the 32-bit size of all instructions in ARM mode. But, when your code references symbols in the other sections it will use absolute addressing. It is possible in theory for GCC to emit position independent data references but I have found no standard option. I have heard of patches that add this ability to GCC, but just keep this in mind. I also yank out the text section in the build scripts below to make a flat binary and this is why I place everything into the text section.
<sourcesyntaxhighlight lang="text">
ENTRY (entry)
 
Line 567 ⟶ 579:
_EOI = .;
}
</syntaxhighlight>
</source>
 
=== Compile And Link ===
Line 574 ⟶ 586:
''I only left it out because I would rather wet your appetite instead of run you away with this being difficult to compile or link.''
 
<sourcesyntaxhighlight lang="bash">
arm-eabi-gcc -s -I./inc -nostdlib -nostartfiles -ffreestanding -std=gnu99 -c *.c
arm-eabi-ld -T link.ld -o __arm.bin *.o
arm-eabi-objcopy -j .text -O binary __arm.bin arm.bin
</syntaxhighlight>
</source>
 
=== Test ===
<sourcesyntaxhighlight lang="bash">
qemu-system-arm -m 8 -kernel arm.bin -serial stdio
</syntaxhighlight>
</source>
 
=== Next Phase ===
Now, that we have a preemptive multitasking system you might be wondering how we can improve? Well, for starters we could actually add in memory management and virtual memory.
 
With, [[User:Pancakes/ARM_Integrator-CP_IRQTimerPICTasksAndMM|IRQ, Timer, PIC, Tasks, And MM]].
 
=== Going Further ===
I would take a good look at all the parts of this demonstration and ensure you understand what each part does. I would recommend you pay careful attention to the exception entry and exit routines and make sure that you understand each instruction and how it works. This will save you a headache later on when things
are not acting quite right. But, here are some links to continue with. These are ''not'' the only links, but are just a few that I thought would be quite helpful.
 
 
{| class="wikitable"
Line 610 ⟶ 628:
| [[ARM_Integrator-CP_PL110_Dirty|PL110 - Color Display|QEMU PL110 Color Display]]
| Take your system to the next level with color graphics!
|-
| [[User:Pancakes/ARM_Integrator-CP_IRQTimerPICTasksAndMM|IRQ, Timer, PIC, Tasks, And MM]]
| Adds memory management including virtual memory.
|}
 
 
[[Category:ARM]]
[[Category:Interrupts]]