±à¼ÍƼö: |
±¾ÎÄÀ´×ÔÓÚcnblogs£¬±¾ÎÄÖ÷ÒªÒÔARMÌåϵ½á¹¹ÏµÄÖжϴ¦ÀíΪÀý£¬½²ÊöÕû¸öÖжϴ¦Àí¹ý³ÌÖеÄÓ²¼þÐÐΪºÍÈí¼þ¶¯×÷¡£ |
|
Ò»¡¢Ç°ÑÔ
±¾ÎÄÖ÷ÒªÒÔARMÌåϵ½á¹¹ÏµÄÖжϴ¦ÀíΪÀý£¬½²ÊöÕû¸öÖжϴ¦Àí¹ý³ÌÖеÄÓ²¼þÐÐΪºÍÈí¼þ¶¯×÷¡£¾ßÌåÕû¸ö´¦Àí¹ý³Ì·Ö³ÉÈý¸ö²½ÖèÀ´ÃèÊö£º
1¡¢µÚ¶þÕÂÃèÊöÁËÖжϴ¦ÀíµÄ×¼±¸¹ý³Ì
2¡¢µÚÈýÕÂÃèÊöÁ˵±·¢ÉúÖеÄʱºò£¬ARMÓ²¼þµÄÐÐΪ
3¡¢µÚËÄÕÂÃèÊöÁËARMµÄÖжϽøÈë¹ý³Ì
4¡¢µÚÎåÕÂÃèÊöÁËARMµÄÖжÏÍ˳ö¹ý³Ì
±¾ÎÄÉæ¼°µÄ´úÂëÀ´×Ô3.14Äںˡ£ÁíÍ⣬±¾ÎÄ×¢ÒâÃèÊöARMÖ¸ÁµÄÄÚÈÝ£¬ÓÐЩsource codeΪÁ˼ò¶ÌһЩ£¬É¾³ýÁËTHUMBÏà¹ØµÄ´úÂ룬³ý´ËÖ®Í⣬ÓÐЩdebugÏà¹ØµÄÄÚÈÝÒ²»áɾ³ý¡£
¶þ¡¢Öжϴ¦ÀíµÄ×¼±¸¹ý³Ì
1¡¢ÖжÏģʽµÄstack×¼±¸
ARM´¦ÀíÆ÷ÓжàÖÖprocessor mode£¬ÀýÈçuser mode£¨Óû§¿Õ¼äµÄAPËù´¦ÓÚµÄģʽ£©¡¢supervisor
mode£¨¼´SVC mode£¬´ó²¿·ÖµÄÄÚºË̬´úÂë¶¼´¦ÓÚÕâÖÖmode£©¡¢IRQ mode£¨·¢ÉúÖжϺ󣬴¦ÀíÆ÷»áÇÐÈëµ½¸Ãmode£©µÈ¡£¶ÔÓÚlinux
kernel£¬ÆäÖжϴ¦Àí´¦Àí¹ý³ÌÖУ¬ARM ´¦ÀíÆ÷´ó²¿·Ö¶¼ÊÇ´¦ÓÚSVC mode¡£µ«ÊÇ£¬Êµ¼ÊÉϲúÉúÖжϵÄʱºò£¬ARM´¦ÀíÆ÷ʵ¼ÊÉÏÊǽøÈëIRQ
mode£¬Òò´ËÔÚ½øÈëÕæÕýµÄIRQÒì³£´¦Àí֮ǰ»áÓÐһС¶ÎIRQ modeµÄ²Ù×÷£¬Ö®ºó»á½øÈëSVC mode½øÐÐÕæÕýµÄIRQÒì³£´¦Àí¡£ÓÉÓÚIRQ
modeÖ»ÊÇÒ»¸ö¹ý¶È£¬Òò´ËIRQ modeµÄÕ»ºÜС£¬Ö»ÓÐ12¸ö×Ö½Ú£¬¾ßÌåÈçÏ£º
struct stack
{
u32 irq[3];
u32 abt[3];
u32 und[3];
} ____cacheline_aligned;
static struct stack stacks[NR_CPUS]; |
³ýÁËirq mode£¬linux kernelÔÚ´¦Àíabt mode£¨µ±·¢Éúdata
abort exception»òÕßprefetch abort exceptionµÄʱºò½øÈëµÄģʽ£©ºÍund
mode£¨´¦ÀíÆ÷Óöµ½Ò»¸ö䶨ÒåµÄÖ¸ÁîµÄʱºò½øÈëµÄÒ쳣ģʽ£©µÄʱºòÒ²ÊDzÉÓÃÁËÏàͬµÄ²ßÂÔ¡£Ò²¾ÍÊǾ¹ýÒ»¸ö¼ò¶ÌµÄabt»òÕßund
modeÖ®ºó£¬stackÇл»µ½svc modeµÄÕ»ÉÏ£¬Õâ¸öÕ»¾ÍÊÇ·¢ÉúÒì³£ÄǸöʱ¼äµãcurrent threadµÄÄÚºËÕ»¡£anyway£¬ÔÚirq
modeºÍsvc modeÖ®¼ä×ÜÊÇÐèÒªÒ»¸östack±£´æÊý¾Ý£¬Õâ¾ÍÊÇÖжÏģʽµÄstack£¬ÏµÍ³³õʼ»¯µÄʱºò£¬cpu_initº¯ÊýÖÐ»á½øÐÐÖжÏģʽstackµÄÉ趨£º
void notrace
cpu_init(void)
{
unsigned int cpu = smp_processor_id();££££££»ñÈ¡CPU
ID
struct stack *stk = &stacks[cpu];£££££££££»ñÈ¡¸ÃCPU¶ÔÓÚµÄirq
abtºÍundµÄstackÖ¸Õë
¡¡
#ifdef CONFIG_THUMB2_KERNEL
#define PLC "r"££££££Thumb-2Ï£¬msrÖ¸Áî²»ÔÊÐíʹÓÃÁ¢¼´Êý£¬Ö»ÄÜʹÓüĴæÆ÷¡£
#else
#define PLC "I"
#endif
__asm__ ( "msr cpsr_c, %1\n\t"££££££ÈÃCPU½øÈëIRQ
mode "add r14, %0, %2\n\t"££££££r14¼Ä´æÆ÷±£´æstk->irq
"mov sp, r14\n\t"££££££££É趨IRQ
modeµÄstackΪstk->irq "msr cpsr_c,
%3\n\t" "add r14, %0, %4\n\t"
"mov sp, r14\n\t"££££££££É趨abt
modeµÄstackΪstk->abt "msr cpsr_c,
%5\n\t" "add r14, %0, %6\n\t"
"mov sp, r14\n\t"££££££££É趨und
modeµÄstackΪstk->und "msr cpsr_c,
%7"££££££££»Øµ½SVC mode
:££££££££££££££££££££ÉÏÃæÊÇcode£¬ÏÂÃæµÄoutput²¿·ÖÊǿյÄ
: "r" (stk),££££££££££££££££££££££¶ÔÓ¦ÉÏÃæ´úÂëÖеÄ%0
PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),££££££¶ÔÓ¦ÉÏÃæ´úÂëÖеÄ%1
"I" (offsetof(struct stack, irq[0])),££££££££££££¶ÔÓ¦ÉÏÃæ´úÂëÖеÄ%2
PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),££££££ÒÔ´ËÀàÍÆ£¬ÏÂÃæ²»×¸Êö
"I" (offsetof(struct stack, abt[0])),
PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE), "I"
(offsetof(struct stack, und[0])),
PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
: "r14");££££££££ÉÏÃæÊÇinput²Ù×÷ÊýÁÐ±í£¬r14ÊÇÒªclobbered
registerÁбí
} |
ǶÈëʽ»ã±àµÄÓï·¨¸ñʽÊÇ£ºasm(code : output operand list : input
operand list : clobber list);´ó¼Ò¶Ô×ÅÉÏÃæµÄcode¾Í¿ÉÒÔ·Ö¿ª¸÷¶ÎÄÚÈÝÁË¡£ÔÚinput
operand listÖУ¬ÓÐÁ½ÖÖÏÞÖÆ·û£¨constraint£©£¬"r"»òÕß"I"£¬"I"±íʾÁ¢¼´Êý£¨Immediate
operands£©£¬"r"±íʾÓÃͨÓüĴæÆ÷´«µÝ²ÎÊý¡£clobber listÖÐÓÐÒ»¸ör14£¬±íʾÔÚ»ã±à´úÂëÖÐÐÞ¸ÄÁËr14µÄÖµ£¬ÕâЩÐÅÏ¢ÊDZàÒëÆ÷ÐèÒªµÄÄÚÈÝ¡£
¶ÔÓÚSMP£¬bootstrap CPU»áÔÚϵͳ³õʼ»¯µÄʱºòÖ´ÐÐcpu_initº¯Êý£¬½øÐб¾CPUµÄirq¡¢abtºÍundÈýÖÖģʽµÄÄÚºËÕ»µÄÉ趨£¬¾ßÌåµ÷ÓÃÐòÁÐÊÇ£ºstart_kernel--->setup_arch--->setup_processor--->cpu_init¡£¶ÔÓÚϵͳÖÐÆäËûµÄCPU£¬bootstrap
CPU»áÔÚϵͳ³õʼ»¯µÄ×îºó£¬¶Ôÿһ¸öonlineµÄCPU½øÐгõʼ»¯£¬¾ßÌåµÄµ÷ÓÃÐòÁÐÊÇ£ºstart_kernel--->rest_init--->kernel_init--->kernel_init_freeable--->kernel_init_freeable--->smp_init--->cpu_up--->_cpu_up--->__cpu_up¡£__cpu_upº¯ÊýÊǺÍCPU
architectureÏà¹ØµÄ¡£¶ÔÓÚARM£¬Æäµ÷ÓÃÐòÁÐÊÇ__cpu_up--->boot_secondary--->smp_ops.smp_boot_secondary(SOCÏà¹Ø´úÂë)--->secondary_startup--->__secondary_switched--->secondary_start_kernel--->cpu_init¡£
³ýÁ˳õʼ»¯£¬ÏµÍ³µçÔ´¹ÜÀíÒ²ÐèÒªirq¡¢abtºÍund stackµÄÉ趨¡£Èç¹ûÎÒÃÇÉ趨µÄµçÔ´¹ÜÀí״̬ÔÚ½øÈësleepµÄʱºò£¬CPU»á¶ªÊ§irq¡¢abtºÍund
stack point¼Ä´æÆ÷µÄÖµ£¬ÄÇôÔÚCPU resumeµÄ¹ý³ÌÖУ¬Òªµ÷ÓÃcpu_initÀ´ÖØÐÂÉ趨ÕâЩֵ¡£
2¡¢SVCģʽµÄstack×¼±¸
ÎÒÃǾ³£Ëµ½ø³ÌµÄÓû§¿Õ¼äºÍÄں˿ռ䣬¶ÔÓÚÒ»¸öÓ¦ÓóÌÐò¶øÑÔ£¬¿ÉÒÔÔËÐÐÔÚÓû§¿Õ¼ä£¬Ò²¿ÉÒÔͨ¹ýϵͳµ÷ÓýøÈëÄں˿ռ䡣ÔÚÓû§¿Õ¼ä£¬Ê¹ÓõÄÊÇÓû§Õ»£¬Ò²¾ÍÊÇÎÒÃÇÈí¼þ¹¤³Ìʦ±àдÓû§¿Õ¼ä³ÌÐòµÄʱºò£¬±£´æ¾Ö²¿±äÁ¿µÄstack¡£ÏÝÈëÄں˺󣬵±È»²»ÄÜÓÃÓû§Õ»ÁË£¬Õâʱºò¾ÍÐèҪʹÓõ½ÄÚºËÕ»¡£ËùνÄÚºËÕ»Æäʵ¾ÍÊÇ´¦ÓÚSVC
modeʱºòʹÓõÄÕ»¡£
ÔÚlinux×ʼÆô¶¯µÄʱºò£¬ÏµÍ³Ö»ÓÐÒ»¸ö½ø³Ì£¨¸ü׼ȷµÄ˵ÊÇkernel
thread£©£¬¾ÍÊÇPIDµÈÓÚ0µÄÄǸö½ø³Ì£¬½Ð×öswapper½ø³Ì£¨»òÕß½Ð×öidle½ø³Ì£©¡£¸Ã½ø³ÌµÄÄÚºËÕ»ÊǾ²Ì¬¶¨ÒåµÄ£¬ÈçÏ£º
union thread_union
init_thread_union __init_task_data =
{ INIT_THREAD_INFO(init_task) };
union thread_union {
struct thread_info thread_info;
unsigned long stack[THREAD_SIZE/sizeof(long)];
}; |
¶ÔÓÚARMƽ̨£¬THREAD_SIZEÊÇ8192¸öbyte£¬Òò´ËÕ¼¾ÝÁ½¸öpage
frame¡£Ëæ×ųõʼ»¯µÄ½øÐУ¬user spaceµÄ½ø³ÌÒ²»á´´½¨½ø³Ì»òÕßÏ̡߳£Linux kernelÔÚ´´½¨½ø³Ì£¨°üÀ¨Óû§½ø³ÌºÍÄÚºËỊ̈߳©µÄʱºò¶¼»á·ÖÅäÒ»¸ö£¨»òÕßÁ½¸ö£¬ºÍÅäÖÃÏà¹Ø£©page
frame£¬¾ßÌå´úÂëÈçÏ£º
static struct
task_struct *dup_task_struct(struct task_struct
*orig)
{
......
ti = alloc_thread_info_node(tsk, node);
if (!ti)
goto free_tsk;
......
} |
µ×²¿ÊÇstruct thread_infoÊý¾Ý½á¹¹£¬¶¥²¿£¨¸ßµØÖ·£©¾ÍÊǸýø³ÌµÄÄÚºËÕ»¡£µ±½ø³ÌÇл»µÄʱºò£¬Õû¸öÓ²¼þºÍÈí¼þµÄÉÏÏÂÎͼ»á½øÐÐÇл»£¬ÕâÀï¾Í°üÀ¨ÁËsvc
modeµÄsp¼Ä´æÆ÷µÄÖµ±»Çл»µ½µ÷¶ÈË㷨ѡ¶¨µÄеĽø³ÌµÄÄÚºËÕ»ÉÏÀ´¡£
3¡¢Òì³£ÏòÁ¿±íµÄ×¼±¸
¶ÔÓÚARM´¦ÀíÆ÷¶øÑÔ£¬µ±·¢ÉúÒì³£µÄʱºò£¬´¦ÀíÆ÷»áÔÝÍ£µ±Ç°Ö¸ÁîµÄÖ´ÐУ¬±£´æÏÖ³¡£¬×ª¶øÈ¥Ö´ÐжÔÓ¦µÄÒì³£ÏòÁ¿´¦µÄÖ¸Áµ±´¦ÀíÍê¸ÃÒì³£µÄʱºò£¬»Ö¸´ÏÖ³¡£¬»Øµ½ÔÀ´µÄÄǵãÈ¥¼ÌÐøÖ´ÐгÌÐò¡£ÏµÍ³ËùÓеÄÒì³£ÏòÁ¿£¨¹²¼Æ8¸ö£©×é³ÉÁËÒì³£ÏòÁ¿±í¡£ÏòÁ¿±í£¨vector
table£©µÄ´úÂëÈçÏ£º
.section .vectors,
"ax", %progbits
__vectors_start:
W(b) vector_rst
W(b) vector_und
W(ldr) pc, __vectors_start + 0x1000
W(b) vector_pabt
W(b) vector_dabt
W(b) vector_addrexcptn
W(b) vector_irq ---------------------------IRQ
Vector
W(b) vector_fiq |
¶ÔÓÚ±¾ÎĶøÑÔ£¬ÎÒÃÇÖØµã¹Ø×¢vector_irqÕâ¸öexception vector¡£Òì³£ÏòÁ¿±í¿ÉÄܱ»°²·ÅÔÚÁ½¸öλÖÃÉÏ£º
£¨1£©Òì³£ÏòÁ¿±íλÓÚ0x0µÄµØÖ·¡£ÕâÖÖÉèÖýÐ×öNormal vectors»òÕßLow vectors¡£
£¨2£©Òì³£ÏòÁ¿±íλÓÚ0xffff0000µÄµØÖ·¡£ÕâÖÖÉèÖýÐ×öhigh vectors
¾ßÌåÊÇlow vectors»¹ÊÇhigh vectorsÊÇÓÉARMµÄÒ»¸ö½Ð×öµÄSCTLR¼Ä´æÆ÷µÄµÚ13¸öbit
£¨vector bit£©¿ØÖƵġ£¶ÔÓÚÆôÓÃMMUµÄARM Linux¶øÑÔ£¬ÏµÍ³Ê¹ÓÃÁËhigh vectors¡£ÎªÊ²Ã´²»ÓÃlow
vectorÄØ£¿¶ÔÓÚlinux¶øÑÔ£¬0¡«3GµÄ¿Õ¼äÊÇÓû§¿Õ¼ä£¬Èç¹ûʹÓÃlow vector£¬ÄÇôÒì³£ÏòÁ¿±íÔÚ0µØÖ·£¬ÄÇôÔòÊÇÓû§¿Õ¼äµÄλÖã¬Òò´ËlinuxÑ¡ÓÃhigh
vector¡£µ±È»£¬Ê¹ÓÃLow vectorÒ²¿ÉÒÔ£¬ÕâÑùLow vectorËùÔڵĿռäÔòÊôÓÚkernel
spaceÁË£¨Ò²¾ÍÊÇ˵£¬3G¡«4GµÄ¿Õ¼ä¼ÓÉÏLow vectorËùÕ¼µÄ¿Õ¼äÊôÓÚkernel space£©£¬²»¹ýÕâʱºòҪעÒâÒ»µã£¬ÒòΪËùÓеĽø³Ì¹²Ïíkernel
space£¬¶øÓû§¿Õ¼äµÄ³ÌÐò¾³£»á·¢Éú¿ÕÖ¸Õë·ÃÎÊ£¬Õâʱºò£¬ÄÚ´æ±£»¤»úÖÆÓ¦¸Ã¿ÉÒÔ²¶»ñÕâÖÖ´íÎ󣨴󲿷ֵÄMMU¶¼¿ÉÒÔ×öµ½£¬ÀýÈ磺½ûÖ¹userspace·ÃÎÊkernel
spaceµÄµØÖ·¿Õ¼ä£©£¬·ÀÖ¹vector table±»·ÃÎʵ½¡£¶ÔÓÚÄÚºËÖÐÓÉÓÚ³ÌÐò´íÎóµ¼ÖµĿÕÖ¸Õë·ÃÎÊ£¬ÄÚ´æ±£»¤»úÖÆÒ²ÐèÒª¿ØÖÆvector
table±»Ð޸ģ¬Òò´Ëvector tableËùÔڵĿռ䱻ÉèÖóÉread onlyµÄ¡£ÔÚʹÓÃÁËMMUÖ®ºó£¬¾ßÌåÒì³£ÏòÁ¿±í·ÅÔÚÄǸöÎïÀíµØÖ·ÒѾ²»ÖØÒªÁË£¬ÖØÒªµÄÊǰÑËüÓ³Éäµ½0xffff0000µÄÐéÄâµØÖ·¾ÍOKÁË£¬¾ßÌå´úÂëÈçÏ£º
static void
__init devicemaps_init(const struct machine_desc
*mdesc)
{
¡¡
vectors = early_alloc(PAGE_SIZE * 2); £££££·ÖÅäÁ½¸öpageµÄÎïÀíÒ³Ö¡
early_trap_init(vectors); £££££££copyÏòÁ¿±íÒÔ¼°Ïà¹Øhelp
functionµ½¸ÃÇøÓò
¡¡
map.pfn = __phys_to_pfn(virt_to_phys(vectors));
map.virtual = 0xffff0000;
map.length = PAGE_SIZE;
#ifdef CONFIG_KUSER_HELPERS
map.type = MT_HIGH_VECTORS;
#else
map.type = MT_LOW_VECTORS;
#endif
create_mapping(&map); ££££££££££Ó³Éä0xffff0000µÄÄǸöpage
frame
if (!vectors_high()) {£££Èç¹ûSCTLR.VµÄÖµÉ趨Ϊlow vectors£¬ÄÇô»¹ÒªÓ³Éä0µØÖ·¿ªÊ¼µÄmemory
map.virtual = 0;
map.length = PAGE_SIZE * 2;
map.type = MT_LOW_VECTORS;
create_mapping(&map);
}
map.pfn += 1;
map.virtual = 0xffff0000 + PAGE_SIZE;
map.length = PAGE_SIZE;
map.type = MT_LOW_VECTORS;
create_mapping(&map); ££££££££££Ó³Éähigh vecotr¿ªÊ¼µÄµÚ¶þ¸öpage
frame
¡¡
} |
ΪʲôҪ·ÖÅäÁ½¸öpage frameÄØ£¿ÕâÀïvectors tableºÍkuser helperº¯Êý£¨Äں˿ռäÌṩµÄº¯Êý£¬µ«ÊÇÓû§¿Õ¼äʹÓã©Õ¼ÓÃÁËÒ»¸öpage
frame£¬ÁíÍâÒì³£´¦ÀíµÄstubº¯ÊýÕ¼ÓÃÁËÁíÍâÒ»¸öpage frame¡£ÎªÊ²Ã´»áÓÐstubº¯ÊýÄØ£¿ÉÔºó»á½²µ½¡£
ÔÚearly_trap_initº¯ÊýÖлá³õʼ»¯Òì³£ÏòÁ¿±í£¬¾ßÌå´úÂëÈçÏ£º
void __init
early_trap_init(void *vectors_base)
{
unsigned long vectors = (unsigned long)vectors_base;
extern char __stubs_start[], __stubs_end[];
extern char __vectors_start[], __vectors_end[];
unsigned i;
vectors_page = vectors_base;
½«Õû¸övector tableÄǸöpage frameÌî³ä³É䶨ÒåµÄÖ¸Áî¡£Æðʼvector
table¼ÓÉÏkuser helperº¯Êý²¢²»ÄÜÍêÈ«µÄ³äÂúÕâ¸öpage£¬ÓÐЩ·ì϶¡£Èç¹û²»Õâô´¦Àí£¬µ±¼«¶ËÇé¿öÏ£¨³ÌÐò´íÎó»òÕßHWµÄissue£©£¬CPU¿ÉÄÜ´ÓÕâЩ·ì϶ÖÐȡִָÐУ¬´Ó¶øµ¼Ö²»¿ÉÖªµÄºó¹û¡£Èç¹û½«ÕâЩ·ì϶Ìî³ä䶨ÒåÖ¸ÁÄÇôCPU¿ÉÒÔ²¶»ñÕâÖÖÒì³£¡£
for (i = 0; i < PAGE_SIZE / sizeof(u32); i++)
((u32 *)vectors_base)[i] = 0xe7fddef1;
¿½±´vector table£¬¿½±´stub function
memcpy((void *)vectors, __vectors_start, __vectors_end
- __vectors_start);
memcpy((void *)vectors + 0x1000, __stubs_start,
__stubs_end - __stubs_start);
kuser_init(vectors_base); ££££copy kuser helper
function
flush_icache_range(vectors, vectors + PAGE_SIZE
* 2);
modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
} |
½«Õû¸övector tableÄǸöpage frameÌî³ä³É䶨ÒåµÄÖ¸Áî¡£Æðʼvector
table¼ÓÉÏkuser helperº¯Êý²¢²»ÄÜÍêÈ«µÄ³äÂúÕâ¸öpage£¬ÓÐЩ·ì϶¡£Èç¹û²»Õâô´¦Àí£¬µ±¼«¶ËÇé¿öÏ£¨³ÌÐò´íÎó»òÕßHWµÄissue£©£¬CPU¿ÉÄÜ´ÓÕâЩ·ì϶ÖÐȡִָÐУ¬´Ó¶øµ¼Ö²»¿ÉÖªµÄºó¹û¡£Èç¹û½«ÕâЩ·ì϶Ìî³ä䶨ÒåÖ¸ÁÄÇôCPU¿ÉÒÔ²¶»ñÕâÖÖÒì³£¡£
Ò»µ©Éæ¼°´úÂëµÄ¿½±´£¬ÎÒÃǾÍÐèÒª¹ØÐÄÆä±àÒëÁ¬½ÓʱµØÖ·£¨link-time address)ºÍÔËÐÐʱµØÖ·£¨run-time
address£©¡£ÔÚkernelÍê³ÉÁ´½Óºó£¬__vectors_startÓÐÁËÆälink-time
address£¬Èç¹ûlink-time addressºÍrun-time addressÒ»Ö£¬ÄÇôÕâ¶Î´úÂëÔËÐÐʱºÁÎÞѹÁ¦¡£µ«ÊÇ£¬Ä¿Ç°¶ÔÓÚvector
table¶øÑÔ£¬Æä±»copyµ½ÆäËûµÄµØÖ·ÉÏ£¨¶ÔÓÚHigh vector£¬ÕâÊǵØÖ·¾ÍÊÇ0xffff00000£©£¬Ò²¾ÍÊÇ˵£¬link-time
addressºÍrun-time address²»Ò»ÑùÁË£¬Èç¹ûÈÔÈ»ÏëÒªÕâЩ´úÂë¿ÉÒÔÕýÈ·ÔËÐУ¬ÄÇôÐèÒªÕâЩ´úÂëÊÇλÖÃÎ޹صĴúÂë¡£¶ÔÓÚvector
table¶øÑÔ£¬±ØÐëҪλÖÃÎ޹ء£BÕâ¸öbranch instruction±¾Éí¾ÍÊÇλÖÃÎ޹صģ¬Ëü¿ÉÒÔÌø×ªµ½Ò»¸öµ±Ç°Î»ÖõÄoffset¡£²»¹ý²¢·ÇËùÓеÄvector¶¼ÊÇʹÓÃÁËbranch
instruction£¬¶ÔÓÚÈíÖжϣ¬ÆävectorµØÖ·ÉÏÖ¸ÁîÊÇ¡°W(ldr) pc, __vectors_start
+ 0x1000 ¡±£¬ÕâÌõÖ¸Áî±»±àÒëÆ÷±àÒë³Éldr pc, [pc, #4080]£¬ÕâÖÖÇé¿öÏ£¬¸ÃÖ¸ÁîÒ²ÊÇλÖÃÎ޹ص쬵«ÊÇÓиöÏÞÖÆ£¬offset±ØÐëÔÚ4KµÄ·¶Î§ÄÚ£¬ÕâÒ²ÊÇΪºÎ´æÔÚstub
sectionµÄÔÒòÁË¡£
4¡¢ÖжϿØÖÆÆ÷µÄ³õʼ»¯
¾ßÌå¿ÉÒԲο¼GIC´úÂë·ÖÎö¡£
Èý¡¢ARM HW¶ÔÖжÏʼþµÄ´¦Àí
µ±Ò»ÇÐ×¼±¸ºÃÖ®ºó£¬Ò»µ©´ò¿ª´¦ÀíÆ÷µÄÈ«¾ÖÖжϾͿÉÒÔ´¦ÀíÀ´×ÔÍâÉèµÄ¸÷ÖÖÖжÏʼþÁË¡£
µ±ÍâÉ裨SOCÄÚ²¿»òÕßÍⲿ¶¼¿ÉÒÔ£©¼ì²âµ½ÁËÖжÏʼþ£¬¾Í»áͨ¹ýinterrupt requestion
lineÉÏµÄµçÆ½»òÕß±ßÑØ£¨ÉÏÉýÑØ»òÕßϽµÑØ»òÕßboth£©Í¨Öªµ½¸ÃÍâÉèÁ¬½Óµ½µÄÄǸöÖжϿØÖÆÆ÷£¬¶øÖжϿØÖÆÆ÷¾Í»áÔÚ¶à¸ö´¦ÀíÆ÷ÖÐÑ¡ÔñÒ»¸ö£¬²¢°Ñ¸ÃÖжÏͨ¹ýIRQ£¨»òÕßFIQ£¬±¾ÎIJ»ÌÖÂÛFIQµÄÇé¿ö£©·Ö·¢¸ø¸Ãprocessor¡£ARM´¦ÀíÆ÷¸ÐÖªµ½ÁËÖжÏʼþºó£¬»á½øÐÐÏÂÃæÒ»ÏµÁе͝×÷£º
1¡¢ÐÞ¸ÄCPSR£¨Current Program Status Register£©¼Ä´æÆ÷ÖеÄM[4:0]¡£M[4:0]±íʾÁËARM´¦ÀíÆ÷µ±Ç°´¦ÓÚµÄģʽ£¨
processor modes£©¡£ARM¶¨ÒåµÄmode°üÀ¨£º

Ò»µ©É趨ÁËCPSR.M£¬ARM´¦ÀíÆ÷¾Í»á½«processor modeÇл»µ½IRQ mode¡£
2¡¢±£´æ·¢ÉúÖжÏÄÇÒ»µãµÄCPSRÖµ£¨step 1֮ǰµÄ״̬£©ºÍPCÖµ
ARM´¦ÀíÆ÷Ö§³Ö9ÖÖprocessor mode£¬Ã¿ÖÖmode¿´µ½µÄARM
core register£¨R0¡«R15£¬¹²¼Æ16¸ö£©¶¼ÊDz»Í¬µÄ¡£Ã¿ÖÖmode¶¼ÊÇ´ÓÒ»¸ö°üÀ¨ËùÓеÄBanked
ARM core registerÖÐѡȡ¡£È«²¿Banked ARM core register°üÀ¨£º

ÔÚIRQ modeÏ£¬CPU¿´µ½µÄR0¡«R12¼Ä´æÆ÷¡¢PCÒÔ¼°CPSRÊǺÍusr mode£¨userspace£©»òÕßsvc
mode£¨kernel space£©ÊÇÒ»ÑùµÄ¡£²»Í¬µÄÊÇIRQ modeÏ£¬ÓÐ×Ô¼ºµÄR13(SP£¬stack
pointer£©¡¢R14£¨LR£¬link register£©ºÍSPSR£¨Saved Program
Status Register£©¡£
CPSRÊǹ²Óõģ¬ËäÈ»ÖжϿÉÄÜ·¢ÉúÔÚusr mode£¨Óû§¿Õ¼ä£©£¬Ò²¿ÉÄÜÊÇsvc mode£¨Äں˿ռ䣩£¬²»¹ýÕâЩÐÅÏ¢¶¼ÊÇÌåÏÖÔÚCPSR¼Ä´æÆ÷ÖС£Ó²¼þ»á½«·¢ÉúÖжÏÄÇÒ»¿ÌµÄCPSR±£´æÔÚSPSR¼Ä´æÆ÷ÖУ¨ÓÉÓÚ²»Í¬µÄmodeÏÂÓв»Í¬µÄSPSR¼Ä´æÆ÷£¬Òò´Ë¸ü׼ȷµÄ˵Ӧ¸ÃÊÇSPSR-irq£¬Ò²¾ÍÊÇIRQ
modeÖеÄSPSR¼Ä´æÆ÷£©¡£
PCÒ²Êǹ²Óõģ¬ÓÉÓÚºóÐøPC»á±»ÐÞ¸ÄΪirq exception vector£¬Òò´ËÓбØÒª±£´æPCÖµ¡£µ±È»£¬ÓëÆä˵±£´æPCÖµ£¬²»Èç˵ÊDZ£´æ·µ»ØÖ´ÐеĵØÖ·¡£¶ÔÓÚIRQ¶øÑÔ£¬ÎÒÃÇÆÚÍû·µ»ØµØÖ·ÊÇ·¢ÉúÖжÏÄÇÒ»µãÖ´ÐÐÖ¸ÁîµÄÏÂÒ»ÌõÖ¸Áî¡£¾ßÌåµÄ·µ»ØµØÖ·±£´æÔÚlr¼Ä´æÆ÷ÖУ¨×¢Ò⣺Õâ¸ölr¼Ä´æÆ÷ÊÇIRQ
modeµÄlr¼Ä´æÆ÷£¬¿ÉÒÔ±íʾΪlr_irq£©£º
£¨1£©¶ÔÓÚthumb state£¬lr_irq £½ PC
£¨2£©¶ÔÓÚARM state£¬lr_irq £½ PC £ 4
ΪºÎÒª¼õÈ¥4£¿ÎÒµÄÀí½âÊÇÕâÑùµÄ£¨²»Ò»¶¨¶Ô£©¡£ÓÉÓÚARM²ÉÓÃÁ÷Ë®Ï߽ṹ£¬µ±CPUÕýÔÚÖ´ÐÐijһÌõÖ¸ÁîµÄʱºò£¬ÆäʵȡָµÄ¶¯×÷Ôç¾ÍÖ´ÐÐÁË£¬ÕâʱºòPCÖµ£½ÕýÔÚÖ´ÐеÄÖ¸ÁîµØÖ·
£« 8£¬ÈçÏÂËùʾ£º
££££> ·¢ÉúÖжϵÄÖ¸Áî
·¢ÉúÖжϵÄÖ¸Á4
£PC££>·¢ÉúÖжϵÄÖ¸Á8
·¢ÉúÖжϵÄÖ¸Á12
Ò»µ©·¢ÉúÁËÖжϣ¬µ±Ç°ÕýÔÚÖ´ÐеÄÖ¸ÁȻҪִÐÐÍê±Ï£¬µ«ÊÇÒѾÍê³Éȡָ¡¢ÒëÂëµÄÖ¸ÁîÔòÖÕÖ¹Ö´ÐС£µ±·¢ÉúÖжϵÄÖ¸ÁîÖ´ÐÐÍê±ÏÖ®ºó£¬ÔÀ´Ö¸Ïò£¨·¢ÉúÖжϵÄÖ¸Á8£©µÄPC»á¼ÌÐøÔö¼Ó4£¬Òò´Ë·¢ÉúÖжϺó£¬ARM
coreµÄÓ²¼þ×ÅÊÖ´¦Àí¸ÃÖжϵÄʱºò£¬Ó²¼þÏÖ³¡ÈçÏÂͼËùʾ£º
££££> ·¢ÉúÖжϵÄÖ¸Áî
·¢ÉúÖжϵÄÖ¸Á4 <-------ÖжϷµ»ØµÄÖ¸ÁîÊÇÕâÌõÖ¸Áî
·¢ÉúÖжϵÄÖ¸Á8
£PC££>·¢ÉúÖжϵÄÖ¸Á12
ÕâʱºòµÄPCÖµÆäʵÊDZȷ¢ÉúÖжÏʱºòµÄÖ¸Áǰ12¡£¼õÈ¥4Ö®ºó£¬lr_irqÖб£´æÁË£¨·¢ÉúÖжϵÄÖ¸Á8£©µÄµØÖ·¡£ÎªÊ²Ã´HW²»°ïæֱ½Ó¼õÈ¥8ÄØ£¿ÕâÑù£¬ºóÐøÈí¼þ²»¾Í²»ÓÃÔÙ¼õÈ¥4ÁË¡£ÕâÀïÎÒÃDz»ÄܹÂÁ¢µÄ¿´´ýÎÊÌ⣬ʵ¼ÊÉÏARMµÄÒì³£´¦ÀíµÄÓ²¼þÂß¼²»½ö½ö´¦ÀíIRQµÄexception£¬»¹Òª´¦Àí¸÷ÖÖexception£¬ºÜÒź¶£¬²»Í¬µÄexceptionÆÚÍûµÄ·µ»ØµØÖ·²»Í³Ò»£¬Òò´Ë£¬Ó²¼þÖ»Êǰïæ¼õÈ¥4£¬Ê£ÏµĽ»¸øÈí¼þÈ¥µ÷Õû¡£
3¡¢mask IRQ exception¡£Ò²¾ÍÊÇÉ趨CPSR.I = 1
4¡¢É趨PCֵΪIRQ exception vector¡£»ù±¾ÉÏ£¬ARM´¦ÀíÆ÷µÄÓ²¼þ¾ÍÖ»ÄܰïÄã°ïµ½ÕâÀïÁË£¬Ò»µ©É趨PCÖµ£¬ARM´¦ÀíÆ÷¾Í»áÌø×ªµ½IRQµÄexception
vectorµØÖ·ÁË£¬ºóÐøµÄ¶¯×÷¶¼ÊÇÈí¼þÐÐΪÁË¡£
ËÄ¡¢ÈçºÎ½øÈëARMÖжϴ¦Àí
1¡¢IRQ modeÖеĴ¦Àí
IRQ modeµÄ´¦Àí¶¼ÔÚvector_irqÖУ¬vector_stubÊÇÒ»¸öºê£¬¶¨ÒåÈçÏ£º
.macro vector_stub,
name, mode, correction=0
.align 5
vector_\name:
.if \correction
sub lr, lr, #\correction££££££££££££££¨1£©
.endif
@
@ Save r0, lr_ (parent PC) and spsr_
@ (parent CPSR)
@
stmia sp, {r0, lr} @ save r0, lr£££££££££¨2£©
mrs lr, spsr
str lr, [sp, #8] @ save spsr
@
@ Prepare for SVC32 mode. IRQs remain disabled.
@
mrs r0, cpsr££££££££££££££££££££££££¨3£©
eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
msr spsr_cxsf, r0
@
@ the branch table must immediately follow this
code
@
and lr, lr, #0x0f£££lr±£´æÁË·¢ÉúIRQʱºòµÄCPSR£¬Í¨¹ýand²Ù×÷£¬¿ÉÒÔ»ñÈ¡CPSR.M[3:0]µÄÖµ
Õâʱºò£¬Èç¹ûÖжϷ¢ÉúÔÚÓû§¿Õ¼ä£¬lr=0£¬Èç¹ûÊÇÄں˿ռ䣬lr=3
THUMB( adr r0, 1f )££££¸ù¾Ýµ±Ç°PCÖµ£¬»ñÈ¡lable 1µÄµØÖ·
THUMB( ldr lr, [r0, lr, lsl #2] )£lr¸ù¾Ýµ±Ç°mode£¬ÒªÃ´ÊÇ__irq_usrµÄµØÖ·
£¬ÒªÃ´ÊÇ__irq_svcµÄµØÖ·
mov r0, sp££££££½«irq modeµÄstack pointͨ¹ýr0´«µÝ¸ø¼´½«Ìø×ªµÄº¯Êý
ARM( ldr lr, [pc, lr, lsl #2] )£££¸ù¾Ýmode£¬¸ølr¸³Öµ£¬__irq_usr»òÕß__irq_svc
movs pc, lr @ branch to handler in SVC mode££££££¨4£©
ENDPROC(vector_\name)
.align 2
@ handler addresses follow this label
1:
.endm |
£¨1£©ÎÒÃÇÆÚÍûÔÚÕ»Éϱ£´æ·¢ÉúÖжÏʱºòµÄÓ²¼þÏÖ³¡£¨HW context£©£¬ÕâÀï¾Í°üÀ¨ARMµÄcore
register¡£ÉÏÒ»ÕÂÎÒÃÇÒѾÁ˽⵽£¬µ±·¢ÉúIRQÖжϵÄʱºò£¬lrÖб£´æÁË·¢ÉúÖжϵÄPC£«4£¬Èç¹û¼õÈ¥4µÄ»°£¬µÃµ½µÄ¾ÍÊÇ·¢ÉúÖжÏÄÇÒ»µãµÄPCÖµ¡£
£¨2£©µ±Ç°ÊÇIRQ mode£¬SP_irqÔÚ³õʼ»¯µÄʱºòÒѾÉ趨£¨12¸ö×Ö½Ú£©¡£ÔÚirq modeµÄstackÉÏ£¬ÒÀ´Î±£´æÁË·¢ÉúÖжÏÄÇÒ»µãµÄr0Öµ¡¢PCÖµÒÔ¼°CPSRÖµ£¨¾ßÌå²Ù×÷ÊÇͨ¹ýspsr½øÐе쬯äʵӲ¼þÒѾ°ïÎÒÃDZ£´æÁËCPSRµ½SPSRÖÐÁË£©¡£ÎªºÎÒª±£´ær0Öµ£¿ÒòÎªËæºóµÄ´úÂëҪʹÓÃr0¼Ä´æÆ÷£¬Òò´ËÎÒÃÇÒª°Ñr0·Åµ½Õ»ÉÏ£¬Ö»ÓÐÕâÑù²ÅÄÜÍêÍêȫȫ»Ö¸´Ó²¼þÏÖ³¡¡£
£¨3£©¿ÉÁ¯µÄIRQ modeÉÔ×ݼ´ÊÅ£¬Õâ¶Î´úÂë¾ÍÊÇ×¼±¸½«ARMÍÆË͵½SVC mode¡£ÈçºÎ×¼±¸£¿Æäʵ¾ÍÊÇÐÞ¸ÄSPSRµÄÖµ£¬SPSR²»ÊÇCPSR£¬²»»áÒýÆðprocessor
modeµÄÇл»£¨±Ï¾¹ÕâÒ»²½Ö»ÊÇ×¼±¸¶øÒÑ£©¡£
£¨4£©ºÜ¶àÒì³£´¦ÀíµÄ´úÂë·µ»ØµÄʱºò¶¼ÊÇʹÓÃÁËstackÏà¹ØµÄ²Ù×÷£¬ÕâÀïûÓС£¡°movs pc, lr
¡±Ö¸Áî³ýÁË×ÖÃæÉÏÒâ˼£¨°ÑlrµÄÖµ¸¶¸øpc£©£¬»¹ÓÐÒ»¸öÒþº¬µÄ²Ù×÷£¨movsÖС®s¡¯µÄº¬Ò壩£º°ÑSPSR
copyµ½CPSR£¬´Ó¶øÊµÏÖÁËģʽµÄÇл»¡£
2¡¢µ±·¢ÉúÖжϵÄʱºò£¬´úÂëÔËÐÐÔÚÓû§¿Õ¼ä
Interrupt dispatcherµÄ´úÂëÈçÏ£º
vector_stub
irq, IRQ_MODE, 4 £££££¼õÈ¥4£¬È·±£·µ»Ø·¢ÉúÖжÏÖ®ºóµÄÄÇÌõÖ¸Áî
.long __irq_usr @ 0 (USR_26 / USR_32) <--------------------->
base address + 0
.long __irq_invalid @ 1 (FIQ_26 / FIQ_32)
.long __irq_invalid @ 2 (IRQ_26 / IRQ_32)
.long __irq_svc @ 3 (SVC_26 / SVC_32)<--------------------->
base address + 12
.long __irq_invalid @ 4
.long __irq_invalid @ 5
.long __irq_invalid @ 6
.long __irq_invalid @ 7
.long __irq_invalid @ 8
.long __irq_invalid @ 9
.long __irq_invalid @ a
.long __irq_invalid @ b
.long __irq_invalid @ c
.long __irq_invalid @ d
.long __irq_invalid @ e
.long __irq_invalid @ f |
ÕâÆäʵ¾ÍÊÇÒ»¸ölookup table£¬¸ù¾ÝCPSR.M[3:0]µÄÖµ½øÐÐÌø×ª£¨²Î¿¼ÉÏÒ»½ÚµÄ´úÂ룺and
lr, lr, #0x0f£©¡£Òò´Ë£¬¸Ãlookup table¹²É趨ÁË16¸öÈë¿Ú£¬µ±È»Ö»ÓÐÁ½ÏîÓÐЧ£¬·Ö±ð¶ÔÓ¦user
modeºÍsvc modeµÄÌø×ªµØÖ·¡£ÆäËûÈë¿ÚµÄ__irq_invalidÒ²ÊǷdz£¹Ø¼üµÄ£¬Õâ±£Ö¤ÁËÔÚÆäģʽÏ·¢ÉúÁËÖжϣ¬ÏµÍ³¿ÉÒÔ²¶»ñµ½ÕâÑùµÄ´íÎó£¬ÎªdebugÌṩÓÐÓõÄÐÅÏ¢¡£
.align 5
__irq_usr:
usr_entry£££££££££Çë²Î¿¼±¾ÕµÚÒ»½Ú£¨1£©±£´æÓû§ÏÖ³¡µÄÃèÊö
kuser_cmpxchg_check£££ºÍ±¾ÎÄÃèÊöµÄÄÚÈÝÎ޹أ¬ÕâЩ²»¾Í½éÉÜÁË
irq_handler££££££££££ºËÐÄ´¦ÀíÄÚÈÝ£¬Çë²Î¿¼±¾Õµڶþ½ÚµÄÃèÊö
get_thread_info tsk££££££tskÊÇr9£¬Ö¸Ïòµ±Ç°µÄthread infoÊý¾Ý½á¹¹
mov why, #0££££££££whyÊÇr8
b ret_to_user_from_irq££££ÖжϷµ»Ø£¬ÏÂÒ»Õ»áÏêϸÃèÊö |
whyÆäʵ¾ÍÊÇr8¼Ä´æÆ÷£¬ÓÃÀ´´«µÝ²ÎÊýµÄ£¬±íʾ±¾´Î·Å»ØÓû§¿Õ¼äÏà¹ØµÄϵͳµ÷ÓÃÊÇÄĸö£¿Öжϴ¦ÀíÕâ¸ö³¡¾°ºÍϵͳµ÷ÓÃÎ޹أ¬Òò´ËÉ趨Ϊ0¡£
£¨1£©±£´æ·¢ÉúÖжÏʱºòµÄÏÖ³¡¡£Ëùν±£´æÏÖ³¡Æäʵ¾ÍÊǰѷ¢ÉúÖжÏÄÇÒ»¿ÌµÄÓ²¼þÉÏÏÂÎÄ£¨¸÷¸ö¼Ä´æÆ÷£©±£´æÔÚÁËSVC
modeµÄstackÉÏ¡£
.macro usr_entry
sub sp, sp, #S_FRAME_SIZE££££££££££££££A
stmib sp, {r1 - r12} £££££££££££££££££££B
ldmia r0, {r3 - r5}££££££££££££££££££££C
add r0, sp, #S_PC£££££££££££££££££££D
mov r6, #-1££££orig_r0µÄÖµ
str r3, [sp] ££££±£´æÖжÏÄÇÒ»¿ÌµÄr0
stmia r0, {r4 - r6}££££££££££££££££££££E
stmdb r0, {sp, lr}^£££££££££££££££££££F
.endm |
A£º´úÂëÖ´Ðе½ÕâÀïµÄʱºò£¬ARM´¦ÀíÒѾÇл»µ½ÁËSVC mode¡£Ò»µ©½øÈëSVC mode£¬ARM´¦ÀíÆ÷¿´µ½µÄ¼Ä´æÆ÷ÒѾ·¢Éú±ä»¯£¬ÕâÀïµÄspÒѾ±ä³ÉÁËsp_svcÁË¡£Òò´Ë£¬ºóÐøµÄѹջ²Ù×÷¶¼ÊÇѹÈëÁË·¢ÉúÖжÏÄÇÒ»¿ÌµÄ½ø³ÌµÄ£¨»òÕßÄÚºËỊ̈߳©ÄÚºËÕ»£¨svc
modeÕ»£©¡£¾ßÌå±£´æ¶àÉÙ¸ö¼Ä´æÆ÷Öµ£¿S_FRAME_SIZEÒѾ¸ø³öÁ˴𰸣¬Õâ¸öÖµÊÇ18¸ö¼Ä´æÆ÷¡£r0¡«r15ÔÙ¼ÓÉÏCPSRÒ²Ö»ÓÐ17¸ö¶øÒÑ¡£Ïȱ£ÁôÕâ¸öÒÉÎÊ£¬ÎÒÃÇÉÔºó»Ø´ð¡£
B£ºÑ¹Õ»Ê×ÏÈѹÈëÁËr1¡«r12£¬ÕâÀïΪºÎ²»´¦Àír0£¿ÒòΪr0ÔÚirq modeÇе½svc modeµÄʱºò±»ÎÛȾÁË£¬²»¹ý£¬ÔʼµÄr0±»±£´æµÄirq
modeµÄstackÉÏÁË¡£r13£¨sp£©ºÍr14£¨lr£©ÐèÒª±£´æÂ𣬵±È»ÐèÒª£¬ÉÔºóÔÙ±£´æ¡£Ö´Ðе½ÕâÀÄÚºËÕ»µÄ²¼¾ÖÈçÏÂͼËùʾ£º

stmibÖеÄib±íʾincrement before£¬Òò´Ë£¬ÔÚѹÈëR1µÄʱºò£¬stack pointer»áÏÈÔö¼Ó4£¬ÖØÒªÊÇÔ¤Áôr0µÄλÖá£stmib
sp, {r1 - r12}Ö¸ÁîÖеÄspûÓС°£¡¡±µÄÐÞÊηû£¬±íʾѹջÍê³Éºó²¢²»»áÕæÕý¸üÐÂstack
pointer£¬Òò´Ësp±£³ÖÔÀ´µÄÖµ¡£
C£º×¢Ò⣬ÕâÀïr0Ö¸ÏòÁËirq stack£¬Òò´Ë£¬r3ÊÇÖжÏʱºòµÄr0Öµ£¬r4ÊÇÖжÏÏÖ³¡µÄPCÖµ£¬r5ÊÇÖжÏÏÖ³¡µÄCPSRÖµ¡£
D£º°Ñr0¸³ÖµÎªS_PCµÄÖµ¡£¸ù¾Ýstruct pt_regsµÄ¶¨Ò壨Õâ¸öÊý¾Ý½á¹¹·´Ó¦ÁËÄÚºËÕ»Éϵı£´æµÄ¼Ä´æÆ÷µÄÅÅÁÐÐÅÏ¢£©£¬´ÓµÍµØÖ·µ½¸ßµØÖ·ÒÀ´ÎΪ£º
ARM_r0
ARM_r1
ARM_r2
ARM_r3
ARM_r4
ARM_r5
ARM_r6
ARM_r7
ARM_r8
ARM_r9
ARM_r10
ARM_fp
ARM_ip
ARM_sp
ARM_lr
ARM_pc<---------add r0, sp, #S_PCÖ¸ÁîʹµÃr0Ö¸ÏòÁËÕâ¸öλÖÃ
ARM_cpsr
ARM_ORIG_r0 |
ΪʲôҪ¸ør0¸³Öµ£¿Òò´Ëkernel²»ÏëÐÞ¸ÄspµÄÖµ£¬±£³ÖspÖ¸ÏòÕ»¶¥¡£
E£ºÔÚÄÚºËÕ»Éϱ£´æÊ£ÓàµÄ¼Ä´æÆ÷µÄÖµ£¬¸ù¾Ý´úÂ룬ÒÀ´ÎÊÇr0£¬PC£¬CPSRºÍorig r0¡£Ö´Ðе½ÕâÀÄÚºËÕ»µÄ²¼¾ÖÈçÏÂͼËùʾ£º

R0£¬PCºÍCPSRÀ´×ÔIRQ modeµÄstack¡£Êµ¼ÊÉÏÕâ¶Î²Ù×÷¾ÍÊÇ´Óirq stack¾ÍÖжÏÏÖ³¡°áÒÆµ½ÄÚºËÕ»ÉÏ¡£
F£ºÄÚºËÕ»ÉÏ»¹ÓÐÁ½¸ö¼Ä´æÆ÷ûÓб£³Ö£¬·Ö±ðÊÇ·¢ÉúÖжÏʱºòspºÍlrÕâÁ½¸ö¼Ä´æÆ÷¡£Õâʱºò£¬r0Ö¸ÏòÁ˱£´æPC¼Ä´æÆ÷ÄǸöµØÖ·£¨add
r0, sp, #S_PC£©£¬stmdb r0, {sp, lr}^Öеġ°db¡±ÊÇdecrement
before£¬Òò´Ë£¬½«spºÍlrѹÈëstackÖеÄÊ£ÓàµÄÁ½¸öλÖá£ÐèҪעÒâµÄÊÇ£¬ÎÒÃDZ£´æµÄÊÇ·¢ÉúÖжÏÄÇÒ»¿Ì£¨¶ÔÓÚ±¾½Ú£¬ÕâÊǵ±Ê±user
modeµÄspºÍlr£©£¬Ö¸ÁîÖеġ°^¡±·ûºÅ±íʾ·ÃÎÊuser modeµÄ¼Ä´æÆ÷¡£
£¨2£©ºËÐÄ´¦Àí
irq_handlerµÄ´¦ÀíÓÐÁ½ÖÖÅäÖá£Ò»ÖÖÊÇÅäÖÃÁËCONFIG_MULTI_IRQ_HANDLER¡£ÕâÖÖÇé¿öÏ£¬linux
kernelÔÊÐírun timeÉ趨irq handler¡£Èç¹ûÎÒÃÇÐèÒªÒ»¸ölinux kernel
imageÖ§³Ö¶à¸öƽ̨£¬ÕâÊǾÍÐèÒªÅäÖÃÕâ¸öÑ¡Ïî¡£ÁíÍâÒ»ÖÖÊÇ´«Í³µÄlinuxµÄ×ö·¨£¬irq_handlerʵ¼ÊÉϾÍÊÇarch_irq_handler_default£¬¾ßÌå´úÂëÈçÏ£º
.macro irq_handler
#ifdef CONFIG_MULTI_IRQ_HANDLER
ldr r1, =handle_arch_irq
mov r0, sp££££££££É趨´«µÝ¸ømachine¶¨ÒåµÄhandle_arch_irqµÄ²ÎÊý
adr lr, BSYM(9997f)££££É趨·µ»ØµØÖ·
ldr pc, [r1]
#else
arch_irq_handler_default
#endif
9997:
.endm |
¶ÔÓÚÇé¿öÒ»£¬machineÏà¹Ø´úÂëÐèÒªÉ趨handle_arch_irqº¯ÊýÖ¸Õ룬ÕâÀïµÄ»ã±àÖ¸ÁîÖ»ÐèÒªµ÷ÓÃÕâ¸ömachine´úÂëÌṩµÄirq
handler¼´¿É£¨µ±È»£¬Òª×¼±¸ºÃ²ÎÊý´«µÝºÍ·µ»ØµØÖ·É趨£©¡£
Çé¿ö¶þÒªÉÔ΢¸´ÔÓһЩ£¨¶øÇÒ£¬¿´ÆðÀ´kernelÖÐʹÓõÄÔ½À´Ô½ÉÙ£©£¬´úÂëÈçÏ£º
.macro arch_irq_handler_default
get_irqnr_preamble r6, lr
1: get_irqnr_and_base r0, r2, r6, lr
movne r1, sp
@
@ asm_do_IRQ ÐèÒªÁ½¸ö²ÎÊý£¬Ò»¸öÊÇ irq number£¨±£´æÔÚr0£©
@ ÁíÒ»¸öÊÇ struct pt_regs *£¨±£´æÔÚr1ÖУ©
adrne lr, BSYM(1b)£££££££·µ»ØµØÖ·É趨Ϊ·ûºÅ1£¬Ò²¾ÍÊÇ˵Ҫ²»¶ÏµÄ½âÎöirq״̬¼Ä´æÆ÷µÄÄÚÈÝ£¬µÃµ½IRQ
number£¬Ö±µ½ËùÓеÄirq number´¦ÀíÍê±Ï
bne asm_do_IRQ
.endm |
ÕâÀïµÄ´úÂëÒѾÊǺÍmachineÏà¹ØµÄ´úÂëÁË£¬ÎÒÃÇÕâÀïÖ»ÊǼò¶ÌÃèÊöһϡ£ËùνmachineÏà¹ØÒ²¾ÍÊÇ˵ºÍϵͳÖеÄÖжϿØÖÆÆ÷Ïà¹ØÁË¡£get_irqnr_preambleÊÇΪÖжϴ¦Àí×ö×¼±¸£¬ÓÐЩƽ̨¸ù±¾²»ÐèÒªÕâ¸ö²½Ö裬ֱ½Ó¶¨ÒåΪ¿Õ¼´¿É¡£get_irqnr_and_base
ÓÐËĸö²ÎÊý£¬·Ö±ðÊÇ£ºr0±£´æÁ˱¾´Î½âÎöµÄirq number£¬r2ÊÇirq״̬¼Ä´æÆ÷µÄÖµ£¬r6ÊÇirq
controllerµÄbase address£¬lrÊÇscratch register¡£
¶ÔÓÚARMƽ̨¶øÑÔ£¬ÎÒÃÇÍÆ¼öʹÓõÚÒ»ÖÖ·½·¨£¬ÒòΪ´ÓÂß¼ÉϽ²£¬Öжϴ¦Àí¾ÍÊÇÐèÒª¸ù¾Ýµ±Ç°µÄÓ²¼þÖжÏϵͳµÄ״̬£¬×ª»»³ÉÒ»¸öIRQ
number£¬È»ºóµ÷ÓøÃIRQ numberµÄ´¦Àíº¯Êý¼´¿É¡£Í¨¹ýget_irqnr_and_baseÕâÑùµÄºê¶¨ÒåÀ´»ñÈ¡IRQÊǾɵÄARM
SOCϵͳʹÓõķ½·¨£¬ËüÊǼÙÉèSOCÉÏÓÐÒ»¸öÖжϿØÖÆÆ÷£¬Ó²¼þ״̬ºÍIRQ numberÖ®¼äµÄ¹ØÏµ·Ç³£¼òµ¥¡£µ«ÊÇʵ¼ÊÉÏ£¬ARMƽ̨ÉϵÄÓ²¼þÖжÏϵͳÒѾÊÇÔ½À´Ô½¸´ÔÓÁË£¬ÐèÒªÒýÈëinterrupt
controller¼¶Áª£¬irq domainµÈµÈ¸ÅÄÒò´Ë£¬Ê¹ÓõÚÒ»ÖÖ·½·¨Óŵã¸ü¶à¡£
3¡¢µ±·¢ÉúÖжϵÄʱºò£¬´úÂëÔËÐÐÔÚÄں˿ռä
Èç¹ûÖжϷ¢ÉúÔÚÄں˿ռ䣬´úÂë»áÌø×ªµ½__irq_svc´¦Ö´ÐУº
.align 5
__irq_svc:
svc_entry££££±£´æ·¢ÉúÖжÏÄÇÒ»¿ÌµÄÏÖ³¡±£´æÔÚÄÚºËÕ»ÉÏ
irq_handler ££££¾ßÌåµÄÖжϴ¦Àí£¬Í¬user modeµÄ´¦Àí¡£
#ifdef CONFIG_PREEMPT££££££££ºÍpreemptÏà¹ØµÄ´¦Àí
get_thread_info tsk
ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
ldr r0, [tsk, #TI_FLAGS] @ get flags
teq r8, #0 @ if preempt count != 0
movne r0, #0 @ force flags to 0
tst r0, #_TIF_NEED_RESCHED
blne svc_preempt
#endif
svc_exit r5, irq = 1 @ return from exception |
Ò»¸ötaskµÄthread infoÊý¾Ý½á¹¹¶¨ÒåÈçÏ£¨Ö»±£ÁôºÍ±¾³¡¾°Ïà¹ØµÄÄÚÈÝ£©£º
struct thread_info
{
unsigned long flags; /* low level flags */
int preempt_count; /* 0 => preemptable, <0
=> bug */
¡¡
}; |
flag³ÉÔ±ÓÃÀ´±ê¼ÇһЩlow levelµÄflag£¬¶øpreempt_countÓÃÀ´Åжϵ±Ç°ÊÇ·ñ¿ÉÒÔ·¢ÉúÇÀÕ¼£¬Èç¹ûpreempt_count²»µÈÓÚ0£¨¿ÉÄÜÊÇ´úÂëµ÷ÓÃpreempt_disableÏÔʽµÄ½ûÖ¹ÁËÇÀÕ¼£¬Ò²¿ÉÄÜÊÇ´¦ÓÚÖжÏÉÏÏÂÎĵȣ©£¬ËµÃ÷µ±Ç°²»ÄܽøÐÐÇÀÕ¼£¬Ö±½Ó½øÈë»Ö¸´ÏÖ³¡µÄ¹¤×÷¡£Èç¹ûpreempt_countµÈÓÚ0£¬ËµÃ÷ÒѾ¾ß±¸ÁËÇÀÕ¼µÄÌõ¼þ£¬µ±È»¾ßÌåÊÇ·ñÒªÇÀÕ¼µ±Ç°½ø³Ì»¹ÊÇÒª¿´¿´thread
infoÖеÄflag³ÉÔ±ÊÇ·ñÉ趨ÁË_TIF_NEED_RESCHEDÕâ¸ö±ê¼Ç£¨¿ÉÄÜÊǵ±Ç°µÄ½ø³ÌµÄʱ¼äƬÓÃÍêÁË£¬Ò²¿ÉÄÜÊÇÓÉÓÚÖжϻ½ÐÑÁËÓÅÏȼ¶¸ü¸ßµÄ½ø³Ì£©¡£
±£´æÏÖ³¡µÄ´úÂëºÍuser modeϵÄÏÖ³¡±£´æÊÇÀàËÆµÄ£¬Òò´ËÕâÀï²»ÔÙÏêϸÃèÊö£¬Ö»ÊÇÔÚÏÂÃæµÄ´úÂëÖÐÄÚǶһЩעÊÍ¡£
.macro svc_entry,
stack_hole=0
sub sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)££££spÖ¸Ïòstruct
pt_regsÖÐr1µÄλÖÃ
stmia sp, {r1 - r12} ££££££¼Ä´æÆ÷ÈëÕ»¡£
ldmia r0, {r3 - r5}
add r7, sp, #S_SP - 4 ££££££r7Ö¸Ïòstruct pt_regsÖÐr12µÄλÖÃ
mov r6, #-1 ££££££££££orig r0ÉèΪ-1
add r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)££££r2ÊÇ·¢ÏÖÖжÏÄÇÒ»¿ÌstackµÄÏÖ³¡
str r3, [sp, #-4]! ££££±£´ær0£¬×¢ÒâÓÐÒ»¸ö£¡£¬sp»á¼ÓÉÏ4£¬Õâʱºòsp¾ÍÖ¸ÏòÕ»¶¥µÄr0λÖÃÁË
mov r3, lr ££££±£´æsvc modeµÄlrµ½r3
stmia r7, {r2 - r6} £££££££££Ñ¹Õ»£¬ÔÚÕ»ÉÏÐγÉÐγÉstruct
pt_regs
.endm |
ÖÁ´Ë£¬ÔÚÄÚºËÕ»Éϱ£´æÁËÍêÕûµÄÓ²¼þÉÏÏÂÎÄ¡£Êµ¼ÊÉϲ»µ«ÍêÕû£¬¶øÇÒ»¹ÓÐЩÈßÓ࣬ÒòΪÆäÖÐÓÐÒ»¸öorig_r0µÄ³ÉÔ±¡£Ëùνoriginal
r0¾ÍÊÇ·¢ÉúÖжÏÄÇÒ»¿ÌµÄr0Öµ£¬°´Àí˵£¬ARM_r0ºÍARM_ORIG_r0¶¼Ó¦¸ÃÊÇÓû§¿Õ¼äµÄÄǸör0¡£
ΪºÎÒª±£´æÁ½¸ör0ֵĨ£¿ÎªºÎÖжϽ«-1±£´æµ½ÁËARM_ORIG_r0λÖÃÄØ£¿Àí½âÕâ¸öÎÊÌâÐèÒªÌøÍÑÖжϴ¦ÀíÕâ¸öÖ÷Ì⣬ÎÒÃÇÀ´¿´ARMµÄϵͳµ÷Ó᣶ÔÓÚϵͳµ÷Óã¬Ëü
ºÍÖжϴ¦ÀíËäÈ»¶¼ÊÇcpuÒì³£´¦Àí·¶³ë£¬µ«ÊÇÒ»¸öÃ÷ÏԵIJ»Í¬ÊÇϵͳµ÷ÓÃÐèÒª´«µÝ²ÎÊý£¬·µ»Ø½á¹û¡£Èç¹û½øÐÐÕâÑùµÄ²ÎÊý´«µÝÄØ£¿¶ÔÓÚARM£¬µ±È»ÊǼĴæÆ÷ÁË£¬
ÌØ±ðÊÇ·µ»Ø½á¹û£¬±£´æÔÚÁËr0ÖС£¶ÔÓÚARM£¬r0¡«r7ÊǸ÷ÖÖcpu mode¶¼ÏàͬµÄ£¬ÓÃÓÚ´«µÝ²ÎÊý»¹ÊǺܷ½±ãµÄ¡£Òò´Ë£¬½øÈëϵͳµ÷ÓõÄʱºò£¬ÔÚÄÚºËÕ»Éϱ£´æÁË·¢Éúϵͳµ÷ÓÃÏÖ³¡µÄËùÓмĴæÆ÷£¬Ò»·½Ãæ±£´æÁËhardware
context£¬ÁíÍâÒ»·½Ã棬Ҳ¾ÍÊÇ»ñÈ¡ÁËϵͳµ÷ÓõIJÎÊý¡£·µ»ØµÄʱºò£¬½«·µ»ØÖµ·Åµ½r0¾ÍOKÁË¡£
¸ù¾ÝÉÏÃæµÄÃèÊö£¬r0ÓÐÁ½¸ö×÷Ó㬴«µÝ²ÎÊý£¬·µ»Ø½á¹û¡£µ±°Ñϵͳµ÷ÓõĽá¹û·Åµ½r0µÄʱºò£¬Í¨¹ýr0´«µÝµÄ²ÎÊýÖµ¾Í±»¸²¸ÇÁË¡£±¾À´£¬ÕâҲûÓÐʲô£¬µ«ÊÇÓÐЩ³¡ºÏÊÇÐèÒªÐèÒªÕâÁ½¸öÖµµÄ£º
1¡¢ptrace £¨ºÍdebuggerÏà¹Ø£¬ÕâÀï¾Í²»ÔÙÏêϸÃèÊöÁË£©
2¡¢system call restart £¨ºÍsignalÏà¹Ø£¬ÕâÀï¾Í²»ÔÙÏêϸÃèÊöÁË£©
ÕýÒòΪÈç´Ë£¬Ó²¼þÉÏÏÂÎĵļĴæÆ÷ÖÐr0ÓÐÁ½·Ý£¬ARM_r0ÊÇ´«µÝµÄ²ÎÊý£¬²¢¸´ÖÆÒ»·Ýµ½ARM_ORIG_r0£¬µ±ÏµÍ³µ÷Ó÷µ»ØµÄʱºò£¬ARM_r0ÊÇϵͳµ÷Óõķµ»ØÖµ¡£
OK£¬ÎÒÃÇÔٻص½ÖжÏÕâ¸öÖ÷Ì⣬ÆäʵÔÚÖжϴ¦Àí¹ý³ÌÖУ¬Ã»ÓÐʹÓÃARM_ORIG_r0Õâ¸öÖµ£¬µ«ÊÇ£¬ÎªÁË·ÀÖ¹system
call restart£¬¿ÉÒÔ¸³ÖµÎª·Çϵͳµ÷ÓúŵÄÖµ£¨ÀýÈç-1£©¡£
Îå¡¢ÖжÏÍ˳ö¹ý³Ì
ÎÞÂÛÊÇÔÚÄÚºË̬£¨°üÀ¨ÏµÍ³µ÷ÓúÍÖжÏÉÏÏÂÎÄ£©»¹ÊÇÓû§Ì¬£¬·¢ÉúÁËÖжϺ󶼻áµ÷ÓÃirq_handler½øÐд¦Àí£¬ÕâÀï»áµ÷ÓöÔÓ¦µÄirq
numberµÄhandler£¬´¦Àísoftirq¡¢tasklet¡¢workqueueµÈ£¨ÕâЩÄÚÈÝÁí¿ªÒ»¸öÎĵµÃèÊö£©£¬µ«ÎÞÂÛÈçºÎ£¬×îÖÕ¶¼ÊÇÒª·µ»Ø·¢ÉúÖжϵÄÏÖ³¡¡£
1¡¢ÖжϷ¢ÉúÔÚuser modeϵÄÍ˳ö¹ý³Ì£¬´úÂëÈçÏ£º
ENTRY(ret_to_user_from_irq)
ldr r1, [tsk, #TI_FLAGS]
tst r1, #_TIF_WORK_MASK£££££££££££££££A
bne work_pending
no_work_pending:
asm_trace_hardirqs_on ££££££ºÍirq flag traceÏà¹Ø£¬ÔÝÇÒÂÔ¹ý
/* perform architecture specific actions before
user return */
arch_ret_to_user r1, lr££££ÓÐЩӲ¼þƽ̨ÐèÒªÔÚÖжϷµ»ØÓû§¿Õ¼ä×öÒ»Ð©ÌØ±ð´¦Àí
ct_user_enter save = 0 ££££ºÍtrace contextÏà¹Ø£¬ÔÝÇÒÂÔ¹ý
restore_user_regs fast = 0, offset = 0££££££££££££B
ENDPROC(ret_to_user_from_irq)
ENDPROC(ret_to_user) |
A£ºthread_infoÖеÄflags³ÉÔ±ÖÐÓÐһЩlow levelµÄ±êʶ£¬Èç¹ûÕâЩ±êʶÉ趨Á˾ÍÐèÒª½øÐÐÒ»Ð©ÌØ±ðµÄ´¦Àí£¬ÕâÀï¼ì²âµÄflagÖ÷Òª°üÀ¨£º
#define _TIF_WORK_MASK
(_TIF_NEED_RESCHED | _TIF_SIGPENDING | _TIF_NOTIFY_RESUME) |
ÕâÈý¸öflag·Ö±ð±íʾÊÇ·ñÐèÒªµ÷¶È¡¢ÊÇ·ñÓÐÐźŴ¦Àí¡¢·µ»ØÓû§¿Õ¼ä֮ǰÊÇ·ñÐèÒªµ÷ÓÃcallbackº¯Êý¡£Ö»ÒªÓÐÒ»¸öflag±»É趨ÁË£¬³ÌÐò¾Í½øÈëwork_pendingÕâ¸ö·ÖÖ§£¨work_pendingº¯ÊýÐèÒª´«µÝÈý¸ö²ÎÊý£¬µÚÈý¸öÊDzÎÊýwhyÊDZêʶÄÄÒ»¸öϵͳµ÷Ó㬵±È»£¬ÎÒÃÇÕâÀï´«µÝµÄÊÇ0£©¡£
B£º´Ó×ÖÃæµÄÒâ˼Ҳ¿ÉÒÔ¿´³É£¬Õⲿ·ÖµÄ´úÂë¾ÍÊǽ«½øÈëÖжϵÄʱºò±£´æµÄÏÖ³¡£¨¼Ä´æÆ÷Öµ£©»Ö¸´µ½Êµ¼ÊµÄARMµÄ¸÷¸ö¼Ä´æÆ÷ÖУ¬´Ó¶øÍêÈ«·µ»Øµ½ÁËÖжϷ¢ÉúµÄÄÇÒ»µã¡£¾ßÌåµÄ´úÂëÈçÏ£º
.macro restore_user_regs,
fast = 0, offset = 0
ldr r1, [sp, #\offset + S_PSR] ££££r1±£´æÁËpt_regsÖеÄspsr£¬Ò²¾ÍÊÇ·¢ÉúÖжÏʱµÄCPSR
ldr lr, [sp, #\offset + S_PC]! ££££lr±£´æÁËPCÖµ£¬Í¬Ê±spÒÆ¶¯µ½ÁËpt_regsÖÐPCµÄλÖÃ
msr spsr_cxsf, r1 £££££££££¸³Öµ¸øspsr£¬½øÐзµ»ØÓû§¿Õ¼äµÄ×¼±¸
clrex @ clear the exclusive monitor
.if \fast
ldmdb sp, {r1 - lr}^ @ get calling r1 - lr
.else
ldmdb sp, {r0 - lr}^ ££££££½«±£´æÔÚÄÚºËÕ»ÉϵÄÊý¾Ý±£´æµ½Óû§Ì¬µÄr0¡«r14¼Ä´æÆ÷
.endif
mov r0, r0 £££££££££NOP²Ù×÷£¬ARMv5T֮ǰµÄÐèÒªÕâ¸ö²Ù×÷
add sp, sp, #S_FRAME_SIZE - S_PC££££ÏÖ³¡ÒѾ»Ö¸´£¬Òƶ¯svc
modeµÄspµ½ÔÀ´µÄλÖÃ
movs pc, lr ££££££££·µ»ØÓû§¿Õ¼ä
.endm |
2¡¢ÖжϷ¢ÉúÔÚsvc modeϵÄÍ˳ö¹ý³Ì¡£¾ßÌå´úÂëÈçÏ£º
.macro svc_exit,
rpsr, irq = 0
.if \irq != 0
@ IRQs already off
.else
@ IRQs off again before pulling preserved data
off the stack
disable_irq_notrace
.endif
msr spsr_cxsf, \rpsr£££££££½«ÖжÏÏÖ³¡µÄcpsrÖµ±£´æµ½spsrÖУ¬×¼±¸·µ»ØÖжϷ¢ÉúµÄÏÖ³¡
ldmia sp, {r0 - pc}^ £££££ÕâÌõÖ¸ÁîÊÇldmÒì³£·µ»ØÖ¸ÁÕâÌõÖ¸Áî³ýÁË×ÖÃæÉϵIJÙ×÷£¬
»¹°üÀ¨Á˽«spsr copyµ½cpsrÖС£
.endm |
|