九章编程法实战:重构 Linux 内核软中断子系统,千行核心代码压缩到388 行题-CSDN博客
本文是按此C码,严格依照九章编译法,生成汇编码。
# Linux软中断调度器 · 九章空间几何结构直译汇编
# 三元对齐标准:单指令 = 操作码 + 源操作数 + 目的/标志位
# Arch: x86_64 System V ABI, GCC as
# 几何常量完全绑定C宏,无硬编码虚化数值
.section .rodata
.align 8
# 软中断名字符串(只读几何常量)
hi_name: .asciz "hi"
timer_name: .asciz "timer"
net_tx_name: .asciz "net_tx"
net_rx_name: .asciz "net_rx"
block_name: .asciz "block"
irq_poll_name: .asciz "irq_poll"
tasklet_name: .asciz "tasklet"
sched_name: .asciz "sched"
hrtimer_name: .asciz "hrtimer"
rcu_name: .asciz "rcu"
# C struct softirq_desc [name, budget, weight, wake_thread_on_full]
softirq_table:
.quad hi_name, 10, 4, 1
.quad timer_name, 100, 1, 1
.quad net_tx_name, 64, 1, 1
.quad net_rx_name, 64, 1, 1
.quad block_name, 32, 1, 1
.quad irq_poll_name,32, 1, 1
.quad tasklet_name, 0, 1, 1
.quad sched_name, 0, 2, 0
.quad hrtimer_name,0, 1, 1
.quad rcu_name, 0, 2, 0
# 全局几何常量(与C完全同构)
NR_SOFTIRQS = 10
MAX_RESTART = 10
MAX_PRESSURE = 10000000000
INT_MAX = 0x7fffffff
# per-CPU irq_cpustat_t 几何偏移(严格对齐C结构体布局)
PENDING_OFFSET = 0 # u32 __softirq_pending
SUM_OFFSET = 4 # u64 softirqs_sum[10]
PRESSURE_OFFSET = 84 # u64 softirqs_pressure
IRQ_STAT_SIZE = 96
# 全局导出符号
.globl do_softirq
.globl raise_softirq
.globl raise_softirq_irqoff
.globl __raise_softirq_irqoff
.globl open_softirq
.globl softirq_cpu_dead
.globl ksoftirqd_entry
.section .bss
.align 64
# per-CPU 运行存储几何(最多64CPU,空间精确计算无冗余)
per_cpu_irq_stat:
.space IRQ_STAT_SIZE * 64
per_cpu_ksoftirqd:
.space 8 * 64
# softirq动作向量表 void (*action)(struct softirq_action *)
softirq_vec:
.space 8 * NR_SOFTIRQS
.section .text
# ===================== 三元算子:位图操作 纯几何基元 =====================
# si_pend_set(cpu=rdi, nr=esi) 三元:shl(src)|or(op)|内存dst
si_pend_set:
shlq $4, %rdi
lea per_cpu_irq_stat(%rip), %rax
addq %rdi, %rax
movl $1, %ecx
shll %cl, %esi
orl %esi, PENDING_OFFSET(%rax)
ret
# si_pend_clr(cpu=rdi, nr=esi)
si_pend_clr:
shlq $4, %rdi
lea per_cpu_irq_stat(%rip), %rax
addq %rdi, %rax
movl $1, %ecx
shll %cl, %esi
notl %esi
andl %esi, PENDING_OFFSET(%rax)
ret
# si_pend_get(cpu=rdi) -> eax 返回pending位图
si_pend_get:
shlq $4, %rdi
lea per_cpu_irq_stat(%rip), %rax
addq %rdi, %rax
movl PENDING_OFFSET(%rax), %eax
ret
# ===================== 三元算子:ksoftirqd线程唤醒 =====================
# si_wake_thread(cpu=rdi)
si_wake_thread:
pushq %rbx
movl %edi, %ebx
shlq $3, %rdi
lea per_cpu_ksoftirqd(%rip), %rax
movq (%rax,%rdi), %rdi
testq %rdi, %rdi
jz .wake_exit
callq task_is_running
testl %eax, %eax
jnz .wake_exit
movq %rdi, %rdi
callq wake_up_process
.wake_exit:
popq %rbx
ret
# ===================== 三元算子:软中断耗时统计 si_account =====================
# si_account(nr=rdi, start=rsi)
si_account:
pushq %rbx
movq %rsi, %rbx
callq smp_processor_id
movl %eax, %r8d
shlq $4, %rax
lea per_cpu_irq_stat(%rip), %rcx
addq %rax, %rcx
callq sched_clock
subq %rbx, %rax
# sum += delta
movq %rax, %rdx
shlq $3, %rdi
addq $SUM_OFFSET, %rdi
addq %rdx, (%rcx,%rdi)
# pressure += delta * weight
lea softirq_table(%rip), %rsi
shlq $4, %rdi
movl 16(%rsi,%rdi), %edi
mulq %rdi
addq %rax, PRESSURE_OFFSET(%rcx)
popq %rbx
ret
# ===================== 核心调度骨架 do_softirq 完整三元分支直译 =====================
do_softirq:
pushq %rbp
movq %rsp, %rbp
pushq %rbx
pushq %r12
pushq %r13
pushq %r14
pushq %r15
# 判定1:中断上下文直接返回
callq in_interrupt
testl %eax, %eax
jnz .softirq_done
# 保存中断标志 local_irq_save
pushfq
popq %r15
cli
callq smp_processor_id
movl %eax, %r12d
movl %r12d, %edi
callq si_pend_get
movl %eax, %r13d
testl %r13d, %r13d
jz .irq_restore
movl $MAX_RESTART, %r14d
.softirq_loop:
# 三元判定1 pending==0
testl %r13d, %r13d
jz .irq_restore
# 三元判定2 restart <= 0
cmpl $0, %r14d
jle .wake_ksoftirqd_jmp
# 读取per-cpu压力值
movl %r12d, %edi
shlq $4, %rdi
lea per_cpu_irq_stat(%rip), %rax
addq %rdi, %rax
movq PRESSURE_OFFSET(%rax), %rbx
# 三元判定3 pressure > MAX_PRESSURE
cmpq $MAX_PRESSURE, %rbx
ja .wake_ksoftirqd_jmp
# 本轮快照mask = pending
movl %r13d, %r8d
xorl %r9d, %r9d
.softirq_inner:
cmpl $NR_SOFTIRQS, %r9d
jge .round_next
testl %r8d, (1<<%r9d)
jz .inner_skip
# 清除当前软中断pending位
movl %r12d, %edi
movl %r9d, %esi
callq si_pend_clr
# 读取budget
lea softirq_table(%rip), %rax
shlq $4, %r9
movl 8(%rax,%r9), %ecx
testl %ecx, %ecx
jnz .budget_ok
movl $INT_MAX, %ecx
.budget_ok:
# 开中断执行action
sti
lea softirq_vec(%rip), %rax
movq (%rax,%r9,8), %rdi
callq sched_clock
movq %rax, %rsi
callq *%rdi
movl %r9d, %rdi
movq %rsi, %rsi
callq si_account
cli
# mask清除当前位
movl $1, %edx
shll %dl, %r9d
notl %edx
andl %edx, %r8d
.inner_skip:
incl %r9d
jmp .softirq_inner
.round_next:
# 刷新pending、restart自减
movl %r12d, %edi
callq si_pend_get
movl %eax, %r13d
decl %r14d
jmp .softirq_loop
.wake_ksoftirqd_jmp:
movl %r12d, %edi
callq si_wake_thread
.irq_restore:
# 恢复中断标志 local_irq_restore
pushq %r15
popfq
.softirq_done:
popq %r15
popq %r14
popq %r13
popq %r12
popq %rbx
popq %rbp
ret
# ===================== 对外标准接口直译 =====================
# raise_softirq_irqoff(nr=rdi)
raise_softirq_irqoff:
pushq %rbx
movl %edi, %ebx
callq smp_processor_id
movl %eax, %edi
movl %ebx, %esi
callq si_pend_set
popq %rbx
ret
# __raise_softirq_irqoff 别名
__raise_softirq_irqoff:
jmp raise_softirq_irqoff
# raise_softirq(nr=rdi) 带中断保存恢复
raise_softirq:
pushq %rbx
pushfq
popq %r10
movl %edi, %ebx
cli
callq smp_processor_id
movl %eax, %edi
movl %ebx, %esi
callq si_pend_set
pushq %r10
popfq
popq %rbx
ret
# open_softirq(nr=rdi, action=rsi) 注册软中断回调
open_softirq:
lea softirq_vec(%rip), %rax
movq %rsi, (%rax,%rdi,8)
ret
# CPU离线清理 softirq_cpu_dead(cpu=rdi)
softirq_cpu_dead:
pushq %rbx
movl %edi, %ebx
xorl %r9d, %r9d
.dead_loop:
cmpl $NR_SOFTIRQS, %r9d
jge .dead_wake
movl %ebx, %edi
callq si_pend_get
testl %eax, (1<<%r9d)
jz .dead_skip
movl %ebx, %edi
movl %r9d, %esi
callq si_pend_clr
callq smp_processor_id
movl %eax, %edi
movl %r9d, %esi
callq si_pend_set
.dead_skip:
incl %r9d
jmp .dead_loop
.dead_wake:
callq smp_processor_id
movl %eax, %edi
callq si_wake_thread
popq %rbx
ret
# ksoftirqd内核线程入口 ksoftirqd_entry(__bind_cpu=rdi)
ksoftirqd_entry:
pushq %rbx
movq %rdi, %rbx
.ksoft_loop:
callq kthread_should_stop
testl %eax, %eax
jnz .ksoft_exit
callq smp_processor_id
movl %eax, %edi
callq si_pend_get
testl %eax, %eax
jnz .run_softirq
movq $TASK_INTERRUPTIBLE, %rdi
callq set_current_state
callq schedule
jmp .ksoft_loop
.run_softirq:
movq $TASK_RUNNING, %rdi
callq __set_current_state
callq do_softirq
movq $TASK_INTERRUPTIBLE, %rdi
callq set_current_state
jmp .ksoft_loop
.ksoft_exit:
movq $TASK_RUNNING, %rdi
callq __set_current_state
xorl %eax, %eax
popq %rbx
ret
1685

被折叠的 条评论
为什么被折叠?



