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