新增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

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);