Gossip
In the past, the X86 analysis of the kernel, do development, trouble shooting, for other architectures to learn less, for the new structure of learning, and even some resistance, this time to analyze the problem of the opportunity to study the arm architecture of the basic knowledge, the right to take notes.
Here is the AArch32 architecture (that is, 32-bit, behind are all shortened to arm), relatively simple, essential to get started. ARM Processor Mode
Before introducing security extensions, ARM had 7 processor modes, 6 of which were privileged mode, and the other was the unprivileged mode that ran for the user program. In privileged mode, you can do things that you can't do in user mode, such as MMU configuration and cache operation.
Mode |
Function |
Privilege |
User (USR) |
Mode in which most programs and applications run |
unprivileged |
FIQ |
Entered on a FIQ interrupt exception IRQ entered on an IRQ interrupt exception |
|
Supervisor (SVC) |
Entered on reset or when a supervisor call instruction (SVC) |
|
is executed |
|
|
Abort (ABT) |
Entered on a memory access exception Undef (UND) entered when a undefined instruction |
|
System (SYS) |
Mode in which the OS runs, sharing the Register view |
|
The Trustzone security extensions introduces two types of secure states, independent of patterns, and a new monitor pattern. So there are 8 kinds of CPU modes.
In the Trustzone Security extensions environment, the system is enhanced by dividing all hardware and software resources by device. When the CPU is in normal (non-secure) state, it cannot access the memory allocated under secure state.
The current processor mode, determined by the value of the CPSR (current program status register) register, changes the CPU mode can be set by the privileged software display of the register, can also be triggered by the exception (after an exception, the CPU will automatically switch to the corresponding mode). Register Device
The ARM architecture provides 16 32-bit general-purpose registers (R0-R15) and r0-r14 can be used as a common data store.
R15 is a PC register, modifying the R15 can change the execution flow of the program. The PC value points to the address plus 8 of the current execution instruction, and the PC is read/write restricted.
R14 also known as LR (Link register), usually used to save the return address of the current function (the previous function), when it is idle, can also be used as a normal register. Each model has its own independent (physical) R14.
R13, also known as the SP, is the stack-top pointer used to hold the stack, which can also be used as a normal register when it is idle. Each exception pattern has its own independent R13, which usually points to a stack dedicated to the exception pattern. When arm into the abnormal mode, the program can put the general register into the stack, back to the stack, to ensure that the state of the program in various modes of integrity.
The program can also access CPSR,SPSR is a copy of CPSR in the previous execution mode.
Although the software can access these registers, however, in different modes, the actual physical storage location of some registers may be different, that is to say, in different modes, partial registers (except R0-7 and R15) are physically different (although the software is transparent and the software sees the same logical registers), These registers can only be accessed in the appropriate mode.
Program Status Registers. CPSR for storage: Flags, current CPU mode, interrupt disable tag, current CPU state, and so on. In user mode, the CPSR corresponding registers are APSR (restricted version of CPSR). coprocessor
CP15, a system control coprocessor, is used to control core requirements, including C0-C15 main 32-bit registers, which are often also accessed by name, such as CP15.SCTLR Cache
The common cache architecture in arm is as follows:
Cache Problem
Let the program execution time become unknown.
It is not acceptable for systems that require high real-time performance.
Peripherals need to use up-to-date data, need cache control. other
Tag takes up physical space, but is not counted in cache size
Invalidate operation: Lose cache.
Clean operation: The dirty data is brushed into memory to ensure consistency. Point of coherency and unification
For Set/way based clean and invalidate, the operation are performed on a specific level of cache. For operations this use a virtual address, the architecture defines two conceptual points: Point of coherency (PoC)
For a particular address, the PoC are the point in which all blocks, for example,cores, DSPs, or DMA engines, which can acce SS memory are guaranteed to thesame copy of a memory location. Typically, this would be the main external systemmemory. Point of Unification (PoU)
The PoU for a core are the point at which the instruction and data caches of the Coreare guaranteed to the same copy of A memory location. For example, a Unifiedlevel 2 cache would to the point of unification in a system with Harvard level 1caches and a TLB for Cacheing translation table entries. If no external cache ispresent, main memory would is the point of the unification.
The ARM64 contains several types of exceptions: interrupts (interrupts), the interrupts we normally understand, are triggered primarily by peripherals, and are typical asynchronous exceptions. ARM64 includes two types of interrupts: IRQ (normal interrupts) and Fiq (high priority interrupts, faster processing). Linux kernel does not seem to use the Fiq, not to look at the code carefully, specifically not detailed. Aborts. may be a synchronous or asynchronous exception. This includes instruction exceptions (generated when instructions are taken), data exceptions (generated when reading and writing memory data), can be generated by MMU (such as a typical page fault exception), or can be generated by an external storage system (usually a hardware issue). Reset. The reset is treated as a special exception. Exception generating instructions. Exceptions triggered by an exception trigger instruction, such as supervisor call (SVC), Hypervisor call (HVC), Secure Monitor Call (SMC) exception level (EL)
In arm, the exception is divided by the level, as shown in the following figure, as long as the attention:
Ordinary user program is in EL0, lowest level
The kernel is in El1,hyperv and the el2,el1-3 is at the privileged level.
Exception Handling
The exception handling process in arm is similar to the X86, also includes the hardware Auto-complete part and the software part, also needs to set the interrupt vector, saves the context, the different exception type processing method may have the slight difference. Not in detail here.
Attention needs to be paid to: User State (EL0) cannot handle exceptions, and when an exception occurs in a user state, the exception level (EL) is switched and the default switch to EL1 (kernel state) occurs. Interrupt Vector Table
The interrupt vector table in the Arm64 architecture is somewhat special (as opposed to X86 ~), contains 16 entry, 16 entry are grouped into 4 groups, each containing 4 entry, 4 entry in each group corresponding to 4 types of exceptions: Serror FIQ IRQ Synchronous aborts
The 4-group classification differs according to whether an exception level switch occurs when an exception occurs, and when the stack pointer is used. Corresponds to the following 4 groups: The exception occurs at the current level and uses sp_el0 (the stack pointer corresponding to the EL0 level), that is, when an exception occurs without an exception level switch, it can be simply understood that the exception occurs in the kernel State (EL1) and uses the SP corresponding to the EL0 level. This situation is not substantively processed in the Linux kernel and goes directly into the Bad_mode () process. The exception occurs at the current level and uses Sp_elx (the stack pointer corresponding to the ELX level, x may be 1, 2, 3), where an exception occurs without an exception level switch, which can be easily understood as an exception occurring in the kernel State (EL1) and using the SP corresponding to the EL1 level. This is a more common scenario. The exception occurs at a lower level and the AARCH64 mode is used for exception handling. It can be simply understood that the exception occurs in the user state and that when the kernel handles the exception, the AArch64 execution mode (AARCH32 mode) is used. This is also a more common scenario. The exception occurs at a lower level and the AARCH32 mode is used for exception handling. It can be simply understood that the exception occurs in the user state and that when the kernel handles the exception, the AArch32 execution mode (AArch64 mode) is used. This scenario is largely unhandled. Code Analysis
# # Interrupt Vector table
In the Linux kernel, the interrupt vector table is implemented in entry. s file, the code is as follows:
* * * Exception vectors. */. Align/*el1 represents the kernel state, el0 on behalf of the user state * * ENTRY (vectors) ventry el1_sync_invalid//Synchronous el1t, Ventry el1_irq_i Nvalid//IRQ el1t ventry el1_fiq_invalid//Fiq el1t//Kernel State system Error, using sp_el0 (User state stack)/Ventry el1_error_inval ID//Error el1t ventry el1_sync//synchronous el1h Ventry EL1_IRQ//IRQ el1h Ventry// FIQ el1h/* Kernel State system Error, using Sp_el1 (kernel stack)/ventry el1_error_invalid//Error el1h ventry el0_sync//Synchron ous 64-bit EL0 ventry EL0_IRQ//IRQ 64-bit EL0 ventry el0_fiq_invalid//Fiq 64-bit/* User State System Error, using S P_el1 (kernel state stack)/ventry el0_error_invalid//Error 64-bit EL0 #ifdef config_compat ventry el0_sync_compat//SYNCHR Onous 32-bit EL0 ventry el0_irq_compat//IRQ 32-bit EL0 ventry el0_fiq_invalid_compat//Fiq 32-bit EL0 E L0_error_invalid_compat//Error 32-bit EL0 #else ventry el0_sync_invalid//synchronous 32-bit EL0 Ventry-el0_Irq_invalid//IRQ 32-bit EL0 ventry el0_fiq_invalid//Fiq 32-bit EL0 ventry-el0_error_invalid//Error 32-bit E
L0 #endif End (vectors)
The grouping and categorization can be clearly seen. Invalid class processing
The vector with the invalid suffix is a vector that Linux does not do further processing, the default will enter the Bad_mode () process, indicating that this kind of abnormal Linux kernel can not be processed, can only be escalated to the user process (user state, Sigkill or sigbus signal) or Die (kernel state)
Vectors with invalid suffixes eventually call the Inv_entry,inv_entry implementation as follows:
* * Invalid mode handlers
/
/*invalid class exception is handled here, the unified call Bad_mode function * *
. Macro inv_entry, El, Reason, Regsize =
kernel_entry el, \regsize/
* Incoming bad_mode three parameters/
mov x0, SP
/*reason by the upper level incoming * *
mov x1, #\reason
/*esr_el1 is EL1 (kernel state)-level ESR (abnormal State Register), used to record the details of the exception, the specific content of the resolution needs to refer to the hardware manual/
Mrs x2, ESR_ EL1/
* Call Bad_mode function/
b bad_mode
. Endm
Call Bad_mode, a C function, that notifies the user of the state process or the panic.
* * Bad_mode handles the impossible case in the exception vector.
* *
asmlinkage void Bad_mode (struct pt_regs *regs, int reason, unsigned int esr)
{
siginfo_t info;
/* The PC pointer to get an exception/
void __user *pc = (void __user *) instruction_pointer (regs);
Console_verbose ();
/* Print exception information, which can be seen in messages. * *
Pr_crit ("Bad mode in%s handler detected, code 0x%08x--%s\n",
Handler[reason], ESR, esr_get_class_string (es R));
/* Print Register content * *
__show_regs (regs);
* If occurs in the user state, need to send a signal to it, in this case, send sigill signal, so there will be no core file produced * *
Info.si_signo = Sigill;
Info.si_errno = 0;
Info.si_code = ill_illopc;
Info.si_addr = PC;
/* Give a signal to the user-state process, or die then panic*/
arm64_notify_die ("Oops-bad mode", Regs, &info, 0);
Arm64_notify_die:
void Arm64_notify_die (const char *str, struct pt_regs *regs,
struct siginfo *info, int err)
{/
* If the context in which an exception occurs is in the user state, send a signal to the corresponding user-state process *
/if (User_mode (regs)) {
current->thread.fault_address = 0;
Current->thread.fault_code = err;
Force_sig_info (Info->si_signo, info, current);
} else {
///If it is a kernel state, direct die will eventually panic*/
die (str, regs, err);
}
IRQ Interrupt Handling
Scene in the scene (regardless of EL2 and EL3), IRQ processing is divided into two situations: the user state of the interruption and the loss of the kernel state, the corresponding interrupt processing interface, respectively:
El0_sync
El1_sync
The corresponding code is as follows:
El1_sync:
. align 6
EL1_IRQ:/
* Save Interrupt Context/
Kernel_entry 1
enable_dbg
#ifdef config_trace_irqflags
bl trace_hardirqs_off
#endif/
* Call Interrupt handling Default function * * *
irq_handler/
* If support preemption, handle slightly complex * *
ifdef config_preempt
get_thread_info tsk
ldr w24 , [tsk, #TI_PREEMPT] //Get preempt Count
CBNZ W24, 1f //Preempt count!= 0
Ldr x0, [tsk, #TI_FLAGS] //Get FLAGS
tbz x0, #TIF _need_resched, 1f //needs rescheduling?
BL el1_preempt
1:
#endif
#ifdef config_trace_irqflags
bl trace_hardirqs_on
# endif
/* Recovery context
/* Kernel_exit 1
endproc (EL1_IRQ)
The code is very simple, the main is to invoke the Irq_handler () function, do not do in-depth parsing, you are interested to look at the code.
El0_sync processing is similar, the main difference is that it involves user state and kernel state of context switching and recovery.
. align 6
EL0_IRQ:
kernel_entry 0
el0_irq_naked:
enable_dbg
#ifdef config_trace_ Irqflags
bl trace_hardirqs_off
#endif/
* Exit User context */
ct_user_exit
irq_handler
#ifdef config_trace_irqflags
bl trace_hardirqs_on
#endif/
* Return User state */
b ret_to_user
Endproc (EL0_IRQ)
Original address: https://happyseeker.github.io/kernel/2016/03/05/ARM-Cortex-A-programming-mannual-notes.html