当前位置: 首页 > news >正文

Linux内核,内存分布

x86_64的物理地址范围为64bit,但是因为地址空间太大目前不可能完全用完,当前支持57bit和48bit两种虚拟地址模式。

地址模式单个空间用户地址空间内核地址空间
32位2G0x00000000 - 0x7FFFFFFF0x80000000 - 0xFFFFFFFF
64位(48bit)128T0x00000000 00000000 - 0x00007FFF FFFFFFFF0xFFFF8000 00000000 - 0xFFFFFFFF FFFFFFFF
64位(57bit)64P0x00000000 00000000 - 0x00FFFFFF FFFFFFFF0xFF000000 00000000 - 0xFFFFFFFF FFFFFFFF

48bit模式的地址空间布局(4级页表)

Start addrOffsetEnd addrSizeVM area description描述
0000000000000000000007fffffffffff128 TBuser-space virtual memory, different per mm用户地址空间,每个进程mm指向的都不同
0000800000000000+128 TBffff7fffffffffff~16M TB… huge, almost 64 bits wide hole of non-canonical virtual memory addresses up to the -128 TB starting offset of kernel mappings.巨大空洞
Kernel-space virtual memory, shared between all processes:以下为内核地址空间:
ffff800000000000-128 TBffff87ffffffffff8 TB… guard hole, also reserved for hypervisor
ffff880000000000-120 TBffff887fffffffff0.5 TBLDT remap for PTILDT(Local Descriptor Table):局部描述符表KPTI(Kernel page-table isolation):内核页表隔离
ffff888000000000-119.5 TBffffc87fffffffff64 TBdirect mapping of all physical memory (page_offset_base)线性映射的区域
0000000000000000-55.5 TBffffc8ffffffffff0.5 TB… unused hole
ffffc90000000000-55 TBffffe8ffffffffff32 TBvmalloc/ioremap space (vmalloc_base)vmalloc和ioremap空间
ffffe90000000000-23 TBffffe9ffffffffff1 TB… unused hole
ffffea0000000000-22 TBffffeaffffffffff1 TBvirtual memory map (vmemmap_base)page结构存储的位置
ffffeb0000000000-21 TBffffebffffffffff1 TB… unused hole
ffffec0000000000-20 TBfffffbffffffffff16 TBKASAN shadow memoryKASAN影子内存
Identical layout to the 56-bit one from here on:从这里开始,与56-bit布局相同:
fffffc0000000000000007fffffffffff128 TBuser-space virtual memory, different per mm用户地址空间,每个进程mm指向的都不同
0000000000000000-4 TBfffffdffffffffff2 TB… unused hole
vaddr_end for KASLR
fffffe0000000000-2 TBfffffe7fffffffff0.5 TBcpu_entry_area mapping
fffffe8000000000-1.5 TBfffffeffffffffff0.5 TB… unused hole
ffffff0000000000-1 TBffffff7fffffffff0.5 TB%esp fixup stacks
ffffff8000000000-512 GBffffffeeffffffff444 GB… unused hole
ffffffef00000000-68 GBfffffffeffffffff64 GBEFI region mapping space
ffffffff00000000-4 GBffffffff7fffffff2 GB… unused hole
ffffffff80000000-2 GBffffffff9fffffff512 MBkernel text mapping, mapped to physical address 0内核代码区域
ffffffff80000000-2048 MB
ffffffffa0000000-1536 MBfffffffffeffffff1520 MBmodule mapping space模块加载区域
ffffffffff000000-16 MB
FIXADDR_START~-11 MBffffffffff5fffff~0.5 MBkernel-internal fixmap range, variable size and offset
ffffffffff600000-10 MBffffffffff600fff4 kBlegacy vsyscall ABI
fffffffffffe00000-2 MBfffffffffffffffff2 MB… unused hole

其中重点区域的说明:

direct mapping:直接映射覆盖系统中的所有内存,直至最高内存地址(这意味着在某些情况下,它还可以包括PCI内 memory)。
vmalloc space:vmalloc空间也是lazy策略的,使用page_fault机制来延后分配,使用init_top_pgt作为参考。
EFI region:我们将EFI运行时服务映射到64Gb大型虚拟内存窗口中的“ efi_pgd” PGD中(此大小是任意的,以后可以根据需要提高)。映射不是任何其他内核PGD的一部分,并且仅在EFI运行时期间可用。
KASLR:请注意,如果启用CONFIG_RANDOMIZE_MEMORY,则将随机化所有物理内存,直接映射物理内存空间(direct mapping)、vmalloc/ioremap空间和虚拟内存映射。它们的顺序被保留,但是它们在启动时加上基础偏移。在此处进行任何更改时,请务必对KASLR格外小心。除KASAN阴影区域外,KASLR地址范围不得与其他区域重叠。因此KASAN为了保证正确会禁用KASLR。

57bit模式的地址空间布局(5级页表)

在这里插入图片描述

内核页表初始化

decompress阶段

head_64.S和head64.c

early_top_pgt

内核代码在跳转到start_kernel()以前,运行在head_64.S和head64.c中,此时使用一个临时页表early_top_pgt来做虚拟地址到物理地址的转换:

SYM_DATA_START_PTI_ALIGNED(early_top_pgt).fill	512,8,0.fill	PTI_USER_PGD_FILL,8,0
SYM_DATA_END(early_top_pgt)

SYM_DATA_START_PTI_ALIGNED(early_top_pgt):声明符号early_top_pgt,并要求按PTI对齐规则(通常为4K对齐)。
.fill 512,8,0:填充512个8字节的条目,初始值为0。这对应x86-64四级分页中的顶级页表(PML4),每个条目占用8字节,共512项。
.fill PTI_USER_PGD_FILL,8,0:进一步填充用户空间相关的页表条目。PTI_USER_PGD_FILL是一个宏,表示需要隔离的用户空间条目数量。例如,内核可能保留部分条目供用户态隔离使用,防止通过侧信道攻击访问内核数据。

代码部分功能描述
SYM_DATA_START_PTI_ALIGNED(…)定义对齐的页表起始位置,确保分页结构符合硬件要求。
.fill 512,8,0初始化PML4表,覆盖所有可能的条目,为后续映射预留空间。
.fill PTI_USER_PGD_FILL,8,0按PTI要求隔离用户空间条目,缓解Meltdown等侧信道攻击。

init_top_pgt

