docs(api): enforce linux-style public header documentation

This commit is contained in:
Microindole 2026-05-12 18:02:23 +08:00
parent fdb1406ba2
commit 78bc6b70cf
No known key found for this signature in database
GPG Key ID: 22FB34CD2133ACA1
7 changed files with 292 additions and 17 deletions

View File

@ -45,7 +45,10 @@
- 如果代码依赖硬件手册、启动协议、调用顺序或特殊寄存器状态,应写明约束。 - 如果代码依赖硬件手册、启动协议、调用顺序或特殊寄存器状态,应写明约束。
- 如果一个实现是临时简化,应写清楚后续替换边界,而不是写成永久接口。 - 如果一个实现是临时简化,应写清楚后续替换边界,而不是写成永久接口。
- 公共头文件 `include/tianole/*.h` 中的函数声明必须使用 Linux kernel-doc 风格块注释。 - 公共头文件 `include/tianole/*.h` 中的函数声明必须使用 Linux kernel-doc 风格块注释。
- 公共结构体、枚举、typedef 和长期宏常量也必须使用 kernel-doc 风格块注释。
- 公共函数注释至少说明函数职责、关键参数、返回值或副作用;不要只复述函数名。 - 公共函数注释至少说明函数职责、关键参数、返回值或副作用;不要只复述函数名。
- 公共类型注释要说明字段含义、所有权、生命周期或并发约束。
- 公共宏注释要说明它代表的协议常量、标志位或长期 ABI 含义。
- 公共函数声明和前一个声明/注释块之间必须留一个空行,避免 API 挤在一起。 - 公共函数声明和前一个声明/注释块之间必须留一个空行,避免 API 挤在一起。
- 私有 `static` 小函数不要求每个都写函数头注释;只有逻辑、数据流、锁语义或硬件约束不明显时才写。 - 私有 `static` 小函数不要求每个都写函数头注释;只有逻辑、数据流、锁语义或硬件约束不明显时才写。
- 多行注释要控制行宽,优先写职责、数据流和调用约束,而不是描述每一行代码。 - 多行注释要控制行宽,优先写职责、数据流和调用约束,而不是描述每一行代码。

View File

