新增rust ffi (#77)

* 引入cargo

* 取消对Cargo.lock的跟踪

* 解决vscode报错问题

* new: rust的代码能够调用c语言的printk_color

* 1、将原本run.sh的工作拆解,变为几个不同的make命令
2、在docker镜像中编译rust

* 更改workflow

* update workflow

* new: 解决workflow无法通过编译的问题
This commit is contained in:
login
2022-11-11 15:35:37 +08:00
committed by GitHub
parent 5e023cf791
commit 2813126e31
271 changed files with 609 additions and 307 deletions

79
kernel/src/Makefile Normal file
View File

@ -0,0 +1,79 @@
SUBDIR_ROOTS := .
DIRS := . $(shell find $(SUBDIR_ROOTS) -type d)
GARBAGE_PATTERNS := *.o *.s~ *.s *.S~ *.c~ *.h~ kernel
GARBAGE := $(foreach DIR,$(DIRS),$(addprefix $(DIR)/,$(GARBAGE_PATTERNS)))
DIR_LIB=lib
lib_patterns := *.a
LIB_FILES := $(foreach DIR,$(DIR_LIB),$(addprefix $(DIR)/,$(lib_patterns)))
# 控制操作系统使用的中断控制器 _INTR_8259A_ _INTR_APIC_
PIC := _INTR_APIC_
CFLAGS = $(GLOBAL_CFLAGS) -D $(PIC) -I $(shell pwd)
export ASFLAGS := --64
LD_LIST := head.o
kernel_subdirs := common driver process debug filesystem time arch exception mm smp sched syscall ktest lib ipc
head.o: head.S
$(CC) -E head.S > _head.s # 预处理
as $(ASFLAGS) -o head.o _head.s
main.o: main.c
# -fno-builtin: 不使用C语言内建函数
# The -m64 option sets int to 32bits and long and pointer to 64 bits and generates code for AMDs x86-64 architecture.
$(CC) $(CFLAGS) -c main.c -o main.o
all: kernel
rustup default nightly
cargo +nightly build --release --target ./arch/x86_64/x86_64-unknown-none.json
@echo "Linking kernel..."
ld -b elf64-x86-64 -z muldefs -o kernel head.o main.o $(shell find . -name "*.o") ../target/x86_64-unknown-none/release/libdragonos_kernel.a -T link.lds
# 生成kallsyms
current_dir=$(pwd)
@dbg='debug';for x in $$dbg; do \
cd $$x;\
$(MAKE) generate_kallsyms kernel_root_path="$(shell pwd)";\
cd ..;\
if [ "$$?" != "0" ]; then\
exit $$?;\
fi;\
done
# 重新链接
@echo "Re-Linking kernel..."
ld -b elf64-x86-64 -z muldefs -o kernel head.o main.o $(shell find . -name "*.o") ../target/x86_64-unknown-none/release/libdragonos_kernel.a ./debug/kallsyms.o -T link.lds
@echo "Generating kernel ELF file..."
# 生成内核文件
objcopy -I elf64-x86-64 -O elf64-x86-64 -R ".comment" -R ".eh_frame" kernel ../../bin/kernel/kernel.elf
@echo "Kernel Build Done."
ECHO:
@echo "$@"
$(kernel_subdirs): ECHO
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)" kernel_root_path="$(shell pwd)"
kernel: head.o main.o $(kernel_subdirs)
clean:
cargo clean
rm -rf $(GARBAGE)
@list='$(kernel_subdirs)'; for subdir in $$list; do \
echo "Clean in dir: $$subdir";\
cd $$subdir && $(MAKE) clean;\
cd .. ;\
done

17
kernel/src/arch/Makefile Normal file
View File

@ -0,0 +1,17 @@
CFLAGS += -I .
ifeq ($(ARCH), __x86_64__)
kernel_arch_subdirs:=x86_64
endif
all:
@list='$(kernel_arch_subdirs)'; for subdir in $$list; do \
echo "make all in $$subdir";\
cd $$subdir;\
$(MAKE) all CFLAGS="$(CFLAGS)" PIC="$(PIC)";\
cd ..;\
done
clean:
echo "Done."

12
kernel/src/arch/arch.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#define ARCH(arch) (defined(AK_ARCH_##arch) && AK_ARCH_##arch)
#ifdef __i386__
# define AK_ARCH_I386 1
#endif
#ifdef __x86_64__
# define AK_ARCH_X86_64 1
#endif

View File

@ -0,0 +1,10 @@
CFLAGS += -I .
all: x86_64_ipi.o ia64_msi.o
x86_64_ipi.o: x86_64_ipi.c
$(CC) $(CFLAGS) -c x86_64_ipi.c -o x86_64_ipi.o
ia64_msi.o: ia64_msi.c
$(CC) $(CFLAGS) -c ia64_msi.c -o ia64_msi.o

View File

@ -0,0 +1,149 @@
#pragma once
#include <stdint.h>
#define sti() __asm__ __volatile__("sti\n\t" :: \
: "memory") //开启外部中断
#define cli() __asm__ __volatile__("cli\n\t" :: \
: "memory") //关闭外部中断
#define nop() __asm__ __volatile__("nop\n\t")
#define hlt() __asm__ __volatile__("hlt\n\t")
#define pause() asm volatile("pause\n\t"); // 处理器等待一段时间
//内存屏障
#define io_mfence() __asm__ __volatile__("mfence\n\t" :: \
: "memory") // 在mfence指令前的读写操作必须在mfence指令后的读写操作前完成。
#define io_sfence() __asm__ __volatile__("sfence\n\t" :: \
: "memory") // 在sfence指令前的写操作必须在sfence指令后的写操作前完成
#define io_lfence() __asm__ __volatile__("lfence\n\t" :: \
: "memory") // 在lfence指令前的读操作必须在lfence指令后的读操作前完成。
/*
* Macros to generate condition code outputs from inline assembly,
* The output operand must be type "bool".
*/
// 如果编译器支持输出标志寄存器值到变量的话则会定义__GCC_ASM_FLAG_OUTPUTS__
#ifdef __GCC_ASM_FLAG_OUTPUTS__
// CC_SET(c)则是用于设置标志寄存器中的某一位
#define CC_SET(c) "\n\t/* output condition code " #c "*/\n"
// "=@cccond"的用法是将标志寄存器中的cond也就是指令集定义的标准条件的值输出到变量中
#define CC_OUT(c) "=@cc" #c
#else
#define CC_SET(c) "\n\tset" #c " %[_cc_" #c "]\n"
#define CC_OUT(c) [_cc_##c] "=qm"
#endif
#define rdtsc() ({ \
uint64_t tmp1 = 0, tmp2 = 0; \
asm volatile("rdtsc" \
: "=d"(tmp1), "=a"(tmp2)::"memory"); \
(tmp1 << 32 | tmp2); \
})
/**
* @brief 读取rsp寄存器的值存储了页目录的基地址
*
* @return unsigned* rsp的值的指针
*/
unsigned long *get_rsp()
{
uint64_t *tmp;
__asm__ __volatile__(
"movq %%rsp, %0\n\t"
: "=r"(tmp)::"memory");
return tmp;
}
/**
* @brief 读取rbp寄存器的值存储了页目录的基地址
*
* @return unsigned* rbp的值的指针
*/
unsigned long *get_rbp()
{
uint64_t *tmp;
__asm__ __volatile__(
"movq %%rbp, %0\n\t"
: "=r"(tmp)::"memory");
return tmp;
}
/**
* @brief 读取ds寄存器的值存储了页目录的基地址
*
* @return unsigned* ds的值的指针
*/
unsigned long *get_ds()
{
uint64_t *tmp;
__asm__ __volatile__(
"movq %%ds, %0\n\t"
: "=r"(tmp)::"memory");
return tmp;
}
/**
* @brief 读取rax寄存器的值存储了页目录的基地址
*
* @return unsigned* rax的值的指针
*/
unsigned long *get_rax()
{
uint64_t *tmp;
__asm__ __volatile__(
"movq %%rax, %0\n\t"
: "=r"(tmp)::"memory");
return tmp;
}
/**
* @brief 读取rbx寄存器的值存储了页目录的基地址
*
* @return unsigned* rbx的值的指针
*/
unsigned long *get_rbx()
{
uint64_t *tmp;
__asm__ __volatile__(
"movq %%rbx, %0\n\t"
: "=r"(tmp)::"memory");
return tmp;
}
// ========= MSR寄存器组操作 =============
/**
* @brief 向msr寄存器组的address处的寄存器写入值value
*
* @param address 地址
* @param value 要写入的值
*/
void wrmsr(uint64_t address, uint64_t value)
{
__asm__ __volatile__("wrmsr \n\t" ::"d"(value >> 32), "a"(value & 0xffffffff), "c"(address)
: "memory");
}
/**
* @brief 从msr寄存器组的address地址处读取值
* rdmsr返回高32bits在edx低32bits在eax
* @param address 地址
* @return uint64_t address处的寄存器的值
*/
uint64_t rdmsr(uint64_t address)
{
unsigned int tmp0, tmp1;
__asm__ __volatile__("rdmsr \n\t"
: "=d"(tmp0), "=a"(tmp1)
: "c"(address)
: "memory");
return ((uint64_t)tmp0 << 32) | tmp1;
}
uint64_t get_rflags()
{
unsigned long tmp = 0;
__asm__ __volatile__("pushfq \n\t"
"movq (%%rsp), %0 \n\t"
"popfq \n\t"
: "=r"(tmp)::"memory");
return tmp;
}

View File

@ -0,0 +1,81 @@
#pragma once
#include <common/compiler.h>
#include <arch/x86_64/asm/asm.h>
/**
* @brief 通过extern不存在的函数来让编译器报错。以防止不符合要求的代码的产生。
*/
extern void __cmpxchg_wrong_size(void) __compiletime_error("Bad argument size for cmpxchg");
// 定义常量:操作符涉及到的字节数
#define __X86_CASE_B 1
#define __X86_CASE_W 2
#define __X86_CASE_L 4
#define __X86_CASE_Q 8
/**
* @brief lock cmpxchg指令的包装。
* 将_ptr指向的值与old_ptr指向的值做比较如果相等则将_new指向的值加载到_ptr指向的值中。
*/
#define __raw_try_cmpxchg(_ptr, _old_ptr, _new, size) \
({ \
bool is_success = false; \
typeof(_ptr) _old = (typeof(_ptr))(_old_ptr); \
typeof(*(_ptr)) __old = *_old; \
typeof(*(_ptr)) __new = (_new); \
switch (size) \
{ \
case __X86_CASE_B: \
{ \
volatile uint8_t *__ptr = (volatile uint8_t *)(_ptr); \
asm volatile("lock cmpxchgb %[new], %[ptr]\n\t" \
: CC_OUT(z)(is_success), \
[ptr] "+m"(*__ptr), \
[old] "+a"(__old) \
: [new] "q"(__new) \
: "memory"); \
break; \
} \
case __X86_CASE_W: \
{ \
volatile uint16_t *__ptr = (volatile uint16_t *)(_ptr); \
asm volatile("lock cmpxchgw %[new], %[ptr]\n\t" \
: CC_OUT(z)(is_success), \
[ptr] "+m"(*__ptr), \
[old] "+a"(__old) \
: [new] "q"(__new) \
: "memory"); \
break; \
} \
case __X86_CASE_L: \
{ \
volatile uint32_t *__ptr = (volatile uint32_t *)(_ptr); \
asm volatile("lock cmpxchgl %[new], %[ptr]\n\t" \
: CC_OUT(z)(is_success), \
[ptr] "+m"(*__ptr), \
[old] "+a"(__old) \
: [new] "q"(__new) \
: "memory"); \
break; \
} \
case __X86_CASE_Q: \
{ \
volatile uint64_t *__ptr = (volatile uint64_t *)(_ptr); \
asm volatile("lock cmpxchgq %[new], %[ptr]\n\t" \
: CC_OUT(z)(is_success), \
[ptr] "+m"(*__ptr), \
[old] "+a"(__old) \
: [new] "q"(__new) \
: "memory"); \
break; \
} \
default: \
__cmpxchg_wrong_size(); \
} \
if (unlikely(is_success == false)) \
*_old = __old; \
likely(is_success); \
})
#define arch_try_cmpxchg(ptr, old_ptr, new_ptr) \
__raw_try_cmpxchg((ptr), (old_ptr), (new_ptr), sizeof(*ptr))

View File

@ -0,0 +1,20 @@
#pragma once
#include <common/glib.h>
#pragma GCC push_options
#pragma GCC optimize("O0")
struct process_control_block;
// 获取当前的pcb
struct process_control_block *get_current_pcb()
{
struct process_control_block *current = NULL;
// 利用了当前pcb和栈空间总大小为32k大小对齐将rsp低15位清空即可获得pcb的起始地址
barrier();
__asm__ __volatile__("andq %%rsp, %0 \n\t"
: "=r"(current)
: "0"(~32767UL));
barrier();
return current;
};
#define current_pcb get_current_pcb()
#pragma GCC pop_options

View File

@ -0,0 +1,28 @@
#include "ia64_msi.h"
/**
* @brief 生成架构相关的msi的message address
*
*/
#define ia64_pci_get_arch_msi_message_address(processor) ((0xfee00000UL | (processor << 12)))
/**
* @brief 生成架构相关的message data
*
*/
#define ia64_pci_get_arch_msi_message_data(vector, processor, edge_trigger, assert) ((uint32_t)((vector & 0xff) | (edge_trigger == 1 ? 0 : (1 << 15)) | ((assert == 0) ? 0 : (1 << 14))))
/**
* @brief 生成msi消息
*
* @param msi_desc msi描述符
* @return struct msi_msg_t* msi消息指针在描述符内
*/
struct msi_msg_t *msi_arch_get_msg(struct msi_desc_t *msi_desc)
{
msi_desc->msg.address_hi = 0;
msi_desc->msg.address_lo = ia64_pci_get_arch_msi_message_address(msi_desc->processor);
msi_desc->msg.data = ia64_pci_get_arch_msi_message_data(msi_desc->irq_num, msi_desc->processor, msi_desc->edge_trigger, msi_desc->assert);
msi_desc->msg.vector_control = 0;
return &(msi_desc->msg);
}

View File

@ -0,0 +1,11 @@
#pragma once
#include <driver/pci/msi.h>
/**
* @brief 生成msi消息
*
* @param msi_desc msi描述符
* @return struct msi_msg_t* msi消息指针在描述符内
*/
struct msi_msg_t *msi_arch_get_msg(struct msi_desc_t *msi_desc);

View File

@ -0,0 +1,69 @@
#include <common/stddef.h>
/**
* @brief 统计二进制数的前导0
*
* @param x 待统计的数
* @return int 结果
*/
static __always_inline int __clz(uint32_t x)
{
asm volatile("bsr %%eax, %%eax\n\t"
"xor $0x1f, %%eax\n\t"
: "=a"(x)
: "a"(x)
: "memory");
return x;
}
/**
* @brief 统计二进制数的前导0 (宽度为unsigned long)
*
* @param x 待统计的数
* @return int 结果
*/
static __always_inline int __clzl(unsigned long x)
{
int res = 0;
asm volatile("cltq\n\t"
"bsr %%rax, %%rax\n\t"
"xor $0x3f, %%rax\n\t"
"mov %%eax,%0\n\t"
: "=m"(res)
: "a"(x)
: "memory");
return res;
}
/**
* @brief 统计二进制数的前导0宽度为unsigned long long
*
* @param x 待统计的数
* @return int 结果
*/
static __always_inline int __clzll(unsigned long long x)
{
int res = 0;
asm volatile("cltq\n\t"
"bsr %%rax, %%rax\n\t"
"xor $0x3f, %%rax\n\t"
"mov %%eax,%0\n\t"
: "=m"(res)
: "a"(x)
: "memory");
return res;
}
static __always_inline int __ctz(uint32_t x)
{
asm volatile("tzcnt %%eax, %%eax":"=a"(x):"a"(x):"memory");
return x;
}
static __always_inline int __ctzl(unsigned long x)
{
asm volatile("tzcnt %%rax, %%rax":"=a"(x):"a"(x):"memory");
return x;
}
#define __ctzll __ctzl

View File

@ -0,0 +1,15 @@
{
"llvm-target": "x86_64-unknown-none",
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
"arch": "x86_64",
"target-endian": "little",
"target-pointer-width": "64",
"target-c-int-width": "32",
"os": "none",
"linker": "rust-lld",
"linker-flavor": "ld.lld",
"executables": true,
"features": "-mmx,-sse,+soft-float",
"disable-redzone": true,
"panic-strategy": "abort"
}

View File

@ -0,0 +1,49 @@
#include "x86_64_ipi.h"
#include <driver/interrupt/apic/apic.h>
void ipi_send_IPI(uint32_t dest_mode, uint32_t deliver_status, uint32_t level, uint32_t trigger,
uint32_t vector, uint32_t deliver_mode, uint32_t dest_shorthand, uint32_t destination)
{
struct INT_CMD_REG icr_entry;
icr_entry.dest_mode = dest_mode;
icr_entry.deliver_status = deliver_status;
icr_entry.res_1 = 0;
icr_entry.level = level;
icr_entry.trigger = trigger;
icr_entry.res_2 = 0;
icr_entry.res_3 = 0;
icr_entry.vector = vector;
icr_entry.deliver_mode = deliver_mode;
icr_entry.dest_shorthand = dest_shorthand;
// x2APIC下ICR寄存器地址为0x830
// xAPIC下则为0xfee00300(31-0) 0xfee00310 (63-32)
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED) // x2APIC
{
icr_entry.destination.x2apic_destination = destination;
wrmsr(0x830, *(unsigned long *)&icr_entry); // 发送ipi
}
else // xAPIC
{
icr_entry.destination.apic_destination.dest_field = destination & 0xff;
icr_entry.destination.apic_destination.res_4 = 0;
// 先向高32bit写数据然后再向低32bit写数据不能调转
*(uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + 0x310) = (uint32_t)(((*(ul *)&icr_entry) >> 32) & 0xffffffff);
*(uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + 0x300) = (uint32_t)((*(ul *)&icr_entry) & 0xffffffff);
}
}
int ipi_regiserIPI(uint64_t irq_num, void *arg,
void (*handler)(uint64_t irq_num, uint64_t param, struct pt_regs *regs),
uint64_t param, hardware_intr_controller *controller, char *irq_name)
{
irq_desc_t *p = &SMP_IPI_desc[irq_num - 200];
p->controller = NULL; // 由于ipi不涉及到具体的硬件操作因此不需要controller
p->irq_name = irq_name;
p->parameter = param;
p->flags = 0;
p->handler = handler;
return 0;
}

View File

@ -0,0 +1,45 @@
/**
* @file ipi.h
* @author fslongjin(longjin@RinGoTek.cn)
* @brief 多核通信驱动
* @version 0.1
* @date 2022-04-07
*
* @copyright Copyright (c) 2022
*
*/
#pragma once
#include <common/kprint.h>
#include <driver/interrupt/apic/apic.h>
/**
* @brief 发送ipi消息
*
* @param dest_mode 目标模式
* @param deliver_status 投递模式
* @param level 信号驱动电平
* @param trigger 触发模式
* @param vector 中断向量
* @param deliver_mode 投递模式
* @param dest_shorthand 投递目标速记值
* @param destination 投递目标
*/
void ipi_send_IPI(uint32_t dest_mode, uint32_t deliver_status, uint32_t level, uint32_t trigger,
uint32_t vector, uint32_t deliver_mode, uint32_t dest_shorthand, uint32_t destination);
/**
* @brief ipi中断处理注册函数
*
* @param irq_num 中断向量号
* @param arg 参数
* @param handler 处理函数
* @param param 参数
* @param controller 当前为NULL
* @param irq_name ipi中断名
* @return int 成功0
*/
int ipi_regiserIPI(uint64_t irq_num, void *arg,
void (*handler)(uint64_t irq_num, uint64_t param, struct pt_regs *regs),
uint64_t param, hardware_intr_controller *controller, char *irq_name);

View File

@ -0,0 +1,14 @@
CFLAGS += -I .
kernel_common_subdirs:= math
ECHO:
@echo "$@"
$(kernel_common_subdirs): ECHO
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)"
all: $(kernel_common_subdirs)

28
kernel/src/common/asm.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#ifndef __ASM__
#define __ASM__
// 符号名
#define SYMBOL_NAME(X) X
// 符号名字符串
#define SYMBOL_NAME_STR(X) #X
// 符号名label
#define SYMBOL_NAME_LABEL(X) X##:
#define L1_CACHE_BYTES 32
#define asmlinkage __attribute__((regparm(0)))
#define ____cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES)))
#define ENTRY(name) \
.global SYMBOL_NAME(name); \
SYMBOL_NAME_LABEL(name)
#endif

View File

@ -0,0 +1,99 @@
/**
* @file atomic.h
* @author fslongjin (longjin@RinGoTek.cn)
* @brief 原子变量
* @version 0.1
* @date 2022-04-12
*
* @copyright Copyright (c) 2022
*
*/
#pragma once
#define atomic_read(atomic) ((atomic)->value) // 读取原子变量
#define atomic_set(atomic,val) (((atomic)->value) = (val)) // 设置原子变量的初始值
typedef struct
{
volatile long value;
} atomic_t;
/**
* @brief 原子变量增加值
*
* @param ato 原子变量对象
* @param val 要增加的值
*/
inline void atomic_add(atomic_t *ato, long val)
{
asm volatile("lock addq %1, %0 \n\t"
: "=m"(ato->value)
: "m"(val)
: "memory");
}
/**
* @brief 原子变量减少值
*
* @param ato 原子变量对象
* @param val 要减少的值
*/
inline void atomic_sub(atomic_t *ato, long val)
{
asm volatile("lock subq %1, %0 \n\t"
: "=m"(ato->value)
: "m"(val)
: "memory");
}
/**
* @brief 原子变量自增
*
* @param ato 原子变量对象
*/
void atomic_inc(atomic_t *ato)
{
asm volatile("lock incq %0 \n\t"
: "=m"(ato->value)
: "m"(ato->value)
: "memory");
}
/**
* @brief 原子变量自减
*
* @param ato 原子变量对象
*/
void atomic_dec(atomic_t *ato)
{
asm volatile("lock decq %0 \n\t"
: "=m"(ato->value)
: "m"(ato->value)
: "memory");
}
/**
* @brief 设置原子变量的mask
*
* @param ato 原子变量对象
*/
inline void atomic_set_mask(atomic_t *ato, long mask)
{
__asm__ __volatile__("lock orq %1, %0 \n\t"
: "=m"(ato->value)
: "r"(mask)
: "memory");
}
/**
* @brief 清除原子变量的mask
*
* @param ato 原子变量对象
*/
inline void atomic_clear_mask(atomic_t *ato, long mask)
{
__asm__ __volatile__("lock andq %1, %0 \n\t"
: "=m"(ato->value)
: "r"(mask)
: "memory");
}

View File

@ -0,0 +1,79 @@
#pragma once
#include <common/glib.h>
struct bt_node_t
{
struct bt_node_t *left;
struct bt_node_t *right;
struct bt_node_t *parent;
void *value; // 数据
} __attribute__((aligned(sizeof(long))));
struct bt_root_t
{
struct bt_node_t *bt_node;
int32_t size; // 树中的元素个数
int (*cmp)(void *a, void *b); // 比较函数 a>b 返回1 a==b返回0, a<b返回-1
/**
* @brief 释放结点的value的函数
* @param value 结点的值
*/
int (*release)(void *value);
};
/**
* @brief 创建二叉搜索树
*
* @param node 根节点
* @param cmp 比较函数
* @param release 用来释放结点的value的函数
* @return struct bt_root_t* 树根结构体
*/
struct bt_root_t *bt_create_tree(struct bt_node_t *node, int (*cmp)(void *a, void *b), int (*release)(void *value));
/**
* @brief 创建结点
*
* @param left 左子节点
* @param right 右子节点
* @param value 当前节点的值
* @return struct bt_node_t*
*/
struct bt_node_t *bt_create_node(struct bt_node_t *left, struct bt_node_t *right, struct bt_node_t *parent, void *value);
/**
* @brief 插入结点
*
* @param root 树根结点
* @param value 待插入结点的值
* @return int 返回码
*/
int bt_insert(struct bt_root_t *root, void *value);
/**
* @brief 搜索值为value的结点
*
* @param root 树根结点
* @param value 值
* @param ret_addr 返回的结点基地址
* @return int 错误码
*/
int bt_query(struct bt_root_t *root, void *value, uint64_t *ret_addr);
/**
* @brief 删除结点
*
* @param root 树根
* @param value 待删除结点的值
* @return int 返回码
*/
int bt_delete(struct bt_root_t *root, void *value);
/**
* @brief 释放整个二叉搜索树
*
* @param root
* @return int
*/
int bt_destroy_tree(struct bt_root_t *root);

View File

@ -0,0 +1,94 @@
#pragma once
#include <common/glib.h>
#include "stdint.h"
#include <common/semaphore.h>
#include <common/mutex.h>
#define BLK_TYPE_AHCI 0
#define DISK_NAME_LEN 32 // 磁盘名称的最大长度
struct blk_gendisk;
struct block_device_operation
{
long (*open)();
long (*close)();
long (*ioctl)(long cmd, long arg);
/**
* @brief 块设备驱动程序的传输函数
*
* @param gd 磁盘设备结构体
* @param cmd 控制命令
* @param base_addr 48位LBA地址
* @param count total sectors to read
* @param buf 缓冲区线性地址
* @return long
*/
long (*transfer)(struct blk_gendisk *gd, long cmd, uint64_t base_addr, uint64_t count, uint64_t buf);
};
/**
* @brief 块设备请求队列内的packet
*
*/
struct block_device_request_packet
{
uchar cmd;
uint64_t LBA_start;
uint32_t count;
uint64_t buffer_vaddr;
uint8_t device_type; // 0: ahci
void (*end_handler)(ul num, ul arg);
wait_queue_node_t wait_queue;
};
/**
* @brief 块设备的请求队列
*
*/
struct block_device_request_queue
{
wait_queue_node_t wait_queue_list;
struct block_device_request_packet *in_service; // 正在请求的结点
ul request_count;
};
/**
* @brief 块设备结构体(对应磁盘的一个分区)
*
*/
struct block_device
{
sector_t bd_start_sector; // 该分区的起始扇区
uint64_t bd_start_LBA; // 起始LBA号
sector_t bd_sectors_num; // 该分区的扇区数
struct vfs_superblock_t *bd_superblock; // 执行超级块的指针
struct blk_gendisk *bd_disk; // 当前分区所属的磁盘
struct block_device_request_queue *bd_queue; // 请求队列
uint16_t bd_partno; // 在磁盘上的分区号
};
// 定义blk_gendisk中的标志位
#define BLK_GF_AHCI (1 << 0)
/**
* @brief 磁盘设备结构体
*
*/
struct blk_gendisk
{
char disk_name[DISK_NAME_LEN]; // 磁盘驱动器名称
uint16_t part_cnt; // 磁盘分区计数
uint16_t flags;
struct block_device *partition; // 磁盘分区数组
const struct block_device_operation *fops; // 磁盘操作
struct block_device_request_queue *request_queue; // 磁盘请求队列
void *private_data;
mutex_t open_mutex; // open()/close()操作的互斥锁
};

10
kernel/src/common/block.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#include "blk_types.h"
/**
* @brief 将磁盘注册到块设备框架中
*
* @param gendisk 磁盘结构体
* @return int 错误码
*/
int blk_register_gendisk(struct blk_gendisk * gendisk);

View File

@ -0,0 +1,23 @@
/**
* @file boot_info.h
* @brief 启动信息接口
*/
#pragma once
#include "glib.h"
/**
* @brief 启动信息接口
* 由引导传递的机器信息处理
* 如 grub2 传递的 multiboot2 结构
* 注意这部分是通过内存传递的,在重新保存之前不能被覆盖
* 架构专有的数据在 dtb.h 或 multiboot2.h
* 实现在 dtb.cpp 或 multiboot2.cpp
*/
/// 声明,定义在具体的实现中
/// 地址
extern uintptr_t boot_info_addr;
/// 长度
extern unsigned int boot_info_size;

View File

@ -0,0 +1,145 @@
#pragma once
#include <common/compiler_attributes.h>
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#ifndef barrier
// 内存屏障
#define barrier() __asm__ __volatile__("" :: \
: "memory");
#endif
/**
* @brief 编译时断言如果condition不为1则输出msg
*
* @param prefix 一个“不存在的函数名”的前缀
* @param suffix 一个“不存在的函数名”的后缀
*/
#define __compiletime_assert(condition, msg, prefix, suffix) \
do \
{ \
/** \
* 声明一个不存在的函数的extern如果assert失败就调用它从而导致 \
* 链接时出错,进而达到“编译时断言”的功能。 \
*/ \
__noreturn extern void prefix##suffix(void) \
__compiletime_error(msg); \
if (!(condition)) \
prefix##suffix(); \
} while (0)
/**
* @brief 当condition是false时中断编译并输出指定的错误信息
*
* @param condition assert的情况
* @param msg condition为false时输出的错误信息
*/
#define complietime_assert(condition, msg) \
__compiletime_assert(condition, msg, __compiletime_assert__, __COUNTER__)
/**
* @brief 从src读取数据到dst该过程避免编译器优化。
*
* @param dst 目标地址指针
* @param src 源地址指针
* @param size 要读取的数据大小建议1、2、4、8字节若不满足要求则采用memcpy读取。
*/
static __always_inline void __read_once_size(void *dst, const volatile void *src, int size)
{
switch (size)
{
case 1:
*(__u8_alias_t *)dst = *(volatile __u8_alias_t *)src;
break;
case 2:
*(__u16_alias_t *)dst = *(volatile __u16_alias_t *)src;
break;
case 4:
*(__u32_alias_t *)dst = *(volatile __u32_alias_t *)src;
break;
case 8:
*(__u64_alias_t *)dst = *(volatile __u64_alias_t *)src;
break;
default:
barrier();
__builtin_memcpy((void *)dst, (const void *)src, size);
barrier();
break;
}
}
/**
* @brief 把src处的数据到dst该过程避免编译器优化。
*
* @param dst 目标地址指针
* @param src 源地址指针
* @param size 要写入的数据大小建议1、2、4、8字节若不满足要求则采用memcpy传输。
*/
static __always_inline void __write_once_size(volatile void *dst, void *src, int size)
{
switch (size)
{
case 1:
*(volatile __u8_alias_t *)dst = *(__u8_alias_t *)src;
break;
case 2:
*(volatile __u16_alias_t *)dst = *(__u16_alias_t *)src;
break;
case 4:
*(volatile __u32_alias_t *)dst = *(__u32_alias_t *)src;
break;
case 8:
*(volatile __u64_alias_t *)dst = *(__u64_alias_t *)src;
break;
default:
barrier();
__builtin_memcpy((void *)dst, (const void *)src, size);
barrier();
break;
}
}
/**
* 这两个宏能够避免编译器重排序、合并涉及到的读写操作,从而避免由于编译器优化导致的多线程读写顺序错误。
* 通过将有顺序要求的两个读/写操作放置在READ_ONCE()和WRITE_ONCE()之中,能够让编译器知道这些操作具有顺序要求。
*
* 这两个宏同样适用于Union或struct。如果要访问的数据大小不是1、2、4、8字节则会使用memcpy来处理。
*
* 这两个宏的主要使用场景:
* 1.两个进程或者中断处理函数之间的信息交流与沟通
* 2.确保编译器不会折叠、旋转或以其他方式对代码进行优化,从而破坏数据访问顺序。
*
* 这两个宏的union __u内的__c用作这个union的地址的指针
*
* 关于READ_ONCE和WRITE_ONCE的简单说明请转到https://bbs.dragonos.org/forum.php?mod=viewthread&tid=24
*/
/**
* @brief 读取变量x (避免编译器优化)
*/
#define READ_ONCE(x) \
({ \
union \
{ \
typeof(x) __val; \
char __c[1]; \
} __u = {.__c = {0}}; \
__read_once_size(__u.__c, &(x), sizeof(x)); \
__u.__val; \
})
/**
* @brief 将val写入变量x (避免编译器优化)
*/
#define WRITE_ONCE(x, val) \
({ \
union \
{ \
typeof(x) __val; \
char __c[1]; \
} __u = {.val = (val)}; \
__write_once_size(&(x), __u.__c, sizeof(x)); \
__u.__val; \
})

View File

@ -0,0 +1,23 @@
#pragma once
#include <common/stddef.h>
// 当函数的返回值未被使用时,编译器抛出警告信息
#define __must_check __attribute__((__warn_unused_result__))
#define __force __attribute__((force))
// 无返回值的属性
#define __noreturn __attribute__((__noreturn__))
/*
* Optional: only supported since clang >= 14.0
*
* gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-error-function-attribute
*/
#if __has_attribute(__error__)
#define __compiletime_error(msg) __attribute__((__error__(msg)))
#else
#define __compiletime_error(msg)
#endif
typedef uint8_t __attribute__((__may_alias__)) __u8_alias_t;
typedef uint16_t __attribute__((__may_alias__)) __u16_alias_t;
typedef uint32_t __attribute__((__may_alias__)) __u32_alias_t;
typedef uint64_t __attribute__((__may_alias__)) __u64_alias_t;

View File

@ -0,0 +1,47 @@
#include <common/spinlock.h>
#include <common/wait_queue_head.h>
#include <process/process.h>
#include <time/sleep.h>
#include <time/timer.h>
// 永久地设置该completion已经被完成,不会再有进程等待
#define COMPLETE_ALL UINT32_MAX
struct completion
{
unsigned int done;
wait_queue_head_t wait_queue;
};
#define DECLARE_COMPLETION_ON_STACK(name) \
struct completion name = {0}; \
completion_init(&name);
/**
* 对外函数声明
*/
void completion_init(struct completion *x);
void complete(struct completion *x);
void complete_all(struct completion *x);
void wait_for_completion(struct completion *x);
long wait_for_completion_timeout(struct completion *x, long timeout);
void wait_for_completion_interruptible(struct completion *x);
long wait_for_completion_interruptible_timeout(struct completion *x, long timeout);
void wait_for_multicompletion(struct completion x[], int n);
bool try_wait_for_completion(struct completion *x);
bool completion_done(struct completion *x);
/**
* 测试函数声明 (测试代码辅助函数)
*/
struct __test_data
{
int id;
struct completion *one_to_one;
struct completion *one_to_many;
struct completion *many_to_one;
};
int __test_completion_waiter(void *data); // 等待者
int __test_completion_worker(void *data); // 执行者
void __test_completion();

69
kernel/src/common/cpu.h Normal file
View File

@ -0,0 +1,69 @@
#pragma once
#include "glib.h"
#define MAX_CPU_NUM 32 // 操作系统支持的最大处理器数量
// cpu支持的最大cpuid指令的基础主功能号
extern uint32_t Cpu_cpuid_max_Basic_mop;
// cpu支持的最大cpuid指令的扩展主功能号
extern uint32_t Cpu_cpuid_max_Extended_mop;
// cpu制造商信息
extern char Cpu_Manufacturer_Name[17];
// 处理器名称信息
extern char Cpu_BrandName[49];
// 处理器家族ID
extern uint32_t Cpu_Family_ID;
// 处理器扩展家族ID
extern uint32_t Cpu_Extended_Family_ID;
// 处理器模式ID
extern uint32_t Cpu_Model_ID;
// 处理器扩展模式ID
extern uint32_t Cpu_Extended_Model_ID;
// 处理器步进ID
extern uint32_t Cpu_Stepping_ID;
// 处理器类型
extern uint32_t Cpu_Processor_Type;
// 处理器支持的最大物理地址可寻址地址线宽度
extern uint32_t Cpu_max_phys_addrline_size;
// 处理器支持的最大线性地址可寻址地址线宽度
extern uint32_t Cpu_max_linear_addrline_size;
// 处理器的tsc频率单位hz(HPET定时器在测定apic频率时顺便测定了这个值)
extern uint64_t Cpu_tsc_freq;
/**
* @brief 执行cpuid指令
*
* @param mop 主功能号
* @param sop 子功能号
* @param eax 结果的eax值
* @param ebx 结果的ebx值
* @param ecx 结果的ecx值
* @param edx 结果的edx值
*
* cpuid指令参考英特尔开发手册卷2A Chapter3 3.2 Instruction
*/
void cpu_cpuid(uint32_t mop, uint32_t sop, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
/**
* @brief 初始化获取处理器信息模块
*
*/
void cpu_init(void);
struct cpu_core_info_t
{
uint64_t stack_start; // 栈基地址
uint64_t ist_stack_start; // IST栈基地址
uint64_t tss_vaddr; // tss地址
};
extern struct cpu_core_info_t cpu_core_info[MAX_CPU_NUM];
/**
* @brief 获取当前cpu核心晶振频率
*
* @return uint32_t 当前cpu核心晶振频率
*/
uint32_t cpu_get_core_crysral_freq();

12
kernel/src/common/crc16.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <common/sys/types.h>
/**
* @brief 计算crc16
*
* @param crc crc初始值
* @param buffer 输入缓冲区
* @param len buffer大小bytes
* @return uint16_t crc
*/
uint16_t crc16(uint16_t crc, const uint8_t *buffer, size_t len);

12
kernel/src/common/crc32.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <common/sys/types.h>
/**
* @brief 计算crc32
*
* @param crc crc初始值
* @param buffer 输入缓冲区
* @param len buffer大小bytes
* @return uint32_t crc
*/
uint32_t crc32(uint32_t crc, const uint8_t *buffer, size_t len);

12
kernel/src/common/crc64.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <common/sys/types.h>
/**
* @brief 计算crc64
*
* @param crc crc初始值
* @param buffer 输入缓冲区
* @param len buffer大小bytes
* @return uint64_t crc
*/
uint64_t crc64(uint64_t crc, const uint8_t *buffer, size_t len);

12
kernel/src/common/crc7.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <common/sys/types.h>
/**
* @brief 计算crc7
*
* @param crc crc初始值
* @param buffer 输入缓冲区
* @param len buffer大小bytes
* @return uint8_t crc
*/
uint8_t crc7(uint8_t crc, const uint8_t *buffer, size_t len);

12
kernel/src/common/crc8.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <common/sys/types.h>
/**
* @brief 计算crc8
*
* @param crc crc初始值
* @param buffer 输入缓冲区
* @param len buffer大小bytes
* @return uint8_t crc
*/
uint8_t crc8(uint8_t crc, const uint8_t *buffer, size_t len);

View File

@ -0,0 +1,11 @@
#pragma once
#include <common/sys/types.h>
struct dirent
{
ino_t d_ino; // 文件序列号
off_t d_off; // dir偏移量
unsigned short d_reclen; // 目录下的记录数
unsigned char d_type; // entry的类型
char d_name[]; // 文件entry的名字是一个零长度的数组
};

367
kernel/src/common/elf.h Normal file
View File

@ -0,0 +1,367 @@
#pragma once
#include <common/glib.h>
// --> begin ==============EHDR=====================
// Reference: https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-43405.html#scrolltoc
// ====== ELF32 Header中的数据类型定义 ====
typedef uint32_t Elf32_Addr;
typedef uint16_t Elf32_Half;
typedef uint32_t Elf32_Off;
typedef uint32_t Elf32_SWord;
typedef uint32_t Elf32_Word;
// ====== ELF64 Header中的数据类型定义 ====
typedef uint64_t Elf64_Addr;
typedef uint16_t Elf64_Half;
typedef uint64_t Elf64_Off;
typedef uint32_t Elf64_Sword;
typedef uint32_t Elf64_Word;
typedef uint64_t Elf64_Xword;
typedef uint64_t Elf64_Sxword;
// ====== ELF Identification Index ======
// Purpose: File identification
#define EI_MAG0 0
#define EI_MAG1 1
#define EI_MAG2 2
#define EI_MAG3 3
// Purpose: File class
#define EI_CLASS 4
// Purpose: Data encoding
#define EI_DATA 5
// Purpose: File version
#define EI_VERSION 6 // e_ident[EI_VERSION]指定了ELF header的版本号 当前这个值必须是EV_CURRENT
// Purpose: Operating system/ABI identification
#define EI_OSABI 7 // e_ident[EI_OSABI]指定了操作系统以及对象所对应的ABI
// Purpose: ABI version
#define EI_ABIVERSION 8 // e_ident[EI_ABIVERSION] 指定了对象所对应的ABI版本.
// Purpose: Start of padding bytes
#define EI_PAD 9 // 这个值标志了e_ident中未使用字节的的起始下标
// Purpose: Size of e_ident[]
#define EI_NIDENT 16
// EI_MAG0 - EI_MAG3 这是一个4byte的 magic number
#define ELFMAG0 0x7f
#define ELFMAG1 'E'
#define ELFMAG2 'L'
#define ELFMAG3 'F'
// EI_CLASS e_ident[EI_CLASS]指明了文件的类型或capacity
#define ELFCLASSNONE 0 // Invalid class
#define ELFCLASS32 1 // 32bit objects
#define ELFCLASS64 2 // 64bit objects
// EI_DATA e_ident[EI_DATA]指明了与处理器相关的数据的编码方式
#define ELFDATANONE 0
#define ELFDATA2LSB 1 // 小端对齐
#define ELFDATA2MSB 2 // 大端对齐
// ELF e_type的类型定义
#define ET_NONE 0 // No file type
#define ET_REL 1 // Relocatable file
#define ET_EXEC 2 // Executable file
#define ET_DYN 3 // Shared object file
#define ET_CORE 4 // Core file
#define ET_LOPROC 0xff00 // Processor-specific
#define ET_HIPROC 0xffff // Processor-specific
// e_machine的类型定义
#define EM_NONE 0 // No machine
#define EM_SPARC 2 // SPARC
#define EM_386 3 // Intel 80386
#define EM_SPARC32PLUS 18 // Sun SPARC 32+
#define EM_SPARCV9 43 // SPARC V9
#define EM_AMD64 62 // AMD 64
// e_version的类型定义
#define EV_NONE 0 // Invalid Version
// EV_CURRENT: Value>=1 means current version
// e_flags 定义
// e_flags for SPARC
#define EF_SPARC_EXT_MASK 0xffff00 // Vendor Extension mask
#define EF_SPARC_32PLUS 0x000100 // Generic V8+ features
#define EF_SPARC_SUN_US1 0x000200 // Sun UltraSPARC 1 Extensions
#define EF_SPARC_HAL_R1 0x000400 // HAL R1 Extensions
#define EF_SPARC_SUN_US3 0x000800 // Sun UltraSPARC 3 Extensions
#define EF_SPARCV9_MM 0x3 // Mask for Memory Model
#define EF_SPARCV9_TSO 0x0 // Total Store Ordering
#define EF_SPARCV9_PSO 0x1 // Partial Store Ordering
#define EF_SPARCV9_RMO 0x2 // Relaxed Memory Ordering
#define PN_XNUM 0xffff
typedef struct
{
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} Elf32_Ehdr;
typedef struct
{
unsigned char e_ident[EI_NIDENT]; // 标志字节,这些字节与机器架构类型无关。目的是为了告诉我们如何解析这个文件的内容
Elf64_Half e_type; // 文件类型标志符
Elf64_Half e_machine; // 该文件依赖的处理器架构类型
Elf64_Word e_version; // 对象文件的版本
Elf64_Addr e_entry; // 进程的虚拟地址入点使用字节偏移量表示。如果没有entry point则该值为0
Elf64_Off e_phoff; // The program header table's file offset in bytes. 若没有则为0
Elf64_Off e_shoff; // The section header table's file offset in bytes. 若没有则为0
Elf64_Word e_flags; // 与处理器相关联的flags。格式为 EF_machine_flag 如果是x86架构那么该值为0
Elf64_Half e_ehsize; // ELF Header的大小单位字节
Elf64_Half e_phentsize; // 程序的program header table中的一个entry的大小所有的entry大小相同
Elf64_Half e_phnum; // program header table的entry数量
// e_phentsize*e_phnum=program header table的大小
// 如果没有program header table该值为0
// 如果entry num>=PN_XNUM(0xffff), 那么该值为0xffff且真实的pht的entry数量存储在section header的sh_info中index=0
// 其他情况下第一个section header entry的sh_info的值为0
Elf64_Half e_shentsize; // 每个section header的大小字节
// 每个section header是section header table的一个entry
Elf64_Half e_shnum; // section header table的entry数量
// e_shentsize*e_shnum=section header table的大小
// 如果没有section header table那么该值为0
// 如果section的数量>=SHN_LORESERVE(0xff00)那么该值为0且真实的section数量存储在
// section header at index 0的sh_size变量中否则第一个sh_size为0
Elf64_Half e_shstrndx; // 与section name string表相关联的section header table的entry的索引下标
// 如果没有name string table,那么该值等于SHN_UNDEF
// 如果对应的index>=SHN_LORESERVE(0xff00) 那么该变量值为SHN_XINDEX(0xffff)
// 且真正的section name string table的index被存放在section header的index=0处的sh_link变量中
// 否则初始section header entry的sh_link变量为0
} Elf64_Ehdr;
// --> end ==============EHDR=====================
// --> begin ==============SHDR=====================
// reference: https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-94076.html#scrolltoc
// ===== ELF Special Section Indexes =====
#define SHN_UNDEF 0 // An undefined, missing, irrelevant, or otherwise meaningless section reference.
#define SHN_LORESERVE 0xff00 // The lower boundary of the range of reserved indexes.
// The system reserves indexes between SHN_LORESERVE and SHN_HIRESERVE, inclusive.
#define SHN_LOPROC 0xff00 // SHN_LOPROC - SHN_HIPROC 这个范围以内的数据为处理器特定的语义所保留
#define SHN_BEFORE 0xff00 // SHN_BEFORE, SHN_AFTER 与SHF_LINK_ORDER及SHF_ORDERED section flags一起提供初始和终止section的
#define SHN_AFTER 0xff01
#define SHN_AMD64_LCOMMON 0xff02 // x64 specific common block label. This label is similar to SHN_COMMON, but provides for identifying a large common block.
#define SHN_HIPROC 0xff1f
#define SHN_LOOS 0xff20 // SHN_LOOS - SHN_HIOS 这个范围你的数为操作系统特定的语义所保留
#define SHN_LOSUNW 0xff3f // SHN_LOSUNW - SHN_HISUNW Values in this inclusive range are reserved for Sun-specific semantics.
#define SHN_SUNW_IGNORE 0xff3f // This section index provides a temporary symbol definition within relocatable objects. Reserved for internal use by dtrace(1M).
#define SHN_HISUNW 0xff3f
#define SHN_HIOS 0xff3f
#define SHN_ABS 0xfff1 // 对应的引用的绝对值。 举个例子symbols defined relative to section number SHN_ABS have absolute values and are not affected by relocation.
#define SHN_COMMON 0xfff2 // Symbols defined relative to this section are common symbols
#define SHN_XINDEX 0xffff
#define SHN_HIRESERVE 0xffff // The upper boundary of the range of reserved indexes.
/*
Note -
Although index 0 is reserved as the undefined value,
the section header table contains an entry for index 0.
That is, if the e_shnum member of the ELF header indicates
a file has 6 entries in the section header table, the sections
have the indexes 0 through 5. The contents of the initial entry
are specified later in this section.
*/
typedef struct
{
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} Elf32_Shdr;
typedef struct
{
Elf64_Word sh_name; // 段名
Elf64_Word sh_type; // 段的类型(按照内容和语义来分类)
Elf64_Xword sh_flags;
Elf64_Addr sh_addr; // 该section在进程的内存空间中的基地址。如果该段不需要出现在内存中该值为0
Elf64_Off sh_offset; // The byte offset from the beginning of the file to the first byte in the section
// 对于一个 SHT_NOBITS section这个变量指的是概念上的偏移量。因为这种段并不是真正存在于文件中
Elf64_Xword sh_size; // The section's size in bytes(如果是SHT_NOBITS类型的sectionsection不会在文件中真正占用sh_size的空间)
Elf64_Word sh_link; // A section header table index link, whose interpretation depends on the section type.
Elf64_Word sh_info; // 依赖于section type来解析的额外的信息。如果sh_flags有SHF_INFO_LINK属性那么这个变量代表一个section header table index.
Elf64_Xword sh_addralign; // 地址按照多少bytes对齐。只允许使用2的n次幂的值。如果值为0或1则意味着地址没有对齐要求。
Elf64_Xword sh_entsize; // 如果某个段拥有指定size的entry则在这里指定否则为0
} Elf64_Shdr;
// ELF Section Types, sh_type
#define SHT_NULL 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2 // Identifies a symbol table
#define SHT_STRTAB 3 // Identifies a string table.
#define SHT_RELA 4
#define SHT_HASH 5
#define SHT_DYNAMIC 6
#define SHT_NOTE 7
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_SHLIB 10
#define SHT_DYNSYM 11 // Identifies a symbol table
#define SHT_INIT_ARRAY 14
#define SHT_FINI_ARRAY 15
#define SHT_PREINIT_ARRAY 16
#define SHT_GROUP 17
#define SHT_SYMTAB_SHNDX 18
#define SHT_LOOS 0x60000000
#define SHT_LOSUNW 0x6fffffef
#define SHT_SUNW_capchain 0x6fffffef
#define SHT_SUNW_capinfo 0x6ffffff0
#define SHT_SUNW_symsort 0x6ffffff1
#define SHT_SUNW_tlssort 0x6ffffff2
#define SHT_SUNW_LDYNSYM 0x6ffffff3 // Identifies a symbol table
#define SHT_SUNW_dof 0x6ffffff4
#define SHT_SUNW_cap 0x6ffffff5
#define SHT_SUNW_SIGNATURE 0x6ffffff6
#define SHT_SUNW_ANNOTATE 0x6ffffff7
#define SHT_SUNW_DEBUGSTR 0x6ffffff8
#define SHT_SUNW_DEBUG 0x6ffffff9
#define SHT_SUNW_move 0x6ffffffa
#define SHT_SUNW_COMDAT 0x6ffffffb
#define SHT_SUNW_syminfo 0x6ffffffc
#define SHT_SUNW_verdef 0x6ffffffd
#define SHT_SUNW_verneed 0x6ffffffe
#define SHT_SUNW_versym 0x6fffffff
#define SHT_HISUNW 0x6fffffff
#define SHT_HIOS 0x6fffffff
#define SHT_LOPROC 0x70000000
#define SHT_SPARC_GOTDATA 0x70000000
#define SHT_AMD64_UNWIND 0x70000001
#define SHT_HIPROC 0x7fffffff
#define SHT_LOUSER 0x80000000
#define SHT_HIUSER 0xffffffff
// ELF Section Attribute Flags
#define SHF_WRITE 0x1 // Identifies a section that should be writable during process execution
#define SHF_ALLOC 0x2 // Identifies a section that occupies memory during process execution
#define SHF_EXECINSTR 0x4 // contains executable machine instructions
#define SHF_MERGE 0x10
#define SHF_STRINGS 0x20
#define SHF_INFO_LINK 0x40 // This section headers sh_info field holds a section header table index
#define SHF_LINK_ORDER 0x80 // This section adds special ordering requirements to the link-editor
#define SHF_OS_NONCONFORMING 0x100
#define SHF_GROUP 0x200
#define SHF_TLS 0x400
#define SHF_MASKOS 0x0ff00000
#define SHF_AMD64_LARGE 0x10000000 // identifies a section that can hold more than 2 Gbyte
#define SHF_ORDERED 0x40000000
#define SHF_EXCLUDE 0x80000000
#define SHF_MASKPROC 0xf0000000
// --> end ==============SHDR=====================
// --> begin ========== symbol table section ======
typedef struct
{
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
} Elf32_Sym;
typedef struct
{
Elf64_Word st_name;
unsigned char st_info;
unsigned char st_other;
Elf64_Half st_shndx;
Elf64_Addr st_value;
Elf64_Xword st_size;
} Elf64_Sym;
// --> end ========== symbol table section ======
// --> begin ========== program header =========
// Ref: https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-83432.html#scrolltoc
typedef struct
{
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} Elf32_Phdr;
typedef struct
{
Elf64_Word p_type;
Elf64_Word p_flags;
Elf64_Off p_offset;
Elf64_Addr p_vaddr;
Elf64_Addr p_paddr;
Elf64_Xword p_filesz;
Elf64_Xword p_memsz;
Elf64_Xword p_align;
} Elf64_Phdr;
// ELF segment types
#define PT_NULL 0
#define PT_LOAD 1 // Specifies a loadable segment
#define PT_DYNAMIC 2 // Specifies dynamic linking information.
#define PT_INTERP 3 // Specifies the location and size of a null-terminated path name to invoke as an interpreter
#define PT_NOTE 4 // Specifies the location and size of auxiliary information
#define PT_SHLIB 5
#define PT_PHDR 6 // Specifies the location and size of the program header table
#define PT_TLS 7 // Specifies a thread-local storage template
/*
PT_LOOS - PT_HIOS
Values in this inclusive range are reserved for OS-specific semantics.
*/
#define PT_LOOS 0x60000000
#define PT_SUNW_UNWIND 0x6464e550
#define PT_SUNW_EH_FRAME 0x6474e550
#define PT_LOSUNW 0x6ffffffa
#define PT_SUNWBSS 0x6ffffffa
#define PT_SUNWSTACK 0x6ffffffb
#define PT_SUNWDTRACE 0x6ffffffc
#define PT_SUNWCAP 0x6ffffffd
#define PT_HISUNW 0x6fffffff
#define PT_HIOS 0x6fffffff
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7fffffff
// ELF Segment Flags
#define PF_X 0x1 // Execute
#define PF_W 0x2 // Write
#define PF_R 0x4 // Read
#define PF_MASKPROC 0xf0000000 // Unspecified
// --> end ========== program header =========
/**
* @brief 校验是否为ELF文件
*
* @param ehdr
*/
bool elf_check(void * ehdr);

46
kernel/src/common/err.h Normal file
View File

@ -0,0 +1,46 @@
#pragma once
#include <common/compiler.h>
#include <stdint.h>
#define MAX_ERRNO 4095
#define IS_ERR_VALUE(x) unlikely((x) >= (uint64_t)-MAX_ERRNO)
/**
* @brief 判断返回的指针是否为errno
*
* @param ptr 待校验的指针
* @return long 1 => 是错误码
* 0 => 不是错误码
*/
static inline long __must_check IS_ERR(const void* ptr)
{
return IS_ERR_VALUE((uint64_t)ptr);
}
/**
* @brief 判断返回的指针是否为errno或者为空
*
* @param ptr 待校验的指针
* @return long 1 => 是错误码或NULL
* 0 => 不是错误码或NULL
*/
static inline long __must_check IS_ERR_OR_NULL(const void* ptr)
{
return !ptr || IS_ERR_VALUE((uint64_t)ptr);
}
/**
* @brief 将错误码转换为指针
*
* @param error 错误码
* @return void* 转换后的指针
*/
static inline void* __must_check ERR_PTR(long error)
{
return (void*)(error);
}
static inline long __must_check PTR_ERR(void * ptr)
{
return (long)ptr;
}

101
kernel/src/common/errno.h Normal file
View File

@ -0,0 +1,101 @@
/**
* @file errno.h
* @author fslongjin (longjin@RinGoTek.cn)
* @brief
* @version 0.1
* @date 2022-04-22
*
* @copyright Copyright (c) 2022
*
*/
#pragma once
#define E2BIG 1 /* 参数列表过长或者在输出buffer中缺少空间 或者参数比系统内建的最大值要大 Argument list too long. */
#define EACCES 2 /* 访问被拒绝 Permission denied */
#define EADDRINUSE 3 /* 地址正在被使用 Address in use.*/
#define EADDRNOTAVAIL 4 /* 地址不可用 Address not available.*/
#define EAFNOSUPPORT 5 /* 地址family不支持 Address family not supported. */
#define EAGAIN 6 /* 资源不可用,请重试。 Resource unavailable, try again (may be the same value as [EWOULDBLOCK]).*/
#define EALREADY 7 /* 连接已经在处理 Connection already in progress. */
#define EBADF 8 /* 错误的文件描述符 Bad file descriptor. */
#define EBADMSG 9 /* 错误的消息 Bad message. */
#define EBUSY 10 /* 设备或资源忙 Device or resource busy. */
#define ECANCELED 11 /* 操作被取消 Operation canceled. */
#define ECHILD 12 /* 没有子进程 No child processes. */
#define ECONNABORTED 13 /* 连接已断开 Connection aborted. */
#define ECONNREFUSED 14 /* 连接被拒绝 Connection refused. */
#define ECONNRESET 15 /* 连接被重置 Connection reset. */
#define EDEADLK 16 /* 资源死锁将要发生 Resource deadlock would occur. */
#define EDESTADDRREQ 17 /* 需要目标地址 Destination address required.*/
#define EDOM 18 /* 数学参数超出作用域 Mathematics argument out of domain of function. */
#define EDQUOT 19 /* 保留使用 Reserved */
#define EEXIST 20 /* 文件已存在 File exists. */
#define EFAULT 21 /* 错误的地址 Bad address */
#define EFBIG 22 /* 文件太大 File too large. */
#define EHOSTUNREACH 23 /* 主机不可达 Host is unreachable.*/
#define EIDRM 24 /* 标志符被移除 Identifier removed. */
#define EILSEQ 25 /* 不合法的字符序列 Illegal byte sequence. */
#define EINPROGRESS 26 /* 操作正在处理 Operation in progress. */
#define EINTR 27 /* 被中断的函数 Interrupted function. */
#define EINVAL 28 /* 不可用的参数 Invalid argument. */
#define EIO 29 /* I/O错误 I/O error. */
#define EISCONN 30 /* 套接字已连接 Socket is connected. */
#define EISDIR 31 /* 是一个目录 Is a directory */
#define ELOOP 32 /* 符号链接级别过多 Too many levels of symbolic links. */
#define EMFILE 33 /* 文件描述符的值过大 File descriptor value too large. */
#define EMLINK 34 /* 链接数过多 Too many links. */
#define EMSGSIZE 35 /* 消息过大 Message too large. */
#define EMULTIHOP 36 /* 保留使用 Reserved. */
#define ENAMETOOLONG 37 /* 文件名过长 Filename too long. */
#define ENETDOWN 38 /* 网络已关闭 Network is down. */
#define ENETRESET 39 /* 网络连接已断开 Connection aborted by network. */
#define ENETUNREACH 40 /* 网络不可达 Network unreachable. */
#define ENFILE 41 /* 系统中打开的文件过多 Too many files open in system.*/
#define ENOBUFS 42 /* 缓冲区空间不足 No buffer space available. */
#define ENODATA 43 /* 队列头没有可读取的消息 No message is available on the STREAM head read queue. */
#define ENODEV 44 /* 没有指定的设备 No such device. */
#define ENOENT 45 /* 没有指定的文件或目录 No such file or directory. */
#define ENOEXEC 46 /* 可执行文件格式错误 Executable file format error. */
#define ENOLCK 47 /* 没有可用的锁 No locks available. */
#define ENOLINK 48 /* 保留 Reserved. */
#define ENOMEM 49 /* 没有足够的空间 Not enough space. */
#define ENOMSG 50 /* 没有期待类型的消息 No message of the desired type. */
#define ENOPROTOOPT 51 /* 协议不可用 Protocol not available. */
#define ENOSPC 52 /* 设备上没有空间 No space left on device. */
#define ENOSR 53 /* 没有STREAM资源 No STREAM resources.*/
#define ENOSTR 54 /* 不是STREAM Not a STREAM */
#define ENOSYS 55 /* 功能不支持 Function not supported. */
#define ENOTCONN 56 /* 套接字未连接 The socket is not connected. */
#define ENOTDIR 57 /* 不是目录 Not a directory. */
#define ENOTEMPTY 58 /* 目录非空 Directory not empty. */
#define ENOTRECOVERABLE 59 /* 状态不可覆盖 State not recoverable. */
#define ENOTSOCK 60 /* 不是一个套接字 Not a socket.*/
#define ENOTSUP 61 /* 不被支持 Not supported (may be the same value as [EOPNOTSUPP]). */
#define ENOTTY 62 /* 不正确的I/O控制操作 Inappropriate I/O control operation. */
#define ENXIO 63 /* 没有这样的设备或地址 No such device or address. */
#define EOPNOTSUPP 64 /* 套接字不支持该操作 Operation not supported on socket (may be the same value as [ENOTSUP]). */
#define EOVERFLOW 65 /* 数值过大,产生溢出 Value too large to be stored in data type. */
#define EOWNERDEAD 66 /* 之前的拥有者挂了 Previous owner died. */
#define EPERM 67 /* 操作不被允许 Operation not permitted. */
#define EPIPE 68 /* 断开的管道 Broken pipe. */
#define EPROTO 69 /* 协议错误 Protocol error. */
#define EPROTONOSUPPORT 70 /* 协议不被支持 Protocol not supported. */
#define EPROTOTYPE 71 /* 对于套接字而言,错误的协议 Protocol wrong type for socket. */
#define ERANGE 72 /* 结果过大 Result too large. */
#define EROFS 73 /* 只读的文件系统 Read-only file system. */
#define ESPIPE 74 /* 错误的寻道 Invalid seek. */
#define ESRCH 75 /* 没有这样的进程 No such process. */
#define ESTALE 76 /* 保留 Reserved. */
#define ETIME 77 /* 流式ioctl()超时 Stream ioctl() timeout */
#define ETIMEDOUT 78 /* 连接超时 Connection timed out.*/
#define ETXTBSY 79 /* 文本文件忙 Text file busy. */
#define EWOULDBLOCK 80 /* 操作将被禁止 Operation would block (may be the same value as [EAGAIN]). */
#define EXDEV 81 /* 跨设备连接 Cross-device link. */

55
kernel/src/common/fcntl.h Normal file
View File

@ -0,0 +1,55 @@
/**
* @file fcntl.h
* @author fslongjin (longjin@RinGoTek.cn)
* @brief
* @version 0.1
* @date 2022-04-26
*
* @copyright Copyright (c) 2022
*
*/
#pragma once
#define O_RDONLY 00000000 // Open Read-only
#define O_WRONLY 00000001 // Open Write-only
#define O_RDWR 00000002 // Open read/write
#define O_ACCMODE 00000003 // Mask for file access modes
#define O_CREAT 00000100 // Create file if it does not exist
#define O_EXCL 00000200 // Fail if file already exists
#define O_NOCTTY 00000400 // Do not assign controlling terminal
#define O_TRUNC 00001000 // 文件存在且是普通文件并以O_RDWR或O_WRONLY打开则它会被清空
#define O_APPEND 00002000 // 文件指针会被移动到文件末尾
#define O_NONBLOCK 00004000 // 非阻塞式IO模式
#define O_EXEC 00010000 // 以仅执行的方式打开(非目录文件)
#define O_SEARCH 00020000 // Open the directory for search only
#define O_DIRECTORY 00040000 // 打开的必须是一个目录
#define O_NOFOLLOW 00100000 // Do not follow symbolic links
/*
* The constants AT_REMOVEDIR and AT_EACCESS have the same value. AT_EACCESS is
* meaningful only to faccessat, while AT_REMOVEDIR is meaningful only to
* unlinkat. The two functions do completely different things and therefore,
* the flags can be allowed to overlap. For example, passing AT_REMOVEDIR to
* faccessat would be undefined behavior and thus treating it equivalent to
* AT_EACCESS is valid undefined behavior.
*/
// 作为当前工作目录的文件描述符用于指代cwd
#define AT_FDCWD -100
#define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */
#define AT_EACCESS 0x200 /* Test access permitted for effective IDs, not real IDs. */
#define AT_REMOVEDIR 0x200 /* Remove directory instead of unlinking file. */
#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */
#define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */
#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */
#define AT_STATX_SYNC_TYPE 0x6000 /* Type of synchronisation required from statx() */
#define AT_STATX_SYNC_AS_STAT 0x0000 /* - Do whatever stat() does */
#define AT_STATX_FORCE_SYNC 0x2000 /* - Force the attributes to be sync'd with the server */
#define AT_STATX_DONT_SYNC 0x4000 /* - Don't sync attributes with the server */
#define AT_RECURSIVE 0x8000 /* Apply to the entire subtree */

316
kernel/src/common/font.h Normal file
View File

@ -0,0 +1,316 @@
#pragma once
unsigned char font_ascii[256][16]=
{
/* 0000 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 0010 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 0020 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 0030 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x10,0x10,0x00,0x00}, //33 '!'
{0x28,0x28,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '"'
{0x00,0x44,0x44,0x44,0xfe,0x44,0x44,0x44,0x44,0x44,0xfe,0x44,0x44,0x44,0x00,0x00}, // '#'
{0x10,0x3a,0x56,0x92,0x92,0x90,0x50,0x38,0x14,0x12,0x92,0x92,0xd4,0xb8,0x10,0x10}, // '$'
{0x62,0x92,0x94,0x94,0x68,0x08,0x10,0x10,0x20,0x2c,0x52,0x52,0x92,0x8c,0x00,0x00}, // '%'
{0x00,0x70,0x88,0x88,0x88,0x90,0x60,0x47,0xa2,0x92,0x8a,0x84,0x46,0x39,0x00,0x00}, // '&'
{0x04,0x08,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '''
/* 0040 */
{0x02,0x04,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x08,0x08,0x04,0x02,0x00}, // '('
{0x80,0x40,0x20,0x20,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x20,0x20,0x40,0x80,0x00}, // ')'
{0x00,0x00,0x00,0x00,0x00,0x10,0x92,0x54,0x38,0x54,0x92,0x10,0x00,0x00,0x00,0x00}, // '*'
{0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0xfe,0x10,0x10,0x10,0x00,0x00,0x00,0x00}, // '+'
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x08,0x08,0x10}, // ','
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '-'
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00}, // '.'
{0x02,0x02,0x04,0x04,0x08,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x40,0x80,0x80}, // '/'
{0x00,0x18,0x24,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x24,0x18,0x00,0x00}, //48 '0'
{0x00,0x08,0x18,0x28,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3e,0x00,0x00}, // '1'
/* 0050 */
{0x00,0x18,0x24,0x42,0x42,0x02,0x04,0x08,0x10,0x20,0x20,0x40,0x40,0x7e,0x00,0x00}, // '2'
{0x00,0x18,0x24,0x42,0x02,0x02,0x04,0x18,0x04,0x02,0x02,0x42,0x24,0x18,0x00,0x00}, // '3'
{0x00,0x0c,0x0c,0x0c,0x14,0x14,0x14,0x24,0x24,0x44,0x7e,0x04,0x04,0x1e,0x00,0x00}, // '4'
{0x00,0x7c,0x40,0x40,0x40,0x58,0x64,0x02,0x02,0x02,0x02,0x42,0x24,0x18,0x00,0x00}, // '5'
{0x00,0x18,0x24,0x42,0x40,0x58,0x64,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00}, // '6'
{0x00,0x7e,0x42,0x42,0x04,0x04,0x08,0x08,0x08,0x10,0x10,0x10,0x10,0x38,0x00,0x00}, // '7'
{0x00,0x18,0x24,0x42,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x42,0x24,0x18,0x00,0x00}, // '8'
{0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x26,0x1a,0x02,0x42,0x24,0x18,0x00,0x00}, // '9'
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00}, //58 ':'
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x08,0x08,0x10}, // ';'
/* 0060 */
{0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x00}, // '<'
{0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0x00}, // '='
{0x00,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x00}, // '>'
{0x00,0x38,0x44,0x82,0x82,0x82,0x04,0x08,0x10,0x10,0x00,0x00,0x18,0x18,0x00,0x00}, // '?'
{0x00,0x38,0x44,0x82,0x9a,0xaa,0xaa,0xaa,0xaa,0xaa,0x9c,0x80,0x46,0x38,0x00,0x00}, // '@'
{0x00,0x18,0x18,0x18,0x18,0x24,0x24,0x24,0x24,0x7e,0x42,0x42,0x42,0xe7,0x00,0x00}, //65 'A'
{0x00,0xf0,0x48,0x44,0x44,0x44,0x48,0x78,0x44,0x42,0x42,0x42,0x44,0xf8,0x00,0x00}, // 'B'
{0x00,0x3a,0x46,0x42,0x82,0x80,0x80,0x80,0x80,0x80,0x82,0x42,0x44,0x38,0x00,0x00}, // 'C'
{0x00,0xf8,0x44,0x44,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x44,0x44,0xf8,0x00,0x00}, // 'D'
{0x00,0xfe,0x42,0x42,0x40,0x40,0x44,0x7c,0x44,0x40,0x40,0x42,0x42,0xfe,0x00,0x00}, // 'E'
/* 0070 */
{0x00,0xfe,0x42,0x42,0x40,0x40,0x44,0x7c,0x44,0x44,0x40,0x40,0x40,0xf0,0x00,0x00}, // 'F'
{0x00,0x3a,0x46,0x42,0x82,0x80,0x80,0x9e,0x82,0x82,0x82,0x42,0x46,0x38,0x00,0x00}, // 'G'
{0x00,0xe7,0x42,0x42,0x42,0x42,0x42,0x7e,0x42,0x42,0x42,0x42,0x42,0xe7,0x00,0x00}, // 'H'
{0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00}, // 'I'
{0x00,0x1f,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x84,0x48,0x30,0x00}, // 'J'
{0x00,0xe7,0x42,0x44,0x48,0x50,0x50,0x60,0x50,0x50,0x48,0x44,0x42,0xe7,0x00,0x00}, // 'K'
{0x00,0xf0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x42,0x42,0xfe,0x00,0x00}, // 'L'
{0x00,0xc3,0x42,0x66,0x66,0x66,0x5a,0x5a,0x5a,0x42,0x42,0x42,0x42,0xe7,0x00,0x00}, // 'M'
{0x00,0xc7,0x42,0x62,0x62,0x52,0x52,0x52,0x4a,0x4a,0x4a,0x46,0x46,0xe2,0x00,0x00}, // 'N'
{0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x44,0x38,0x00,0x00}, // 'O'
/* 0080 */
{0x00,0xf8,0x44,0x42,0x42,0x42,0x44,0x78,0x40,0x40,0x40,0x40,0x40,0xf0,0x00,0x00}, // 'P'
{0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x92,0x8a,0x44,0x3a,0x00,0x00}, // 'Q'
{0x00,0xfc,0x42,0x42,0x42,0x42,0x7c,0x44,0x42,0x42,0x42,0x42,0x42,0xe7,0x00,0x00}, // 'R'
{0x00,0x3a,0x46,0x82,0x82,0x80,0x40,0x38,0x04,0x02,0x82,0x82,0xc4,0xb8,0x00,0x00}, // 'S'
{0x00,0xfe,0x92,0x92,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00}, // 'T'
{0x00,0xe7,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x3c,0x00,0x00}, // 'U'
{0x00,0xe7,0x42,0x42,0x42,0x42,0x24,0x24,0x24,0x24,0x18,0x18,0x18,0x18,0x00,0x00}, // 'V'
{0x00,0xe7,0x42,0x42,0x42,0x5a,0x5a,0x5a,0x5a,0x24,0x24,0x24,0x24,0x24,0x00,0x00}, // 'W'
{0x00,0xe7,0x42,0x42,0x24,0x24,0x24,0x18,0x24,0x24,0x24,0x42,0x42,0xe7,0x00,0x00}, // 'X'
{0x00,0xee,0x44,0x44,0x44,0x28,0x28,0x28,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00}, // 'Y'
/* 0090 */
{0x00,0xfe,0x84,0x84,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x42,0x82,0xfe,0x00,0x00}, // 'Z'
{0x00,0x3e,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3e,0x00}, //91 '['
{0x80,0x80,0x40,0x40,0x20,0x20,0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x04,0x02,0x02}, // '\'
{0x00,0x7c,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x7c,0x00}, // ']'
{0x00,0x10,0x28,0x44,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '^'
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x00}, // '_'
{0x10,0x08,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '`'
{0x00,0x00,0x00,0x00,0x00,0x70,0x08,0x04,0x3c,0x44,0x84,0x84,0x8c,0x76,0x00,0x00}, //97 'a'
{0xc0,0x40,0x40,0x40,0x40,0x58,0x64,0x42,0x42,0x42,0x42,0x42,0x64,0x58,0x00,0x00}, // 'b'
{0x00,0x00,0x00,0x00,0x00,0x30,0x4c,0x84,0x84,0x80,0x80,0x82,0x44,0x38,0x00,0x00}, // 'c'
/* 0100 */
{0x0c,0x04,0x04,0x04,0x04,0x34,0x4c,0x84,0x84,0x84,0x84,0x84,0x4c,0x36,0x00,0x00}, // 'd'
{0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x82,0x82,0xfc,0x80,0x82,0x42,0x3c,0x00,0x00}, // 'e'
{0x0e,0x10,0x10,0x10,0x10,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00}, // 'f'
{0x00,0x00,0x00,0x00,0x00,0x36,0x4c,0x84,0x84,0x84,0x84,0x4c,0x34,0x04,0x04,0x38}, // 'g'
{0xc0,0x40,0x40,0x40,0x40,0x58,0x64,0x42,0x42,0x42,0x42,0x42,0x42,0xe3,0x00,0x00}, // 'h'
{0x00,0x10,0x10,0x00,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00}, // 'i'
{0x00,0x04,0x04,0x00,0x00,0x0c,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x08,0x30}, // 'j'
{0xc0,0x40,0x40,0x40,0x40,0x4e,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0xe6,0x00,0x00}, // 'k'
{0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00}, // 'l'
{0x00,0x00,0x00,0x00,0x00,0xf6,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0xdb,0x00,0x00}, // 'm'
/* 0110 */
{0x00,0x00,0x00,0x00,0x00,0xd8,0x64,0x42,0x42,0x42,0x42,0x42,0x42,0xe3,0x00,0x00}, // 'n'
{0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0x44,0x38,0x00,0x00}, // 'o'
{0x00,0x00,0x00,0x00,0xd8,0x64,0x42,0x42,0x42,0x42,0x42,0x64,0x58,0x40,0x40,0xe0}, // 'p'
{0x00,0x00,0x00,0x00,0x34,0x4c,0x84,0x84,0x84,0x84,0x84,0x4c,0x34,0x04,0x04,0x0e}, // 'q'
{0x00,0x00,0x00,0x00,0x00,0xdc,0x62,0x42,0x40,0x40,0x40,0x40,0x40,0xe0,0x00,0x00}, // 'r'
{0x00,0x00,0x00,0x00,0x00,0x7a,0x86,0x82,0xc0,0x38,0x06,0x82,0xc2,0xbc,0x00,0x00}, // 's'
{0x00,0x00,0x10,0x10,0x10,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x0e,0x00,0x00}, // 't'
{0x00,0x00,0x00,0x00,0x00,0xc6,0x42,0x42,0x42,0x42,0x42,0x42,0x46,0x3b,0x00,0x00}, // 'u'
{0x00,0x00,0x00,0x00,0x00,0xe7,0x42,0x42,0x42,0x24,0x24,0x24,0x18,0x18,0x00,0x00}, // 'v'
{0x00,0x00,0x00,0x00,0x00,0xe7,0x42,0x42,0x5a,0x5a,0x5a,0x24,0x24,0x24,0x00,0x00}, // 'w'
/* 0120 */
{0x00,0x00,0x00,0x00,0x00,0xc6,0x44,0x28,0x28,0x10,0x28,0x28,0x44,0xc6,0x00,0x00}, // 'x'
{0x00,0x00,0x00,0x00,0x00,0xe7,0x42,0x42,0x24,0x24,0x24,0x18,0x18,0x10,0x10,0x60}, // 'y'
{0x00,0x00,0x00,0x00,0x00,0xfe,0x82,0x84,0x08,0x10,0x20,0x42,0x82,0xfe,0x00,0x00}, // 'z'
{0x00,0x06,0x08,0x10,0x10,0x10,0x10,0x60,0x10,0x10,0x10,0x10,0x08,0x06,0x00,0x00}, // '{'
{0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10}, // '|'
{0x00,0x60,0x10,0x08,0x08,0x08,0x08,0x06,0x08,0x08,0x08,0x08,0x10,0x60,0x00,0x00}, // '}'
{0x00,0x72,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '~'
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 0130 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 0140 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 0150 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 0160 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 0170 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 0180 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 0190 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 0200 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 0210 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 0220 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 0230 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 0240 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 0250~0255 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
};

8
kernel/src/common/gfp.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
#include <common/sys/types.h>
#include <common/compiler.h>
/**
* __GFP_ZERO: 获取内存的同时,将获取到的这块内存清空
*
*/
#define __GFP_ZERO ((gfp_t)(1UL << 0))

347
kernel/src/common/glib.h Normal file
View File

@ -0,0 +1,347 @@
//
// 内核全局通用库
// Created by longjin on 2022/1/22.
//
#pragma once
//引入对bool类型的支持
#include <stdbool.h>
#include <stdint.h>
#include <common/stddef.h>
#include <arch/arch.h>
#include <common/compiler.h>
#include <common/list.h>
#if ARCH(I386) || ARCH(X86_64)
#include <arch/x86_64/asm/asm.h>
#else
#error Arch not supported.
#endif
/**
* @brief 根据结构体变量内某个成员变量member的基地址计算出该结构体变量的基地址
* @param ptr 指向结构体变量内的成员变量member的指针
* @param type 成员变量所在的结构体
* @param member 成员变量名
*
* 方法使用ptr减去结构体内的偏移得到结构体变量的基地址
*/
#define container_of(ptr, type, member) \
({ \
typeof(((type *)0)->member) *p = (ptr); \
(type *)((unsigned long)p - (unsigned long)&(((type *)0)->member)); \
})
// 定义类型的缩写
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ul;
typedef unsigned long long int ull;
typedef long long int ll;
#define ABS(x) ((x) > 0 ? (x) : -(x)) // 绝对值
// 最大最小值
#define max(x, y) ((x > y) ? (x) : (y))
#define min(x, y) ((x < y) ? (x) : (y))
// 遮罩高32bit
#define MASK_HIGH_32bit(x) (x & (0x00000000ffffffffUL))
// 四舍五入成整数
ul round(double x)
{
return (ul)(x + 0.5);
}
/**
* @brief 地址按照align进行对齐
*
* @param addr
* @param _align
* @return ul 对齐后的地址
*/
static __always_inline ul ALIGN(const ul addr, const ul _align)
{
return (ul)((addr + _align - 1) & (~(_align - 1)));
}
void *memset(void *dst, unsigned char C, ul size)
{
int d0, d1;
unsigned long tmp = C * 0x0101010101010101UL;
__asm__ __volatile__("cld \n\t"
"rep \n\t"
"stosq \n\t"
"testb $4, %b3 \n\t"
"je 1f \n\t"
"stosl \n\t"
"1:\ttestb $2, %b3 \n\t"
"je 2f\n\t"
"stosw \n\t"
"2:\ttestb $1, %b3 \n\t"
"je 3f \n\t"
"stosb \n\t"
"3: \n\t"
: "=&c"(d0), "=&D"(d1)
: "a"(tmp), "q"(size), "0"(size / 8), "1"(dst)
: "memory");
return dst;
}
void *memset_c(void *dst, uint8_t c, size_t count)
{
uint8_t *xs = (uint8_t *)dst;
while (count--)
*xs++ = c;
return dst;
}
/**
* @brief 内存拷贝函数
*
* @param dst 目标数组
* @param src 源数组
* @param Num 字节数
* @return void*
*/
static void *memcpy(void *dst, const void *src, long Num)
{
int d0 = 0, d1 = 0, d2 = 0;
__asm__ __volatile__("cld \n\t"
"rep \n\t"
"movsq \n\t"
"testb $4,%b4 \n\t"
"je 1f \n\t"
"movsl \n\t"
"1:\ttestb $2,%b4 \n\t"
"je 2f \n\t"
"movsw \n\t"
"2:\ttestb $1,%b4 \n\t"
"je 3f \n\t"
"movsb \n\t"
"3: \n\t"
: "=&c"(d0), "=&D"(d1), "=&S"(d2)
: "0"(Num / 8), "q"(Num), "1"(dst), "2"(src)
: "memory");
return dst;
}
// 从io口读入8个bit
unsigned char io_in8(unsigned short port)
{
unsigned char ret = 0;
__asm__ __volatile__("inb %%dx, %0 \n\t"
"mfence \n\t"
: "=a"(ret)
: "d"(port)
: "memory");
return ret;
}
// 从io口读入32个bit
unsigned int io_in32(unsigned short port)
{
unsigned int ret = 0;
__asm__ __volatile__("inl %%dx, %0 \n\t"
"mfence \n\t"
: "=a"(ret)
: "d"(port)
: "memory");
return ret;
}
// 输出8个bit到输出端口
void io_out8(unsigned short port, unsigned char value)
{
__asm__ __volatile__("outb %0, %%dx \n\t"
"mfence \n\t"
:
: "a"(value), "d"(port)
: "memory");
}
// 输出32个bit到输出端口
void io_out32(unsigned short port, unsigned int value)
{
__asm__ __volatile__("outl %0, %%dx \n\t"
"mfence \n\t"
:
: "a"(value), "d"(port)
: "memory");
}
/**
* @brief 从端口读入n个word到buffer
*
*/
#define io_insw(port, buffer, nr) \
__asm__ __volatile__("cld;rep;insw;mfence;" ::"d"(port), "D"(buffer), "c"(nr) \
: "memory")
/**
* @brief 从输出buffer中的n个word到端口
*
*/
#define io_outsw(port, buffer, nr) \
__asm__ __volatile__("cld;rep;outsw;mfence;" ::"d"(port), "S"(buffer), "c"(nr) \
: "memory")
/**
* @brief 验证地址空间是否为用户地址空间
*
* @param addr_start 地址起始值
* @param length 地址长度
* @return true
* @return false
*/
bool verify_area(uint64_t addr_start, uint64_t length)
{
if ((addr_start + length) <= 0x00007fffffffffffUL) // 用户程序可用的的地址空间应<= 0x00007fffffffffffUL
return true;
else
return false;
}
/**
* @brief 从用户空间搬运数据到内核空间
*
* @param dst 目的地址
* @param src 源地址
* @param size 搬运的大小
* @return uint64_t
*/
static inline uint64_t copy_from_user(void *dst, void *src, uint64_t size)
{
uint64_t tmp0, tmp1;
if (!verify_area((uint64_t)src, size))
return 0;
/**
* @brief 先每次搬运8 bytes剩余就直接一个个byte搬运
*
*/
asm volatile("rep \n\t"
"movsq \n\t"
"movq %3, %0 \n\t"
"rep \n\t"
"movsb \n\t"
: "=&c"(size), "=&D"(tmp0), "=&S"(tmp1)
: "r"(size & 7), "0"(size >> 3), "1"(dst), "2"(src)
: "memory");
return size;
}
/**
* @brief 从内核空间搬运数据到用户空间
*
* @param dst 目的地址
* @param src 源地址
* @param size 搬运的大小
* @return uint64_t
*/
static inline uint64_t copy_to_user(void *dst, void *src, uint64_t size)
{
uint64_t tmp0, tmp1;
if (verify_area((uint64_t)src, size))
return 0;
/**
* @brief 先每次搬运8 bytes剩余就直接一个个byte搬运
*
*/
asm volatile("rep \n\t"
"movsq \n\t"
"movq %3, %0 \n\t"
"rep \n\t"
"movsb \n\t"
: "=&c"(size), "=&D"(tmp0), "=&S"(tmp1)
: "r"(size & 7), "0"(size >> 3), "1"(dst), "2"(src)
: "memory");
return size;
}
/**
* @brief 这个函数让蜂鸣器发声,目前仅用于真机调试。未来将移除,请勿依赖此函数。
*
* @param times 发声循环多少遍
*/
void __experimental_beep(uint64_t times);
/**
* @brief 往指定地址写入8字节
* 防止由于编译器优化导致不支持的内存访问类型尤其是在mmio的时候
*
* @param vaddr 虚拟地址
* @param value 要写入的值
*/
static __always_inline void __write8b(uint64_t vaddr, uint64_t value)
{
asm volatile("movq %%rdx, 0(%%rax)" ::"a"(vaddr), "d"(value)
: "memory");
}
/**
* @brief 往指定地址写入4字节
* 防止由于编译器优化导致不支持的内存访问类型尤其是在mmio的时候
*
* @param vaddr 虚拟地址
* @param value 要写入的值
*/
static __always_inline void __write4b(uint64_t vaddr, uint32_t value)
{
asm volatile("movl %%edx, 0(%%rax)" ::"a"(vaddr), "d"(value)
: "memory");
}
/**
* @brief 从指定地址读取8字节
* 防止由于编译器优化导致不支持的内存访问类型尤其是在mmio的时候
*
* @param vaddr 虚拟地址
* @return uint64_t 读取到的值
*/
static __always_inline uint64_t __read8b(uint64_t vaddr)
{
uint64_t retval;
asm volatile("movq 0(%%rax), %0"
: "=r"(retval)
: "a"(vaddr)
: "memory");
return retval;
}
/**
* @brief 从指定地址读取4字节
* 防止由于编译器优化导致不支持的内存访问类型尤其是在mmio的时候
*
* @param vaddr 虚拟地址
* @return uint64_t 读取到的值
*/
static __always_inline uint32_t __read4b(uint64_t vaddr)
{
uint32_t retval;
asm volatile("movl 0(%%rax), %0"
: "=d"(retval)
: "a"(vaddr)
: "memory");
return retval;
}
/**
* @brief 将数据从src搬运到dst并能正确处理地址重叠的问题
*
* @param dst 目标地址指针
* @param src 源地址指针
* @param size 大小
* @return void* 指向目标地址的指针
*/
void *memmove(void *dst, const void *src, uint64_t size);

166
kernel/src/common/hid.h Normal file
View File

@ -0,0 +1,166 @@
#pragma once
#include <common/stddef.h>
#define __HID_USAGE_TABLE_SIZE 64 // usage stack的大小
#define HID_MAX_REPORT 300 // 最大允许的hid report数目包括feature、input、output
#define HID_MAX_PATH_SIZE 16 // maximum depth for path
// 这部分请参考hid_1_11.pdf Section 6.2.2.4
#define HID_ITEM_COLLECTION 0xA0
#define HID_ITEM_END_COLLECTION 0xC0
#define HID_ITEM_FEATURE 0xB0
#define HID_ITEM_INPUT 0x80
#define HID_ITEM_OUTPUT 0x90
/**
* @brief 枚举hid的usage page列表。
* 原始数据请见<HID Usage Tables FOR Universal Serial Bus (USB)>。
* 该文件可从usb.org下载
*/
enum HID_USAGE_PAGE_TYPES
{
HID_USAGE_PAGE_GEN_DESKTOP = 0x1,
HID_USAGE_PAGE_SIMU_CTRL, // simulation controls
HID_USAGE_PAGE_VR_CTRL, // vr controls page
HID_USAGE_PAGE_SPORT_CTRL, // sport controls
HID_USAGE_PAGE_GAME_CTRL, // game controls
HID_USAGE_PAGE_GEN_DEVICE_CTRL, // general device controls
HID_USAGE_PAGE_KBD_KPD, // keyboard/ keypad page
HID_USAGE_PAGE_LED, // LED
HID_USAGE_PAGE_BUTTON, // button page
HID_USAGE_PAGE_ORDINAL, // ordinal page
HID_USAGE_PAGE_TEL_DEVICE, // telephony device
HID_USAGE_PAGE_CONSUMER, // consumer page
HID_USAGE_PAGE_DIGITIZER, // digitizers page
HID_USAGE_PAGE_HAPTICS, // haptics page
HID_USAGE_PAGE_PHY_INPUT_DEVICE, // physical input device page
HID_USAGE_PAGE_UNICODE = 0x10, // unicode page
HID_USAGE_PAGE_EYE_HEAD_TRACKER = 0x12, // eye and head trackers page
HID_USAGE_PAGE_AUX_DISPLAY = 0x14, // auxiliary display page
HID_USAGE_PAGE_SENSORS = 0x20, // sensors page
HID_USAGE_PAGE_MEDICAL = 0x40, // medical instruments
HID_USAGE_PAGE_BRAILLE_DISPLAY, // barille display
HID_USAGE_PAGE_LIGHTNING_ILLU = 0x59, // lighting and illumination page
HID_USAGE_PAGE_MONITOR = 0x80, // monitor page
HID_USAGE_PAGE_MONITOR_ENUMERATED, // monitor enumerated page
HID_USAGE_PAGE_VESA_VIRT_CTRL, // VESA virtual controls page
HID_USAGE_PAGE_POWER = 0x84, // power page
HID_USAGE_PAGE_BATTERY_SYSTEM, // battery system page
HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c, // barcode scanner page
HID_USAGE_PAGE_SCALES, // scales page
HID_USAGE_PAGE_MAGNET_STRIPE_READER, // magnetic stript reader page
HID_USAGE_PAGE_CAMERA_CONTROL = 0x90, // camera control page
HID_USAGE_PAGE_ARCADE, // arcade page
HID_USAGE_PAGE_GAMING_DEVICE, // gaming device page
HID_USAGE_PAGE_FIDO_ALLIANCE = 0xf1d0, // FIDO alliance page
};
/**
* @brief usage type for HID_USAGE_PAGE_GEN_DESKTOP page
*
*/
enum USAGE_TYPE_GENDESK
{
HID_USAGE_GENDESK_UNDEF = 0, // undefined
HID_USAGE_GENDESK_POINTER,
HID_USAGE_GENDESK_MOUSE,
HID_USAGE_GENDESK_KEYBOARD = 0x6,
HID_USAGE_GENDESK_POINTER_X = 0x30,
HID_USAGE_GENDESK_POINTER_Y,
HID_USAGE_GENDESK_WHEEL = 0x38,
HID_USAGE_GENDESK_NOTHING = 0xff,
};
/**
* @brief 描述hid path中的一个节点
*
*/
struct hid_node_t
{
int u_page;
int usage;
};
/**
* @brief 描述一条hid path
*
*/
struct hid_path_t
{
int size; // 路径中的节点数目
struct hid_node_t node[HID_MAX_PATH_SIZE];
};
/**
* @brief Describe a HID Data with its location in report
*
*/
struct hid_data_t
{
int value; // hid对象的值
struct hid_path_t path; // hid path
int report_count; // count of reports for this usage type
int offset; // offset of data in report
int size; // size of data in bits
uint8_t report_id; // report id(from incoming report)
uint8_t type; // 数据类型FEATURE / INPUT / OUTPUT
uint8_t attribute; // report field attribute. (2 = (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position))
// (6 = (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position))
int8_t unit_exp; // unit exponent;
uint32_t unit; // HID unit
int logical_min; // Logical min
int logical_max; // Logical max
int phys_min; // Physical min
int phys_max; // Physical max
};
/**
* @brief hid解析器
*
*/
struct hid_parser
{
const uint8_t *report_desc; // 指向report descriptor的指针
int report_desc_size; // report descriptor的大小字节
int pos; // report_desc中当前正在处理的位置
uint8_t item; // 暂存当前的item
uint32_t value; // 暂存当前的值
struct hid_data_t data; // 存储当前的环境
int offset_table[HID_MAX_REPORT][3]; // 存储 hid report的ID、type、offset
int report_count; // hid report的数量
int count; // local items的计数
uint32_t u_page;
struct hid_node_t usage_table[__HID_USAGE_TABLE_SIZE]; // Usage stack
int usage_size; // usage的数量
int usage_min;
int usage_max;
int cnt_objects; // report descriptor中的对象数目
int cnt_report; // report desc中的report数目
};
struct hid_usage_types_string
{
int value;
const char *string;
};
struct hid_usage_pages_string
{
int value;
struct hid_usage_types_string *types;
const char *string;
};
int hid_parse_report(const void *report_data, const int len);
bool hid_parse_find_object(const void *hid_report, const int report_size, struct hid_data_t *data);

173
kernel/src/common/idr.h Normal file
View File

@ -0,0 +1,173 @@
#pragma GCC push_options
#pragma GCC optimize("O1")
#include <common/errno.h>
#include <common/spinlock.h>
#if ARCH(I386) || ARCH(X86_64)
#include <arch/x86_64/math/bitcount.h>
#else
#error Arch not supported.
#endif
/**
* idr: 基于radix-tree的ID-pointer的数据结构
* 主要功能:
* 1. 获取一个ID, 并且将该ID与一个指针绑定 - 需要外部加锁
* 2. 删除一个已分配的ID - 需要外部加锁
* 3. 根据ID查找对应的指针 (读操作,看情况加锁)
* 4. 根据ID使用新的ptr替换旧的ptr - 需要外部加锁
*
* 附加功能:
* 1. 给定starting_id, 查询下一个已分配的next_id (即:next_id>starting_id)
* 2. 销毁整个idr
*
*
* .... 待实现
*/
// 默认64位机器
#define IDR_BITS 6
#define IDR_FULL 0xfffffffffffffffful
// size = 64
#define IDR_SIZE (1 << IDR_BITS)
#define IDR_MASK ((1 << IDR_BITS) - 1)
// 能管理的ID范围[0:1<<31]
#define MAX_ID_SHIFT (sizeof(int) * 8 - 1)
#define MAX_ID_BIT (1U << MAX_ID_SHIFT)
#define MAX_ID_MASK (MAX_ID_BIT - 1)
// IDR可能最大的层次 以及 IDR预分配空间的最大限制
#define MAX_LEVEL ((MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS)
#define IDR_FREE_MAX (MAX_LEVEL << 1)
// 给定layer, 计算完全64叉树的大小
#define TREE_SIZE(layer) ((layer >= 0) ? (1ull << ((layer + 1) * IDR_BITS)) : 1)
// 计算最后(最低位)一个1的位置 (注意使用64位的版本)
#define __lowbit_id(x) ((x) ? (__ctzll(x)) : -1)
// 计算最前(最高位)一个1的位置 (注意使用64位的版本)
#define __mostbit_id(x) ((x) ? (63 - __clzll(x)) : -1)
// radix-tree 节点定义
struct idr_layer
{
struct idr_layer *ary[IDR_SIZE]; // IDR_SIZE叉树
unsigned long bitmap; // 每一位表示这个子树是否被使用
unsigned long full; // 64个儿子子树, 每一位代表一个子树是否满了
int layer; // 层数(从底向上)
};
// idr: 将id与pointer绑定的数据结构
struct idr
{
struct idr_layer *top;
struct idr_layer *free_list;
int id_free_cnt;
spinlock_t lock;
}__attribute__((aligned(8)));
#define DECLARE_IDR(name) \
struct idr name = {0}; \
idr_init(&(name));
#define DECLARE_IDR_LAYER(name) \
struct idr_layer name = {0}; \
memset(name, 0, sizeof(struct idr_layer));
/**
* 对外函数声明
**/
int idr_preload(struct idr *idp, gfp_t gfp_mask);
int idr_alloc(struct idr *idp, void *ptr, int *id);
void *idr_remove(struct idr *idp, int id);
void idr_remove_all(struct idr *idp);
void idr_destroy(struct idr *idp);
void *idr_find(struct idr *idp, int id);
void *idr_find_next(struct idr *idp, int start_id);
void *idr_find_next_getid(struct idr *idp, int64_t start_id, int *nextid);
int idr_replace_get_old(struct idr *idp, void *ptr, int id, void **oldptr);
int idr_replace(struct idr *idp, void *ptr, int id);
void idr_init(struct idr *idp);
bool idr_empty(struct idr *idp);
bool idr_count(struct idr *idp, int id);
/**
* 对外宏遍历idr两种方式
* 1. 从第一个元素开始遍历
* 2. 从某一个id开始遍历
*/
/**
* @brief 第一种遍历方式: 从第一个元素开始遍历
* @param idp idr指针
* @param id 遍历的id你不需要初始化这个id因为它每一次都是从最小已分配的id开始遍历
* @param ptr 数据指针(entry),你不需要初始化这个指针
*/
#define for_each_idr_entry(idp, id, ptr) \
for (id = -1, ptr = idr_find_next_getid(idp, id, &id); ptr != NULL || !idr_count(idp, id); ptr = idr_find_next_getid(idp, id, &id))
/**
* @brief 第二种遍历方式: 从某一个id开始遍历
* @param idp idr指针
* @param id 遍历的id你需要初始化这个id(请你设置为你要从哪一个id开始遍历遍历过程将会包括这个id)
* @param ptr 数据指针(entry),你不需要初始化这个指针
*/
#define for_each_idr_entry_continue(idp, id, ptr) \
for (ptr = idr_find_next_getid(idp, id - 1, &id); ptr != NULL || !idr_count(idp, id); ptr = idr_find_next_getid(idp, id, &id))
/**
* ida: 基于IDR实现的ID分配器
* 主要功能:
* 1. 获取一个未分配的ID
* 2. 询问一个ID是否被分配
* 3. 删除一个已分配ID
*
* 附加功能:
* 1. 暂定
*/
// 一个块的大小 - 即 sizeof(struct ida_bitmap)
#define IDA_CHUNK_SIZE 128
// ida_bitmap的长度
#define IDA_BITMAP_LONGS (IDA_CHUNK_SIZE / sizeof(long) - 1)
// 对应linux的IDA_BITMAP_BITS = 960 = 15 * 64
#define IDA_FULL (IDA_BITMAP_LONGS * sizeof(long) * 8)
#define IDA_BITMAP_BITS IDA_FULL
#define IDA_BMP_SIZE (8 * sizeof(long))
// 自定义bitmap
struct ida_bitmap
{
unsigned long count; // bitmap中已经分配的id数量
unsigned long bitmap[IDA_BITMAP_LONGS]; // bitmap本身, 每一个bit代表一个ID
};
// id-allocater 管理+分配ID的数据结构
struct ida
{
struct idr idr;
struct ida_bitmap *free_list; // 预分配的数据块
};
#define DECLARE_IDA(name) \
struct ida name = {0}; \
idr_init(&name.idr); \
name.free_list = (NULL);
/**
* 对外函数声明
*/
void ida_init(struct ida *ida_p);
bool ida_empty(struct ida *ida_p);
int ida_preload(struct ida *ida_p, gfp_t gfp_mask);
int ida_alloc(struct ida *ida_p, int *p_id);
bool ida_count(struct ida *ida_p, int id);
void ida_remove(struct ida *ida_p, int id);
void ida_destroy(struct ida *ida_p);
#pragma GCC pop_options

153
kernel/src/common/kfifo.h Normal file
View File

@ -0,0 +1,153 @@
#pragma once
#include <stdint.h>
#include <common/spinlock.h>
struct kfifo_t
{
uint32_t total_size; // 缓冲区总空间
uint32_t size; // 元素所占的字节数
uint32_t in_offset; // 入口偏移
uint32_t out_offset; // 出口偏移
void *buffer; // 缓冲区
} __attribute__((aligned(sizeof(long))));
/**
* @brief 忽略kfifo队列中的所有内容并把输入和输出偏移量都归零
*
*/
#define kfifo_reset(fifo) (void)({ \
(fifo)->size = 0; \
(fifo)->in_offset = 0; \
(fifo)->out_offset = 0; \
})
/**
* @brief 忽略kfifo队列中的所有内容并将输入偏移量赋值给输出偏移量
*
*/
#define kfifo_reset_out(fifo) (void)({ \
(fifo)->size = 0; \
(fifo)->out_offset = (fifo)->in_offset; \
})
/**
* @brief 获取kfifo缓冲区的最大大小
*
* @param fifo 队列结构体
* @return uint32_t 缓冲区最大大小
*/
#define kfifo_total_size(fifo) ((fifo)->total_size)
/**
* @brief 获取kfifo缓冲区当前已使用的大小
*
* @param fifo 队列结构体
* @return uint32_t 缓冲区当前已使用的大小
*/
#define kfifo_size(fifo) ((fifo)->size)
/**
* @brief 判断kfifo缓冲区当前是否为空
*
* @param fifo 队列结构体
* @return uint32_t 0->非空, 1->空
*/
#define kfifo_empty(fifo) (((fifo)->size == 0) ? 1 : 0)
/**
* @brief 判断kfifo缓冲区当前是否为满
*
* @param fifo 队列结构体
* @return uint32_t 0->不满, 1->满
*/
#define kfifo_full(fifo) (((fifo)->size == (fifo)->total_size) ? 1 : 0)
/**
* @brief 通过动态方式初始化kfifo缓冲队列
*
* @param fifo 队列结构体
* @param size 缓冲区大小
* @param reserved 暂时保留请置为0
* @return int 错误码:成功->0
*/
int kfifo_alloc(struct kfifo_t *fifo, uint32_t size, uint64_t reserved);
/**
* @brief 释放通过kfifo_alloc创建的fifo缓冲区
*
* @param fifo fifo队列结构体
*/
void kfifo_free_alloc(struct kfifo_t *fifo);
/**
* @brief 使用指定的缓冲区来初始化kfifo缓冲队列
*
* @param fifo 队列结构体
* @param buffer 缓冲区
* @param size 缓冲区大小
*/
void kfifo_init(struct kfifo_t *fifo, void *buffer, uint32_t size);
/**
* @brief 向kfifo缓冲区推入指定大小的数据
*
* @param fifo 队列结构体
* @param from 来源数据地址
* @param size 数据大小(字节数)
* @return uint32_t 推入的数据大小
*/
uint32_t kfifo_in(struct kfifo_t *fifo, const void *from, uint32_t size);
/**
* @brief 从kfifo缓冲区取出数据并从队列中删除数据
*
* @param fifo 队列结构体
* @param to 拷贝目标地址
* @param size 数据大小(字节数)
* @return uint32_t 取出的数据大小
*/
uint32_t kfifo_out(struct kfifo_t *fifo, void *to, uint32_t size);
/**
* @brief 从kfifo缓冲区取出数据但是不从队列中删除数据
*
* @param fifo 队列结构体
* @param to 拷贝目标地址
* @param size 数据大小(字节数)
* @return uint32_t 取出的数据大小
*/
uint32_t kfifo_out_peek(struct kfifo_t *fifo, void *to, uint32_t size);
/**
* @brief 向kfifo缓冲区推入指定大小的数据并在过程加锁
*
* @param fifo 队列结构体
* @param from 来源数据地址
* @param size 数据大小(字节数)
* @param lock 自旋锁
* @return uint32_t 推入的数据大小
*/
uint32_t __always_inline kfifo_in_locked(struct kfifo_t *fifo, const void *from, uint32_t size, spinlock_t *lock)
{
spin_lock(lock);
uint32_t retval = kfifo_in(fifo, from, size);
spin_unlock(lock);
return retval;
}
/**
* @brief 从kfifo缓冲区取出数据并从队列中删除数据并在过程加锁
*
* @param fifo 队列结构体
* @param to 拷贝目标地址
* @param size 数据大小(字节数)
* @param lock 自旋锁
* @return uint32_t 取出的数据大小
*/
uint32_t __always_inline kfifo_out_locked(struct kfifo_t *fifo, void *to, uint32_t size, spinlock_t *lock)
{
spin_lock(lock);
uint32_t retval = kfifo_out(fifo, to, size);
spin_unlock(lock);
return retval;
}

View File

@ -0,0 +1,78 @@
/**
* @file kprint.h
* @author longjin
* @brief 内核日志打印程序
* @date 2022-01-28
*
* @copyright Copyright (c) 2022 longjin
*
*/
#pragma once
#include "printk.h"
#define ksuccess(...) \
do \
{ \
printk("[ "); \
printk_color(GREEN, BLACK, "SUCCESS"); \
printk(" ] "); \
printk(__VA_ARGS__); \
printk("\n"); \
} while (0)
#define kinfo(...) \
do \
{ \
printk("[ INFO ] "); \
printk(__VA_ARGS__); \
printk("\n"); \
} while (0)
#define kdebug(...) \
do \
{ \
printk("[ DEBUG ] (%s:%d)\t", __FILE__, __LINE__); \
printk(__VA_ARGS__); \
printk("\n"); \
} while (0)
#define kwarn(...) \
do \
{ \
printk("[ "); \
printk_color(YELLOW, BLACK, "WARN"); \
printk(" ] "); \
printk(__VA_ARGS__); \
printk("\n"); \
} while (0)
#define kerror(...) \
do \
{ \
printk("[ "); \
printk_color(RED, BLACK, "ERROR"); \
printk(" ] "); \
printk(__VA_ARGS__); \
printk("\n"); \
} while (0)
#define kterminated(...) \
do \
{ \
printk("[ "); \
printk_color(RED, BLACK, "TERMINATED"); \
printk(" ] "); \
printk(__VA_ARGS__); \
printk("\n"); \
} while (0)
#define kBUG(...) \
do \
{ \
printk("[ "); \
printk_color(RED, BLACK, "BUG"); \
printk(" ] (%s:%d)\t", __FILE__, __LINE__); \
printk(__VA_ARGS__); \
printk("\n"); \
} while (0)

108
kernel/src/common/kthread.h Normal file
View File

@ -0,0 +1,108 @@
#pragma once
#include <common/numa.h>
#include <process/proc-types.h>
#include <common/err.h>
#include <process/process.h>
/**
* @brief kthread信息
* 该结构体将会绑定到pcb的worker_private中
*/
struct kthread_info_t
{
uint64_t flags;
uint32_t cpu;
int result;
int (*thread_fn)(void *);
void *data;
// todo: 将这里改为completion机制
bool exited; // 是否已退出
char *full_name; // 内核线程的名称
};
struct process_control_block *kthread_create_on_node(int (*thread_fn)(void *data),
void *data,
int node,
const char name_fmt[], ...);
/**
* @brief 在当前结点上创建一个内核线程
*
* @param thread_fn 该内核线程要执行的函数
* @param data 传递给 thread_fn 的参数数据
* @param name_fmt printf-style format string for the thread name
* @param arg name_fmt的参数
*
* 请注意,该宏会创建一个内核线程,并将其设置为停止状态
*/
#define kthread_create(thread_fn, data, name_fmt, arg...) \
kthread_create_on_node(thread_fn, data, NUMA_NO_NODE, name_fmt, ##arg)
/**
* @brief 创建内核线程,并将其唤醒
*
* @param thread_fn 该内核线程要执行的函数
* @param data 传递给 thread_fn 的参数数据
* @param name_fmt printf-style format string for the thread name
* @param arg name_fmt的参数
*/
#define kthread_run(thread_fn, data, name_fmt, ...) \
({ \
struct process_control_block *__kt = kthread_create(thread_fn, data, name_fmt, ##__VA_ARGS__); \
if (!IS_ERR(__kt)) \
process_wakeup(__kt); \
__kt; \
})
/**
* @brief 向kthread发送停止信号请求其结束
*
* @param pcb 内核线程的pcb
* @return int 错误码
*/
int kthread_stop(struct process_control_block * pcb);
/**
* @brief 内核线程调用该函数,检查自身的标志位,判断自己是否应该执行完任务后退出
*
* @return true 内核线程应该退出
* @return false 无需退出
*/
bool kthread_should_stop(void);
/**
* @brief 让当前内核线程退出并返回result参数给kthread_stop()函数
*
* @param result 返回值
*/
void kthread_exit(long result);
/**
* @brief 初始化kthread机制(只应被process_init调用)
*
* @return int 错误码
*/
int kthread_mechanism_init();
/**
* @brief 设置pcb中的worker_private字段只应被设置一次
*
* @param pcb pcb
* @return bool 成功或失败
*/
bool kthread_set_worker_private(struct process_control_block *pcb);
/**
* @brief 获取pcb中的kthread结构体
*
* @param pcb pcb
* @return struct kthread* kthread信息结构体
*/
struct kthread_info_t *to_kthread(struct process_control_block *pcb);
/**
* @brief 释放pcb指向的worker private
*
* @param pcb 要释放的pcb
*/
void free_kthread_struct(struct process_control_block *pcb);

357
kernel/src/common/list.h Normal file
View File

@ -0,0 +1,357 @@
#pragma once
#include <common/stddef.h>
#if ARCH(I386) || ARCH(X86_64)
#include <arch/x86_64/asm/asm.h>
#else
#error Arch not supported.
#endif
//链表数据结构
struct List
{
struct List *prev, *next;
};
//初始化循环链表
static inline void list_init(struct List *list)
{
list->next = list;
io_mfence();
list->prev = list;
}
/**
* @brief
* @param entry 给定的节点
* @param node 待插入的节点
**/
static inline void list_add(struct List *entry, struct List *node)
{
node->next = entry->next;
barrier();
node->prev = entry;
barrier();
node->next->prev = node;
barrier();
entry->next = node;
}
/**
* @brief 将node添加到给定的list的结尾(也就是当前节点的前面)
* @param entry 列表的入口
* @param node 待添加的节点
*/
static inline void list_append(struct List *entry, struct List *node)
{
struct List *tail = entry->prev;
list_add(tail, node);
}
/**
* @brief 从列表中删除节点
* @param entry 待删除的节点
*/
static inline void list_del(struct List *entry)
{
entry->next->prev = entry->prev;
entry->prev->next = entry->next;
}
/**
* @brief 删除链表的结点,并将这个结点重新初始化
*
*/
#define list_del_init(entry) \
list_del(entry); \
list_init(entry);
/**
* @brief 将新的链表结点替换掉旧的链表结点并使得旧的结点的前后指针均为NULL
*
* @param old 要被替换的结点
* @param new 新的要换上去的结点
*/
static inline void list_replace(struct List *old, struct List *new)
{
if (old->prev != NULL)
old->prev->next = new;
new->prev = old->prev;
if (old->next != NULL)
old->next->prev = new;
new->next = old->next;
old->prev = NULL;
old->next = NULL;
}
static inline bool list_empty(struct List *entry)
{
/**
* @brief 判断循环链表是否为空
* @param entry 入口
*/
if (entry == entry->next && entry->prev == entry)
return true;
else
return false;
}
/**
* @brief 获取链表的上一个元素
*
* @param entry
* @return 链表的上一个元素
*/
static inline struct List *list_prev(struct List *entry)
{
if (entry->prev != NULL)
return entry->prev;
else
return NULL;
}
/**
* @brief 获取链表的下一个元素
*
* @param entry
* @return 链表的下一个元素
*/
static inline struct List *list_next(struct List *entry)
{
if (entry->next != NULL)
return entry->next;
else
return NULL;
}
/**
* @brief 获取当前entry的链表结构体
*
* @param ptr 指向List结构体的指针
* @param type 包裹着List结构体的外层结构体的类型
* @param member List结构体在上述的“包裹list结构体的结构体”中的变量名
*/
#define list_entry(ptr, type, member) container_of(ptr, type, member)
/**
* @brief 获取链表中的第一个元素
* 请注意,该宏要求链表非空,否则会出错
*
* @param ptr 指向链表头的指针
* @param type 包裹着List结构体的外层结构体的类型
* @param member List结构体在上述的“包裹list结构体的结构体”中的变量名
*/
#define list_first_entry(ptr, type, member) list_entry((ptr)->next, type, member)
/**
* @brief 获取链表中的第一个元素
* 若链表为空则返回NULL
*
* @param ptr 指向链表头的指针
* @param type 包裹着List结构体的外层结构体的类型
* @param member List结构体在上述的“包裹list结构体的结构体”中的变量名
*/
#define list_first_entry_or_null(ptr, type, member) (!list_empty(ptr) ? list_entry((ptr)->next, type, member) : NULL)
/**
* @brief 获取链表中的最后一个元素
* 请注意,该宏要求链表非空,否则会出错
*
* @param ptr 指向链表头的指针
* @param type 包裹着List结构体的外层结构体的类型
* @param member List结构体在上述的“包裹list结构体的结构体”中的变量名
*/
#define list_last_entry(ptr, type, member) list_entry((ptr)->prev, type, member)
/**
* @brief 获取链表中的最后一个元素
* 若链表为空则返回NULL
*
* @param ptr 指向链表头的指针
* @param type 包裹着List结构体的外层结构体的类型
* @param member List结构体在上述的“包裹list结构体的结构体”中的变量名
*/
#define list_last_entry_or_full(ptr, type, member) (!list_empty(ptr) ? list_entry((ptr)->prev, type, member) : NULL)
/**
* @brief 获取链表中的下一个元素
*
* @param pos 指向当前的外层结构体的指针
* @param member 链表结构体在外层结构体内的变量名
*/
#define list_next_entry(pos, member) list_entry((pos)->member.next, typeof(*(pos)), member)
/**
* @brief 获取链表中的上一个元素
*
* @param pos 指向当前的外层结构体的指针
* @param member 链表结构体在外层结构体内的变量名
*/
#define list_prev_entry(pos, member) list_entry((pos)->member.prev, typeof(*(pos)), member)
/**
* @brief 遍历整个链表(从前往后)
*
* @param ptr the &struct list_head to use as a loop cursor.
* @param head the head for your list.
*/
#define list_for_each(ptr, head) \
for ((ptr) = (head)->next; (ptr) != (head); (ptr) = (ptr)->next)
/**
* @brief 遍历整个链表(从后往前)
*
* @param ptr the &struct list_head to use as a loop cursor.
* @param head the head for your list.
*/
#define list_for_each_prev(ptr, head) \
for ((ptr) = (head)->prev; (ptr) != (head); (ptr) = (ptr)->prev)
/**
* @brief 遍历整个链表(从前往后)(支持删除当前链表结点)
* 该宏通过暂存中间变量防止在迭代链表的过程中由于删除了当前ptr所指向的链表结点从而造成错误
*
* @param ptr the &struct list_head to use as a loop cursor.
* @param n 用于存储临时值的List类型的指针
* @param head the head for your list.
*/
#define list_for_each_safe(ptr, n, head) \
for ((ptr) = (head)->next, (n) = (ptr)->next; (ptr) != (head); (ptr) = n, n = (ptr)->next)
/**
* @brief 遍历整个链表(从前往后)(支持删除当前链表结点)
* 该宏通过暂存中间变量防止在迭代链表的过程中由于删除了当前ptr所指向的链表结点从而造成错误
*
* @param ptr the &struct list_head to use as a loop cursor.
* @param n 用于存储临时值的List类型的指针
* @param head the head for your list.
*/
#define list_for_each_prev_safe(ptr, n, head) \
for ((ptr) = (head)->prev, (n) = (ptr)->prev; (ptr) != (head); (ptr) = n, n = (ptr)->prev)
/**
* @brief 从头开始迭代给定类型的链表
*
* @param pos 指向特定类型的结构体的指针
* @param head 链表头
* @param member struct List在pos的结构体中的成员变量名
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member); \
&pos->member != (head); \
pos = list_next_entry(pos, member))
/**
* @brief 从头开始迭代给定类型的链表(支持删除当前链表结点)
*
* @param pos 指向特定类型的结构体的指针
* @param n 用于存储临时值的和pos相同类型的指针
* @param head 链表头
* @param member struct List在pos的结构体中的成员变量名
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member), n = list_next_entry(pos, member); \
&pos->member != (head); \
pos = n, n = list_next_entry(n, member))
/**
* @brief 逆序迭代给定类型的链表
*
* @param pos 指向特定类型的结构体的指针
* @param head 链表头
* @param member struct List在pos的结构体中的成员变量名
*/
#define list_for_each_entry_reverse(pos, head, member) \
for (pos = list_last_entry(head, typeof(*pos), member); \
&pos->member != (head); \
pos = list_prev_entry(pos, member))
/**
* @brief 为list_for_each_entry_continue()准备一个'pos'结构体
*
* @param pos 指向特定类型的结构体的,用作迭代起点的指针
* @param head 指向要开始迭代的struct List结构体的指针
* @param member struct List在pos的结构体中的成员变量名
*/
#define list_prepare_entry(pos, head, member) \
((pos) ? pos : list_entry(head, typeof(*pos), member))
/**
* @brief 从指定的位置的[下一个元素开始],继续迭代给定的链表
*
* @param pos 指向特定类型的结构体的指针。该指针用作迭代的指针。
* @param head 指向链表头的struct List的指针
* @param member struct List在pos指向的结构体中的成员变量名
*/
#define list_for_each_entry_continue(pos, head, member) \
for (pos = list_next_entry(pos, member); \
&pos->member != (head); \
pos = list_next_entry(pos, member))
/**
* @brief 从指定的位置的[下一个元素开始],继续迭代给定的链表。(支持删除当前链表结点)
*
* @param pos 指向特定类型的结构体的指针。该指针用作迭代的指针。
* @param n 用于存储临时值的和pos相同类型的指针
* @param head 指向链表头的struct List的指针
* @param member struct List在pos指向的结构体中的成员变量名
*/
#define list_for_each_entry_safe_continue(pos, n, head, member) \
for (pos = list_next_entry(pos, member), n = list_next_entry(pos, member); \
&pos->member != (head); \
pos = n, n = list_next_entry(n, member))
/**
* @brief 从指定的位置的[上一个元素开始],【逆序】迭代给定的链表
*
* @param pos 指向特定类型的结构体的指针。该指针用作迭代的指针。
* @param head 指向链表头的struct List的指针
* @param member struct List在pos指向的结构体中的成员变量名
*/
#define list_for_each_entry_continue_reverse(pos, head, member) \
for (pos = list_prev_entry(pos, member); \
&pos->member != (head); \
pos = list_prev_entry(pos, member))
/**
* @brief 从指定的位置的[上一个元素开始],【逆序】迭代给定的链表。(支持删除当前链表结点)
*
* @param pos 指向特定类型的结构体的指针。该指针用作迭代的指针。
* @param head 指向链表头的struct List的指针
* @param member struct List在pos指向的结构体中的成员变量名
*/
#define list_for_each_entry_safe_continue_reverse(pos, n, head, member) \
for (pos = list_prev_entry(pos, member), n = list_prev_entry(pos, member); \
&pos->member != (head); \
pos = n, n = list_prev_entry(n, member))
/**
* @brief 从指定的位置开始,继续迭代给定的链表
*
* @param pos 指向特定类型的结构体的指针。该指针用作迭代的指针。
* @param head 指向链表头的struct List的指针
* @param member struct List在pos指向的结构体中的成员变量名
*/
#define list_for_each_entry_from(pos, head, member) \
for (; \
&pos->member != (head); \
pos = list_next_entry(pos, member))
/**
* @brief 从指定的位置开始,继续迭代给定的链表.(支持删除当前链表结点)
*
* @param pos 指向特定类型的结构体的指针。该指针用作迭代的指针。
* @param n 用于存储临时值的和pos相同类型的指针
* @param head 指向链表头的struct List的指针
* @param member struct List在pos指向的结构体中的成员变量名
*/
#define list_for_each_entry_safe_from(pos, n, head, member) \
for (n = list_next_entry(pos, member); \
&pos->member != (head); \
pos = n, n = list_next_entry(n, member))

104
kernel/src/common/lockref.h Normal file
View File

@ -0,0 +1,104 @@
#pragma once
#include <common/sys/types.h>
#include <common/spinlock.h>
#if ARCH(X86_64)
// 仅在x64架构下启用cmpxchg
#define __LOCKREF_ENABLE_CMPXCHG__
#endif
struct lockref
{
union
{
#ifdef __LOCKREF_ENABLE_CMPXCHG__
aligned_u64 lock_count; // 通过该变量的声明使得整个lockref按照8字节对齐
#endif
struct
{
spinlock_t lock;
int count;
};
};
};
/**
* @brief 原子的将引用计数加1
*
* @param lock_ref 要被操作的lockref变量
*/
void lockref_inc(struct lockref *lock_ref);
/**
* @brief 原子地将引用计数加1.如果原来的count≤0则操作失败。
*
* @param lock_ref 指向要被操作的lockref变量的指针
* @return int 操作成功=>true
* 操作失败=>false
*/
bool lockref_inc_not_zero(struct lockref *lock_ref);
/**
* @brief 原子地减少引用计数。如果已处于count≤0的状态则返回-1
*
* 本函数与lockref_dec_return()的区别在于当在cmpxchg()中检测到count<=0或已加锁本函数会再次尝试通过加锁来执行操作
* 而后者会直接返回错误
*
* @param lock_ref 指向要被操作的lockref变量的指针
* @return int 操作成功 => 返回新的引用变量值
* lockref处于count≤0的状态 => 返回-1
*/
int lockref_dec(struct lockref *lock_ref);
/**
* @brief 原子地减少引用计数。如果处于已加锁或count≤0的状态则返回-1
*
* 本函数与lockref_dec()的区别在于当在cmpxchg()中检测到count<=0或已加锁本函数会直接返回错误
* 而后者会再次尝试通过加锁来执行操作
*
* @param lock_ref 指向要被操作的lockref变量的指针
* @return int 操作成功 => 返回新的引用变量值
* lockref处于已加锁或count≤0的状态 => 返回-1
*/
int lockref_dec_return(struct lockref *lock_ref);
/**
* @brief 原子地减少引用计数。若当前的引用计数≤1则操作失败
*
* 该函数与lockref_dec_or_lock_not_zero()的区别在于当cmpxchg()时发现old.count≤1时该函数会直接返回false.
* 而后者在这种情况下,会尝试加锁来进行操作。
*
* @param lock_ref 指向要被操作的lockref变量的指针
* @return true 成功将引用计数减1
* @return false 如果当前的引用计数≤1操作失败
*/
bool lockref_dec_not_zero(struct lockref *lock_ref);
/**
* @brief 原子地减少引用计数。若当前的引用计数≤1则操作失败
*
* 该函数与lockref_dec_not_zero()的区别在于当cmpxchg()时发现old.count≤1时该函数会尝试加锁来进行操作。
* 而后者在这种情况下会直接返回false.
*
* @param lock_ref 指向要被操作的lockref变量的指针
* @return true 成功将引用计数减1
* @return false 如果当前的引用计数≤1操作失败
*/
bool lockref_dec_or_lock_not_zero(struct lockref *lock_ref);
/**
* @brief 将lockref变量标记为已经死亡将count设置为负值
*
* @param lock_ref 指向要被操作的lockref变量的指针
*/
void lockref_mark_dead(struct lockref * lock_ref);
/**
* @brief 自增引用计数。除非该lockref已经死亡
*
* @param lock_ref 指向要被操作的lockref变量的指针
* @return true 操作成功
* @return false 操作失败lockref已死亡
*/
bool lockref_inc_not_dead(struct lockref *lock_ref);

771
kernel/src/common/lz4.h Normal file
View File

@ -0,0 +1,771 @@
/*
* LZ4 - Fast LZ compression algorithm
* Header File
* Copyright (C) 2011-present, Yann Collet.
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You can contact the author at :
- LZ4 homepage : http://www.lz4.org
- LZ4 source repository : https://github.com/lz4/lz4
*/
#if defined(__cplusplus)
extern "C"
{
#endif
#ifndef LZ4_H_2983827168210
#define LZ4_H_2983827168210
/* --- Dependency --- */
#include <common/stddef.h> /* size_t */
/**
Introduction
LZ4 is lossless compression algorithm, providing compression speed >500 MB/s per core,
scalable with multi-cores CPU. It features an extremely fast decoder, with speed in
multiple GB/s per core, typically reaching RAM speed limits on multi-core systems.
The LZ4 compression library provides in-memory compression and decompression functions.
It gives full buffer control to user.
Compression can be done in:
- a single step (described as Simple Functions)
- a single step, reusing a context (described in Advanced Functions)
- unbounded multiple steps (described as Streaming compression)
lz4.h generates and decodes LZ4-compressed blocks (doc/lz4_Block_format.md).
Decompressing such a compressed block requires additional metadata.
Exact metadata depends on exact decompression function.
For the typical case of LZ4_decompress_safe(),
metadata includes block's compressed size, and maximum bound of decompressed size.
Each application is free to encode and pass such metadata in whichever way it wants.
lz4.h only handle blocks, it can not generate Frames.
Blocks are different from Frames (doc/lz4_Frame_format.md).
Frames bundle both blocks and metadata in a specified manner.
Embedding metadata is required for compressed data to be self-contained and portable.
Frame format is delivered through a companion API, declared in lz4frame.h.
The `lz4` CLI can only manage frames.
*/
/*^***************************************************************
* Export parameters
*****************************************************************/
/*
* LZ4_DLL_EXPORT :
* Enable exporting of functions when building a Windows DLL
* LZ4LIB_VISIBILITY :
* Control library symbols visibility.
*/
#ifndef LZ4LIB_VISIBILITY
#if defined(__GNUC__) && (__GNUC__ >= 4)
#define LZ4LIB_VISIBILITY __attribute__((visibility("default")))
#else
#define LZ4LIB_VISIBILITY
#endif
#endif
#if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT == 1)
#define LZ4LIB_API __declspec(dllexport) LZ4LIB_VISIBILITY
#elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT == 1)
#define LZ4LIB_API __declspec(dllimport) LZ4LIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
#else
#define LZ4LIB_API LZ4LIB_VISIBILITY
#endif
/*------ Version ------*/
#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
#define LZ4_VERSION_MINOR 9 /* for new (non-breaking) interface capabilities */
#define LZ4_VERSION_RELEASE 3 /* for tweaks, bug-fixes, or development */
#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR * 100 * 100 + LZ4_VERSION_MINOR * 100 + LZ4_VERSION_RELEASE)
#define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE
#define LZ4_QUOTE(str) #str
#define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str)
#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION)
LZ4LIB_API int LZ4_versionNumber(void); /**< library version number; useful to check dll version */
LZ4LIB_API const char *LZ4_versionString(void); /**< library version string; useful to check dll version */
/*-************************************
* Tuning parameter
**************************************/
/*!
* LZ4_MEMORY_USAGE :
* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
* Increasing memory usage improves compression ratio.
* Reduced memory usage may improve speed, thanks to better cache locality.
* Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache
*/
#ifndef LZ4_MEMORY_USAGE
#define LZ4_MEMORY_USAGE 14
#endif
/*-************************************
* Simple Functions
**************************************/
/*! LZ4_compress_default() :
* Compresses 'srcSize' bytes from buffer 'src'
* into already allocated 'dst' buffer of size 'dstCapacity'.
* Compression is guaranteed to succeed if 'dstCapacity' >= LZ4_compressBound(srcSize).
* It also runs faster, so it's a recommended setting.
* If the function cannot compress 'src' into a more limited 'dst' budget,
* compression stops *immediately*, and the function result is zero.
* In which case, 'dst' content is undefined (invalid).
* srcSize : max supported value is LZ4_MAX_INPUT_SIZE.
* dstCapacity : size of buffer 'dst' (which must be already allocated)
* @return : the number of bytes written into buffer 'dst' (necessarily <= dstCapacity)
* or 0 if compression fails
* Note : This function is protected against buffer overflow scenarios (never writes outside 'dst' buffer, nor read outside 'source' buffer).
*/
LZ4LIB_API int LZ4_compress_default(const char *src, char *dst, int srcSize, int dstCapacity);
/*! LZ4_decompress_safe() :
* compressedSize : is the exact complete size of the compressed block.
* dstCapacity : is the size of destination buffer (which must be already allocated), presumed an upper bound of decompressed size.
* @return : the number of bytes decompressed into destination buffer (necessarily <= dstCapacity)
* If destination buffer is not large enough, decoding will stop and output an error code (negative value).
* If the source stream is detected malformed, the function will stop decoding and return a negative result.
* Note 1 : This function is protected against malicious data packets :
* it will never writes outside 'dst' buffer, nor read outside 'source' buffer,
* even if the compressed block is maliciously modified to order the decoder to do these actions.
* In such case, the decoder stops immediately, and considers the compressed block malformed.
* Note 2 : compressedSize and dstCapacity must be provided to the function, the compressed block does not contain them.
* The implementation is free to send / store / derive this information in whichever way is most beneficial.
* If there is a need for a different format which bundles together both compressed data and its metadata, consider looking at lz4frame.h instead.
*/
LZ4LIB_API int LZ4_decompress_safe(const char *src, char *dst, int compressedSize, int dstCapacity);
/*-************************************
* Advanced Functions
**************************************/
#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize) / 255) + 16)
/*! LZ4_compressBound() :
Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible)
This function is primarily useful for memory allocation purposes (destination buffer size).
Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example).
Note that LZ4_compress_default() compresses faster when dstCapacity is >= LZ4_compressBound(srcSize)
inputSize : max supported value is LZ4_MAX_INPUT_SIZE
return : maximum output size in a "worst case" scenario
or 0, if input size is incorrect (too large or negative)
*/
LZ4LIB_API int LZ4_compressBound(int inputSize);
/*! LZ4_compress_fast() :
Same as LZ4_compress_default(), but allows selection of "acceleration" factor.
The larger the acceleration value, the faster the algorithm, but also the lesser the compression.
It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.
An acceleration value of "1" is the same as regular LZ4_compress_default()
Values <= 0 will be replaced by LZ4_ACCELERATION_DEFAULT (currently == 1, see lz4.c).
Values > LZ4_ACCELERATION_MAX will be replaced by LZ4_ACCELERATION_MAX (currently == 65537, see lz4.c).
*/
LZ4LIB_API int LZ4_compress_fast(const char *src, char *dst, int srcSize, int dstCapacity, int acceleration);
/*! LZ4_compress_fast_extState() :
* Same as LZ4_compress_fast(), using an externally allocated memory space for its state.
* Use LZ4_sizeofState() to know how much memory must be allocated,
* and allocate it on 8-bytes boundaries (using `malloc()` typically).
* Then, provide this buffer as `void* state` to compression function.
*/
LZ4LIB_API int LZ4_sizeofState(void);
LZ4LIB_API int LZ4_compress_fast_extState(void *state, const char *src, char *dst, int srcSize, int dstCapacity, int acceleration);
/*! LZ4_compress_destSize() :
* Reverse the logic : compresses as much data as possible from 'src' buffer
* into already allocated buffer 'dst', of size >= 'targetDestSize'.
* This function either compresses the entire 'src' content into 'dst' if it's large enough,
* or fill 'dst' buffer completely with as much data as possible from 'src'.
* note: acceleration parameter is fixed to "default".
*
* *srcSizePtr : will be modified to indicate how many bytes where read from 'src' to fill 'dst'.
* New value is necessarily <= input value.
* @return : Nb bytes written into 'dst' (necessarily <= targetDestSize)
* or 0 if compression fails.
*
* Note : from v1.8.2 to v1.9.1, this function had a bug (fixed un v1.9.2+):
* the produced compressed content could, in specific circumstances,
* require to be decompressed into a destination buffer larger
* by at least 1 byte than the content to decompress.
* If an application uses `LZ4_compress_destSize()`,
* it's highly recommended to update liblz4 to v1.9.2 or better.
* If this can't be done or ensured,
* the receiving decompression function should provide
* a dstCapacity which is > decompressedSize, by at least 1 byte.
* See https://github.com/lz4/lz4/issues/859 for details
*/
LZ4LIB_API int LZ4_compress_destSize(const char *src, char *dst, int *srcSizePtr, int targetDstSize);
/*! LZ4_decompress_safe_partial() :
* Decompress an LZ4 compressed block, of size 'srcSize' at position 'src',
* into destination buffer 'dst' of size 'dstCapacity'.
* Up to 'targetOutputSize' bytes will be decoded.
* The function stops decoding on reaching this objective.
* This can be useful to boost performance
* whenever only the beginning of a block is required.
*
* @return : the number of bytes decoded in `dst` (necessarily <= targetOutputSize)
* If source stream is detected malformed, function returns a negative result.
*
* Note 1 : @return can be < targetOutputSize, if compressed block contains less data.
*
* Note 2 : targetOutputSize must be <= dstCapacity
*
* Note 3 : this function effectively stops decoding on reaching targetOutputSize,
* so dstCapacity is kind of redundant.
* This is because in older versions of this function,
* decoding operation would still write complete sequences.
* Therefore, there was no guarantee that it would stop writing at exactly targetOutputSize,
* it could write more bytes, though only up to dstCapacity.
* Some "margin" used to be required for this operation to work properly.
* Thankfully, this is no longer necessary.
* The function nonetheless keeps the same signature, in an effort to preserve API compatibility.
*
* Note 4 : If srcSize is the exact size of the block,
* then targetOutputSize can be any value,
* including larger than the block's decompressed size.
* The function will, at most, generate block's decompressed size.
*
* Note 5 : If srcSize is _larger_ than block's compressed size,
* then targetOutputSize **MUST** be <= block's decompressed size.
* Otherwise, *silent corruption will occur*.
*/
LZ4LIB_API int LZ4_decompress_safe_partial(const char *src, char *dst, int srcSize, int targetOutputSize, int dstCapacity);
/*-*********************************************
* Streaming Compression Functions
***********************************************/
typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */
LZ4LIB_API LZ4_stream_t *LZ4_createStream(void);
LZ4LIB_API int LZ4_freeStream(LZ4_stream_t *streamPtr);
/*! LZ4_resetStream_fast() : v1.9.0+
* Use this to prepare an LZ4_stream_t for a new chain of dependent blocks
* (e.g., LZ4_compress_fast_continue()).
*
* An LZ4_stream_t must be initialized once before usage.
* This is automatically done when created by LZ4_createStream().
* However, should the LZ4_stream_t be simply declared on stack (for example),
* it's necessary to initialize it first, using LZ4_initStream().
*
* After init, start any new stream with LZ4_resetStream_fast().
* A same LZ4_stream_t can be re-used multiple times consecutively
* and compress multiple streams,
* provided that it starts each new stream with LZ4_resetStream_fast().
*
* LZ4_resetStream_fast() is much faster than LZ4_initStream(),
* but is not compatible with memory regions containing garbage data.
*
* Note: it's only useful to call LZ4_resetStream_fast()
* in the context of streaming compression.
* The *extState* functions perform their own resets.
* Invoking LZ4_resetStream_fast() before is redundant, and even counterproductive.
*/
LZ4LIB_API void LZ4_resetStream_fast(LZ4_stream_t *streamPtr);
/*! LZ4_loadDict() :
* Use this function to reference a static dictionary into LZ4_stream_t.
* The dictionary must remain available during compression.
* LZ4_loadDict() triggers a reset, so any previous data will be forgotten.
* The same dictionary will have to be loaded on decompression side for successful decoding.
* Dictionary are useful for better compression of small data (KB range).
* While LZ4 accept any input as dictionary,
* results are generally better when using Zstandard's Dictionary Builder.
* Loading a size of 0 is allowed, and is the same as reset.
* @return : loaded dictionary size, in bytes (necessarily <= 64 KB)
*/
LZ4LIB_API int LZ4_loadDict(LZ4_stream_t *streamPtr, const char *dictionary, int dictSize);
/*! LZ4_compress_fast_continue() :
* Compress 'src' content using data from previously compressed blocks, for better compression ratio.
* 'dst' buffer must be already allocated.
* If dstCapacity >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster.
*
* @return : size of compressed block
* or 0 if there is an error (typically, cannot fit into 'dst').
*
* Note 1 : Each invocation to LZ4_compress_fast_continue() generates a new block.
* Each block has precise boundaries.
* Each block must be decompressed separately, calling LZ4_decompress_*() with relevant metadata.
* It's not possible to append blocks together and expect a single invocation of LZ4_decompress_*() to decompress them together.
*
* Note 2 : The previous 64KB of source data is __assumed__ to remain present, unmodified, at same address in memory !
*
* Note 3 : When input is structured as a double-buffer, each buffer can have any size, including < 64 KB.
* Make sure that buffers are separated, by at least one byte.
* This construction ensures that each block only depends on previous block.
*
* Note 4 : If input buffer is a ring-buffer, it can have any size, including < 64 KB.
*
* Note 5 : After an error, the stream status is undefined (invalid), it can only be reset or freed.
*/
LZ4LIB_API int LZ4_compress_fast_continue(LZ4_stream_t *streamPtr, const char *src, char *dst, int srcSize, int dstCapacity, int acceleration);
/*! LZ4_saveDict() :
* If last 64KB data cannot be guaranteed to remain available at its current memory location,
* save it into a safer place (char* safeBuffer).
* This is schematically equivalent to a memcpy() followed by LZ4_loadDict(),
* but is much faster, because LZ4_saveDict() doesn't need to rebuild tables.
* @return : saved dictionary size in bytes (necessarily <= maxDictSize), or 0 if error.
*/
LZ4LIB_API int LZ4_saveDict(LZ4_stream_t *streamPtr, char *safeBuffer, int maxDictSize);
/*-**********************************************
* Streaming Decompression Functions
* Bufferless synchronous API
************************************************/
typedef union LZ4_streamDecode_u LZ4_streamDecode_t; /* tracking context */
/*! LZ4_createStreamDecode() and LZ4_freeStreamDecode() :
* creation / destruction of streaming decompression tracking context.
* A tracking context can be re-used multiple times.
*/
LZ4LIB_API LZ4_streamDecode_t *LZ4_createStreamDecode(void);
LZ4LIB_API int LZ4_freeStreamDecode(LZ4_streamDecode_t *LZ4_stream);
/*! LZ4_setStreamDecode() :
* An LZ4_streamDecode_t context can be allocated once and re-used multiple times.
* Use this function to start decompression of a new stream of blocks.
* A dictionary can optionally be set. Use NULL or size 0 for a reset order.
* Dictionary is presumed stable : it must remain accessible and unmodified during next decompression.
* @return : 1 if OK, 0 if error
*/
LZ4LIB_API int LZ4_setStreamDecode(LZ4_streamDecode_t *LZ4_streamDecode, const char *dictionary, int dictSize);
/*! LZ4_decoderRingBufferSize() : v1.8.2+
* Note : in a ring buffer scenario (optional),
* blocks are presumed decompressed next to each other
* up to the moment there is not enough remaining space for next block (remainingSize < maxBlockSize),
* at which stage it resumes from beginning of ring buffer.
* When setting such a ring buffer for streaming decompression,
* provides the minimum size of this ring buffer
* to be compatible with any source respecting maxBlockSize condition.
* @return : minimum ring buffer size,
* or 0 if there is an error (invalid maxBlockSize).
*/
LZ4LIB_API int LZ4_decoderRingBufferSize(int maxBlockSize);
#define LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize) (65536 + 14 + (maxBlockSize)) /* for static allocation; maxBlockSize presumed valid */
/*! LZ4_decompress_*_continue() :
* These decoding functions allow decompression of consecutive blocks in "streaming" mode.
* A block is an unsplittable entity, it must be presented entirely to a decompression function.
* Decompression functions only accepts one block at a time.
* The last 64KB of previously decoded data *must* remain available and unmodified at the memory position where they were decoded.
* If less than 64KB of data has been decoded, all the data must be present.
*
* Special : if decompression side sets a ring buffer, it must respect one of the following conditions :
* - Decompression buffer size is _at least_ LZ4_decoderRingBufferSize(maxBlockSize).
* maxBlockSize is the maximum size of any single block. It can have any value > 16 bytes.
* In which case, encoding and decoding buffers do not need to be synchronized.
* Actually, data can be produced by any source compliant with LZ4 format specification, and respecting maxBlockSize.
* - Synchronized mode :
* Decompression buffer size is _exactly_ the same as compression buffer size,
* and follows exactly same update rule (block boundaries at same positions),
* and decoding function is provided with exact decompressed size of each block (exception for last block of the stream),
* _then_ decoding & encoding ring buffer can have any size, including small ones ( < 64 KB).
* - Decompression buffer is larger than encoding buffer, by a minimum of maxBlockSize more bytes.
* In which case, encoding and decoding buffers do not need to be synchronized,
* and encoding ring buffer can have any size, including small ones ( < 64 KB).
*
* Whenever these conditions are not possible,
* save the last 64KB of decoded data into a safe buffer where it can't be modified during decompression,
* then indicate where this data is saved using LZ4_setStreamDecode(), before decompressing next block.
*/
LZ4LIB_API int LZ4_decompress_safe_continue(LZ4_streamDecode_t *LZ4_streamDecode, const char *src, char *dst, int srcSize, int dstCapacity);
/*! LZ4_decompress_*_usingDict() :
* These decoding functions work the same as
* a combination of LZ4_setStreamDecode() followed by LZ4_decompress_*_continue()
* They are stand-alone, and don't need an LZ4_streamDecode_t structure.
* Dictionary is presumed stable : it must remain accessible and unmodified during decompression.
* Performance tip : Decompression speed can be substantially increased
* when dst == dictStart + dictSize.
*/
LZ4LIB_API int LZ4_decompress_safe_usingDict(const char *src, char *dst, int srcSize, int dstCapcity, const char *dictStart, int dictSize);
#endif /* LZ4_H_2983827168210 */
/*^*************************************
* !!!!!! STATIC LINKING ONLY !!!!!!
***************************************/
/*-****************************************************************************
* Experimental section
*
* Symbols declared in this section must be considered unstable. Their
* signatures or semantics may change, or they may be removed altogether in the
* future. They are therefore only safe to depend on when the caller is
* statically linked against the library.
*
* To protect against unsafe usage, not only are the declarations guarded,
* the definitions are hidden by default
* when building LZ4 as a shared/dynamic library.
*
* In order to access these declarations,
* define LZ4_STATIC_LINKING_ONLY in your application
* before including LZ4's headers.
*
* In order to make their implementations accessible dynamically, you must
* define LZ4_PUBLISH_STATIC_FUNCTIONS when building the LZ4 library.
******************************************************************************/
#ifdef LZ4_STATIC_LINKING_ONLY
#ifndef LZ4_STATIC_3504398509
#define LZ4_STATIC_3504398509
#ifdef LZ4_PUBLISH_STATIC_FUNCTIONS
#define LZ4LIB_STATIC_API LZ4LIB_API
#else
#define LZ4LIB_STATIC_API
#endif
/*! LZ4_compress_fast_extState_fastReset() :
* A variant of LZ4_compress_fast_extState().
*
* Using this variant avoids an expensive initialization step.
* It is only safe to call if the state buffer is known to be correctly initialized already
* (see above comment on LZ4_resetStream_fast() for a definition of "correctly initialized").
* From a high level, the difference is that
* this function initializes the provided state with a call to something like LZ4_resetStream_fast()
* while LZ4_compress_fast_extState() starts with a call to LZ4_resetStream().
*/
LZ4LIB_STATIC_API int LZ4_compress_fast_extState_fastReset(void *state, const char *src, char *dst, int srcSize, int dstCapacity, int acceleration);
/*! LZ4_attach_dictionary() :
* This is an experimental API that allows
* efficient use of a static dictionary many times.
*
* Rather than re-loading the dictionary buffer into a working context before
* each compression, or copying a pre-loaded dictionary's LZ4_stream_t into a
* working LZ4_stream_t, this function introduces a no-copy setup mechanism,
* in which the working stream references the dictionary stream in-place.
*
* Several assumptions are made about the state of the dictionary stream.
* Currently, only streams which have been prepared by LZ4_loadDict() should
* be expected to work.
*
* Alternatively, the provided dictionaryStream may be NULL,
* in which case any existing dictionary stream is unset.
*
* If a dictionary is provided, it replaces any pre-existing stream history.
* The dictionary contents are the only history that can be referenced and
* logically immediately precede the data compressed in the first subsequent
* compression call.
*
* The dictionary will only remain attached to the working stream through the
* first compression call, at the end of which it is cleared. The dictionary
* stream (and source buffer) must remain in-place / accessible / unchanged
* through the completion of the first compression call on the stream.
*/
LZ4LIB_STATIC_API void LZ4_attach_dictionary(LZ4_stream_t *workingStream, const LZ4_stream_t *dictionaryStream);
/*! In-place compression and decompression
*
* It's possible to have input and output sharing the same buffer,
* for highly contrained memory environments.
* In both cases, it requires input to lay at the end of the buffer,
* and decompression to start at beginning of the buffer.
* Buffer size must feature some margin, hence be larger than final size.
*
* |<------------------------buffer--------------------------------->|
* |<-----------compressed data--------->|
* |<-----------decompressed size------------------>|
* |<----margin---->|
*
* This technique is more useful for decompression,
* since decompressed size is typically larger,
* and margin is short.
*
* In-place decompression will work inside any buffer
* which size is >= LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize).
* This presumes that decompressedSize > compressedSize.
* Otherwise, it means compression actually expanded data,
* and it would be more efficient to store such data with a flag indicating it's not compressed.
* This can happen when data is not compressible (already compressed, or encrypted).
*
* For in-place compression, margin is larger, as it must be able to cope with both
* history preservation, requiring input data to remain unmodified up to LZ4_DISTANCE_MAX,
* and data expansion, which can happen when input is not compressible.
* As a consequence, buffer size requirements are much higher,
* and memory savings offered by in-place compression are more limited.
*
* There are ways to limit this cost for compression :
* - Reduce history size, by modifying LZ4_DISTANCE_MAX.
* Note that it is a compile-time constant, so all compressions will apply this limit.
* Lower values will reduce compression ratio, except when input_size < LZ4_DISTANCE_MAX,
* so it's a reasonable trick when inputs are known to be small.
* - Require the compressor to deliver a "maximum compressed size".
* This is the `dstCapacity` parameter in `LZ4_compress*()`.
* When this size is < LZ4_COMPRESSBOUND(inputSize), then compression can fail,
* in which case, the return code will be 0 (zero).
* The caller must be ready for these cases to happen,
* and typically design a backup scheme to send data uncompressed.
* The combination of both techniques can significantly reduce
* the amount of margin required for in-place compression.
*
* In-place compression can work in any buffer
* which size is >= (maxCompressedSize)
* with maxCompressedSize == LZ4_COMPRESSBOUND(srcSize) for guaranteed compression success.
* LZ4_COMPRESS_INPLACE_BUFFER_SIZE() depends on both maxCompressedSize and LZ4_DISTANCE_MAX,
* so it's possible to reduce memory requirements by playing with them.
*/
#define LZ4_DECOMPRESS_INPLACE_MARGIN(compressedSize) (((compressedSize) >> 8) + 32)
#define LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize) ((decompressedSize) + LZ4_DECOMPRESS_INPLACE_MARGIN(decompressedSize)) /**< note: presumes that compressedSize < decompressedSize. note2: margin is overestimated a bit, since it could use compressedSize instead */
#ifndef LZ4_DISTANCE_MAX /* history window size; can be user-defined at compile time */
#define LZ4_DISTANCE_MAX 65535 /* set to maximum value by default */
#endif
#define LZ4_COMPRESS_INPLACE_MARGIN (LZ4_DISTANCE_MAX + 32) /* LZ4_DISTANCE_MAX can be safely replaced by srcSize when it's smaller */
#define LZ4_COMPRESS_INPLACE_BUFFER_SIZE(maxCompressedSize) ((maxCompressedSize) + LZ4_COMPRESS_INPLACE_MARGIN) /**< maxCompressedSize is generally LZ4_COMPRESSBOUND(inputSize), but can be set to any lower value, with the risk that compression can fail (return code 0(zero)) */
#endif /* LZ4_STATIC_3504398509 */
#endif /* LZ4_STATIC_LINKING_ONLY */
#ifndef LZ4_H_98237428734687
#define LZ4_H_98237428734687
/*-************************************************************
* Private Definitions
**************************************************************
* Do not use these definitions directly.
* They are only exposed to allow static allocation of `LZ4_stream_t` and `LZ4_streamDecode_t`.
* Accessing members will expose user code to API and/or ABI break in future versions of the library.
**************************************************************/
#define LZ4_HASHLOG (LZ4_MEMORY_USAGE - 2)
#define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE)
#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */
#if defined(__cplusplus) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
#include <stdint.h>
typedef int8_t LZ4_i8;
typedef uint8_t LZ4_byte;
typedef uint16_t LZ4_u16;
typedef uint32_t LZ4_u32;
#else
typedef signed char LZ4_i8;
typedef unsigned char LZ4_byte;
typedef unsigned short LZ4_u16;
typedef unsigned int LZ4_u32;
#endif
typedef struct LZ4_stream_t_internal LZ4_stream_t_internal;
struct LZ4_stream_t_internal
{
LZ4_u32 hashTable[LZ4_HASH_SIZE_U32];
LZ4_u32 currentOffset;
LZ4_u32 tableType;
const LZ4_byte *dictionary;
const LZ4_stream_t_internal *dictCtx;
LZ4_u32 dictSize;
};
typedef struct
{
const LZ4_byte *externalDict;
size_t extDictSize;
const LZ4_byte *prefixEnd;
size_t prefixSize;
} LZ4_streamDecode_t_internal;
/*! LZ4_stream_t :
* Do not use below internal definitions directly !
* Declare or allocate an LZ4_stream_t instead.
* LZ4_stream_t can also be created using LZ4_createStream(), which is recommended.
* The structure definition can be convenient for static allocation
* (on stack, or as part of larger structure).
* Init this structure with LZ4_initStream() before first use.
* note : only use this definition in association with static linking !
* this definition is not API/ABI safe, and may change in future versions.
*/
#define LZ4_STREAMSIZE 16416 /* static size, for inter-version compatibility */
#define LZ4_STREAMSIZE_VOIDP (LZ4_STREAMSIZE / sizeof(void *))
union LZ4_stream_u
{
void *table[LZ4_STREAMSIZE_VOIDP];
LZ4_stream_t_internal internal_donotuse;
}; /* previously typedef'd to LZ4_stream_t */
/*! LZ4_initStream() : v1.9.0+
* An LZ4_stream_t structure must be initialized at least once.
* This is automatically done when invoking LZ4_createStream(),
* but it's not when the structure is simply declared on stack (for example).
*
* Use LZ4_initStream() to properly initialize a newly declared LZ4_stream_t.
* It can also initialize any arbitrary buffer of sufficient size,
* and will @return a pointer of proper type upon initialization.
*
* Note : initialization fails if size and alignment conditions are not respected.
* In which case, the function will @return NULL.
* Note2: An LZ4_stream_t structure guarantees correct alignment and size.
* Note3: Before v1.9.0, use LZ4_resetStream() instead
*/
LZ4LIB_API LZ4_stream_t *LZ4_initStream(void *buffer, size_t size);
/*! LZ4_streamDecode_t :
* information structure to track an LZ4 stream during decompression.
* init this structure using LZ4_setStreamDecode() before first use.
* note : only use in association with static linking !
* this definition is not API/ABI safe,
* and may change in a future version !
*/
#define LZ4_STREAMDECODESIZE_U64 (4 + ((sizeof(void *) == 16) ? 2 : 0) /*AS-400*/)
#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long))
union LZ4_streamDecode_u
{
unsigned long long table[LZ4_STREAMDECODESIZE_U64];
LZ4_streamDecode_t_internal internal_donotuse;
}; /* previously typedef'd to LZ4_streamDecode_t */
/*-************************************
* Obsolete Functions
**************************************/
/*! Deprecation warnings
*
* Deprecated functions make the compiler generate a warning when invoked.
* This is meant to invite users to update their source code.
* Should deprecation warnings be a problem, it is generally possible to disable them,
* typically with -Wno-deprecated-declarations for gcc
* or _CRT_SECURE_NO_WARNINGS in Visual.
*
* Another method is to define LZ4_DISABLE_DEPRECATE_WARNINGS
* before including the header file.
*/
#ifdef LZ4_DISABLE_DEPRECATE_WARNINGS
#define LZ4_DEPRECATED(message) /* disable deprecation warnings */
#else
#if defined(__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */
#define LZ4_DEPRECATED(message) [[deprecated(message)]]
#elif defined(_MSC_VER)
#define LZ4_DEPRECATED(message) __declspec(deprecated(message))
#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 45))
#define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))
#elif defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 31)
#define LZ4_DEPRECATED(message) __attribute__((deprecated))
#else
#pragma message("WARNING: LZ4_DEPRECATED needs custom implementation for this compiler")
#define LZ4_DEPRECATED(message) /* disabled */
#endif
#endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */
/*! Obsolete compression functions (since v1.7.3) */
LZ4_DEPRECATED("use LZ4_compress_default() instead")
LZ4LIB_API int LZ4_compress(const char *src, char *dest, int srcSize);
LZ4_DEPRECATED("use LZ4_compress_default() instead")
LZ4LIB_API int LZ4_compress_limitedOutput(const char *src, char *dest, int srcSize, int maxOutputSize);
LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead")
LZ4LIB_API int LZ4_compress_withState(void *state, const char *source, char *dest, int inputSize);
LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead")
LZ4LIB_API int LZ4_compress_limitedOutput_withState(void *state, const char *source, char *dest, int inputSize, int maxOutputSize);
LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead")
LZ4LIB_API int LZ4_compress_continue(LZ4_stream_t *LZ4_streamPtr, const char *source, char *dest, int inputSize);
LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead")
LZ4LIB_API int LZ4_compress_limitedOutput_continue(LZ4_stream_t *LZ4_streamPtr, const char *source, char *dest, int inputSize, int maxOutputSize);
/*! Obsolete decompression functions (since v1.8.0) */
LZ4_DEPRECATED("use LZ4_decompress_fast() instead")
LZ4LIB_API int LZ4_uncompress(const char *source, char *dest, int outputSize);
LZ4_DEPRECATED("use LZ4_decompress_safe() instead")
LZ4LIB_API int LZ4_uncompress_unknownOutputSize(const char *source, char *dest, int isize, int maxOutputSize);
/* Obsolete streaming functions (since v1.7.0)
* degraded functionality; do not use!
*
* In order to perform streaming compression, these functions depended on data
* that is no longer tracked in the state. They have been preserved as well as
* possible: using them will still produce a correct output. However, they don't
* actually retain any history between compression calls. The compression ratio
* achieved will therefore be no better than compressing each chunk
* independently.
*/
LZ4_DEPRECATED("Use LZ4_createStream() instead")
LZ4LIB_API void *LZ4_create(char *inputBuffer);
LZ4_DEPRECATED("Use LZ4_createStream() instead")
LZ4LIB_API int LZ4_sizeofStreamState(void);
LZ4_DEPRECATED("Use LZ4_resetStream() instead")
LZ4LIB_API int LZ4_resetStreamState(void *state, char *inputBuffer);
LZ4_DEPRECATED("Use LZ4_saveDict() instead")
LZ4LIB_API char *LZ4_slideInputBuffer(void *state);
/*! Obsolete streaming decoding functions (since v1.7.0) */
LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead")
LZ4LIB_API int LZ4_decompress_safe_withPrefix64k(const char *src, char *dst, int compressedSize, int maxDstSize);
LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead")
LZ4LIB_API int LZ4_decompress_fast_withPrefix64k(const char *src, char *dst, int originalSize);
/*! Obsolete LZ4_decompress_fast variants (since v1.9.0) :
* These functions used to be faster than LZ4_decompress_safe(),
* but this is no longer the case. They are now slower.
* This is because LZ4_decompress_fast() doesn't know the input size,
* and therefore must progress more cautiously into the input buffer to not read beyond the end of block.
* On top of that `LZ4_decompress_fast()` is not protected vs malformed or malicious inputs, making it a security liability.
* As a consequence, LZ4_decompress_fast() is strongly discouraged, and deprecated.
*
* The last remaining LZ4_decompress_fast() specificity is that
* it can decompress a block without knowing its compressed size.
* Such functionality can be achieved in a more secure manner
* by employing LZ4_decompress_safe_partial().
*
* Parameters:
* originalSize : is the uncompressed size to regenerate.
* `dst` must be already allocated, its size must be >= 'originalSize' bytes.
* @return : number of bytes read from source buffer (== compressed size).
* The function expects to finish at block's end exactly.
* If the source stream is detected malformed, the function stops decoding and returns a negative result.
* note : LZ4_decompress_fast*() requires originalSize. Thanks to this information, it never writes past the output buffer.
* However, since it doesn't know its 'src' size, it may read an unknown amount of input, past input buffer bounds.
* Also, since match offsets are not validated, match reads from 'src' may underflow too.
* These issues never happen if input (compressed) data is correct.
* But they may happen if input data is invalid (error or intentional tampering).
* As a consequence, use these functions in trusted environments with trusted data **only**.
*/
LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe() instead")
LZ4LIB_API int LZ4_decompress_fast(const char *src, char *dst, int originalSize);
LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_continue() instead")
LZ4LIB_API int LZ4_decompress_fast_continue(LZ4_streamDecode_t *LZ4_streamDecode, const char *src, char *dst, int originalSize);
LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_usingDict() instead")
LZ4LIB_API int LZ4_decompress_fast_usingDict(const char *src, char *dst, int originalSize, const char *dictStart, int dictSize);
/*! LZ4_resetStream() :
* An LZ4_stream_t structure must be initialized at least once.
* This is done with LZ4_initStream(), or LZ4_resetStream().
* Consider switching to LZ4_initStream(),
* invoking LZ4_resetStream() will trigger deprecation warnings in the future.
*/
LZ4LIB_API void LZ4_resetStream(LZ4_stream_t *streamPtr);
#endif /* LZ4_H_98237428734687 */
#if defined(__cplusplus)
}
#endif

10
kernel/src/common/math.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#include "stddef.h"
#include <arch/arch.h>
#if ARCH(I386) || ARCH(X86_64)
#include <arch/x86_64/math/bitcount.h>
#else
#error Arch not supported.
#endif
int64_t pow(int64_t x, int y);

View File

@ -0,0 +1,14 @@
CFLAGS += -I .
all: fabs.o round.o pow.o
fabs.o: fabs.c
$(CC) $(CFLAGS) -c fabs.c -o fabs.o
round.o: round.c
$(CC) $(CFLAGS) -c round.c -o round.o
pow.o: pow.c
$(CC) $(CFLAGS) -c pow.c -o pow.o

View File

@ -0,0 +1,30 @@
#include <common/math.h>
#include <common/sys/types.h>
#include "libm.h"
double fabs(double x)
{
union
{
double f;
uint64_t i;
} u = {x};
u.i &= -1ULL / 2;
return u.f;
}
#if __LDBL_MANT_DIG__ == 53 && __LDBL_MAX_EXP__ == 1024
long double fabsl(long double x)
{
return fabs(x);
}
#elif (__LDBL_MANT_DIG__ == 64 || __LDBL_MANT_DIG__ == 113) && __LDBL_MAX_EXP__ == 16384
long double fabsl(long double x)
{
union ldshape u = {x};
u.i.se &= 0x7fff;
return u.f;
}
#endif

View File

@ -0,0 +1,75 @@
#pragma once
#include <common/sys/types.h>
// ===== 描述long double 的数据比特结构
#if __LDBL_MANT_DIG__ == 53 && __LDBL_MAX_EXP__ == 1024
#elif __LDBL_MANT_DIG__ == 64 && __LDBL_MAX_EXP__ == 16384 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
union ldshape
{
long double f;
struct
{
uint64_t m;
uint16_t se;
} i;
};
#elif __LDBL_MANT_DIG__ == 113 && __LDBL_MAX_EXP__ == 16384 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
union ldshape
{
long double f;
struct
{
uint64_t lo;
uint32_t mid;
uint16_t top;
uint16_t se;
} i;
struct
{
uint64_t lo;
uint64_t hi;
} i2;
};
#elif __LDBL_MANT_DIG__ == 113 && __LDBL_MAX_EXP__ == 16384 && __BYTE_ORDER__ == __BIG_ENDIAN
union ldshape
{
long double f;
struct
{
uint16_t se;
uint16_t top;
uint32_t mid;
uint64_t lo;
} i;
struct
{
uint64_t hi;
uint64_t lo;
} i2;
};
#else
#error Unsupported long double representation
#endif
#define FORCE_EVAL(x) \
do \
{ \
if (sizeof(x) == sizeof(float)) \
{ \
volatile float __x; \
__x = (x); \
(void)__x; \
} \
else if (sizeof(x) == sizeof(double)) \
{ \
volatile double __x; \
__x = (x); \
(void)__x; \
} \
else \
{ \
volatile long double __x; \
__x = (x); \
(void)__x; \
} \
} while (0)

View File

@ -0,0 +1,21 @@
#include <common/math.h>
#include <common/stddef.h>
int64_t pow(int64_t x, int y)
{
if (y == 0)
return 1;
if (y == 1)
return x;
if (y == 2)
return x * x;
int64_t res = 1;
while (y != 0)
{
if (y & 1)
res *= x;
y >>= 1;
x *= x;
}
return res;
}

View File

@ -0,0 +1,43 @@
#include "libm.h"
#if __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == 1
#define EPS __DBL_EPSILON__
#elif __FLT_EVAL_METHOD__ == 2
#define EPS __LDBL_EPSILON__
#endif
static const double toint = 1 / EPS;
double round(double x)
{
union
{
double f;
uint64_t i;
} u = {x};
int e = u.i >> 52 & 0x7ff;
double y;
if (e >= 0x3ff + 52)
return x;
if (u.i >> 63)
x = -x;
if (e < 0x3ff - 1)
{
/* raise inexact if x!=0 */
FORCE_EVAL(x + toint);
return 0 * u.f;
}
y = x + toint - toint - x;
if (y > 0.5)
y = y + x - 1;
else if (y <= -0.5)
y = y + x + 1;
else
y = y + x;
if (u.i >> 63)
y = -y;
return y;
}

69
kernel/src/common/mutex.h Normal file
View File

@ -0,0 +1,69 @@
#pragma once
#include <common/atomic.h>
#include <common/spinlock.h>
#include <common/glib.h>
#include <process/proc-types.h>
/**
* @brief Mutex - 互斥锁
*
* - 同一时间只有1个任务可以持有mutex
* - 不允许递归地加锁、解锁
* - 只允许通过mutex的api来操作mutex
* - 在硬中断、软中断中不能使用mutex
*/
typedef struct
{
atomic_t count; // 锁计数。1->已解锁。 0->已上锁,且有可能存在等待者
spinlock_t wait_lock; // mutex操作锁用于对mutex的list的操作进行加锁
struct List wait_list; // Mutex的等待队列
} mutex_t;
/**
* @brief 在mutex上的等待者的结构体
*
*/
struct mutex_waiter_t
{
struct List list;
struct process_control_block *pcb;
};
/**
* @brief 初始化互斥量
*
* @param lock mutex结构体
*/
void mutex_init(mutex_t *lock);
/**
* @brief 对互斥量加锁
*
* @param lock mutex结构体
*/
void mutex_lock(mutex_t *lock);
/**
* @brief 对互斥量解锁
*
* @param lock mutex结构体
*/
void mutex_unlock(mutex_t *lock);
/**
* @brief 尝试对互斥量加锁
*
* @param lock mutex结构体
*
* @return 成功加锁->1, 加锁失败->0
*/
int mutex_trylock(mutex_t *lock);
/**
* @brief 判断mutex是否已被加锁
*
* @return 已加锁->1, 未加锁->0
*/
#define mutex_is_locked(lock) ((atomic_read(&(lock)->count) == 1) ? 0 : 1)

3
kernel/src/common/numa.h Normal file
View File

@ -0,0 +1,3 @@
#pragma once
#define NUMA_NO_NODE (-1)

View File

@ -0,0 +1,84 @@
//
// Created by longjin on 2022/1/21.
//
#pragma once
#pragma GCC push_options
#pragma GCC optimize("O0")
#define PAD_ZERO 1 // 0填充
#define LEFT 2 // 靠左对齐
#define RIGHT 4 // 靠右对齐
#define PLUS 8 // 在正数前面显示加号
#define SPACE 16
#define SPECIAL 32 // 在八进制数前面显示 '0o',在十六进制数前面显示 '0x' 或 '0X'
#define SMALL 64 // 十进制以上数字显示小写字母
#define SIGN 128 // 显示符号位
#define is_digit(c) ((c) >= '0' && (c) <= '9') // 用来判断是否是数字的宏
// 字体颜色的宏定义
#define WHITE 0x00ffffff //白
#define BLACK 0x00000000 //黑
#define RED 0x00ff0000 //红
#define ORANGE 0x00ff8000 //橙
#define YELLOW 0x00ffff00 //黄
#define GREEN 0x0000ff00 //绿
#define BLUE 0x000000ff //蓝
#define INDIGO 0x0000ffff //靛
#define PURPLE 0x008000ff //紫
// 异常的宏定义
#define EPOS_OVERFLOW 1 // 坐标溢出
#define EFB_MISMATCH 2 // 帧缓冲区与指定的屏幕大小不匹配
#define EUNSUPPORTED 3 // 当前操作暂不被支持
#include "font.h"
#include "glib.h"
#include <lib/libUI/screen_manager.h>
#include <stdarg.h>
extern unsigned char font_ascii[256][16]; //导出ascii字体的bitmap8*16大小 ps:位于font.h中
/**
* @brief 将字符串按照fmt和args中的内容进行格式化然后保存到buf中
*
* @param buf 结果缓冲区
* @param fmt 格式化字符串
* @param args 内容
* @return 最终字符串的长度
*/
int vsprintf(char *buf, const char *fmt, va_list args);
/**
* @brief 将字符串按照fmt和args中的内容进行格式化截取字符串前buf_size-1保存到buf中
*
* @param buf 结果缓冲区大小为buf_size
* @param fmt 格式化字符串
* @param buf_size 缓冲区长度
* @param args 内容
* @return 最终字符串的长度
*/
int vsnprintf(char *buf, const char *fmt, int buf_size, va_list args);
/**
* @brief 格式化打印字符串
*
* @param FRcolor 前景色
* @param BKcolor 背景色
* @param ... 格式化字符串
*/
#define printk(...) printk_color(WHITE, BLACK, __VA_ARGS__)
int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ...);
/**
* @brief 格式化字符串并输出到buf
*
* @param buf 输出缓冲区
* @param fmt 格式
* @param ... 参数
* @return int 字符串长度
*/
int sprintk(char *buf, const char *fmt, ...);
#pragma GCC pop_options

View File

@ -0,0 +1,47 @@
/**
* @file semaphore.h
* @author fslngjin (lonjin@RinGoTek.cn)
* @brief 信号量
* @version 0.1
* @date 2022-04-12
*
* @copyright Copyright (c) 2022
*
*/
#pragma once
#include <common/atomic.h>
#include <common/wait_queue.h>
/**
* @brief 信号量的结构体
*
*/
typedef struct
{
atomic_t counter;
wait_queue_node_t wait_queue;
} semaphore_t;
/**
* @brief 初始化信号量
*
* @param sema 信号量对象
* @param count 信号量的初始值
*/
static __always_inline void semaphore_init(semaphore_t *sema, ul count)
{
atomic_set(&sema->counter, count);
wait_queue_init(&sema->wait_queue, NULL);
}
/**
* @brief 信号量down
*
* @param sema
*/
void semaphore_down(semaphore_t *sema);
void semaphore_up(semaphore_t *sema);

View File

@ -0,0 +1,184 @@
/**
* @file spinlock.h
* @author fslongjin (longjin@RinGoTek.cn)
* @brief 自旋锁
* @version 0.1
* @date 2022-04-07
*
* @copyright Copyright (c) 2022
*
*/
#pragma once
#include <common/glib.h>
#include <process/preempt.h>
#include <debug/bug.h>
/**
* @brief 定义自旋锁结构体
*
*/
typedef struct
{
int8_t lock; // 1:unlocked 0:locked
} spinlock_t;
/**
* @brief 自旋锁加锁
*
* @param lock
*/
void spin_lock(spinlock_t *lock)
{
__asm__ __volatile__("1: \n\t"
"lock decb %0 \n\t" // 尝试-1
"jns 3f \n\t" // 加锁成功跳转到步骤3
"2: \n\t" // 加锁失败,稍后再试
"pause \n\t"
"cmpb $0, %0 \n\t"
"jle 2b \n\t" // 若锁被占用,则继续重试
"jmp 1b \n\t" // 尝试加锁
"3:"
: "=m"(lock->lock)::"memory");
preempt_disable();
}
/**
* @brief 自旋锁解锁
*
* @param lock
*/
void spin_unlock(spinlock_t *lock)
{
preempt_enable();
__asm__ __volatile__("movb $1, %0 \n\t"
: "=m"(lock->lock)::"memory");
}
/**
* @brief 初始化自旋锁
*
* @param lock
*/
void spin_init(spinlock_t *lock)
{
barrier();
lock->lock = 1;
barrier();
}
/**
* @brief 自旋锁加锁(不改变自旋锁持有计数)
*
* @warning 慎用此函数,除非你有十足的把握不会产生自旋锁计数错误
*/
void spin_lock_no_preempt(spinlock_t *lock)
{
__asm__ __volatile__("1: \n\t"
"lock decb %0 \n\t" // 尝试-1
"jns 3f \n\t" // 加锁成功跳转到步骤3
"2: \n\t" // 加锁失败,稍后再试
"pause \n\t"
"cmpb $0, %0 \n\t"
"jle 2b \n\t" // 若锁被占用,则继续重试
"jmp 1b \n\t" // 尝试加锁
"3:"
: "=m"(lock->lock)::"memory");
}
/**
* @brief 自旋锁解锁(不改变自旋锁持有计数)
*
* @warning 慎用此函数,除非你有十足的把握不会产生自旋锁计数错误
*/
void spin_unlock_no_preempt(spinlock_t *lock)
{
__asm__ __volatile__("movb $1, %0 \n\t"
: "=m"(lock->lock)::"memory");
}
/**
* @brief 尝试加锁
*
* @param lock
* @return long 锁变量的值1为成功加锁0为加锁失败
*/
long spin_trylock(spinlock_t *lock)
{
uint64_t tmp_val = 0;
preempt_disable();
// 交换tmp_val和lock的值若tmp_val==1则证明加锁成功
asm volatile("lock xchg %%bx, %1 \n\t" // 确保只有1个进程能得到锁
: "=q"(tmp_val), "=m"(lock->lock)
: "b"(0)
: "memory");
if (!tmp_val)
preempt_enable();
return tmp_val;
}
// 保存当前rflags的值到变量x内并关闭中断
#define local_irq_save(x) __asm__ __volatile__("pushfq ; popq %0 ; cli" \
: "=g"(x)::"memory")
// 恢复先前保存的rflags的值x
#define local_irq_restore(x) __asm__ __volatile__("pushq %0 ; popfq" ::"g"(x) \
: "memory")
#define local_irq_disable() cli();
#define local_irq_enable() sti();
/**
* @brief 保存中断状态,关闭中断,并自旋锁加锁
*
*/
#define spin_lock_irqsave(lock, flags) \
do \
{ \
local_irq_save(flags); \
spin_lock(lock); \
} while (0)
/**
* @brief 恢复rflags以及中断状态并解锁自旋锁
*
*/
#define spin_unlock_irqrestore(lock, flags) \
do \
{ \
spin_unlock(lock); \
local_irq_restore(flags); \
} while (0)
/**
* @brief 关闭中断并加锁
*
*/
#define spin_lock_irq(lock) \
do \
{ \
local_irq_disable(); \
spin_lock(lock); \
} while (0)
/**
* @brief 解锁并开启中断
*
*/
#define spin_unlock_irq(lock) \
do \
{ \
spin_unlock(lock); \
local_irq_enable(); \
} while (0)
/**
* @brief 判断自旋锁是否已经加锁
*
* @param lock 待判断的自旋锁
* @return true 已经加锁
* @return false 尚未加锁
*/
static inline bool spin_is_locked(const spinlock_t *lock)
{
int x = READ_ONCE(lock->lock);
return (x == 0) ? true : false;
}
#define assert_spin_locked(lock) BUG_ON(!spin_is_locked(lock))

View File

@ -0,0 +1,7 @@
#pragma once
#include "./sys/types.h"
#define NULL 0
typedef __PTRDIFF_TYPE__ ptrdiff_t; // Signed integer type of the result of subtracting two pointers.

13
kernel/src/common/stdio.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include <stdarg.h>
#include <common/printk.h>
#define SEEK_SET 0 /* Seek relative to start-of-file */
#define SEEK_CUR 1 /* Seek relative to current position */
#define SEEK_END 2 /* Seek relative to end-of-file */
#define SEEK_MAX 3
extern int vsprintf(char *buf, const char *fmt, va_list args);
extern int sprintk(char *buf, const char *fmt, ...);

View File

@ -0,0 +1,9 @@
#pragma once
/**
* @brief 将长整型转换为字符串
*
* @param input 输入的数据
* @return const char* 结果字符串
*/
const char* ltoa(long input);

View File

@ -0,0 +1,78 @@
#pragma once
#include "glib.h"
/**
* @brief 拷贝整个字符串
*
* @param dst 目标地址
* @param src 源地址
* @return char* 目标字符串
*/
char *strcpy(char *dst, const char *src);
//计算字符串的长度经过测试该版本比采用repne/scasb汇编的运行速度快16.8%左右)
static inline int strlen(const char *s)
{
if (s == NULL)
return 0;
register int __res = 0;
while (s[__res] != '\0')
{
++__res;
}
return __res;
}
/**
* @brief 测量字符串的长度
*
* @param src 字符串
* @param maxlen 最大长度
* @return long
*/
long strnlen(const char *src, unsigned long maxlen);
/*
比较字符串 FirstPart and SecondPart
FirstPart = SecondPart => 0
FirstPart > SecondPart => 1
FirstPart < SecondPart => -1
*/
int strcmp(const char *FirstPart, const char *SecondPart);
char *strncpy(char *dst, const char *src, long count);
long strncpy_from_user(char *dst, const char *src, unsigned long size);
/**
* @brief 测量来自用户空间的字符串的长度,会检验地址空间是否属于用户空间
* @param src
* @param maxlen
* @return long
*/
long strnlen_user(const char *src, unsigned long maxlen);
/**
* @brief 逐字节比较指定内存区域的值并返回s1、s2的第一个不相等的字节i处的差值s1[i]-s2[i])。
* 若两块内存区域的内容相同则返回0
*
* @param s1 内存区域1
* @param s2 内存区域2
* @param len 要比较的内存区域长度
* @return int s1、s2的第一个不相等的字节i处的差值s1[i]-s2[i])。若两块内存区域的内容相同则返回0
*/
static inline int memcmp(const void *s1, const void *s2, size_t len)
{
int diff;
asm("cld \n\t" // 复位DF确保s1、s2指针是自增的
"repz; cmpsb\n\t" CC_SET(nz)
: CC_OUT(nz)(diff), "+D"(s1), "+S"(s2)
: "c"(len)
: "memory");
if (diff)
diff = *(const unsigned char *)(s1 - 1) - *(const unsigned char *)(s2 - 1);
return diff;
}

View File

@ -0,0 +1,97 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned int u_int;
typedef unsigned long u_long;
typedef uint32_t uid_t;
typedef uint32_t gid_t;
typedef long long ssize_t;
typedef int __pid_t;
#define pid_t uint64_t
typedef __SIZE_TYPE__ size_t;
typedef char *caddr_t;
typedef int id_t;
typedef uint64_t ino_t;
typedef int64_t off_t;
typedef uint32_t blkcnt_t;
typedef uint32_t blksize_t;
typedef uint32_t dev_t;
typedef uint16_t mode_t;
typedef uint32_t nlink_t;
typedef int64_t time_t;
typedef uint32_t useconds_t;
typedef int32_t suseconds_t;
typedef uint32_t clock_t;
typedef uint64_t fsblkcnt_t;
typedef uint64_t fsfilcnt_t;
typedef uint64_t sector_t;
#define __socklen_t_defined
#define __socklen_t uint32_t
typedef __socklen_t socklen_t;
#define pgoff_t unsigned long
struct utimbuf
{
time_t actime;
time_t modtime;
};
typedef int pthread_t;
typedef int pthread_key_t;
typedef uint32_t pthread_once_t;
typedef struct __pthread_mutex_t
{
uint32_t lock;
pthread_t owner;
int level;
int type;
} pthread_mutex_t;
typedef void *pthread_attr_t;
typedef struct __pthread_mutexattr_t
{
int type;
} pthread_mutexattr_t;
typedef struct __pthread_cond_t
{
pthread_mutex_t *mutex;
uint32_t value;
int clockid; // clockid_t
} pthread_cond_t;
typedef uint64_t pthread_rwlock_t;
typedef void *pthread_rwlockattr_t;
typedef struct __pthread_spinlock_t
{
int m_lock;
} pthread_spinlock_t;
typedef struct __pthread_condattr_t
{
int clockid; // clockid_t
} pthread_condattr_t;
typedef uint64_t gfp_t;
// 定义8字节对齐变量属性
#ifndef __aligned_u64
#define __aligned_u64 uint64_t __attribute__((aligned(8)))
#endif
#define aligned_u64 __aligned_u64

View File

@ -0,0 +1,12 @@
#pragma once
#include "types.h"
/**
* @brief 等待指定pid的子进程退出
*
* @param pid 子进程的pid
* @param stat_loc 返回的子进程结束状态
* @param options 额外的控制选项
* @return pid_t
*/
pid_t waitpid(pid_t pid, int *stat_loc, int options);

53
kernel/src/common/time.h Normal file
View File

@ -0,0 +1,53 @@
#pragma once
#include "stddef.h"
// 操作系统定义时间以ns为单位
#define CLOCKS_PER_SEC 1000000
struct tm
{
int tm_sec; /* Seconds. [0-60] (1 leap second) */
int tm_min; /* Minutes. [0-59] */
int tm_hour; /* Hours. [0-23] */
int tm_mday; /* Day. [1-31] */
int tm_mon; /* Month. [0-11] */
int tm_year; /* Year - 1900. */
int tm_wday; /* Day of week. [0-6] */
int tm_yday; /* Days in year.[0-365] */
int tm_isdst; /* DST. [-1/0/1]*/
long int __tm_gmtoff; /* Seconds east of UTC. */
const char *__tm_zone; /* Timezone abbreviation. */
};
struct timespec
{
long int tv_sec; // 秒
long long tv_nsec; // 纳秒
};
/**
* @brief 休眠指定时间
*
* @param rqtp 指定休眠的时间
* @param rmtp 返回的剩余休眠时间
* @return int
*/
extern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
/**
* @brief 睡眠指定时间
*
* @param usec 微秒
* @return int
*/
extern int usleep(useconds_t usec);
/**
* @brief 获取当前的CPU时间
*
* @return uint64_t timer_jiffies
*/
extern uint64_t clock();

View File

@ -0,0 +1,36 @@
/**
* @file unistd.h
* @author fslongjin (longjin@RinGoTek.cn)
* @brief
* @version 0.1
* @date 2022-04-22
*
* @copyright Copyright (c) 2022
*
*/
#pragma once
#include <syscall/syscall.h>
#include <syscall/syscall_num.h>
/**
* @brief fork当前进程
*
* @return pid_t
*/
pid_t fork(void);
/**
* @brief vfork当前进程
*
* @return pid_t
*/
pid_t vfork(void);
/**
* @brief 交换n字节
* @param src 源地址
* @param dest 目的地址
* @param nbytes 交换字节数
*/
void swab(void *restrict src, void *restrict dest, ssize_t nbytes);

View File

@ -0,0 +1,7 @@
#pragma once
// todo: 引入用户命名空间
struct user_namespace
{
};

View File

@ -0,0 +1,49 @@
#pragma once
#include <common/glib.h>
/**
* @brief 信号量的等待队列
*
*/
typedef struct
{
struct List wait_list;
struct process_control_block *pcb;
} wait_queue_node_t;
/**
* @brief 初始化等待队列
*
* @param wait_queue 等待队列
* @param pcb pcb
*/
void wait_queue_init(wait_queue_node_t *wait_queue, struct process_control_block *pcb);
/**
* @brief 在等待队列上进行等待
*
* @param wait_queue_head 队列头指针
*/
void wait_queue_sleep_on(wait_queue_node_t *wait_queue_head);
/**
* @brief 在等待队列上进行等待,同时释放自旋锁
*
* @param wait_queue_head 队列头指针
*/
void wait_queue_sleep_on_unlock(wait_queue_node_t *wait_queue_head,
void *lock);
/**
* @brief 在等待队列上进行等待(允许中断)
*
* @param wait_queue_head 队列头指针
*/
void wait_queue_sleep_on_interriptible(wait_queue_node_t *wait_queue_head);
/**
* @brief 唤醒在等待队列的头部的进程
*
* @param wait_queue_head 队列头
* @param state 要唤醒的进程的状态
*/
void wait_queue_wakeup(wait_queue_node_t *wait_queue_head, int64_t state);

View File

@ -0,0 +1,68 @@
#include <common/spinlock.h>
#include <common/wait_queue.h>
typedef struct
{
struct List wait_list;
spinlock_t lock; // 队列需要有一个自旋锁,虽然目前内部并没有使用,但是以后可能会用.[在completion内部使用]
} wait_queue_head_t;
#define DECLARE_WAIT_ON_STACK(name, pcb) \
wait_queue_node_t name = {0}; \
wait_queue_init(&(name), pcb);
#define DECLARE_WAIT_ON_STACK_SELF(name) \
wait_queue_node_t name = {0}; \
wait_queue_init(&(name), current_pcb);
#define DECLARE_WAIT_ALLOC(name, pcb) \
wait_queue_node_t *wait = (wait_queue_node_t *)kzalloc(sizeof(wait_queue_node_t), 0); \
wait_queue_init(&(name), pcb);
#define DECLARE_WAIT_ALLOC_SELF(name) \
wait_queue_node_t *wait = (wait_queue_node_t *)kzalloc(sizeof(wait_queue_node_t), 0); \
wait_queue_init(&(name), current_pcb);
#define DECLARE_WAIT_QUEUE_HEAD(name) \
struct wait_queue_head_t name = {0}; \
wait_queue_head_init(&name);
/**
* @brief 初始化wait_queue队列头
*
* @param wait_queue
*/
void wait_queue_head_init(wait_queue_head_t *wait_queue);
/**
* @brief 在等待队列上进行等待, 但是你需要确保wait已经被init, 同时wakeup只能使用wake_up_on_stack函数。
*
* @param q 队列头指针
* @param wait wait节点
*/
void wait_queue_sleep_with_node(wait_queue_head_t *q, wait_queue_node_t *wait);
/**
* @brief 在等待队列上进行等待,同时释放自旋锁, 但是你需要确保wait已经被init, 同时wakeup只能使用wake_up_on_stack函数。
*
* @param q 队列头指针
* @param wait wait节点
* @param lock
*/
void wait_queue_sleep_with_node_unlock(wait_queue_head_t *q, wait_queue_node_t *wait, void *lock);
/**
* @brief 在等待队列上进行等待(允许中断), 但是你需要确保wait已经被init, 同时wakeup只能使用wake_up_on_stack函数。
*
* @param wait_queue_head 队列头指针
* @param wait wait节点
*/
void wait_queue_sleep_with_node_interriptible(wait_queue_head_t *q, wait_queue_node_t *wait);
/**
* @brief 唤醒在等待队列的头部的进程, 但是不会free掉这个节点的空间(默认这个节点在栈上创建)
*
* @param wait_queue_head_t q: 队列头
* @param state 要唤醒的进程的状态
*/
void wait_queue_wakeup_on_stack(wait_queue_head_t *q, int64_t state);

2
kernel/src/debug/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
kallsyms
kallsyms.S

24
kernel/src/debug/Makefile Normal file
View File

@ -0,0 +1,24 @@
all: traceback.o
CFLAGS += -I .
kallsyms.o: kallsyms.c
$(CC) -o kallsyms kallsyms.c
rm -rf kallsyms.o
traceback.o: traceback/traceback.c
$(CC) $(CFLAGS) -c traceback/traceback.c -o traceback/traceback.o
# 生成内核栈符号表的汇编文件
generate_kallsyms: kallsyms.o
echo "Generating kallsyms..."
nm -n $(kernel_root_path)/kernel | ./kallsyms > kallsyms.S
$(CC) -c kallsyms.S -o kallsyms.o
@echo "Kallsyms generated."
clean:
rm -rf kallsyms

68
kernel/src/debug/bug.h Normal file
View File

@ -0,0 +1,68 @@
#pragma once
#include <common/compiler.h>
#include <common/kprint.h>
#pragma GCC push_options
#pragma GCC optimize("O0")
/**
* @brief 当condition为true时认为产生了bug
*
*/
#define BUG_ON(condition) ({ \
int __ret_bug_on = !!(condition); \
if (unlikely(__ret_bug_on)) \
kBUG("BUG at %s:%d", __FILE__, __LINE__); \
unlikely(__ret_bug_on); \
})
/**
* @brief 当condition为true时输出警告信息
*
*/
#define WARN_ON(condition) ({ \
int __ret_warn_on = !!(condition); \
if (unlikely(__ret_warn_on)) \
kwarn("Assertion failed at %s:%d", __FILE__, __LINE__); \
unlikely(__ret_warn_on); \
})
/**
* @brief 当condition不为0时输出警告信息且只会输出一次警告信息
*
*/
#define WARN_ON_ONCE(condition) ({ \
static int __warned; \
int __ret_warn_once = !!(condition); \
\
if (unlikely(__ret_warn_once && !__warned)) \
{ \
__warned = true; \
WARN_ON(1); \
} \
unlikely(__ret_warn_once); \
})
#define FAIL_ON_TO(condition, to) ({ \
int __ret_warn_on = !!(condition); \
if (unlikely(__ret_warn_on)) \
goto to; \
unlikely(__ret_warn_on); \
})
/**
* @brief 当condition为true时中断编译并输出错误信息msg
*
* 如果你的代码依赖于一些能够在编译期间计算出来的值,那么请使用这个宏以防止其他人错误的修改了这些值,从而导致程序运行错误
*/
#define BUILD_BUG_ON_MSG(condition, msg) complietime_assert(!(condition), msg)
/**
* @brief 当condition为true时中断编译。
*
* 如果你的代码依赖于一些能够在编译期间计算出来的值,那么请使用这个宏以防止其他人错误的修改了这些值,从而导致程序运行错误
*/
#define BUILD_BUG_ON(condition) \
BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition)
#pragma GCC pop_options

200
kernel/src/debug/kallsyms.c Normal file
View File

@ -0,0 +1,200 @@
/**
* @file kallsyms.c
* @author longjin (longjin@RinGoTek.cn)
* @brief 内核栈跟踪
* @version 0.1
* @date 2022-06-22
*
* @copyright Copyright (c) 2022
*
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
* @brief 判断符号是否需要被输出只输出text段内的符号
*
*/
#define symbol_to_write(vaddr, tv, etv) \
((vaddr < tv || vaddr > etv) ? 0 : 1)
/**
* @brief 使用nm命令提取出来的信息存到这个结构体之中
*
*/
struct kernel_symbol_entry_t
{
uint64_t vaddr;
char type;
char *symbol;
int symbol_length;
};
struct kernel_symbol_entry_t *symbol_table;
// 符号表最大能容纳的entry数量
uint64_t table_size = 0;
// 符号表当前的entry数量
uint64_t entry_count = 0;
// 符号表中text和etext的下标
uint64_t text_vaddr, etext_vaddr;
/**
* @brief 读取一个符号到entry之中
*
* @param filp stdin的文件指针
* @param entry 待填写的entry
* @return int 返回码
*/
int read_symbol(FILE *filp, struct kernel_symbol_entry_t *entry)
{
// 本函数假设nm命令输出的结果中每行最大512字节
char str[512] = {0};
int retval = fscanf(filp, "%llx %c %510s\n", &entry->vaddr, &entry->type, str);
// 如果当前行不符合要求
if (retval != 3)
{
if (retval != EOF)
{
// 如果不是输入流的结尾,说明该行不符合要求,将其过滤
fgets(str, 512, filp);
}
return -1;
}
// malloc一块内存然后把str的内容拷贝进去接着修改symbol指针
entry->symbol = strdup(str);
entry->symbol_length = strlen(str) + 1; // +1的原因是.asciz指令会在字符串末尾自动添加结束符\0
return 0;
}
/**
* @brief 接收标准输入流的数据解析nm命令输出的内容
*
* @param filp
*/
void read_map(FILE *filp)
{
// 循环读入数据直到输入流结束
while (!feof(filp))
{
// 给符号表扩容
if (entry_count >= table_size)
{
table_size += 100;
// 由于使用了realloc因此符号表原有的内容会被自动的copy过去
symbol_table = (struct kernel_symbol_entry_t *)realloc(symbol_table, sizeof(struct kernel_symbol_entry_t) * table_size);
}
// 若成功读取符号表的内容,则将计数器+1
if (read_symbol(filp, &symbol_table[entry_count]) == 0)
++entry_count;
}
// 查找符号表中的text和etext标签
for (uint64_t i = 0; i < entry_count; ++i)
{
if (strcmp(symbol_table[i].symbol, "_text")==0)
text_vaddr = symbol_table[i].vaddr;
if (strcmp(symbol_table[i].symbol, "_etext")==0)
etext_vaddr = symbol_table[i].vaddr;
}
}
/**
* @brief 输出最终的kallsyms汇编代码文件
* 直接输出到stdout通过命令行的 > 命令,写入文件
*/
void generate_result()
{
printf(".section .rodata\n\n");
printf(".global kallsyms_address\n");
printf(".align 8\n\n");
printf("kallsyms_address:\n"); // 地址数组
uint64_t last_vaddr = 0;
uint64_t total_syms_to_write = 0; // 真正输出的符号的数量
// 循环写入地址数组
for (uint64_t i = 0; i < entry_count; ++i)
{
// 判断是否为text段的符号
if (!symbol_to_write(symbol_table[i].vaddr, text_vaddr, etext_vaddr))
continue;
if (symbol_table[i].vaddr == last_vaddr)
continue;
// 输出符号地址
printf("\t.quad\t%#llx\n", symbol_table[i].vaddr);
++total_syms_to_write;
last_vaddr = symbol_table[i].vaddr;
}
putchar('\n');
// 写入符号表的表项数量
printf(".global kallsyms_num\n");
printf(".align 8\n");
printf("kallsyms_num:\n");
printf("\t.quad\t%lld\n", total_syms_to_write);
putchar('\n');
// 循环写入符号名称的下标索引
printf(".global kallsyms_names_index\n");
printf(".align 8\n");
printf("kallsyms_names_index:\n");
uint64_t position = 0;
last_vaddr = 0;
for (uint64_t i = 0; i < entry_count; ++i)
{
// 判断是否为text段的符号
if (!symbol_to_write(symbol_table[i].vaddr, text_vaddr, etext_vaddr))
continue;
if (symbol_table[i].vaddr == last_vaddr)
continue;
// 输出符号名称的偏移量
printf("\t.quad\t%lld\n", position);
position += symbol_table[i].symbol_length;
last_vaddr = symbol_table[i].vaddr;
}
putchar('\n');
// 输出符号名
printf(".global kallsyms_names\n");
printf(".align 8\n");
printf("kallsyms_names:\n");
last_vaddr = 0;
for (uint64_t i = 0; i < entry_count; ++i)
{
// 判断是否为text段的符号
if (!symbol_to_write(symbol_table[i].vaddr, text_vaddr, etext_vaddr))
continue;
if (symbol_table[i].vaddr == last_vaddr)
continue;
// 输出符号名称
printf("\t.asciz\t\"%s\"\n", symbol_table[i].symbol);
last_vaddr = symbol_table[i].vaddr;
}
putchar('\n');
}
int main(int argc, char **argv)
{
read_map(stdin);
generate_result();
}

View File

@ -0,0 +1,71 @@
#include "traceback.h"
#include <common/printk.h>
#include <process/process.h>
static int lookup_kallsyms(uint64_t addr, int level)
{
const char *str = (const char *)&kallsyms_names;
// 暴力查找符合要求的symbol
// todo: 改用二分搜索。
// 由于符号表使用nm -n生成因此是按照地址升序排列的因此可以二分
uint64_t index = 0;
for (index = 0; index < kallsyms_num - 1; ++index)
{
if (addr > kallsyms_address[index] && addr <= kallsyms_address[index + 1])
break;
}
if (index < kallsyms_num) // 找到对应的函数
{
// 依次输出函数名称、rip离函数起始处的偏移量、函数执行的rip
printk("function:%s() \t(+) %04d address:%#018lx\n", &str[kallsyms_names_index[index]], addr - kallsyms_address[index], addr);
return 0;
}
else
return -1;
}
/**
* @brief 追溯内核栈调用情况
*
* @param regs 内核栈结构体
*/
void traceback(struct pt_regs *regs)
{
// 先检验是否为用户态出错,若为用户态出错,则直接返回
if (verify_area(regs->rbp, 0))
{
printk_color(YELLOW, BLACK, "Kernel traceback: Fault in userland. pid=%ld, rbp=%#018lx\n", current_pcb->pid, regs->rbp);
return;
}
uint64_t *rbp = (uint64_t *)regs->rbp;
printk_color(YELLOW, BLACK, "======== Kernel traceback =======\n");
// printk("&kallsyms_address:%#018lx,kallsyms_address:%#018lx\n", &kallsyms_address, kallsyms_address);
// printk("&kallsyms_syms_num:%#018lx,kallsyms_syms_num:%d\n", &kallsyms_num, kallsyms_num);
// printk("&kallsyms_index:%#018lx\n", &kallsyms_names_index);
// printk("&kallsyms_names:%#018lx,kallsyms_names:%s\n", &kallsyms_names, &kallsyms_names);
uint64_t ret_addr = regs->rip;
// 最大追踪10层调用栈
for (int i = 0; i < 10; ++i)
{
if (lookup_kallsyms(ret_addr, i) != 0)
break;
// 当前栈帧的rbp的地址大于等于内核栈的rbp的时候表明调用栈已经到头了追踪结束。
// 当前rbp的地址为用户空间时直接退出
if((uint64_t)(rbp) >= current_pcb->thread->rbp || ((uint64_t)rbp<regs->rsp))
break;
printk_color(ORANGE, BLACK, "rbp:%#018lx,*rbp:%#018lx\n", rbp, *rbp);
// 由于x86处理器在执行call指令时先将调用返回地址压入栈中然后再把函数的rbp入栈最后将rsp设为新的rbp。
// 因此此处的rbp就是上一层的rsp那么*(rbp+1)得到的就是上一层函数的返回地址
ret_addr = *(rbp + 1);
rbp = (uint64_t *)(*rbp);
printk("\n");
}
printk_color(YELLOW, BLACK, "======== Kernel traceback end =======\n");
}

View File

@ -0,0 +1,17 @@
#pragma once
#include <common/glib.h>
#include<process/ptrace.h>
// 使用弱引用属性导出kallsyms中的符号表。
// 采用weak属性是由于第一次编译时kallsyms还未链接进来若不使用weak属性则会报错
extern const uint64_t kallsyms_address[] __attribute__((weak));
extern const uint64_t kallsyms_num __attribute__((weak));
extern const uint64_t kallsyms_names_index[] __attribute__((weak));
extern const char* kallsyms_names __attribute__((weak));
/**
* @brief 追溯内核栈调用情况
*
* @param regs 内核栈结构体
*/
void traceback(struct pt_regs * regs);

View File

@ -0,0 +1,17 @@
CFLAGS += -I .
kernel_driver_subdirs:=video interrupt usb pci uart acpi disk keyboard mouse multiboot2 timers tty hid
ECHO:
@echo "$@"
$(kernel_driver_subdirs): ECHO
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)"
all: $(kernel_driver_subdirs)
clean:
echo "Done."

View File

@ -0,0 +1,8 @@
all: acpi.o
CFLAGS += -I .
acpi.o: acpi.c
$(CC) $(CFLAGS) -c acpi.c -o acpi.o

View File

@ -0,0 +1,241 @@
#include "acpi.h"
#include <common/printk.h>
#include <common/kprint.h>
#include <driver/multiboot2/multiboot2.h>
#include <mm/mm.h>
#include <mm/mmio.h>
#define acpi_get_RSDT_entry_vaddr(phys_addr) (acpi_description_header_base + (phys_addr)-acpi_RSDT_entry_phys_base) // 获取RSDT entry的虚拟地址
// #define acpi_get_XSDT_entry_vaddr(phys_addr) (ACPI_DESCRIPTION_HEDERS_BASE + (phys_addr)-acpi_XSDT_entry_phys_base) // 获取XSDT entry的虚拟地址
static struct acpi_RSDP_t *rsdpv1;
static struct acpi_RSDP_2_t *rsdpv2;
static struct acpi_RSDT_Structure_t *rsdt;
static struct acpi_XSDT_Structure_t *xsdt;
static struct multiboot_tag_old_acpi_t old_acpi;
static struct multiboot_tag_new_acpi_t new_acpi;
static ul acpi_RSDT_offset = 0;
static ul acpi_XSDT_offset = 0;
static uint acpi_RSDT_Entry_num = 0;
static uint acpi_XSDT_Entry_num = 0;
static ul acpi_RSDT_entry_phys_base = 0; // RSDT中的第一个entry所在物理页的基地址
static uint64_t acpi_madt_vaddr = 0; // MADT的虚拟地址
static uint64_t acpi_rsdt_virt_addr_base = 0; // RSDT的虚拟地址
static uint64_t acpi_description_header_base = 0; // RSDT中的第一个entry所在虚拟地址
// static ul acpi_XSDT_entry_phys_base = 0; // XSDT中的第一个entry所在物理页的基地址
/**
* @brief 迭代器用于迭代描述符头位于ACPI标准文件的Table 5-29
* @param _fun 迭代操作调用的函数
* @param _data 数据
*/
void acpi_iter_SDT(bool (*_fun)(const struct acpi_system_description_table_header_t *, void *),
void *_data)
{
struct acpi_system_description_table_header_t *sdt_header;
if (acpi_use_xsdt)
{
ul *ent = &(xsdt->Entry);
for (int i = 0; i < acpi_XSDT_Entry_num; ++i)
{
mm_map_phys_addr(acpi_description_header_base + PAGE_2M_SIZE * i, (*(ent + i)) & PAGE_2M_MASK, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
sdt_header = (struct acpi_system_description_table_header_t *)((ul)(acpi_description_header_base + PAGE_2M_SIZE * i));
if (_fun(sdt_header, _data) == true)
return;
}
}
else
{
uint *ent = &(rsdt->Entry);
for (int i = 0; i < acpi_RSDT_Entry_num; ++i)
{
sdt_header = (struct acpi_system_description_table_header_t *)(acpi_get_RSDT_entry_vaddr((ul)(*(ent + i))));
if (_fun(sdt_header, _data) == true)
return;
}
}
return;
}
/**
* @brief 获取MADT信息 Multiple APIC Description Table
*
* @param _iter_data 要被迭代的信息的结构体
* @param _data 返回的MADT的虚拟地址
* @param count 返回数组的长度
* @return true
* @return false
*/
bool acpi_get_MADT(const struct acpi_system_description_table_header_t *_iter_data, void *_data)
{
if (!(_iter_data->Signature[0] == 'A' && _iter_data->Signature[1] == 'P' && _iter_data->Signature[2] == 'I' && _iter_data->Signature[3] == 'C'))
return false;
//*(struct acpi_Multiple_APIC_Description_Table_t *)_data = *(struct acpi_Multiple_APIC_Description_Table_t *)_iter_data;
// 返回MADT的虚拟地址
*(ul *)_data = (ul)_iter_data;
acpi_madt_vaddr = (ul)_iter_data;
return true;
}
/**
* @brief 获取HPET HPET_description_table
*
* @param _iter_data 要被迭代的信息的结构体
* @param _data 返回的HPET表的虚拟地址
* @return true
* @return false
*/
bool acpi_get_HPET(const struct acpi_system_description_table_header_t *_iter_data, void *_data)
{
if (!(_iter_data->Signature[0] == 'H' && _iter_data->Signature[1] == 'P' && _iter_data->Signature[2] == 'E' && _iter_data->Signature[3] == 'T'))
return false;
*(ul *)_data = (ul)_iter_data;
return true;
}
/**
* @brief 初始化acpi模块
*
*/
// todo: 修复bug当物理机上提供了rsdpv2之后rsdpv1是不提供的物理地址为0因此需要手动判断rsdp的版本信息然后做对应的解析。
void acpi_init()
{
kinfo("Initializing ACPI...");
// 获取物理地址
int reserved;
multiboot2_iter(multiboot2_get_acpi_old_RSDP, &old_acpi, &reserved);
rsdpv1 = &(old_acpi.rsdp);
multiboot2_iter(multiboot2_get_acpi_new_RSDP, &new_acpi, &reserved);
rsdpv2 = &(new_acpi.rsdp);
uint64_t paddr = 0;
// An ACPI-compatible OS must use the XSDT if present
if (rsdpv2->XsdtAddress != 0x00UL)
{
// 不要删除这段注释因为还不确定是代码的bug还是真机的bug
/*
acpi_use_xsdt = true;
ul xsdt_phys_base = rsdpv2->XsdtAddress & PAGE_2M_MASK;
acpi_XSDT_offset = rsdpv2->XsdtAddress - xsdt_phys_base;
mm_map_phys_addr(ACPI_XSDT_VIRT_ADDR_BASE, xsdt_phys_base, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
kdebug("XSDT mapped!");
xsdt = (struct acpi_XSDT_Structure_t *)(ACPI_XSDT_VIRT_ADDR_BASE + acpi_XSDT_offset);
// 计算RSDT Entry的数量
kdebug("offset=%d", sizeof(xsdt->header));
kdebug("xsdt sign=%s", xsdt->header.Signature);
acpi_XSDT_Entry_num = (xsdt->header.Length - sizeof(xsdt->header)) / 8;
printk_color(ORANGE, BLACK, "XSDT Length=%dbytes.\n", xsdt->header.Length);
printk_color(ORANGE, BLACK, "XSDT Entry num=%d\n", acpi_XSDT_Entry_num);
mm_map_phys_addr(ACPI_XSDT_VIRT_ADDR_BASE, xsdt_phys_base, xsdt->header.Length + PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
// 映射所有的Entry的物理地址
ul *ent = &(xsdt->Entry);
for (int j = 0; j < acpi_XSDT_Entry_num; ++j)
{
kdebug("entry=%#018lx, virt=%#018lx", (*(ent + j)) & PAGE_2M_MASK, ACPI_XSDT_DESCRIPTION_HEDERS_BASE + PAGE_2M_SIZE * j);
// 映射RSDT ENTRY的物理地址
mm_map_phys_addr(ACPI_XSDT_DESCRIPTION_HEDERS_BASE + PAGE_2M_SIZE * j, (*(ent + j)) & PAGE_2M_MASK, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
}
*/
// 由于解析XSDT出现问题。暂时只使用Rsdpv2的rsdt但是这是不符合ACPI规范的
ul rsdt_phys_base = rsdpv2->rsdp1.RsdtAddress & PAGE_2M_MASK;
acpi_RSDT_offset = rsdpv2->rsdp1.RsdtAddress - rsdt_phys_base;
//申请mmio空间
uint64_t size = 0;
mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_rsdt_virt_addr_base, &size);
//映射rsdt表
paddr = (uint64_t)rsdt_phys_base;
mm_map(&initial_mm, acpi_rsdt_virt_addr_base, PAGE_2M_SIZE, paddr);
// rsdt表虚拟地址
rsdt = (struct acpi_RSDT_Structure_t *)(acpi_rsdt_virt_addr_base + acpi_RSDT_offset);
kdebug("RSDT mapped!(v2)");
// 计算RSDT Entry的数量
kdebug("offset=%d", sizeof(rsdt->header));
acpi_RSDT_Entry_num = (rsdt->header.Length - 36) / 4;
printk_color(ORANGE, BLACK, "RSDT Length=%dbytes.\n", rsdt->header.Length);
printk_color(ORANGE, BLACK, "RSDT Entry num=%d\n", acpi_RSDT_Entry_num);
//申请mmio空间
mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_description_header_base, &size);
// 映射所有的Entry的物理地址
acpi_RSDT_entry_phys_base = ((ul)(rsdt->Entry)) & PAGE_2M_MASK;
// 由于地址只是32bit的并且存在脏数据这里需要手动清除高32bit否则会触发#GP
acpi_RSDT_entry_phys_base = MASK_HIGH_32bit(acpi_RSDT_entry_phys_base);
paddr = (uint64_t)acpi_RSDT_entry_phys_base;
mm_map(&initial_mm, acpi_description_header_base, PAGE_2M_SIZE, paddr);
}
else if (rsdpv1->RsdtAddress != (uint)0x00UL)
{
// rsdt表物理地址
ul rsdt_phys_base = rsdpv1->RsdtAddress & PAGE_2M_MASK;
acpi_RSDT_offset = rsdpv1->RsdtAddress - rsdt_phys_base;
kdebug("rsdpv1->RsdtAddress=%#018lx", rsdpv1->RsdtAddress);
//申请mmio空间
uint64_t size = 0;
mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_rsdt_virt_addr_base, &size);
// kdebug("acpi_rsdt_virt_addr_base = %#018lx,size= %#010lx", acpi_rsdt_virt_addr_base, size);
//映射rsdt表
paddr = (uint64_t)rsdt_phys_base;
mm_map(&initial_mm, acpi_rsdt_virt_addr_base, PAGE_2M_SIZE, paddr);
// rsdt表虚拟地址
rsdt = (struct acpi_RSDT_Structure_t *)(acpi_rsdt_virt_addr_base + acpi_RSDT_offset);
kdebug("RSDT mapped!");
// kdebug("length = %d",rsdt->header.Length);
// 计算RSDT Entry的数量
// kdebug("offset=%d", sizeof(rsdt->header));
acpi_RSDT_Entry_num = (rsdt->header.Length - 36) / 4;
printk_color(ORANGE, BLACK, "RSDT Length=%dbytes.\n", rsdt->header.Length);
printk_color(ORANGE, BLACK, "RSDT Entry num=%d\n", acpi_RSDT_Entry_num);
//申请mmio空间
mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_description_header_base, &size);
// 映射所有的Entry的物理地址
acpi_RSDT_entry_phys_base = ((ul)(rsdt->Entry)) & PAGE_2M_MASK;
// 由于地址只是32bit的并且存在脏数据这里需要手动清除高32bit否则会触发#GP
acpi_RSDT_entry_phys_base = MASK_HIGH_32bit(acpi_RSDT_entry_phys_base);
paddr = (uint64_t)acpi_RSDT_entry_phys_base;
mm_map(&initial_mm, acpi_description_header_base, PAGE_2M_SIZE, paddr);
// kinfo("entry mapped!");
}
else
{
// should not reach here!
kBUG("At acpi_init(): Cannot get right SDT!");
while (1)
;
}
kinfo("ACPI module initialized!");
return;
}

View File

@ -0,0 +1,197 @@
/**
* 解析acpi信息的模块
**/
#pragma once
#include <common/glib.h>
#include <mm/mm.h>
#define ACPI_ICS_TYPE_PROCESSOR_LOCAL_APIC 0
#define ACPI_ICS_TYPE_IO_APIC 1
#define ACPI_ICS_TYPE_INTERRUPT_SOURCE_OVERRIDE 2
#define ACPI_ICS_TYPE_NMI_SOURCE 3
#define ACPI_ICS_TYPE_LOCAL_APIC_NMI 4
#define ACPI_ICS_TYPE_LOCAL_APIC_ADDRESS_OVERRIDE 5
#define ACPI_ICS_TYPE_IO_SAPIC 6
#define ACPI_ICS_TYPE_LOCAL_SAPIC 7
#define ACPI_ICS_TYPE_PLATFORM_INTERRUPT_SOURCES 8
#define ACPI_ICS_TYPE_PROCESSOR_LOCAL_x2APIC 9
#define ACPI_ICS_TYPE_PROCESSOR_LOCAL_x2APIC_NMI 0xA
#define ACPI_ICS_TYPE_PROCESSOR_GICC 0xB
#define ACPI_ICS_TYPE_PROCESSOR_GICD 0xC
#define ACPI_ICS_TYPE_PROCESSOR_GIC_MSI_Frame 0xD
#define ACPI_ICS_TYPE_PROCESSOR_GICR 0xE
#define ACPI_ICS_TYPE_PROCESSOR_GIC_ITS 0xF
// 0x10-0x7f Reserved. OSPM skips structures of the reserved type.
// 0x80-0xff Reserved for OEM use
// extern const uint64_t acpi_rsdt_virt_addr_base ; // RSDT的虚拟地址
// extern const uint64_t acpi_description_header_base ; // RSDT中的第一个entry所在虚拟地址
bool acpi_use_xsdt = false;
struct acpi_RSDP_t
{
unsigned char Signature[8];
unsigned char Checksum;
unsigned char OEMID[6];
unsigned char Revision;
// 32bit physical address of the RSDT
uint RsdtAddress;
} __attribute__((packed));
struct acpi_RSDP_2_t
{
struct acpi_RSDP_t rsdp1;
// fields below are only valid when the revision value is 2 or above
// 表的长度单位字节从offset=0开始算
uint Length;
// 64bit的XSDT的物理地址
ul XsdtAddress;
unsigned char ExtendedChecksum; // 整个表的checksum包括了之前的checksum区域
unsigned char Reserved[3];
} __attribute__((packed));
struct acpi_system_description_table_header_t
{
// The ascii string representation of the table header.
unsigned char Signature[4];
// 整个表的长度单位字节包括了header从偏移量0处开始
uint Length;
// The revision of the structure corresponding to the signature field for this table.
unsigned char Revision;
// The entire table, including the checksum field, must add to zero to be considered valid.
char Checksum;
unsigned char OEMID[6];
unsigned char OEM_Table_ID[8];
uint OEMRevision;
uint CreatorID;
uint CreatorRevision;
} __attribute__((packed));
// HPET描述符结构体sign为HPET
struct acpi_HPET_description_table_t
{
struct acpi_system_description_table_header_t header;
uint8_t hardware_rev_id;
uint8_t comparator_count : 5; // Number of Comparators in 1st Timer Block
uint8_t counter_size : 1; // COUNT_SIZE_CAP counter size
uint8_t reserved0 : 1;
uint8_t legacy_replacement : 1; // LegacyReplacement IRQ Routing Capable
uint16_t pci_vendor_id; // PCI Vendor ID of 1st Timer Block
uint8_t address_space_id; // 0 - system memory, 1 - system I/O
uint8_t register_bit_width;
uint8_t register_bit_offset;
uint8_t reserved1;
uint64_t address;
uint8_t hpet_number;
uint16_t minimum_tick; // The minimum clock ticks can be set without lost interrupts while the counter is programmed to operate in periodic mode
uint8_t page_protection;
} __attribute__((packed));
// =========== MADT结构其中Signature为APIC ============
struct acpi_Multiple_APIC_Description_Table_t
{
struct acpi_system_description_table_header_t header;
// 32bit的每个处理器可访问的local中断控制器的物理地址
uint Local_Interrupt_Controller_Address;
// Multiple APIC flags, 详见 ACPI Specification Version 6.3, Table 5-44
uint flags;
// 接下来的(length-44)字节是Interrupt Controller Structure
};
struct apic_Interrupt_Controller_Structure_header_t
{
unsigned char type;
unsigned char length;
};
struct acpi_Processor_Local_APIC_Structure_t
{
// type=0
struct apic_Interrupt_Controller_Structure_header_t header;
unsigned char ACPI_Processor_UID;
// 处理器的local apic id
unsigned char local_apic_id;
//详见 ACPI Specification Version 6.3, Table 5-47
uint flags;
};
struct acpi_IO_APIC_Structure_t
{
// type=1
struct apic_Interrupt_Controller_Structure_header_t header;
unsigned char IO_APIC_ID;
unsigned char Reserved;
// 32bit的IO APIC物理地址 每个IO APIC都有一个独立的物理地址
uint IO_APIC_Address;
// 当前IO APIC的全局系统中断向量号起始值
// The number of intr inputs is determined by the IO APIC's Max Redir Entry register.
uint Global_System_Interrupt_Base;
};
// =========== RSDT 结构 =============
struct acpi_RSDT_Structure_t
{
// 通过RSDT的header->Length可以计算出entry的数量n
// n = (length - 32)/4
struct acpi_system_description_table_header_t header;
// 一个包含了n个32bit物理地址的数组指向了其他的description headers
uint Entry;
};
// =========== XSDT 结构 =============
struct acpi_XSDT_Structure_t
{
// 通过RSDT的header->Length可以计算出entry的数量n
// n = (length - 36)/8
struct acpi_system_description_table_header_t header;
// 一个包含了n个64bit物理地址的数组指向了其他的description headers
ul Entry;
};
/**
* @brief 迭代器用于迭代描述符头位于ACPI标准文件的Table 5-29
* @param _fun 迭代操作调用的函数
* @param _data 数据
*/
void acpi_iter_SDT(bool (*_fun)(const struct acpi_system_description_table_header_t *, void *),
void *_data);
/**
* @brief 获取MADT信息 Multiple APIC Description Table
*
* @param _iter_data 要被迭代的信息的结构体
* @param _data 返回的MADT的虚拟地址
* @param count 返回数组的长度
* @return true
* @return false
*/
bool acpi_get_MADT(const struct acpi_system_description_table_header_t *_iter_data, void *_data);
/**
* @brief 获取HPET HPET_description_table
*
* @param _iter_data 要被迭代的信息的结构体
* @param _data 返回的HPET表的虚拟地址
* @return true
* @return false
*/
bool acpi_get_HPET(const struct acpi_system_description_table_header_t *_iter_data, void *_data);
// 初始化acpi模块
void acpi_init();

View File

@ -0,0 +1,10 @@
all: ata.o ahci.o
CFLAGS += -I .
ata.o: ata.c
$(CC) $(CFLAGS) -c ata.c -o ata.o
ahci.o: ahci/ahci.c
$(CC) $(CFLAGS) -c ahci/ahci.c -o ahci/ahci.o

View File

@ -0,0 +1,678 @@
#include "ahci.h"
#include <common/kprint.h>
#include <mm/slab.h>
#include <syscall/syscall.h>
#include <syscall/syscall_num.h>
#include <sched/sched.h>
#include <common/string.h>
#include <common/block.h>
#include <filesystem/MBR.h>
#include <debug/bug.h>
struct pci_device_structure_header_t *ahci_devs[MAX_AHCI_DEVICES];
struct block_device_request_queue ahci_req_queue;
struct blk_gendisk ahci_gendisk0 = {0}; // 暂时硬性指定一个ahci_device
static int __first_port = -1; // 临时用于存储 ahci控制器的第一个可用端口 的变量
static uint32_t count_ahci_devices = 0;
static uint64_t ahci_port_base_vaddr; // 端口映射base addr
static uint64_t ahci_port_base_phys_addr; // 端口映射的物理基地址ahci控制器的参数的地址都是物理地址
static void start_cmd(HBA_PORT *port);
static void stop_cmd(HBA_PORT *port);
static void port_rebase(HBA_PORT *port, int portno);
static long ahci_query_disk();
// Find a free command list slot
static int ahci_find_cmdslot(HBA_PORT *port);
// 计算HBA_MEM的虚拟内存地址
#define cal_HBA_MEM_VIRT_ADDR(device_num) (AHCI_MAPPING_BASE + (ul)(((struct pci_device_structure_general_device_t *)(ahci_devs[device_num]))->BAR5 - ((((struct pci_device_structure_general_device_t *)(ahci_devs[0]))->BAR5) & PAGE_2M_MASK)))
long ahci_open();
long ahci_close();
static long ahci_ioctl(long cmd, long arg);
static long ahci_transfer(struct blk_gendisk *gd, long cmd, uint64_t base_addr, uint64_t count, uint64_t buf);
struct block_device_operation ahci_operation =
{
.open = ahci_open,
.close = ahci_close,
.ioctl = ahci_ioctl,
.transfer = ahci_transfer,
};
/**
* @brief ahci驱动器在block_device中的私有数据结构体
*
*/
struct ahci_blk_private_data
{
uint16_t ahci_ctrl_num; // ahci控制器号
uint16_t ahci_port_num; // ahci端口号
struct MBR_disk_partition_table_t *part_table; // 分区表
};
/**
* @brief 申请ahci设备的私有信息结构体
*
* @return struct ahci_blk_private_data* 申请到的私有信息结构体
*/
static struct ahci_blk_private_data *__alloc_private_data()
{
struct ahci_blk_private_data *data = (struct ahci_blk_private_data *)kzalloc(sizeof(struct ahci_blk_private_data), 0);
data->part_table = (struct MBR_disk_partition_table_t *)kzalloc(512, 0);
return data;
}
/**
* @brief 释放ahci设备的分区的私有信息结构体
*
* @param pdata 待释放的结构体
* @return int 错误码
*/
static int __release_private_data(struct ahci_blk_private_data *pdata)
{
kfree(pdata->part_table);
kfree(pdata);
return 0;
}
/**
* @brief 初始化gendisk结构体(暂时只支持1个gendisk)
*
*/
static int ahci_init_gendisk()
{
memset(&ahci_gendisk0, 0, sizeof(ahci_gendisk0));
strcpy(ahci_gendisk0.disk_name, "ahci0");
ahci_gendisk0.flags = BLK_GF_AHCI;
ahci_gendisk0.fops = &ahci_operation;
mutex_init(&ahci_gendisk0.open_mutex);
ahci_gendisk0.request_queue = &ahci_req_queue;
// 为存储分区结构,分配内存空间
ahci_gendisk0.private_data = __alloc_private_data();
// 读取分区表
// 暂时假设全都是MBR分区表的
// todo: 支持GPT
((struct ahci_blk_private_data *)ahci_gendisk0.private_data)->ahci_ctrl_num = 0;
((struct ahci_blk_private_data *)ahci_gendisk0.private_data)->ahci_port_num = __first_port;
MBR_read_partition_table(&ahci_gendisk0, ((struct ahci_blk_private_data *)ahci_gendisk0.private_data)->part_table);
struct MBR_disk_partition_table_t *ptable = ((struct ahci_blk_private_data *)ahci_gendisk0.private_data)->part_table;
// 求出可用分区数量
for (int i = 0; i < 4; ++i)
{
// 分区可用
if (ptable->DPTE[i].type != 0)
++ahci_gendisk0.part_cnt;
}
if (ahci_gendisk0.part_cnt)
{
// 分配分区结构体数组的空间
ahci_gendisk0.partition = (struct block_device *)kzalloc(ahci_gendisk0.part_cnt * sizeof(struct block_device), 0);
int cnt = 0;
// 循环遍历每个分区
for (int i = 0; i < 4; ++i)
{
// 分区可用
if (ptable->DPTE[i].type != 0)
{
// 初始化分区结构体
ahci_gendisk0.partition[cnt].bd_disk = &ahci_gendisk0;
ahci_gendisk0.partition[cnt].bd_partno = cnt;
ahci_gendisk0.partition[cnt].bd_queue = &ahci_req_queue;
ahci_gendisk0.partition[cnt].bd_sectors_num = ptable->DPTE[i].total_sectors;
ahci_gendisk0.partition[cnt].bd_start_sector = ptable->DPTE[i].starting_sector;
ahci_gendisk0.partition[cnt].bd_superblock = NULL; // 挂载文件系统时才会初始化superblock
ahci_gendisk0.partition[cnt].bd_start_LBA = ptable->DPTE[i].starting_LBA;
++cnt;
}
}
}
return 0;
};
/**
* @brief 初始化ahci模块
*
*/
void ahci_init()
{
kinfo("Initializing AHCI...");
pci_get_device_structure(0x1, 0x6, ahci_devs, &count_ahci_devices);
if (count_ahci_devices == 0)
{
kwarn("There is no AHCI device found on this computer!");
return;
}
// 映射ABAR
kdebug("phys_2_virt(ahci_devs[0])= %#018lx", (ahci_devs[0]));
kdebug("((struct pci_device_structure_general_device_t *)phys_2_virt(ahci_devs[0])))->BAR5= %#018lx", ((struct pci_device_structure_general_device_t *)(ahci_devs[0]))->BAR5);
uint32_t bar5 = ((struct pci_device_structure_general_device_t *)(ahci_devs[0]))->BAR5;
mm_map_phys_addr(AHCI_MAPPING_BASE, (ul)(bar5)&PAGE_2M_MASK, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
kdebug("ABAR mapped!");
for (int i = 0; i < count_ahci_devices; ++i)
{
// kdebug("[%d] class_code=%d, sub_class=%d, progIF=%d, ABAR=%#010lx", i, ahci_devs[i]->Class_code, ahci_devs[i]->SubClass, ahci_devs[i]->ProgIF, ((struct pci_device_structure_general_device_t *)(ahci_devs[i]))->BAR5);
// 赋值HBA_MEM结构体
ahci_devices[i].dev_struct = ahci_devs[i];
ahci_devices[i].hba_mem = (HBA_MEM *)(cal_HBA_MEM_VIRT_ADDR(i));
kdebug("ahci_devices[i].hba_mem = %#018lx", (ul)ahci_devices[i].hba_mem);
}
// todo: 支持多个ahci控制器。
ahci_port_base_vaddr = (uint64_t)kmalloc(1048576, 0);
kdebug("ahci_port_base_vaddr=%#018lx", ahci_port_base_vaddr);
ahci_probe_port(0);
// 初始化请求队列
ahci_req_queue.in_service = NULL;
wait_queue_init(&ahci_req_queue.wait_queue_list, NULL);
ahci_req_queue.request_count = 0;
BUG_ON(ahci_init_gendisk() != 0);
kinfo("AHCI initialized.");
}
// Check device type
static int check_type(HBA_PORT *port)
{
uint32_t ssts = port->ssts;
uint8_t ipm = (ssts >> 8) & 0x0F;
uint8_t det = ssts & 0x0F;
if (det != HBA_PORT_DET_PRESENT) // Check drive status
return AHCI_DEV_NULL;
if (ipm != HBA_PORT_IPM_ACTIVE)
return AHCI_DEV_NULL;
switch (port->sig)
{
case SATA_SIG_ATAPI:
return AHCI_DEV_SATAPI;
case SATA_SIG_SEMB:
return AHCI_DEV_SEMB;
case SATA_SIG_PM:
return AHCI_DEV_PM;
default:
return AHCI_DEV_SATA;
}
}
/**
* @brief 检测端口连接的设备的类型
*
* @param device_num ahci控制器号
*/
static void ahci_probe_port(const uint32_t device_num)
{
HBA_MEM *abar = ahci_devices[device_num].hba_mem;
uint32_t pi = abar->pi;
for (int i = 0; i < 32; ++i, (pi >>= 1))
{
if (pi & 1)
{
uint dt = check_type(&abar->ports[i]);
ahci_devices[i].type = dt;
switch (dt)
{
case AHCI_DEV_SATA:
kdebug("SATA drive found at port %d", i);
goto found;
case AHCI_DEV_SATAPI:
kdebug("SATAPI drive found at port %d", i);
goto found;
case AHCI_DEV_SEMB:
kdebug("SEMB drive found at port %d", i);
goto found;
case AHCI_DEV_PM:
kdebug("PM drive found at port %d", i);
goto found;
found:;
port_rebase(&ahci_devices[0].hba_mem->ports[i], i);
if (__first_port == -1)
__first_port = i;
break;
default:
kdebug("No drive found at port %d", i);
break;
}
}
}
}
// Start command engine
static void start_cmd(HBA_PORT *port)
{
// Wait until CR (bit15) is cleared
while ((port->cmd) & HBA_PxCMD_CR)
;
// Set FRE (bit4) and ST (bit0)
port->cmd |= HBA_PxCMD_FRE;
port->cmd |= HBA_PxCMD_ST;
}
// Stop command engine
static void stop_cmd(HBA_PORT *port)
{
// Clear ST (bit0)
port->cmd &= ~HBA_PxCMD_ST;
// Clear FRE (bit4)
port->cmd &= ~HBA_PxCMD_FRE;
// Wait until FR (bit14), CR (bit15) are cleared
while (1)
{
if (port->cmd & HBA_PxCMD_FR)
continue;
if (port->cmd & HBA_PxCMD_CR)
continue;
break;
}
}
static void port_rebase(HBA_PORT *port, int portno)
{
// Before rebasing Port memory space, OS must wait for current pending commands to finish
// and tell HBA to stop receiving FIS from the port. Otherwise an accidently incoming FIS may be
// written into a partially configured memory area.
stop_cmd(port); // Stop command engine
// Command list offset: 1K*portno
// Command list entry size = 32
// Command list entry maxim count = 32
// Command list maxim size = 32*32 = 1K per port
port->clb = virt_2_phys(ahci_port_base_vaddr + (portno << 10));
memset((void *)(phys_2_virt(port->clb)), 0, 1024);
// FIS offset: 32K+256*portno
// FIS entry size = 256 bytes per port
port->fb = virt_2_phys(ahci_port_base_vaddr + (32 << 10) + (portno << 8));
memset((void *)(phys_2_virt(port->fb)), 0, 256);
// Command table offset: 40K + 8K*portno
// Command table size = 256*32 = 8K per port
HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER *)(phys_2_virt(port->clb));
for (int i = 0; i < 32; ++i)
{
cmdheader[i].prdtl = 8; // 8 prdt entries per command table
// 256 bytes per command table, 64+16+48+16*8
// Command table offset: 40K + 8K*portno + cmdheader_index*256
cmdheader[i].ctba = virt_2_phys((ahci_port_base_vaddr + (40 << 10) + (portno << 13) + (i << 8)));
memset((void *)phys_2_virt(cmdheader[i].ctba), 0, 256);
}
start_cmd(port); // Start command engine
}
/**
* @brief read data from SATA device using 48bit LBA address
*
* @param port HBA PORT
* @param startl low 32bits of start addr
* @param starth high 32bits of start addr
* @param count total sectors to read
* @param buf buffer
* @return true done
* @return false failed
*/
static bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, uint64_t buf)
{
port->is = (uint32_t)-1; // Clear pending interrupt bits
int spin = 0; // Spin lock timeout counter
int slot = ahci_find_cmdslot(port);
if (slot == -1)
return E_NOEMPTYSLOT;
HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER *)phys_2_virt(port->clb);
cmdheader += slot;
cmdheader->cfl = sizeof(FIS_REG_H2D) / sizeof(uint32_t); // Command FIS size
cmdheader->w = 0; // Read from device
cmdheader->prdtl = (uint16_t)((count - 1) >> 4) + 1; // PRDT entries count
HBA_CMD_TBL *cmdtbl = (HBA_CMD_TBL *)phys_2_virt(cmdheader->ctba);
memset(cmdtbl, 0, sizeof(HBA_CMD_TBL) + (cmdheader->prdtl - 1) * sizeof(HBA_PRDT_ENTRY));
// 8K bytes (16 sectors) per PRDT
int i;
for (i = 0; i < cmdheader->prdtl - 1; ++i)
{
cmdtbl->prdt_entry[i].dba = virt_2_phys(buf);
cmdtbl->prdt_entry[i].dbc = 8 * 1024 - 1; // 8K bytes (this value should always be set to 1 less than the actual value)
cmdtbl->prdt_entry[i].i = 1;
buf += 4 * 1024; // 4K uint16_ts
count -= 16; // 16 sectors
}
// Last entry
cmdtbl->prdt_entry[i].dba = virt_2_phys(buf);
cmdtbl->prdt_entry[i].dbc = (count << 9) - 1; // 512 bytes per sector
cmdtbl->prdt_entry[i].i = 1;
// Setup command
FIS_REG_H2D *cmdfis = (FIS_REG_H2D *)(&cmdtbl->cfis);
cmdfis->fis_type = FIS_TYPE_REG_H2D;
cmdfis->c = 1; // Command
cmdfis->command = AHCI_CMD_READ_DMA_EXT;
cmdfis->lba0 = (uint8_t)startl;
cmdfis->lba1 = (uint8_t)(startl >> 8);
cmdfis->lba2 = (uint8_t)(startl >> 16);
cmdfis->device = 1 << 6; // LBA mode
cmdfis->lba3 = (uint8_t)(startl >> 24);
cmdfis->lba4 = (uint8_t)starth;
cmdfis->lba5 = (uint8_t)(starth >> 8);
cmdfis->countl = count & 0xFF;
cmdfis->counth = (count >> 8) & 0xFF;
// The below loop waits until the port is no longer busy before issuing a new command
while ((port->tfd & (AHCI_DEV_BUSY | AHCI_DEV_DRQ)) && spin < 1000000)
{
spin++;
}
if (spin == 1000000)
{
kerror("Port is hung");
return E_PORT_HUNG;
}
port->ci = 1 << slot; // Issue command
current_pcb->flags |= PF_NEED_SCHED;
sched();
int retval = AHCI_SUCCESS;
// Wait for completion
while (1)
{
// In some longer duration reads, it may be helpful to spin on the DPS bit
// in the PxIS port field as well (1 << 5)
if ((port->ci & (1 << slot)) == 0)
break;
if (port->is & HBA_PxIS_TFES) // Task file error
{
kerror("Read disk error");
retval = E_TASK_FILE_ERROR;
break;
}
}
// Check again
if (port->is & HBA_PxIS_TFES)
{
kerror("Read disk error");
retval = E_TASK_FILE_ERROR;
}
enter_syscall_int(SYS_AHCI_END_REQ, 0, 0, 0, 0, 0, 0, 0, 0);
return retval;
}
static bool ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count,
uint64_t buf)
{
// kdebug("ahci write");
port->is = 0xffff; // Clear pending interrupt bits
int slot = ahci_find_cmdslot(port);
if (slot == -1)
return E_NOEMPTYSLOT;
HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER *)phys_2_virt(port->clb);
cmdheader += slot;
cmdheader->cfl = sizeof(FIS_REG_H2D) / sizeof(uint32_t); // Command FIS size
cmdheader->w = 1;
cmdheader->c = 1;
cmdheader->p = 1;
cmdheader->prdtl = (uint16_t)((count - 1) >> 4) + 1; // PRDT entries count
HBA_CMD_TBL *cmdtbl = (HBA_CMD_TBL *)phys_2_virt(cmdheader->ctba);
memset(cmdtbl, 0, sizeof(HBA_CMD_TBL) + (cmdheader->prdtl - 1) * sizeof(HBA_PRDT_ENTRY));
int i = 0;
for (i = 0; i < cmdheader->prdtl - 1; ++i)
{
cmdtbl->prdt_entry[i].dba = virt_2_phys(buf);
cmdtbl->prdt_entry[i].dbc = 8 * 1024 - 1; // 8K bytes
cmdtbl->prdt_entry[i].i = 0;
buf += 4 * 1024; // 4K words
count -= 16; // 16 sectors
}
cmdtbl->prdt_entry[i].dba = virt_2_phys(buf);
cmdtbl->prdt_entry[i].dbc = count << 9; // 512 bytes per sector
cmdtbl->prdt_entry[i].i = 0;
FIS_REG_H2D *cmdfis = (FIS_REG_H2D *)(&cmdtbl->cfis);
cmdfis->fis_type = FIS_TYPE_REG_H2D;
cmdfis->c = 1; // Command
cmdfis->command = AHCI_CMD_WRITE_DMA_EXT;
cmdfis->lba0 = (uint8_t)startl;
cmdfis->lba1 = (uint8_t)(startl >> 8);
cmdfis->lba2 = (uint8_t)(startl >> 16);
cmdfis->lba3 = (uint8_t)(startl >> 24);
cmdfis->lba4 = (uint8_t)starth;
cmdfis->lba5 = (uint8_t)(starth >> 8);
cmdfis->device = 1 << 6; // LBA mode
cmdfis->countl = count & 0xff;
cmdfis->counth = count >> 8;
// printk("[slot]{%d}", slot);
port->ci = 1; // Issue command
current_pcb->flags |= PF_NEED_SCHED;
sched();
int retval = AHCI_SUCCESS;
while (1)
{
// In some longer duration reads, it may be helpful to spin on the DPS bit
// in the PxIS port field as well (1 << 5)
if ((port->ci & (1 << slot)) == 0)
break;
if (port->is & HBA_PxIS_TFES)
{ // Task file error
kerror("Write disk error");
retval = E_TASK_FILE_ERROR;
break;
}
}
if (port->is & HBA_PxIS_TFES)
{
kerror("Write disk error");
retval = E_TASK_FILE_ERROR;
}
// kdebug("ahci write retval=%d", retval);
enter_syscall_int(SYS_AHCI_END_REQ, 0, 0, 0, 0, 0, 0, 0, 0);
return retval;
}
// Find a free command list slot
static int ahci_find_cmdslot(HBA_PORT *port)
{
// If not set in SACT and CI, the slot is free
uint32_t slots = (port->sact | port->ci);
int num_of_cmd_clots = (ahci_devices[0].hba_mem->cap & 0x0f00) >> 8; // bit 12-8
for (int i = 0; i < num_of_cmd_clots; i++)
{
if ((slots & 1) == 0)
return i;
slots >>= 1;
}
kerror("Cannot find free command list entry");
return -1;
}
long ahci_open()
{
return 0;
}
long ahci_close()
{
return 0;
}
/**
* @brief 创建ahci磁盘请求包
*
* @param cmd 控制命令
* @param base_addr 48位LBA地址
* @param count total sectors to read
* @param buf 缓冲区线性地址
* @param ahci_ctrl_num ahci控制器号
* @param port_num ahci控制器端口号
* @return struct block_device_request_packet*
*/
static struct ahci_request_packet_t *ahci_make_request(long cmd, uint64_t base_addr, uint64_t count, uint64_t buffer, uint8_t ahci_ctrl_num, uint8_t port_num)
{
struct ahci_request_packet_t *pack = (struct ahci_request_packet_t *)kmalloc(sizeof(struct ahci_request_packet_t), 0);
wait_queue_init(&pack->blk_pak.wait_queue, current_pcb);
pack->blk_pak.device_type = BLK_TYPE_AHCI;
// 由于ahci不需要中断即可读取磁盘因此end handler为空
switch (cmd)
{
case AHCI_CMD_READ_DMA_EXT:
pack->blk_pak.end_handler = NULL;
pack->blk_pak.cmd = AHCI_CMD_READ_DMA_EXT;
break;
case AHCI_CMD_WRITE_DMA_EXT:
pack->blk_pak.end_handler = NULL;
pack->blk_pak.cmd = AHCI_CMD_WRITE_DMA_EXT;
break;
default:
pack->blk_pak.end_handler = NULL;
pack->blk_pak.cmd = cmd;
break;
}
pack->blk_pak.LBA_start = base_addr;
pack->blk_pak.count = count;
pack->blk_pak.buffer_vaddr = buffer;
pack->ahci_ctrl_num = ahci_ctrl_num;
pack->port_num = port_num;
return pack;
}
/**
* @brief 结束磁盘请求
*
*/
void ahci_end_request()
{
ahci_req_queue.in_service->wait_queue.pcb->state = PROC_RUNNING;
// ahci_req_queue.in_service->wait_queue.pcb->flags |= PF_NEED_SCHED;
// current_pcb->flags |= PF_NEED_SCHED;
kfree((uint64_t *)ahci_req_queue.in_service);
ahci_req_queue.in_service = NULL;
// 进行下一轮的磁盘请求 由于未实现单独的io调度器这里会造成长时间的io等待
if (ahci_req_queue.request_count > 0)
ahci_query_disk();
}
static long ahci_query_disk()
{
wait_queue_node_t *wait_queue_tmp = container_of(list_next(&ahci_req_queue.wait_queue_list.wait_list), wait_queue_node_t, wait_list);
struct ahci_request_packet_t *pack = (struct ahci_request_packet_t *)container_of(wait_queue_tmp, struct block_device_request_packet, wait_queue);
ahci_req_queue.in_service = (struct block_device_request_packet *)pack;
list_del(&(ahci_req_queue.in_service->wait_queue.wait_list));
--ahci_req_queue.request_count;
// kdebug("ahci_query_disk");
long ret_val = 0;
switch (pack->blk_pak.cmd)
{
case AHCI_CMD_READ_DMA_EXT:
ret_val = ahci_read(&(ahci_devices[pack->ahci_ctrl_num].hba_mem->ports[pack->port_num]), pack->blk_pak.LBA_start & 0xFFFFFFFF, ((pack->blk_pak.LBA_start) >> 32) & 0xFFFFFFFF, pack->blk_pak.count, pack->blk_pak.buffer_vaddr);
break;
case AHCI_CMD_WRITE_DMA_EXT:
ret_val = ahci_write(&(ahci_devices[pack->ahci_ctrl_num].hba_mem->ports[pack->port_num]), pack->blk_pak.LBA_start & 0xFFFFFFFF, ((pack->blk_pak.LBA_start) >> 32) & 0xFFFFFFFF, pack->blk_pak.count, pack->blk_pak.buffer_vaddr);
break;
default:
kerror("Unsupport ahci command: %#05lx", pack->blk_pak.cmd);
ret_val = E_UNSUPPORTED_CMD;
break;
}
// kdebug("ahci_query_disk: retval=%d", ret_val);
// ahci_end_request();
return ret_val;
}
/**
* @brief 将请求包提交到io队列
*
* @param pack
*/
static void ahci_submit(struct ahci_request_packet_t *pack)
{
list_append(&(ahci_req_queue.wait_queue_list.wait_list), &(pack->blk_pak.wait_queue.wait_list));
++ahci_req_queue.request_count;
if (ahci_req_queue.in_service == NULL) // 当前没有正在请求的io包立即执行磁盘请求
ahci_query_disk();
}
/**
* @brief ahci驱动程序的传输函数
*
* @param gd 磁盘设备结构体
* @param cmd 控制命令
* @param base_addr 48位LBA地址
* @param count total sectors to read
* @param buf 缓冲区线性地址
* @return long
*/
static long ahci_transfer(struct blk_gendisk *gd, long cmd, uint64_t base_addr, uint64_t count, uint64_t buf)
{
struct ahci_request_packet_t *pack = NULL;
struct ahci_blk_private_data *pdata = (struct ahci_blk_private_data *)gd->private_data;
if (cmd == AHCI_CMD_READ_DMA_EXT || cmd == AHCI_CMD_WRITE_DMA_EXT)
{
pack = ahci_make_request(cmd, base_addr, count, buf, pdata->ahci_ctrl_num, pdata->ahci_port_num);
ahci_submit(pack);
}
else
return E_UNSUPPORTED_CMD;
return AHCI_SUCCESS;
}
/**
* @brief todo: io控制器函数
*
* @param cmd 命令
* @param arg 参数
* @return long
*/
static long ahci_ioctl(long cmd, long arg)
{
return 0;
}

View File

@ -0,0 +1,402 @@
#pragma once
#include <common/blk_types.h>
#include <driver/pci/pci.h>
#include <mm/mm.h>
/**
* @todo 加入io调度器当操作系统实现了多进程之后要加入这个
*
*/
#define AHCI_MAPPING_BASE SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + AHCI_MAPPING_OFFSET
#define MAX_AHCI_DEVICES 100
#define HBA_PxCMD_ST 0x0001
#define HBA_PxCMD_FRE 0x0010
#define HBA_PxCMD_FR 0x4000
#define HBA_PxCMD_CR 0x8000
#define AHCI_DEV_BUSY 0x80
#define AHCI_DEV_DRQ 0x08
#define AHCI_CMD_READ_DMA_EXT 0x25
#define AHCI_CMD_WRITE_DMA_EXT 0x30
#define HBA_PxIS_TFES (1 << 30) /* TFES - Task File Error Status */
#define AHCI_SUCCESS 0 // 请求成功
#define E_NOEMPTYSLOT 1 // 没有空闲的slot
#define E_PORT_HUNG 2 // 端口被挂起
#define E_TASK_FILE_ERROR 3 // 任务文件错误
#define E_UNSUPPORTED_CMD 4 // 不支持的命令
extern struct block_device_operation ahci_operation;
/**
* @brief 在SATA3.0规范中定义的Frame Information Structure类型
*
*/
typedef enum
{
FIS_TYPE_REG_H2D = 0x27, // Register FIS - host to device
FIS_TYPE_REG_D2H = 0x34, // Register FIS - device to host
FIS_TYPE_DMA_ACT = 0x39, // DMA activate FIS - device to host
FIS_TYPE_DMA_SETUP = 0x41, // DMA setup FIS - bidirectional
FIS_TYPE_DATA = 0x46, // Data FIS - bidirectional
FIS_TYPE_BIST = 0x58, // BIST activate FIS - bidirectional
FIS_TYPE_PIO_SETUP = 0x5F, // PIO setup FIS - device to host
FIS_TYPE_DEV_BITS = 0xA1, // Set device bits FIS - device to host
} FIS_TYPE;
/**
* @brief FIS_REG_H2D 被用于从主机向设备发送控制命令
* 注意reserved bit应当被清零
*/
typedef struct tagFIS_REG_H2D
{
// DWORD 0
uint8_t fis_type; // FIS_TYPE_REG_H2D
uint8_t pmport : 4; // Port multiplier
uint8_t rsv0 : 3; // Reserved
uint8_t c : 1; // 1: Command, 0: Control
uint8_t command; // Command register
uint8_t featurel; // Feature register, 7:0
// DWORD 1
uint8_t lba0; // LBA low register, 7:0
uint8_t lba1; // LBA mid register, 15:8
uint8_t lba2; // LBA high register, 23:16
uint8_t device; // Device register
// DWORD 2
uint8_t lba3; // LBA register, 31:24
uint8_t lba4; // LBA register, 39:32
uint8_t lba5; // LBA register, 47:40
uint8_t featureh; // Feature register, 15:8
// DWORD 3
uint8_t countl; // Count register, 7:0
uint8_t counth; // Count register, 15:8
uint8_t icc; // Isochronous command completion
uint8_t control; // Control register
// DWORD 4
uint8_t rsv1[4]; // Reserved
} FIS_REG_H2D;
// A device to host register FIS is used by the device to notify the host that some ATA register has changed.
// It contains the updated task files such as status, error and other registers.
typedef struct tagFIS_REG_D2H
{
// DWORD 0
uint8_t fis_type; // FIS_TYPE_REG_D2H
uint8_t pmport : 4; // Port multiplier
uint8_t rsv0 : 2; // Reserved
uint8_t i : 1; // Interrupt bit
uint8_t rsv1 : 1; // Reserved
uint8_t status; // Status register
uint8_t error; // Error register
// DWORD 1
uint8_t lba0; // LBA low register, 7:0
uint8_t lba1; // LBA mid register, 15:8
uint8_t lba2; // LBA high register, 23:16
uint8_t device; // Device register
// DWORD 2
uint8_t lba3; // LBA register, 31:24
uint8_t lba4; // LBA register, 39:32
uint8_t lba5; // LBA register, 47:40
uint8_t rsv2; // Reserved
// DWORD 3
uint8_t countl; // Count register, 7:0
uint8_t counth; // Count register, 15:8
uint8_t rsv3[2]; // Reserved
// DWORD 4
uint8_t rsv4[4]; // Reserved
} FIS_REG_D2H;
// This FIS is used by the host or device to send data payload. The data size can be varied.
typedef struct tagFIS_DATA
{
// DWORD 0
uint8_t fis_type; // FIS_TYPE_DATA
uint8_t pmport : 4; // Port multiplier
uint8_t rsv0 : 4; // Reserved
uint8_t rsv1[2]; // Reserved
// DWORD 1 ~ N
uint32_t data[1]; // Payload
} FIS_DATA;
// This FIS is used by the device to tell the host that its about to send or ready to receive a PIO data payload.
typedef struct tagFIS_PIO_SETUP
{
// DWORD 0
uint8_t fis_type; // FIS_TYPE_PIO_SETUP
uint8_t pmport : 4; // Port multiplier
uint8_t rsv0 : 1; // Reserved
uint8_t d : 1; // Data transfer direction, 1 - device to host
uint8_t i : 1; // Interrupt bit
uint8_t rsv1 : 1;
uint8_t status; // Status register
uint8_t error; // Error register
// DWORD 1
uint8_t lba0; // LBA low register, 7:0
uint8_t lba1; // LBA mid register, 15:8
uint8_t lba2; // LBA high register, 23:16
uint8_t device; // Device register
// DWORD 2
uint8_t lba3; // LBA register, 31:24
uint8_t lba4; // LBA register, 39:32
uint8_t lba5; // LBA register, 47:40
uint8_t rsv2; // Reserved
// DWORD 3
uint8_t countl; // Count register, 7:0
uint8_t counth; // Count register, 15:8
uint8_t rsv3; // Reserved
uint8_t e_status; // New value of status register
// DWORD 4
uint16_t tc; // Transfer count
uint8_t rsv4[2]; // Reserved
} FIS_PIO_SETUP;
typedef struct tagFIS_DMA_SETUP
{
// DWORD 0
uint8_t fis_type; // FIS_TYPE_DMA_SETUP
uint8_t pmport : 4; // Port multiplier
uint8_t rsv0 : 1; // Reserved
uint8_t d : 1; // Data transfer direction, 1 - device to host
uint8_t i : 1; // Interrupt bit
uint8_t a : 1; // Auto-activate. Specifies if DMA Activate FIS is needed
uint8_t rsved[2]; // Reserved
// DWORD 1&2
uint64_t DMAbufferID; // DMA Buffer Identifier. Used to Identify DMA buffer in host memory.
// SATA Spec says host specific and not in Spec. Trying AHCI spec might work.
// DWORD 3
uint32_t rsvd; // More reserved
// DWORD 4
uint32_t DMAbufOffset; // Byte offset into buffer. First 2 bits must be 0
// DWORD 5
uint32_t TransferCount; // Number of bytes to transfer. Bit 0 must be 0
// DWORD 6
uint32_t resvd; // Reserved
} FIS_DMA_SETUP;
typedef volatile struct tagHBA_PORT
{
uint64_t clb; // 0x00, command list base address, 1K-byte aligned
uint64_t fb; // 0x08, FIS base address, 256-byte aligned
uint32_t is; // 0x10, interrupt status
uint32_t ie; // 0x14, interrupt enable
uint32_t cmd; // 0x18, command and status
uint32_t rsv0; // 0x1C, Reserved
uint32_t tfd; // 0x20, task file data
uint32_t sig; // 0x24, signature
uint32_t ssts; // 0x28, SATA status (SCR0:SStatus)
uint32_t sctl; // 0x2C, SATA control (SCR2:SControl)
uint32_t serr; // 0x30, SATA error (SCR1:SError)
uint32_t sact; // 0x34, SATA active (SCR3:SActive)
uint32_t ci; // 0x38, command issue
uint32_t sntf; // 0x3C, SATA notification (SCR4:SNotification)
uint32_t fbs; // 0x40, FIS-based switch control
uint32_t rsv1[11]; // 0x44 ~ 0x6F, Reserved
uint32_t vendor[4]; // 0x70 ~ 0x7F, vendor specific
} HBA_PORT;
typedef volatile struct tagHBA_MEM
{
// 0x00 - 0x2B, Generic Host Control
uint32_t cap; // 0x00, Host capability
uint32_t ghc; // 0x04, Global host control
uint32_t is; // 0x08, Interrupt status
uint32_t pi; // 0x0C, Port implemented
uint32_t vs; // 0x10, Version
uint32_t ccc_ctl; // 0x14, Command completion coalescing control
uint32_t ccc_pts; // 0x18, Command completion coalescing ports
uint32_t em_loc; // 0x1C, Enclosure management location
uint32_t em_ctl; // 0x20, Enclosure management control
uint32_t cap2; // 0x24, Host capabilities extended
uint32_t bohc; // 0x28, BIOS/OS handoff control and status
// 0x2C - 0x9F, Reserved
uint8_t rsv[0xA0 - 0x2C];
// 0xA0 - 0xFF, Vendor specific registers
uint8_t vendor[0x100 - 0xA0];
// 0x100 - 0x10FF, Port control registers
HBA_PORT ports[32]; // 1 ~ 32
} HBA_MEM;
// There are four kinds of FIS which may be sent to the host by the device as indicated in the following structure declaration.
//
typedef volatile struct tagHBA_FIS
{
// 0x00
FIS_DMA_SETUP dsfis; // DMA Setup FIS
uint8_t pad0[4];
// 0x20
FIS_PIO_SETUP psfis; // PIO Setup FIS
uint8_t pad1[12];
// 0x40
FIS_REG_D2H rfis; // Register Device to Host FIS
uint8_t pad2[4];
// 0x58
// FIS_DEV_BITS sdbfis; // Set Device Bit FIS
// 0x60
uint8_t ufis[64];
// 0xA0
uint8_t rsv[0x100 - 0xA0];
} HBA_FIS;
typedef struct tagHBA_CMD_HEADER
{
// DW0
uint8_t cfl : 5; // Command FIS length in DWORDS, 2 ~ 16
uint8_t a : 1; // ATAPI
uint8_t w : 1; // Write, 1: H2D, 0: D2H
uint8_t p : 1; // Prefetchable
uint8_t r : 1; // Reset
uint8_t b : 1; // BIST
uint8_t c : 1; // Clear busy upon R_OK
uint8_t rsv0 : 1; // Reserved
uint8_t pmp : 4; // Port multiplier port
uint16_t prdtl; // Physical region descriptor table length in entries
// DW1
volatile uint32_t prdbc; // Physical region descriptor byte count transferred
// DW2, 3
uint64_t ctba; // Command table descriptor base address
// DW4 - 7
uint32_t rsv1[4]; // Reserved
} HBA_CMD_HEADER;
typedef struct tagHBA_PRDT_ENTRY
{
uint64_t dba; // Data base address
uint32_t rsv0; // Reserved
// DW3
uint32_t dbc : 22; // Byte count, 4M max
uint32_t rsv1 : 9; // Reserved
uint32_t i : 1; // Interrupt on completion
} HBA_PRDT_ENTRY;
typedef struct tagHBA_CMD_TBL
{
// 0x00
uint8_t cfis[64]; // Command FIS
// 0x40
uint8_t acmd[16]; // ATAPI command, 12 or 16 bytes
// 0x50
uint8_t rsv[48]; // Reserved
// 0x80
HBA_PRDT_ENTRY prdt_entry[1]; // Physical region descriptor table entries, 0 ~ 65535
} HBA_CMD_TBL;
struct ahci_device_t
{
uint32_t type; // 设备类型
struct pci_device_structure_header_t *dev_struct;
HBA_MEM *hba_mem;
} ahci_devices[MAX_AHCI_DEVICES];
#define SATA_SIG_ATA 0x00000101 // SATA drive
#define SATA_SIG_ATAPI 0xEB140101 // SATAPI drive
#define SATA_SIG_SEMB 0xC33C0101 // Enclosure management bridge
#define SATA_SIG_PM 0x96690101 // Port multiplier
#define AHCI_DEV_NULL 0
#define AHCI_DEV_SATA 1
#define AHCI_DEV_SEMB 2
#define AHCI_DEV_PM 3
#define AHCI_DEV_SATAPI 4
#define HBA_PORT_IPM_ACTIVE 1
#define HBA_PORT_DET_PRESENT 3
struct ahci_request_packet_t
{
struct block_device_request_packet blk_pak; // 块设备请求包
uint8_t ahci_ctrl_num; // ahci控制器号 默认应为0
uint8_t port_num; // ahci的设备端口号
};
/**
* @brief 初始化ahci模块
*
*/
void ahci_init();
/**
* @brief 检测端口连接的设备的类型
*
* @param device_num ahci设备号
*/
static void ahci_probe_port(const uint32_t device_num);
/**
* @brief read data from SATA device using 48bit LBA address
*
* @param port HBA PORT
* @param startl low 32bits of start addr
* @param starth high 32bits of start addr
* @param count total sectors to read
* @param buf buffer
* @return true done
* @return false failed
*/
static bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, uint64_t buf);
/**
* @brief write data to SATA device using 48bit LBA address
*
* @param port HBA PORT
* @param startl low 32bits of start addr
* @param starth high 32bits of start addr
* @param count total sectors to read
* @param buf buffer
* @return true done
* @return false failed
*/
static bool ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count,
uint64_t buf);
void ahci_end_request();

View File

@ -0,0 +1,81 @@
#include "ata.h"
#include <common/kprint.h>
#include <driver/interrupt/apic/apic.h>
struct apic_IO_APIC_RTE_entry entry;
/**
* @brief 硬盘中断上半部处理程序
*
* @param irq_num
* @param param
* @param regs
*/
void ata_disk_handler(ul irq_num, ul param, struct pt_regs *regs)
{
struct ata_identify_device_data info;
kdebug("irq_num=%ld", irq_num);
// 从端口读入磁盘配置信息
io_insw(PORT_DISK0_DATA, &info, 256);
kdebug("General_Config=%#018lx", info.General_Config);
printk("Serial number:");
unsigned char buf[64];
int js=0;
//printk("%d", info.Serial_Number);
for(int i = 0;i<10;i++)
{
buf[js++]=(info.Serial_Number[i] & 0xff);
}
buf[js] = '\0';
printk("%s", buf);
printk("\n");
}
hardware_intr_controller ata_disk_intr_controller =
{
.enable = apic_ioapic_enable,
.disable = apic_ioapic_disable,
.install = apic_ioapic_install,
.uninstall = apic_ioapic_uninstall,
.ack = apic_ioapic_edge_ack,
};
/**
* @brief 初始化ATA磁盘驱动程序
*
*/
void ata_init()
{
entry.vector = 0x2e;
entry.deliver_mode = IO_APIC_FIXED;
entry.dest_mode = DEST_PHYSICAL;
entry.deliver_status = IDLE;
entry.polarity = POLARITY_HIGH;
entry.remote_IRR = IRR_RESET;
entry.trigger_mode = EDGE_TRIGGER;
entry.mask = MASKED;
entry.reserved = 0;
entry.destination.physical.reserved1 = 0;
entry.destination.physical.reserved2 = 0;
entry.destination.physical.phy_dest = 0; // 投递至BSP
irq_register(entry.vector, &entry, &ata_disk_handler, 0, &ata_disk_intr_controller, "ATA Disk 1");
io_out8(PORT_DISK0_STATUS_CTRL_REG, 0); // 使能中断请求
io_out8(PORT_DISK0_ERR_STATUS, 0);
io_out8(PORT_DISK0_SECTOR_CNT, 0);
io_out8(PORT_DISK0_LBA_7_0, 0);
io_out8(PORT_DISK0_LBA_15_8, 0);
io_out8(PORT_DISK0_LBA_23_16, 0);
io_out8(PORT_DISK0_DEVICE_CONFIGURE_REG, 0);
io_out8(PORT_DISK0_CONTROLLER_STATUS_CMD, 0xec); // 获取硬件设备识别信息
}

View File

@ -0,0 +1,345 @@
#pragma once
#include <common/glib.h>
// ======== PIO端口定义 ========
#define PORT_DISK0_DATA 0x1f0 // 数据
#define PORT_DISK0_ERR_STATUS 0x1f1 // 错误状态
#define PORT_DISK0_SECTOR_CNT 0x1f2 // 操作扇区数
#define PORT_DISK0_LBA_7_0 0x1f3 // 扇区号 / LBA[7:0]
#define PORT_DISK0_LBA_15_8 0x1f4 // 柱面号[7:0] / LBA[15:8]
#define PORT_DISK0_LBA_23_16 0x1f5 // 柱面号[15:8] / LBA[23:16]
#define PORT_DISK0_DEVICE_CONFIGURE_REG 0x1f6 // 设备配置寄存器
#define PORT_DISK0_CONTROLLER_STATUS_CMD 0x1f7 // 控制器状态端口 / 控制器命令端口
#define PORT_DISK0_STATUS_CTRL_REG 0x3f6 // 状态寄存器 / 控制寄存器
#define PORT_DISK1_DATA 0x170 // 数据
#define PORT_DISK1_ERR_STATUS 0x171 // 错误状态
#define PORT_DISK1_SECTOR_CNT 0x172 // 操作扇区数
#define PORT_DISK1_LBA_7_0 0x173 // 扇区号 / LBA[7:0]
#define PORT_DISK1_LBA_15_8 0x174 // 柱面号[7:0] / LBA[15:8]
#define PORT_DISK1_LBA_23_16 0x175 // 柱面号[15:8] / LBA[23:16]
#define PORT_DISK1_DEVICE_CONFIGURE_REG 0x176 // 设备配置寄存器
#define PORT_DISK1_CONTROLLER_STATUS_CMD 0x177 // 控制器状态端口 / 控制器命令端口
#define PORT_DISK1_STATUS_CTRL_REG 0x376 // 状态寄存器 / 控制寄存器
// ======= 状态寄存器的状态位 ==========
#define DISK_STATUS_BUSY (1 << 7) // 控制器忙
#define DISK_STATUS_READY (1 << 6) // 驱动器准备就绪
#define DISK_STATUS_SEEK (1 << 4) // 驱动器寻道
#define DISK_STATUS_DATA_REQ (1 << 3) // 数据请求
#define DISK_STATUS_DATA_ERROR (1 << 0) // 命令执行错误
/**
* @brief 执行0xec指令返回的512bytes的硬件设备识别信息
* 位于ATA8-ACS中 Table-22
*/
struct ata_identify_device_data
{
// 0 General configuration bit-significant information
unsigned short General_Config;
// 1 Obsolete
unsigned short Obsolete0;
// 2 Specific configuration
unsigned short Specific_Coinfig;
// 3 Obsolete
unsigned short Obsolete1;
// 4-5 Retired
unsigned short Retired0[2];
// 6 Obsolete
unsigned short Obsolete2;
// 7-8 Reserved for the CompactFlash Association
unsigned short CompactFlash[2];
// 9 Retired
unsigned short Retired1;
// 10-19 Serial number (20 ASCII characters)
unsigned short Serial_Number[10];
// 20-21 Retired
unsigned short Retired2[2];
// 22 Obsolete
unsigned short Obsolete3;
// 23-26 Firmware revision(8 ASCII characters)
unsigned short Firmware_Version[4];
// 27-46 Model number (40 ASCII characters)
unsigned short Model_Number[20];
// 47 15:8 80h
// 7:0 00h=Reserved
// 01h-FFh = Maximumnumber of logical sectors that shall be transferred per DRQ data block on READ/WRITE MULTIPLE commands
unsigned short Max_logical_transferred_per_DRQ;
// 48 Trusted Computing feature set options
unsigned short Trusted_Computing_feature_set_options;
// 49 Capabilities
unsigned short Capabilities0;
// 50 Capabilities
unsigned short Capabilities1;
// 51-52 Obsolete
unsigned short Obsolete4[2];
// 53 15:8 Free-fall Control Sensitivity
// 7:3 Reserved
// 2 the fields reported in word 88 are valid
// 1 the fields reported in words (70:64) are valid
unsigned short Report_88_70to64_valid;
// 54-58 Obsolete
unsigned short Obsolete5[5];
// 59 15:9 Reserved
// 8 Multiple sector setting is valid
// 7:0 xxh current setting for number of logical sectors that shall be transferred per DRQ data block on READ/WRITE Multiple commands
unsigned short Mul_Sec_Setting_Valid;
// 60-61 Total number of user addresssable logical sectors for 28bit CMD
unsigned short Addressable_Logical_Sectors_for_28[2];
// 62 Obsolete
unsigned short Obsolete6;
// 63 15:11 Reserved
// 10:8=1 Multiword DMA mode 210 is selected
// 7:3 Reserved
// 2:0=1 Multiword DMA mode 210 and below are supported
unsigned short MultWord_DMA_Select;
// 64 15:8 Reserved
// 7:0 PIO mdoes supported
unsigned short PIO_mode_supported;
// 65 Minimum Multiword DMA transfer cycle time per word
unsigned short Min_MulWord_DMA_cycle_time_per_word;
// 66 Manufacturer`s recommended Multiword DMA transfer cycle time
unsigned short Manufacture_Recommend_MulWord_DMA_cycle_time;
// 67 Minimum PIO transfer cycle time without flow control
unsigned short Min_PIO_cycle_time_Flow_Control;
// 68 Minimum PIO transfer cycle time with IORDY flow control
unsigned short Min_PIO_cycle_time_IOREDY_Flow_Control;
// 69-70 Reserved
unsigned short Reserved1[2];
// 71-74 Reserved for the IDENTIFY PACKET DEVICE command
unsigned short Reserved2[4];
// 75 Queue depth
unsigned short Queue_depth;
// 76 Serial ATA Capabilities
unsigned short SATA_Capabilities;
// 77 Reserved for Serial ATA
unsigned short Reserved3;
// 78 Serial ATA features Supported
unsigned short SATA_features_Supported;
// 79 Serial ATA features enabled
unsigned short SATA_features_enabled;
// 80 Major Version number
unsigned short Major_Version;
// 81 Minor version number
unsigned short Minor_Version;
// 82 Commands and feature sets supported
unsigned short Cmd_feature_sets_supported0;
// 83 Commands and feature sets supported
unsigned short Cmd_feature_sets_supported1;
// 84 Commands and feature sets supported
unsigned short Cmd_feature_sets_supported2;
// 85 Commands and feature sets supported or enabled
unsigned short Cmd_feature_sets_supported3;
// 86 Commands and feature sets supported or enabled
unsigned short Cmd_feature_sets_supported4;
// 87 Commands and feature sets supported or enabled
unsigned short Cmd_feature_sets_supported5;
// 88 15 Reserved
// 14:8=1 Ultra DMA mode 6543210 is selected
// 7 Reserved
// 6:0=1 Ultra DMA mode 6543210 and below are suported
unsigned short Ultra_DMA_modes;
// 89 Time required for Normal Erase mode SECURITY ERASE UNIT command
unsigned short Time_required_Erase_CMD;
// 90 Time required for an Enhanced Erase mode SECURITY ERASE UNIT command
unsigned short Time_required_Enhanced_CMD;
// 91 Current APM level value
unsigned short Current_APM_level_Value;
// 92 Master Password Identifier
unsigned short Master_Password_Identifier;
// 93 Hardware resset result.The contents of bits (12:0) of this word shall change only during the execution of a hardware reset.
unsigned short HardWare_Reset_Result;
// 94 Current AAM value
// 15:8 Vendors recommended AAM value
// 7:0 Current AAM value
unsigned short Current_AAM_value;
// 95 Stream Minimum Request Size
unsigned short Stream_Min_Request_Size;
// 96 Streaming Transger Time-DMA
unsigned short Streaming_Transger_time_DMA;
// 97 Streaming Access Latency-DMA and PIO
unsigned short Streaming_Access_Latency_DMA_PIO;
// 98-99 Streaming Performance Granularity (DWord)
unsigned short Streaming_Performance_Granularity[2];
// 100-103 Total Number of User Addressable Logical Sectors for 48-bit commands (QWord)
unsigned short Total_user_LBA_for_48_Address_Feature_set[4];
// 104 Streaming Transger Time-PIO
unsigned short Streaming_Transfer_Time_PIO;
// 105 Reserved
unsigned short Reserved4;
// 106 Physical Sector size/Logical Sector Size
unsigned short Physical_Logical_Sector_Size;
// 107 Inter-seek delay for ISO-7779 acoustic testing in microseconds
unsigned short Inter_seek_delay;
// 108-111 World wide name
unsigned short World_wide_name[4];
// 112-115 Reserved
unsigned short Reserved5[4];
// 116 Reserved for TLC
unsigned short Reserved6;
// 117-118 Logical sector size (DWord)
unsigned short Words_per_Logical_Sector[2];
// 119 Commands and feature sets supported (Continued from words 84:82)
unsigned short CMD_feature_Supported;
// 120 Commands and feature sets supported or enabled (Continued from words 87:85)
unsigned short CMD_feature_Supported_enabled;
// 121-126 Reserved for expanded supported and enabled settings
unsigned short Reserved7[6];
// 127 Obsolete
unsigned short Obsolete7;
// 128 Security status
unsigned short Security_Status;
// 129-159 Vendor specific
unsigned short Vendor_Specific[31];
// 160 CFA power mode
unsigned short CFA_Power_mode;
// 161-167 Reserved for the CompactFlash Association
unsigned short Reserved8[7];
// 168 Device Nominal Form Factor
unsigned short Dev_from_Factor;
// 169-175 Reserved
unsigned short Reserved9[7];
// 176-205 Current media serial number (ATA string)
unsigned short Current_Media_Serial_Number[30];
// 206 SCT Command Transport
unsigned short SCT_Cmd_Transport;
// 207-208 Reserved for CE-ATA
unsigned short Reserved10[2];
// 209 Alignment of logical blocks within a physical block
unsigned short Alignment_Logical_blocks_within_a_physical_block;
// 210-211 Write-Read-Verify Sector Count Mode 3 (DWord)
unsigned short Write_Read_Verify_Sector_Count_Mode_3[2];
// 212-213 Write-Read-Verify Sector Count Mode 2 (DWord)
unsigned short Write_Read_Verify_Sector_Count_Mode_2[2];
// 214 NV Cache Capabilities
unsigned short NV_Cache_Capabilities;
// 215-216 NV Cache Size in Logical Blocks (DWord)
unsigned short NV_Cache_Size[2];
// 217 Nominal media rotation rate
unsigned short Nominal_media_rotation_rate;
// 218 Reserved
unsigned short Reserved11;
// 219 NV Cache Options
unsigned short NV_Cache_Options;
// 220 Write-Read-Verify feature set current mode
unsigned short Write_Read_Verify_feature_set_current_mode;
// 221 Reserved
unsigned short Reserved12;
// 222 Transport major version number.
// 0000h or ffffh = device does not report version
unsigned short Transport_Major_Version_Number;
// 223 Transport Minor version number
unsigned short Transport_Minor_Version_Number;
// 224-233 Reserved for CE-ATA
unsigned short Reserved13[10];
// 234 Minimum number of 512-byte data blocks per DOWNLOAD MICROCODE command for mode 03h
unsigned short Mini_blocks_per_CMD;
// 235 Maximum number of 512-byte data blocks per DOWNLOAD MICROCODE command for mode 03h
unsigned short Max_blocks_per_CMD;
// 236-254 Reserved
unsigned short Reserved14[19];
// 255 Integrity word
// 15:8 Checksum
// 7:0 Checksum Validity Indicator
unsigned short Integrity_word;
} __attribute__((packed));
/**
* @brief 初始化ATA磁盘驱动程序
*
*/
void ata_init();

View File

@ -0,0 +1,19 @@
CFLAGS += -I .
kernel_driver_hid_subdirs:= usbhid
kernel_driver_hid_objs:= $(shell find ./*.c)
ECHO:
@echo "$@"
$(kernel_driver_hid_subdirs): ECHO
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)"
$(kernel_driver_hid_objs): ECHO
$(CC) $(CFLAGS) -c $@ -o $@.o
all: $(kernel_driver_hid_objs) $(kernel_driver_hid_subdirs)
@echo $(kernel_driver_hid_objs)

View File

@ -0,0 +1,583 @@
#include "internal.h"
#include <common/compiler.h>
#include <common/glib.h>
#include <common/hid.h>
#include <common/printk.h>
#include <common/string.h>
#include <debug/bug.h>
/*
参考文档https://www.usb.org/document-library/device-class-definition-hid-111
本文件参考了FYSOS https://github.com/fysnet/FYSOS.git
*/
static bool HID_PARSE_OUTPUT = true; // 是否输出解析信息
static char __tmp_usage_page_str[128] = {0};
static void hid_reset_parser(struct hid_parser *parser);
static const char *hid_get_usage_page_str(const int u_page);
static const char *hid_get_usage_type_str(const int page, const int type);
static const char *hid_get_collection_str(const int value);
static int *__get_report_offset(struct hid_parser *parser, const uint8_t report_id, const uint8_t report_type);
static __always_inline const struct hid_usage_pages_string *hid_get_usage_page(const int u_page);
static __always_inline const struct hid_usage_types_string *hid_get_usage_type(
const struct hid_usage_pages_string *upage, const int type);
// hid item的低2位为size
#define HID_SIZE_MASK 0x3
// 高6bit为item内容
#define HID_ITEM_MASK 0xFC
#define HID_ITEM_UPAGE 0x04 // usage page
#define HID_ITEM_USAGE 0x08 // local item
#define HID_ITEM_LOG_MIN 0x14
#define HID_ITEM_USAGE_MIN 0x18 // local item
#define HID_ITEM_LOG_MAX 0x24
#define HID_ITEM_USAGE_MAX 0x28 // local item
#define HID_ITEM_PHY_MIN 0x34
#define HID_ITEM_PHY_MAX 0x44
#define HID_ITEM_UNIT_EXP 0x54
#define HID_ITEM_UNIT 0x64
#define HID_ITEM_REP_SIZE 0x74
#define HID_ITEM_STRING 0x78 // local item?
#define HID_ITEM_REP_ID 0x84
#define HID_ITEM_REP_COUNT 0x94
static char __spaces_buf[33];
char *__spaces(uint8_t cnt)
{
static char __space_overflow_str[] = "**";
if (cnt > 32)
{
return __space_overflow_str;
}
memset(__spaces_buf, ' ', 32);
__spaces_buf[cnt] = '\0';
return __spaces_buf;
}
static __always_inline uint32_t __format_value(uint32_t value, uint8_t size)
{
switch (size)
{
case 1:
value = (uint32_t)(uint8_t)value;
break;
case 2:
value = (uint32_t)(uint16_t)value;
break;
}
return value;
}
/**
* @brief 重置parser
*
* @param parser 解析器
* @return int 状态码
*/
static void hid_reset_parser(struct hid_parser *parser)
{
memset(parser, 0, sizeof(struct hid_parser));
parser->data.report_id = 1; // we must give it a non-zero value or the parser doesn't work
}
/**
* @brief 从usage_stack中弹出第一个元素
*
* @param parser 解析器
* @return __always_inline
*/
static __always_inline void __pop_usage_stack(struct hid_parser *parser)
{
if (parser->usage_size > 0)
{
for (int js = 0; js < parser->usage_size - 1; ++js)
memmove(&parser->usage_table[js], &parser->usage_table[js + 1], sizeof(struct hid_node_t));
--parser->usage_size;
}
}
/**
* @brief 解析hid report并获取下一个数据到data字段中
* todo:(不知道为什么在qemu上面发现键盘的usage都是0xff)
*
* @param parser 解析器
* @param data 返回的数据
* @return true 解析成功
* @return false 解析失败
*/
static bool hid_parse(struct hid_parser *parser, struct hid_data_t *data)
{
bool found = false;
static uint8_t space_cnt = 0;
static bool did_collection = false;
static int item_size[4] = {0, 1, 2, 4};
// 循环解析
while (!found && (parser->pos < parser->report_desc_size))
{
// 当前parse过程还没有解析到report
if (parser->count == 0)
{
// 打印当前 report_data 的值
if (HID_PARSE_OUTPUT)
printk("\n %02X ", parser->report_desc[parser->pos]);
// 获取到report size
parser->item = parser->report_desc[parser->pos++];
parser->value = 0;
// 拷贝report的数据
memcpy(&parser->value, &parser->report_desc[parser->pos], item_size[parser->item & HID_SIZE_MASK]);
if (HID_PARSE_OUTPUT)
{
for (int i = 0; i < 4; ++i)
{
if (i < item_size[parser->item & HID_SIZE_MASK])
printk("%02X ", parser->report_desc[parser->pos + i]);
else
printk(" ");
}
}
// 将指针指向下一个item
parser->pos += item_size[parser->item & HID_SIZE_MASK];
}
switch (parser->item & HID_ITEM_MASK)
{
case HID_ITEM_UPAGE:
// 拷贝upage
parser->u_page = (int)parser->value;
if (HID_PARSE_OUTPUT)
printk("%sUsage Page (%s)", __spaces(space_cnt), hid_get_usage_page_str(parser->u_page));
// 拷贝到 usage table。由于这是一个USAGE entry因此不增加usage_size(以便后面覆盖它)
parser->usage_table[parser->usage_size].u_page = parser->u_page;
parser->usage_table[parser->usage_size].usage = 0xff;
break;
case HID_ITEM_USAGE:
// 拷贝upage到usage table中
if ((parser->item & HID_SIZE_MASK) > 2) // item大小为32字节
parser->usage_table[parser->usage_size].u_page = (int)(parser->value >> 16);
else
parser->usage_table[parser->usage_size].u_page = parser->u_page;
if (HID_PARSE_OUTPUT)
printk("%sUsage (%s)", __spaces(space_cnt),
hid_get_usage_type_str(parser->u_page, parser->value & 0xffff));
++parser->usage_size;
break;
case HID_ITEM_USAGE_MIN:
// todo: 设置usage min
if (HID_PARSE_OUTPUT)
printk("%sUsage min (%i=%s)", __spaces(space_cnt), parser->value,
hid_get_usage_type_str(parser->u_page, parser->value));
break;
case HID_ITEM_USAGE_MAX:
// todo: 设置usage max
if (HID_PARSE_OUTPUT)
printk("%sUsage max (%i=%s)", __spaces(space_cnt), parser->value,
hid_get_usage_type_str(parser->u_page, parser->value));
break;
case HID_ITEM_COLLECTION:
// 从usage table中取出第一个u_page和usage并且将他们存储在parser->data.path
parser->data.path.node[parser->data.path.size].u_page = parser->usage_table[0].u_page;
parser->data.path.node[parser->data.path.size].usage = parser->usage_table[0].usage;
++parser->data.path.size;
// 由于上面取出了元素因此将队列往前移动1个位置
__pop_usage_stack(parser);
// 获取index(如果有的话)???
if (parser->value >= 0x80)
{
kdebug("parser->value > 0x80");
parser->data.path.node[parser->data.path.size].u_page = 0xff;
parser->data.path.node[parser->data.path.size].usage = parser->value & 0x7f;
++parser->data.path.size;
}
if (HID_PARSE_OUTPUT)
{
printk("%sCollection (%s)", __spaces(space_cnt), hid_get_collection_str(parser->value));
space_cnt += 2;
}
break;
case HID_ITEM_END_COLLECTION:
--parser->data.path.size; // 为什么要--
// 删除多余的(未识别的node
if (parser->data.path.node[parser->data.path.size].u_page == 0xff)
--parser->data.path.size;
if (HID_PARSE_OUTPUT)
{
if (space_cnt >= 2)
space_cnt -= 2;
printk("%sEnd Collection", __spaces(space_cnt));
}
break;
case HID_ITEM_FEATURE:
case HID_ITEM_INPUT:
case HID_ITEM_OUTPUT:
// 找到了一个对象
found = true;
// 增加对象计数器
++parser->cnt_objects;
// 更新local items的计数
if (parser->count == 0)
parser->count = parser->report_count;
// 从usage_table获取u_page和usage将他们存储到parser.data.path
parser->data.path.node[parser->data.path.size].u_page = parser->usage_table[0].u_page;
parser->data.path.node[parser->data.path.size].usage = parser->usage_table[0].usage;
++parser->data.path.size;
// 从usage table中弹出刚刚那个node
__pop_usage_stack(parser);
// 拷贝数据到data
parser->data.type = (uint8_t)(parser->item & HID_ITEM_MASK);
parser->data.attribute = (uint8_t)parser->value;
int *offset_ptr =
__get_report_offset(parser, parser->data.report_id, (uint8_t)(parser->item & HID_ITEM_MASK));
if (unlikely(offset_ptr == NULL))
{
BUG_ON(1);
return false;
}
parser->data.offset = *offset_ptr;
// 获取pData中的对象
memcpy(data, &parser->data, sizeof(struct hid_data_t));
// 增加report offset
*offset_ptr = (*offset_ptr) + parser->data.size;
// 从path中删除最后一个节点刚刚弹出的这个节点
--parser->data.path.size;
// 减少local items计数
if (parser->count > 0)
--parser->count;
if (!did_collection)
{
if (HID_PARSE_OUTPUT)
{
if ((parser->item & HID_ITEM_MASK) == HID_ITEM_FEATURE)
printk("%sFeature ", __spaces(space_cnt));
else if ((parser->item & HID_ITEM_MASK) == HID_ITEM_INPUT)
printk("%sInput ", __spaces(space_cnt));
else if ((parser->item & HID_ITEM_MASK) == HID_ITEM_OUTPUT)
printk("%sOutut ", __spaces(space_cnt));
printk("(%s,%s,%s" /* ",%s,%s,%s,%s" */ ")", !(parser->value & (1 << 0)) ? "Data" : "Constant",
!(parser->value & (1 << 1)) ? "Array" : "Variable",
!(parser->value & (1 << 2)) ? "Absolute" : "Relative" /*,
!(parser->value & (1<<3)) ? "No Wrap" : "Wrap",
!(parser->value & (1<<4)) ? "Linear" : "Non Linear",
!(parser->value & (1<<5)) ? "Preferred State" : "No Preferred",
!(parser->value & (1<<6)) ? "No Null" : "Null State",
//!(parser->value & (1<<8)) ? "Bit Fueld" : "Buffered Bytes"
*/
);
}
did_collection = true;
}
break;
case HID_ITEM_REP_ID: // 当前item表示report id
parser->data.report_id = (uint8_t)parser->value;
if (HID_PARSE_OUTPUT)
printk("%sReport ID: %i", __spaces(space_cnt), parser->data.report_id);
break;
case HID_ITEM_REP_SIZE: // 当前item表示report size
parser->data.size = parser->value;
if (HID_PARSE_OUTPUT)
printk("%sReport size (%i)", __spaces(space_cnt), parser->data.size);
break;
case HID_ITEM_REP_COUNT:
parser->report_count = parser->value;
if (HID_PARSE_OUTPUT)
printk("%sReport count (%i)", __spaces(space_cnt), parser->report_count);
break;
case HID_ITEM_UNIT_EXP:
parser->data.unit_exp = (int8_t)parser->value;
if (parser->data.unit_exp > 7)
parser->data.unit_exp |= 0xf0;
if (HID_PARSE_OUTPUT)
printk("%sUnit Exp (%i)", __spaces(space_cnt), parser->data.unit_exp);
break;
case HID_ITEM_UNIT:
parser->data.unit = parser->value;
if (HID_PARSE_OUTPUT)
printk("%sUnit (%i)", __spaces(space_cnt), parser->data.unit);
break;
case HID_ITEM_LOG_MIN: // logical min
parser->data.logical_min = __format_value(parser->value, item_size[parser->item & HID_SIZE_MASK]);
if (HID_PARSE_OUTPUT)
printk("%sLogical Min (%i)", __spaces(space_cnt), parser->data.logical_min);
break;
case HID_ITEM_LOG_MAX:
parser->data.logical_max = __format_value(parser->value, item_size[parser->item & HID_SIZE_MASK]);
if (HID_PARSE_OUTPUT)
printk("%sLogical Max (%i)", __spaces(space_cnt), parser->data.logical_max);
break;
case HID_ITEM_PHY_MIN:
parser->data.phys_min = __format_value(parser->value, item_size[parser->item & HID_SIZE_MASK]);
if (HID_PARSE_OUTPUT)
printk("%Physical Min (%i)", __spaces(space_cnt), parser->data.phys_min);
break;
case HID_ITEM_PHY_MAX:
parser->data.phys_max = __format_value(parser->value, item_size[parser->item & HID_SIZE_MASK]);
if (HID_PARSE_OUTPUT)
printk("%Physical Max (%i)", __spaces(space_cnt), parser->data.phys_max);
break;
default:
printk("\n Found unknown item %#02X\n", parser->item & HID_ITEM_MASK);
return found;
}
}
return found;
}
/**
* @brief 解析hid report的数据
*
* @param report_data 从usb hid设备获取到hid report
* @param len report_data的大小字节
* @return int错误码
*/
int hid_parse_report(const void *report_data, const int len)
{
struct hid_parser parser = {0};
struct hid_data_t data;
hid_reset_parser(&parser);
parser.report_desc = (const uint8_t *)report_data;
parser.report_desc_size = len;
while (hid_parse(&parser, &data))
;
return 0;
}
/**
* @brief 根据usage page的id获取usage page string结构体.当u_page不属于任何已知的id时返回NULL
*
* @param u_page usage page id
* @return const struct hid_usage_pages_string * usage page string结构体
*/
static __always_inline const struct hid_usage_pages_string *hid_get_usage_page(const int u_page)
{
int i = 0;
while ((hid_usage_page_strings[i].value < u_page) && (hid_usage_page_strings[i].value < 0xffff))
++i;
if ((hid_usage_page_strings[i].value != u_page) || (hid_usage_page_strings[i].value == 0xffff))
return NULL;
else
return &hid_usage_page_strings[i];
}
/**
* @brief 从指定的upage获取指定类型的usage type结构体。当不存在时返回NULL
*
* @param upage 指定的upage
* @param type usage的类型
* @return const struct hid_usage_types_string * 目标usage type结构体。
*/
static __always_inline const struct hid_usage_types_string *hid_get_usage_type(
const struct hid_usage_pages_string *upage, const int type)
{
if (unlikely(upage == NULL || upage->types == NULL))
{
BUG_ON(1);
return NULL;
}
struct hid_usage_types_string *types = upage->types;
int i = 0;
while ((types[i].value < type) && (types[i].value != 0xffff))
++i;
if ((types[i].value != type) || (types[i].value == 0xffff))
return NULL;
return &types[i];
}
/**
* @brief 获取usage page的名称
*
* @param u_page usage page的id
* @return const char* usage page的字符串
*/
static const char *hid_get_usage_page_str(const int u_page)
{
const struct hid_usage_pages_string *upage = hid_get_usage_page(u_page);
if (unlikely(upage == NULL))
{
sprintk(__tmp_usage_page_str, "Unknown Usage Page: %#04x", u_page);
return __tmp_usage_page_str;
}
return upage->string;
}
/**
* @brief 打印usage page的指定类型的usage
*
* @param page usage page id
* @param type usage的类型
* @return const char*
*/
static const char *hid_get_usage_type_str(const int page, const int type)
{
const struct hid_usage_pages_string *upage = hid_get_usage_page(page);
if (unlikely(upage == NULL))
{
sprintk(__tmp_usage_page_str, "Unknown Usage Page: %#04x", page);
return __tmp_usage_page_str;
}
// button press, ordinal, or UTC
if (page == 0x0009)
{
sprintk(__tmp_usage_page_str, "Button number %i", type);
return __tmp_usage_page_str;
}
else if (page == 0x000a)
{
sprintk(__tmp_usage_page_str, "Ordinal %i", type);
return __tmp_usage_page_str;
}
else if (page == 0x0010)
{
sprintk(__tmp_usage_page_str, "UTC %#04X", type);
return __tmp_usage_page_str;
}
const struct hid_usage_types_string *usage_type = hid_get_usage_type(upage, type);
if (unlikely(usage_type == NULL))
{
sprintk(__tmp_usage_page_str, "Usage Page %s, with Unknown Type: %#04X", upage->string, type);
return __tmp_usage_page_str;
}
return usage_type->string;
}
/**
* @brief 输出colection字符串
*
* @param value collection的值
* @return const char*
*/
static const char *hid_get_collection_str(const int value)
{
if (value <= 0x06)
return hid_collection_str[value];
else if (value <= 0x7f)
return "Reserved";
else if (value <= 0xff)
return "Vendor-defined";
else
return "Error in get_collection_str(): value > 0xff";
}
/**
* @brief 从parser的offset table中根据report_id和report_type获取表中指向offset字段的指针
*
* @param parser 解析器
* @param report_id report_id
* @param report_type report类型
* @return int* 指向offset字段的指针
*/
static int *__get_report_offset(struct hid_parser *parser, const uint8_t report_id, const uint8_t report_type)
{
int pos = 0;
// 尝试从已有的report中获取
while ((pos < HID_MAX_REPORT) && (parser->offset_table[pos][0] != 0)) // 当offset的id不为0时
{
if ((parser->offset_table[pos][0] == report_id) && (parser->offset_table[pos][1] == report_type))
return &parser->offset_table[pos][2];
++pos;
}
// 在offset table中占用一个新的表项来存储这个report的offset
if (pos < HID_MAX_REPORT)
{
++parser->cnt_report;
parser->offset_table[pos][0] = report_id;
parser->offset_table[pos][1] = report_type;
parser->offset_table[pos][2] = 0;
return &parser->offset_table[pos][2];
}
// 当offset table满了且未找到结果的时候返回NULL
return NULL;
}
static __always_inline bool __find_object(struct hid_parser *parser, struct hid_data_t *data)
{
kdebug("target_type=%d report_id=%d, offset=%d, size=%d", data->type, data->report_id, data->offset, data->size);
struct hid_data_t found_data = {0};
while (hid_parse(parser, &found_data))
{
kdebug("size=%d, type=%d, report_id=%d, u_page=%d, usage=%d", found_data.size, found_data.type,
found_data.report_id, found_data.path.node[0].u_page, found_data.path.node[0].usage);
// 按照路径完整匹配data
if ((data->path.size > 0) && (found_data.type == data->type) &&
(memcmp(found_data.path.node, data->path.node, data->path.size * sizeof(struct hid_node_t)) == 0))
{
goto found;
}
// 通过report id以及offset匹配成功
else if ((found_data.report_id == data->report_id) && (found_data.type == data->type) &&
(found_data.offset == data->offset))
{
goto found;
}
}
return false;
found:;
memcpy(data, &found_data, sizeof(struct hid_data_t));
data->report_count = parser->report_count;
return true;
}
/**
* @brief 在hid report中寻找参数data给定的节点数据并将结果写入到data中
*
* @param hid_report hid report 数据
* @param report_size report_data的大小字节
* @param data 要寻找的节点数据。
* @return true 找到指定的节点
* @return false 未找到指定的节点
*/
bool hid_parse_find_object(const void *hid_report, const int report_size, struct hid_data_t *data)
{
struct hid_parser parser = {0};
hid_reset_parser(&parser);
parser.report_desc = hid_report;
parser.report_desc_size = report_size;
// HID_PARSE_OUTPUT = false;
printk("\nFinding Coordinate value:");
if (__find_object(&parser, data))
{
printk(" size: %i (in bits)\n"
" offset: %i (in bits)\n"
" min: %i\n"
" max: %i\n"
" attrib: 0x%02X (input, output, or feature, etc.)\n",
data->size, data->offset, data->logical_min, data->logical_max, data->attribute);
return true;
}
else
{
printk(" Did not find Coordinate value.\n");
return false;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
#pragma once
#include <common/hid.h>
extern struct hid_usage_types_string hid_usage_type001[];
extern struct hid_usage_types_string hid_usage_type002[];
extern struct hid_usage_types_string hid_usage_type003[];
extern struct hid_usage_types_string hid_usage_type004[];
extern struct hid_usage_types_string hid_usage_type005[];
extern struct hid_usage_types_string hid_usage_type006[];
extern struct hid_usage_types_string hid_usage_type007[];
extern struct hid_usage_types_string hid_usage_type008[];
extern struct hid_usage_types_string hid_usage_type00B[];
extern struct hid_usage_types_string hid_usage_type00C[];
extern struct hid_usage_types_string hid_usage_type00D[];
extern struct hid_usage_types_string hid_usage_type00F[];
extern struct hid_usage_types_string hid_usage_type014[];
extern struct hid_usage_types_string hid_usage_type040[];
extern struct hid_usage_types_string hid_usage_type080[];
extern struct hid_usage_types_string hid_usage_type082[];
extern struct hid_usage_types_string hid_usage_type083[];
extern struct hid_usage_types_string hid_usage_type084[];
extern struct hid_usage_types_string hid_usage_type085[];
extern struct hid_usage_types_string hid_usage_type086[];
extern struct hid_usage_types_string hid_usage_type087[];
extern struct hid_usage_types_string hid_usage_type08C[];
extern struct hid_usage_types_string hid_usage_type08D[];
extern struct hid_usage_types_string hid_usage_type08E[];
extern struct hid_usage_types_string hid_usage_type08F[];
extern struct hid_usage_types_string hid_usage_type090[];
extern struct hid_usage_types_string hid_usage_type091[];
extern struct hid_usage_types_string hid_usage_typeFF00[];
extern struct hid_usage_types_string hid_usage_typeFF84[];
extern struct hid_usage_types_string hid_usage_typeFF85[];
extern struct hid_usage_pages_string hid_usage_page_strings[];
extern char hid_collection_str[][64];

View File

@ -0,0 +1,15 @@
CFLAGS += -I .
kernel_driver_usbhid_objs:= $(shell find ./*.c)
ECHO:
@echo "$@"
$(kernel_driver_usbhid_objs): ECHO
$(CC) $(CFLAGS) -c $@ -o $@.o
all: $(kernel_driver_hid_objs) $(kernel_driver_hid_subdirs)
@echo $(kernel_driver_hid_objs)

View File

@ -0,0 +1,66 @@
#include "8259A.h"
#include <common/printk.h>
#include <common/kprint.h>
#include <exception/gate.h>
// 导出定义在irq.c中的中段门表
extern void (*interrupt_table[24])(void);
void init_8259A()
{
// 初始化中断门, 中断使用第0个ist
for(int i=32;i<=55;++i)
set_intr_gate(i, 0, interrupt_table[i-32]);
kinfo("Initializing 8259A...");
// 初始化主芯片
io_out8(0x20, 0x11); // 初始化主芯片的icw1
io_out8(0x21, 0x20); // 设置主芯片的中断向量号为0x20(0x20-0x27)
io_out8(0x21, 0x04); // 设置int2端口级联从芯片
io_out8(0x21, 0x01); // 设置为AEOI模式、FNM、无缓冲
// 初始化从芯片
io_out8(0xa0, 0x11);
io_out8(0xa1, 0x28); // 设置从芯片的中断向量号为0x28(0x28-0x2f)
io_out8(0xa1, 0x02); // 设置从芯片连接到主芯片的int2
io_out8(0xa1, 0x01);
// 设置ocw1, 允许所有中断请求
io_out8(0x21, 0x00);
io_out8(0xa1, 0x00);
sti();
kinfo("IRQ circuit 8259A initialized.");
}
/**
* @brief 中断服务程序
*
* @param rsp 中断栈指针
* @param number 中断号
*/
void do_IRQ(struct pt_regs *regs, ul number)
{
unsigned char x;
switch (number)
{
case 0x20: // 时钟中断信号
break;
case 0x21: // 键盘中断
x = io_in8(0x60);
printk_color(ORANGE, BLACK, "Received key irq, key code:%#018lx\n", x);
break;
default:
break;
}
if(number!=0x20)
printk_color(ORANGE, BLACK, "Received irq:%#018x\n", number);
// 向主芯片发送中断结束信号
io_out8(PIC_master, PIC_EOI);
}

View File

@ -0,0 +1,33 @@
/**
* @file 8259A.h
* @author longjin
* @brief 8259A中断芯片
* @version 0.1
* @date 2022-01-29
*
* @copyright Copyright (c) 2022
*
*/
#pragma once
#include <common/glib.h>
#include <exception/irq.h>
#define PIC_EOI 0x20
#define PIC_master 0x20 /* IO base address for master PIC */
#define PIC2_slave 0xA0 /* IO base address for slave PIC */
// 初始化8259A芯片的中断服务
void init_8259A();
/**
* @brief 中断服务程序
*
* @param rsp 中断栈指针
* @param number 中断号
*/
void do_IRQ(struct pt_regs* rsp, ul number);

View File

@ -0,0 +1,14 @@
all: pic.o
# 中断处理芯片的驱动程序
ifeq ($(PIC), _INTR_8259A_)
pic.o: 8259A/8259A.c
$(CC) $(CFLAGS) -c 8259A/8259A.c -o pic.o
else
pic.o: apic/apic.c apic_timer.o
$(CC) $(CFLAGS) -c apic/apic.c -o pic.o
apic_timer.o: apic/apic_timer.c
$(CC) $(CFLAGS) -c apic/apic_timer.c -o apic/apic_timer.o
endif

View File

@ -0,0 +1,654 @@
#include "apic.h"
#include <common/kprint.h>
#include <common/printk.h>
#include <common/cpu.h>
#include <common/glib.h>
#include <exception/gate.h>
#include <driver/acpi/acpi.h>
#include <exception/softirq.h>
#include <process/process.h>
#include <sched/sched.h>
#pragma GCC push_options
#pragma GCC optimize("O0")
// 导出定义在irq.c中的中段门表
extern void (*interrupt_table[24])(void);
static bool flag_support_apic = false;
static bool flag_support_x2apic = false;
uint8_t __apic_enable_state = APIC_XAPIC_ENABLED;
static uint local_apic_version;
static uint local_apic_max_LVT_entries;
static struct acpi_Multiple_APIC_Description_Table_t *madt;
static struct acpi_IO_APIC_Structure_t *io_apic_ICS;
static void __local_apic_xapic_init();
static void __local_apic_x2apic_init();
static __always_inline void __send_eoi()
{
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
{
__asm__ __volatile__("movq $0x00, %%rdx \n\t"
"movq $0x00, %%rax \n\t"
"movq $0x80b, %%rcx \n\t"
"wrmsr \n\t" ::
: "memory");
}
else
{
io_mfence();
__write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_EOI, 0);
io_mfence();
}
}
/**
* @brief 初始化io_apic
*
*/
void apic_io_apic_init()
{
ul madt_addr;
acpi_iter_SDT(acpi_get_MADT, &madt_addr);
madt = (struct acpi_Multiple_APIC_Description_Table_t *)madt_addr;
// kdebug("MADT->local intr controller addr=%#018lx", madt->Local_Interrupt_Controller_Address);
// kdebug("MADT->length= %d bytes", madt->header.Length);
// 寻找io apic的ICS
void *ent = (void *)(madt_addr) + sizeof(struct acpi_Multiple_APIC_Description_Table_t);
struct apic_Interrupt_Controller_Structure_header_t *header = (struct apic_Interrupt_Controller_Structure_header_t *)ent;
while (header->length > 2)
{
header = (struct apic_Interrupt_Controller_Structure_header_t *)ent;
if (header->type == 1)
{
struct acpi_IO_APIC_Structure_t *t = (struct acpi_IO_APIC_Structure_t *)ent;
// kdebug("IO apic addr = %#018lx", t->IO_APIC_Address);
io_apic_ICS = t;
break;
}
ent += header->length;
}
// kdebug("Global_System_Interrupt_Base=%d", io_apic_ICS->Global_System_Interrupt_Base);
apic_ioapic_map.addr_phys = io_apic_ICS->IO_APIC_Address;
apic_ioapic_map.virtual_index_addr = (unsigned char *)APIC_IO_APIC_VIRT_BASE_ADDR;
apic_ioapic_map.virtual_data_addr = (uint *)(APIC_IO_APIC_VIRT_BASE_ADDR + 0x10);
apic_ioapic_map.virtual_EOI_addr = (uint *)(APIC_IO_APIC_VIRT_BASE_ADDR + 0x40);
// kdebug("(ul)apic_ioapic_map.virtual_index_addr=%#018lx", (ul)apic_ioapic_map.virtual_index_addr);
// 填写页表,完成地址映射
mm_map_phys_addr((ul)apic_ioapic_map.virtual_index_addr, apic_ioapic_map.addr_phys, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
// 设置IO APIC ID 为0x0f000000
*apic_ioapic_map.virtual_index_addr = 0x00;
io_mfence();
*apic_ioapic_map.virtual_data_addr = 0x0f000000;
io_mfence();
// kdebug("I/O APIC ID:%#010x", ((*apic_ioapic_map.virtual_data_addr) >> 24) & 0xff);
io_mfence();
// 获取IO APIC Version
*apic_ioapic_map.virtual_index_addr = 0x01;
io_mfence();
kdebug("IO APIC Version=%d, Max Redirection Entries=%d", *apic_ioapic_map.virtual_data_addr & 0xff, (((*apic_ioapic_map.virtual_data_addr) >> 16) & 0xff) + 1);
// 初始化RTE表项将所有RTE表项屏蔽
for (int i = 0x10; i < 0x40; i += 2)
{
// 以0x20为起始中断向量号初始化RTE
apic_ioapic_write_rte(i, 0x10020 + ((i - 0x10) >> 1));
}
// 不需要手动启动IO APIC只要初始化了RTE寄存器之后io apic就会自动启用了。
// 而且不是每台电脑都有RCBA寄存器因此不需要手动启用IO APIC
}
/**
* @brief 初始化AP处理器的Local apic
*
*/
void apic_init_ap_core_local_apic()
{
kinfo("Initializing AP-core's local apic...");
uint eax, edx;
// 启用xAPIC 和x2APIC
uint64_t ia32_apic_base = rdmsr(0x1b);
ia32_apic_base |= (1 << 11);
if (flag_support_x2apic) // 如果支持x2apic则启用
{
ia32_apic_base |= (1 << 10);
wrmsr(0x1b, ia32_apic_base);
}
ia32_apic_base = rdmsr(0x1b);
eax = ia32_apic_base & 0xffffffff;
// 检测是否成功启用xAPIC和x2APIC
if ((eax & 0xc00) == 0xc00)
kinfo("xAPIC & x2APIC enabled!");
else if ((eax & 0x800) == 0x800)
kinfo("Only xAPIC enabled!");
else
kerror("Both xAPIC and x2APIC are not enabled.");
// 设置SVR寄存器开启local APIC、禁止EOI广播
if (flag_support_x2apic) // 当前为x2APIC
__local_apic_x2apic_init();
else // 当前为xapic
__local_apic_xapic_init();
}
/**
* @brief 当前使用xapic来初始化local apic
*
*/
static void __local_apic_xapic_init()
{
__apic_enable_state = APIC_XAPIC_ENABLED;
// 设置svr的 apic软件使能位
uint64_t qword = *(uint64_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_SVR);
qword |= (1 << 8);
*(uint64_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_SVR) = qword;
qword = *(uint64_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_SVR);
if (qword & 0x100)
kinfo("APIC Software Enabled.");
if (qword & 0x1000)
kinfo("EOI-Broadcast Suppression Enabled.");
// 从 Local APIC Version register 获取Local APIC Version
qword = *(uint64_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_Version);
qword &= 0xffffffff;
local_apic_max_LVT_entries = ((qword >> 16) & 0xff) + 1;
local_apic_version = qword & 0xff;
kdebug("local APIC Version:%#010x,Max LVT Entry:%#010x,SVR(Suppress EOI Broadcast):%#04x\t", local_apic_version, local_apic_max_LVT_entries, (qword >> 24) & 0x1);
if ((qword & 0xff) < 0x10)
{
kdebug("82489DX discrete APIC");
}
else if (((qword & 0xff) >= 0x10) && ((qword & 0xff) <= 0x15))
kdebug("Integrated APIC.");
io_mfence();
// 如果写入这里的话,在有的机器上面会报错
// *(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_CMCI) = APIC_LVT_INT_MASKED;
io_mfence();
*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER) = APIC_LVT_INT_MASKED;
io_mfence();
*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL) = APIC_LVT_INT_MASKED;
io_mfence();
*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR) = APIC_LVT_INT_MASKED;
io_mfence();
*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT0) = APIC_LVT_INT_MASKED;
io_mfence();
*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT1) = APIC_LVT_INT_MASKED;
io_mfence();
*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_ERROR) = APIC_LVT_INT_MASKED;
io_mfence();
kdebug("All LVT Masked");
}
/**
* @brief 当前使用x2apic来初始化local apic
*
*/
static void __local_apic_x2apic_init()
{
__apic_enable_state = APIC_X2APIC_ENABLED;
uint32_t eax, edx;
__asm__ __volatile__("movq $0x80f, %%rcx \n\t"
"rdmsr \n\t"
"bts $8, %%rax \n\t"
// "bts $12, %%rax \n\t"
"movq $0x80f, %%rcx \n\t"
"wrmsr \n\t"
"movq $0x80f , %%rcx \n\t"
"rdmsr \n\t"
: "=a"(eax), "=d"(edx)::"memory");
if (eax & 0x100)
kinfo("APIC Software Enabled.");
if (eax & 0x1000)
kinfo("EOI-Broadcast Suppression Enabled.");
// 获取Local APIC Version
// 0x803处是 Local APIC Version register
__asm__ __volatile__("movq $0x803, %%rcx \n\t"
"rdmsr \n\t"
: "=a"(eax), "=d"(edx)::"memory");
local_apic_max_LVT_entries = ((eax >> 16) & 0xff) + 1;
local_apic_version = eax & 0xff;
kdebug("local APIC Version:%#010x,Max LVT Entry:%#010x,SVR(Suppress EOI Broadcast):%#04x\t", local_apic_version, local_apic_max_LVT_entries, (eax >> 24) & 0x1);
if ((eax & 0xff) < 0x10)
kdebug("82489DX discrete APIC");
else if (((eax & 0xff) >= 0x10) && ((eax & 0xff) <= 0x15))
kdebug("Integrated APIC.");
// 由于尚未配置LVT对应的处理程序因此先屏蔽所有的LVT
__asm__ __volatile__( // "movq $0x82f, %%rcx \n\t" // CMCI
// "wrmsr \n\t"
"movq $0x832, %%rcx \n\t" // Timer
"wrmsr \n\t"
"movq $0x833, %%rcx \n\t" // Thermal Monitor
"wrmsr \n\t"
"movq $0x834, %%rcx \n\t" // Performance Counter
"wrmsr \n\t"
"movq $0x835, %%rcx \n\t" // LINT0
"wrmsr \n\t"
"movq $0x836, %%rcx \n\t" // LINT1
"wrmsr \n\t"
"movq $0x837, %%rcx \n\t" // Error
"wrmsr \n\t"
:
: "a"(0x10000), "d"(0x00)
: "memory");
kdebug("All LVT Masked");
}
/**
* @brief 初始化local apic
*
*/
void apic_local_apic_init()
{
uint64_t ia32_apic_base = rdmsr(0x1b);
// kdebug("apic base=%#018lx", (ia32_apic_base & 0x1FFFFFFFFFF000));
// 映射Local APIC 寄存器地址
mm_map_phys_addr(APIC_LOCAL_APIC_VIRT_BASE_ADDR, (ia32_apic_base & 0x1FFFFFFFFFFFFF), PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
uint a, b, c, d;
cpu_cpuid(1, 0, &a, &b, &c, &d);
// kdebug("CPUID 0x01, eax:%#010lx, ebx:%#010lx, ecx:%#010lx, edx:%#010lx", a, b, c, d);
// 判断是否支持APIC和xAPIC
if ((1 << 9) & d)
{
flag_support_apic = true;
kdebug("This computer support APIC&xAPIC");
}
else
{
flag_support_apic = false;
kerror("This computer does not support APIC&xAPIC");
while (1)
;
}
// 判断是否支持x2APIC
if ((1 << 21) & c)
{
flag_support_x2apic = true;
kdebug("This computer support x2APIC");
}
else
{
flag_support_x2apic = false;
kwarn("This computer does not support x2APIC");
}
uint eax, edx;
// 启用xAPIC 和x2APIC
ia32_apic_base = rdmsr(0x1b);
ia32_apic_base |= (1 << 11);
if (flag_support_x2apic) // 如果支持x2apic则启用
{
ia32_apic_base |= (1 << 10);
wrmsr(0x1b, ia32_apic_base);
}
ia32_apic_base = rdmsr(0x1b);
eax = ia32_apic_base & 0xffffffff;
// 检测是否成功启用xAPIC和x2APIC
if ((eax & 0xc00) == 0xc00)
kinfo("xAPIC & x2APIC enabled!");
else if ((eax & 0x800) == 0x800)
kinfo("Only xAPIC enabled!");
else
kerror("Both xAPIC and x2APIC are not enabled.");
// 设置SVR寄存器开启local APIC、禁止EOI广播
if (flag_support_x2apic) // 当前为x2APIC
__local_apic_x2apic_init();
else // 当前为xapic
__local_apic_xapic_init();
// 获取Local APIC的基础信息 参见英特尔开发手册Vol3A 10-39
// Table 10-6. Local APIC Register Address Map Supported by x2APIC
// 获取 Local APIC ID
// 0x802处是x2APIC ID 位宽32bits 的 Local APIC ID register
/*
__asm__ __volatile__("movq $0x802, %%rcx \n\t"
"rdmsr \n\t"
: "=a"(eax), "=d"(edx)::"memory");
*/
// kdebug("get Local APIC ID: edx=%#010x, eax=%#010x", edx, eax);
// kdebug("local_apic_id=%#018lx", *(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_ID));
}
/**
* @brief 初始化apic控制器
*
*/
int apic_init()
{
// 初始化中断门, 中断使用rsp0防止在软中断时发生嵌套然后处理器重新加载导致数据被抹掉
for (int i = 32; i <= 55; ++i)
set_intr_gate(i, 0, interrupt_table[i - 32]);
// 设置local apic中断门
for (int i = 150; i < 160; ++i)
set_intr_gate(i, 0, local_apic_interrupt_table[i - 150]);
// 屏蔽类8259A芯片
io_out8(0x21, 0xff);
io_out8(0xa1, 0xff);
// 写入8259A pic的EOI位
io_out8(0x20, 0x20);
io_out8(0xa0, 0x20);
kdebug("8259A Masked.");
// enable IMCR
io_out8(0x22, 0x70);
io_out8(0x23, 0x01);
apic_local_apic_init();
apic_io_apic_init();
// get RCBA address
io_out32(0xcf8, 0x8000f8f0);
uint32_t RCBA_phys = io_in32(0xcfc);
// 获取RCBA寄存器的地址
if (RCBA_phys > 0xfec00000 && RCBA_phys < 0xfee00000)
RCBA_vaddr = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + RCBA_phys;
else
{
RCBA_vaddr = 0;
kwarn("Cannot get RCBA address. RCBA_phys=%#010lx", RCBA_phys);
}
sti();
return 0;
}
/**
* @brief 中断服务程序
*
* @param rsp 中断栈指针
* @param number 中断向量号
*/
void do_IRQ(struct pt_regs *rsp, ul number)
{
if (number < 0x80 && number >= 32) // 以0x80为界限低于0x80的是外部中断控制器高于0x80的是Local APIC
{
// ==========外部中断控制器========
irq_desc_t *irq = &interrupt_desc[number - 32];
// 执行中断上半部处理程序
if (irq != NULL && irq->handler != NULL)
irq->handler(number, irq->parameter, rsp);
else
kwarn("Intr vector [%d] does not have a handler!");
// 向中断控制器发送应答消息
if (irq->controller != NULL && irq->controller->ack != NULL)
irq->controller->ack(number);
else
__send_eoi();
}
else if (number >= 200)
{
apic_local_apic_edge_ack(number);
{
irq_desc_t *irq = &SMP_IPI_desc[number - 200];
if (irq->handler != NULL)
irq->handler(number, irq->parameter, rsp);
}
}
else if (number >= 150 && number < 200)
{
irq_desc_t *irq = &local_apic_interrupt_desc[number - 150];
// 执行中断上半部处理程序
if (irq != NULL && irq->handler != NULL)
irq->handler(number, irq->parameter, rsp);
else
kwarn("Intr vector [%d] does not have a handler!");
// 向中断控制器发送应答消息
if (irq->controller != NULL && irq->controller->ack != NULL)
irq->controller->ack(number);
else
__send_eoi(); // 向EOI寄存器写入0x00表示结束中断
}
else
{
kwarn("do IRQ receive: %d", number);
// 忽略未知中断
return;
}
// kdebug("before softirq");
// 进入软中断处理程序
do_softirq();
// kdebug("after softirq");
// 检测当前进程是否持有自旋锁,若持有自旋锁,则不进行抢占式的进程调度
if (current_pcb->preempt_count > 0)
return;
else if (current_pcb->preempt_count < 0)
kBUG("current_pcb->preempt_count<0! pid=%d", current_pcb->pid); // should not be here
// 检测当前进程是否可被调度
if (current_pcb->flags & PF_NEED_SCHED)
{
io_mfence();
sched();
}
}
/**
* @brief 读取RTE寄存器
* 由于RTE位宽为64位而IO window寄存器只有32位因此需要两次读取
* @param index 索引值
* @return ul
*/
ul apic_ioapic_read_rte(unsigned char index)
{
// 由于处理器的乱序执行的问题,需要加入内存屏障以保证结果的正确性。
ul ret;
// 先读取高32bit
*apic_ioapic_map.virtual_index_addr = index + 1;
io_mfence();
ret = *apic_ioapic_map.virtual_data_addr;
ret <<= 32;
io_mfence();
// 读取低32bit
*apic_ioapic_map.virtual_index_addr = index;
io_mfence();
ret |= *apic_ioapic_map.virtual_data_addr;
io_mfence();
return ret;
}
/**
* @brief 写入RTE寄存器
*
* @param index 索引值
* @param value 要写入的值
*/
void apic_ioapic_write_rte(unsigned char index, ul value)
{
// 先写入低32bit
*apic_ioapic_map.virtual_index_addr = index;
io_mfence();
*apic_ioapic_map.virtual_data_addr = value & 0xffffffff;
io_mfence();
// 再写入高32bit
value >>= 32;
io_mfence();
*apic_ioapic_map.virtual_index_addr = index + 1;
io_mfence();
*apic_ioapic_map.virtual_data_addr = value & 0xffffffff;
io_mfence();
}
// =========== 中断控制操作接口 ============
void apic_ioapic_enable(ul irq_num)
{
ul index = 0x10 + ((irq_num - 32) << 1);
ul value = apic_ioapic_read_rte(index);
value &= (~0x10000UL);
apic_ioapic_write_rte(index, value);
}
void apic_ioapic_disable(ul irq_num)
{
ul index = 0x10 + ((irq_num - 32) << 1);
ul value = apic_ioapic_read_rte(index);
value |= (0x10000UL);
apic_ioapic_write_rte(index, value);
}
ul apic_ioapic_install(ul irq_num, void *arg)
{
struct apic_IO_APIC_RTE_entry *entry = (struct apic_IO_APIC_RTE_entry *)arg;
// RTE表项值写入对应的RTE寄存器
apic_ioapic_write_rte(0x10 + ((irq_num - 32) << 1), *(ul *)entry);
return 0;
}
void apic_ioapic_uninstall(ul irq_num)
{
// 将对应的RTE表项设置为屏蔽状态
apic_ioapic_write_rte(0x10 + ((irq_num - 32) << 1), 0x10000UL);
}
void apic_ioapic_level_ack(ul irq_num) // 电平触发
{
__send_eoi();
*apic_ioapic_map.virtual_EOI_addr = irq_num;
}
void apic_ioapic_edge_ack(ul irq_num) // 边沿触发
{
// 向EOI寄存器写入0x00表示结束中断
/*
uint *eoi = (uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_EOI);
*eoi = 0x00;
*/
__send_eoi();
}
/**
* @brief local apic 边沿触发应答
*
* @param irq_num
*/
void apic_local_apic_edge_ack(ul irq_num)
{
// 向EOI寄存器写入0x00表示结束中断
__send_eoi();
}
/**
* @brief 读取指定类型的 Interrupt Control Structure
*
* @param type ics的类型
* @param ret_vaddr 对应的ICS的虚拟地址数组
* @param total 返回数组的元素总个数
* @return uint
*/
uint apic_get_ics(const uint type, ul ret_vaddr[], uint *total)
{
void *ent = (void *)(madt) + sizeof(struct acpi_Multiple_APIC_Description_Table_t);
struct apic_Interrupt_Controller_Structure_header_t *header = (struct apic_Interrupt_Controller_Structure_header_t *)ent;
bool flag = false;
uint cnt = 0;
while (header->length > 2)
{
header = (struct apic_Interrupt_Controller_Structure_header_t *)ent;
if (header->type == type)
{
ret_vaddr[cnt++] = (ul)ent;
flag = true;
}
ent += header->length;
}
*total = cnt;
if (!flag)
return APIC_E_NOTFOUND;
else
return APIC_SUCCESS;
}
/**
* @brief 构造RTE Entry结构体
*
* @param entry 返回的结构体
* @param vector 中断向量
* @param deliver_mode 投递模式
* @param dest_mode 目标模式
* @param deliver_status 投递状态
* @param polarity 电平触发极性
* @param irr 远程IRR标志位只读
* @param trigger 触发模式
* @param mask 屏蔽标志位0为未屏蔽 1为已屏蔽
* @param dest_apicID 目标apicID
*/
void apic_make_rte_entry(struct apic_IO_APIC_RTE_entry *entry, uint8_t vector, uint8_t deliver_mode, uint8_t dest_mode,
uint8_t deliver_status, uint8_t polarity, uint8_t irr, uint8_t trigger, uint8_t mask, uint8_t dest_apicID)
{
entry->vector = vector;
entry->deliver_mode = deliver_mode;
entry->dest_mode = dest_mode;
entry->deliver_status = deliver_status;
entry->polarity = polarity;
entry->remote_IRR = irr;
entry->trigger_mode = trigger;
entry->mask = mask;
entry->reserved = 0;
if (dest_mode == DEST_PHYSICAL)
{
entry->destination.physical.phy_dest = dest_apicID;
entry->destination.physical.reserved1 = 0;
entry->destination.physical.reserved2 = 0;
}
else
{
entry->destination.logical.logical_dest = dest_apicID;
entry->destination.logical.reserved1 = 0;
}
}
#pragma GCC pop_options

View File

@ -0,0 +1,333 @@
#pragma once
#include <common/asm.h>
#include <process/ptrace.h>
#include <exception/irq.h>
#include <mm/mm.h>
#pragma GCC push_options
#pragma GCC optimize("O0")
#define APIC_SUCCESS 0
#define APIC_E_NOTFOUND 1
#define APIC_IO_APIC_VIRT_BASE_ADDR SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + IO_APIC_MAPPING_OFFSET
#define APIC_LOCAL_APIC_VIRT_BASE_ADDR SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + LOCAL_APIC_MAPPING_OFFSET
// 当前apic启用状态标志
extern uint8_t __apic_enable_state;
#define APIC_XAPIC_ENABLED 0
#define APIC_X2APIC_ENABLED 1
#define CURRENT_APIC_STATE (__apic_enable_state )
// ======== local apic 寄存器虚拟地址偏移量表 =======
// 0x00~0x10 Reserved.
#define LOCAL_APIC_OFFSET_Local_APIC_ID 0x20
#define LOCAL_APIC_OFFSET_Local_APIC_Version 0x30
// 0x40~0x70 Reserved.
#define LOCAL_APIC_OFFSET_Local_APIC_TPR 0x80
#define LOCAL_APIC_OFFSET_Local_APIC_APR 0x90
#define LOCAL_APIC_OFFSET_Local_APIC_PPR 0xa0
#define LOCAL_APIC_OFFSET_Local_APIC_EOI 0xb0
#define LOCAL_APIC_OFFSET_Local_APIC_RRD 0xc0
#define LOCAL_APIC_OFFSET_Local_APIC_LDR 0xd0
#define LOCAL_APIC_OFFSET_Local_APIC_DFR 0xe0
#define LOCAL_APIC_OFFSET_Local_APIC_SVR 0xf0
#define LOCAL_APIC_OFFSET_Local_APIC_ISR_31_0 0x100
#define LOCAL_APIC_OFFSET_Local_APIC_ISR_63_32 0x110
#define LOCAL_APIC_OFFSET_Local_APIC_ISR_95_64 0x120
#define LOCAL_APIC_OFFSET_Local_APIC_ISR_127_96 0x130
#define LOCAL_APIC_OFFSET_Local_APIC_ISR_159_128 0x140
#define LOCAL_APIC_OFFSET_Local_APIC_ISR_191_160 0x150
#define LOCAL_APIC_OFFSET_Local_APIC_ISR_223_192 0x160
#define LOCAL_APIC_OFFSET_Local_APIC_ISR_255_224 0x170
#define LOCAL_APIC_OFFSET_Local_APIC_TMR_31_0 0x180
#define LOCAL_APIC_OFFSET_Local_APIC_TMR_63_32 0x190
#define LOCAL_APIC_OFFSET_Local_APIC_TMR_95_64 0x1a0
#define LOCAL_APIC_OFFSET_Local_APIC_TMR_127_96 0x1b0
#define LOCAL_APIC_OFFSET_Local_APIC_TMR_159_128 0x1c0
#define LOCAL_APIC_OFFSET_Local_APIC_TMR_191_160 0x1d0
#define LOCAL_APIC_OFFSET_Local_APIC_TMR_223_192 0x1e0
#define LOCAL_APIC_OFFSET_Local_APIC_TMR_255_224 0x1f0
#define LOCAL_APIC_OFFSET_Local_APIC_IRR_31_0 0x200
#define LOCAL_APIC_OFFSET_Local_APIC_IRR_63_32 0x210
#define LOCAL_APIC_OFFSET_Local_APIC_IRR_95_64 0x220
#define LOCAL_APIC_OFFSET_Local_APIC_IRR_127_96 0x230
#define LOCAL_APIC_OFFSET_Local_APIC_IRR_159_128 0x240
#define LOCAL_APIC_OFFSET_Local_APIC_IRR_191_160 0x250
#define LOCAL_APIC_OFFSET_Local_APIC_IRR_223_192 0x260
#define LOCAL_APIC_OFFSET_Local_APIC_IRR_255_224 0x270
#define LOCAL_APIC_OFFSET_Local_APIC_ESR 0x280
// 0x290~0x2e0 Reserved.
#define LOCAL_APIC_OFFSET_Local_APIC_LVT_CMCI 0x2f0
#define LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0 0x300
#define LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32 0x310
#define LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER 0x320
#define LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL 0x330
#define LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR 0x340
#define LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT0 0x350
#define LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT1 0x360
#define LOCAL_APIC_OFFSET_Local_APIC_LVT_ERROR 0x370
// 初始计数寄存器(定时器专用)
#define LOCAL_APIC_OFFSET_Local_APIC_INITIAL_COUNT_REG 0x380
// 当前计数寄存器(定时器专用)
#define LOCAL_APIC_OFFSET_Local_APIC_CURRENT_COUNT_REG 0x390
// 0x3A0~0x3D0 Reserved.
// 分频配置寄存器(定时器专用)
#define LOCAL_APIC_OFFSET_Local_APIC_CLKDIV 0x3e0
uint32_t RCBA_vaddr = 0; // RCBA寄存器的虚拟地址
/*
1: LVT CMCI
2: LVT Timer
3: LVT Thermal Monitor
4: LVT Performace Counter
5: LVT LINT0
6: LVT LINT1
7: LVT Error
*/
/**
* LVT表项
* */
struct apic_LVT
{
uint vector : 8, // 0-7位全部置为1
delivery_mode : 3, // 第[10:8]位置为100, 表示NMI
reserved_1 : 1, // 第11位保留
delivery_status : 1, // 第12位投递状态 -> 发送挂起
polarity : 1, // 第13位电平触发极性 存在于LINT0,LINT1
remote_IRR : 1, // 第14位远程IRR标志位只读 存在于LINT0,LINT1
trigger_mode : 1, // 第15位触发模式0位边沿触发1为电平触发 存在于LINT0,LINT1
mask : 1, // 第16位屏蔽标志位0为未屏蔽 1为已屏蔽
timer_mode : 2, // 第[18:17]位定时模式。00一次性定时 01周期性定时 10指定TSC值计数 存在于定时器寄存器
reserved_2 : 13; // [31:19]位保留
} __attribute((packed)); // 取消结构体的align
/*
ICR
*/
struct INT_CMD_REG
{
unsigned int vector : 8, // 0~7
deliver_mode : 3, // 8~10
dest_mode : 1, // 11
deliver_status : 1, // 12
res_1 : 1, // 13
level : 1, // 14
trigger : 1, // 15
res_2 : 2, // 16~17
dest_shorthand : 2, // 18~19
res_3 : 12; // 20~31
union
{
struct
{
unsigned int res_4 : 24, // 32~55
dest_field : 8; // 56~63
} apic_destination;
unsigned int x2apic_destination; // 32~63
} destination;
} __attribute__((packed));
/**
* @brief I/O APIC 的中断定向寄存器的结构体
*
*/
struct apic_IO_APIC_RTE_entry
{
unsigned int vector : 8, // 0~7
deliver_mode : 3, // [10:8] 投递模式默认为NMI
dest_mode : 1, // 11 目标模式(0位物理模式1为逻辑模式)
deliver_status : 1, // 12 投递状态
polarity : 1, // 13 电平触发极性
remote_IRR : 1, // 14 远程IRR标志位只读
trigger_mode : 1, // 15 触发模式0位边沿触发1为电平触发
mask : 1, // 16 屏蔽标志位0为未屏蔽 1为已屏蔽
reserved : 15; // [31:17]位保留
union
{
// 物理模式
struct
{
unsigned int reserved1 : 24, // [55:32] 保留
phy_dest : 4, // [59:56] APIC ID
reserved2 : 4; // [63:60] 保留
} physical;
// 逻辑模式
struct
{
unsigned int reserved1 : 24, // [55:32] 保留
logical_dest : 8; // [63:56] 自定义APIC ID
} logical;
} destination;
} __attribute__((packed));
// ========== APIC的寄存器的参数定义 ==============
// 投递模式
#define LOCAL_APIC_FIXED 0
#define IO_APIC_FIXED 0
#define ICR_APIC_FIXED 0
#define IO_APIC_Lowest_Priority 1
#define ICR_Lowest_Priority 1
#define LOCAL_APIC_SMI 2
#define APIC_SMI 2
#define ICR_SMI 2
#define LOCAL_APIC_NMI 4
#define APIC_NMI 4
#define ICR_NMI 4
#define LOCAL_APIC_INIT 5
#define APIC_INIT 5
#define ICR_INIT 5
#define ICR_Start_up 6
#define IO_APIC_ExtINT 7
// 时钟模式
#define APIC_LVT_Timer_One_Shot 0
#define APIC_LVT_Timer_Periodic 1
#define APIC_LVT_Timer_TSC_Deadline 2
// 屏蔽
#define UNMASKED 0
#define MASKED 1
#define APIC_LVT_INT_MASKED 0x10000UL
// 触发模式
#define EDGE_TRIGGER 0 // 边沿触发
#define Level_TRIGGER 1 // 电平触发
// 投递模式
#define IDLE 0 // 挂起
#define SEND_PENDING 1 // 发送等待
// destination shorthand
#define ICR_No_Shorthand 0
#define ICR_Self 1
#define ICR_ALL_INCLUDE_Self 2
#define ICR_ALL_EXCLUDE_Self 3
// 投递目标模式
#define DEST_PHYSICAL 0 // 物理模式
#define DEST_LOGIC 1 // 逻辑模式
// level
#define ICR_LEVEL_DE_ASSERT 0
#define ICR_LEVEL_ASSERT 1
// 远程IRR标志位, 在处理Local APIC标志位时置位在收到处理器发来的EOI命令时复位
#define IRR_RESET 0
#define IRR_ACCEPT 1
// 电平触发极性
#define POLARITY_HIGH 0
#define POLARITY_LOW 1
struct apic_IO_APIC_map
{
// 间接访问寄存器的物理基地址
uint addr_phys;
// 索引寄存器虚拟地址
unsigned char *virtual_index_addr;
// 数据寄存器虚拟地址
uint *virtual_data_addr;
// EOI寄存器虚拟地址
uint *virtual_EOI_addr;
} apic_ioapic_map;
/**
* @brief 中断服务程序
*
* @param rsp 中断栈指针
* @param number 中断向量号
*/
void do_IRQ(struct pt_regs *rsp, ul number);
/**
* @brief 读取RTE寄存器
*
* @param index 索引值
* @return ul
*/
ul apic_ioapic_read_rte(unsigned char index);
/**
* @brief 写入RTE寄存器
*
* @param index 索引值
* @param value 要写入的值
*/
void apic_ioapic_write_rte(unsigned char index, ul value);
/**
* @brief 初始化AP处理器的Local apic
*
*/
void apic_init_ap_core_local_apic();
/**
* @brief 初始化apic控制器
*
*/
int apic_init();
/**
* @brief 读取指定类型的 Interrupt Control Structure
*
* @param type ics的类型
* @param ret_vaddr 对应的ICS的虚拟地址数组
* @param total 返回数组的元素总个数
* @return uint
*/
uint apic_get_ics(const uint type, ul ret_vaddr[], uint *total);
// =========== 中断控制操作接口 ============
void apic_ioapic_enable(ul irq_num);
void apic_ioapic_disable(ul irq_num);
ul apic_ioapic_install(ul irq_num, void *arg);
void apic_ioapic_uninstall(ul irq_num);
void apic_ioapic_level_ack(ul irq_num); // ioapic电平触发 应答
void apic_ioapic_edge_ack(ul irq_num); // ioapic边沿触发 应答
// void apic_local_apic_level_ack(ul irq_num);// local apic电平触发 应答
void apic_local_apic_edge_ack(ul irq_num); // local apic边沿触发 应答
/**
* @brief 构造RTE Entry结构体
*
* @param entry 返回的结构体
* @param vector 中断向量
* @param deliver_mode 投递模式
* @param dest_mode 目标模式
* @param deliver_status 投递状态
* @param polarity 电平触发极性
* @param irr 远程IRR标志位只读
* @param trigger 触发模式
* @param mask 屏蔽标志位0为未屏蔽 1为已屏蔽
* @param dest_apicID 目标apicID
*/
void apic_make_rte_entry(struct apic_IO_APIC_RTE_entry *entry, uint8_t vector, uint8_t deliver_mode, uint8_t dest_mode,
uint8_t deliver_status, uint8_t polarity, uint8_t irr, uint8_t trigger, uint8_t mask, uint8_t dest_apicID);
#pragma GCC pop_options

View File

@ -0,0 +1,98 @@
#include "apic_timer.h"
#include <exception/irq.h>
#include <process/process.h>
#include <common/kprint.h>
#include <sched/sched.h>
// #pragma GCC push_options
// #pragma GCC optimize("O0")
uint64_t apic_timer_ticks_result = 0;
void apic_timer_enable(uint64_t irq_num)
{
// 启动apic定时器
io_mfence();
uint64_t val = apic_timer_get_LVT();
io_mfence();
val &= (~APIC_LVT_INT_MASKED);
io_mfence();
apic_timer_write_LVT(val);
io_mfence();
}
void apic_timer_disable(uint64_t irq_num)
{
apic_timer_stop();
}
/**
* @brief 安装local apic定时器中断
*
* @param irq_num 中断向量号
* @param arg 初始计数值
* @return uint64_t
*/
uint64_t apic_timer_install(ul irq_num, void *arg)
{
// 设置div16
io_mfence();
apic_timer_stop();
io_mfence();
apic_timer_set_div(APIC_TIMER_DIVISOR);
io_mfence();
// 设置初始计数
apic_timer_set_init_cnt(*(uint64_t *)arg);
io_mfence();
// 填写LVT
apic_timer_set_LVT(APIC_TIMER_IRQ_NUM, 1, APIC_LVT_Timer_Periodic);
io_mfence();
}
void apic_timer_uninstall(ul irq_num)
{
apic_timer_write_LVT(APIC_LVT_INT_MASKED);
io_mfence();
}
hardware_intr_controller apic_timer_intr_controller =
{
.enable = apic_timer_enable,
.disable = apic_timer_disable,
.install = apic_timer_install,
.uninstall = apic_timer_uninstall,
.ack = apic_local_apic_edge_ack,
};
/**
* @brief local apic定时器的中断处理函数
*
* @param number 中断向量号
* @param param 参数
* @param regs 寄存器值
*/
void apic_timer_handler(uint64_t number, uint64_t param, struct pt_regs *regs)
{
io_mfence();
sched_update_jiffies();
io_mfence();
}
/**
* @brief 初始化local APIC定时器
*
*/
void apic_timer_init()
{
if (apic_timer_ticks_result == 0)
{
kBUG("APIC timer ticks in 5ms is equal to ZERO!");
while (1)
hlt();
}
kinfo("Initializing apic timer for cpu %d", proc_current_cpu_id);
io_mfence();
irq_register(APIC_TIMER_IRQ_NUM, &apic_timer_ticks_result, &apic_timer_handler, 0, &apic_timer_intr_controller, "apic timer");
io_mfence();
// kinfo("Successfully initialized apic timer for cpu %d", proc_current_cpu_id);
}

View File

@ -0,0 +1,108 @@
#pragma once
#include <common/unistd.h>
#include "apic.h"
extern uint64_t apic_timer_ticks_result;
// 5ms产生一次中断
#define APIC_TIMER_INTERVAL 5
#define APIC_TIMER_DIVISOR 3
#define APIC_TIMER_IRQ_NUM 151
#pragma GCC push_options
#pragma GCC optimize("O0")
/**
* @brief 设置apic定时器的分频计数
*
* @param divider 分频除数
*/
static __always_inline void apic_timer_set_div(uint64_t divider)
{
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
wrmsr(0x83e, divider);
else
__write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_CLKDIV, divider);
}
/**
* @brief 设置apic定时器的初始计数值
*
* @param init_cnt 初始计数值
*/
static __always_inline void apic_timer_set_init_cnt(uint32_t init_cnt)
{
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
wrmsr(0x838, init_cnt);
else
__write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_INITIAL_COUNT_REG, init_cnt);
}
/**
* @brief 设置apic定时器的lvt并启动定时器
*
* @param vector 中断向量号
* @param mask 是否屏蔽1屏蔽 0不屏蔽
* @param mode 计时模式
*/
static __always_inline void apic_timer_set_LVT(uint32_t vector, uint32_t mask, uint32_t mode)
{
register uint32_t val = (mode << 17) | vector | (mask ? (APIC_LVT_INT_MASKED) : 0);
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
wrmsr(0x832, val);
else
__write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER, val);
}
static __always_inline void apic_timer_write_LVT(uint32_t value)
{
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
wrmsr(0x832, value);
else
__write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER, value);
}
/**
* @brief 获取apic定时器的LVT的值
*
*/
static __always_inline uint32_t apic_timer_get_LVT()
{
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
return rdmsr(0x832);
else
return __read4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER);
}
/**
* @brief 获取apic定时器当前计数值
*
*/
static __always_inline uint32_t apic_timer_get_current()
{
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
return (uint32_t)rdmsr(0x839);
else
return __read4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_CURRENT_COUNT_REG);
}
/**
* @brief 停止apic定时器
*
*/
#define apic_timer_stop() \
do \
{ \
uint32_t val = apic_timer_get_LVT(); \
val |= APIC_LVT_INT_MASKED; \
apic_timer_write_LVT(val); \
} while (0)
/**
* @brief 初始化local APIC定时器
*
*/
void apic_timer_init();
#pragma GCC pop_options

View File

@ -0,0 +1,8 @@
all: ps2_keyboard.o
CFLAGS += -I .
ps2_keyboard.o: ps2_keyboard.c
$(CC) $(CFLAGS) -c ps2_keyboard.c -o ps2_keyboard.o

View File

@ -0,0 +1,220 @@
#include "ps2_keyboard.h"
#include <driver/interrupt/apic/apic.h>
#include <mm/mm.h>
#include <mm/slab.h>
#include <common/printk.h>
#include <filesystem/VFS/VFS.h>
#include <filesystem/devfs/devfs.h>
#include <common/wait_queue.h>
#include <common/spinlock.h>
#include <common/kfifo.h>
// 键盘输入缓冲区
static struct kfifo_t kb_buf;
// 缓冲区等待队列
static wait_queue_node_t ps2_keyboard_wait_queue;
// 缓冲区读写锁
static spinlock_t ps2_kb_buf_rw_lock;
/**
* @brief 重置ps2键盘输入缓冲区
*
* @param kbp 缓冲区对象指针
*/
static void ps2_keyboard_reset_buffer(struct kfifo_t *kbp)
{
kfifo_reset(kbp);
}
struct apic_IO_APIC_RTE_entry entry;
hardware_intr_controller ps2_keyboard_intr_controller =
{
.enable = apic_ioapic_enable,
.disable = apic_ioapic_disable,
.install = apic_ioapic_install,
.uninstall = apic_ioapic_uninstall,
.ack = apic_ioapic_edge_ack,
};
/**
* @brief 打开键盘文件
*
* @param inode 所在的inode
* @param filp 文件指针
* @return long
*/
long ps2_keyboard_open(struct vfs_index_node_t *inode, struct vfs_file_t *filp)
{
filp->private_data = &kb_buf;
ps2_keyboard_reset_buffer(&kb_buf);
return 0;
}
/**
* @brief 关闭键盘文件
*
* @param inode 所在的inode
* @param filp 文件指针
* @return long
*/
long ps2_keyboard_close(struct vfs_index_node_t *inode, struct vfs_file_t *filp)
{
filp->private_data = NULL;
ps2_keyboard_reset_buffer(&kb_buf);
return 0;
}
/**
* @brief 键盘io控制接口
*
* @param inode 所在的inode
* @param filp 键盘文件指针
* @param cmd 命令
* @param arg 参数
* @return long
*/
long ps2_keyboard_ioctl(struct vfs_index_node_t *inode, struct vfs_file_t *filp, uint64_t cmd, uint64_t arg)
{
switch (cmd)
{
case KEYBOARD_CMD_RESET_BUFFER:
ps2_keyboard_reset_buffer(&kb_buf);
break;
default:
break;
}
return 0;
}
/**
* @brief 读取键盘文件的操作接口
*
* @param filp 文件指针
* @param buf 输出缓冲区
* @param count 要读取的字节数
* @param position 读取的位置
* @return long 读取的字节数
*/
long ps2_keyboard_read(struct vfs_file_t *filp, char *buf, int64_t count, long *position)
{
// 缓冲区为空则等待
if (kfifo_empty(&kb_buf))
wait_queue_sleep_on(&ps2_keyboard_wait_queue);
count = (count > kb_buf.size) ? kb_buf.size : count;
return kfifo_out(&kb_buf, buf, count);
}
/**
* @brief 键盘文件写入接口(无作用,空)
*
* @param filp
* @param buf
* @param count
* @param position
* @return long
*/
long ps2_keyboard_write(struct vfs_file_t *filp, char *buf, int64_t count, long *position)
{
return 0;
}
/**
* @brief ps2键盘驱动的虚拟文件接口
*
*/
struct vfs_file_operations_t ps2_keyboard_fops =
{
.open = ps2_keyboard_open,
.close = ps2_keyboard_close,
.ioctl = ps2_keyboard_ioctl,
.read = ps2_keyboard_read,
.write = ps2_keyboard_write,
};
/**
* @brief 键盘中断处理函数(中断上半部)
* 将数据存入缓冲区
* @param irq_num 中断向量号
* @param param 参数
* @param regs 寄存器信息
*/
void ps2_keyboard_handler(ul irq_num, ul buf_vaddr, struct pt_regs *regs)
{
unsigned char x = io_in8(PORT_PS2_KEYBOARD_DATA);
uint8_t count = kfifo_in((struct kfifo_t*)buf_vaddr, &x, sizeof(unsigned char));
if (count == 0)
{
kwarn("ps2 keyboard buffer full.");
return;
}
wait_queue_wakeup(&ps2_keyboard_wait_queue, PROC_UNINTERRUPTIBLE);
}
/**
* @brief 初始化键盘驱动程序的函数
*
*/
void ps2_keyboard_init()
{
// ======= 初始化键盘循环队列缓冲区 ===========
// 初始化键盘循环队列缓冲区
kfifo_alloc(&kb_buf, ps2_keyboard_buffer_size, 0);
// ======== 初始化中断RTE entry ==========
entry.vector = PS2_KEYBOARD_INTR_VECTOR; // 设置中断向量号
entry.deliver_mode = IO_APIC_FIXED; // 投递模式:混合
entry.dest_mode = DEST_PHYSICAL; // 物理模式投递中断
entry.deliver_status = IDLE;
entry.trigger_mode = EDGE_TRIGGER; // 设置边沿触发
entry.polarity = POLARITY_HIGH; // 高电平触发
entry.remote_IRR = IRR_RESET;
entry.mask = MASKED;
entry.reserved = 0;
entry.destination.physical.reserved1 = 0;
entry.destination.physical.reserved2 = 0;
entry.destination.physical.phy_dest = 0; // 设置投递到BSP处理器
// ======== 初始化键盘控制器,写入配置值 =========
wait_ps2_keyboard_write();
io_out8(PORT_PS2_KEYBOARD_CONTROL, PS2_KEYBOARD_COMMAND_WRITE);
wait_ps2_keyboard_write();
io_out8(PORT_PS2_KEYBOARD_DATA, PS2_KEYBOARD_PARAM_INIT);
wait_ps2_keyboard_write();
// 执行一百万次nop等待键盘控制器把命令执行完毕
for (int i = 0; i < 1000; ++i)
for (int j = 0; j < 1000; ++j)
nop();
wait_queue_init(&ps2_keyboard_wait_queue, NULL);
// 初始化键盘缓冲区的读写锁
spin_init(&ps2_kb_buf_rw_lock);
// 注册中断处理程序
irq_register(PS2_KEYBOARD_INTR_VECTOR, &entry, &ps2_keyboard_handler, (ul)&kb_buf, &ps2_keyboard_intr_controller, "ps/2 keyboard");
// 先读一下键盘的数据,防止由于在键盘初始化之前,由于按键被按下从而导致接收不到中断。
io_in8(PORT_PS2_KEYBOARD_DATA);
// 将设备挂载到devfs
devfs_register_device(DEV_TYPE_CHAR, CHAR_DEV_STYPE_PS2_KEYBOARD, &ps2_keyboard_fops, NULL);
kinfo("ps/2 keyboard registered.");
}
/**
* @brief 键盘驱动卸载函数
*
*/
void ps2_keyboard_exit()
{
irq_unregister(PS2_KEYBOARD_INTR_VECTOR);
kfifo_free_alloc(&kb_buf);
}

View File

@ -0,0 +1,61 @@
#pragma once
#include <common/glib.h>
#define PS2_KEYBOARD_INTR_VECTOR 0x21 // 键盘的中断向量号
// 定义键盘循环队列缓冲区大小为100bytes
#define ps2_keyboard_buffer_size 8
#define KEYBOARD_CMD_RESET_BUFFER 1
#define PORT_PS2_KEYBOARD_DATA 0x60
#define PORT_PS2_KEYBOARD_STATUS 0x64
#define PORT_PS2_KEYBOARD_CONTROL 0x64
#define PS2_KEYBOARD_COMMAND_WRITE 0x60 // 向键盘发送配置命令
#define PS2_KEYBOARD_COMMAND_READ 0x20 // 读取键盘的配置值
#define PS2_KEYBOARD_PARAM_INIT 0x47 // 初始化键盘控制器的配置值
// ========= 检测键盘控制器输入/输出缓冲区是否已满
#define PS2_KEYBOARD_FLAG_OUTBUF_FULL 0x01 // 键盘的输出缓冲区已满标志位
#define PS2_KEYBOARD_FLAG_INBUF_FULL 0x02 // 键盘的输入缓冲区已满标志位
// 等待向键盘控制器写入信息完成
// todo: bugfix:在不包含ps2键盘控制器的机器上这里会卡死
#define wait_ps2_keyboard_write() while (io_in8(PORT_PS2_KEYBOARD_STATUS) & PS2_KEYBOARD_FLAG_INBUF_FULL)
// #define wait_ps2_keyboard_write() (1)
// 等待从键盘控制器读取信息完成
#define wait_ps2_keyboard_read() while (io_in8(PORT_PS2_KEYBOARD_STATUS) & PS2_KEYBOARD_FLAG_OUTBUF_FULL)
// #define wait_ps2_keyboard_read() (1)
extern struct vfs_file_operations_t ps2_keyboard_fops;
/**
* @brief 初始化键盘驱动程序的函数
*
*/
void ps2_keyboard_init();
/**
* @brief 键盘驱动卸载函数
*
*/
void ps2_keyboard_exit();
/**
* @brief 解析键盘扫描码
*
*/
void ps2_keyboard_analyze_keycode();
/**
* @brief 从缓冲队列中获取键盘扫描码
* @return 键盘扫描码
* 若缓冲队列为空则返回-1
*/
int ps2_keyboard_get_scancode();

View File

@ -0,0 +1,8 @@
all: ps2_mouse.o
CFLAGS += -I .
ps2_mouse.o: ps2_mouse.c
$(CC) $(CFLAGS) -c ps2_mouse.c -o ps2_mouse.o

View File

@ -0,0 +1,384 @@
#include "ps2_mouse.h"
#include <driver/interrupt/apic/apic.h>
#include <mm/mm.h>
#include <mm/slab.h>
#include <common/printk.h>
#include <common/kprint.h>
static struct ps2_mouse_input_buffer *ps2_mouse_buf_ptr = NULL;
static int c = 0;
struct apic_IO_APIC_RTE_entry ps2_mouse_entry;
static unsigned char ps2_mouse_id = 0;
struct ps2_mouse_packet_3bytes pak;
static int ps2_mouse_count = 0;
/**
* @brief 清空缓冲区
*
*/
static void ps2_mouse_clear_buf()
{
ps2_mouse_buf_ptr->ptr_head = ps2_mouse_buf_ptr->buffer;
ps2_mouse_buf_ptr->ptr_tail = ps2_mouse_buf_ptr->buffer;
ps2_mouse_buf_ptr->count = 0;
memset(ps2_mouse_buf_ptr->buffer, 0, ps2_mouse_buffer_size);
}
/**
* @brief 从缓冲队列中获取鼠标数据字节
* @return 鼠标数据包的字节
* 若缓冲队列为空则返回-1024
*/
static int ps2_mouse_get_scancode()
{
// 缓冲队列为空
if (ps2_mouse_buf_ptr->count == 0)
while (!ps2_mouse_buf_ptr->count)
nop();
if (ps2_mouse_buf_ptr->ptr_tail == ps2_mouse_buf_ptr->buffer + ps2_mouse_buffer_size)
ps2_mouse_buf_ptr->ptr_tail = ps2_mouse_buf_ptr->buffer;
int ret = (int)((char)(*(ps2_mouse_buf_ptr->ptr_tail)));
--(ps2_mouse_buf_ptr->count);
++(ps2_mouse_buf_ptr->ptr_tail);
// printk("count=%d", ps2_mouse_buf_ptr->count);
return ret;
}
/**
* @brief 鼠标中断处理函数(中断上半部)
* 将数据存入缓冲区
* @param irq_num 中断向量号
* @param param 参数
* @param regs 寄存器信息
*/
void ps2_mouse_handler(ul irq_num, ul param, struct pt_regs *regs)
{
// 读取鼠标输入的信息
unsigned char x = io_in8(PORT_KEYBOARD_DATA);
// 当头指针越过界时,恢复指向数组头部
if (ps2_mouse_buf_ptr->ptr_head == ps2_mouse_buf_ptr->buffer + ps2_mouse_buffer_size)
ps2_mouse_buf_ptr->ptr_head = ps2_mouse_buf_ptr->buffer;
if (ps2_mouse_buf_ptr->count >= ps2_mouse_buffer_size)
{
kwarn("ps2_mouse input buffer is full.");
return;
}
*ps2_mouse_buf_ptr->ptr_head = x;
++(ps2_mouse_buf_ptr->count);
++(ps2_mouse_buf_ptr->ptr_head);
printk("c=%d\tval = %d\n", ++c, x);
}
hardware_intr_controller ps2_mouse_intr_controller =
{
.enable = apic_ioapic_enable,
.disable = apic_ioapic_disable,
.install = apic_ioapic_install,
.uninstall = apic_ioapic_uninstall,
.ack = apic_ioapic_edge_ack,
};
/**
* @brief 从键盘控制器读取ps2_mouse id
*
* @return unsigned char 鼠标id
*/
static unsigned char ps2_mouse_get_mouse_ID()
{
// 读取鼠标的ID
io_out8(PORT_KEYBOARD_CONTROL, KEYBOARD_COMMAND_SEND_TO_PS2_MOUSE);
wait_keyboard_write();
io_out8(PORT_KEYBOARD_DATA, PS2_MOUSE_GET_ID);
wait_keyboard_write();
ps2_mouse_id = io_in8(PORT_KEYBOARD_DATA);
wait_keyboard_write();
io_in8(PORT_KEYBOARD_DATA);
for (int i = 0; i < 1000; i++)
for (int j = 0; j < 1000; j++)
nop();
return ps2_mouse_id;
}
/**
* @brief 设置鼠标采样率
*
* @param hz 采样率
*/
int ps2_mouse_set_sample_rate(unsigned int hz)
{
switch (hz)
{
case 10:
case 20:
case 40:
case 60:
case 80:
case 100:
case 200:
wait_keyboard_write();
io_out8(PORT_KEYBOARD_CONTROL, KEYBOARD_COMMAND_SEND_TO_PS2_MOUSE);
wait_keyboard_write();
io_out8(PORT_KEYBOARD_DATA, PS2_MOUSE_SET_SAMPLING_RATE);
wait_keyboard_write();
io_in8(PORT_KEYBOARD_DATA);
for (int i = 0; i < 1000; i++)
for (int j = 0; j < 1000; j++)
nop();
io_out8(PORT_KEYBOARD_CONTROL, KEYBOARD_COMMAND_SEND_TO_PS2_MOUSE);
wait_keyboard_write();
io_out8(PORT_KEYBOARD_DATA, hz);
for (int i = 0; i < 1000; i++)
for (int j = 0; j < 1000; j++)
nop();
wait_keyboard_write();
io_in8(PORT_KEYBOARD_DATA);
break;
default:
return EINVALID_ARGUMENT;
break;
}
return SUCCESS;
}
/**
* @brief 使鼠标支持滚轮
* 该模式下鼠标ID=3
*/
static int ps2_mouse_enable_scroll_wheel()
{
if (ps2_mouse_id == 3)
return SUCCESS;
ps2_mouse_set_sample_rate(200);
ps2_mouse_set_sample_rate(100);
ps2_mouse_set_sample_rate(80);
if (ps2_mouse_get_mouse_ID() != 3)
{
kerror("Cannot set mouse ID to 3");
return EFAIL;
}
// 清空缓冲区,防止解析时产生错误
ps2_mouse_clear_buf();
return SUCCESS;
}
/**
* @brief 使鼠标支持5键
* 该模式下ID=4
*/
static int ps2_mouse_enable_5keys()
{
if (ps2_mouse_id == 4)
return SUCCESS;
// 根据规范应当先启用ID=3
ps2_mouse_enable_scroll_wheel();
ps2_mouse_set_sample_rate(200);
ps2_mouse_set_sample_rate(200);
ps2_mouse_set_sample_rate(80);
if (ps2_mouse_get_mouse_ID() != 4)
{
kerror("Cannot set ps2_mouse ID to 4");
return EFAIL;
}
// 清空缓冲区,防止解析时产生错误
ps2_mouse_clear_buf();
return SUCCESS;
}
/**
* @brief 初始化鼠标驱动程序
*
*/
void ps2_mouse_init()
{
// 初始化鼠标读入队列缓冲区
ps2_mouse_buf_ptr = (struct ps2_mouse_input_buffer *)kzalloc(sizeof(struct ps2_mouse_input_buffer), 0);
ps2_mouse_buf_ptr->ptr_head = ps2_mouse_buf_ptr->buffer;
ps2_mouse_buf_ptr->ptr_tail = ps2_mouse_buf_ptr->buffer;
ps2_mouse_buf_ptr->count = 0;
memset(ps2_mouse_buf_ptr->buffer, 0, ps2_mouse_buffer_size);
// ======== 初始化中断RTE entry ==========
ps2_mouse_entry.vector = PS2_MOUSE_INTR_VECTOR; // 设置中断向量号
ps2_mouse_entry.deliver_mode = IO_APIC_FIXED; // 投递模式:混合
ps2_mouse_entry.dest_mode = DEST_PHYSICAL; // 物理模式投递中断
ps2_mouse_entry.deliver_status = IDLE;
ps2_mouse_entry.trigger_mode = EDGE_TRIGGER; // 设置边沿触发
ps2_mouse_entry.polarity = POLARITY_HIGH; // 高电平触发
ps2_mouse_entry.remote_IRR = IRR_RESET;
ps2_mouse_entry.mask = MASKED;
ps2_mouse_entry.reserved = 0;
ps2_mouse_entry.destination.physical.reserved1 = 0;
ps2_mouse_entry.destination.physical.reserved2 = 0;
ps2_mouse_entry.destination.physical.phy_dest = 0; // 设置投递到BSP处理器
// 注册中断处理程序
irq_register(PS2_MOUSE_INTR_VECTOR, &ps2_mouse_entry, &ps2_mouse_handler, (ul)ps2_mouse_buf_ptr, &ps2_mouse_intr_controller, "ps/2 mouse");
wait_keyboard_write();
io_out8(PORT_KEYBOARD_CONTROL, KEYBOARD_COMMAND_ENABLE_PS2_MOUSE_PORT); // 开启鼠标端口
for (int i = 0; i < 1000; i++)
for (int j = 0; j < 1000; j++)
nop();
wait_keyboard_write();
io_in8(PORT_KEYBOARD_DATA);
io_out8(PORT_KEYBOARD_CONTROL, KEYBOARD_COMMAND_SEND_TO_PS2_MOUSE);
wait_keyboard_write();
io_out8(PORT_KEYBOARD_DATA, PS2_MOUSE_ENABLE); // 允许鼠标设备发送数据包
wait_keyboard_write();
io_in8(PORT_KEYBOARD_DATA);
for (int i = 0; i < 1000; i++)
for (int j = 0; j < 1000; j++)
nop();
wait_keyboard_write();
io_out8(PORT_KEYBOARD_CONTROL, KEYBOARD_COMMAND_WRITE);
wait_keyboard_write();
io_out8(PORT_KEYBOARD_DATA, KEYBOARD_PARAM_INIT); // 设置键盘控制器
wait_keyboard_write();
io_in8(PORT_KEYBOARD_DATA);
for (int i = 0; i < 1000; i++)
for (int j = 0; j < 1000; j++)
nop();
wait_keyboard_write();
//ps2_mouse_enable_5keys();
ps2_mouse_get_mouse_ID();
ps2_mouse_set_sample_rate(30);
ps2_mouse_clear_buf();
kdebug("ps2_mouse ID:%d", ps2_mouse_id);
c = 0;
//ps2_mouse_count = 1;
}
/**
* @brief 卸载鼠标驱动程序
*
*/
void ps2_mouse_exit()
{
irq_unregister(PS2_MOUSE_INTR_VECTOR);
kfree((ul *)ps2_mouse_buf_ptr);
}
/**
* @brief 获取鼠标数据包
*
* @param packet 数据包的返回值
* @return int 错误码
*/
int ps2_mouse_get_packet(void *packet)
{
// if (ps2_mouse_buf_ptr->count != 0)
// kdebug("at get packet: count=%d", ps2_mouse_buf_ptr->count);
int code = 0;
switch (ps2_mouse_id)
{
case 0: // 3bytes 数据包
if (ps2_mouse_buf_ptr->count < 4)
return EFAIL;
do
{
code = ps2_mouse_get_scancode();
((struct ps2_mouse_packet_3bytes *)packet)->byte0 = (unsigned char)code;
} while (code == -1024);
do
{
code = ps2_mouse_get_scancode();
((struct ps2_mouse_packet_3bytes *)packet)->movement_x = (char)code;
} while (code == -1024);
do
{
code = ps2_mouse_get_scancode();
((struct ps2_mouse_packet_3bytes *)packet)->movement_y = (char)code;
} while (code == -1024);
return SUCCESS;
break;
case 3: // 4bytes数据包
case 4:
if (ps2_mouse_buf_ptr->count < 5)
return EFAIL;
do
{
code = ps2_mouse_get_scancode();
((struct ps2_mouse_packet_4bytes *)packet)->byte0 = (unsigned char)code;
} while (code == -1024);
do
{
code = ps2_mouse_get_scancode();
((struct ps2_mouse_packet_4bytes *)packet)->movement_x = (char)code;
} while (code == -1024);
do
{
code = ps2_mouse_get_scancode();
((struct ps2_mouse_packet_4bytes *)packet)->movement_y = (char)code;
} while (code == -1024);
do
{
code = ps2_mouse_get_scancode();
((struct ps2_mouse_packet_4bytes *)packet)->byte3 = (char)code;
} while (code == -1024);
return SUCCESS;
break;
default: // Should not reach here
kBUG("ps2_mouse_get_packet(): Invalid ps2_mouse_id!");
return EFAIL;
break;
}
return SUCCESS;
}
void analyze_mousecode()
{
if(!ps2_mouse_buf_ptr->count)
return;
else printk_color(ORANGE, BLACK, "COUNT=%d\n", ps2_mouse_buf_ptr->count);
unsigned char x = ps2_mouse_get_scancode();
switch (ps2_mouse_count)
{
case 0:
ps2_mouse_count++;
break;
case 1:
pak.byte0 = x;
ps2_mouse_count++;
break;
case 2:
pak.movement_x = (char)x;
ps2_mouse_count++;
break;
case 3:
pak.movement_y = (char)x;
ps2_mouse_count = 1;
printk_color(RED, GREEN, "(M:%02x,X:%3d,Y:%3d)\tcount=%d\n", pak.byte0, pak.movement_x, pak.movement_y, ps2_mouse_buf_ptr->count);
break;
default:
break;
}
}

View File

@ -0,0 +1,108 @@
#pragma once
#include <common/glib.h>
#define PS2_MOUSE_INTR_VECTOR 0x2c // 鼠标的中断向量号
#define KEYBOARD_COMMAND_SEND_TO_PS2_MOUSE 0xd4 // 键盘控制器向鼠标设备发送数据的命令
#define PS2_MOUSE_GET_ID 0xf2 // 获取鼠标的ID
#define PS2_MOUSE_SET_SAMPLING_RATE 0xf3 // 设置鼠标的采样率
#define PS2_MOUSE_ENABLE 0xf4 // 允许鼠标设备发送数据包
#define PS2_MOUSE_DISABLE 0xf5 // 禁止鼠标设备发送数据包
#define PS2_MOUSE_SET_DEFAULT_SAMPLING_RATE 0xf6 // 设置使用默认采样率100hz分辨率4px/mm
#define PS2_MOUSE_RESEND_LAST_PACKET 0xfe // 重新发送上一条数据包
#define PS2_MOUSE_RESET 0xff // 重启鼠标
#define KEYBOARD_COMMAND_ENABLE_PS2_MOUSE_PORT 0xa8 // 通过键盘控制器开启鼠标端口的命令
#define ps2_mouse_buffer_size 360
#define PORT_KEYBOARD_DATA 0x60
#define PORT_KEYBOARD_STATUS 0x64
#define PORT_KEYBOARD_CONTROL 0x64
#define KEYBOARD_COMMAND_WRITE 0x60 // 向键盘发送配置命令
#define KEYBOARD_COMMAND_READ 0x20 // 读取键盘的配置值
#define KEYBOARD_PARAM_INIT 0x47 // 初始化键盘控制器的配置值
// ========= 检测键盘控制器输入/输出缓冲区是否已满
#define KEYBOARD_FLAG_OUTBUF_FULL 0x01 // 键盘的输出缓冲区已满标志位
#define KEYBOARD_FLAG_INBUF_FULL 0x02 // 键盘的输入缓冲区已满标志位
// 等待向键盘控制器写入信息完成
#define wait_keyboard_write() while (io_in8(PORT_KEYBOARD_STATUS) & KEYBOARD_FLAG_INBUF_FULL)
// 等待从键盘控制器读取信息完成
#define wait_keyboard_read() while (io_in8(PORT_KEYBOARD_STATUS) & KEYBOARD_FLAG_OUTBUF_FULL)
#define SUCCESS 0
#define EINVALID_ARGUMENT -1
#define EFAIL -2
// =========== 定义鼠标数据包 ==============
// 其中x、y方向的移动值用9位二进制补码表示算上byte0中的符号位
// 目前只用到8位精度要求没那么高
struct ps2_mouse_packet_3bytes
{
unsigned char byte0; // 第0字节
// [y溢出x溢出y符号位 x符号位 1 鼠标中键, 鼠标右键,鼠标左键]
char movement_x;
char movement_y;
};
// ID = 3 或 ID = 4时采用4bytes数据包
struct ps2_mouse_packet_4bytes
{
unsigned char byte0; // 第0字节
// [y溢出x溢出y符号位 x符号位 1 鼠标中键, 鼠标右键,鼠标左键]
char movement_x;
char movement_y;
char byte3; // 当鼠标ID=3时表示z移动值
// 当鼠标ID=4时表示[0, 0, 鼠标第5键, 鼠标第4键, Z3, Z2, Z1, Z0]
// 其中,[Z3,Z0]表示鼠标滚轮滚动方向
// Z3~Z0: 0:无滚动, 1:垂直向上滚动, F:垂直向下滚动, 2:水平向右滚动, E:水平向左滚动
};
/**
* @brief 键盘循环队列缓冲区结构体
*
*/
struct ps2_mouse_input_buffer
{
unsigned char *ptr_head;
unsigned char *ptr_tail;
int count;
unsigned char buffer[ps2_mouse_buffer_size];
};
/**
* @brief 初始化鼠标驱动程序
*
*/
void ps2_mouse_init();
/**
* @brief 卸载鼠标驱动程序
*
*/
void ps2_mouse_exit();
/**
* @brief 设置鼠标采样率
*
* @param hz 采样率
*/
int ps2_mouse_set_sample_rate(unsigned int hz);
/**
* @brief 获取鼠标数据包
*
* @param packet 数据包的返回值
* @return int 错误码
*/
int ps2_mouse_get_packet(void *packet);
void analyze_mousecode();

Some files were not shown because too many files have changed in this diff Show More