#if defined(CONFIG_XEN_PV) || defined(CONFIG_PVH)
SYM_DATA_START_PTI_ALIGNED(init_top_pgt).quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC  ; 直接映射条目.org init_top_pgt + L4_PAGE_OFFSET*8, 0                            ; 清零用户空间条目.quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC  ; 可能的兼容性设置.org init_top_pgt + L4_START_KERNEL*8, 0                           ; 定位到内核空间条目.quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE_NOENC   ; 内核虚拟映射.fill PTI_USER_PGD_FILL,8,0                                        ; 填充剩余用户条目为0
SYM_DATA_END(init_top_pgt)
/** 定义页上级目录(Page Upper Directory, PUD),即level3_ident_pgt* 该页表用于内核启动初期的直接映射(物理地址=虚拟地址)* SYM_DATA_START_PAGE_ALIGNED 确保符号按页(4096字节)对齐*/
SYM_DATA_START_PAGE_ALIGNED(level3_ident_pgt)/** 第一个PUD条目指向level2_ident_pgt(PMD)* 计算方式:level2_ident_pgt的物理地址 + 页表属性* * 关键分解:* 1. level2_ident_pgt - __START_KERNEL_map:*    __START_KERNEL_map 是内核虚拟地址空间起始地址(如0xffffffff80000000)*    通过减去该值,将虚拟地址转换为物理地址(直接映射阶段)* 2. _KERNPG_TABLE_NOENC:*    页表项属性:存在位 | 可读写 | 内核权限 | 无内存加密*    值通常为 0x003(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED)*/.quad   level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC/** 填充剩余的511个PUD条目为0* 原因:* 1. 每个页表层级(PUD/PMD等)有512个条目* 2. 此处仅需映射第一个1GB物理内存(由后续level2_ident_pgt配置)* 3. 其他条目保持未映射状态(安全且节省空间)*/.fill   511, 8, 0  /* 511 entries x 8 bytes = 4088 bytes */
SYM_DATA_END(level3_ident_pgt)  /* 结束符号定义 *//** 定义页中间目录(Page Middle Directory, PMD),即level2_ident_pgt* 该页表负责映射前1GB物理内存,使用大页(2MB或1GB)提升效率*/
SYM_DATA_START_PAGE_ALIGNED(level2_ident_pgt)/** PMDS宏:生成连续的PMD条目以映射连续物理内存* 参数解析:* @0: 起始物理地址(0表示从物理地址0开始映射)* @__PAGE_KERNEL_IDENT_LARGE_EXEC: 页表属性(大页+可执行)* @PTRS_PER_PMD: 条目数量(通常为512,覆盖完整PMD)** 属性详解:* __PAGE_KERNEL_IDENT_LARGE_EXEC 包含:* - _PAGE_PRESENT: 页存在* - _PAGE_RW: 可读写* - _PAGE_ACCESSED: 已访问* - _PAGE_DIRTY: 脏页* - _PAGE_LARGE: 使用大页(2MB或1GB)* - _PAGE_GLOBAL: 全局页(TLB不刷新)* - _PAGE_EXEC: 允许代码执行(未设置NX位)** 注释说明:* 1. 显式设置_PAGE_GLOBAL,即使CPU可能忽略该标志(兼容性考虑)* 2. 不设置NX(No Execute)位,允许从此区域执行代码* 3. 映射前1GB物理内存(512 entries x 2MB = 1GB)*/PMDS(0, __PAGE_KERNEL_IDENT_LARGE_EXEC, PTRS_PER_PMD)
SYM_DATA_END(level2_ident_pgt)  /* 结束符号定义 */
SYM_DATA_START_PAGE_ALIGNED(level2_fixmap_pgt).fill	(512 - 4 - FIXMAP_PMD_NUM),8,0pgtno = 0.rept (FIXMAP_PMD_NUM).quad level1_fixmap_pgt + (pgtno << PAGE_SHIFT) - __START_KERNEL_map \+ _PAGE_TABLE_NOENC;pgtno = pgtno + 1.endr/* 6 MB reserved space + a 2MB hole */.fill	4,8,0
SYM_DATA_END(level2_fixmap_pgt)SYM_DATA_START_PAGE_ALIGNED(level1_fixmap_pgt).rept (FIXMAP_PMD_NUM).fill	512,8,0.endr
SYM_DATA_END(level1_fixmap_pgt)
/** level2_fixmap_pgt:页中间目录(PMD),用于管理固定映射(Fixmap)区域* Fixmap 是内核中用于特殊用途的虚拟地址空间(如临时映射设备内存、APIC 等)* SYM_DATA_START_PAGE_ALIGNED 确保该符号按页(4096 字节)对齐*/
SYM_DATA_START_PAGE_ALIGNED(level2_fixmap_pgt)/** 步骤 1:填充无效条目(保留空间)* 总条目数 512 - 保留末尾 4 条目 - FIXMAP_PMD_NUM 有效条目* 目的:* 1. 保留 FIXMAP_PMD_NUM 个 PMD 条目用于 Fixmap* 2. 末尾保留 4 个条目(可能与特定硬件或内存布局对齐要求相关)* 3. 中间区域填充 0 表示未映射*/.fill   (512 - 4 - FIXMAP_PMD_NUM), 8, 0  /* 填充无效条目 *//* * 步骤 2:生成 FIXMAP_PMD_NUM 个有效 PMD 条目* 这些条目指向 level1_fixmap_pgt(PTE 表),形成层级结构*/pgtno = 0  /* 初始化页表编号计数器 */.rept (FIXMAP_PMD_NUM)  /* 重复生成 FIXMAP_PMD_NUM 次 *//** 构造 PMD 条目:* 物理地址 = level1_fixmap_pgt + pgtno * PAGE_SIZE - __START_KERNEL_map* 属性 = _PAGE_TABLE_NOENC(存在 + 可读可写)* * 关键分解:* 1. level1_fixmap_pgt 是虚拟地址,需转换为物理地址:*    - __START_KERNEL_map 是内核虚拟地址空间起始(如 0xffffffff80000000)*    - 减去 __START_KERNEL_map 得到物理地址* 2. (pgtno << PAGE_SHIFT):每个 PTE 表占一页(4096 字节),按页偏移* 3. _PAGE_TABLE_NOENC:属性标志(0x003,存在 + 可读可写)*/.quad level1_fixmap_pgt + (pgtno << PAGE_SHIFT) - __START_KERNEL_map \+ _PAGE_TABLE_NOENCpgtno = pgtno + 1  /* 递增页表编号 */.endr/* 步骤 3:保留末尾 4 个 PMD 条目(填充 0) *//* 注释提到的 "6 MB reserved space + a 2MB hole" 可能指特定平台的保留区域 */.fill   4, 8, 0  /* 填充 4 个无效条目 */
SYM_DATA_END(level2_fixmap_pgt)  /* 结束符号定义 *//** level1_fixmap_pgt:页表条目(PTE)数组,用于实际物理页映射* 每个 PMD 条目指向一个 PTE 表,每个 PTE 表管理 512 个 4KB 页(共 2MB)*/
SYM_DATA_START_PAGE_ALIGNED(level1_fixmap_pgt)/** 初始化 FIXMAP_PMD_NUM 个 PTE 表,每个表 512 个条目,初始为 0* 目的:* 1. 预留空间供内核运行时动态映射(如 fixmap 机制)* 2. 初始时未映射,后续按需设置具体物理地址*/.rept (FIXMAP_PMD_NUM)  /* 重复生成 FIXMAP_PMD_NUM 个 PTE 表 */.fill   512, 8, 0  /* 每个 PTE 表 512 条目 × 8 字节 = 4096 字节(一页) */.endr
SYM_DATA_END(level1_fixmap_pgt)  /* 结束符号定义 */

下面是关于汇编指令的介绍:
ORG是Origin的缩写:起始地址,源。在汇编语言源程序的开始通常都用一条ORG伪指令来实现规
操作步骤:
计算目标地址:
init_top_pgt + L4_PAGE_OFFSET*8 定位到用户空间地址对应的PML4条目位置。
调整位置计数器:
将汇编器的当前位置计数器($)设置到该目标地址。
填充未初始化区域:
若当前位置与目标地址之间存在间隙(如之前的条目未填满),用0填充这些间隙。
实际效果:
确保用户空间地址对应的PML4条目被显式初始化为0,表示 用户空间无法直接访问内核内存。这是 页表隔离(PTI) 的关键步骤,防止用户程序通过侧信道攻击(如Meltdown)窃取内核数据。

