[커널 18차] 76-77주차
2022.11.12 22:24
exception 완료
git :
https://github.com/iamroot18/5.10/commit/6de3bb5187eae9aa69a7a6bc570683c1bc91a8cb
https://github.com/iamroot18/5.10/commit/920b07300f7a0c3ea533d136bcefc91baec01e55
https://github.com/iamroot18/5.10/commit/81c78bfa7d4c45af6dfb1961c1d61c209dbda755
https://github.com/iamroot18/5.10/commit/be82bd40a371a05391f890dd255a5050f0411889
https://github.com/iamroot18/5.10/commit/829397b8e9a9a45fa55f40e98cfe06aa4a5f936d
https://github.com/iamroot18/5.10/commit/6096d76e81813bcb33e9f5f227b21a490fcd1b1a
diff --git a/README.md b/README.md
index 9dacd6ea30e0..3b3d290c097b 100644
--- a/README.md
+++ b/README.md
@@ -331,3 +331,7 @@
- 2022.10.29, Zoom 온라인(6명 참석)
- gicv3 - gic_of_init() 진행중
+### 76주차
+- 2022.11.05, Zoom 온라인(5명 참석)
+- exception 부터 irq 처리 흐름 진행중
+
diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h
index 1771cd2e5d38..1d752c3fb5ed 100644
--- a/arch/arm64/include/asm/arch_gicv3.h
+++ b/arch/arm64/include/asm/arch_gicv3.h
@@ -38,6 +38,11 @@ static __always_inline void gic_write_dir(u32 irq)
isb();
}
+/*
+ * IAMROOT, 2022.11.05:
+ * Interrupt Controller Interrupt Acknowledge Register를 읽어
+ * 인터럽트 번호를 알아온다.
+ */
static inline u64 gic_read_iar_common(void)
{
u64 irqstat;
@@ -168,13 +173,17 @@ static inline u32 gic_read_rpr(void)
/*
* IAMROOT, 2022.10.08:
- * - priority masking 지원여부 확인.
+ * - GIC의 priority masking 지원여부 확인.
*/
static inline bool gic_prio_masking_enabled(void)
{
return system_uses_irq_prio_masking();
}
+/*
+ * IAMROOT, 2022.11.05:
+ * Pesudo-NMI 지원하는 시스템에서 일반 인터럽트를 disable 한다.
+ */
static inline void gic_pmr_mask_irqs(void)
{
BUILD_BUG_ON(GICD_INT_DEF_PRI < (__GIC_PRIO_IRQOFF |
@@ -195,6 +204,10 @@ static inline void gic_pmr_mask_irqs(void)
gic_write_pmr(GIC_PRIO_IRQOFF);
}
+/*
+ * IAMROOT, 2022.11.05:
+ * DAIF중 I와 F를 클리어한다.
+ */
static inline void gic_arch_enable_irqs(void)
{
asm volatile ("msr daifclr, #3" : : : "memory");
diff --git a/arch/arm64/include/asm/asm-uaccess.h b/arch/arm64/include/asm/asm-uaccess.h
index ccedf548dac9..98cc8cb94662 100644
--- a/arch/arm64/include/asm/asm-uaccess.h
+++ b/arch/arm64/include/asm/asm-uaccess.h
@@ -12,6 +12,14 @@
* User access enabling/disabling macros.
*/
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+/*
+ * IAMROOT, 2022.11.08:
+ * - uaccess(user access)
+ * 1. ttbr1_el1의 값을 가져와 asid를 지우고, reserved_pg_dir을 ttbr0_el1에 set한다.
+ * 2. ttbr1_e1에도 reserved asid(0 clear)로 set한다.
+ * ttbr0_el1에 asid가 0가된 reserved_pg_dir을 가리키게 함으로써 kernel이
+ * user space에 접근하는것을 막는다.
+ */
.macro __uaccess_ttbr0_disable, tmp1
mrs \tmp1, ttbr1_el1 // swapper_pg_dir
bic \tmp1, \tmp1, #TTBR_ASID_MASK
diff --git a/arch/arm64/include/asm/asm_pointer_auth.h b/arch/arm64/include/asm/asm_pointer_auth.h
index f1bba5fc61c4..c4ec2c138fdc 100644
--- a/arch/arm64/include/asm/asm_pointer_auth.h
+++ b/arch/arm64/include/asm/asm_pointer_auth.h
@@ -9,6 +9,11 @@
#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
+/*
+ * IAMROOT, 2022.11.08:
+ * - @tsk에서 thread.keys_kernel.apia의 lo, hi를 를 가져와서
+ * SYS_APIAKEYLO_EL1, SYS_APIAKEYHI_EL1에 넣는다.
+ */
.macro __ptrauth_keys_install_kernel_nosync tsk, tmp1, tmp2, tmp3
mov \tmp1, #THREAD_KEYS_KERNEL
add \tmp1, \tsk, \tmp1
@@ -48,6 +53,15 @@ alternative_else_nop_endif
* thread.keys_user.ap* as offset exceeds the #imm offset range
* so use the base value of ldp as thread.keys_user and offset as
* thread.keys_user.ap*.
+ */
+/*
+ * IAMROOT, 2022.11.09:
+ * - papago
+ * thread.keys_user.ap*는 오프셋이 #imm 오프셋 범위를 초과하므로 ldp의 기본 값을
+ * thread.keys_user로 사용하고 오프셋을 thread.keys_user.ap*으로 사용합니다.
+ *
+ * - @tsk에서 thread.keys_user.apia의 lo, hi를 를 가져와서
+ * SYS_APIAKEYLO_EL1, SYS_APIAKEYHI_EL1에 넣는다.
*/
.macro __ptrauth_keys_install_user tsk, tmp1, tmp2, tmp3
mov \tmp1, #THREAD_KEYS_USER
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 06951ebfe90a..11b59cc4e258 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -81,6 +81,12 @@
msr daifclr, #8
.endm
+/*
+ * IAMROOT, 2022.11.05:
+ * thread_info->flags에서 TIF_SINGLESTEP 플래그가 있는 경우에 한해
+ * software step control을 disable한다.
+ * (mdscr_el1.ss 비트를 clear한다.)
+ */
.macro disable_step_tsk, flgs, tmp
tbz \flgs, #TIF_SINGLESTEP, 9990f
mrs \tmp, mdscr_el1
@@ -90,6 +96,12 @@
9990:
.endm
+/*
+ * IAMROOT, 2022.11.05:
+ * thread_info->flags에서 TIF_SINGLESTEP 플래그가 있는 경우에 한해
+ * software step control을 enable한다.
+ * (mdscr_el1.ss 비트를 set한다.)
+ */
/* call with daif masked */
.macro enable_step_tsk, flgs, tmp
tbz \flgs, #TIF_SINGLESTEP, 9990f
@@ -324,6 +336,12 @@ alternative_endif
* @sym: The name of the per-cpu variable
* @tmp: scratch register
*/
+/*
+ * IAMROOT, 2022.11.07:
+ * - @sym에 대한 pcpu address를 가져온다.
+ * - @tmp 임시 변수. cpu offset을 저장해놓는다.
+ * dst = adr_l(sym) + tmp
+ */
.macro ldr_this_cpu dst, sym, tmp
adr_l \dst, \sym
get_this_cpu_offset \tmp
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index e1c79406d464..bccec8a412b7 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -69,6 +69,13 @@
* and 0 otherwise.
*/
#define array_index_mask_nospec array_index_mask_nospec
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - 0 <= idx < sz
+ * 범위내라면 ~0
+ * - sz보다 크면 0으로 고정시킨다.
+ */
static inline unsigned long array_index_mask_nospec(unsigned long idx,
unsigned long sz)
{
diff --git a/arch/arm64/include/asm/daifflags.h b/arch/arm64/include/asm/daifflags.h
index 57b269c81ad3..76081f86a16e 100644
--- a/arch/arm64/include/asm/daifflags.h
+++ b/arch/arm64/include/asm/daifflags.h
@@ -13,12 +13,21 @@
#include <asm/ptrace.h>
#define DAIF_PROCCTX 0
+/*
+ * IAMROOT, 2022.11.07:
+ * - irq, fiq disable
+ */
#define DAIF_PROCCTX_NOIRQ (PSR_I_BIT | PSR_F_BIT)
#define DAIF_ERRCTX (PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)
#define DAIF_MASK (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)
/* mask/save/unmask/restore all exceptions, including interrupts. */
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - irq disable
+ */
static inline void local_daif_mask(void)
{
WARN_ON(system_has_prio_mask_debugging() &&
diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index 29f97eb3dad4..c7bb3f3c0e3c 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -39,6 +39,11 @@
#define ESR_ELx_EC_FPAC (0x1C) /* EL1 and above */
/* Unallocated EC: 0x1D - 0x1E */
#define ESR_ELx_EC_IMP_DEF (0x1f) /* EL3 only */
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - LOW : low exception level
+ */
#define ESR_ELx_EC_IABT_LOW (0x20)
#define ESR_ELx_EC_IABT_CUR (0x21)
#define ESR_ELx_EC_PC_ALIGN (0x22)
@@ -102,6 +107,10 @@
#define ESR_ELx_S1PTW (UL(1) << ESR_ELx_S1PTW_SHIFT)
/* Shared ISS fault status code(IFSC/DFSC) for Data/Instruction aborts */
+/*
+ * IAMROOT, 2022.11.12:
+ * - ISS의 Data Fault Status Code.
+ */
#define ESR_ELx_FSC (0x3F)
#define ESR_ELx_FSC_TYPE (0x3C)
#define ESR_ELx_FSC_LEVEL (0x03)
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index c586cc0caf3c..bbfe40ceaf47 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -285,6 +285,10 @@
#define THREAD_ALIGN THREAD_SIZE
#endif
+/*
+ * IAMROOT, 2022.11.08:
+ * - THREAD_SIZE == page size
+ */
#define IRQ_STACK_SIZE THREAD_SIZE
#define OVERFLOW_STACK_SIZE SZ_4K
@@ -350,12 +354,22 @@
* Open-coded (swapper_pg_dir - reserved_pg_dir) as this cannot be calculated
* until link time.
*/
+/*
+ * IAMROOT, 2022.11.10:
+ * - vmlinux.lds.S를 참고하면 reserved_이 swapper_pg_dir에서 PAGE_SIZE만큼
+ * 멀리있다.
+ */
#define RESERVED_SWAPPER_OFFSET (PAGE_SIZE)
/*
* Open-coded (swapper_pg_dir - tramp_pg_dir) as this cannot be calculated
* until link time.
*/
+/*
+ * IAMROOT, 2022.11.10:
+ * - vmlinux.lds.S를 참고하면 tramp_pg_dir이 swapper_pg_dir에서 2 PAGE_SIZE만큼
+ * 멀리있다.
+ */
#define TRAMP_SWAPPER_OFFSET (2 * PAGE_SIZE)
#ifndef __ASSEMBLY__
@@ -412,6 +426,13 @@ static inline unsigned long kaslr_offset(void)
* up with a tagged userland pointer. Clear the tag to get a sane pointer to
* pass on to access_ok(), for instance.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - papago
+ * 데이터 중단, 감시점 또는 명령 트랩을 처리할 때 태그가 지정된 사용자
+ * 영역 포인터로 끝날 수 있습니다. 예를 들어 access_ok()에 전달할 정상적인
+ * 포인터를 얻으려면 태그를 지우십시오.
+ */
#define __untagged_addr(addr) \
((__force __typeof__(addr))sign_extend64((__force u64)(addr), 55))
diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
index e9c30859f80c..1495c294264f 100644
--- a/arch/arm64/include/asm/mmu.h
+++ b/arch/arm64/include/asm/mmu.h
@@ -9,6 +9,9 @@
#define MMCF_AARCH32 0x1 /* mm context flag for AArch32 executables */
#define USER_ASID_BIT 48
+/*
+ * IAMROOT, 2022.11.10:
+ * - */
#define USER_ASID_FLAG (UL(1) << USER_ASID_BIT)
#define TTBR_ASID_MASK (UL(0xffff) << 48)
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 496dcebcb8c8..043dc88e8fd9 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -345,6 +345,14 @@ long get_tagged_addr_ctrl(struct task_struct *task);
BUG_ON(!on_accessible_stack(current, current_stack_pointer, 1, &_info)); \
_info.high; \
})
+
+/*
+ * IAMROOT, 2022.11.05:
+ * 현재 태스크가 가리키는 스택 범위에 current_stack_pointer가 포함되는지
+ * 여부를 알아온다.
+ * - current_stack_pointer(arch/arm64/include/asm/stack_pointer.h)
+ * asm("sp")
+ */
#define on_thread_stack() (on_task_stack(current, current_stack_pointer, 1, NULL))
#endif /* __ASSEMBLY__ */
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 61617c32301e..9cf85b2eddc9 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -59,6 +59,12 @@
* 명시적으로 요구합니다. 비트 GIC_PRIO_PSR_I_SET이 우선 순위 마스크에 포함되어 있으면
* PSR.I가 설정되어야 하고 일시적으로 인터럽트 비활성화가 IRQ 우선 순위에 의존하지
* 않음을 나타냅니다.
+ * --------
+ *
+ * GIC_PRIO_IRQON 0b1110_0000
+ * __GIC_PRIO_IRQOFF 0b0110_0000
+ * __GIC_PRIO_IRQOFF_NS 0b1010_0000
+ * GIC_PRIO_PSR_I_SET 0b0001_0000
*/
#define GIC_PRIO_IRQON 0xe0
#define __GIC_PRIO_IRQOFF (GIC_PRIO_IRQON & ~0x80)
@@ -74,7 +80,7 @@
* ..
* 0b1110_0000 0xe0 enable (0b1110_0000) 0b1111_0000 0xf0
* ^
- * | 이 부분을 dsiable
+ * | 이 부분을 disable
* v
* 0b1010_0000 0xa0 normal irq(GICD_INT_DEF_PRI) 0b1101_0000 0xd0
* 0b1010_0000 0xa0 disable (__GIC_PRIO_IRQOFF_NS)
@@ -176,6 +182,14 @@
*
* This must have the value -1, for ABI compatibility with ptrace etc.
*/
+/*
+ * IAMROOT, 2022.11.08:
+ * - papago
+ * pt_regs.syscallno == NO_SYSCALL이면 스레드가 시스템 호출을 실행하지 않는
+ * 것입니다.
+ *
+ * ptrace 등과의 ABI 호환성을 위해 이 값은 -1이어야 합니다.
+ */
#define NO_SYSCALL (-1)
#ifndef __ASSEMBLY__
@@ -254,6 +268,11 @@ struct pt_regs {
s32 syscallno;
u32 unused2;
#endif
+/*
+ * IAMROOT, 2022.11.05:
+ * Software_Delegated_Exception_Interface
+ */
+
u64 sdei_ttbr1;
/* Only valid when ARM64_HAS_IRQ_PRIO_MASKING is enabled. */
u64 pmr_save;
@@ -295,11 +314,23 @@ static inline void forget_syscall(struct pt_regs *regs)
#define processor_mode(regs) \
((regs)->pstate & PSR_MODE_MASK)
+/*
+ * IAMROOT, 2022.11.05:
+ * Pesudo-NMI를 사용할 때 irq가 unmask 상태인지 여부를 알아온다.
+ */
#define irqs_priority_unmasked(regs) \
(system_uses_irq_prio_masking() ? \
(regs)->pmr_save == GIC_PRIO_IRQON : \
true)
+/*
+ * IAMROOT, 2022.11.10:
+ * - !((regs)->pstate & PSR_I_BIT)
+ * I가 없고, 즉 daif의 interrupt가 켜져있고,
+ * - irqs_priority_unmasked(regs)
+ * PMR이 ON인 상태
+ * daif도 I가 꺼져있고 PMR도 ON이면 interrupt가 가능한 상태다.
+ */
#define interrupts_enabled(regs) \
(!((regs)->pstate & PSR_I_BIT) && irqs_priority_unmasked(regs))
@@ -366,6 +397,11 @@ static inline unsigned long pt_regs_read_reg(const struct pt_regs *regs, int r)
* Write a register given an architectural register index r.
* This handles the common case where 31 means XZR, not SP.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - @r registe numbver(X0~X30)
+ * @val register에 들어갈 값.
+ */
static inline void pt_regs_write_reg(struct pt_regs *regs, int r,
unsigned long val)
{
diff --git a/arch/arm64/include/asm/rwonce.h b/arch/arm64/include/asm/rwonce.h
index 1bce62fa908a..384cfb85c5b0 100644
--- a/arch/arm64/include/asm/rwonce.h
+++ b/arch/arm64/include/asm/rwonce.h
@@ -13,6 +13,27 @@
#ifndef BUILD_VDSO
#ifdef CONFIG_AS_HAS_LDAPR
+/*
+ * IAMROOT, 2022.11.11:
+ * - consistency
+ * https://www.youtube.com/watch?v=Fm8iUFM2iWU
+ * https://www.cs.colostate.edu/~cs551/CourseNotes/Consistency/TypesConsistency.html
+ * https://www.inf.ed.ac.uk/teaching/courses/pa/Notes/lecture07-sc.pdf
+ * https://www.youtube.com/watch?v=6OLnU27wDb0
+ * https://en.wikipedia.org/wiki/Release_consistency
+ *
+ * - processor consistency
+ * https://en.wikipedia.org/wiki/Processor_consistency
+ * process에 실행된 write의 순서가 다른 process에서 동일하게 read된다는것.
+ *
+ * - RCpc(release consistent processor consisten),
+ * RCsc (release consistent sequential consistent)
+ * https://stackoverflow.com/questions/68676666/armv8-3-meaning-of-rcpc
+ * https://www.hpl.hp.com/techreports/Compaq-DEC/WRL-95-7.pdf
+ *
+ * - ldapr(load acquire RCpc Register)
+ * https://www.dpdk.org/wp-content/uploads/sites/35/2019/10/StateofC11Code.pdf
+ */
#define __LOAD_RCPC(sfx, regs...) \
ALTERNATIVE( \
"ldar" #sfx "\t" #regs, \
@@ -33,6 +54,19 @@
* READ_ONCE() definition with one that provides RCpc acquire semantics
* when building with LTO.
*/
+/*
+ * IAMROOT, 2022.11.11:
+ * - papago
+ * LTO로 빌드할 때 컴파일러가 READ_ONCE() 호출이 이끄는 주소 종속성을 제어
+ * 종속성으로 변환하고 결과적으로 CPU에 의한 유해한 재정렬을 허용할 위험이
+ * 증가합니다.
+ *
+ * LTO로 구축할 때 RCpc 획득 의미 체계를 제공하는 일반 READ_ONCE() 정의를
+ * 재정의하여 이러한 변환이 무해한지 확인합니다.
+ *
+ * - LTO(Link Time Optimization)
+ * https://gcc.gnu.org/wiki/LinkTimeOptimization
+ */
#define __READ_ONCE(x) \
({ \
typeof(&(x)) __x = &(x); \
diff --git a/arch/arm64/include/asm/scs.h b/arch/arm64/include/asm/scs.h
index 8297bccf0784..54dd5ca7744a 100644
--- a/arch/arm64/include/asm/scs.h
+++ b/arch/arm64/include/asm/scs.h
@@ -8,11 +8,17 @@
#ifdef CONFIG_SHADOW_CALL_STACK
scs_sp .req x18
-
+/*
+ * IAMROOT, 2022.11.08:
+ * - x18에 thread_info.scs_sp 를 load
+ */
.macro scs_load tsk
ldr scs_sp, [\tsk, #TSK_TI_SCS_SP]
.endm
-
+/*
+ * IAMROOT, 2022.11.08:
+ * - x18을 thread_ifo.scs_sp 로 넣기.
+ */
.macro scs_save tsk
str scs_sp, [\tsk, #TSK_TI_SCS_SP]
.endm
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
index 6d1344a40010..8bde34c14954 100644
--- a/arch/arm64/include/asm/smp.h
+++ b/arch/arm64/include/asm/smp.h
@@ -107,6 +107,10 @@ extern void __cpu_die(unsigned int cpu);
extern void cpu_die(void);
extern void cpu_die_early(void);
+/*
+ * IAMROOT, 2022.11.07:
+ * - cpu park.
+ */
static inline void cpu_park_loop(void)
{
for (;;) {
diff --git a/arch/arm64/include/asm/spectre.h b/arch/arm64/include/asm/spectre.h
index f62ca39da6c5..e9c19e532a45 100644
--- a/arch/arm64/include/asm/spectre.h
+++ b/arch/arm64/include/asm/spectre.h
@@ -67,6 +67,11 @@ struct bp_hardening_data {
DECLARE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
+/*
+ * IAMROOT, 2022.11.05:
+ * SoC에 SPECTRE_V2 이슈가 있는 경우
+ * Branch predict 관련 취약점을 숨길 수 있는 콜백함수를 호출한다.
+ */
static inline void arm64_apply_bp_hardening(void)
{
struct bp_hardening_data *d;
diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h
index 8aebc00c1718..cac44fc5160e 100644
--- a/arch/arm64/include/asm/stacktrace.h
+++ b/arch/arm64/include/asm/stacktrace.h
@@ -69,6 +69,10 @@ extern void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk,
DECLARE_PER_CPU(unsigned long *, irq_stack_ptr);
+/*
+ * IAMROOT, 2022.11.05:
+ * 스택 포인터 + size가 low ~ high 범위에 있는지 여부를 알아온다.
+ */
static inline bool on_stack(unsigned long sp, unsigned long size,
unsigned long low, unsigned long high,
enum stack_type type, struct stack_info *info)
@@ -87,6 +91,10 @@ static inline bool on_stack(unsigned long sp, unsigned long size,
return true;
}
+/*
+ * IAMROOT, 2022.11.05:
+ * irq 전용 스택 범위에 스택 포인터 @sp + @size가 포함되는지 여부를 알아온다.
+ */
static inline bool on_irq_stack(unsigned long sp, unsigned long size,
struct stack_info *info)
{
@@ -96,6 +104,11 @@ static inline bool on_irq_stack(unsigned long sp, unsigned long size,
return on_stack(sp, size, low, high, STACK_TYPE_IRQ, info);
}
+/*
+ * IAMROOT, 2022.11.05:
+ * 태스크가 가리키는 스택 범위에 스택 포인터 @sp + @size가 포함되는지
+ * 여부를 알아온다.
+ */
static inline bool on_task_stack(const struct task_struct *tsk,
unsigned long sp, unsigned long size,
struct stack_info *info)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 5993d900f862..3444b95be800 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -23,6 +23,14 @@
* [11-8] : CRm
* [7-5] : Op2
*/
+/*
+ * IAMROOT, 2022.11.08:
+ * - 주석에 적혀있다 ARMv8 Ref System instruction class encoding overview 참고
+ * |31 30 29 28|27 26 25 24|23 22 21 20|19 18 16|15 12| 11 8| 7 5 4| 0|
+ * |1 1 0 1 0 1 0 1 0 0 |L | Op0 | OP1 | CRn | CRm | op2| Rt |
+ * __________ ___________
+ * d 5
+ */
#define Op0_shift 19
#define Op0_mask 0x3
#define Op1_shift 16
@@ -90,14 +98,49 @@
* CRm = Imm4 for the instruction.
* Rt = 0x1f
*/
+/*
+ * IAMROOT, 2022.11.08:
+ * - papago
+ * PSTATE 필드 수정 지침.
+ * Arm v8-A용 ARM ARM, 섹션 C.5.1.3 op0 == 0b00, 아키텍처 힌트,
+ * 장벽 및 CLREX, PSTATE 액세스, ARM DDI 0487 C.a에 따라 PSTATE 필드에
+ * 액세스하기 위한 시스템 명령어에는 다음 인코딩이 있습니다.
+ * Op0 = 0, CRn = 4Op1, Op2는 수정된 PSTATE 필드를 인코딩하고 제약 조건을
+ * 정의합니다.
+ * 명령의 경우 CRm = Imm4입니다.
+ * Rt = 0x1f.
+ */
#define pstate_field(op1, op2) ((op1) << Op1_shift | (op2) << Op2_shift)
#define PSTATE_Imm_shift CRm_shift
#define PSTATE_PAN pstate_field(0, 4)
#define PSTATE_UAO pstate_field(0, 3)
#define PSTATE_SSBS pstate_field(3, 1)
+/*
+ * IAMROOT, 2022.11.08:
+ * - TCO(Tag Check Override)
+ * https://developer.arm.com/documentation/ddi0601/2020-12/AArch64-Registers/TCO--Tag-Check-Override
+ * https://developer.arm.com/documentation/ddi0595/2021-06/AArch64-Registers/SPSR-EL1--Saved-Program-Status-Register--EL1-
+ * ARM ref. Chapter D6 Memory Tagging Extension
+ * Tag Check Override. Set to the value of PSTATE.TCO on taking an exception to
+ * EL1, and copied to PSTATE.TCO on executing an exception return operation in EL1.
+ * When FEAT_MTE2 is not implemented, it is CONSTRAINED UNPREDICTABLE whether
+ * this field is RES0 or behaves as if FEAT_MTE is implemented.
+ * - When the value of PSTATE.TCO is 1, all loads and stores are Tag Unchecked.
+ * - When PSTATE.TCO is 1, all loads and stores generate Tag Unchecked accesses.
+ * - set 0 : enable, set 1 : disable
+ */
#define PSTATE_TCO pstate_field(3, 4)
+/*
+ * IAMROOT, 2022.11.08:
+ * - ARMv8 Ref System instruction class encoding overview 참고
+ * |31 30 29 28|27 26 25 24|23 22 21 20|19 18 16|15 14 13 12| 11 8| 7 5 4|3 2 1 0|
+ * |1 1 0 1 0 1 0 1 0 0 |0 | 0 0 | OP1 | 0 1 0 0 | CRm | op2|1 1 1 1 1|
+ * Op0 CRn
+ * __________ ___________ ____________ _________ __________ ______ _____ _______
+ * d 5 0 0 4 0 1 f
+ */
#define SET_PSTATE_PAN(x) __emit_inst(0xd500401f | PSTATE_PAN | ((!!x) << PSTATE_Imm_shift))
#define SET_PSTATE_UAO(x) __emit_inst(0xd500401f | PSTATE_UAO | ((!!x) << PSTATE_Imm_shift))
#define SET_PSTATE_SSBS(x) __emit_inst(0xd500401f | PSTATE_SSBS | ((!!x) << PSTATE_Imm_shift))
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 6623c99f0984..fec3868dcdd3 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -60,6 +60,13 @@ int arch_dup_task_struct(struct task_struct *dst,
#endif
+/*
+ * IAMROOT, 2022.11.05:
+ * thread_info->flags에서 사용되는 플래그들
+ * 가장 대표적인 것인
+ * - TIF_SIGPENDING (태스크에 시그널이 pending 상태)
+ * - TIF_NEED_RESCHED (리스케쥴링 요청)
+ */
#define TIF_SIGPENDING 0 /* signal pending */
#define TIF_NEED_RESCHED 1 /* rescheduling necessary */
#define TIF_NOTIFY_RESUME 2 /* callback before returning to user */
@@ -103,6 +110,10 @@ int arch_dup_task_struct(struct task_struct *dst,
_TIF_UPROBE | _TIF_MTE_ASYNC_FAULT | \
_TIF_NOTIFY_SIGNAL)
+/*
+ * IAMROOT, 2022.11.12:
+ * - debug / log용
+ */
#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
_TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \
_TIF_SYSCALL_EMU)
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 868979dcbf4e..537ba887ed6c 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -3144,6 +3144,10 @@ static inline bool __attribute_const__ is_emulated(u32 id)
* With CRm == 0, reg should be one of :
* MIDR_EL1, MPIDR_EL1 or REVIDR_EL1.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - @id에 해당하는 value를 얻어온다.
+ */
static inline int emulate_id_reg(u32 id, u64 *valp)
{
switch (id) {
@@ -3164,6 +3168,10 @@ static inline int emulate_id_reg(u32 id, u64 *valp)
return 0;
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - @id에 해당하는 value를 찾아와서 @valp에 기록한다.
+ */
static int emulate_sys_reg(u32 id, u64 *valp)
{
struct arm64_ftr_reg *regp;
@@ -3186,6 +3194,10 @@ static int emulate_sys_reg(u32 id, u64 *valp)
return 0;
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - @sys_reg를 통해서 val을 얻어온후, regs에 기록한다.
+ */
int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt)
{
int rc;
@@ -3199,6 +3211,10 @@ int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt)
return rc;
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - mrs emulate.
+ */
static int emulate_mrs(struct pt_regs *regs, u32 insn)
{
u32 sys_reg, rt;
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index 09368e4c5092..f039f868d35f 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -347,6 +347,10 @@ static int brk_handler(unsigned long unused, unsigned int esr,
}
NOKPROBE_SYMBOL(brk_handler);
+/*
+ * IAMROOT, 2022.11.12:
+ * - arm32 break 관련 inst인지 확인
+ */
int aarch32_break_handler(struct pt_regs *regs)
{
u32 arm_instr;
diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c
index 32f9796c4ffe..d60985d55875 100644
--- a/arch/arm64/kernel/entry-common.c
+++ b/arch/arm64/kernel/entry-common.c
@@ -96,6 +96,14 @@ static void noinstr exit_to_kernel_mode(struct pt_regs *regs)
* Before this function is called it is not safe to call regular kernel code,
* intrumentable code, or any code which may trigger an exception.
*/
+/*
+ * IAMROOT, 2022.11.07:
+ * - papago
+ * 사용자 모드에서 진입할 때 IRQ/컨텍스트 상태 관리를 처리합니다.
+ * 이 함수가 호출되기 전에는 일반 커널 코드, 계측 가능 코드 또는 예외를
+ * 유발할 수 있는 모든 코드를 호출하는 것이 안전하지 않습니다.
+ * - dubug, context tracking 관련.
+ */
static __always_inline void __enter_from_user_mode(void)
{
lockdep_hardirqs_off(CALLER_ADDR0);
@@ -104,6 +112,10 @@ static __always_inline void __enter_from_user_mode(void)
trace_hardirqs_off_finish();
}
+/*
+ * IAMROOT, 2022.11.07:
+ * - irq 진입시 debug, context tracking 관련 처리.
+ */
static __always_inline void enter_from_user_mode(struct pt_regs *regs)
{
__enter_from_user_mode();
@@ -114,6 +126,10 @@ static __always_inline void enter_from_user_mode(struct pt_regs *regs)
* After this function returns it is not safe to call regular kernel code,
* intrumentable code, or any code which may trigger an exception.
*/
+/*
+ * IAMROOT, 2022.11.07:
+ * - irq 퇴장시 debug, context tracking 관련 처리.
+ */
static __always_inline void __exit_to_user_mode(void)
{
trace_hardirqs_on_prepare();
@@ -121,7 +137,10 @@ static __always_inline void __exit_to_user_mode(void)
user_enter_irqoff();
lockdep_hardirqs_on(CALLER_ADDR0);
}
-
+/*
+ * IAMROOT, 2022.11.07:
+ * - irq disable
+ */
static __always_inline void prepare_exit_to_user_mode(struct pt_regs *regs)
{
unsigned long flags;
@@ -133,6 +152,10 @@ static __always_inline void prepare_exit_to_user_mode(struct pt_regs *regs)
do_notify_resume(regs, flags);
}
+/*
+ * IAMROOT, 2022.11.07:
+ * - irq disable
+ */
static __always_inline void exit_to_user_mode(struct pt_regs *regs)
{
prepare_exit_to_user_mode(regs);
@@ -260,9 +283,33 @@ static void __sched arm64_preempt_schedule_irq(void)
preempt_schedule_irq();
}
+/*
+ * IAMROOT, 2022.11.08:
+ * - @handler 실행
+ * - irq 흐름.
+ * vectors(arch/arm64/kernel/entry.S)
+ * |
+ * |(kernel_ventry)
+ * |(entry_handler)
+ * |(el0_interrupt or el1_interrupt)
+ * |(do_interrupt_handler) <---------- 현재
+ * |(handler_arch_irq 실행) <----------/
+ * v
+ * chip handler(handler_arch_irq, gic의 경우 gic_handle_irq)
+ * v
+ * flow handler
+ * v
+ * irq_handler
+ */
static void do_interrupt_handler(struct pt_regs *regs,
void (*handler)(struct pt_regs *))
{
+/*
+ * IAMROOT, 2022.11.05:
+ * sp가 현재 태스크의 스택 포인터 범위안에 존재하는 경우
+ * call_on_irq_stack() 내부에서 전용 irq 스택에 LR, SP를 백업하고,
+ * handler(regs)를 호출한다.
+ */
if (on_thread_stack())
call_on_irq_stack(regs, handler);
else
@@ -457,6 +504,10 @@ asmlinkage void noinstr el1h_64_irq_handler(struct pt_regs *regs)
el1_interrupt(regs, handle_arch_irq);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - handler_arch_fiq실행
+ */
asmlinkage void noinstr el1h_64_fiq_handler(struct pt_regs *regs)
{
el1_interrupt(regs, handle_arch_fiq);
@@ -472,8 +523,16 @@ asmlinkage void noinstr el1h_64_error_handler(struct pt_regs *regs)
arm64_exit_nmi(regs);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - data fault
+ */
static void noinstr el0_da(struct pt_regs *regs, unsigned long esr)
{
+/*
+ * IAMROOT, 2022.11.12:
+ * - fault address register. fault 발생 주소를 가져온다.
+ */
unsigned long far = read_sysreg(far_el1);
enter_from_user_mode(regs);
@@ -482,6 +541,11 @@ static void noinstr el0_da(struct pt_regs *regs, unsigned long esr)
exit_to_user_mode(regs);
}
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - inst fault
+ */
static void noinstr el0_ia(struct pt_regs *regs, unsigned long esr)
{
unsigned long far = read_sysreg(far_el1);
@@ -500,6 +564,10 @@ static void noinstr el0_ia(struct pt_regs *regs, unsigned long esr)
exit_to_user_mode(regs);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - warnning을 띄운다.
+ */
static void noinstr el0_fpsimd_acc(struct pt_regs *regs, unsigned long esr)
{
enter_from_user_mode(regs);
@@ -553,6 +621,10 @@ static void noinstr el0_sp(struct pt_regs *regs, unsigned long esr)
exit_to_user_mode(regs);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - undef 처리.
+ */
static void noinstr el0_undef(struct pt_regs *regs)
{
enter_from_user_mode(regs);
@@ -588,6 +660,10 @@ static void noinstr el0_dbg(struct pt_regs *regs, unsigned long esr)
exit_to_user_mode(regs);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - syscall
+ */
static void noinstr el0_svc(struct pt_regs *regs)
{
enter_from_user_mode(regs);
@@ -604,51 +680,125 @@ static void noinstr el0_fpac(struct pt_regs *regs, unsigned long esr)
exit_to_user_mode(regs);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * -
+ */
asmlinkage void noinstr el0t_64_sync_handler(struct pt_regs *regs)
{
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - Exception Syndrome Register
+ */
unsigned long esr = read_sysreg(esr_el1);
switch (ESR_ELx_EC(esr)) {
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - systemcall
+ */
case ESR_ELx_EC_SVC64:
el0_svc(regs);
break;
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - data abort
+ */
case ESR_ELx_EC_DABT_LOW:
el0_da(regs, esr);
break;
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - inst abort
+ */
case ESR_ELx_EC_IABT_LOW:
el0_ia(regs, esr);
break;
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - advanced SIMD
+ */
case ESR_ELx_EC_FP_ASIMD:
el0_fpsimd_acc(regs, esr);
break;
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - SVE
+ */
case ESR_ELx_EC_SVE:
el0_sve_acc(regs, esr);
break;
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - float pointer
+ */
case ESR_ELx_EC_FP_EXC64:
el0_fpsimd_exc(regs, esr);
break;
+/*
+ * IAMROOT, 2022.11.12:
+ * - mrs/msr exception
+ */
case ESR_ELx_EC_SYS64:
+/*
+ * IAMROOT, 2022.11.12:
+ * - WFI,WFE exception
+ */
case ESR_ELx_EC_WFx:
el0_sys(regs, esr);
break;
+/*
+ * IAMROOT, 2022.11.12:
+ * - sp align
+ */
case ESR_ELx_EC_SP_ALIGN:
el0_sp(regs, esr);
break;
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - pc align
+ */
case ESR_ELx_EC_PC_ALIGN:
el0_pc(regs, esr);
break;
+/*
+ * IAMROOT, 2022.11.12:
+ * - undef inst
+ */
case ESR_ELx_EC_UNKNOWN:
el0_undef(regs);
break;
+/*
+ * IAMROOT, 2022.11.12:
+ * - byte top ignore
+ */
case ESR_ELx_EC_BTI:
el0_bti(regs);
break;
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - debug용
+ */
case ESR_ELx_EC_BREAKPT_LOW:
case ESR_ELx_EC_SOFTSTP_LOW:
case ESR_ELx_EC_WATCHPT_LOW:
case ESR_ELx_EC_BRK64:
el0_dbg(regs, esr);
break;
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - point authentication exception
+ */
case ESR_ELx_EC_FPAC:
el0_fpac(regs, esr);
break;
@@ -657,26 +807,59 @@ asmlinkage void noinstr el0t_64_sync_handler(struct pt_regs *regs)
}
}
+/*
+ * IAMROOT, 2022.11.07:
+ * - irq, fiq disable후 @handler 수행
+ */
static void noinstr el0_interrupt(struct pt_regs *regs,
void (*handler)(struct pt_regs *))
{
+/*
+ * IAMROOT, 2022.11.05:
+ * 유저에서 진입하여 irq 처리가 시작 되기 전 trace 출력 등
+ */
enter_from_user_mode(regs);
+/*
+ * IAMROOT, 2022.11.05:
+ * PSTATE의 DAIF 중 IF에 해당하는 irq & fiq를 1로 mask하여 두 기능을 disable한다.
+ */
write_sysreg(DAIF_PROCCTX_NOIRQ, daif);
if (regs->pc & BIT(55))
arm64_apply_bp_hardening();
+/*
+ * IAMROOT, 2022.11.05:
+ * 인터럽트 핸들러로 연동
+ */
do_interrupt_handler(regs, handler);
+/*
+ * IAMROOT, 2022.11.05:
+ * irq 처리가 끝난 후 유저로 빠져나갈때의 trace 출력 등
+ */
exit_to_user_mode(regs);
}
+/*
+ * IAMROOT, 2022.11.05:
+ * 인터럽트가 진입하는 경우 대표 인터럽트 컨트롤러의 핸들러로 향한다.
+ * 예) GICv3: gic_handle_irq
+ * - handle_arch_irq
+ * arch/arm64/kernel/irq.c
+ * gic의 경우 gic_init_bases-> set_handle_irq를 통해서 gic_handle_irq가 설정된다.
+ */
static void noinstr __el0_irq_handler_common(struct pt_regs *regs)
{
el0_interrupt(regs, handle_arch_irq);
}
+/*
+ * IAMROOT, 2022.11.05:
+ * 64bit user appl ----(irq)-----> vectors -> 아래 핸들러 호출
+ */
+
asmlinkage void noinstr el0t_64_irq_handler(struct pt_regs *regs)
{
__el0_irq_handler_common(regs);
@@ -793,6 +976,10 @@ UNHANDLED(el0t, 32, error)
#endif /* CONFIG_COMPAT */
#ifdef CONFIG_VMAP_STACK
+/*
+ * IAMROOT, 2022.11.07:
+ * - interrupt수행중 overflow_stack시 진입. arm64_enter_nmi, regs print후 죽는다
+ */
asmlinkage void noinstr handle_bad_stack(struct pt_regs *regs)
{
unsigned int esr = read_sysreg(esr_el1);
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index ece280f2f7bc..a9319d11a998 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -29,6 +29,10 @@
#include <asm/asm-uaccess.h>
#include <asm/unistd.h>
+/*
+ * IAMROOT, 2022.11.08:
+ * - x0 ~ x29까지 mov xN, xzr
+ */
.macro clear_gp_regs
.irp n,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29
mov x\n, xzr
@@ -40,10 +44,108 @@
* 인자로 만들어지는 branch 함수들은 entry_handler macro에 의해 만들어지는
* 함수들이며 결국 해당 함수에서 _handler가 붙은 함수를 호출한다.
* ex) el1h_64_sync -> el1h_64_sync_handler
+ */
+/*
+ * IAMROOT, 2022.11.07:
+ * - macro 정리
+ * el ht regsize label
+ * 1 t 64 sync
+ * 1 t 64 irq
+ * 1 t 64 fiq
+ * 1 t 64 error
+ *
+ * 1 h 64 sync
+ * 1 h 64 irq
+ * 1 h 64 fiq
+ * 1 h 64 error
+ *
+ * 0 t 64 sync
+ * 0 t 64 irq
+ * 0 t 64 fiq
+ * 0 t 64 error
+ *
+ * 0 t 32 sync
+ * 0 t 32 irq
+ * 0 t 32 fiq
+ * 0 t 32 error
+ * - ex) el1 64bit irq발생시 흐름
+ * vectors
+ * v
+ * kernel_ventry 1, h, 64, irq <--현재 여기
+ * v
+ * el1h_64_irq
+ * v
+ * kernel_entry 1, 64
+ * v
+ * el1h_64_irq_handler
+ * v
+ * (chip -> flow -> irq handler 수행후 복귀)
+ * v
+ * ret_to_kernel
+ *
+ * - irq 흐름.
+ * vectors(arch/arm64/kernel/entry.S)
+ * |
+ * |(kernel_ventry) <--현재 여기
+ * |(entry_handler)
+ * |(el0_interrupt or el1_interrupt)
+ * |(do_interrupt_handler)
+ * |(handler_arch_irq 실행)
+ * v
+ * chip handler(handler_arch_irq, gic의 경우 gic_handle_irq)
+ * v
+ * flow handler(handle_fasteoi_nmi()등)
+ * v
+ * irq_handler(user isr)
*/
.macro kernel_ventry, el:req, ht:req, regsize:req, label:req
.align 7
+/*
+ * IAMROOT, 2022.11.07:
+ * - UNMAP_KERNEL_AT_EL0
+ * bool "Unmap kernel when running in userspace (aka \"KAISER\")" if EXPERT
+ * default y
+ * help
+ * Speculation attacks against some high-performance processors can
+ * be used to bypass MMU permission checks and leak kernel data to
+ * userspace. This can be defended against by unmapping the kernel
+ * when running in userspace, mapping it back in on exception entry
+ * via a trampoline page in the vector table.
+ * -- papago
+ * 일부 고성능 프로세서에 대한 추측 공격은 MMU 권한 검사를 우회하고 커널
+ * 데이터를 사용자 공간으로 유출하는 데 사용할 수 있습니다. 이것은 사용자
+ * 공간에서 실행될 때 커널을 매핑 해제하고 벡터 테이블의 트램폴린 페이지를
+ * 통해 예외 항목에 다시 매핑하여 방어할 수 있습니다.
+ *
+ * user 영역에서 kernel영역이 보이지 않게 unmap을 하겠다는것.
+ */
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+/*
+ * IAMROOT, 2022.11.07:
+ * - tpidrro_el0은 원래용도로 사용안하고 scratch로 사용한다.
+ * - CONFIG_UNMAP_KERNEL_AT_EL0을 사용했다는건 exception이 tramp_ventry
+ * 를 통해서 진입을 한 상태고 tramp_ventry에서 tpidrro_el0에
+ * x30(lr)을 넣어놓은 상태이다. 해당 값을 x30으로 다시 가져오고
+ * tpidrro_el0를 지워놓는다.
+ *
+ * - tpidrro_el0의 원래 용도.
+ * TPIDRRO_EL0, EL0 Read-Only Software Thread ID Register
+ * 참고) https://developer.arm.com/documentation/ddi0601/2021-12/AArch64-Registers/TPIDRRO-EL0--EL0-Read-Only-Software-Thread-ID-Register
+ * Provides a location where software executing at EL1 or higher can store
+ * thread identifying information that is visible to software executing
+ * at EL0, for OS management purposes.
+ *
+ * The PE makes no use of this register.
+ * -- papago
+ * OS 관리 목적으로 EL1 이상에서 실행되는 소프트웨어가 EL0에서 실행하는
+ * 소프트웨어에 표시되는 스레드 식별 정보를 저장할 수 있는 위치를 제공합니다.
+ * PE는 이 레지스터를 사용하지 않습니다.
+ *
+ * -- Bits [63:0]
+ * Thread ID. Thread identifying information stored by software running at
+ * this Exception level.
+ *
+ */
.if \el == 0
alternative_if ARM64_UNMAP_KERNEL_AT_EL0
.if \regsize == 64
@@ -56,6 +158,10 @@ alternative_else_nop_endif
.endif
#endif
+/*
+ * IAMROOT, 2022.11.05:
+ * context save(모든 레지스터)를 위해 struct pt_regs 구조체 크기만 스택을 확보한다.
+ */
sub sp, sp, #PT_REGS_SIZE
#ifdef CONFIG_VMAP_STACK
/*
@@ -63,11 +169,69 @@ alternative_else_nop_endif
* Task and IRQ stacks are aligned so that SP & (1 << THREAD_SHIFT)
* should always be zero.
*/
+/*
+ * IAMROOT, 2022.11.07:
+ * -papago
+ * GPR을 손상시키지 않고 SP가 오버플로되었는지 테스트합니다.
+ * Task 및 IRQ 스택은 SP & (1 << THREAD_SHIFT)가 항상 0이 되도록 정렬됩니다.
+ *
+ * - x0에 stack size를 구한다. stack size는 THREAD_SHIFT로 정렬되잇다.
+ * THREAD_SHIFT bit가 깨지면 align이 깨졌다고 러프하게 판단한다.
+ *
+ * - sp <-> x0값을 교환해서 sp를 검사하는 방식으로 수행한다.
+ * register끼리의 교환이므로 속도가 빠르다.
+ *
+ * - add sp, sp, x0 --> sp : sp(old) + x0(old)
+ * sub x0, sp, x0 --> x0 : sp - x0(old) = sp(old) + x0(old) - x0(old) = sp(old).
+ * x0에 sp(old) 위치완료.
+ * tbnz x0, #THREAD_SHIFT, 0f --> x0(old sp) 의 THREAD_SHIFT bit 검사.
+ * 0가 아니면 깨진것으로 판단
+ * sub x0, sp, x0 --> x0 : sp - x0 = (sp(old) + x0(old)) - sp(old) = x0(old)
+ * x0원복 완료
+ * sub sp, sp, x0 --> sp : sp - x0(old) = sp(old) + x0(old) - x0(old)
+ * sp 원복 완료
+ */
add sp, sp, x0 // sp' = sp + x0
sub x0, sp, x0 // x0' = sp' - x0 = (sp + x0) - x0 = sp
tbnz x0, #THREAD_SHIFT, 0f
sub x0, sp, x0 // x0'' = sp' - x0' = (sp + x0) - sp = x0
sub sp, sp, x0 // sp'' = sp' - x0 = (sp + x0) - x0 = sp
+/*
+ * IAMROOT, 2022.11.07:
+ * - entry_handler 참고
+ * el1t_64_sync
+ * el1t_64_irq
+ * el1t_64_fiq
+ * el1t_64_error
+ *
+ * el1h_64_sync
+ * el1h_64_irq
+ * el1h_64_fiq
+ * el1h_64_error
+ *
+ * el0t_64_sync
+ * el0t_64_irq
+ * el0t_64_fiq
+ * el0t_64_error
+ *
+ * el0t_32_sync
+ * el0t_32_irq
+ * el0t_32_fiq
+ * el0t_32_error
+ *
+ * - ex) el1 64bit irq발생시 flow
+ * vectors
+ * v
+ * kernel_ventry 1, h, 64, irq
+ * v
+ * el1h_64_irq <-- 여기로 이제 진입.
+ * v
+ * kernel_entry 1, 64
+ * v
+ * el1h_64_irq_handler
+ * v
+ * ret_to_kernel
+ */
b el\el\ht\()_\regsize\()_\label
0:
@@ -78,19 +242,52 @@ alternative_else_nop_endif
*/
/* Stash the original SP (minus PT_REGS_SIZE) in tpidr_el0. */
+/*
+ * IAMROOT, 2022.11.07:
+ * - papago
+ * 방금 오버플로를 감지했거나 오버플로 스택에서 예외가 발생했습니다.
+ * 어느 쪽이든, 우리는 사용자 공간으로 돌아가지 않을 것이며 GPR을 해제하기
+ * 위해 EL0 레지스터를 방해할 수 있습니다.
+ *
+ * 원래 SP(PT_REGS_SIZE 빼기)를 tpidr_el0에 숨깁니다.
+ * - 여기 라벨이 온시점에 x0엔 sp가 있을것이다. 그걸 tpidr_el0로 넣어놓는다.
+ */
msr tpidr_el0, x0
/* Recover the original x0 value and stash it in tpidrro_el0 */
+/*
+ * IAMROOT, 2022.11.07:
+ * - x0도 원래의 x0값으로 원복해주고 tpidrro_el0에 넣어놓는다.
+ */
sub x0, sp, x0
msr tpidrro_el0, x0
/* Switch to the overflow stack */
+/*
+ * IAMROOT, 2022.11.07:
+ * - adr_this_cpu
+ * arch/arm64/include/asm/stacktrace.h 에 pcpu로 overflow_stack이 정의되있다.
+ * 현재 cpu에 대한 pcpu address를 가져온다.
+ * - overflow_stack + OVERFLOW_STACK_SIZE 의 현재 cpu에 대한 pcpu address를
+ * 가져와 sp로 사용한다.
+ * x0는 임시변수로 쓴다.
+ */
adr_this_cpu sp, overflow_stack + OVERFLOW_STACK_SIZE, x0
/*
* Check whether we were already on the overflow stack. This may happen
* after panic() re-enables interrupts.
*/
+/*
+ * IAMROOT, 2022.11.07:
+ * - tpider_el0에 저장되있는 old sp를 가져와서 현재 sp와 비교한다
+ * OVERFLOW_STACK_SIZE보다 차이가 안난다면 overflow stack처리과정에서 다시한번
+ * overflow stack처리로 진입하게 된것이다.
+ *
+ * - tst is 0 => 이미 overflow_stack 진입한 상태. __bad_stack으로
+ * 안가고 entry_handler로 간다. 어짜피 곧 죽을거 적당히 처리하는듯.
+ * not 0 => overflow_stack으로 진입하기 시작. __bad_stack으로 이동한다.
+ */
mrs x0, tpidr_el0 // sp of interrupted context
sub x0, sp, x0 // delta with top of overflow stack
tst x0, #~(OVERFLOW_STACK_SIZE - 1) // within range?
@@ -100,9 +297,19 @@ alternative_else_nop_endif
sub sp, sp, x0
mrs x0, tpidrro_el0
#endif
+/*
+ * IAMROOT, 2022.11.05:
+ * 예) el0 64bit user -----(irq)----> b el0t_64_irq
+ * entry_handler 참고
+ */
+
b el\el\ht\()_\regsize\()_\label
.endm
+/*
+ * IAMROOT, 2022.11.09:
+ * - TRAMP_VALIAS + offset으로 sym의 주소를 얻어온다.
+ */
.macro tramp_alias, dst, sym
mov_q \dst, TRAMP_VALIAS
add \dst, \dst, #(\sym - .entry.tramp.text)
@@ -112,6 +319,11 @@ alternative_else_nop_endif
* This macro corrupts x0-x3. It is the caller's duty to save/restore
* them if required.
*/
+/*
+ * IAMROOT, 2022.11.08:
+ * - SSBD(Speculative Store Bypass Disabl)
+ * - SKIP
+ */
.macro apply_ssbd, state, tmp1, tmp2
alternative_cb spectre_v4_patch_fw_mitigation_enable
b .L__asm_ssbd_skip\@ // Patched to NOP
@@ -129,6 +341,17 @@ alternative_cb_end
.endm
/* Check for MTE asynchronous tag check faults */
+/*
+ * IAMROOT, 2022.11.08:
+ * - async tag check fault mode 인지 확인.
+ * 맞다면 SYS_TFSR_EL1_TF0_SHIFT를 검사했는지 확인하고 발생했으면
+ * ti-flags에 _TIF_MTE_ASYNC_FAULT를 추가한다.
+ *
+ * - tcf(tag check fault)
+ * Documentation/arm64/memory-tagging-extension.rst
+ * - SCTLR_EL1_TCF0_SHIFT + 1가 set됬으면
+ * Tag Check Faults are asynchronously accumulated.
+ */
.macro check_mte_async_tcf, tmp, ti_flags, thread_sctlr
#ifdef CONFIG_ARM64_MTE
.arch_extension lse
@@ -140,18 +363,41 @@ alternative_else_nop_endif
* ASYM (3) modes. In each of these modes bit 1 of SCTLR_EL1.TCF0 is
* set, so skip the check if it is unset.
*/
+/*
+ * IAMROOT, 2022.11.08:
+ * - papago
+ * 비동기식 태그 검사 오류는 ASYNC(2) 또는 ASYM(3) 모드에서만 가능합니다.
+ * 이러한 각 모드에서 SCTLR_EL1.TCF0의 비트 1이 설정되므로 설정되지 않은 경우
+ * 확인을 건너뜁니다.
+ * - async tcf mode인지 확인한다. 아니면 1f로 이동하고 종료
+ */
tbz \thread_sctlr, #(SCTLR_EL1_TCF0_SHIFT + 1), 1f
mrs_s \tmp, SYS_TFSRE0_EL1
+/*
+ * IAMROOT, 2022.11.08:
+ * - SYS_TFSR_EL1_TF0_SHIFT를 검사한다. set되있다면 async tcf가 발생한것이므로
+ * ti_flags에 _TIF_MTE_ASYNC_FAULT flag bit를 추가해준다. 이는 추후 처리된다.
+ */
tbz \tmp, #SYS_TFSR_EL1_TF0_SHIFT, 1f
/* Asynchronous TCF occurred for TTBR0 access, set the TI flag */
mov \tmp, #_TIF_MTE_ASYNC_FAULT
add \ti_flags, tsk, #TSK_TI_FLAGS
+/*
+ * IAMROOT, 2022.11.08:
+ * - stset
+ * ti_flags |= tmp
+ * https://developer.arm.com/documentation/dui0801/g/A64-Data-Transfer-Instructions/STSET--STSETL--STSETL
+ */
stset \tmp, [\ti_flags]
1:
#endif
.endm
/* Clear the MTE asynchronous tag check faults */
+/*
+ * IAMROOT, 2022.11.09:
+ * - async2, async3 mode인지 판단하여 clear
+ */
.macro clear_mte_async_tcf thread_sctlr
#ifdef CONFIG_ARM64_MTE
alternative_if ARM64_MTE
@@ -172,6 +418,10 @@ alternative_else_nop_endif
#endif
.endm
+/*
+ * IAMROOT, 2022.11.08:
+ * - kernel의 gcr 설정값을 hw에 적용한다.
+ */
.macro mte_set_kernel_gcr, tmp, tmp2
#ifdef CONFIG_KASAN_HW_TAGS
alternative_if_not ARM64_MTE
@@ -183,6 +433,10 @@ alternative_else_nop_endif
#endif
.endm
+/*
+ * IAMROOT, 2022.11.09:
+ * - user(tsk)의 gcr 설정값을 hw에 적용한다.
+ */
.macro mte_set_user_gcr, tsk, tmp, tmp2
#ifdef CONFIG_ARM64_MTE
alternative_if_not ARM64_MTE
@@ -195,7 +449,20 @@ alternative_else_nop_endif
#endif
.endm
+/*
+ * IAMROOT, 2022.11.05:
+ * - @x0 pt_regs 저장할 주소
+ * exception이 발생하여 context 를 백업한다. (전체 레지스터)
+ * 그 외 mte, ptr_auth, hw debuger 관련 동작 등을 체크한다.
+ */
.macro kernel_entry, el, regsize = 64
+/*
+ * IAMROOT, 2022.11.05:
+ * 32bit 유저에서 진입한 경우 x0의 상위 32비트를 클리어한다.
+ * - pt_regs 상태
+ * regs[0~28] = registers
+ * regs[29] = x29(fp)
+ */
.if \regsize == 32
mov w0, w0 // zero upper 32 bits of x0
.endif
@@ -215,7 +482,23 @@ alternative_else_nop_endif
stp x26, x27, [sp, #16 * 13]
stp x28, x29, [sp, #16 * 14]
+/*
+ * IAMROOT, 2022.11.08:
+ * - el0
+ */
.if \el == 0
+/*
+ * IAMROOT, 2022.11.08:
+ * 1. x0~x29 clear
+ * 2. sp_el0를 x21에 backup
+ * 3. tsk(x29), sp_el0 에 pcp __entry_task(armch/arm64/process.c) 를 가져온다.
+ * (pcp task_struct *)
+ * - sp_el0
+ * user에서 kernel mode를 진입할때 current task를 저장하고 kernel mode에서는
+ * 현재 thread_info를 빠르게 알아내는 용도로 사용한다.
+ * 4. ss(debug single step), MTE, PAC, SCS, SSBD 처리
+ *
+*/
clear_gp_regs
mrs x21, sp_el0
ldr_this_cpu tsk, __entry_task, x20
@@ -226,12 +509,26 @@ alternative_else_nop_endif
* when scheduling.
*/
ldr x19, [tsk, #TSK_TI_FLAGS]
+/*
+ * IAMROOT, 2022.11.09:
+ * - ret_to_user등에서 다시 enable한다.
+ */
disable_step_tsk x19, x20
/* Check for asynchronous tag check faults in user space */
ldr x0, [tsk, THREAD_SCTLR_USER]
check_mte_async_tcf x22, x23, x0
+/*
+ * IAMROOT, 2022.11.08:
+ * - PAC(Pointer Authentication)
+ * Documentation/arm64/pointer-authentication.rst
+ * https://www.kernel.org/doc/html/latest/arm64/pointer-authentication.html
+ * https://community.arm.com/arm-community-blogs/b/tools-software-ides-blog/posts/code-reuse-attacks-the-compiler-story
+ * - ENAI
+ * Controls enabling of pointer authentication (using the APIAKey_EL1 key)
+ * of instruction addresses in the EL1&0 translation regime.
+ */
#ifdef CONFIG_ARM64_PTR_AUTH
alternative_if ARM64_HAS_ADDRESS_AUTH
/*
@@ -243,6 +540,18 @@ alternative_if ARM64_HAS_ADDRESS_AUTH
* was disabled on kernel exit then we would have left the kernel IA
* installed so there is no need to install it again.
*/
+/*
+ * IAMROOT, 2022.11.08:
+ * - papago
+ * task에서 비활성화된 경우 커널 내 PAC에 대해 IA를 활성화합니다. 이것은
+ * 부하를 피하는 무조건적인 MRS로 구현할 수 있지만 Cortex-A75 및
+ * Cortex-A76에서 더 느린 것으로 측정되었습니다.
+ *
+ * task에서 IA가 활성화된 경우에만 커널 IA 키를 설치합니다. kernel exit시
+ * IA가 비활성화된 경우 커널 IA가 설치된 상태로남아 있으므로 다시 설치할
+ * 필요가 없습니다.
+ * - PAC IA가 disable되있다면 install한다.
+ */
tbz x0, SCTLR_ELx_ENIA_SHIFT, 1f
__ptrauth_keys_install_kernel_nosync tsk, x20, x22, x23
b 2f
@@ -262,6 +571,10 @@ alternative_else_nop_endif
* Any non-self-synchronizing system register updates required for
* kernel entry should be placed before this point.
*/
+/*
+ * IAMROOT, 2022.11.08:
+ * - MTE, PAC 둘중하나라도 사용중이라면 isb를 한번 하겠다는것.
+ */
alternative_if ARM64_MTE
isb
b 1f
@@ -272,10 +585,27 @@ alternative_else_nop_endif
1:
scs_load tsk
+/*
+ * IAMROOT, 2022.11.08:
+ * - el1
+ * 1. el0와는 다르게 register clear를 안한다.
+ * 2. sp를 x21에 백업한다.
+ * 3. task를 current task로 그대로 사용한다.
+ */
.else
add x21, sp, #PT_REGS_SIZE
get_current_task tsk
.endif /* \el == 0 */
+/*
+ * IAMROOT, 2022.11.08:
+ * - elr_el1, spsr_el1을 x22, x23에 백업한다.
+ * - lr, x21(backup sp)를 sp(pt_regs.regs[30], pt_regs.sp)에 backup한다.
+ * - pt_regs 상태
+ * regs[0~28] = registers
+ * regs[29] = x29(fp)
+ * regs[30] = lr
+ * sp = sp(before) + PT_REGS_SIZE
+ */
mrs x22, elr_el1
mrs x23, spsr_el1
stp lr, x21, [sp, #S_LR]
@@ -285,6 +615,22 @@ alternative_else_nop_endif
* For exceptions from EL1, create a synthetic frame record so the
* interrupted code shows up in the backtrace.
*/
+/*
+ * IAMROOT, 2022.11.08:
+ * - papago
+ * EL0의 예외에 대해 최종 프레임 레코드를 생성합니다.
+ * EL1 예외의 경우 중단된 코드가 역추적에 표시되도록 합성 프레임 레코드를
+ * 만듭니다.
+ *
+ * - el1인 경우 fp, elr_el1이 backup될것이다.
+ * - pt_regs 상태
+ * regs[0~28] = registers
+ * regs[29] = x29(fp)
+ * regs[30] = lr
+ * sp = sp(before) + PT_REGS_SIZE
+ * stackframe[0] = el0: 0, el1: fp
+ * stackframe[1] = el0: 0, el1: elr_el1
+ */
.if \el == 0
stp xzr, xzr, [sp, #S_STACKFRAME]
.else
@@ -294,10 +640,26 @@ alternative_else_nop_endif
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
alternative_if_not ARM64_HAS_PAN
+/*
+ * IAMROOT, 2022.11.08:
+ * - el1인 경우 이미 disabled 됬을 경우 x23(backup spsr)에 PSR_PAN_BIT가
+ * 추가될 수 있다.
+ */
bl __swpan_entry_el\el
alternative_else_nop_endif
#endif
-
+/*
+ * IAMROOT, 2022.11.08:
+ * - pt_regs 상태
+ * regs[0~28] = registers
+ * regs[29] = x29(fp)
+ * regs[30] = lr
+ * sp = sp(before) + PT_REGS_SIZE
+ * stackframe[0] = el0: 0, el1: fp
+ * stackframe[1] = el0: 0, el1: elr_el1
+ * pc = elr_el1
+ * pstate = spsr
+ */
stp x22, x23, [sp, #S_PC]
/* Not in a syscall by default (el0_svc overwrites for real syscall) */
@@ -305,17 +667,53 @@ alternative_else_nop_endif
mov w21, #NO_SYSCALL
str w21, [sp, #S_SYSCALLNO]
.endif
+/*
+ * IAMROOT, 2022.11.08:
+ * - pt_regs 상태
+ * regs[0~28] = registers
+ * regs[29] = x29(fp)
+ * regs[30] = lr
+ * sp = sp + PT_REGS_SIZE
+ * stackframe[0] = el0: 0, el1: fp
+ * stackframe[1] = el0: 0, el1: elr_el1
+ * pc = elr_el1
+ * pstate = spsr
+ * syscallno = el0 : -1
+ */
/* Save pmr */
alternative_if ARM64_HAS_IRQ_PRIO_MASKING
mrs_s x20, SYS_ICC_PMR_EL1
+/*
+ * IAMROOT, 2022.11.08:
+ * - pt_regs 상태
+ * regs[0~28] = registers
+ * regs[29] = x29(fp)
+ * regs[30] = lr
+ * sp = sp + PT_REGS_SIZE
+ * stackframe[0] = el0: 0, el1: fp
+ * stackframe[1] = el0: 0, el1: elr_el1
+ * pc = elr_el1
+ * pstate = spsr
+ * syscallno = el0 : -1
+ * pmr_save = SYS_ICC_PMR_EL1(before)
+ */
str x20, [sp, #S_PMR_SAVE]
+/*
+ * IAMROOT, 2022.11.08:
+ * - git blame 참고
+ * debug시 경고문때문인듯 하며 local_daif_save와 일관성을 유지한다.
+ */
mov x20, #GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET
msr_s SYS_ICC_PMR_EL1, x20
alternative_else_nop_endif
/* Re-enable tag checking (TCO set on exception entry) */
#ifdef CONFIG_ARM64_MTE
+/*
+ * IAMROOT, 2022.11.09:
+ * - set 0 를 함으로써 enable시킨다.
+ */
alternative_if ARM64_MTE
SET_PSTATE_TCO(0)
alternative_else_nop_endif
@@ -331,11 +729,25 @@ alternative_else_nop_endif
*/
.endm
+/*
+ * IAMROOT, 2022.11.05:
+ * exceptino 처리 후 커널 또는 유저로 복귀하기 전에 수행할 루틴
+ * - kernel_entry에서 백업해뒀던 값들을 복구한다.
+ */
.macro kernel_exit, el
+/*
+ * IAMROOT, 2022.11.05:
+ * 커널로 북귀하는 경우 DAIF 플래그를 모두 disable 한다.
+ * el0의 경우 handler에서 이미 disable했었다.
+ */
.if \el != 0
disable_daif
.endif
+/*
+ * IAMROOT, 2022.11.05:
+ * kernel_entry에서 backup해두었던 pmr을 다시 복구한다.
+ */
/* Restore pmr */
alternative_if ARM64_HAS_IRQ_PRIO_MASKING
ldr x20, [sp, #S_PMR_SAVE]
@@ -348,18 +760,40 @@ alternative_else_nop_endif
ldp x21, x22, [sp, #S_PC] // load ELR, SPSR
+/*
+ * IAMROOT, 2022.11.05:
+ * ttbr0를 조작하는 방법으로 즉, sw emulation 방법으로 커널에서 유저 영역의
+ * 가상 주소에 접근하지 못하게 한다.
+ * (최신 armv8에는 hardware 방식의 PAN 방식을 지원한다)
+ */
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
alternative_if_not ARM64_HAS_PAN
bl __swpan_exit_el\el
alternative_else_nop_endif
#endif
+/*
+ * IAMROOT, 2022.11.05:
+ * 유저용 sp를 복구한다.
+ */
+
.if \el == 0
ldr x23, [sp, #S_SP] // load return stack pointer
msr sp_el0, x23
+/*
+ * IAMROOT, 2022.11.10:
+ * - x22에 #PSR_MODE32_BIT set.
+ * tst => 1 => Z 0 => b.eq동작안함
+ * - x22에 #PSR_MODE32_BIT unset
+ * tst => 0 => Z 1 => b.eq동작.
+ */
tst x22, #PSR_MODE32_BIT // native task?
b.eq 3f
+/*
+ * IAMROOT, 2022.11.05:
+ * 32bit 유저로 돌아가는 경우에만 workaround 코드를 수행한다.
+ */
#ifdef CONFIG_ARM64_ERRATUM_845719
alternative_if ARM64_WORKAROUND_845719
#ifdef CONFIG_PID_IN_CONTEXTIDR
@@ -371,8 +805,16 @@ alternative_if ARM64_WORKAROUND_845719
alternative_else_nop_endif
#endif
3:
+/*
+ * IAMROOT, 2022.11.05:
+ * shadow call stack 커널 옵션을 사용하는 경우엔 관련 정보도 복구한다.
+ */
scs_save tsk
+/*
+ * IAMROOT, 2022.11.05:
+ * mte 관련
+ */
/* Ignore asynchronous tag check faults in the uaccess routines */
ldr x0, [tsk, THREAD_SCTLR_USER]
clear_mte_async_tcf x0
@@ -402,6 +844,10 @@ alternative_else_nop_endif
apply_ssbd 0, x0, x1
.endif
+/*
+ * IAMROOT, 2022.11.05:
+ * 나머지 레지스터들을 복구한다.
+ */
msr elr_el1, x21 // set up the return data
msr spsr_el1, x22
ldp x0, x1, [sp, #16 * 0]
@@ -425,23 +871,72 @@ alternative_else_nop_endif
.if \el == 0
alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+/*
+ * IAMROOT, 2022.11.09:
+ * - el0
+ * ARM64_UNMAP_KERNEL_AT_EL0가 없으면 eret을 하며 user로 복귀.
+ * 그게 아니면 nop가 대신 한번 실행되면서 해당 처리를 해준다.
+ * kernel_ventry에서 64bit인경우 x30에 tramp_ventry에서 저장해놨던 lr,
+ * 32bit인경우 0를 저장해 놨엇다.
+ * - trampoline
+ * https://en.wikipedia.org/wiki/Trampoline_(computing)
+ * https://xiayingp.gitbook.io/build_a_os/traps-and-interrupts/untitled-3
+ *
+ * - 위에 tst x22, #PSR_MODE32_BIT
+ * 이 code에서 user mode가 32bit인지 64bit인지 확인한채로 Z가
+ * 그대로 있는상태다.
+ * 64bit면 tramp_exit_native, 32bit면 tramp_exit_compat.
+ * - far_el1은 scratch register로 사용한다. x30(tramp_ventry에서 가져온 lr)을 여기서
+ * far_el1에 넣어놓는다.
+ * x30을 계속 다른용도로 사용해야되기 때문이다.
+ */
bne 4f
msr far_el1, x30
+/*
+ * IAMROOT, 2022.11.09:
+ * - 각각의 가상주소를 가져와서 br tramp_exit_native, tramp_exit_compat로 넘어간다.
+ * - 해당함수에서 eret이 일어난다.
+ */
tramp_alias x30, tramp_exit_native
br x30
4:
tramp_alias x30, tramp_exit_compat
br x30
#endif
+/*
+ * IAMROOT, 2022.11.09:
+ * - el1인 경우 eret으로 el1 -> el1으로 복귀 되거나 할것이다.
+ */
.else
/* Ensure any device/NC reads complete */
alternative_insn nop, "dmb sy", ARM64_WORKAROUND_1508412
eret
.endif
+/*
+ * IAMROOT, 2022.11.09:
+ * - SB(Speculation Barrier) sequence
+ * (Git blame 참고, ARM ref. Speculation Barrier (SB) 참고)
+ * https://developer.arm.com/documentation/ddi0597/2022-06/Base-Instructions/SB--Speculation-Barrier-
+ * - eret의 뒤에 보통 위치한다. 일부 cpu에서 eret지점에서 낮은 권한 수준에 의해 제어되고,
+ * eret이 수행되기전에 memory speculative access가 수행될수있어 side-channel공격에
+ * 사용될수 있다고 한다.
+ * sb 명령을 사용함으로 이전 명령어가 완료될때까지 speculative를 실행할수없게한다.
+ * - What is speculative execution?
+ * https://www.extremetech.com/computing/261792-what-is-speculative-execution
+ * - isb, dsb, sb
+ * 처음에 isb, dsb에서 i,d를 뺀거인줄알았는데 아니였다.
+ * sb : Speculation Barrier
+ * isb : Instruction Synchronization Barrier
+ * dsb : data Synchronization Barrier
+ */
sb
.endm
+/*
+ * IAMROOT, 2022.11.08:
+ * - Emulate Privileged Access Never using TTBR0_EL1 switching
+ */
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
/*
* Set the TTBR0 PAN bit in SPSR. When the exception is taken from
@@ -451,11 +946,29 @@ alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0
* feature as all TTBR0_EL1 accesses are disabled, not just those to
* user mappings.
*/
+/*
+ * IAMROOT, 2022.11.08:
+ * - papago
+ * SPSR에서 TTBR0 PAN 비트를 설정합니다. EL0에서 예외가 발생하면 항상 액세스가
+ * 활성화되어 있으므로 TTBR0_EL1의 상태를 확인할 필요가 없습니다.
+ * 사용자 매핑뿐만 아니라 모든 TTBR0_EL1 액세스가 비활성화되므로 이 비트의
+ * 의미는 ARMv8.1 PAN 기능과 다릅니다.
+ * - @x23 : register로 backup해놓은 spsr
+ * - ttbr0 user access disable을 수행한다.
+ */
SYM_CODE_START_LOCAL(__swpan_entry_el1)
mrs x21, ttbr0_el1
tst x21, #TTBR_ASID_MASK // Check for the reserved ASID
orr x23, x23, #PSR_PAN_BIT // Set the emulated PAN in the saved SPSR
+/*
+ * IAMROOT, 2022.11.08:
+ * - TTBR_ASID_MASK가 0이라는건 이미 꺼놧다는것. 1f로 점프
+ */
b.eq 1f // TTBR0 access already disabled
+/*
+ * IAMROOT, 2022.11.08:
+ * - 다시 spsr을 복원하고 __uaccess_ttbr0_disable을 수행한다.
+ */
and x23, x23, #~PSR_PAN_BIT // Clear the emulated PAN in the saved SPSR
SYM_INNER_LABEL(__swpan_entry_el0, SYM_L_LOCAL)
__uaccess_ttbr0_disable x21
@@ -466,13 +979,26 @@ SYM_CODE_END(__swpan_entry_el1)
* Restore access to TTBR0_EL1. If returning to EL0, no need for SPSR
* PAN bit checking.
*/
+/*
+ * IAMROOT, 2022.11.09:
+ * @x22 spsr
+ * - ttbr0 user access enable을 수행하고 PSR_PAN_BIT를 clear한다.
+ */
SYM_CODE_START_LOCAL(__swpan_exit_el1)
+/*
+ * IAMROOT, 2022.11.09:
+ * - PSR_PAN_BIT가 set되있다면 ttbr0를 그대로 놔뚠다.(disable 상태 유지)
+ */
tbnz x22, #22, 1f // Skip re-enabling TTBR0 access if the PSR_PAN_BIT is set
__uaccess_ttbr0_enable x0, x1
1: and x22, x22, #~PSR_PAN_BIT // ARMv8.0 CPUs do not understand this bit
ret
SYM_CODE_END(__swpan_exit_el1)
+/*
+ * IAMROOT, 2022.11.09:
+ * - ttbr0 user access enable을 수행한다. el0는 PSR_PAN_BIT확인을 안하므로 필요없다.
+ */
SYM_CODE_START_LOCAL(__swpan_exit_el0)
__uaccess_ttbr0_enable x0, x1
/*
@@ -481,6 +1007,13 @@ SYM_CODE_START_LOCAL(__swpan_exit_el0)
* Cavium erratum 27456 (broadcast TLBI instructions may cause I-cache
* corruption).
*/
+/*
+ * IAMROOT, 2022.11.09:
+ * - papago
+ * 사용자에게 돌아가는 경우에만 에라타 해결 방법을 활성화하십시오.
+ * 현재 TTBR0_EL1 변경에 필요한 유일한 해결 방법은 Cavium erratum 27456에 대한
+ * 것입니다(방송 TLBI 명령으로 인해 I-캐시 손상이 발생할 수 있음).
+ */
b post_ttbr_update_workaround
SYM_CODE_END(__swpan_exit_el0)
#endif
@@ -497,26 +1030,66 @@ tsk .req x28 // current thread_info
/*
* IAMROOT, 2022.02.08:
+ * - exception 발생시 발생하는 일들
+ * 1. pstate -> spsr_elx로 백업
+ * 2. pc -> elr_elx로 백업
+ * 3. pstate에서 i가 autu set.
+ * 참고
+ * https://developer.arm.com/documentation/100933/0100/Exception-handling
+ * aarch64_exception_and_interrupt_handling
+ *
* - exception 함수들은 include/asm/exception.h에 위치
- * ex) el1h_64_sync_handler
+ * 예) el0 64bit user -----(irq)----> b el0t_64_irq_handler
+ * - t(thread)
+ * - h(handler)
+ * - ex) el1 64bit irq발생시 flow
+ * vectors
+ * v
+ * kernel_ventry 1, h, 64, irq
+ * v
+ * el1h_64_irq
+ * v
+ * kernel_entry 1, 64
+ * v
+ * el1h_64_irq_handler
+ * v
+ * ret_to_kernel
*/
.align 11
SYM_CODE_START(vectors)
+/*
+ * IAMROOT, 2022.11.07:
+ * - thread
+ * - sp가 sp_el0를 가리킬때 동작. user app용. kernel은 미사용.
+ */
kernel_ventry 1, t, 64, sync // Synchronous EL1t
kernel_ventry 1, t, 64, irq // IRQ EL1t
kernel_ventry 1, t, 64, fiq // FIQ EL1h
kernel_ventry 1, t, 64, error // Error EL1t
-
+/*
+ * IAMROOT, 2022.11.07:
+ * - handler
+ * - sp가 sp_el1을 가리킬때 동작.
+ * kernel thread등의 동작중일때 진입.
+ */
kernel_ventry 1, h, 64, sync // Synchronous EL1h
kernel_ventry 1, h, 64, irq // IRQ EL1h
kernel_ventry 1, h, 64, fiq // FIQ EL1h
kernel_ventry 1, h, 64, error // Error EL1h
-
+/*
+ * IAMROOT, 2022.11.07:
+ * - lower64
+ * 64bit app용
+ */
kernel_ventry 0, t, 64, sync // Synchronous 64-bit EL0
kernel_ventry 0, t, 64, irq // IRQ 64-bit EL0
kernel_ventry 0, t, 64, fiq // FIQ 64-bit EL0
kernel_ventry 0, t, 64, error // Error 64-bit EL0
-
+/*
+ * IAMROOT, 2022.11.07:
+ * - lower32
+ * 32bit app용
+ */
kernel_ventry 0, t, 32, sync // Synchronous 32-bit EL0
kernel_ventry 0, t, 32, irq // IRQ 32-bit EL0
kernel_ventry 0, t, 32, fiq // FIQ 32-bit EL0
@@ -524,6 +1097,10 @@ SYM_CODE_START(vectors)
SYM_CODE_END(vectors)
#ifdef CONFIG_VMAP_STACK
+/*
+ * IAMROOT, 2022.11.07:
+ * - overflow_stack진입시 들어간다.
+ */
SYM_CODE_START_LOCAL(__bad_stack)
/*
* We detected an overflow in kernel_ventry, which switched to the
@@ -532,6 +1109,15 @@ SYM_CODE_START_LOCAL(__bad_stack)
*/
/* Restore the original x0 value */
+/*
+ * IAMROOT, 2022.11.07:
+ * - papago
+ * 오버플로 스택으로 전환된 kernel_ventry에서 오버플로를 감지했습니다.
+ * 예외 규정을 숨기고 오버플로 처리기로 이동합니다.
+ *
+ * - tpidrro_el0에 x0(pt_regs address)를 이 함수 진입전에 저장해놨었다.
+ * x0에 복원한다.
+ */
mrs x0, tpidrro_el0
/*
@@ -540,6 +1126,12 @@ SYM_CODE_START_LOCAL(__bad_stack)
*/
sub sp, sp, #PT_REGS_SIZE
kernel_entry 1
+/*
+ * IAMROOT, 2022.11.07:
+ * - overflow_stack진입전 sp를 tpidr_el0에 넣어놨었다. x0에 불러와서
+ * sp + PT_REGS_SIZE의 주소를 overflow_stack의 sp에 저장한다.
+ *
+ */
mrs x0, tpidr_el0
add x0, x0, #PT_REGS_SIZE
str x0, [sp, #S_SP]
@@ -555,9 +1147,49 @@ SYM_CODE_END(__bad_stack)
/*
* IAMROOT, 2022.02.08:
- * ex) el1h_64_sync_handler
+ *
+ * 1. kernel_entry에서 exception이 발생하여 context 를 백업한다. (전체 레지스터)
+ * 2. exception에 해당하는 핸들러를 호출한다.
+ * ex) el1h_64_sync_handler
+ * 3. 유저 or 커널로 복귀하기 전에 context를 복구한다.
*/
.macro entry_handler el:req, ht:req, regsize:req, label:req
+/*
+ * IAMROOT, 2022.11.07:
+ * - 함수가 macro로 만들어진다. 내부에선 뒤에 _handler가 붙은 함수로 호출된다.
+ * el1t_64_sync 0x000
+ * el1t_64_irq 0x080
+ * el1t_64_fiq 0x100
+ * el1t_64_error 0x180
+ *
+ * el1h_64_sync 0x200
+ * el1h_64_irq 0x280
+ * el1h_64_fiq 0x300
+ * el1h_64_error 0x380
+ *
+ * el0t_64_sync 0x400
+ * el0t_64_irq 0x480
+ * el0t_64_fiq 0x500
+ * el0t_64_error 0x580
+ *
+ * el0t_32_sync 0x600
+ * el0t_32_irq 0x680
+ * el0t_32_fiq 0x700
+ * el0t_32_error 0x780
+ *
+ * - ex) el1 64bit irq발생시 flow
+ * vectors
+ * v
+ * kernel_ventry 1, h, 64, irq
+ * v
+ * el1h_64_irq <-- 시작
+ * v
+ * kernel_entry 1, 64
+ * v
+ * el1h_64_irq_handler
+ * v
+ * ret_to_kernel <-- 끝
+ */
SYM_CODE_START_LOCAL(el\el\ht\()_\regsize\()_\label)
kernel_entry \el, \regsize
mov x0, sp
@@ -572,6 +1204,11 @@ SYM_CODE_END(el\el\ht\()_\regsize\()_\label)
/*
* Early exception handlers
+ */
+/*
+ * IAMROOT, 2022.11.05:
+ * 부팅 후 곧바로 동작할 16개의 함수
+ * 예) el0t_64_irq
*/
entry_handler 1, t, 64, sync
entry_handler 1, t, 64, irq
@@ -593,10 +1230,21 @@ SYM_CODE_END(el\el\ht\()_\regsize\()_\label)
entry_handler 0, t, 32, fiq
entry_handler 0, t, 32, error
+/*
+ * IAMROOT, 2022.11.09:
+ * - 원래 지점으로 돌아간다.
+ */
SYM_CODE_START_LOCAL(ret_to_kernel)
kernel_exit 1
SYM_CODE_END(ret_to_kernel)
+/*
+ * IAMROOT, 2022.11.05:
+ * 유저로 복귀하기 전에 동작하는 루틴.
+ * x19 <- tsk->thread_info.flags
+ * - el0 exception시 exception handler를 완료하고 진입한다.
+ * - kernel_entry에서 disable했던 single step debug를 다시 enable한다.
+ */
SYM_CODE_START_LOCAL(ret_to_user)
ldr x19, [tsk, #TSK_TI_FLAGS] // re-check for single-step
enable_step_tsk x19, x2
@@ -615,6 +1263,10 @@ SYM_CODE_END(ret_to_user)
.pushsection ".entry.tramp.text", "ax"
// Move from tramp_pg_dir to swapper_pg_dir
+/*
+ * IAMROOT, 2022.11.10:
+ * - tramp_pg_dir -> swapper_pg_dir로 전환. 전환하며 USER_ASID_FLAG를 unset한다.
+ */
.macro tramp_map_kernel, tmp
mrs \tmp, ttbr1_el1
add \tmp, \tmp, #TRAMP_SWAPPER_OFFSET
@@ -634,6 +1286,10 @@ alternative_else_nop_endif
#endif /* CONFIG_QCOM_FALKOR_ERRATUM_1003 */
.endm
+/*
+ * IAMROOT, 2022.11.09:
+ * - swapper_pg_dir -> tramp_pg_dir로 교체하면서 USER_ASID_FLAG로 넣어놓는다.
+ */
// Move from swapper_pg_dir to tramp_pg_dir
.macro tramp_unmap_kernel, tmp
mrs \tmp, ttbr1_el1
@@ -647,9 +1303,18 @@ alternative_else_nop_endif
*/
.endm
+/*
+ * IAMROOT, 2022.11.09:
+ * - exception -> tramp_ventry -> kernel_ventry ....
+ * - ttbr1_el1이 tramp_pg_dir -> swapper_pg_dir로 전환된다.
+ */
.macro tramp_ventry, regsize = 64
.align 7
1:
+/*
+ * IAMROOT, 2022.11.10:
+ * - tpidrro_el0에 x30(lr) 에 저장해놨다가 kernel_ventry에서 꺼내서 사용한다.
+ */
.if \regsize == 64
msr tpidrro_el0, x30 // Restored in kernel_ventry
.endif
@@ -658,10 +1323,26 @@ alternative_else_nop_endif
* entry onto the return stack and using a RET instruction to
* enter the full-fat kernel vectors.
*/
+/*
+ * IAMROOT, 2022.11.10:
+ * - papago
+ * 반환 스택에 더미 항목을 밀어넣고 RET 명령을 사용하여 전체 팻 커널 벡터를
+ * 입력하여 분기 앨리어싱 공격으로부터 방어합니다.
+ */
bl 2f
b .
+/*
+ * IAMROOT, 2022.11.10:
+ * - tramp_pg_dir -> swapper_pg_dir로 전환.
+ */
2:
tramp_map_kernel x30
+/*
+ * IAMROOT, 2022.11.10:
+ * - randomize가 없으면 vectors를 즉시 가져온다.
+ * 그게 아니라면 tramp_vectors + PAGE_SIZE에 vectors가 있다.
+ * (map_entry_trampoline()참고)
+ */
#ifdef CONFIG_RANDOMIZE_BASE
adr x30, tramp_vectors + PAGE_SIZE
alternative_insn isb, nop, ARM64_WORKAROUND_QCOM_FALKOR_E1003
@@ -672,12 +1353,27 @@ alternative_insn isb, nop, ARM64_WORKAROUND_QCOM_FALKOR_E1003
alternative_if_not ARM64_WORKAROUND_CAVIUM_TX2_219_PRFM
prfm plil1strm, [x30, #(1b - tramp_vectors)]
alternative_else_nop_endif
+/*
+ * IAMROOT, 2022.11.10:
+ * - vbar_el1에 vectors를 넣어놓고 x30(lr)을 수정후 ret으로 수정된 x30으로
+ * 점프한다.
+ * - 1b - tramp_vectors
+ * tramp_vectors에서 현재 발생한 tramp_ventry의 offset.
+ * 즉 이걸 vectors에 적용하면 vectors + offset이므로 현재 offset에 해당하는
+ * kernel_ventry로 진입할수있게된다.
+ */
msr vbar_el1, x30
add x30, x30, #(1b - tramp_vectors)
isb
ret
.endm
+/*
+ * IAMROOT, 2022.11.09:
+ * - vbar_el1에 tramp_vectors를 넣고, ttbr1_el1도 tramp_pg_dir로
+ * USER_ASID_FLAG를 넣어서 교체해준다.
+ * far_el1에 저장해놨던 lr를 x30에 원복한다.
+ */
.macro tramp_exit, regsize = 64
adr x30, tramp_vectors
msr vbar_el1, x30
@@ -690,6 +1386,11 @@ alternative_else_nop_endif
.endm
.align 11
+
+/*
+ * IAMROOT, 2022.11.10:
+ * - user용만 있는게 확인된다.
+ */
SYM_CODE_START_NOALIGN(tramp_vectors)
.space 0x400
@@ -704,16 +1405,30 @@ SYM_CODE_START_NOALIGN(tramp_vectors)
tramp_ventry 32
SYM_CODE_END(tramp_vectors)
+/*
+ * IAMROOT, 2022.11.09:
+ * - 64로 실행
+ */
SYM_CODE_START(tramp_exit_native)
tramp_exit
SYM_CODE_END(tramp_exit_native)
+/*
+ * IAMROOT, 2022.11.09:
+ * - 32bit로 실행
+*/
SYM_CODE_START(tramp_exit_compat)
tramp_exit 32
SYM_CODE_END(tramp_exit_compat)
.ltorg
.popsection // .entry.tramp.text
+/*
+ * IAMROOT, 2022.11.10:
+ * - randomize가 적용되면 vecotrs address를 여기에 저장해놓는다.
+ * 해당주소는 fixmap으로 TRAMP_VALIAS + PAGE_SIZE에 mapping된다.
+ * (map_entry_trampoline() 참고)
+ */
#ifdef CONFIG_RANDOMIZE_BASE
.pushsection ".rodata", "a"
.align PAGE_SHIFT
@@ -781,27 +1496,52 @@ NOKPROBE(ret_from_fork)
*
* Calls func(regs) using this CPU's irq stack and shadow irq stack.
*/
+/*
+ * IAMROOT, 2022.11.08:
+ * - pcp irq_stack_ptr로 sp를 전환하여 @func(x1)을 실행한다.
+ * - @func실행 전후로 fp, lr 저장 / 원복 등이 이루어진다.
+ * - SCS(Shadow call stack)
+ * https://clang.llvm.org/docs/ShadowCallStack.html
+ */
SYM_FUNC_START(call_on_irq_stack)
#ifdef CONFIG_SHADOW_CALL_STACK
stp scs_sp, xzr, [sp, #-16]!
ldr_this_cpu scs_sp, irq_shadow_call_stack_ptr, x17
#endif
/* Create a frame record to save our LR and SP (implicit in FP) */
+/*
+ * IAMROOT, 2022.11.08:
+ * - x30은 lr로 사용한다
+ * https://developer.arm.com/documentation/100933/0100/Returning-from-an-exception
+ * - 기존 x29, x30(fp, lr)을 sp에 저장해놓고, 갱신된 sp를 x29에 저장해놓는다.
+ */
stp x29, x30, [sp, #-16]!
mov x29, sp
-
+/*
+ * IAMROOT, 2022.11.08:
+ * - pcp irq_stack_ptr을 구해와 sp를 대체한다.
+ */
ldr_this_cpu x16, irq_stack_ptr, x17
mov x15, #IRQ_STACK_SIZE
add x16, x16, x15
/* Move to the new stack and call the function there */
mov sp, x16
+/*
+ * IAMROOT, 2022.11.08:
+ * - func실행. func(regs). 형태로 0번인자가 regs로 진입한다.
+ */
blr x1
/*
* Restore the SP from the FP, and restore the FP and LR from the frame
* record.
*/
+/*
+ * IAMROOT, 2022.11.08:
+ * - func실행전 x29에 저장해놓은 sp를 복구하고, 저장해놓은 sp에서 기존 fp, lr을
+ * x29, x30에 원복한다.
+ */
mov sp, x29
ldp x29, x30, [sp], #16
#ifdef CONFIG_SHADOW_CALL_STACK
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 8b6799176aca..c0b00522be2d 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -1000,6 +1000,10 @@ void do_sve_acc(unsigned int esr, struct pt_regs *regs)
/*
* Trapped FP/ASIMD access.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - warrning. arm64는 필요없다.
+ */
void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs)
{
/* TODO: implement lazy context saving/restoring */
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c
index bda49430c9ea..660e7d8f0000 100644
--- a/arch/arm64/kernel/irq.c
+++ b/arch/arm64/kernel/irq.c
@@ -81,9 +81,19 @@ static void default_handle_fiq(struct pt_regs *regs)
panic("FIQ taken without a root FIQ handler\n");
}
+/*
+ * IAMROOT, 2022.11.05:
+ * 대표 인터럽트 controller의 핸들러가 호출되는 콜백
+ * 예) GICv3: gic_handle_irq
+ * gic의 경우 gic_init_bases-> set_handle_irq를 통해서 gic_handle_irq가 설정된다.
+ */
void (*handle_arch_irq)(struct pt_regs *) __ro_after_init = default_handle_irq;
void (*handle_arch_fiq)(struct pt_regs *) __ro_after_init = default_handle_fiq;
+/*
+ * IAMROOT, 2022.11.05:
+ * 이 함수에서 대표 인터럽트 컨트롤러의 핸들러를 지정한다.
+ */
int __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
{
if (handle_arch_irq != default_handle_irq)
@@ -94,6 +104,10 @@ int __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
return 0;
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - fiq handler set
+ */
int __init set_handle_fiq(void (*handle_fiq)(struct pt_regs *))
{
if (handle_arch_fiq != default_handle_fiq)
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 782917bbc63f..1129c5a80a96 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -436,6 +436,15 @@ static void ssbs_thread_switch(struct task_struct *next)
* This is *only* for exception entry from EL0, and is not valid until we
* __switch_to() a user task.
*/
+/*
+ * IAMROOT, 2022.11.08:
+ * - papago
+ * current task를 sp_el0에 저장합니다. 사용자 공간에서 입력할 때 이를 복원할 수
+ * 있도록 섀도 복사본을 유지합니다.
+ *
+ * 이것은 EL0의 예외 항목에 대한 *only*이며 사용자 작업을 __switch_to()할
+ * 때까지 유효하지 않습니다.
+ */
DEFINE_PER_CPU(struct task_struct *, __entry_task);
static void entry_task_switch(struct task_struct *next)
diff --git a/arch/arm64/kernel/sys.c b/arch/arm64/kernel/sys.c
index 1dbd51918b25..712d376b22cf 100644
--- a/arch/arm64/kernel/sys.c
+++ b/arch/arm64/kernel/sys.c
@@ -96,6 +96,12 @@ asmlinkage long __arm64_sys_ni_syscall(const struct pt_regs *__unused)
#undef __SYSCALL
#define __SYSCALL(nr, sym) [nr] = __arm64_##sym,
+/*
+ * IAMROOT, 2022.11.12:
+ * - arch/arm64/include/asm/unistd.h
+ * -> arch/arm64/include/uapi/asm/unistd.h
+ * -> include/uapi/asm-generic/unistd.h
+ */
const syscall_fn_t sys_call_table[__NR_syscalls] = {
[0 ... __NR_syscalls - 1] = __arm64_sys_ni_syscall,
#include <asm/unistd.h>
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index 50a0f1a38e84..3ad27ff26c07 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -19,6 +19,10 @@
long compat_arm_syscall(struct pt_regs *regs, int scno);
long sys_ni_syscall(void);
+/*
+ * IAMROOT, 2022.11.12:
+ * - arm전용 syscall
+ */
static long do_ni_syscall(struct pt_regs *regs, int scno)
{
#ifdef CONFIG_COMPAT
@@ -33,11 +37,20 @@ static long do_ni_syscall(struct pt_regs *regs, int scno)
return sys_ni_syscall();
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - syscall_fn 실행.
+ * ex)sys_clone
+ */
static long __invoke_syscall(struct pt_regs *regs, syscall_fn_t syscall_fn)
{
return syscall_fn(regs);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - @scno 에따라 syscall.
+ */
static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
unsigned int sc_nr,
const syscall_fn_t syscall_table[])
@@ -47,6 +60,10 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
add_random_kstack_offset();
if (scno < sc_nr) {
+/*
+ * IAMROOT, 2022.11.12:
+ * - posix syscall
+ */
syscall_fn_t syscall_fn;
syscall_fn = syscall_table[array_index_nospec(scno, sc_nr)];
ret = __invoke_syscall(regs, syscall_fn);
@@ -70,6 +87,10 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
choose_random_kstack_offset(get_random_int() & 0x1FF);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - debug flag가 있는지 확인한다.
+ */
static inline bool has_syscall_work(unsigned long flags)
{
return unlikely(flags & _TIF_SYSCALL_WORK);
@@ -78,11 +99,18 @@ static inline bool has_syscall_work(unsigned long flags)
int syscall_trace_enter(struct pt_regs *regs);
void syscall_trace_exit(struct pt_regs *regs);
+/*
+ * IAMROOT, 2022.11.12:
+ * - syscall
+ */
static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
const syscall_fn_t syscall_table[])
{
unsigned long flags = current_thread_info()->flags;
-
+/*
+ * IAMROOT, 2022.11.12:
+ * - x0는 syscall nr로 사용해야되서 backup해놓는다.
+ */
regs->orig_x0 = regs->regs[0];
regs->syscallno = scno;
@@ -103,7 +131,28 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
* So, don't touch regs->pstate & PSR_BTYPE_MASK here.
* (Similarly for HVC and SMC elsewhere.)
*/
-
+/*
+ * IAMROOT, 2022.11.12:
+ * - papago
+ * BTI 참고:
+ * 아키텍처는 SVC를 사용할 때 SPSR.BTYPE이 0임을 보장하지 않으므로 시스템 호출 후 0이 아닌
+ * BTYPE을 사용하여 사용자 공간으로 돌아갈 수 있습니다.
+ *
+ * 이는 사용자 공간이 BTI/PACIxSP 지침을 준수하지 않는 페이지에서 PROT_BTI를 설정하거나,
+ * PROT_BTI가 다른 실행 페이지에서 다른 실행 페이지로 넘어가거나, ptrace를 통해 BTYPE을
+ * 엉망으로 만드는 것과 같이 명시적으로 어리석은 일을 하는 경우를 제외하고는 중요하지
+ * 않습니다.
+ * 이러한 경우 시스템 호출 반환 시 SIGILL이 발생하더라도 사용자 공간은 놀라지 않아야
+ * 합니다.
+ *
+ * 따라서 여기에서 regs->pstate & PSR_BTYPE_MASK를 건드리지 마십시오.
+ * (다른 곳에서 HVC 및 SMC와 유사합니다.).
+ *
+ * - PSTATE.BTYPE(Branch target identification bit)
+ *
+ * - irq enable
+ * syscall 호출 도중에 irq가 들어올수있다.
+ */
local_daif_restore(DAIF_PROCCTX);
if (flags & _TIF_MTE_ASYNC_FAULT) {
@@ -112,6 +161,12 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
* syscall. do_notify_resume() will send a signal to userspace
* before the syscall is restarted.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - papago
+ * 실제 시스템 호출 전에 비동기 태그 검사 오류를 처리합니다. do_notify_resume()은
+ * 시스템 호출이 다시 시작되기 전에 사용자 공간에 신호를 보냅니다.
+ */
syscall_set_return_value(current, regs, -ERESTARTNOINTR, 0);
return;
}
@@ -132,6 +187,20 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
* setting the return value is unlikely to do anything sensible
* anyway.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - papago
+ * ptrace를 사용하여 시스템 호출을 건너뛰는 사실상의 표준 방법은 시스템 호출을
+ * -1(NO_SYSCALL)로 설정하고 x0을 사용자 공간에서 사용하기에 적합한 error 코드로 설정하는
+ * 것입니다. 그러나 이것은 사용자가 발행한 syscall(-1)과 구별할 수 없으므로 추적
+ * 프로그램에서 건너뛰기를 실행하지 않고 x0이 보존된 trace_exit에 빠질 경우를 대비하여
+ * 여기에서 x0을 -ENOSYS로 설정해야 합니다.
+ *
+ * 이것은 추적자가 시스템 호출 번호를 -1로 설정하지만 x0을 초기화하지 않으면 사용자가
+ * 발행한 syscall(-1)을 제외한 모든 시스템 호출에 대해 x0이 보존된다는 의미이기 때문에
+ * 약간 이상합니다. 그러나 건너뛰기를 요청하고 반환 값을 설정하지 않는 것은 어쨌든
+ * 합리적이지 않을 것입니다.
+ */
if (scno == NO_SYSCALL)
syscall_set_return_value(current, regs, -ENOSYS, 0);
scno = syscall_trace_enter(regs);
@@ -158,11 +227,19 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
syscall_trace_exit(regs);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - sve를 지원중이라면 discard시킨다.
+ */
static inline void sve_user_discard(void)
{
if (!system_supports_sve())
return;
+/*
+ * IAMROOT, 2022.11.12:
+ * - SVE를 지원하는 system이라면 thread flag에서 TIF_SVE flag를 지운다.
+ */
clear_thread_flag(TIF_SVE);
/*
@@ -172,9 +249,22 @@ static inline void sve_user_discard(void)
* modification (sigreturn, ptrace) intervenes.
* So, ensure that CPACR_EL1 is already correct for the fast-path case.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - papago
+ * task_fpsimd_load()는 TIF_FOREIGN_FPSTATE가 아직 설정되어 있지 않으면
+ * ret_to_user에서 CPACR_EL1을 업데이트하기 위해 호출되지 않습니다.
+ * 이는 컨텍스트 전환 또는 kernel_neon_begin() 또는 컨텍스트
+ * 수정(sigreturn, ptrace)이 개입하는 경우에만 발생합니다.
+ * 따라서 CPACR_EL1이 빠른 경로의 경우에 이미 올바른지 확인하십시오.
+ */
sve_user_disable();
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - syscall
+ */
void do_el0_svc(struct pt_regs *regs)
{
sve_user_discard();
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 04e3387ade06..dc731007e611 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -286,17 +286,29 @@ void arm64_force_sig_ptrace_errno_trap(int errno, unsigned long far,
force_sig_ptrace_errno_trap(errno, (void __user *)far);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - user / kernel 에 따라 kill / die를 동작한다.
+ */
void arm64_notify_die(const char *str, struct pt_regs *regs,
int signo, int sicode, unsigned long far,
int err)
{
if (user_mode(regs)) {
+/*
+ * IAMROOT, 2022.11.12:
+ * - user에서 발생한경우 해당 process kill
+ */
WARN_ON(regs != current_pt_regs());
current->thread.fault_address = 0;
current->thread.fault_code = err;
arm64_force_sig_fault(signo, sicode, far, str);
} else {
+/*
+ * IAMROOT, 2022.11.12:
+ * - 자살
+ */
die(str, regs, err);
}
}
@@ -376,6 +388,11 @@ void arm64_skip_faulting_instruction(struct pt_regs *regs, unsigned long size)
static LIST_HEAD(undef_hook);
static DEFINE_RAW_SPINLOCK(undef_lock);
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - unref_hook에 @hook를 등록한다.
+ */
void register_undef_hook(struct undef_hook *hook)
{
unsigned long flags;
@@ -394,6 +411,10 @@ void unregister_undef_hook(struct undef_hook *hook)
raw_spin_unlock_irqrestore(&undef_lock, flags);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - 특정 inst에 hook를 걸수있다. 그것을 호출해준다.
+ */
static int call_undef_hook(struct pt_regs *regs)
{
struct undef_hook *hook;
@@ -429,6 +450,10 @@ static int call_undef_hook(struct pt_regs *regs)
instr = le32_to_cpu(instr_le);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - undef_hook에서 찾아서 fn을 호출한다.
+ */
raw_spin_lock_irqsave(&undef_lock, flags);
list_for_each_entry(hook, &undef_hook, node)
if ((instr & hook->instr_mask) == hook->instr_val &&
@@ -486,6 +511,10 @@ void arm64_notify_segfault(unsigned long addr)
force_signal_inject(SIGSEGV, code, addr, 0);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - unref_hook 에 unref가 있는지 찾아본다.
+ */
void do_undefinstr(struct pt_regs *regs)
{
/* check for AArch32 breakpoint instructions */
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index d1c152666a43..fa532b5d16b9 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -53,6 +53,10 @@ struct fault_info {
static const struct fault_info fault_info[];
static struct fault_info debug_fault_info[];
+/*
+ * IAMROOT, 2022.11.12:
+ * - ISS의 Data Fault Status Code.
+ */
static inline const struct fault_info *esr_to_fault_info(unsigned int esr)
{
return fault_info + (esr & ESR_ELx_FSC);
@@ -462,6 +466,10 @@ static void set_thread_esr(unsigned long address, unsigned int esr)
current->thread.fault_code = esr;
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - user에서 발생했으면 send sig. kernel이면 fault.
+ */
static void do_bad_area(unsigned long far, unsigned int esr,
struct pt_regs *regs)
{
@@ -477,6 +485,10 @@ static void do_bad_area(unsigned long far, unsigned int esr,
set_thread_esr(addr, esr);
arm64_force_sig_fault(inf->sig, inf->code, far, inf->name);
} else {
+/*
+ * IAMROOT, 2022.11.12:
+ * - kernel fault.
+ */
__do_kernel_fault(addr, esr, regs);
}
}
@@ -484,6 +496,10 @@ static void do_bad_area(unsigned long far, unsigned int esr,
#define VM_FAULT_BADMAP 0x010000
#define VM_FAULT_BADACCESS 0x020000
+/*
+ * IAMROOT, 2022.11.12:
+ * - mm fault 수행
+ */
static vm_fault_t __do_page_fault(struct mm_struct *mm, unsigned long addr,
unsigned int mm_flags, unsigned long vm_flags,
struct pt_regs *regs)
@@ -497,6 +513,10 @@ static vm_fault_t __do_page_fault(struct mm_struct *mm, unsigned long addr,
* Ok, we have a good vm_area for this memory access, so we can handle
* it.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - 범위검사.
+ */
if (unlikely(vma->vm_start > addr)) {
if (!(vma->vm_flags & VM_GROWSDOWN))
return VM_FAULT_BADMAP;
@@ -527,6 +547,10 @@ static bool is_write_abort(unsigned int esr)
return (esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - user page fault
+ */
static int __kprobes do_page_fault(unsigned long far, unsigned int esr,
struct pt_regs *regs)
{
@@ -556,6 +580,12 @@ static int __kprobes do_page_fault(unsigned long far, unsigned int esr,
* vma->vm_flags & vm_flags and returns an error if the
* intersection is empty
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - inst fault -> VM_EXEC
+ * write abort -> VM_WRITE
+ * read abort(그외) -> VM_READ
+ */
if (is_el0_instruction_abort(esr)) {
/* It was exec fault */
vm_flags = VM_EXEC;
@@ -610,6 +640,10 @@ static int __kprobes do_page_fault(unsigned long far, unsigned int esr,
#endif
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - page fualt 수행
+ */
fault = __do_page_fault(mm, addr, mm_flags, vm_flags, regs);
/* Quick path to respond to signals */
@@ -684,15 +718,27 @@ static int __kprobes do_page_fault(unsigned long far, unsigned int esr,
return 0;
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - mapping이 없을때 fault.
+ */
static int __kprobes do_translation_fault(unsigned long far,
unsigned int esr,
struct pt_regs *regs)
{
unsigned long addr = untagged_addr(far);
+/*
+ * IAMROOT, 2022.11.12:
+ * - user라면 do page fault
+ */
if (is_ttbr0_addr(addr))
return do_page_fault(far, esr, regs);
+/*
+ * IAMROOT, 2022.11.12:
+ * - kernel은 전부 mapping이 되있는데 fault인건 말이안된다.
+ */
do_bad_area(far, esr, regs);
return 0;
}
@@ -819,14 +865,27 @@ static const struct fault_info fault_info[] = {
{ do_bad, SIGKILL, SI_KERNEL, "unknown 63" },
};
+/*
+ * IAMROOT, 2022.11.12:
+ * -
+ */
void do_mem_abort(unsigned long far, unsigned int esr, struct pt_regs *regs)
{
const struct fault_info *inf = esr_to_fault_info(esr);
unsigned long addr = untagged_addr(far);
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - 성공하면 빠져나간다.
+ */
if (!inf->fn(far, esr, regs))
return;
+/*
+ * IAMROOT, 2022.11.12:
+ * - kernel에서 호출된경우면 alert.
+ */
if (!user_mode(regs)) {
pr_alert("Unhandled fault at 0x%016lx\n", addr);
mem_abort_decode(esr);
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 395790f4d3b9..a27e6ea53161 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -811,6 +811,10 @@ static int __init parse_rodata(char *arg)
early_param("rodata", parse_rodata);
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+/*
+ * IAMROOT, 2022.11.10:
+ * - fixmap에 tramp 관련 데이터들을 mapping한다.
+ */
static int __init map_entry_trampoline(void)
{
pgprot_t prot = rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;
@@ -826,6 +830,23 @@ static int __init map_entry_trampoline(void)
/* Map both the text and data into the kernel page table */
__set_fixmap(FIX_ENTRY_TRAMP_TEXT, pa_start, prot);
+/*
+ * IAMROOT, 2022.11.10:
+ * - FIX_ENTRY_TRAMP_DATA는 FIX_ENTRY_TRAMP_TEXT + PAGE_SIZE 에 위치할것이다.
+ * 해당 fixmap으로 __entry_tramp_data_start를 mapping한다.
+ * 이걸 함으로써 가상주소적으로
+ *
+ * -- high --
+ * .quad vectors
+ * __entry_tramp_data_start
+ * (PAGE_SIZE)
+ * tramp_vectors
+ * -- low --
+ *
+ * 의 address 체계가 성립함으로서 tramp_vectors로 vectors address가 저장된
+ * .quad로 접근이 가능하며, 이 값을 ldr X, [.quad vecors]함으로써
+ * vectors의 주소를 가져올수있다.
+ */
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
extern char __entry_tramp_data_start[];
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 8f1445bdb67b..aa010fb07304 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -73,7 +73,9 @@ static struct gic_chip_data gic_data __read_mostly;
/*
* IAMROOT, 2022.10.01:
* - gic_init_bases에서 hyp_mode가 안켜져있으면 disable시킨다.
- * eoi를 drop / deactivate의 두개의 기능으로 나누는 것에 대한 지원여부
+ * EL2로 진입하여 hyp_mode가 사용되면 eoi를 drop 시켜 사용한다.
+ * 그리고, Guest OS가 EL1으로 진입하여 hyp_mode가 사용되지 않으면 eoi를
+ * deactivate 하여 사용하도록, eoi를 2개로 분리하여 처리한다.
*/
static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
@@ -711,6 +713,10 @@ static void gic_irq_nmi_teardown(struct irq_data *d)
gic_irq_set_prio(d, GICD_INT_DEF_PRI);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - write eoi.
+ */
static void gic_eoi_irq(struct irq_data *d)
{
gic_write_eoir(gic_irq(d));
@@ -837,10 +843,19 @@ static inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs)
nmi_exit();
}
+/*
+ * IAMROOT, 2022.11.05:
+ * Interrupt Controller Interrupt Acknowledge Register를 읽어
+ * 인터럽트 번호를 알아온다.
+ */
static u32 do_read_iar(struct pt_regs *regs)
{
u32 iar;
+/*
+ * IAMROOT, 2022.11.05:
+ * Pesudo-NMI를 사용하면서 일반 irq가 disable 상태라면 pmr이 설정된 상태인것이다.
+ */
if (gic_supports_nmi() && unlikely(!interrupts_enabled(regs))) {
u64 pmr;
@@ -857,6 +872,32 @@ static u32 do_read_iar(struct pt_regs *regs)
* actually only allow NMIs before reading IAR, and then
* restore it to what it was.
*/
+/*
+ * IAMROOT, 2022.11.05:
+ * - papago
+ * 우리는 IRQ가 비활성화된 상황에 있었습니다. 그러나 입력 코드는
+ * PMR을 NMI뿐만 아니라 모든 인터럽트를 승인할 수 있는 값으로 설정했습니다.
+ * NMI가 그 사이에 폐기되고 IRQ가 보류 중인 경우 이는 놀라운 효과로 이어질
+ * 수 있습니다. 그런 다음 IRQ는 NMI 컨텍스트에서 수행되며 아무도 두 번
+ * 디버그하기를 원하지 않습니다.
+ *
+ * 이것을 정렬할 때까지 PMR을 IAR을 읽기 전에 실제로 NMI만 허용하는 수준으로
+ * 다시 떨어뜨린 다음 원래 상태로 복원합니다.
+ *
+ * - spurious interrupts
+ * https://developer.arm.com/documentation/ihi0048/b/Introduction/Terminology/Spurious-interrupts
+ * https://en.wikipedia.org/wiki/Interrupt
+ * - Git Blame
+ * spurious interrupt(nmi)가 발생(iar을 읽기전에 retired)한 상황에서 irq가
+ * pending중일때, nmi context에서 pending중인 irq에 대한 ack가 나갈수있다는것
+ * 같다.
+ * 그래서 spurious interrupt를 handle_bad_irq로 처리할려고
+ * (core-api/generic.rst) 확실히 off시킨후 iar을 얻어올려는거 같다.
+ * (부정확)
+ *
+ * - pmr을 사용하여 일반 인터럽트를 disable 한상태에서 iar을 통해 인터럽트 번호를
+ * 읽어온다. 그 후 pmr을 원래 값으로 복구한다.
+ */
pmr = gic_read_pmr();
gic_pmr_mask_irqs();
isb();
@@ -873,10 +914,39 @@ static u32 do_read_iar(struct pt_regs *regs)
/*
* IAMROOT, 2022.10.08:
- * - TODO
* - gic control handler.
* interrupt가 vector table다음으로 받는 handler.
- * - vector table -> gic_handle_irq -> irq flow handler
+ * - irq 흐름
+ * vectors(arch/arm64/kernel/entry.S)
+ * v
+ * chip handler(handler_arch_irq, gic의 경우 gic_handle_irq) <--- 현재
+ * v
+ * flow handler
+ * v
+ * irq_handler
+ *
+ * - gic 흐름
+ * interrupt 발생
+ * v
+ * register backup
+ * v
+ * gic_handle_irq(진입)
+ * v
+ * ack(iar)
+ * v
+ * interrupt enable(PSR의 IF clear 및 PMR-NMI 적용)
+ * (NMI의 경우 PMR-NMI 우선순위보다 높은 interrupt만
+ * 들어올수있게 enable된다.)
+ * v
+ * (eoimode1: drop)
+ * v
+ * flow handler 실행
+ * v
+ * (eoimode:0 eoi + drop)
+ * v
+ * gic_handle_irq(완료)
+ * v
+ * register restore
*/
static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
{
@@ -884,21 +954,46 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
irqnr = do_read_iar(regs);
+/*
+ * IAMROOT, 2022.11.05:
+ * 1020~1023번 인터럽트는 스페셜 인터럽트로 핸들러에 대한 호출을 할 필요 없다.
+ */
/* Check for special IDs first */
if ((irqnr >= 1020 && irqnr <= 1023))
return;
+/*
+ * IAMROOT, 2022.11.05:
+ * Pesudo-NMI 인터럽트에 대한 핸들러 호출이다.
+ * 예) request_nmi() & request_percpu_nmi()
+ */
if (gic_supports_nmi() &&
unlikely(gic_read_rpr() == GICD_INT_RPR_PRI(GICD_INT_NMI_PRI))) {
gic_handle_nmi(irqnr, regs);
return;
}
+/*
+ * IAMROOT, 2022.11.05:
+ * Pesudo-NMI를 지원하면서 GIC 역시 priority masking을 지원하는 경우
+ * pmr을 사용하여 일반 인터럽트를 disable 하고, DAIF 중 IF를 clear한다.
+ *
+ * 중요) 이렇게 하면 인터럽트 처리 중에도 IF를 clear하여 NMI 인터럽트는
+ * 진입이 가능하도록 허용한다.
+ */
if (gic_prio_masking_enabled()) {
gic_pmr_mask_irqs();
gic_arch_enable_irqs();
}
+/*
+ * IAMROOT, 2022.11.05:
+ * EL2 하이퍼 바이저를 지원하여 eoimode=1을 사용하는 경우에는
+ * 이 시점에서 eoi drop을 한다. 이러한 경우 해당 인터럽트 번호만
+ * drop 되기 때문에 다른 인터럽트들이 진입할 수 있게된다.
+ *
+ * 물론, Pesudo-NMI를 제외하면 아직 cpu의 irq가 enable(IF mask)상태는 아니다.
+ */
if (static_branch_likely(&supports_deactivate_key))
gic_write_eoir(irqnr);
else
@@ -1471,7 +1566,7 @@ static void gic_cpu_sys_reg_init(void)
* --- eoimode example, guest os한테 int50이 들어오는 상황
* 1. eoimode0
* guest os한테 넘겨줌. drop / inactivate 둘다 발생.
- * guest of가 다 처리할때까지 int50을 못받음.
+ * guest os가 다 처리할때까지 int50을 못받음.
*
* 1. eoimode1
* guest os한테 넘겨줌. drop 발생.
diff --git a/include/asm-generic/irq_regs.h b/include/asm-generic/irq_regs.h
index 2e7c6e89d42e..86b17320b652 100644
--- a/include/asm-generic/irq_regs.h
+++ b/include/asm-generic/irq_regs.h
@@ -14,6 +14,10 @@
* Per-cpu current frame pointer - the location of the last exception frame on
* the stack
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - 현재 실행중인 irq context register.
+ */
DECLARE_PER_CPU(struct pt_regs *, __irq_regs);
static inline struct pt_regs *get_irq_regs(void)
@@ -21,6 +25,11 @@ static inline struct pt_regs *get_irq_regs(void)
return __this_cpu_read(__irq_regs);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - @new_regs를 현재 regs에 넣으면서, old를 return한다.
+ * - 전역 percpu __irq_regs에 현재 실행중인 irq의 regs를 저장해놓는다.
+ */
static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs)
{
struct pt_regs *old_regs;
diff --git a/include/asm-generic/softirq_stack.h b/include/asm-generic/softirq_stack.h
index eceeecf6a5bd..5d94a1a83f7a 100644
--- a/include/asm-generic/softirq_stack.h
+++ b/include/asm-generic/softirq_stack.h
@@ -5,6 +5,11 @@
#ifdef CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK
void do_softirq_own_stack(void);
#else
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - TODO
+ */
static inline void do_softirq_own_stack(void)
{
__do_softirq();
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 02ad54c90805..8fc44f0be084 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -554,8 +554,17 @@ DECLARE_STATIC_KEY_FALSE(force_irqthreads_key);
#define local_softirq_pending_ref irq_stat.__softirq_pending
#endif
+/*
+ * IAMROOT, 2022.11.12:
+ * - __raise_softirq_irqoff()참고. pending중인 softirq가 있는지 확인한다.
+ */
#define local_softirq_pending() (__this_cpu_read(local_softirq_pending_ref))
#define set_softirq_pending(x) (__this_cpu_write(local_softirq_pending_ref, (x)))
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - @x로 current cpu에 or.
+ */
#define or_softirq_pending(x) (__this_cpu_or(local_softirq_pending_ref, (x)))
#endif /* local_softirq_pending */
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 056bc42ad034..7e8d196ba9c1 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -258,6 +258,10 @@ enum {
* - IRQ_TYPE_SENSE_MASK
* - IRQD_AFFINITY_MANAGED, IRQD_MANAGED_SHUTDOWN (alloc_descs() 참고)
* affinity->is_managed가 되있는경우 irq desc할당에서 flag로 사용한다.
+ * - IRQD_IRQ_INPROGRESS
+ * irq 진행중
+ * - IRQD_WAKEUP_ARMED
+ * mode armed 상태. interrupt가 뭔가 펼쳐진상태
*
*/
IRQD_TRIGGER_MASK = 0xf,
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index b2c6391f5495..97b80265471b 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -185,6 +185,30 @@ static inline void *irq_desc_get_handler_data(struct irq_desc *desc)
* Architectures call this to let the generic IRQ layer
* handle an interrupt.
*/
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - vector -> chip handler -> flow handler -> action handler..
+ * ^여기를 호출하는 상황.
+ * ex) (일반 irq) handle_fasteoi_irq, handle_percpu_devid_irq
+ * (nmi) handle_fasteoi_nmi, handle_percpu_devid_fasteoi_nmi
+ * ^spi용 ^ppi, sgi용
+ *
+ * -
+ * spi(handle_fasteoi_irq) ppi(handle_percpu_devid_irq)
+ * ---------+---------------------------------------------------------
+ * oneshot, | 고려해서 처리여부 판단 고려없이 모든 인터럽트 처리.
+ * thread등 |
+ * ---------+----------------------------------------------------
+ * eoi, | 상황에 따라 처리여부 판단. 무조건 eoi만 수행.
+ * unmask |
+ * ---------+---------------------------------------------------------
+ * poll | wait후 처리 poll 없음
+ * ---------+---------------------------------------------------------
+ *
+ *
+ *
+ */
static inline void generic_handle_irq_desc(struct irq_desc *desc)
{
desc->handle_irq(desc);
diff --git a/include/linux/irqreturn.h b/include/linux/irqreturn.h
index bd4c066ad39b..b7385413bfac 100644
--- a/include/linux/irqreturn.h
+++ b/include/linux/irqreturn.h
@@ -8,6 +8,16 @@
* @IRQ_HANDLED interrupt was handled by this device
* @IRQ_WAKE_THREAD handler requests to wake the handler thread
*/
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - IRQ_NONE
+ * error 표시
+ * - IRQ_HANDLED
+ * 정상 처리
+ * - IRQ_WAKE_THREAD
+ * 정상 처리 + thread wakeup 요청
+ */
enum irqreturn {
IRQ_NONE = (0 << 0),
IRQ_HANDLED = (1 << 0),
diff --git a/include/linux/nospec.h b/include/linux/nospec.h
index c1e79f72cd89..6a980ca745af 100644
--- a/include/linux/nospec.h
+++ b/include/linux/nospec.h
@@ -48,6 +48,13 @@ static inline unsigned long array_index_mask_nospec(unsigned long index,
* array_index_nospec() will clamp the index within the range of [0,
* size).
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - 범위 검사. 주석참고
+ * array size보다 크면 0번으로 고정시킨다.
+ * mask는 정상값이면 ~0이므로 결과값은 결국 _i가 될것이다.
+ * 비정상일 경우 mask = 0이므로 결과는 무조건 0.
+ */
#define array_index_nospec(index, size) \
({ \
typeof(index) _i = (index); \
diff --git a/include/linux/preempt.h b/include/linux/preempt.h
index 15a5f9974a16..9efbf626f30e 100644
--- a/include/linux/preempt.h
+++ b/include/linux/preempt.h
@@ -84,6 +84,12 @@
#else
# define softirq_count() (preempt_count() & SOFTIRQ_MASK)
#endif
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - 해당 api가 interrupt context(nmi, hardirq, softirq)에서 실행됬는지
+ * 확인한다.
+ */
#define irq_count() (nmi_count() | hardirq_count() | softirq_count())
/*
@@ -109,8 +115,24 @@
* in_softirq() - We have BH disabled, or are processing softirqs
* in_interrupt() - We're in NMI,IRQ,SoftIRQ context or have BH disabled
*/
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - 해당 api가 interrupt context(hardirq)에서 실행됬는지 확인한다.
+ */
#define in_irq() (hardirq_count())
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - 해당 api가 interrupt context(softirq)에서 실행됬는지 확인한다.
+ */
#define in_softirq() (softirq_count())
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - 해당 api가 interrupt context(nmi, hardirq, softirq)에서 실행됬는지
+ * 확인한다.
+ */
#define in_interrupt() (irq_count())
/*
diff --git a/include/linux/sched.h b/include/linux/sched.h
index f72cb434afd7..bb20cd246c51 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -721,6 +721,15 @@ struct kmap_ctrl {
};
struct task_struct {
+/*
+ * IAMROOT, 2022.11.05:
+ * 아래 커널 옵션이 사용되는 경우 보안을 위해 task 구조체 내부의 가장 위에
+ * thread_info 구조체를 가지고 있게 한다.
+ *
+ * 기존엔 스택의 가장 마지막에 thread_info 구조체를 가지고 있어서,
+ * 이를 통해 task_struct의 위치를 금방 찾는 단점이 있었다.
+ */
+
#ifdef CONFIG_THREAD_INFO_IN_TASK
/*
* For reasons of header soup (see current_thread_info()), this
diff --git a/include/linux/sched/task_stack.h b/include/linux/sched/task_stack.h
index 7bd7b1fbdaa0..f01f725d3758 100644
--- a/include/linux/sched/task_stack.h
+++ b/include/linux/sched/task_stack.h
@@ -22,6 +22,13 @@
* try_get_task_stack() instead. task_stack_page will return a pointer
* that could get freed out from under you.
*/
+/*
+ * IAMROOT, 2022.11.08:
+ * - papago
+ * 종료될 수 있는 현재가 아닌 작업의 스택에 액세스할 때 대신
+ * try_get_task_stack()을 사용하십시오. task_stack_page는 아래에서 해제될 수
+ * 있는 포인터를 반환합니다.
+ */
static inline void *task_stack_page(const struct task_struct *task)
{
return task->stack;
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 0e1f49b216b8..ad4715d4d56c 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -498,6 +498,11 @@ void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu)
cpumask_set_cpu(cpu, desc->percpu_enabled);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - disable이 있다면 disable. 아니면 mask.
+ * - irq disalbe한다(gic. gic_mask_irq)
+ */
void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu)
{
if (desc->irq_data.chip->irq_disable)
@@ -618,6 +623,17 @@ void handle_nested_irq(unsigned int irq)
}
EXPORT_SYMBOL_GPL(handle_nested_irq);
+/*
+ * IAMROOT, 2022.11.12:
+ * @return false irq가 inprogress가 아님
+ * irq가 inprogress일때
+ * current cpu가 irq_poll_cpu라면. (예외처리 일종)
+* inprogress가 기다림 -> 기다리고 난후 irq가 disable이거나
+* action handler가 없다면.
+* true inprogress기다림 -> 기다리고 난 후 irq가 enable상태면서
+* action handler가 존재.
+* - inprogress중이라면 기다린다.
+*/
static bool irq_check_poll(struct irq_desc *desc)
{
if (!(desc->istate & IRQS_POLL_INPROGRESS))
@@ -625,6 +641,14 @@ static bool irq_check_poll(struct irq_desc *desc)
return irq_wait_for_poll(desc);
}
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - irq가 run 시킬수 있는지 확인한다. 필요하다면 wait까지 해본다.
+ * @return true.(running가능)
+ * inprogress, wakeup armed상태가 아니라면, 혹은 wait후에도 irq가
+ * enable 상태라면.
+ */
static bool irq_may_run(struct irq_desc *desc)
{
unsigned int mask = IRQD_IRQ_INPROGRESS | IRQD_WAKEUP_ARMED;
@@ -633,6 +657,11 @@ static bool irq_may_run(struct irq_desc *desc)
* If the interrupt is not in progress and is not an armed
* wakeup interrupt, proceed.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - 해당 interrupt가 진행중인지 확인한다. spi는 동시에 진입할수없다.
+ * 동시에 되는게 이상한상태.
+ */
if (!irqd_has_set(&desc->irq_data, mask))
return true;
@@ -641,6 +670,11 @@ static bool irq_may_run(struct irq_desc *desc)
* and suspended, disable it and notify the pm core about the
* event.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - wakeup업중인지 확인하고, wakeup이 아직 안되있으면
+ * irq를 끄고 pending으로 한후 wakepup시킨다.
+ */
if (irq_pm_check_wakeup(desc))
return false;
@@ -782,8 +816,23 @@ void handle_level_irq(struct irq_desc *desc)
}
EXPORT_SYMBOL_GPL(handle_level_irq);
+/*
+ * IAMROOT, 2022.11.12:
+ * - irq_eoi + unmask를 상황에 따라 처리한다.
+ * - 다음과 같은 조건들을 판단한다.
+ * IRQS_ONESHOT
+ * desc->threads_oneshot
+ * irqd_irq_masked
+ * irqd_irq_disabled
+ * IRQCHIP_EOI_THREADED
+ */
static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
{
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - oneshot이 아니면 irq_eoi만 처리.
+ */
if (!(desc->istate & IRQS_ONESHOT)) {
chip->irq_eoi(&desc->irq_data);
return;
@@ -794,6 +843,26 @@ static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
* spurious interrupt or a primary handler handling it
* completely).
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - papago
+ * 다음과 같은 경우 마스크를 해제해야 합니다.
+ * - 스레드를 깨우지 않은 Oneshot irq(spurious 인터럽트 또
+ * 이를 완전히 처리하는 기본 핸들러로 인해 발생).
+ *
+ * - thread인 경우 isr이 매우 짧다(thread만 생성하고 끝나기때문에)
+ * 이런 경우 만약 isr만 처리하고 eoi를 보낼경우 level 인경우 매우많은
+ * thread가 생길 위험이 있다. 이 경우에 대한 처리등을 진행한다. 즉
+ * 1.!irqd_irq_disabled(&desc->irq_data) => irq가 enable상태
+ * irqd_irq_masked(&desc->irq_data) => mask되있는 상태.
+ * !desc->threads_oneshot => oneshot thread가 아닌 상태
+ * 이 경우 eoi를 하고 다시 unmask를 하여 irq를 받아도 되는 상태.
+ * 2. !(chip->flags & IRQCHIP_EOI_THREADED) => thread에서 eoi처리를
+ * 안하는 상황. 즉 flow handler에서 처리한다.
+ * 3. thread에서 처리하거나, thread가 oneshot인 경우등은 eoi를
+ * 여기서 처리 안한다.
+ *
+ */
if (!irqd_irq_disabled(&desc->irq_data) &&
irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) {
chip->irq_eoi(&desc->irq_data);
@@ -812,6 +881,12 @@ static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
* for modern forms of interrupt handlers, which handle the flow
* details in hardware, transparently.
*/
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - 1. running 가능한지 확인한다.
+ * 2. oneshot인경우 masking.
+ */
void handle_fasteoi_irq(struct irq_desc *desc)
{
struct irq_chip *chip = desc->irq_data.chip;
@@ -827,6 +902,13 @@ void handle_fasteoi_irq(struct irq_desc *desc)
* If its disabled or no action available
* then mask it and get out of here:
*/
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - running할수있는 단계까지 왓는데 @desc가 action handler가 없거나
+ * irq disable상태다. pending으로 표시 및 masking하고 out.
+ * 추후에 enable될때 edge trigger만 재전송한다.
+ */
if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
desc->istate |= IRQS_PENDING;
mask_irq(desc);
@@ -834,11 +916,24 @@ void handle_fasteoi_irq(struct irq_desc *desc)
}
kstat_incr_irqs_this_cpu(desc);
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - oneshot이면 @desc를 masking한다.
+ */
if (desc->istate & IRQS_ONESHOT)
mask_irq(desc);
+/*
+ * IAMROOT, 2022.11.12:
+ * - action event handler 처리.
+ */
handle_irq_event(desc);
+/*
+ * IAMROOT, 2022.11.12:
+ * - eoi + unmask 처리 여부 판단
+ */
cond_unmask_eoi_irq(desc, chip);
raw_spin_unlock(&desc->lock);
@@ -1035,6 +1130,20 @@ void handle_percpu_irq(struct irq_desc *desc)
* contain the real device id for the cpu on which this handler is
* called
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - papago
+ * handle_percpu_devid_irq - per cpu dev ID가 있는 per cpu local irq handler
+ * @desc: 이 irq에 대한 인터럽트 설명 구조.
+ *
+ * 잠금 요구 사항이 없는 SMP 시스템의 CPU당 인터럽트. 위의
+ * handle_percpu_irq()와 동일하지만 다음과 같은 추가 사항이 있습니다.
+ *
+ * action->percpu_dev_id는 이 핸들러가 호출되는 CPU의 실제 장치 ID를
+ * 포함하는 percpu 변수에 대한 포인터입니다.
+ *
+ * - action handler를 실행한다. 실행전후로 ack 및 irq_eoi를 수행한다.
+ */
void handle_percpu_devid_irq(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
@@ -1048,9 +1157,18 @@ void handle_percpu_devid_irq(struct irq_desc *desc)
*/
__kstat_incr_irqs_this_cpu(desc);
+/*
+ * IAMROOT, 2022.11.12:
+ * - irq_ack가 있으면 여기서 보낸다. gic경우는 iar을 읽을시 자동으로 ack가
+ * 나가는 구조라 없다.
+ */
if (chip->irq_ack)
chip->irq_ack(&desc->irq_data);
+/*
+ * IAMROOT, 2022.11.12:
+ * - action이 없는데 들어왔다면 이상한 상황. irq disable한다.
+ */
if (likely(action)) {
trace_irq_handler_entry(irq, action);
res = action->handler(irq, raw_cpu_ptr(action->percpu_dev_id));
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index 8ba3b799acaa..a73144ab6ee0 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -60,6 +60,10 @@ static void warn_no_thread(unsigned int irq, struct irqaction *action)
"but no thread function available.", irq, action->name);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - flag를 정리하고 wake_up_process를 한다.
+ */
void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
{
/*
@@ -67,6 +71,15 @@ void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
* we handled the interrupt. The hardirq handler has disabled the
* device interrupt, so no irq storm is lurking.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - papago
+ * 쓰레드가 크래시를 일으키고 죽으면 우리는 인터럽트를 처리한 척합니다.
+ * hardirq 처리기가 장치 인터럽트를 비활성화했으므로 irq 스톰이 숨어 있지
+ * 않습니다.
+ *
+ * - @desc를 사용하는 thread가 종료중. 굳이 처리 할필요없다.
+ */
if (action->thread->flags & PF_EXITING)
return;
@@ -74,6 +87,15 @@ void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
* Wake up the handler thread for this action. If the
* RUNTHREAD bit is already set, nothing to do.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - papago
+ * 이 작업에 대한 핸들러 스레드를 깨우십시오. RUNTHREAD 비트가 이미
+ * 설정되어 있으면 아무 작업도 수행할 수 없습니다.
+ *
+ * - IRQTF_RUNTHREAD이게 있다면 이미 thread 깨웠다. 빠져나간다.
+ * 아니라면 set한다. (test and set)
+ */
if (test_and_set_bit(IRQTF_RUNTHREAD, &action->thread_flags))
return;
@@ -122,6 +144,34 @@ void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
* IRQTF_RUNTHREAD under desc->lock. If set it leaves
* threads_oneshot untouched and runs the thread another time.
*/
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - papago
+ * 여기에서 마스크 잠금 장치를 사용하지 않는 것이 안전합니다.
+ * thread_oneshot에 쓰는 곳은 두 곳뿐입니다: 이 코드와 irq 스레드.
+ *
+ * 이 코드는 하드 irq 컨텍스트이며 두 개의 CPU에서 병렬로 실행할 수
+ * 없습니다. 그렇다면 이 비트마스크보다 더 심각한 문제가 발생합니다
+ *
+ * thread_oneshot에서 실행 비트를 지우는 이 irq의 irq 스레드는 서로에 대해
+ * desc->lock을 통해 직렬화되고 IRQS_INPROGRESS에 의해 이 코드에 대해
+ * 직렬화됩니다.
+ *
+ * ...
+ *
+ * 따라서 스레드는 우리가 IRQS_INPROGRESS를 지우기를 기다리거나 이 지점에
+ * 도달하기 전에 desc->lock이 해제되기 위해 flow handler에서 기다리고
+ * 있습니다. 스레드는 또한 desc->lock에서 IRQTF_RUNTHREAD를 확인합니다.
+ * 설정하면 thread_oneshot을 그대로 두고 스레드를 다시 실행합니다.
+ *
+ * - hard_irq
+ * spin_lock은 flag제어 할때에만 사용하고, spin_lock안에서 flag로
+ * 직렬화 처리를 한다.(handle_irq_event() 참고)
+ *
+ * - irq thread
+ * spin_lock을 통해서 inprogress를 check한다.
+ */
desc->threads_oneshot |= action->thread_mask;
/*
@@ -133,11 +183,25 @@ void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
* against this code (hard irq handler) via IRQS_INPROGRESS
* like the finalize_oneshot() code. See comment above.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - papago
+ * irq 스레드를 깨울 경우에 대비하여 thread_active 카운터를 증가시킵니다.
+ * irq 스레드는 핸들러에서 또는 종료 경로로 돌아올 때 카운터를 감소시키고
+ * 활성 카운트가 0이 될 때 synchronized_irq()에 갇혀 있는 웨이터를
+ * 깨웁니다. synchronize_irq()는 finalize_oneshot() 코드와 같이
+ * IRQS_INPROGRESS를 통해 이 코드(하드 irq 핸들러)에 대해 직렬화됩니다.
+ * 위의 주석을 참조하십시오.
+ */
atomic_inc(&desc->threads_active);
wake_up_process(action->thread);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - action handler를 수행후 필요하다면 thread도 생성한다.
+ */
irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags)
{
irqreturn_t retval = IRQ_NONE;
@@ -146,12 +210,23 @@ irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags
record_irq_time(desc);
+/*
+ * IAMROOT, 2022.11.12:
+ * - spi이므로 여러개가 있을수있다.
+ */
for_each_action_of_desc(desc, action) {
irqreturn_t res;
/*
* If this IRQ would be threaded under force_irqthreads, mark it so.
*/
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - threaded irq 인지 확인한다.
+ * irq_settings_can_thread(desc) : contoller에서 결정.
+ * action->flags : user에서 결정.
+ */
if (irq_settings_can_thread(desc) &&
!(action->flags & (IRQF_NO_THREAD | IRQF_PERCPU | IRQF_ONESHOT)))
lockdep_hardirq_threaded();
@@ -164,12 +239,21 @@ irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags
irq, action->handler))
local_irq_disable();
+/*
+ * IAMROOT, 2022.11.12:
+ * - result여부에 따라 thread를 wakeup한다.
+ */
switch (res) {
case IRQ_WAKE_THREAD:
/*
* Catch drivers which return WAKE_THREAD but
* did not set up a thread function
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - thread fn이 등록이 안됬는데 thread wake 요청이 온경우 경고를 띄우고
+ * break.
+ */
if (unlikely(!action->thread_fn)) {
warn_no_thread(irq, action);
break;
@@ -192,6 +276,10 @@ irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags
return retval;
}
+/*
+ * IAMROOT, 2022.11.12:
+ * -
+ */
irqreturn_t handle_irq_event_percpu(struct irq_desc *desc)
{
irqreturn_t retval;
@@ -206,6 +294,14 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc)
return retval;
}
+/*
+ * IAMROOT, 2022.11.12:
+ * pending flag가 여기서 지워지고, inprogress를 표시한다.
+ * V
+ * handler 실행.
+ * V
+ * inprogress clear.
+ */
irqreturn_t handle_irq_event(struct irq_desc *desc)
{
irqreturn_t ret;
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
index b4674c379965..f99e63500ca1 100644
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -687,6 +687,10 @@ void irq_init_desc(unsigned int irq)
#endif /* !CONFIG_SPARSE_IRQ */
+/*
+ * IAMROOT, 2022.11.12:
+ * - @desc의 irq를 hadndle한다.
+ */
int handle_irq_desc(struct irq_desc *desc)
{
struct irq_data *data;
@@ -695,6 +699,12 @@ int handle_irq_desc(struct irq_desc *desc)
return -EINVAL;
data = irq_desc_get_irq_data(desc);
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - irq진입상태인데, preempt_count가 없는 상태면(혹은 없어도
+ * IRQD_HANDLE_ENFORCE_IRQCTX 상태가 아니라면) 이상한 상황이다.
+ */
if (WARN_ON_ONCE(!in_irq() && handle_enforce_irqctx(data)))
return -EPERM;
@@ -741,6 +751,12 @@ EXPORT_SYMBOL_GPL(generic_handle_domain_irq);
*
* Returns: 0 on success, or -EINVAL if conversion has failed
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - 1.stack에 backup해두었던것을 전역 pcpu 에 저장.
+ * 원래 전역 pcpu에 있던 old_regs는 handler 완료후 원복한다.
+ * 2. @domain에서 @hwirq를 검색해와서 handler를 실행한다.
+ */
int handle_domain_irq(struct irq_domain *domain,
unsigned int hwirq, struct pt_regs *regs)
{
@@ -748,8 +764,16 @@ int handle_domain_irq(struct irq_domain *domain,
struct irq_desc *desc;
int ret = 0;
+/*
+ * IAMROOT, 2022.11.05:
+ * hardirq에 대한 preempt_count를 1 증가시킨다.
+ */
irq_enter();
+/*
+ * IAMROOT, 2022.11.05:
+ * domain + hwirq로 irq 디스크립터를 검색해온다.
+ */
/* The irqdomain code provides boundary checks */
desc = irq_resolve_mapping(domain, hwirq);
if (likely(desc))
@@ -757,6 +781,10 @@ int handle_domain_irq(struct irq_domain *domain,
else
ret = -EINVAL;
+/*
+ * IAMROOT, 2022.11.05:
+ * hardirq에 대한 preempt_count를 1 감소시킨다.
+ */
irq_exit();
set_irq_regs(old_regs);
return ret;
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index a581ffcf7975..f4e4cad52d6d 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1703,9 +1703,9 @@ setup_irq_thread(struct irqaction *new, unsigned int irq, bool secondary)
* 7. /proc/에 생성된 irq번호로 자료구조 추가.
*
* - irq 흐름.
- * vector
+ * vectors(arch/arm64/kernel/entry.S)
* v
- * chip handler
+ * chip handler(handler_arch_irq, gic의 경우 gic_handle_irq)
* v
* flow handler
* v
@@ -3081,7 +3081,6 @@ int setup_percpu_irq(unsigned int irq, struct irqaction *act)
*
* Dev_id는 전역적으로 고유해야 합니다. 이것은 CPU당 변수이며 핸들러는
* 해당 변수의 인터럽트된 CPU 인스턴스와 함께 호출됩니다.
- *
* - ex) ipi의 경우 ipi_handler()
*
* - irq 흐름.
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c
index d7163b503b0b..d1ed7d6e0582 100644
--- a/kernel/irq/pm.c
+++ b/kernel/irq/pm.c
@@ -13,8 +13,20 @@
#include "internals.h"
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - wakeup 중인지 확인한다.
+ */
bool irq_pm_check_wakeup(struct irq_desc *desc)
{
+/*
+ * IAMROOT, 2022.11.12:
+ * - 안깨어있다면.
+ * suspend 상태로 표시.
+ * pending으로 표시.
+ * irq_disable후 wakeup 시도.
+ */
if (irqd_is_wakeup_armed(&desc->irq_data)) {
irqd_clear(&desc->irq_data, IRQD_WAKEUP_ARMED);
desc->istate |= IRQS_SUSPENDED | IRQS_PENDING;
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index 41d3e212368a..a873d6c6e133 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -33,6 +33,23 @@ static atomic_t irq_poll_active;
* action (about to be disabled). Only if it's still active, we return
* true and let the handler run.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - papago
+ * 우리는 poller가 끝날 때까지 여기서 기다립니다.
+ *
+ * 이 CPU에서 poll이 실행되면 큰 소리로 외치고 false를 반환합니다.
+ * 그러면 최악의 경우 인터럽트 라인이 비활성화되지만 절대 발생해서는
+ * 안됩니다.
+ *
+ * poller가 완료될 때까지 기다렸다가 비활성화 및 작업(비활성화될 예정)을
+ * 다시 확인합니다. 여전히 활성 상태인 경우에만 true를 반환하고 핸들러를
+ * 실행합니다.
+ *
+ * - poll하고 있는게 current cpu라면 false.
+ * irq_data가 porgress끝날때가지 기다린다.
+ * - @desc가 enable상태고 action handler가 존재하면 return true;
+ */
bool irq_wait_for_poll(struct irq_desc *desc)
__must_hold(&desc->lock)
{
@@ -51,6 +68,11 @@ bool irq_wait_for_poll(struct irq_desc *desc)
/* Might have been disabled in meantime */
return !irqd_irq_disabled(&desc->irq_data) && desc->action;
#else
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - single core면 polling이 불가능하다.
+ */
return false;
#endif
}
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index bce848e50512..4be18273af72 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -802,6 +802,10 @@ noinstr void rcu_nmi_exit(void)
* If you add or remove a call to rcu_irq_exit(), be sure to test with
* CONFIG_RCU_EQS_DEBUG=y.
*/
+/*
+ * IAMROOT, 2022.11.11:
+ * - TODO
+ */
void noinstr rcu_irq_exit(void)
{
lockdep_assert_irqs_disabled();
@@ -1065,6 +1069,10 @@ noinstr void rcu_nmi_enter(void)
* If you add or remove a call to rcu_irq_enter(), be sure to test with
* CONFIG_RCU_EQS_DEBUG=y.
*/
+/*
+ * IAMROOT, 2022.11.11:
+ * - TODO
+ */
noinstr void rcu_irq_enter(void)
{
lockdep_assert_irqs_disabled();
diff --git a/kernel/softirq.c b/kernel/softirq.c
index a12dbf8ca8bd..cba80841de7d 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -71,6 +71,10 @@ const char * const softirq_to_name[NR_SOFTIRQS] = {
* to the pending events, so lets the scheduler to balance
* the softirq load for us.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - wakeup ksoftirqd
+ */
static void wakeup_softirqd(void)
{
/* Interrupts are disabled: no need to stop preemption */
@@ -131,6 +135,22 @@ EXPORT_PER_CPU_SYMBOL_GPL(hardirq_context);
* The per CPU counter prevents pointless wakeups of ksoftirqd in case that
* the task which is in a softirq disabled section is preempted or blocks.
*/
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - papago
+ * RT는 task::softirqs_disabled_cnt 및 CPU softirq_ctrl::cnt별로 BH
+ * 비활성화 섹션을 설명합니다. 이것은 softirq 비활성화 섹션의 작업이
+ * 선점되도록 하는 데 필요합니다.
+ *
+ * 작업당 카운터는 softirq_count(), in_softirq() 및
+ * in_serving_softirqs()에 사용됩니다. 이러한 카운트는
+ * softirq_ctrl::lock을 보유하는 작업이 실행 중일 때만 유효하기
+ * 때문입니다.
+ *
+ * CPU당 카운터는 softirq 비활성화 섹션에 있는 작업이 선점되거나
+ * 차단되는 경우 ksoftirqd의 무의미한 깨우기를 방지합니다.
+ */
struct softirq_ctrl {
local_lock_t lock;
int cnt;
@@ -266,6 +286,11 @@ EXPORT_SYMBOL(__local_bh_enable_ip);
* Invoked from ksoftirqd_run() outside of the interrupt disabled section
* to acquire the per CPU local lock for reentrancy protection.
*/
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - preempt.
+ */
static inline void ksoftirqd_run_begin(void)
{
__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
@@ -283,11 +308,20 @@ static inline void ksoftirqd_run_end(void)
static inline void softirq_handle_begin(void) { }
static inline void softirq_handle_end(void) { }
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - cnt가 없으면 true.
+ */
static inline bool should_wake_ksoftirqd(void)
{
return !this_cpu_read(softirq_ctrl.cnt);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - softirq_ctrl::cnt == 0이면 softirq wakeup
+ */
static inline void invoke_softirq(void)
{
if (should_wake_ksoftirqd())
@@ -402,6 +436,10 @@ static inline void softirq_handle_end(void)
WARN_ON_ONCE(in_interrupt());
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - !preempt
+ */
static inline void ksoftirqd_run_begin(void)
{
local_irq_disable();
@@ -417,11 +455,20 @@ static inline bool should_wake_ksoftirqd(void)
return true;
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - !preempt
+ * 직접 처리하거나, ksoftirqd을 이용해서 처리하거나를 결정한다.
+ */
static inline void invoke_softirq(void)
{
if (ksoftirqd_running(local_softirq_pending()))
return;
+/*
+ * IAMROOT, 2022.11.12:
+ * - 1. !preempt 이거나 ksoftirqd이 없으면 직접 처리한다.
+ */
if (!force_irqthreads() || !__this_cpu_read(ksoftirqd)) {
#ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK
/*
@@ -429,6 +476,10 @@ static inline void invoke_softirq(void)
* it is the irq stack, because it should be near empty
* at this stage.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - 직접 실행한다.
+ */
__do_softirq();
#else
/*
@@ -443,6 +494,10 @@ static inline void invoke_softirq(void)
}
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - TODO
+ */
asmlinkage __visible void do_softirq(void)
{
__u32 pending;
@@ -512,6 +567,10 @@ static inline bool lockdep_softirq_start(void) { return false; }
static inline void lockdep_softirq_end(bool in_hardirq) { }
#endif
+/*
+ * IAMROOT, 2022.11.12:
+ * - TODO
+ */
asmlinkage __visible void __softirq_entry __do_softirq(void)
{
unsigned long end = jiffies + MAX_SOFTIRQ_TIME;
@@ -593,6 +652,10 @@ asmlinkage __visible void __softirq_entry __do_softirq(void)
*/
void irq_enter_rcu(void)
{
+/*
+ * IAMROOT, 2022.11.05:
+ * hardirq에 대한 preempt_count를 1 증가시킨다.
+ */
__irq_enter_raw();
if (is_idle_task(current) && (irq_count() == HARDIRQ_OFFSET))
@@ -623,6 +686,14 @@ static inline void tick_irq_exit(void)
#endif
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - preempt count감소후 필요에따라 softirq실행
+ * - softirq가 실행되는 상황.
+ * 현재 irq가 중첩이 안됬다면 preempt_count_sub로 인해
+ * !in_interrupt() 조건이 될수있다. 이 상황에서 pending softirq가 있다면
+ * invoke_softirq()를 수행한다.
+ */
static inline void __irq_exit_rcu(void)
{
#ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED
@@ -631,7 +702,16 @@ static inline void __irq_exit_rcu(void)
lockdep_assert_irqs_disabled();
#endif
account_hardirq_exit(current);
+/*
+ * IAMROOT, 2022.11.05:
+ * 인터럽트를 빠져나갈때 HARDIRQ_OFFSET에 대한 preempt count를 1 감소 시킨다.
+ */
preempt_count_sub(HARDIRQ_OFFSET);
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - hardirq 처리후 softirq가 pending되있으면 softirq를 일으킨다.
+ */
if (!in_interrupt() && local_softirq_pending())
invoke_softirq();
@@ -655,8 +735,18 @@ void irq_exit_rcu(void)
*
* Also processes softirqs if needed and possible.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - hardirq preempt count 감소.
+ * - 경우에 따라 softirq 수행.
+ */
void irq_exit(void)
{
+/*
+ * IAMROOT, 2022.11.05:
+ * 아래 함수에서 hardirq에 대한 preempt_count 감소와,
+ * peinding 상태의 softirq 호출이 이루어진다.
+ */
__irq_exit_rcu();
rcu_irq_exit();
/* must be last! */
@@ -666,6 +756,10 @@ void irq_exit(void)
/*
* This function must run with irqs disabled!
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - pending을 일단하고 현재 context가 kernel thread인 경우는 바로 깨운다.
+ */
inline void raise_softirq_irqoff(unsigned int nr)
{
__raise_softirq_irqoff(nr);
@@ -679,6 +773,17 @@ inline void raise_softirq_irqoff(unsigned int nr)
* Otherwise we wake up ksoftirqd to make sure we
* schedule the softirq soon.
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - papago
+ * 인터럽트 또는 softirq에 있으면 작업이 완료됩니다(softirq 비활성화
+ * 코드도 포착됨). irq 또는 softirq에서 돌아오면 실제로
+ * softirq를 실행할 것입니다.
+ *
+ * 그렇지 않으면 ksoftirqd를 깨워 softirq를 곧 예약하도록 합니다.
+ * - !in_interrupt()
+ * 현재 함수의 call이 irq context아니라면 수행한다.
+ */
if (!in_interrupt() && should_wake_ksoftirqd())
wakeup_softirqd();
}
@@ -696,6 +801,11 @@ void raise_softirq(unsigned int nr)
local_irq_restore(flags);
}
+/*
+ * IAMROOT, 2022.11.12:
+ * - softirq 요청 처리.
+ * - @nr에 해당하는 bitmask를 set한다.
+ */
void __raise_softirq_irqoff(unsigned int nr)
{
lockdep_assert_irqs_disabled();
diff --git a/kernel/stackleak.c b/kernel/stackleak.c
index ce161a8e8d97..4d337c34c66f 100644
--- a/kernel/stackleak.c
+++ b/kernel/stackleak.c
@@ -48,6 +48,10 @@ int stack_erasing_sysctl(struct ctl_table *table, int write,
#define skip_erasing() false
#endif /* CONFIG_STACKLEAK_RUNTIME_DISABLE */
+/*
+ * IAMROOT, 2022.11.09:
+ * - PASS
+ */
asmlinkage void notrace stackleak_erase(void)
{
/* It would be nice not to have 'kstack_ptr' and 'boundary' on stack */
diff --git a/mm/memory.c b/mm/memory.c
index 7d1250c81605..63f4e31e9a2b 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -4702,6 +4702,10 @@ static vm_fault_t wp_huge_pud(struct vm_fault *vmf, pud_t orig_pud)
* The mmap_lock may have been released depending on flags and our return value.
* See filemap_fault() and __lock_page_or_retry().
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - pte entry에 memory를 할당받아서 연결한다.
+ */
static vm_fault_t handle_pte_fault(struct vm_fault *vmf)
{
pte_t entry;
@@ -4828,6 +4832,10 @@ static vm_fault_t handle_pte_fault(struct vm_fault *vmf)
* The mmap_lock may have been released depending on flags and our
* return value. See filemap_fault() and __lock_page_or_retry().
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - table 만든후 pte fault수행.
+ */
static vm_fault_t __handle_mm_fault(struct vm_area_struct *vma,
unsigned long address, unsigned int flags)
{
@@ -4984,6 +4992,10 @@ static inline void mm_account_fault(struct pt_regs *regs,
* The mmap_lock may have been released depending on flags and our
* return value. See filemap_fault() and __lock_page_or_retry().
*/
+/*
+ * IAMROOT, 2022.11.12:
+ * - mm fault 수행
+ */
vm_fault_t handle_mm_fault(struct vm_area_struct *vma, unsigned long address,
unsigned int flags, struct pt_regs *regs)
{
@@ -5009,6 +5021,11 @@ vm_fault_t handle_mm_fault(struct vm_area_struct *vma, unsigned long address,
if (flags & FAULT_FLAG_USER)
mem_cgroup_enter_user_fault();
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - mm fault 수행
+ */
if (unlikely(is_vm_hugetlb_page(vma)))
ret = hugetlb_fault(vma->vm_mm, vma, address, flags);
else
@@ -5060,6 +5077,11 @@ int __p4d_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address)
* Allocate page upper directory.
* We've already handled the fast-path in-line.
*/
+
+/*
+ * IAMROOT, 2022.11.12:
+ * - p4d에 연결(populate)한다.
+ */
int __pud_alloc(struct mm_struct *mm, p4d_t *p4d, unsigned long address)
{
pud_t *new = pud_alloc_one(mm, address);
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
공지 | [공지] 스터디 정리 노트 공간입니다. | woos | 2016.05.14 | 626 |
167 | [커널 18차] 80주차 | kkr | 2022.12.03 | 156 |
166 | [커널 19차] 28 ~ 29 주차 | Min | 2022.12.03 | 35 |
165 | [커널 19차] 27 주차 | Min | 2022.11.22 | 82 |
164 | [커널 18차] 78주차 | kkr | 2022.11.19 | 187 |
163 | [커널 19차] 25 ~ 26 주차 | Min | 2022.11.14 | 72 |
» | [커널 18차] 76-77주차 | kkr | 2022.11.12 | 386 |
161 | [커널 19차] 24주차 | Min | 2022.10.31 | 108 |
160 | [커널 17차] 112주차 | ㅇㅇㅇ | 2022.10.30 | 81 |
159 | [커널 18차] 75주차 | kkr | 2022.10.29 | 40 |
158 | [커널 17차] 107 ~ 111주차 | ㅇㅇㅇ | 2022.10.23 | 77 |
157 | [커널 19차] 22주차 | Min | 2022.10.17 | 76 |
156 | [커널 18차] 73주차 | kkr | 2022.10.15 | 46 |
155 | [커널 18차] 72주차 | kkr | 2022.10.09 | 183 |
154 | [커널 18차] 71주차 | kkr | 2022.10.01 | 75 |
153 | [커널 18차] 70주차 | kkr | 2022.09.24 | 77 |
152 | [커널 18차] 69주차 | kkr | 2022.09.22 | 58 |
151 | [커널 17차] 105~106주차 | ㅇㅇㅇ | 2022.09.18 | 50 |
150 | [커널 17차] 104주차 | ㅇㅇㅇ | 2022.09.04 | 88 |
149 | [커널 18차] 67주차 | kkr | 2022.09.03 | 138 |
148 | [커널 17차] 103주차 | ㅇㅇㅇ | 2022.08.28 | 35 |
.