@ -3,8 +3,26 @@
#include <stdint.h> #include <stdint.h>
/**
* BOOT_MEMORY_TYPE_CONVENTIONAL - Firmware memory type for usable RAM.
*
* Mirrors the UEFI conventional memory type used by the bootloader handoff.
* The kernel converts this into its own long-term memory model during MM init.
*/
#define BOOT_MEMORY_TYPE_CONVENTIONAL 7u #define BOOT_MEMORY_TYPE_CONVENTIONAL 7u
/**
* typedef boot_memory_descriptor_t - Boot memory map descriptor.
* @type: Firmware memory type.
* @pad: Reserved padding used to keep the handoff layout stable.
* @physical_start: Physical base address of this region.
* @virtual_start: Firmware virtual address field, currently preserved only.
* @number_of_pages: Region size in 4 KiB pages.
* @attribute: Firmware attributes for the region.
*
* Describes one memory map entry copied from firmware-owned data into the
* Tianole boot handoff format.
*/
typedef struct { typedef struct {
uint32_t type; uint32_t type;
uint32_t pad; uint32_t pad;
@ -14,10 +32,19 @@ typedef struct {
uint64_t attribute; uint64_t attribute;
} boot_memory_descriptor_t; } boot_memory_descriptor_t;
/* /**
* Boot-time handoff data owned by Tianole rather than by a specific * typedef boot_info_t - Bootloader-to-kernel handoff data.
* firmware or architecture API. Fields can grow over time while the * @version: Handoff structure version.
* kernel entry stays stable. * @boot_flags: Flags describing the firmware handoff state.
* @memory_map: Physical address of boot_memory_descriptor_t entries.
* @memory_map_size: Total memory map size in bytes.
* @memory_map_key: Firmware key captured before ExitBootServices().
* @memory_descriptor_size: Size of each memory descriptor entry.
* @memory_descriptor_version: Firmware descriptor version.
* @reserved0: Reserved field for alignment and future expansion.
*
* Boot-time handoff data owned by Tianole rather than by a specific firmware
* or architecture API. Fields can grow while the kernel entry stays stable.
*/ */
typedef struct { typedef struct {
uint32_t version; uint32_t version;
@ -30,7 +57,14 @@ typedef struct {
uint32_t reserved0; uint32_t reserved0;
} boot_info_t; } boot_info_t;
/**
* BOOT_INFO_VERSION - Current boot_info_t layout version.
*/
#define BOOT_INFO_VERSION 1u #define BOOT_INFO_VERSION 1u
/**
* BOOT_FLAG_SERVICES_ACTIVE - Firmware boot services were active at handoff.
*/
#define BOOT_FLAG_SERVICES_ACTIVE (1u << 0) #define BOOT_FLAG_SERVICES_ACTIVE (1u << 0)
#endif #endif

View File

@ -3,16 +3,61 @@
#include <stdint.h> #include <stdint.h>
/**
* ELF_MAGIC - ELF file magic value in little-endian word form.
*/
#define ELF_MAGIC 0x464c457fu #define ELF_MAGIC 0x464c457fu
/**
* ELFCLASS64 - ELF identification value for 64-bit objects.
*/
#define ELFCLASS64 2 #define ELFCLASS64 2
/**
* ELFDATA2LSB - ELF identification value for little-endian objects.
*/
#define ELFDATA2LSB 1 #define ELFDATA2LSB 1
/**
* EV_CURRENT - Current ELF object format version.
*/
#define EV_CURRENT 1 #define EV_CURRENT 1
/**
* ET_EXEC - ELF object type for executable files.
*/
#define ET_EXEC 2 #define ET_EXEC 2
/**
* EM_X86_64 - ELF machine type for x86_64.
*/
#define EM_X86_64 62 #define EM_X86_64 62
/**
* PT_LOAD - ELF program header type for loadable segments.
*/
#define PT_LOAD 1 #define PT_LOAD 1
/**
* typedef elf64_ehdr_t - ELF64 file header.
* @ident: ELF identification bytes.
* @type: Object file type.
* @machine: Target machine architecture.
* @version: ELF object version.
* @entry: Entry point virtual address.
* @phoff: Program header table file offset.
* @shoff: Section header table file offset.
* @flags: Processor-specific flags.
* @ehsize: ELF header size.
* @phentsize: Size of one program header entry.
* @phnum: Number of program header entries.
* @shentsize: Size of one section header entry.
* @shnum: Number of section header entries.
* @shstrndx: Section name string table index.
*
* Used by the bootloader and future ELF loader to validate and locate image
* segments without depending on host libc headers.
*/
typedef struct { typedef struct {
unsigned char ident[16]; unsigned char ident[16];
uint16_t type; uint16_t type;
@ -30,6 +75,20 @@ typedef struct {
uint16_t shstrndx; uint16_t shstrndx;
} elf64_ehdr_t; } elf64_ehdr_t;
/**
* typedef elf64_phdr_t - ELF64 program header.
* @type: Segment type.
* @flags: Segment permissions.
* @offset: Segment file offset.
* @vaddr: Segment virtual address.
* @paddr: Segment physical address, if meaningful for the image.
* @filesz: Number of bytes present in the file.
* @memsz: Number of bytes required in memory.
* @align: Segment alignment requirement.
*
* Describes one loadable or metadata segment consumed by boot and future
* user-mode ELF loading paths.
*/
typedef struct { typedef struct {
uint32_t type; uint32_t type;
uint32_t flags; uint32_t flags;

View File

@ -6,13 +6,38 @@
#include <tianole/boot_info.h> #include <tianole/boot_info.h>
/**
* PAGE_SIZE - Base page size used by the current memory manager.
*/
#define PAGE_SIZE 4096u #define PAGE_SIZE 4096u
/**
* typedef phys_addr_t - Physical address value.
*
* Represents addresses in physical memory, not directly dereferenceable by C.
*/
typedef uint64_t phys_addr_t; typedef uint64_t phys_addr_t;
/**
* typedef virt_addr_t - Virtual address value.
*
* Represents addresses in the active virtual address space.
*/
typedef uint64_t virt_addr_t; typedef uint64_t virt_addr_t;
/**
* PAGE_PRESENT - Mapping flag that marks a page table entry present.
*/
#define PAGE_PRESENT (1ull << 0) #define PAGE_PRESENT (1ull << 0)
/**
* PAGE_WRITABLE - Mapping flag that allows writes through a page mapping.
*/
#define PAGE_WRITABLE (1ull << 1) #define PAGE_WRITABLE (1ull << 1)
/**
* PAGE_NO_EXECUTE - Mapping flag that blocks instruction fetches.
*/
#define PAGE_NO_EXECUTE (1ull << 63) #define PAGE_NO_EXECUTE (1ull << 63)
/** /**

View File

@ -6,9 +6,31 @@
#include <tianole/spinlock.h> #include <tianole/spinlock.h>
/**
* typedef kernel_thread_entry_t - Kernel thread entry function.
* @arg: Opaque argument supplied at thread creation.
*
* The function runs in kernel thread context. Returning from it is equivalent
* to calling kernel_thread_exit().
*/
typedef void (*kernel_thread_entry_t)(void *arg); typedef void (*kernel_thread_entry_t)(void *arg);
/**
* typedef wait_condition_t - Wait queue condition predicate.
* @arg: Opaque predicate argument supplied by the caller.
*
* Return: Non-zero when the condition is satisfied, zero to keep waiting.
*/
typedef int (*wait_condition_t)(void *arg); typedef int (*wait_condition_t)(void *arg);
/**
* enum thread_state - Scheduler-visible thread lifecycle state.
* @THREAD_READY: Thread is runnable and may be selected by the scheduler.
* @THREAD_RUNNING: Thread is currently executing on the CPU.
* @THREAD_SLEEPING: Thread is blocked until a timer deadline.
* @THREAD_WAITING: Thread is blocked on a wait queue.
* @THREAD_DEAD: Thread has exited and is waiting for safe reclamation.
*/
enum thread_state { enum thread_state {
THREAD_READY, THREAD_READY,
THREAD_RUNNING, THREAD_RUNNING,
@ -17,12 +39,39 @@ enum thread_state {
THREAD_DEAD, THREAD_DEAD,
}; };
/**
* struct wait_queue - Queue of threads blocked on an event or condition.
* @lock: Interrupt-safe lock protecting queue links and wakeup state.
* @head: Oldest waiting thread.
* @tail: Newest waiting thread.
*
* The queue owns only wait links. The condition being waited on may be owned
* by another subsystem and must have a documented synchronization rule.
*/
struct wait_queue { struct wait_queue {
struct spinlock lock; struct spinlock lock;
struct thread *head; struct thread *head;
struct thread *tail; struct thread *tail;
}; };
/**
* struct thread - Kernel scheduler thread object.
* @id: Scheduler-assigned thread identifier.
* @state: Current scheduler state.
* @stack_pointer: Saved context stack pointer for context switching.
* @entry: Thread entry function.
* @arg: Entry function argument.
* @stack_base: Allocated kernel stack base.
* @stack_top: Aligned initial stack top.
* @stack_size: Kernel stack size in bytes.
* @wake_tick: Timer tick deadline for sleeping threads.
* @next: Run queue link owned by the scheduler.
* @wait_next: Wait queue link owned by wait queue code.
* @name: Diagnostic thread name.
*
* This structure is public only as an early-stage compromise. Long term, most
* fields should move behind scheduler-private helpers or an opaque handle.
*/
struct thread { struct thread {
uint64_t id; uint64_t id;
enum thread_state state; enum thread_state state;

View File

@ -3,10 +3,20 @@
#include <stdint.h> #include <stdint.h>
/**
* struct spinlock - Early interrupt-safe lock.
* @locked: Non-zero while the lock is held.
*
* Current implementation is single-CPU and panics on contention. The API is
* shaped so it can later grow toward a real SMP spinlock.
*/
struct spinlock { struct spinlock {
int locked; int locked;
}; };
/**
* SPINLOCK_INITIALIZER - Static initializer for struct spinlock.
*/
#define SPINLOCK_INITIALIZER \ #define SPINLOCK_INITIALIZER \
{ \ { \
0 \ 0 \

View File

@ -152,6 +152,71 @@ def collect_function_declarations(lines: list[str]) -> list[tuple[int, int, str]
return decls return decls
def is_public_type_start(line: str) -> bool:
stripped = line.strip()
if stripped.startswith(("struct ", "enum ", "union ")):
return stripped.endswith("{") or "{" in stripped
if not stripped.startswith("typedef "):
return False
return "(" not in stripped
def collect_public_type_declarations(lines: list[str]) -> list[tuple[int, int, str]]:
decls = []
index = 0
while index < len(lines):
if not is_public_type_start(lines[index]):
index += 1
continue
start = index
text = lines[index].strip()
while ";" not in lines[index]:
index += 1
if index >= len(lines):
break
text += " " + lines[index].strip()
if index < len(lines):
decls.append((start, index, text))
index += 1
return decls
def is_documented_public_define(lines: list[str], index: int, guard: str | None) -> bool:
stripped = lines[index].strip()
if not stripped.startswith("#define "):
return False
parts = stripped.split()
if len(parts) < 2:
return False
name = parts[1].split("(", 1)[0]
if name == guard:
return False
return True
def header_guard_name(lines: list[str]) -> str | None:
for line in lines:
stripped = line.strip()
if stripped.startswith("#define "):
parts = stripped.split()
if len(parts) >= 2:
return parts[1]
return None
def has_kernel_doc_before(lines: list[str], start: int) -> bool: def has_kernel_doc_before(lines: list[str], start: int) -> bool:
index = start - 1 index = start - 1
@ -187,26 +252,56 @@ def has_blank_line_before_doc(lines: list[str], start: int) -> bool:
return lines[index - 1].strip() == "" return lines[index - 1].strip() == ""
def check_public_header_function_docs(root: Path, files: list[Path]) -> list[str]: def symbol_name_from_type_declaration(text: str) -> str:
if text.startswith("typedef "):
return text.rsplit("}", 1)[-1].strip().rstrip(";").split()[-1]
parts = text.split()
if len(parts) >= 2:
return parts[1]
return "<unknown>"
def check_kernel_doc_block(
errors: list[str], path: Path, lines: list[str], start: int, kind: str, name: str
) -> None:
line_no = start + 1
if not has_kernel_doc_before(lines, start):
errors.append(
f"{path}:{line_no}: public {kind} '{name}' needs "
"a kernel-doc comment immediately before it"
)
return
if not has_blank_line_before_doc(lines, start):
errors.append(
f"{path}:{line_no}: public {kind} '{name}' "
"comment block must be separated by a blank line"
)
def check_public_header_docs(root: Path, files: list[Path]) -> list[str]:
errors = [] errors = []
for path in files: for path in files:
lines = read_text(root, path).splitlines() lines = read_text(root, path).splitlines()
for start, _end, text in collect_function_declarations(lines): for start, _end, text in collect_function_declarations(lines):
line_no = start + 1
name = text.split("(", 1)[0].split()[-1].lstrip("*") name = text.split("(", 1)[0].split()[-1].lstrip("*")
if not has_kernel_doc_before(lines, start): check_kernel_doc_block(errors, path, lines, start, "function", name)
errors.append(
f"{path}:{line_no}: public function '{name}' needs " for start, _end, text in collect_public_type_declarations(lines):
"a kernel-doc comment immediately before it" name = symbol_name_from_type_declaration(text)
) check_kernel_doc_block(errors, path, lines, start, "type", name)
guard = header_guard_name(lines)
for index, line in enumerate(lines):
if not is_documented_public_define(lines, index, guard):
continue continue
if not has_blank_line_before_doc(lines, start): name = line.strip().split()[1].split("(", 1)[0]
errors.append( check_kernel_doc_block(errors, path, lines, index, "macro", name)
f"{path}:{line_no}: public function '{name}' "
"comment block must be separated by a blank line"
)
return errors return errors
@ -313,7 +408,7 @@ def main() -> int:
errors = [] errors = []
errors.extend(check_no_relative_parent_includes(root, source_files(files))) errors.extend(check_no_relative_parent_includes(root, source_files(files)))
errors.extend(check_public_header_function_docs(root, public_headers(files))) errors.extend(check_public_header_docs(root, public_headers(files)))
errors.extend(check_selftests_are_centralized(c_files(files))) errors.extend(check_selftests_are_centralized(c_files(files)))
errors.extend(check_makefile_source_lists(root, files, all_mode)) errors.extend(check_makefile_source_lists(root, files, all_mode))