形式:.fill repeat , size , value
其中,repeat、size 和value都是常量表达式。Fill的含义是反复拷贝size个字节。Repeat可以大于等于0。size也可以大于等于0,但不能超过8,如果超过8,也只取8。把repeat个字节以8个为一组,每组的最高4个字节内容为0,最低4字节内容置为value。

程序的起始地址。如果不用ORG规定则汇编得到的目标程序将从0000H开始
.quad 定义八个字节的数据
quad bignums
.quad表示零个或多个bignums(用逗号分隔),对于每个bignum,其缺省值是8字节整数。如果bignum超过8字节,则打印一个警告信息;并只取bignum最低8字节。
在这里插入图片描述

其中主要建立了4块区域的映射:

regionsizedesctipt
identity mapping1G虚拟地址和物理地址相等
direct mapping1G线性映射空间,起始虚拟地址
kernel image512M内核映像映射空间
fixmap固定映射空间

但是在跳转到start_kernel()之前,内核重新构造了init_top_pgt:

SYM_DATA(initial_code,	.quad x86_64_start_kernel)

该行代码用于 定义内核的初始执行地址,将 x86_64_start_kernel 函数的入口地址存储到全局符号 initial_code 中,供内核启动流程使用。

1. 符号定义宏 SYM_DATA

作用:
在 Linux 内核汇编中,SYM_DATA 是一个宏,用于定义全局数据符号(Global Data Symbol)。
它会确保符号的正确对齐(如按 8 字节对齐)并附加必要的元信息(如 ELF 节类型),以便链接器和内核正确识别。

2. initial_code 符号

作用:
存储内核的初始代码入口地址,供启动代码(如汇编启动桩)跳转到内核主函数。

生命周期:

编译阶段:由汇编器生成,存储在目标文件(.o)的数据段中。

链接阶段:链接器将其地址固定在内核镜像的特定位置(如 .data 节)。

运行时:内核启动代码通过读取 initial_code 的值,跳转到 x86_64_start_kernel。

3. .quad x86_64_start_kernel

.quad 指令
在当前位置写入一个 64 位(8 字节)的值。此处值为符号 x86_64_start_kernel 的地址。

x86_64_start_kernel
功能:x86_64 架构的主内核入口函数,负责初始化关键子系统(如内存管理、中断控制)。

定义位置:通常位于 arch/x86/kernel/head64.c 或类似文件中。

执行时机:在完成底层汇编环境初始化(如分页、栈设置)后,由此函数接管控制权。

x86_64_start_kernel

asmlinkage __visible void __init __noreturn x86_64_start_kernel(char * real_mode_data)
{/** Build-time sanity checks on the kernel image and module* area mappings. (these are purely build-time and produce no code)*/BUILD_BUG_ON(MODULES_VADDR < __START_KERNEL_map);BUILD_BUG_ON(MODULES_VADDR - __START_KERNEL_map < KERNEL_IMAGE_SIZE);BUILD_BUG_ON(MODULES_LEN + KERNEL_IMAGE_SIZE > 2*PUD_SIZE);BUILD_BUG_ON((__START_KERNEL_map & ~PMD_MASK) != 0);BUILD_BUG_ON((MODULES_VADDR & ~PMD_MASK) != 0);BUILD_BUG_ON(!(MODULES_VADDR > __START_KERNEL));MAYBE_BUILD_BUG_ON(!(((MODULES_END - 1) & PGDIR_MASK) ==(__START_KERNEL & PGDIR_MASK)));BUILD_BUG_ON(__fix_to_virt(__end_of_fixed_addresses) <= MODULES_END);cr4_init_shadow();/* Kill off the identity-map trampoline */reset_early_page_tables();clear_bss();/** This needs to happen *before* kasan_early_init() because latter maps stuff* into that page.*/clear_page(init_top_pgt);/** SME support may update early_pmd_flags to include the memory* encryption mask, so it needs to be called before anything* that may generate a page fault.*/sme_early_init();kasan_early_init();/** Flush global TLB entries which could be left over from the trampoline page* table.** This needs to happen *after* kasan_early_init() as KASAN-enabled .configs* instrument native_write_cr4() so KASAN must be initialized for that* instrumentation to work.*/__native_tlb_flush_global(this_cpu_read(cpu_tlbstate.cr4));idt_setup_early_handler();/* Needed before cc_platform_has() can be used for TDX */tdx_early_init();copy_bootdata(__va(real_mode_data));/** Load microcode early on BSP.*/load_ucode_bsp();/* set init_top_pgt kernel high mapping*/init_top_pgt[511] = early_top_pgt[511];x86_64_start_reservations(real_mode_data);
}

以下是 x86_64_start_kernel 函数的逐行详细分析,结合 Linux 内核启动流程和 x86_64 架构特性:


1. 函数定义

asmlinkage __visible void __init __noreturn x86_64_start_kernel(char * real_mode_data)
  • asmlinkage: 声明函数参数通过栈传递(x86_64 默认用寄存器,此处兼容旧约定)
  • __visible: 强制符号在目标文件中可见(防止链接器优化)
  • __init: 标记函数仅在内核初始化阶段存在(内存会被回收)
  • __noreturn: 函数不会返回(最终跳转到 start_kernel()
  • real_mode_data: 指向实模式阶段数据的指针(如 boot_params)

2. 编译时内存布局检查

BUILD_BUG_ON(MODULES_VADDR < __START_KERNEL_map);
BUILD_BUG_ON(MODULES_VADDR - __START_KERNEL_map < KERNEL_IMAGE_SIZE);
  • 目的:确保内核模块区域(MODULES_VADDR)位于内核镜像(__START_KERNEL_map)之后,且留有足够空间。
  • 失败后果:编译错误,防止模块与内核代码重叠。
BUILD_BUG_ON(MODULES_LEN + KERNEL_IMAGE_SIZE > 2*PUD_SIZE);
  • 验证内核镜像和模块总大小不超过 2个PUD(Page Upper Directory)的容量(通常 2*1GB = 2GB)。
BUILD_BUG_ON((__START_KERNEL_map & ~PMD_MASK) != 0);
BUILD_BUG_ON((MODULES_VADDR & ~PMD_MASK) != 0);
  • 检查内核和模块的起始地址是否按 PMD边界对齐(2MB 对齐),确保大页映射有效性。
BUILD_BUG_ON(!(MODULES_VADDR > __START_KERNEL));
  • 强制模块区域在内核代码之后,避免地址冲突。
MAYBE_BUILD_BUG_ON(!(((MODULES_END - 1) & PGDIR_MASK) == (__START_KERNEL & PGDIR_MASK)));
  • 确保模块结束地址与内核起始地址在 同一PGD条目(Page Global Directory,512GB范围)内,简化页表管理。
BUILD_BUG_ON(__fix_to_virt(__end_of_fixed_addresses) <= MODULES_END);
  • 检查固定映射区域(Fixmap)是否在模块区域之后,避免地址空间覆盖。

3. 关键初始化操作

(1) 影子CR4初始化
cr4_init_shadow();
  • 作用:为每个CPU初始化影子CR4副本,用于安全地管理CR4寄存器更新(如避免TSX切换漏洞)。
(2) 清除临时页表
reset_early_page_tables();
  • 操作:清空 early_top_pgt 中的早期直接映射(Identity Mapping),释放物理页。
  • 目的:移除启动阶段临时页表,防止非法访问。
(3) 清零BSS段
clear_bss();
  • BSS段:存储未初始化的全局变量(如 static int x;)。
  • 操作:将BSS段内存清零,确保变量初始状态正确。
(4) 清空顶级页表
clear_page(init_top_pgt);
  • init_top_pgt:内核正式使用的顶级页表(PML4)。
  • 目的:清除旧数据,避免残留映射干扰后续初始化。
(5) 内存加密初始化
sme_early_init();
  • SME(Secure Memory Encryption):AMD 内存加密技术。
  • 操作:检测并启用内存加密,更新页表属性(如 early_pmd_flags)。
(6) KASAN初始化
kasan_early_init();
  • KASAN(Kernel Address SANitizer):动态内存错误检测工具。
  • 操作:初始化影子内存(Shadow Memory),拦截非法内存访问。
(7) 刷新全局TLB
__native_tlb_flush_global(this_cpu_read(cpu_tlbstate.cr4));
  • 作用:清除早期页表遗留的TLB缓存条目,确保新页表生效。
  • 时机:必须在KASAN初始化后执行(KASAN会插桩内存操作函数)。

4. 中断与安全初始化

(1) 早期中断处理
idt_setup_early_handler();
  • IDT(Interrupt Descriptor Table):设置早期中断处理函数(如#PF、#DB),用于启动阶段异常处理。
(2) TDX初始化
tdx_early_init();
  • TDX(Trust Domain Extensions):Intel 的可信执行环境扩展。
  • 操作:检测并初始化TDX相关配置,为安全容器做准备。

5. 数据与微码处理

(1) 复制实模式数据
copy_bootdata(__va(real_mode_data));
  • __va: 将实模式数据的物理地址转换为内核虚拟地址。
  • 操作:复制 bootloader 传递的数据(如命令行参数、内存映射)到内核空间。
(2) 加载微码更新
load_ucode_bsp();
  • 微码(Microcode):CPU 固件补丁,修复硬件缺陷。
  • 操作:在BSP(Bootstrap Processor)上加载微码更新。

6. 页表切换与后续流程

init_top_pgt[511] = early_top_pgt[511];
  • 操作:将 early_top_pgt 的内核高映射条目复制到 init_top_pgt
  • 目的:保留内核代码和数据的映射,确保后续代码执行连续。
x86_64_start_reservations(real_mode_data);
  • 后续流程:进入内核保留区域初始化,最终调用 start_kernel()(通用内核入口)。

内存布局演进

阶段页表映射范围作用
早期启动early_top_pgt直接映射(1:1)开启分页,跳转到内核代码
reset_early_page_tables()early_top_pgt 清空无直接映射防止非法访问
切换后init_top_pgt高端内核映射(-2GB)正式内存管理,隔离用户空间

安全设计分析

  1. 编译时检查:通过 BUILD_BUG_ON 确保内存布局符合预期,避免运行时崩溃。
  2. 页表隔离:清除临时映射,防止利用物理地址攻击内核。
  3. 加密与消毒:SME和KASAN分别在硬件和软件层增强内存安全。
  4. 微码更新:及时修复CPU漏洞,提升系统安全性。

总结

x86_64_start_kernel 是 x86_64 架构内核启动的核心枢纽,负责:

  • 验证内存布局:确保编译时地址分配合理性。
  • 初始化关键子系统:内存加密、错误检测、中断管理。
  • 环境切换:从临时页表切换到正式内存管理。
  • 数据准备:传递启动参数,加载CPU微码。

该函数体现了 Linux 内核安全至上渐进初始化的设计哲学,为后续 start_kernel() 的执行奠定坚实基础。

x86_64_start_reservations

void __init __noreturn x86_64_start_reservations(char *real_mode_data)
{/* version is always not zero if it is copied */if (!boot_params.hdr.version)copy_bootdata(__va(real_mode_data));x86_early_init_platform_quirks();switch (boot_params.hdr.hardware_subarch) {case X86_SUBARCH_INTEL_MID:x86_intel_mid_early_setup();break;default:break;}start_kernel();
}

以下是对 x86_64_start_reservations 函数的逐行分析解释,结合 Linux 内核启动流程和 x86_64 架构特性:


函数定义

void __init __noreturn x86_64_start_reservations(char *real_mode_data)
  • __init: 标记函数仅在初始化阶段存在,完成后内存会被释放。
  • __noreturn: 函数不会返回(最终调用 start_kernel() 进入无限循环)。
  • real_mode_data: 指向实模式阶段传递的数据(如 boot_params)。

1. 复制启动数据(条件检查)

if (!boot_params.hdr.version)copy_bootdata(__va(real_mode_data));
  • 作用:确保 boot_params(启动参数结构体)已被正确初始化。
  • 逻辑分解
    • boot_params.hdr.version: 引导协议版本号,若为0表示数据未复制。
    • __va(real_mode_data): 将实模式数据的物理地址转换为内核虚拟地址。
    • copy_bootdata(): 将 real_mode_data 中的数据复制到 boot_params
  • 设计意图:避免重复复制(例如在多次调用时),确保数据完整性。

2. 平台早期特性初始化

x86_early_init_platform_quirks();
  • 作用:处理 x86 平台特定的早期硬件兼容性问题或配置。
  • 典型操作
    • 修复特定芯片组的 ACPI 或 IRQ 路由问题。
    • 启用/禁用某些 CPU 特性(如 TSX)。
    • 配置早期控制寄存器(如 CR0/CR4)。

3. 硬件子架构初始化

switch (boot_params.hdr.hardware_subarch) {
case X86_SUBARCH_INTEL_MID:x86_intel_mid_early_setup();break;
default:break;
}
  • hardware_subarch: 标识硬件子架构类型(如 Intel MID、CE4100 等)。
  • X86_SUBARCH_INTEL_MID: Intel 移动设备平台(如 Medfield、Cloverview)。
  • x86_intel_mid_early_setup(): 执行 Intel MID 特有的初始化:
    • 配置 IOAPIC 和定时器。
    • 初始化特定外设(如 SPI、GPIO)。
    • 设置内存映射区域。
  • 默认分支:其他子架构无需额外操作。

4. 进入内核主初始化

start_kernel();
  • 作用:调用通用内核入口函数,完成全局初始化。
  • 关键操作
    • 初始化调度器、内存管理、中断系统。
    • 挂载根文件系统。
    • 启动用户空间(init 进程)。
  • 永不返回:内核进入无限循环,处理中断和进程调度。

代码执行流程

x86_64_start_kernel()→ x86_64_start_reservations()├─ 复制 boot_params(若未初始化)├─ 处理平台特性├─ 配置子架构硬件└─ start_kernel()→ rest_init()→ kernel_init()→ 用户空间启动

内存与数据流

  1. 实模式数据
    Bootloader(如 GRUB)将硬件信息(内存布局、命令行参数)存储在 real_mode_data(物理地址),通过 copy_bootdata 转换为内核虚拟地址并填充到 boot_params

  2. 硬件子架构处理
    Intel MID 设备需要特殊映射(如保留区域),x86_intel_mid_early_setup() 确保内核适配其硬件限制。

  3. 平台特性修正
    x86_early_init_platform_quirks() 解决不同主板或芯片组的兼容性问题(如 Dell 系统特定行为)。


安全性与鲁棒性设计

  • 条件检查:通过 boot_params.hdr.version 避免重复复制导致数据覆盖。
  • 子架构隔离:仅针对特定硬件(如 Intel MID)执行代码,减少通用代码耦合。
  • 虚拟地址转换:使用 __va 确保在内核地址空间访问实模式数据。

典型场景示例

  • Intel MID 设备启动

    1. Bootloader 传递 hardware_subarch = X86_SUBARCH_INTEL_MID
    2. x86_intel_mid_early_setup() 初始化 SPI 控制器和触摸屏驱动。
    3. 内核适配 MID 内存布局(如保留视频缓冲区)。
  • 标准 x86_64 服务器启动

    1. hardware_subarch 保持默认值(非 MID)。
    2. 跳过子架构特定代码,直接进入 start_kernel()

总结

x86_64_start_reservations 是 x86_64 内核启动的关键过渡函数,职责包括:

  1. 数据完整性保障:确保启动参数正确传递。
  2. 硬件适配:处理平台和子架构的特定需求。
  3. 流程交接:最终将控制权移交通用内核入口 start_kernel()

该函数体现了 Linux 内核模块化硬件兼容性设计,为不同 x86 设备提供统一且灵活的启动路径。

物理内存(e820)

在伙伴管理系统正式工作之前,需要一个临时的内存分配机制来满足这个阶段的内存分配需求。最早的临时分配机制是bootmem,现在普遍使用的是memblock。

start_kernel----->setup_arch---->e820__memory_setup
/** Calls e820__memory_setup_default() in essence to pick up the firmware/bootloader* E820 map - with an optional platform quirk available for virtual platforms* to override this method of boot environment processing:*/
void __init e820__memory_setup(void)
{char *who;/* This is a firmware interface ABI - make sure we don't break it: */BUILD_BUG_ON(sizeof(struct boot_e820_entry) != 20);who = x86_init.resources.memory_setup();memcpy(e820_table_kexec, e820_table, sizeof(*e820_table_kexec));memcpy(e820_table_firmware, e820_table, sizeof(*e820_table_firmware));pr_info("BIOS-provided physical RAM map:\n");e820__print_table(who);
}

以下是对 e820__memblock_setup 函数的逐行分析,结合 Linux 内核的内存管理机制和 x86 架构特性:


函数功能

该函数的作用是 将 BIOS 或 UEFI 提供的 E820 内存布局信息,转换为内核早期内存管理器 memblock 的可用/保留内存区域,完成物理内存的初始映射。


代码逐行解析

1. 允许 memblock 动态扩容
memblock_allow_resize();
  • 背景memblock 初始化时默认分配固定大小的内存区域数组(INIT_MEMBLOCK_REGIONS = 128)。
  • 作用:启用动态调整 memblock.memorymemblock.reserved 数组的大小。
  • 必要性:当 E820 条目超过 128 时(如某些 EFI 系统),避免溢出导致数据丢失。

2. 遍历 E820 内存表
for (i = 0; i < e820_table->nr_entries; i++) {struct e820_entry *entry = &e820_table->entries[i];end = entry->addr + entry->size;if (end != (resource_size_t)end)continue;
  • e820_table:存储从 BIOS/UEFI 获取的内存布局信息,每个条目描述一个内存区域。
  • end 计算与校验:检查 addr + size 是否溢出 resource_size_t(通常是 u64)。若溢出则跳过该条目(通常因硬件错误或固件缺陷导致)。

3. 处理 SOFT_RESERVED 类型区域
    if (entry->type == E820_TYPE_SOFT_RESERVED)memblock_reserve(entry->addr, entry->size);
  • E820_TYPE_SOFT_RESERVED:由内核或引导加载器(如 GRUB)标记的软保留区域。
  • 操作:调用 memblock_reserve() 将其标记为保留,防止被意外分配。
  • 典型场景:KASLR 的随机化区域、内核命令行参数占用的内存。

4. 过滤并添加可用内存
    if (entry->type != E820_TYPE_RAM && entry->type != E820_TYPE_RESERVED_KERN)continue;memblock_add(entry->addr, entry->size);
  • 条件:仅处理以下类型的内存区域:
    • E820_TYPE_RAM:可用物理内存。
    • E820_TYPE_RESERVED_KERN:内核保留区域(如内核代码、数据段)。
  • 操作:调用 memblock_add() 将区域添加到 memblock.memory,标记为可用。

5. 内存对齐修剪
memblock_trim_memory(PAGE_SIZE);
  • 作用:将所有内存区域的起始和结束地址按 PAGE_SIZE(通常 4KB)对齐。
  • 必要性
    • 确保后续页表映射不会出现部分页。
    • 避免内存分配器处理未对齐块带来的复杂性。

6. 调试输出
memblock_dump_all();
  • 作用:打印 memblock 的当前状态(memoryreserved 区域)。
  • 输出示例
    MEMBLOCK configuration:memory size = 0x1fff0000 reserved size = 0x1eef000memory.cnt  = 0x3memory[0x0]    [0x0000000000001000-0x000000000009ffff], 0x9f000 bytesmemory[0x1]    [0x0000000000100000-0x000000001ffeffff], 0x1fe00000 bytesreserved.cnt  = 0x3reserved[0x0]  [0x0000000000000000-0x0000000000000fff], 0x1000 bytes
    

关键数据结构

E820 条目类型
类型描述
E820_TYPE_RAM1可用物理内存
E820_TYPE_RESERVED2保留区域(硬件/固件使用)
E820_TYPE_ACPI3ACPI 表格区域
E820_TYPE_NVS4ACPI NVS 内存
E820_TYPE_UNUSABLE5不可用内存
E820_TYPE_PMEM7持久性内存
E820_TYPE_RESERVED_KERN128内核保留区域
E820_TYPE_SOFT_RESERVED129内核软保留区域

内存管理流程

  1. BIOS/UEFI 阶段:固件检测内存布局,生成 E820 表。
  2. 内核启动早期e820__memblock_setup 将 E820 数据转换为 memblock 区域。
  3. memblock 阶段:内核通过 memblock 管理内存分配/保留。
  4. 伙伴系统初始化memblock 数据最终迁移到伙伴系统,完成内存管理切换。

设计要点

  • 兼容性:支持不同固件(BIOS/UEFI)的 E820 表格式。
  • 安全性:严格过滤不可用区域(如 E820_TYPE_UNUSABLE),防止分配到危险内存。
  • 灵活性:动态扩容机制应对复杂内存布局。
  • 性能:早期按页对齐减少后续管理开销。

典型场景示例

  • 系统启动时
    BIOS 报告内存中存在一个 E820_TYPE_RESERVED 区域(如 APIC 寄存器空间),该区域不会被添加到 memblock.memory,确保内核不会分配此区域。

  • KASLR 启用时
    引导加载器将随机化的内核代码区域标记为 E820_TYPE_SOFT_RESERVEDmemblock_reserve() 保护该区域不被其他组件占用。


总结

e820__memblock_setup 是 x86 架构内核启动的关键步骤,其核心任务是将原始内存信息转换为内核可管理的结构,为后续内存初始化奠定基础。通过精确处理不同类型的内存区域,确保内核稳定性和安全性。

在setup_arch()后续过程中,可以使用memblock来分配和释放内存

memblock已经有内存可以分配了,可以通过memblock_alloc()来分配物理内存:

static __always_inline void *memblock_alloc(phys_addr_t size, phys_addr_t align)
{return memblock_alloc_try_nid(size, align, MEMBLOCK_LOW_LIMIT,MEMBLOCK_ALLOC_ACCESSIBLE, NUMA_NO_NODE);
}

在buddy系统建立好后,释放memblock中所有的内存到buddy中,有buddy来承担后续的内存分配工作:

start_kernel()mm_init()mem_init():

(更详细可以参考参考链接:https://zhuanlan.zhihu.com/p/613004422)

相关文章:

Linux内核,内存分布

x86_64的物理地址范围为64bit&#xff0c;但是因为地址空间太大目前不可能完全用完&#xff0c;当前支持57bit和48bit两种虚拟地址模式。 地址模式单个空间用户地址空间内核地址空间32位2G0x00000000 - 0x7FFFFFFF0x80000000 - 0xFFFFFFFF64位(48bit)128T0x00000000 00000000 …...

AI鸟类识别技术革新生态监测:快瞳科技如何用“智慧之眼”守护自然?

在生态环境保护日益受关注的今天&#xff0c;“鸟类识别”已从专业科研工具演变为推动生态治理数字化的核心技术。无论是湿地保护区的珍稀候鸟监测&#xff0c;还是城市机场的鸟击风险预警&#xff0c;AI技术的精准赋能正在改写人类与自然的互动方式。作为行业领先的智能解决方…...

c++之set

一、set特性及用途&#xff1f; 唯一性&#xff1a;set 中的元素是唯一的&#xff0c;不会存在重复的元素。自动排序&#xff1a;set 中的元素会自动按照默认的升序规则进行排序。底层实现&#xff1a;set 通常基于红黑树实现&#xff0c;具有自平衡功能&#xff0c;因此插入、…...

【AI大模型】DeepSeek + 通义万相高效制作AI视频实战详解

目录 一、前言 二、AI视频概述 2.1 什么是AI视频 2.2 AI视频核心特点 2.3 AI视频应用场景 三、通义万相介绍 3.1 通义万相概述 3.1.1 什么是通义万相 3.2 通义万相核心特点 3.3 通义万相技术特点 3.4 通义万相应用场景 四、DeepSeek 通义万相制作AI视频流程 4.1 D…...

【操作系统】自旋锁和互斥锁

自旋锁和互斥锁是用于多线程同步的两种常见锁机制&#xff0c;主要区别在于等待锁的方式和适用场景。以下是它们的对比分析&#xff1a; 1. 等待机制 自旋锁&#xff08;Spinlock&#xff09;互斥锁&#xff08;Mutex&#xff09;线程通过 忙等待&#xff08;Busy-Wait&#x…...

人工智能在医疗影像诊断中的应用与实践

引言 随着人工智能技术的飞速发展&#xff0c;其在医疗领域的应用逐渐成为研究和实践的热点。特别是在医疗影像诊断方面&#xff0c;人工智能技术凭借其强大的数据处理能力和模式识别能力&#xff0c;为提高诊断效率和准确性带来了新的希望。本文将探讨人工智能在医疗影像诊断中…...

Java中synchronized 和 Lock

1. synchronized 关键字 工作原理 对象锁&#xff1a;在Java中&#xff0c;每个对象都有一个与之关联的监视器锁&#xff08;monitor lock&#xff09;。当一个线程尝试进入由 synchronized 保护的代码块或方法时&#xff0c;它必须首先获取该对象的监视器锁。如果锁已经被其…...

【C语言系列】数据在内存中存储

数据在内存中存储 一、整数在内存中的存储二、大小端字节序和字节序判断2.1什么是大小端&#xff1f;2.2练习2.2.1练习12.2.2练习22.2.3练习32.2.4练习42.2.5练习52.2.6练习6 三、浮点数在内存中的存储3.1练习3.2浮点数的存储3.2.1 浮点数存的过程3.2.2 浮点数取的过程 3.3题目…...

qt 对QObject::tr()函数进行重定向

在 Qt 中&#xff0c;QObject::tr() 函数用于国际化&#xff08;i18n&#xff09;&#xff0c;它用于标记需要翻译的字符串。通常情况下&#xff0c;tr() 函数会从翻译文件&#xff08;如 .qm 文件&#xff09;中查找对应的翻译字符串。如果你希望重定向 tr() 函数的行为&#…...

C#基础学习(三)值类型和引用类型:编程世界的“现金“ vs “银行卡“,以及string这个“渣男“的叛变行为

开场白 各位程序猿/媛们&#xff0c;今天我们来聊一聊编程世界里的"金钱观"。 你以为只有人类会纠结现金和存款的区别&#xff1f;不不不&#xff0c;C#中的值类型和引用类型每天都在上演这场大戏&#xff01; 而我们的string同学&#xff0c;表面是…...

自动驾驶背后的数学:多模态传感器融合的简单建模

上一篇博客自动驾驶背后的数学:特征提取中的线性变换与非线性激活 以单个传感器为例,讲解了特征提取中的线性变换与非线性激活。 这一篇将以多模态传感器融合为例,讲解稍复杂的线性变换和非线性激活应用场景。 (一)权重矩阵的张量积分解 y = W x + b = [ w 11 ⋯ w 1 n ⋮…...

如何设置sudo权限

打开终端&#xff1a;按 Ctrl Alt T 打开终端。 编辑 sudoers 文件&#xff1a; 使用 visudo 命令编辑 /etc/sudoers 文件&#xff08;visudo 会检查语法&#xff0c;避免错误&#xff09;&#xff1a; sudo visudo 添加用户权限&#xff1a; 在文件中找到以下行&#xff1…...

Codeforces Round 1012 (Div. 2) 3.23

文章目录 2025.3.23 Div2B. Pushing Balls&#xff08;暴力&#xff09;代码 C. Dining Hall题意思路代码 2025.3.23 Div2 Dashboard - Codeforces Round 1012 (Div. 2) - Codeforces B. Pushing Balls&#xff08;暴力&#xff09; 题意很好懂&#xff0c;每一行每一列从左…...

langfuse追踪Trace

介绍 &#x1f9e0; Langfuse 是什么&#xff1f; Langfuse 是一个专门为 LLM 应用&#xff08;如 OpenAI / LangChain / 自定义 Agent&#xff09; 设计的 观测与追踪平台&#xff08;Observability Platform&#xff09;。 简单说&#xff0c;它就像是你为 AI 应用插上的 “…...

Java-模块二-2

整数类型 byte&#xff1a;在 Java 中占用8位&#xff08;1字节&#xff09;&#xff0c;因此它的取值范围是从 -128 到 127。这是最小的整数类型&#xff0c;适合用于节省空间的情况。 short&#xff1a;这种类型的大小是16位&#xff08;2字节&#xff09;&#xff0c;允许的…...

使用VS2022编译CEF

前提 选择编译的版本 CEF自动编译&#xff0c;在这里可以看到最新的稳定版和Beta版。 从这里得出&#xff0c;最新的稳定版是134.0.6998.118&#xff0c;对应的cef branch是6998。通过这个信息可以在Build requirements查到相关的软件配置信息。 这里主要看Windows下的编译要…...

大模型RLHF训练-PPO算法详解:Proximal Policy Optimization Algorithms

一、TL&#xff1b;DR 提出了一种新的策略梯度方法家族&#xff0c;用于强化学习&#xff0c;这些方法交替进行与环境交互采样数据提出了一个新的目标函数&#xff0c;使得能够进行多个小批量更新的多轮训练这些新方法为近端策略优化&#xff08;Proximal Policy Optimization…...

【STM32实物】基于STM32的扫地机器人/小车控制系统设计

基于STM32的扫地机器人/小车控制系统设计 演示视频: 基于STM32的扫地机器人小车控制系统设计 简介:扫地机器人系统采用分层结构设计,主要包括底层硬件控制层、中间数据处理层和上层用户交互层。底层硬件控制层负责对各个硬件模块进行控制和数据采集,中间数据处理层负责对采…...

【C++初阶】从零开始模拟实现vector(含迭代器失效详细讲解)

目录 1、基本结构 1.1成员变量 1.2无参构造函数 1.3有参构造函数 preserve()的实现 代码部分&#xff1a; push_back()的实现 代码部分&#xff1a; 代码部分&#xff1a; 1.4拷贝构造函数 代码部分&#xff1a; 1.5支持{}初始化的构造函数 代码部分&#xff1a; …...

AI比人脑更强,因为被植入思维模型【21】冯诺依曼思维模型

定义 冯诺依曼思维模型是一种基于数理逻辑和系统分析的思维方式&#xff0c;它将复杂的问题或系统分解为若干个基本的组成部分&#xff0c;通过建立数学模型和逻辑规则来描述和分析这些部分之间的关系&#xff0c;进而实现对整个系统的理解和优化。该模型强调从整体到局部、再…...

Keil5调试技巧

一、引言 Keil5作为一款广泛应用于嵌入式系统开发的集成开发环境&#xff08;IDE&#xff09;&#xff0c;在微控制器编程领域占据着重要地位。它不仅提供了强大的代码编辑和编译功能&#xff0c;还具备丰富的调试工具&#xff0c;帮助开发者快速定位和解决代码中的问题。本文…...

Web PKI现行应用、标准

中国现行 Web PKI 标准 中国在 Web PKI&#xff08;公钥基础设施&#xff09;领域制定了多项国家标准&#xff0c;以确保网络安全和数字证书管理的规范性。以下是一些现行的重要标准&#xff1a; 1. GB/T 21053-2023《信息安全技术 公钥基础设施 PKI系统安全技术要求》 该标…...

ROS多机通信(四)——Ubuntu 网卡 Mesh 模式配置指南

引言 使用Ad-hoc加路由协议和直接Mesh模式配置网卡实现的网络结构是一样的&#xff0c;主要是看应用选择&#xff0c; Ad-Hoc模式 B.A.T.M.A.N. / OLSR 优点&#xff1a;灵活性高&#xff0c;适合移动性强或需要优化的复杂网络。 缺点&#xff1a;配置复杂&#xff0c;需手动…...

【实用部署教程】olmOCR智能PDF文本提取系统:从安装到可视化界面实现

文章目录 引言系统要求1. 环境准备&#xff1a;安装Miniconda激活环境 2. 配置pip源加速下载3. 配置学术加速&#xff08;访问国外资源&#xff09;4. 安装系统依赖5. 安装OLMOCR6. 运行OLMOCR处理PDF文档7. 理解OLMOCR输出结果9. 可视化UI界面9.1 安装界面依赖9.2 创建界面应用…...

STM32单片机uCOS-Ⅲ系统11 中断管理

目录 一、异常与中断的基本概念 1、中断的介绍 2、和中断相关的名词解释 二、中断的运作机制 三、中断延迟的概念 四、中断的应用场景 五、中断管理讲解 六、中断延迟发布 1、中断延迟发布的概念 2、中断队列控制块 3、中断延迟发布任务初始化 OS_IntQTaskInit() 4…...

CTF【WEB】学习笔记1号刊

Kali的小工具箱 curl www.xxx.com&#xff1a;查看服务器响应返回的信息 curl -I www.xxx.com:查看响应的文件头 一、cmd执行命令 ipconfig&#xff1a;ip地址配置等&#xff1b; 二、 Kali操作 1.sudo su&#xff1b; 2.msfconsole 3.search ms17_010 永恒之蓝&#xff…...

cpp-友元

理解 C 中的友元&#xff08;Friend&#xff09; 在 C 语言中&#xff0c;封装&#xff08;Encapsulation&#xff09; 是面向对象编程的重要特性之一。它允许类将数据隐藏在私有&#xff08;private&#xff09;或受保护&#xff08;protected&#xff09;成员中&#xff0c;…...

Spring AOP 核心概念与实践指南

第一章&#xff1a;AOP 核心概念与基础应用 1.1 AOP 核心思想 ​面向切面编程&#xff1a;通过横向抽取机制解决代码重复问题&#xff08;如日志、事务、安全等&#xff09;​核心优势&#xff1a;不修改源代码增强功能&#xff0c;提高代码复用性和可维护性 1.2 基础环境搭…...

利用ffmpeg库实现音频Opus编解码

一、编译与环境配置 ‌libopus库集成‌ 需在编译FFmpeg时添加--enable-libopus参数&#xff0c;编译前需先安装libopus源码并配置动态库路径‌。最新FFmpeg 7.1版本默认支持Opus的浮点运算优化和VBR/CVBR模式‌。 ‌多平台兼容性‌ Opus支持Windows/Linux/macOS平台&#xff0…...

深入理解指针(1)(C语言版)

文章目录 前言一、内存和地址1.1 内存1.2 究竟该如何理解编址 二、指针变量和地址2.1 取地址操作符&2.2 指针变量和解引用操作符*2.2.1 指针变量2.2.2 如何拆解指针类型2.2.3 解引用操作符 2.3 指针变量的大小 三、指针变量类型的意义3.1 指针的解引用3.2 指针-整数3.3 voi…...

计算机网络——通信基础和传输介质

物理层任务&#xff1a;实现相邻节点之间比特&#xff08;0或1&#xff09;的传输 到了数据链路层之后&#xff0c;它会以帧为单位&#xff0c;把若干个比特交给物理层&#xff0c;物理层需要把这些比特信息转化成信号&#xff0c;在物理传输媒体上进行传输 通信基础基本概念 信…...

【橘子网络】关于网络分层以及协议的全局讲解

一、网络设备 1、硬件网络设备 1.1、主机(host) 主机的定义比较广泛&#xff0c;所有的接收流量或者发送流量的设备都可以被称之为主机。可以是电脑&#xff0c;手机&#xff0c;服务器。在当今云服务大行其道的局面下&#xff0c;各种云设备也可以被称之为主机。 基于这个…...

macOS 使用 enca 识别 文件编码类型(比 file 命令准确)

文章目录 macOS 上安装 enca基本使用起因 - iconv关于 enca安装 Encaenca & enconv 其它用法 macOS 上安装 enca brew install enca基本使用 enca filepath.txt示例 $ enca 动态规划算法.txt [0] Simplified Chinese National Standard; GB2312CRLF line terminat…...

MySQL 字符集

目录 字符集的基本概念 常见MySQL字符集 ascii(单字节字符集) latin1(单字节字符集) utf8(多字节字符集) utf8mb4(多字节字符集) MySQL默认字符集 MySQL字符集的层次级别 服务器级别 数据库级别 表级别 列级别 连接字符集 字符集是计算机科学中的一个重要概念&…...

Linux shell脚本3-if语句、case语句、for语句、while语句、until语句、break语句、continue语句,格式说明及程序验证

目录 1.if 控制语句 1.1 if 语句格式 1.2 程序验证 2.case语句 2.1case语句格式 2.2程序验证 2.2.1 终端先执行程序&#xff0c;在输入一个数 2.2.2 终端执行程序时同时输入一个预设变量 2.2.3 case带有按位或运算和通配符匹配 3.for语句 3.1for语句格式 3.2程序验…...

基于虚拟知识图谱的语义化决策引擎

在数字化转型浪潮中&#xff0c;企业数据资产的价值释放面临两大挑战&#xff1a;海量异构数据的整合困局与业务-技术语义鸿沟。本文解析飞速创软灵燕智能体平台的创新解决方案——通过构建业务语义驱动的虚拟知识图谱系统&#xff0c;实现企业数据的智能认知与决策赋能。 一、…...

Unity Shader 的编程流程和结构

Unity Shader 的编程流程和结构 Unity Shader 的编程主要由以下三个核心部分组成&#xff1a;Properties&#xff08;属性&#xff09;、SubShader&#xff08;子着色器&#xff09; 和 Fallback&#xff08;回退&#xff09;。下面是它们的具体作用和结构&#xff1a; 1. Pr…...

C++ 继承

目录 一、继承的概念与定义 1.1 继承的概念 1.2 继承的定义 1.2.1 语法 1.2.2 继承关系和访问限定符 1.2.3 继承基类成员访问方式的变化 二、基类和派生类对象赋值转换 三、继承中的作用域 四、派生类的默认成员函数 五、C11 final 六、继承与友元 七、继承与静态成…...

XSS Game(DOM型) 靶场 通关

目录 靶场网址 Ma Spaghet! 分析 解题 Jefff 分析 解题 方法一 方法二 Ugandan Knuckles 分析 解题 Ricardo Milos 分析 解题 Ah Thats Hawt 分析 解题 方法一 方法二 Ligma 分析 解题 ​ Mafia 分析 解题 方法一&#xff1a;构造函数 方法二&#xf…...

XSS基础靶场练习

目录 1. 准备靶场 2. PASS 1. Level 1&#xff1a;无过滤 源码&#xff1a; 2. level2&#xff1a;转HTML实体 htmlspecialchars简介&#xff1a; 源码 PASS 3. level3:转HTML深入 源码&#xff1a; PASS 4. level4:过滤<> 源码&#xff1a; PASS: 5. level5:过滤on 源码…...

leetcode-200.岛屿数量

首先&#xff0c;想要找岛&#xff0c;肯定是要逐个遍历的&#xff0c;否则肯定会漏岛。 其次&#xff0c;我怎么知道两个点是否属于一个岛&#xff1f;只有一个方法&#xff0c;我踏上一个岛的某个点时&#xff0c;我就分别往四周走&#xff0c;且把当前地块毁掉&#xff0c;就…...

Linux | ubuntu安装 SSH 软件及测试工具

01 windows 要怎么和 ubuntu 互传文件呢&#xff0c;我们可以使用 ssh 软件。 终端输入 sudo apt-get install openssh-server &#xff0c;输入登录 Ubuntu 用户的密码&#xff0c;这里我们输入 y 确认安装。如下图所示。 接着继续改 ssh 配置文件&#xff0c;因为 ssh 默认…...

组件日志——etcd

目录 一、简介 二、安装【Ubuntu】 安装etcd 安装CAPI 三、写一个示例 3.0写一个示例代码 3.1获取一个etcd服务 3.2获取租约(写端操作) 3.3使用租约(写端操作) 3.4销毁租约(写端操作) 3.5获取etcd服务中的服务列表(读端操作) 3.6监听状态变化(读端操作) 一、简介 Et…...

search_fields与filterset_fields的使用

在Django中&#xff0c;search_fields 和 filterset_fields 可以在视图类中使用&#xff0c;尤其是在 Django REST Framework (DRF) 中。它们分别用于实现搜索和过滤功能。以下是它们在视图类中的具体使用方法。 1. search_fields 在视图类中的使用 search_fields 是 DRF 中 S…...

SQLite Delete 语句详解

SQLite Delete 语句详解 SQLite 是一种轻量级的数据库管理系统&#xff0c;广泛应用于移动设备、嵌入式系统和服务器端应用。在数据库管理中&#xff0c;删除数据是一项基本操作。SQLite 提供了强大的删除功能&#xff0c;本文将详细介绍 SQLite 的 Delete 语句及其用法。 1.…...

通往自主智能之路:探索自我成长的AI

1. 引言&#xff1a;当前AI范式与自我成长智能的愿景 当前的人工智能领域在很大程度上由大型语言模型&#xff08;LLM&#xff09;的卓越能力所定义。这些模型&#xff0c;例如OpenAI的GPT系列和谷歌的BERT&#xff0c;已经展示了前所未有的理解和生成类人文本的能力。LLM通常…...

[自动化] 【八爪鱼】使用八爪鱼实现CSDN文章自动阅读脚本

在CSDN上&#xff0c;文章的阅读量往往是衡量内容影响力的一个重要指标。为了测试自动化手段能否提高阅读数&#xff0c;我尝试使用网页自动化工具来模拟人工阅读某个ID的文章。 1. 网页自动化的常见方案 谈到网页自动化&#xff0c;Selenium 是一个最常见的选择。它可以通过…...

Kafka消息序列化深度革命:构建高性能、高安全的自定义编码体系

一、突破默认序列化的桎梏 1.1 原生序列化器的致命缺陷 Kafka默认提供的StringSerializer/ByteArraySerializer在复杂场景下暴露三大痛点&#xff1a; 类型安全黑洞&#xff1a;字节流缺乏元数据描述&#xff0c;消费端解析如履薄冰版本兼容困境&#xff1a;数据结构变更导致…...

2025年如何避免使用验证码求解器时被IP封禁

引言 2025年&#xff0c;验证码求解器已成为自动化网络抓取和其他在线流程的关键工具。然而&#xff0c;自动化用户面临的一个常见挑战是IP封禁。当网站检测到自动化活动时&#xff0c;通常会阻止发出请求的IP地址&#xff0c;导致验证码挑战无法解决。本文将探讨使用验证码求…...

前端 AI IDE应用优缺点

嗯&#xff0c;用户问了三个前端面试的问题&#xff0c;我需要仔细分析每个问题&#xff0c;并结合提供的搜索结果来给出全面且准确的回答。 第一个问题是关于开发工具Cursor或Vim的Windurf在开发中的占比以及它们的缺点。从搜索结果里看&#xff0c;网页3提到了Trae对标Curso…...