port kmalloc and printk to rust (#83)

* 暂时移除cbindgen

* 将lib文件夹更名为libs文件夹(解决rust的冲突)

* 实现了全局的allocator

* 实现了printk宏

* new: 完善了printk的颜色
This commit is contained in:
login
2022-11-13 16:43:58 +08:00
committed by GitHub
parent 82d2e446a4
commit fb6c29d01d
49 changed files with 207 additions and 48 deletions

19
kernel/src/libs/Makefile Normal file
View File

@ -0,0 +1,19 @@
CFLAGS += -I .
kernel_lib_subdirs:= libUI sys libELF rust_helloworld
kernel_lib_objs:= $(shell find ./*.c)
ECHO:
@echo "$@"
$(kernel_lib_subdirs): ECHO
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)"
$(kernel_lib_objs): ECHO
$(CC) $(CFLAGS) -c $@ -o $@.o
all: $(kernel_lib_objs) $(kernel_lib_subdirs)
@echo $(kernel_lib_objs)

234
kernel/src/libs/bitree.c Normal file
View File

@ -0,0 +1,234 @@
#include <common/bitree.h>
#include <mm/slab.h>
#include <common/errno.h>
#include <common/kfifo.h>
#include <common/string.h>
#include <debug/bug.h>
#define smaller(root, a, b) (root->cmp((a)->value, (b)->value) == -1)
#define equal(root, a, b) (root->cmp((a)->value, (b)->value) == 0)
#define greater(root, a, b) (root->cmp((a)->value, (b)->value) == 1)
/**
* @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))
{
if (node == NULL || cmp == NULL)
return (void*)-EINVAL;
struct bt_root_t *root = (struct bt_root_t *)kmalloc(sizeof(struct bt_root_t), 0);
memset((void *)root, 0, sizeof(struct bt_root_t));
root->bt_node = node;
root->cmp = cmp;
root->release = release;
root->size = (node == NULL) ? 0 : 1;
return root;
}
/**
* @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)
{
struct bt_node_t *node = (struct bt_node_t *)kmalloc(sizeof(struct bt_node_t), 0);
FAIL_ON_TO(node == NULL, nomem);
memset((void *)node, 0, sizeof(struct bt_node_t));
node->left = left;
node->right = right;
node->value = value;
node->parent = parent;
return node;
nomem:;
return (void*)-ENOMEM;
}
/**
* @brief 插入结点
*
* @param root 树根结点
* @param value 待插入结点的值
* @return int 返回码
*/
int bt_insert(struct bt_root_t *root, void *value)
{
if (root == NULL)
return -EINVAL;
struct bt_node_t *this_node = root->bt_node;
struct bt_node_t *last_node = NULL;
struct bt_node_t *insert_node = bt_create_node(NULL, NULL, NULL, value);
FAIL_ON_TO((uint64_t)insert_node == (uint64_t)(-ENOMEM), failed);
while (this_node != NULL)
{
last_node = this_node;
if (smaller(root, insert_node, this_node))
this_node = this_node->left;
else
this_node = this_node->right;
}
insert_node->parent = last_node;
if (unlikely(last_node == NULL))
root->bt_node = insert_node;
else
{
if (smaller(root, insert_node, last_node))
last_node->left = insert_node;
else
last_node->right = insert_node;
}
++root->size;
return 0;
failed:;
return -ENOMEM;
}
/**
* @brief 搜索值为value的结点
*
* @param value 值
* @param ret_addr 返回的结点基地址
* @return int 错误码
*/
int bt_query(struct bt_root_t *root, void *value, uint64_t *ret_addr)
{
struct bt_node_t *this_node = root->bt_node;
struct bt_node_t tmp_node = {0};
tmp_node.value = value;
// 如果返回地址为0
if (ret_addr == NULL)
return -EINVAL;
while (this_node != NULL && !equal(root, this_node, &tmp_node))
{
if (smaller(root, &tmp_node, this_node))
this_node = this_node->left;
else
this_node = this_node->right;
}
if (this_node != NULL && equal(root, this_node, &tmp_node))
{
*ret_addr = (uint64_t)this_node;
return 0;
}
else
{
// 找不到则返回-1且addr设为0
*ret_addr = NULL;
return -1;
}
}
static struct bt_node_t *bt_get_minimum(struct bt_node_t *this_node)
{
while (this_node->left != NULL)
this_node = this_node->left;
return this_node;
}
/**
* @brief 删除结点
*
* @param root 树根
* @param value 待删除结点的值
* @return int 返回码
*/
int bt_delete(struct bt_root_t *root, void *value)
{
uint64_t tmp_addr;
int retval;
// 寻找待删除结点
retval = bt_query(root, value, &tmp_addr);
if (retval != 0 || tmp_addr == NULL)
return retval;
struct bt_node_t *this_node = (struct bt_node_t *)tmp_addr;
struct bt_node_t *to_delete = NULL, *to_delete_son = NULL;
if (this_node->left == NULL || this_node->right == NULL)
to_delete = this_node;
else
{
to_delete = bt_get_minimum(this_node->right);
// 释放要被删除的值,并把下一个结点的值替换上来
root->release(this_node->value);
this_node->value = to_delete->value;
}
if (to_delete->left != NULL)
to_delete_son = to_delete->left;
else
to_delete_son = to_delete->right;
if (to_delete_son != NULL)
to_delete_son->parent = to_delete->parent;
if (to_delete->parent == NULL)
root->bt_node = to_delete_son;
else
{
if (to_delete->parent->left == to_delete)
to_delete->parent->left = to_delete_son;
else
to_delete->parent->right = to_delete_son;
}
--root->size;
// 释放最终要删除的结点的对象
kfree(to_delete);
}
/**
* @brief 释放整个二叉搜索树
*
* @param root 树的根节点
* @return int 错误码
*/
int bt_destroy_tree(struct bt_root_t *root)
{
// 新建一个kfifo缓冲区将指向结点的指针存入fifo队列
// 注:为了将指针指向的地址存入队列,我们需要对指针取地址
struct kfifo_t fifo;
kfifo_alloc(&fifo, ((root->size + 1) / 2) * sizeof(struct bt_node_t *), 0);
kfifo_in(&fifo, (void *)&(root->bt_node), sizeof(struct bt_node_t *));
// bfs
while (!kfifo_empty(&fifo))
{
// 取出队列头部的结点指针
struct bt_node_t *nd;
int count = kfifo_out(&fifo, &nd, sizeof(uint64_t));
// 将子节点加入队列
if (nd->left != NULL)
kfifo_in(&fifo, (void *)&(nd->left), sizeof(struct bt_node_t *));
if (nd->right != NULL)
kfifo_in(&fifo, (void *)&(nd->right), sizeof(struct bt_node_t *));
// 销毁当前节点
root->release(nd->value);
kfree(nd);
}
kfifo_free_alloc(&fifo);
return 0;
}

122
kernel/src/libs/cpu.c Normal file
View File

@ -0,0 +1,122 @@
#include <common/cpu.h>
#include <common/kprint.h>
#include <common/printk.h>
// #pragma GCC optimize("O0")
// cpu支持的最大cpuid指令的基础主功能号
uint Cpu_cpuid_max_Basic_mop;
// cpu支持的最大cpuid指令的扩展主功能号
uint Cpu_cpuid_max_Extended_mop;
// cpu制造商信息
char Cpu_Manufacturer_Name[17] = {0};
// 处理器名称信息
char Cpu_BrandName[49] = {0};
// 处理器家族ID
uint Cpu_Family_ID;
// 处理器扩展家族ID
uint Cpu_Extended_Family_ID;
// 处理器模式ID
uint Cpu_Model_ID;
// 处理器扩展模式ID
uint Cpu_Extended_Model_ID;
// 处理器步进ID
uint Cpu_Stepping_ID;
// 处理器类型
uint Cpu_Processor_Type;
// 处理器支持的最大物理地址可寻址地址线宽度
uint Cpu_max_phys_addrline_size;
// 处理器支持的最大线性地址可寻址地址线宽度
uint Cpu_max_linear_addrline_size;
// 处理器的tsc频率单位hz(HPET定时器在测定apic频率时顺便测定了这个值)
uint64_t Cpu_tsc_freq = 0;
struct cpu_core_info_t cpu_core_info[MAX_CPU_NUM];
void cpu_init(void)
{
// 获取处理器制造商信息
uint tmp_info[4] = {0};
cpu_cpuid(0, 0, &tmp_info[0], &tmp_info[1], &tmp_info[2], &tmp_info[3]);
// 保存CPU支持的最大cpuid指令主功能号
Cpu_cpuid_max_Basic_mop = tmp_info[0];
// 保存制造商名称
*(uint *)&Cpu_Manufacturer_Name[0] = tmp_info[1];
*(uint *)&Cpu_Manufacturer_Name[4] = tmp_info[3];
*(uint *)&Cpu_Manufacturer_Name[8] = tmp_info[2];
Cpu_Manufacturer_Name[12] = '\0';
kinfo("CPU manufacturer: %s", Cpu_Manufacturer_Name);
// 获取处理器型号信息
int count = 0;
for (uint i = 0x80000002; i < 0x80000005; ++i)
{
cpu_cpuid(i, 0, &tmp_info[0], &tmp_info[1], &tmp_info[2], &tmp_info[3]);
for (int j = 0; j <= 3; ++j)
{
*(uint *)&Cpu_BrandName[4 * count] = tmp_info[j];
++count;
}
}
Cpu_BrandName[48] = '\0';
kinfo("CPU Brand Name: %s", Cpu_BrandName);
// 使用cpuid主功能号0x01进行查询(未保存ebx ecx edx的信息具体参见白皮书)
cpu_cpuid(1, 0, &tmp_info[0], &tmp_info[1], &tmp_info[2], &tmp_info[3]);
// EAX中包含 Version Informatin Type,Family,Model,and Stepping ID
Cpu_Stepping_ID = tmp_info[0] & 0xf;
Cpu_Model_ID = (tmp_info[0] >> 4) & 0xf;
Cpu_Family_ID = (tmp_info[0] >> 8) & 0xf;
Cpu_Processor_Type = (tmp_info[0] >> 12) & 0x3;
// 14-15位保留
Cpu_Extended_Model_ID = (tmp_info[0] >> 16) & 0xf;
Cpu_Extended_Family_ID = (tmp_info[0] >> 20) & 0xff;
// 31-25位保留
kinfo("Family ID=%#03lx\t Extended Family ID=%#03lx\t Processor Type=%#03lx\t", Cpu_Family_ID, Cpu_Extended_Family_ID, Cpu_Processor_Type);
kinfo("Model ID=%#03lx\t Extended Model ID=%#03lx\tStepping ID=%#03lx\t", Cpu_Model_ID, Cpu_Extended_Model_ID, Cpu_Stepping_ID);
// 使用0x80000008主功能号查询处理器支持的最大可寻址地址线宽度
cpu_cpuid(0x80000008, 0, &tmp_info[0], &tmp_info[1], &tmp_info[2], &tmp_info[3]);
Cpu_max_phys_addrline_size = tmp_info[0] & 0xff;
Cpu_max_linear_addrline_size = (tmp_info[0] >> 8) & 0xff;
kinfo("Cpu_max_phys_addrline_size = %d", Cpu_max_phys_addrline_size);
kinfo("Cpu_max_linear_addrline_size = %d", Cpu_max_linear_addrline_size);
cpu_cpuid(0x80000000, 0, &tmp_info[0], &tmp_info[1], &tmp_info[2], &tmp_info[3]);
Cpu_cpuid_max_Extended_mop = tmp_info[0];
kinfo("Max basic mop=%#05lx", Cpu_cpuid_max_Basic_mop);
kinfo("Max extended mop=%#05lx", Cpu_cpuid_max_Extended_mop);
return;
}
void cpu_cpuid(uint32_t mop, uint32_t sop, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
{
// 向eax和ecx分别输入主功能号和子功能号
// 结果输出到eax, ebx, ecx, edx
__asm__ __volatile__("cpuid \n\t"
: "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
: "0"(mop), "2"(sop)
: "memory");
}
/**
* @brief 获取当前cpu核心晶振频率是一个Write-on-box的值
*
* hint: 某些cpu无法提供该数据返回值为0
* @return uint32_t 当前cpu核心晶振频率
*/
uint32_t cpu_get_core_crysral_freq()
{
uint32_t a = 0, b = 0, c = 0, d = 0;
// cpu_cpuid(0x15, 0, &a, &b, &c, &d);
__asm__ __volatile__("cpuid \n\t"
: "=a"(a), "=b"(b), "=c"(c), "=d"(d)
: "0"(0x15), "2"(0)
: "memory");
// kdebug("Cpu_cpuid_max_Basic_mop = %#03x, a=%ld, b=%ld, c=%ld, d=%ld", Cpu_cpuid_max_Basic_mop, a, b, c, d);
return c;
}

41
kernel/src/libs/crc16.c Normal file
View File

@ -0,0 +1,41 @@
#include <common/sys/types.h>
// Polynomial=0x8005
// Initial Value=0x0
// Final Xor Value=0x0
/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
uint16_t const crc16_table[256] = {
0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011, 0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072, 0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041,
0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2, 0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1, 0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082,
0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192, 0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1,
0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1, 0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151, 0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162,
0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132, 0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101,
0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312, 0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371, 0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342,
0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1, 0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2,
0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2, 0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291, 0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2,
0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2, 0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1,
0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252, 0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231, 0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202};
/**
* @brief 计算crc16
*
* @param crc crc初始值
* @param buffer 输入缓冲区
* @param len buffer大小bytes
* @return uint16_t crc
*/
uint16_t crc16(uint16_t crc, uint8_t const *buffer, size_t len)
{
while (len--)
{
crc = (crc << 8) ^ crc16_table[((crc >> 8) ^ *buffer++) & 0xff];
}
return crc;
}

56
kernel/src/libs/crc32.c Normal file
View File

@ -0,0 +1,56 @@
#include <common/sys/types.h>
// Polynomial=0x4C11DB7
// Initial Value=0x0
// Final Xor Value:0x0
/** CRC table for the CRC-32. The poly is 0x4C11DB7 */
uint32_t const crc32_table[256] = {
0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD,
0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75,
0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD,
0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5,
0xBE2B5B58, 0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D,
0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95,
0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D,
0x34867077, 0x30476DC0, 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072,
0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA,
0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02,
0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC, 0xB6238B25, 0xB2E29692,
0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A,
0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2,
0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34, 0xDC3ABDED, 0xD8FBA05A,
0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB,
0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53,
0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C, 0x3B5A6B9B,
0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623,
0xF12F560E, 0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B,
0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3,
0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B,
0x9B3660C6, 0x9FF77D71, 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3,
0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C,
0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24,
0x119B4BE9, 0x155A565E, 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, 0x29D4F654,
0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C,
0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4,
0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, 0x97FFAD0C,
0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4};
/**
* @brief 计算crc32
*
* @param crc crc初始值
* @param buffer 输入缓冲区
* @param len buffer大小bytes
* @return uint32_t crc
*/
uint32_t crc32(uint32_t crc, uint8_t const *buffer, size_t len)
{
while (len--)
{
crc = (crc << 8) ^ (crc32_table[((crc >> 24) ^ *buffer++) & 0xff]);
}
return crc;
}

57
kernel/src/libs/crc64.c Normal file
View File

@ -0,0 +1,57 @@
#include <common/sys/types.h>
// Polynomial =0x42F0E1EBA9EA3693
// Initial Value=0x0
// Final Xor Value=0x0
uint64_t const crc64_table[256] = {
0x0000000000000000, 0x42F0E1EBA9EA3693, 0x85E1C3D753D46D26, 0xC711223CFA3E5BB5, 0x493366450E42ECDF, 0x0BC387AEA7A8DA4C, 0xCCD2A5925D9681F9, 0x8E224479F47CB76A,
0x9266CC8A1C85D9BE, 0xD0962D61B56FEF2D, 0x17870F5D4F51B498, 0x5577EEB6E6BB820B, 0xDB55AACF12C73561, 0x99A54B24BB2D03F2, 0x5EB4691841135847, 0x1C4488F3E8F96ED4,
0x663D78FF90E185EF, 0x24CD9914390BB37C, 0xE3DCBB28C335E8C9, 0xA12C5AC36ADFDE5A, 0x2F0E1EBA9EA36930, 0x6DFEFF5137495FA3, 0xAAEFDD6DCD770416, 0xE81F3C86649D3285,
0xF45BB4758C645C51, 0xB6AB559E258E6AC2, 0x71BA77A2DFB03177, 0x334A9649765A07E4, 0xBD68D2308226B08E, 0xFF9833DB2BCC861D, 0x388911E7D1F2DDA8, 0x7A79F00C7818EB3B,
0xCC7AF1FF21C30BDE, 0x8E8A101488293D4D, 0x499B3228721766F8, 0x0B6BD3C3DBFD506B, 0x854997BA2F81E701, 0xC7B97651866BD192, 0x00A8546D7C558A27, 0x4258B586D5BFBCB4,
0x5E1C3D753D46D260, 0x1CECDC9E94ACE4F3, 0xDBFDFEA26E92BF46, 0x990D1F49C77889D5, 0x172F5B3033043EBF, 0x55DFBADB9AEE082C, 0x92CE98E760D05399, 0xD03E790CC93A650A,
0xAA478900B1228E31, 0xE8B768EB18C8B8A2, 0x2FA64AD7E2F6E317, 0x6D56AB3C4B1CD584, 0xE374EF45BF6062EE, 0xA1840EAE168A547D, 0x66952C92ECB40FC8, 0x2465CD79455E395B,
0x3821458AADA7578F, 0x7AD1A461044D611C, 0xBDC0865DFE733AA9, 0xFF3067B657990C3A, 0x711223CFA3E5BB50, 0x33E2C2240A0F8DC3, 0xF4F3E018F031D676, 0xB60301F359DBE0E5,
0xDA050215EA6C212F, 0x98F5E3FE438617BC, 0x5FE4C1C2B9B84C09, 0x1D14202910527A9A, 0x93366450E42ECDF0, 0xD1C685BB4DC4FB63, 0x16D7A787B7FAA0D6, 0x5427466C1E109645,
0x4863CE9FF6E9F891, 0x0A932F745F03CE02, 0xCD820D48A53D95B7, 0x8F72ECA30CD7A324, 0x0150A8DAF8AB144E, 0x43A04931514122DD, 0x84B16B0DAB7F7968, 0xC6418AE602954FFB,
0xBC387AEA7A8DA4C0, 0xFEC89B01D3679253, 0x39D9B93D2959C9E6, 0x7B2958D680B3FF75, 0xF50B1CAF74CF481F, 0xB7FBFD44DD257E8C, 0x70EADF78271B2539, 0x321A3E938EF113AA,
0x2E5EB66066087D7E, 0x6CAE578BCFE24BED, 0xABBF75B735DC1058, 0xE94F945C9C3626CB, 0x676DD025684A91A1, 0x259D31CEC1A0A732, 0xE28C13F23B9EFC87, 0xA07CF2199274CA14,
0x167FF3EACBAF2AF1, 0x548F120162451C62, 0x939E303D987B47D7, 0xD16ED1D631917144, 0x5F4C95AFC5EDC62E, 0x1DBC74446C07F0BD, 0xDAAD56789639AB08, 0x985DB7933FD39D9B,
0x84193F60D72AF34F, 0xC6E9DE8B7EC0C5DC, 0x01F8FCB784FE9E69, 0x43081D5C2D14A8FA, 0xCD2A5925D9681F90, 0x8FDAB8CE70822903, 0x48CB9AF28ABC72B6, 0x0A3B7B1923564425,
0x70428B155B4EAF1E, 0x32B26AFEF2A4998D, 0xF5A348C2089AC238, 0xB753A929A170F4AB, 0x3971ED50550C43C1, 0x7B810CBBFCE67552, 0xBC902E8706D82EE7, 0xFE60CF6CAF321874,
0xE224479F47CB76A0, 0xA0D4A674EE214033, 0x67C58448141F1B86, 0x253565A3BDF52D15, 0xAB1721DA49899A7F, 0xE9E7C031E063ACEC, 0x2EF6E20D1A5DF759, 0x6C0603E6B3B7C1CA,
0xF6FAE5C07D3274CD, 0xB40A042BD4D8425E, 0x731B26172EE619EB, 0x31EBC7FC870C2F78, 0xBFC9838573709812, 0xFD39626EDA9AAE81, 0x3A28405220A4F534, 0x78D8A1B9894EC3A7,
0x649C294A61B7AD73, 0x266CC8A1C85D9BE0, 0xE17DEA9D3263C055, 0xA38D0B769B89F6C6, 0x2DAF4F0F6FF541AC, 0x6F5FAEE4C61F773F, 0xA84E8CD83C212C8A, 0xEABE6D3395CB1A19,
0x90C79D3FEDD3F122, 0xD2377CD44439C7B1, 0x15265EE8BE079C04, 0x57D6BF0317EDAA97, 0xD9F4FB7AE3911DFD, 0x9B041A914A7B2B6E, 0x5C1538ADB04570DB, 0x1EE5D94619AF4648,
0x02A151B5F156289C, 0x4051B05E58BC1E0F, 0x87409262A28245BA, 0xC5B073890B687329, 0x4B9237F0FF14C443, 0x0962D61B56FEF2D0, 0xCE73F427ACC0A965, 0x8C8315CC052A9FF6,
0x3A80143F5CF17F13, 0x7870F5D4F51B4980, 0xBF61D7E80F251235, 0xFD913603A6CF24A6, 0x73B3727A52B393CC, 0x31439391FB59A55F, 0xF652B1AD0167FEEA, 0xB4A25046A88DC879,
0xA8E6D8B54074A6AD, 0xEA16395EE99E903E, 0x2D071B6213A0CB8B, 0x6FF7FA89BA4AFD18, 0xE1D5BEF04E364A72, 0xA3255F1BE7DC7CE1, 0x64347D271DE22754, 0x26C49CCCB40811C7,
0x5CBD6CC0CC10FAFC, 0x1E4D8D2B65FACC6F, 0xD95CAF179FC497DA, 0x9BAC4EFC362EA149, 0x158E0A85C2521623, 0x577EEB6E6BB820B0, 0x906FC95291867B05, 0xD29F28B9386C4D96,
0xCEDBA04AD0952342, 0x8C2B41A1797F15D1, 0x4B3A639D83414E64, 0x09CA82762AAB78F7, 0x87E8C60FDED7CF9D, 0xC51827E4773DF90E, 0x020905D88D03A2BB, 0x40F9E43324E99428,
0x2CFFE7D5975E55E2, 0x6E0F063E3EB46371, 0xA91E2402C48A38C4, 0xEBEEC5E96D600E57, 0x65CC8190991CB93D, 0x273C607B30F68FAE, 0xE02D4247CAC8D41B, 0xA2DDA3AC6322E288,
0xBE992B5F8BDB8C5C, 0xFC69CAB42231BACF, 0x3B78E888D80FE17A, 0x7988096371E5D7E9, 0xF7AA4D1A85996083, 0xB55AACF12C735610, 0x724B8ECDD64D0DA5, 0x30BB6F267FA73B36,
0x4AC29F2A07BFD00D, 0x08327EC1AE55E69E, 0xCF235CFD546BBD2B, 0x8DD3BD16FD818BB8, 0x03F1F96F09FD3CD2, 0x41011884A0170A41, 0x86103AB85A2951F4, 0xC4E0DB53F3C36767,
0xD8A453A01B3A09B3, 0x9A54B24BB2D03F20, 0x5D45907748EE6495, 0x1FB5719CE1045206, 0x919735E51578E56C, 0xD367D40EBC92D3FF, 0x1476F63246AC884A, 0x568617D9EF46BED9,
0xE085162AB69D5E3C, 0xA275F7C11F7768AF, 0x6564D5FDE549331A, 0x279434164CA30589, 0xA9B6706FB8DFB2E3, 0xEB46918411358470, 0x2C57B3B8EB0BDFC5, 0x6EA7525342E1E956,
0x72E3DAA0AA188782, 0x30133B4B03F2B111, 0xF7021977F9CCEAA4, 0xB5F2F89C5026DC37, 0x3BD0BCE5A45A6B5D, 0x79205D0E0DB05DCE, 0xBE317F32F78E067B, 0xFCC19ED95E6430E8,
0x86B86ED5267CDBD3, 0xC4488F3E8F96ED40, 0x0359AD0275A8B6F5, 0x41A94CE9DC428066, 0xCF8B0890283E370C, 0x8D7BE97B81D4019F, 0x4A6ACB477BEA5A2A, 0x089A2AACD2006CB9,
0x14DEA25F3AF9026D, 0x562E43B4931334FE, 0x913F6188692D6F4B, 0xD3CF8063C0C759D8, 0x5DEDC41A34BBEEB2, 0x1F1D25F19D51D821, 0xD80C07CD676F8394, 0x9AFCE626CE85B507
};
/**
* @brief 计算crc64
*
* @param crc crc初始值
* @param buffer 输入缓冲区
* @param len buffer大小bytes
* @return uint64_t crc
*/
uint64_t crc64(uint64_t crc, uint8_t const *buffer, size_t len)
{
while (len--)
{
crc = (crc << 8) ^ (crc64_table[((crc >> 56) ^ *buffer++) & 0xff]);
}
return crc;
}

38
kernel/src/libs/crc7.c Normal file
View File

@ -0,0 +1,38 @@
#include <common/sys/types.h>
/** CRC table for the CRC-7. The poly is 0X09 */
// crc7 generator polynomial : G(x)=x7+x3+1
const uint8_t crc7_table[256] = {
0X00, 0X09, 0X12, 0X1B, 0X24, 0X2D, 0X36, 0X3F, 0X48, 0X41, 0X5A, 0X53, 0X6C, 0X65, 0X7E, 0X77,
0X19, 0X10, 0X0B, 0X02, 0X3D, 0X34, 0X2F, 0X26, 0X51, 0X58, 0X43, 0X4A, 0X75, 0X7C, 0X67, 0X6E,
0X32, 0X3B, 0X20, 0X29, 0X16, 0X1F, 0X04, 0X0D, 0X7A, 0X73, 0X68, 0X61, 0X5E, 0X57, 0X4C, 0X45,
0X2B, 0X22, 0X39, 0X30, 0X0F, 0X06, 0X1D, 0X14, 0X63, 0X6A, 0X71, 0X78, 0X47, 0X4E, 0X55, 0X5C,
0X64, 0X6D, 0X76, 0X7F, 0X40, 0X49, 0X52, 0X5B, 0X2C, 0X25, 0X3E, 0X37, 0X08, 0X01, 0X1A, 0X13,
0X7D, 0X74, 0X6F, 0X66, 0X59, 0X50, 0X4B, 0X42, 0X35, 0X3C, 0X27, 0X2E, 0X11, 0X18, 0X03, 0X0A,
0X56, 0X5F, 0X44, 0X4D, 0X72, 0X7B, 0X60, 0X69, 0X1E, 0X17, 0X0C, 0X05, 0X3A, 0X33, 0X28, 0X21,
0X4F, 0X46, 0X5D, 0X54, 0X6B, 0X62, 0X79, 0X70, 0X07, 0X0E, 0X15, 0X1C, 0X23, 0X2A, 0X31, 0X38,
0X41, 0X48, 0X53, 0X5A, 0X65, 0X6C, 0X77, 0X7E, 0X09, 0X00, 0X1B, 0X12, 0X2D, 0X24, 0X3F, 0X36,
0X58, 0X51, 0X4A, 0X43, 0X7C, 0X75, 0X6E, 0X67, 0X10, 0X19, 0X02, 0X0B, 0X34, 0X3D, 0X26, 0X2F,
0X73, 0X7A, 0X61, 0X68, 0X57, 0X5E, 0X45, 0X4C, 0X3B, 0X32, 0X29, 0X20, 0X1F, 0X16, 0X0D, 0X04,
0X6A, 0X63, 0X78, 0X71, 0X4E, 0X47, 0X5C, 0X55, 0X22, 0X2B, 0X30, 0X39, 0X06, 0X0F, 0X14, 0X1D,
0X25, 0X2C, 0X37, 0X3E, 0X01, 0X08, 0X13, 0X1A, 0X6D, 0X64, 0X7F, 0X76, 0X49, 0X40, 0X5B, 0X52,
0X3C, 0X35, 0X2E, 0X27, 0X18, 0X11, 0X0A, 0X03, 0X74, 0X7D, 0X66, 0X6F, 0X50, 0X59, 0X42, 0X4B,
0X17, 0X1E, 0X05, 0X0C, 0X33, 0X3A, 0X21, 0X28, 0X5F, 0X56, 0X4D, 0X44, 0X7B, 0X72, 0X69, 0X60,
0X0E, 0X07, 0X1C, 0X15, 0X2A, 0X23, 0X38, 0X31, 0X46, 0X4F, 0X54, 0X5D, 0X62, 0X6B, 0X70, 0X79};
/**
* @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)
{
while (len--)
{
crc = crc7_table[(crc << 1) ^ *buffer++];
}
return (crc);
}

41
kernel/src/libs/crc8.c Normal file
View File

@ -0,0 +1,41 @@
#include <common/sys/types.h>
// Polynomial=0x31
// Initial Value=0x0
// Final Xor Value=0x0
/** CRC table for the CRC-8. The poly is 0x31 */
const uint8_t crc8_table[256] = {
0x00, 0x31, 0x62, 0x53, 0xc4, 0xf5, 0xa6, 0x97, 0xb9, 0x88, 0xdb, 0xea, 0x7d, 0x4c, 0x1f, 0x2e,
0x43, 0x72, 0x21, 0x10, 0x87, 0xb6, 0xe5, 0xd4, 0xfa, 0xcb, 0x98, 0xa9, 0x3e, 0x0f, 0x5c, 0x6d,
0x86, 0xb7, 0xe4, 0xd5, 0x42, 0x73, 0x20, 0x11, 0x3f, 0x0e, 0x5d, 0x6c, 0xfb, 0xca, 0x99, 0xa8,
0xc5, 0xf4, 0xa7, 0x96, 0x01, 0x30, 0x63, 0x52, 0x7c, 0x4d, 0x1e, 0x2f, 0xb8, 0x89, 0xda, 0xeb,
0x3d, 0x0c, 0x5f, 0x6e, 0xf9, 0xc8, 0x9b, 0xaa, 0x84, 0xb5, 0xe6, 0xd7, 0x40, 0x71, 0x22, 0x13,
0x7e, 0x4f, 0x1c, 0x2d, 0xba, 0x8b, 0xd8, 0xe9, 0xc7, 0xf6, 0xa5, 0x94, 0x03, 0x32, 0x61, 0x50,
0xbb, 0x8a, 0xd9, 0xe8, 0x7f, 0x4e, 0x1d, 0x2c, 0x02, 0x33, 0x60, 0x51, 0xc6, 0xf7, 0xa4, 0x95,
0xf8, 0xc9, 0x9a, 0xab, 0x3c, 0x0d, 0x5e, 0x6f, 0x41, 0x70, 0x23, 0x12, 0x85, 0xb4, 0xe7, 0xd6,
0x7a, 0x4b, 0x18, 0x29, 0xbe, 0x8f, 0xdc, 0xed, 0xc3, 0xf2, 0xa1, 0x90, 0x07, 0x36, 0x65, 0x54,
0x39, 0x08, 0x5b, 0x6a, 0xfd, 0xcc, 0x9f, 0xae, 0x80, 0xb1, 0xe2, 0xd3, 0x44, 0x75, 0x26, 0x17,
0xfc, 0xcd, 0x9e, 0xaf, 0x38, 0x09, 0x5a, 0x6b, 0x45, 0x74, 0x27, 0x16, 0x81, 0xb0, 0xe3, 0xd2,
0xbf, 0x8e, 0xdd, 0xec, 0x7b, 0x4a, 0x19, 0x28, 0x06, 0x37, 0x64, 0x55, 0xc2, 0xf3, 0xa0, 0x91,
0x47, 0x76, 0x25, 0x14, 0x83, 0xb2, 0xe1, 0xd0, 0xfe, 0xcf, 0x9c, 0xad, 0x3a, 0x0b, 0x58, 0x69,
0x04, 0x35, 0x66, 0x57, 0xc0, 0xf1, 0xa2, 0x93, 0xbd, 0x8c, 0xdf, 0xee, 0x79, 0x48, 0x1b, 0x2a,
0xc1, 0xf0, 0xa3, 0x92, 0x05, 0x34, 0x67, 0x56, 0x78, 0x49, 0x1a, 0x2b, 0xbc, 0x8d, 0xde, 0xef,
0x82, 0xb3, 0xe0, 0xd1, 0x46, 0x77, 0x24, 0x15, 0x3b, 0x0a, 0x59, 0x68, 0xff, 0xce, 0x9d, 0xac};
/**
* @brief 计算crc8
*
* @param crc crc初始值
* @param buffer 输入缓冲区
* @param len buffer大小bytes
* @return uint8_t crc
*/
uint8_t crc8(uint8_t crc, uint8_t const *buffer, size_t len)
{
while (len--)
{
// printf("%04x\n",(crc ^ *buffer)&0xff);
crc = crc8_table[crc ^ *buffer++];
}
return (crc);
}

59
kernel/src/libs/glib.c Normal file
View File

@ -0,0 +1,59 @@
#include <common/glib.h>
#include <common/string.h>
/**
* @brief 这个函数让蜂鸣器发声,目前仅用于真机调试。未来将移除,请勿依赖此函数。
*
* @param times 发声循环多少遍
*/
void __experimental_beep(uint64_t times)
{
io_out8(0x43, 182&0xff);
io_out8(0x42, 2280&0xff);
io_out8(0x42, (2280>>8)&0xff);
uint32_t x = io_in8(0x61)&0xff;
x |= 3;
io_out8(0x61, x&0xff);
times *= 10000;
for(uint64_t i=0;i<times;++i)
pause();
x = io_in8(0x61);
x &= 0xfc;
io_out8(0x61, x&0xff);
// 延迟一段时间
for(uint64_t i=0;i<times;++i)
pause();
}
/**
* @brief 将数据从src搬运到dst并能正确处理地址重叠的问题
*
* @param dst 目标地址指针
* @param src 源地址指针
* @param size 大小
* @return void* 指向目标地址的指针
*/
void *memmove(void *dst, const void *src, uint64_t size)
{
const char *_src = src;
char *_dst = dst;
if (!size)
return dst;
// 当源地址大于目标地址时使用memcpy来完成
if (dst <= src)
return memcpy(dst, src, size);
// 当源地址小于目标地址时,为防止重叠覆盖,因此从后往前拷贝
_src += size;
_dst += size;
// 逐字节拷贝
while (size--)
*--_dst = *--_src;
return dst;
}

1054
kernel/src/libs/idr.c Normal file

File diff suppressed because it is too large Load Diff

151
kernel/src/libs/kfifo.c Normal file
View File

@ -0,0 +1,151 @@
#include <common/kfifo.h>
#include <common/glib.h>
#include <common/errno.h>
#include <common/compiler.h>
#include <mm/slab.h>
/**
* @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)
{
memset(fifo, 0, sizeof(struct kfifo_t));
fifo->buffer = kmalloc(size, 0);
if (fifo->buffer == NULL)
goto failed;
fifo->total_size = size;
return 0;
failed:;
return -ENOMEM;
}
/**
* @brief 使用指定的缓冲区来初始化kfifo缓冲队列
*
* @param fifo 队列结构体
* @param buffer 缓冲区
* @param size 缓冲区大小
*/
void kfifo_init(struct kfifo_t *fifo, void *buffer, uint32_t size)
{
memset(fifo, 0, sizeof(struct kfifo_t));
fifo->buffer = buffer;
fifo->total_size = 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)
{
// 判断空间是否够
if (unlikely(fifo->size + size > fifo->total_size))
return 0;
if (unlikely(from == NULL))
return 0;
// 分两种情况,一种是要发生回环,另一种不发生回环
if (fifo->in_offset + size > fifo->total_size) // 发生回环
{
uint32_t tmp = fifo->total_size - fifo->in_offset;
memcpy(fifo->buffer + fifo->in_offset, from, tmp);
memcpy(fifo->buffer, from + tmp, size - tmp);
fifo->in_offset = size - tmp;
}
else // 不发生回环
{
memcpy(fifo->buffer + fifo->in_offset, from, size);
fifo->in_offset += size;
}
fifo->size += size;
return 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)
{
if (unlikely(to == NULL)) // 判断目标地址是否为空
return 0;
if (unlikely(size > fifo->size)) // 判断队列中是否有这么多数据
return 0;
// 判断是否会发生回环
if (fifo->out_offset + size > fifo->total_size) // 发生回环
{
uint32_t tmp = fifo->total_size - fifo->out_offset;
memcpy(to, fifo->buffer + fifo->out_offset, tmp);
memcpy(to + tmp, fifo->buffer, size - tmp);
fifo->out_offset = size - tmp;
}
else // 未发生回环
{
memcpy(to, fifo->buffer + fifo->out_offset, size);
fifo->out_offset += size;
}
fifo->size -= size;
return 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)
{
if (unlikely(to == NULL)) // 判断目标地址是否为空
return 0;
if (unlikely(size > fifo->size)) // 判断队列中是否有这么多数据
return 0;
// 判断是否会发生回环
if (fifo->out_offset + size > fifo->total_size) // 发生回环
{
uint32_t tmp = fifo->total_size - fifo->out_offset;
memcpy(to, fifo->buffer + fifo->out_offset, tmp);
memcpy(to + tmp, fifo->buffer, size - tmp);
}
else // 未发生回环
{
memcpy(to, fifo->buffer + fifo->out_offset, size);
}
return size;
}
/**
* @brief 释放通过kfifo_alloc创建的fifo缓冲区
*
* @param fifo fifo队列结构体
*/
void kfifo_free_alloc(struct kfifo_t *fifo)
{
kfree(fifo->buffer);
memset(fifo, 0, sizeof(struct kfifo_t));
}

View File

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

View File

@ -0,0 +1,33 @@
#include "elf.h"
#include <common/unistd.h>
#include <common/glib.h>
/**
* @brief 校验是否为ELF文件
*
* @param ehdr
*/
bool elf_check(void *ehdr)
{
Elf32_Ehdr *ptr = (Elf32_Ehdr *)ehdr;
bool flag = ptr->e_ident[EI_MAG0] == ELFMAG0 && ptr->e_ident[EI_MAG1] == ELFMAG1 && ptr->e_ident[EI_MAG2] == ELFMAG2 && ptr->e_ident[EI_MAG3] == ELFMAG3;
// 标头已经不符合要求
if (!flag)
return false;
// 检验EI_CLASS是否合法
if (ptr->e_ident[EI_CLASS] == 0 || ptr->e_ident[EI_CLASS] > 2)
return false;
// 检验EI_DATA是否合法
if (ptr->e_ident[EI_DATA] == 0 || ptr->e_ident[EI_DATA] > 2)
return false;
// 检验EI_VERSION是否合法
if(ptr->e_ident[EI_VERSION]==EV_NONE)
return false;
// 是elf文件
return true;
}

View File

@ -0,0 +1,13 @@
all: screen_manager.o textui.o textui-render.o
CFLAGS += -I .
screen_manager.o: screen_manager.c
$(CC) $(CFLAGS) -c screen_manager.c -o screen_manager.o
textui.o: textui.c
$(CC) $(CFLAGS) -c textui.c -o textui.o
textui-render.o: textui-render.c
$(CC) $(CFLAGS) -c textui-render.c -o textui-render.o

View File

@ -0,0 +1,323 @@
#include "screen_manager.h"
#include <common/kprint.h>
#include <common/spinlock.h>
#include <common/string.h>
#include <driver/multiboot2/multiboot2.h>
#include <driver/uart/uart.h>
#include <driver/video/video.h>
#include <mm/mm.h>
#include <mm/slab.h>
extern struct scm_buffer_info_t video_frame_buffer_info;
static struct List scm_framework_list;
static spinlock_t scm_register_lock; // 框架注册锁
static spinlock_t scm_screen_own_lock = {1}; // 改变屏幕归属者时,需要对该锁加锁
static struct scm_ui_framework_t *__current_framework; // 当前拥有屏幕控制权的框架
static uint32_t scm_ui_max_id = 0;
static bool __scm_alloc_enabled = false; // 允许动态申请内存的标志位
static bool __scm_double_buffer_enabled = false; // 允许双缓冲的标志位
/**
* @brief 创建新的帧缓冲区
*
* @param type 帧缓冲区类型
* @return struct scm_buffer_info_t* 新的帧缓冲区结构体
*/
static struct scm_buffer_info_t *__create_buffer(uint64_t type)
{
// 若未启用双缓冲,则直接返回帧缓冲区
if (unlikely(__scm_double_buffer_enabled == false))
return &video_frame_buffer_info;
struct scm_buffer_info_t *buf = (struct scm_buffer_info_t *)kmalloc(sizeof(struct scm_buffer_info_t), 0);
if (buf == NULL)
return (void *)-ENOMEM;
memset(buf, 0, sizeof(struct scm_buffer_info_t));
buf->bit_depth = video_frame_buffer_info.bit_depth;
buf->flags = SCM_BF_DB;
if (type & SCM_BF_PIXEL)
buf->flags |= SCM_BF_PIXEL;
else
buf->flags |= SCM_BF_TEXT;
buf->height = video_frame_buffer_info.height;
buf->width = video_frame_buffer_info.width;
buf->size = video_frame_buffer_info.size;
struct Page *p = alloc_pages(ZONE_NORMAL, PAGE_2M_ALIGN(video_frame_buffer_info.size) / PAGE_2M_SIZE, 0);
if (p == NULL)
goto failed;
buf->vaddr = (uint64_t)phys_2_virt(p->addr_phys);
return buf;
failed:;
kfree(buf);
return (void *)-ENOMEM;
}
/**
* @brief 销毁双缓冲区
*
* @param buf
* @return int
*/
static int __destroy_buffer(struct scm_buffer_info_t *buf)
{
// 不能销毁帧缓冲区对象
if (unlikely(buf == &video_frame_buffer_info || buf == NULL))
return -EINVAL;
if (unlikely(buf->vaddr == NULL))
return -EINVAL;
if (unlikely(verify_area(buf->vaddr, buf->size) == true))
return -EINVAL;
// 是否双缓冲区
if (buf->flags & SCM_BF_FB)
return -EINVAL;
// 释放内存页
free_pages(Phy_to_2M_Page(virt_2_phys(buf->vaddr)), PAGE_2M_ALIGN(video_frame_buffer_info.size) / PAGE_2M_SIZE);
return 0;
}
/**
* @brief 初始化屏幕管理模块
*
*/
void scm_init()
{
list_init(&scm_framework_list);
spin_init(&scm_register_lock);
spin_init(&scm_screen_own_lock);
io_mfence();
scm_ui_max_id = 0;
__scm_alloc_enabled = false; // 禁用动态申请内存
__scm_double_buffer_enabled = false; // 禁用双缓冲
__current_framework = NULL;
}
/**
* @brief 检查ui框架结构体中的参数设置是否合法
*
* @param name 框架名称
* @param type 框架类型
* @param ops 框架的操作
* @return int
*/
static int __check_ui_param(const char *name, const uint8_t type, const struct scm_ui_framework_operations_t *ops)
{
if (name == NULL)
return -EINVAL;
if ((type == SCM_FRAMWORK_TYPE_GUI || type == SCM_FRAMWORK_TYPE_TEXT) == 0)
return -EINVAL;
if (ops == NULL)
return -EINVAL;
if (ops->install == NULL || ops->uninstall == NULL || ops->enable == NULL || ops->disable == NULL ||
ops->change == NULL)
return -EINVAL;
return 0;
}
/**
* @brief 向屏幕管理器注册UI框架动态获取框架对象结构体
*
* @param name 框架名
* @param type 类型
* @param ops 框架操作方法
* @return int
*/
int scm_register_alloc(const char *name, const uint8_t type, struct scm_ui_framework_operations_t *ops)
{
// 若未启用动态申请,则返回。
if (unlikely(__scm_alloc_enabled == false))
return -EAGAIN;
// 检查参数合法性
if (__check_ui_param(name, type, ops) != 0)
return -EINVAL;
struct scm_ui_framework_t *ui = (struct scm_ui_framework_t *)kmalloc(sizeof(struct scm_ui_framework_t *), 0);
memset(ui, 0, sizeof(struct scm_ui_framework_t));
strncpy(ui->name, name, 15);
ui->type = type;
ui->ui_ops = ops;
list_init(&ui->list);
spin_lock(&scm_register_lock);
ui->id = scm_ui_max_id++;
spin_unlock(&scm_register_lock);
// 创建帧缓冲区
ui->buf = __create_buffer(ui->type);
if ((uint64_t)(ui->buf) == (uint64_t)-ENOMEM)
{
kfree(ui);
return -ENOMEM;
}
// 把ui框架加入链表
list_add(&scm_framework_list, &ui->list);
// 调用ui框架的回调函数以安装ui框架并将其激活
ui->ui_ops->install(ui->buf);
ui->ui_ops->enable(NULL);
if (__current_framework == NULL)
return scm_framework_enable(ui);
return 0;
}
/**
* @brief 向屏幕管理器注册UI框架静态设置的框架对象
*
* @param ui 框架结构体指针
* @return int 错误码
*/
int scm_register(struct scm_ui_framework_t *ui)
{
if (ui == NULL)
return -EINVAL;
if (__check_ui_param(ui->name, ui->type, ui->ui_ops) != 0)
return -EINVAL;
list_init(&ui->list);
spin_lock(&scm_register_lock);
ui->id = scm_ui_max_id++;
spin_unlock(&scm_register_lock);
ui->buf = __create_buffer(ui->type);
if ((uint64_t)(ui->buf) == (uint64_t)-ENOMEM)
return -ENOMEM;
// 把ui框架加入链表
list_add(&scm_framework_list, &ui->list);
// 调用ui框架的回调函数以安装ui框架并将其激活
ui->ui_ops->install(ui->buf);
ui->ui_ops->enable(NULL);
if (__current_framework == NULL)
return scm_framework_enable(ui);
return 0;
}
/**
* @brief 向屏幕管理器卸载UI框架
*
* @param ui ui框架结构体
* @return int
*/
int scm_unregister(struct scm_ui_framework_t *ui)
{
return 0;
}
/**
* @brief 向屏幕管理器卸载动态创建的UI框架
*
* @param ui ui框架结构体
* @return int
*/
int scm_unregister_alloc(struct scm_ui_framework_t *ui)
{
return 0;
}
/**
* @brief 允许动态申请内存
*
* @return int
*/
int scm_enable_alloc()
{
__scm_alloc_enabled = true;
return 0;
}
/**
* @brief 允许双缓冲区
*
* @return int
*/
int scm_enable_double_buffer()
{
if (__scm_double_buffer_enabled == true) // 已经开启了双缓冲区了, 直接退出
return 0;
__scm_double_buffer_enabled = true;
if (list_empty(&scm_framework_list)) // scm 框架链表为空
return 0;
// 逐个检查已经注册了的ui框架将其缓冲区更改为双缓冲
struct scm_ui_framework_t *ptr = container_of(list_next(&scm_framework_list), struct scm_ui_framework_t, list);
// 这里的ptr不需要特判空指针吗 问题1
do
{
if (ptr->buf == &video_frame_buffer_info)
{
uart_send_str(COM1, "##init double buffer##\n");
struct scm_buffer_info_t *buf = __create_buffer(SCM_BF_DB | SCM_BF_PIXEL);
if ((uint64_t)(buf) == (uint64_t)-ENOMEM)
return -ENOMEM;
uart_send_str(COM1, "##to change double buffer##\n");
if (ptr->ui_ops->change(buf) != 0) // 这里的change回调函数不会是空指针吗 问题2
{
__destroy_buffer(buf);
kfree(buf);
}
}
} while (list_next(&ptr->list) != &scm_framework_list); // 枚举链表的每一个ui框架
// 设置定时刷新的对象
video_set_refresh_target(__current_framework->buf);
// 通知显示驱动,启动双缓冲
video_reinitialize(true);
uart_send_str(COM1, "##initialized double buffer##\n");
return 0;
}
/**
* @brief 启用某个ui框架将它的帧缓冲区渲染到屏幕上
*
* @param ui 要启动的ui框架
* @return int 返回码
*/
int scm_framework_enable(struct scm_ui_framework_t *ui)
{
if (ui->buf->vaddr == NULL)
return -EINVAL;
spin_lock(&scm_screen_own_lock);
int retval = 0;
if (__scm_double_buffer_enabled == true)
{
retval = video_set_refresh_target(ui->buf);
if (retval == 0)
__current_framework = ui;
}
else
__current_framework = ui;
spin_unlock(&scm_screen_own_lock);
return retval;
}
/**
* @brief 当内存管理单元被初始化之后,重新处理帧缓冲区问题
*
*/
void scm_reinit()
{
scm_enable_alloc();
video_reinitialize(false);
// 遍历当前所有使用帧缓冲区的框架,更新地址
// 逐个检查已经注册了的ui框架将其缓冲区更改为双缓冲
struct scm_ui_framework_t *ptr = container_of(list_next(&scm_framework_list), struct scm_ui_framework_t, list);
do
{
if (ptr->buf == &video_frame_buffer_info)
{
ptr->ui_ops->change(&video_frame_buffer_info);
}
} while (list_next(&ptr->list) != &scm_framework_list);
return;
}

View File

@ -0,0 +1,118 @@
#pragma once
#include <common/sys/types.h>
#include <common/glib.h>
// 帧缓冲区标志位
#define SCM_BF_FB (1 << 0) // 当前buffer是设备显存中的帧缓冲区
#define SCM_BF_DB (1 << 1) // 当前buffer是双缓冲
#define SCM_BF_TEXT (1 << 2) // 使用文本模式
#define SCM_BF_PIXEL (1 << 3) // 使用图像模式
// ui框架类型
#define SCM_FRAMWORK_TYPE_TEXT (uint8_t)0
#define SCM_FRAMWORK_TYPE_GUI (uint8_t)1
/**
* @brief 帧缓冲区信息结构体
*
*/
struct scm_buffer_info_t
{
uint32_t width; // 帧缓冲区宽度pixel或columns
uint32_t height; // 帧缓冲区高度pixel或lines
uint32_t size; // 帧缓冲区大小bytes
uint32_t bit_depth; // 像素点位深度
uint64_t vaddr; // 帧缓冲区的地址
uint64_t flags; // 帧缓冲区标志位
};
/**
* @brief 上层ui框架应当实现的接口
*
*/
struct scm_ui_framework_operations_t
{
int (*install)(struct scm_buffer_info_t *buf); // 安装ui框架的回调函数
int (*uninstall)(void *args); // 卸载ui框架的回调函数
int (*enable)(void *args); // 启用ui框架的回调函数
int (*disable)(void *args); // 禁用ui框架的回调函数
int (*change)(struct scm_buffer_info_t *buf); // 改变ui框架的帧缓冲区的回调函数
};
struct scm_ui_framework_t
{
struct List list;
uint16_t id;
char name[16];
uint8_t type;
struct scm_ui_framework_operations_t *ui_ops;
struct scm_buffer_info_t *buf;
};
/**
* @brief 初始化屏幕管理模块
*
*/
void scm_init();
/**
* @brief 当内存管理单元被初始化之后,重新处理帧缓冲区问题
*
*/
void scm_reinit();
/**
* @brief 向屏幕管理器注册UI框架动态获取框架对象结构体
*
* @param name 框架名
* @param type 类型
* @param ops 框架操作方法
* @return int
*/
int scm_register_alloc(const char *name, const uint8_t type, struct scm_ui_framework_operations_t *ops);
/**
* @brief 向屏幕管理器注册UI框架静态设置的框架对象
*
* @param ui 框架结构体指针
* @return int 错误码
*/
int scm_register(struct scm_ui_framework_t *ui);
/**
* @brief 向屏幕管理器卸载UI框架
*
* @param ui ui框架结构体
* @return int
*/
int scm_unregister(struct scm_ui_framework_t *ui);
/**
* @brief 向屏幕管理器卸载动态创建的UI框架
*
* @param ui ui框架结构体
* @return int
*/
int scm_unregister_alloc(struct scm_ui_framework_t *ui);
/**
* @brief 允许动态申请内存
*
* @return int
*/
int scm_enable_alloc();
/**
* @brief 允许双缓冲区
*
* @return int
*/
int scm_enable_double_buffer();
/**
* @brief 启用某个ui框架将它的帧缓冲区渲染到屏幕上
*
* @param ui 要启动的ui框架
* @return int 返回码
*/
int scm_framework_enable(struct scm_ui_framework_t *ui);

View File

@ -0,0 +1,154 @@
#include "textui.h"
#include <driver/uart/uart.h>
#include <common/errno.h>
#include "screen_manager.h"
#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 //紫
// 根据rgb计算出最终的颜色值
#define calculate_color(r, g, b) ((((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff)) & 0x00ffffff)
extern struct scm_ui_framework_t textui_framework;
extern unsigned char font_ascii[256][16]; //导出ascii字体的bitmap8*16大小 ps:位于font.h中
static void __textui_render_chromatic(uint16_t actual_line, uint16_t index, struct textui_char_chromatic_t *character);
/**
* @brief 重新渲染整个虚拟行
*
* @param window 窗口结构体
* @param vline_id 虚拟行号
* @return int 错误码
*/
int textui_refresh_vline(struct textui_window_t *window, uint16_t vline_id)
{
if (textui_is_chromatic(window->flags))
return textui_refresh_characters(window, vline_id, 0, window->chars_per_line);
else
return textui_refresh_characters(window, vline_id, 0, window->chars_per_line);
}
int textui_refresh_vlines(struct textui_window_t *window, uint16_t start, uint16_t count)
{
char bufff[16] = {0};
// uart_send_str(COM1, " BEGIN ");
for (int i = start; i < window->vlines_num && count > 0; ++i, --count)
{
// sprintk(bufff, "[ 1fresh: %d ] ", i);
// uart_send_str(COM1, bufff);
textui_refresh_vline(window, i);
}
start = 0;
while (count > 0)
{
// sprintk(bufff, "[ 2fresh: %d ] ", start);
// uart_send_str(COM1, bufff);
// sprintk(bufff, " index=%d ", (window->vlines.chromatic)[start].index);
// uart_send_str(COM1, bufff);
textui_refresh_vline(window, start);
++start;
--count;
}
// uart_send_str(COM1, " END ");
return 0;
}
/**
* @brief 刷新某个虚拟行的连续n个字符对象
*
* @param window 窗口结构体
* @param vline_id 虚拟行号
* @param start 起始字符号
* @param count 要刷新的字符数量
* @return int 错误码
*/
int textui_refresh_characters(struct textui_window_t *window, uint16_t vline_id, uint16_t start, uint16_t count)
{
if (window->id != __textui_get_current_window_id())
return 0;
// 判断虚拟行参数是否合法
if (unlikely(vline_id >= window->vlines_num && (start + count) > window->chars_per_line))
return -EINVAL;
// 计算虚拟行对应的真实行
int actual_line_id = (int)vline_id - window->top_vline;
if (actual_line_id < 0)
actual_line_id += __textui_get_actual_lines();
// 判断真实行id是否合理
if (unlikely(actual_line_id < 0 || actual_line_id >= __textui_get_actual_lines()))
return 0;
// 若是彩色像素模式
if (textui_is_chromatic(window->flags))
{
struct textui_vline_chromatic_t *vline = &(window->vlines.chromatic)[vline_id];
for (int i = 0; i < count; ++i)
{
__textui_render_chromatic(actual_line_id, start + i, &vline->chars[start + i]);
}
}
return 0;
}
/**
* @brief 渲染彩色字符
*
* @param actual_line 真实行的行号
* @param index 列号
* @param character 要渲染的字符
*/
static void __textui_render_chromatic(uint16_t actual_line, uint16_t index, struct textui_char_chromatic_t *character)
{
/**
* @brief 在屏幕上指定位置打印字符
*
* @param x 左上角列像素点位置
* @param y 左上角行像素点位置
* @param FRcolor 字体颜色
* @param BKcolor 背景颜色
* @param font 字符的bitmap
*/
unsigned char *font_ptr = font_ascii[(uint8_t)character->c];
unsigned int *addr;
uint32_t *fb = (uint32_t *)textui_framework.buf->vaddr;
uint32_t FRcolor = character->FRcolor & 0x00ffffff;
uint32_t BKcolor = character->BKcolor & 0x00ffffff;
uint32_t x = index * TEXTUI_CHAR_WIDTH;
uint32_t y = actual_line * TEXTUI_CHAR_HEIGHT;
int testbit; // 用来测试某位是背景还是字体本身
for (int i = 0; i < TEXTUI_CHAR_HEIGHT; ++i)
{
// 计算出帧缓冲区的地址
addr = (uint32_t *)(fb + textui_framework.buf->width * (y + i) + x);
testbit = (1 << (TEXTUI_CHAR_WIDTH + 1));
for (int j = 0; j < TEXTUI_CHAR_WIDTH; ++j)
{
// 从左往右逐个测试相应位
testbit >>= 1;
if (*font_ptr & testbit)
*addr = FRcolor; // 字,显示前景色
else
*addr = BKcolor; // 背景色
++addr;
}
++font_ptr;
}
}

View File

@ -0,0 +1,348 @@
#include "textui.h"
#include "driver/uart/uart.h"
#include "screen_manager.h"
#include <common/atomic.h>
#include <common/errno.h>
#include <common/printk.h>
#include <common/string.h>
struct scm_ui_framework_t textui_framework;
static spinlock_t __window_id_lock = {1};
static uint32_t __window_max_id = 0;
// 暂时初始化16080个初始字符对象以及67个虚拟行对象
#define INITIAL_CHARS 16080
#define INITIAL_VLINES (int)(1080 / 16)
static struct textui_char_chromatic_t __initial_chars[INITIAL_CHARS] = {0};
static struct textui_vline_chromatic_t __initial_vlines[INITIAL_VLINES] = {0};
static struct textui_window_t __initial_window = {0}; // 初始窗口
static struct textui_private_info_t __private_info = {0};
static struct List __windows_list;
static spinlock_t change_lock;
/**
* @brief 初始化window对象
*
* @param window 窗口对象
* @param flags 标志位
* @param vlines_num 虚拟行的总数
* @param vlines_ptr 虚拟行数组指针
* @param cperline 每行最大的字符数
*/
static int __textui_init_window(struct textui_window_t *window, uint8_t flags, uint16_t vlines_num, void *vlines_ptr,
uint16_t cperline)
{
memset((window), 0, sizeof(struct textui_window_t));
list_init(&(window)->list);
window->lock.lock = 1;
spin_lock(&__window_id_lock);
window->id = __window_max_id++;
spin_unlock(&__window_id_lock);
window->flags = flags;
window->vlines_num = vlines_num;
window->vlines_used = 1;
window->top_vline = 0;
window->vline_operating = 0;
window->chars_per_line = cperline;
if (textui_is_chromatic(flags))
window->vlines.chromatic = vlines_ptr;
else
window->vlines.normal = vlines_ptr;
list_add(&__windows_list, &(window)->list);
}
/**
* @brief 初始化虚拟行对象
*
* @param vline 虚拟行对象指针
* @param chars_ptr 字符对象数组指针
*/
#define __textui_init_vline(vline, chars_ptr) \
do \
{ \
memset(vline, 0, sizeof(struct textui_vline_chromatic_t)); \
(vline)->index = 0; \
(vline)->chars = chars_ptr; \
} while (0)
int textui_install_handler(struct scm_buffer_info_t *buf)
{
// return printk_init(buf);
uart_send_str(COM1, "textui_install_handler");
return 0;
}
int textui_uninstall_handler(void *args)
{
return 0;
}
int textui_enable_handler(void *args)
{
uart_send_str(COM1, "textui_enable_handler\n");
return 0;
}
int textui_disable_handler(void *args)
{
return 0;
}
int textui_change_handler(struct scm_buffer_info_t *buf)
{
memcpy((void *)buf->vaddr, (void *)(textui_framework.buf->vaddr), textui_framework.buf->size);
textui_framework.buf = buf;
return 0;
}
struct scm_ui_framework_operations_t textui_ops = {
.install = &textui_install_handler,
.uninstall = &textui_uninstall_handler,
.change = &textui_change_handler,
.enable = &textui_enable_handler,
.disable = &textui_disable_handler,
};
/**
* @brief 获取textui的帧缓冲区能容纳的内容的行数
*
* @return uint16_t
*/
uint16_t __textui_get_actual_lines()
{
return __private_info.actual_line;
}
/**
* @brief 获取当前渲染的窗口的id
*
* @return uint16_t
*/
uint32_t __textui_get_current_window_id()
{
return __private_info.current_window->id;
}
/**
* @brief 插入换行
*
* @param window 窗口结构体
* @param vline_id 虚拟行号
* @return int
*/
static int __textui_new_line(struct textui_window_t *window, uint16_t vline_id)
{
// todo: 支持在两个虚拟行之间插入一个新行
++window->vline_operating;
if (unlikely(window->vline_operating == window->vlines_num))
window->vline_operating = 0;
struct textui_vline_chromatic_t *vline = &window->vlines.chromatic[window->vline_operating];
memset(vline->chars, 0, sizeof(struct textui_char_chromatic_t) * window->chars_per_line);
vline->index = 0;
if (likely(window->vlines_used == window->vlines_num)) // 需要滚动屏幕
{
++window->top_vline;
if (unlikely(window->top_vline >= window->vlines_num))
window->top_vline = 0;
// 刷新所有行
textui_refresh_vlines(window, window->top_vline, window->vlines_num);
}
else
++window->vlines_used;
return 0;
}
/**
* @brief 真正向屏幕上输出字符的函数
*
* @param window
* @param character
* @return int
*/
static int __textui_putchar_window(struct textui_window_t *window, uint16_t character, uint32_t FRcolor,
uint32_t BKcolor)
{
if (textui_is_chromatic(window->flags)) // 启用彩色字符
{
struct textui_vline_chromatic_t *vline = &window->vlines.chromatic[window->vline_operating];
vline->chars[vline->index].c = character;
vline->chars[vline->index].FRcolor = FRcolor & 0xffffff;
vline->chars[vline->index].BKcolor = BKcolor & 0xffffff;
++vline->index;
textui_refresh_characters(window, window->vline_operating, vline->index - 1, 1);
// 换行
// 加入光标后,因为会识别光标,所以需超过该行最大字符数才能创建新行
if (vline->index > window->chars_per_line)
{
__textui_new_line(window, window->vline_operating);
}
}
else
{
// todo: 支持纯文本字符
while (1)
pause();
}
return 0;
}
/**
* @brief 在指定窗口上输出一个字符
*
* @param window 窗口
* @param character 字符
* @param FRcolor 前景色RGB
* @param BKcolor 背景色RGB
* @return int
*/
int textui_putchar_window(struct textui_window_t *window, uint16_t character, uint32_t FRcolor, uint32_t BKcolor)
{
if (unlikely(character == '\0'))
return 0;
if (!textui_is_chromatic(window->flags)) // 暂不支持纯文本窗口
return 0;
// uint64_t rflags = 0; // 加锁后rflags存储到这里
spin_lock(&window->lock);
uart_send(COM1, character);
if (unlikely(character == '\n'))
{
// 换行时还需要输出\r
uart_send(COM1, '\r');
__textui_new_line(window, window->vline_operating);
// spin_unlock_irqrestore(&window->lock, rflags);
spin_unlock(&window->lock);
return 0;
}
else if (character == '\t') // 输出制表符
{
int space_to_print = 8 - window->vlines.chromatic[window->vline_operating].index % 8;
while (space_to_print--)
{
__textui_putchar_window(window, ' ', FRcolor, BKcolor);
}
}
else if (character == '\b') // 退格
{
char bufff[128] = {0};
--(window->vlines.chromatic[window->vline_operating].index);
{
uint16_t tmp = window->vlines.chromatic[window->vline_operating].index;
if (tmp >= 0)
{
window->vlines.chromatic[window->vline_operating].chars[tmp].c = ' ';
window->vlines.chromatic[window->vline_operating].chars[tmp].BKcolor = BKcolor & 0xffffff;
textui_refresh_characters(window, window->vline_operating, tmp, 1);
}
}
// 需要向上缩一行
if (window->vlines.chromatic[window->vline_operating].index <= 0)
{
window->vlines.chromatic[window->vline_operating].index = 0;
memset(window->vlines.chromatic[window->vline_operating].chars, 0,
sizeof(struct textui_char_chromatic_t) * window->chars_per_line);
--(window->vline_operating);
if (unlikely(window->vline_operating < 0))
window->vline_operating = window->vlines_num - 1;
// 考虑是否向上滚动
if (likely(window->vlines_used > __private_info.actual_line))
{
--window->top_vline;
if (unlikely(window->top_vline < 0))
window->top_vline = window->vlines_num - 1;
}
--window->vlines_used;
textui_refresh_vlines(window, window->top_vline, __private_info.actual_line);
}
}
else
{
if (window->vlines.chromatic[window->vline_operating].index == window->chars_per_line)
__textui_new_line(window, window->vline_operating);
__textui_putchar_window(window, character, FRcolor, BKcolor);
}
// spin_unlock_irqrestore(&window->lock, rflags);
spin_unlock(&window->lock);
return 0;
}
/**
* @brief 在默认窗口上输出一个字符
*
* @param character 字符
* @param FRcolor 前景色RGB
* @param BKcolor 背景色RGB
* @return int
*/
int textui_putchar(uint16_t character, uint32_t FRcolor, uint32_t BKcolor)
{
return textui_putchar_window(__private_info.default_window, character, FRcolor, BKcolor);
}
/**
* @brief 初始化text ui框架
*
* @return int
*/
int textui_init()
{
spin_init(&change_lock);
spin_init(&__window_id_lock);
__window_max_id = 0;
list_init(&__windows_list);
memset(&textui_framework, 0, sizeof(struct scm_ui_framework_t));
memset(&__private_info, 0, sizeof(struct textui_private_info_t));
io_mfence();
char name[] = "textUI";
strcpy(textui_framework.name, name);
textui_framework.ui_ops = &textui_ops;
textui_framework.type = 0;
// 注册框架到屏幕管理器
int retval = scm_register(&textui_framework);
if (retval != 0)
{
uart_send_str(COM1, "text ui init failed\n");
while (1)
pause();
}
uint16_t chars_per_vline = textui_framework.buf->width / TEXTUI_CHAR_WIDTH;
uint16_t total_vlines = textui_framework.buf->height / TEXTUI_CHAR_HEIGHT;
int cnt = chars_per_vline * total_vlines;
struct textui_vline_chromatic_t *vl_ptr = __initial_vlines;
struct textui_char_chromatic_t *ch_ptr = __initial_chars;
// 初始化虚拟行
for (int i = 0; i < total_vlines; ++i)
{
__textui_init_vline((vl_ptr + i), (ch_ptr + i * chars_per_vline));
}
// 初始化窗口
__textui_init_window((&__initial_window), TEXTUI_WF_CHROMATIC, total_vlines, __initial_vlines, chars_per_vline);
__private_info.current_window = &__initial_window;
__private_info.default_window = &__initial_window;
__private_info.actual_line = textui_framework.buf->height / TEXTUI_CHAR_HEIGHT;
uart_send_str(COM1, "text ui initialized\n");
return 0;
}

View File

@ -0,0 +1,183 @@
#pragma once
#include <common/glib.h>
#include <common/sys/types.h>
#include <common/spinlock.h>
/*
textui中的几个对象的关系
textui_vline_normal_t
+--------------------------------+
| | textui_char_normal_t
textui_window_t | chars: textui_char_normal_t * | +--------------------------+
+----------------------------+ | | | |
| | +------> +--------> c: char |
| list:List | | | index: int16_t | +--------------------------+
| vlines_num:int16_t | | | |
| vlines_used:int16_t | | +--------------------------------+
| | |
| vlines +-----+ textui_char_chromatic_t
| | | textui_vline_chromatic_t +--------------------------+
| top_vline:int16_t | | +-------------------------------------+ | |
| vline_operating:int16_t | | | | | c: uint16_t |
| chars_per_line:int16_t | | | chars: textui_char_chromatic_t * | | |
| flags:uint8_t | | | | | FRcolor:24 |
| lock:spinlock_t | +------> +---> |
| | | index: int16_t | | BKcolor:24 |
| | | | | |
+----------------------------+ +-------------------------------------+ +--------------------------+
*/
// 文本窗口标志位
// 文本窗口是否为彩色
#define TEXTUI_WF_CHROMATIC (1 << 0)
// 窗口是否启用彩色字符
#define textui_is_chromatic(flag) ((flag)&TEXTUI_WF_CHROMATIC)
// 每个字符的宽度和高度(像素)
#define TEXTUI_CHAR_WIDTH 8
#define TEXTUI_CHAR_HEIGHT 16
/**
* @brief 黑白字符对象
*
*/
struct textui_char_normal_t
{
char c;
};
/**
* @brief 彩色字符对象
*
*/
struct textui_char_chromatic_t
{
unsigned c : 16;
// 前景色
unsigned FRcolor : 24; // rgb
// 背景色
unsigned BKcolor : 24; // rgb
};
// 注意!!! 请保持vline结构体的大小、成员变量命名相等
/**
* @brief 单色显示的虚拟行结构体
*
*/
struct textui_vline_normal_t
{
struct textui_char_normal_t *chars; // 字符对象数组
int16_t index; // 当前操作的位置
};
/**
* @brief 彩色显示的虚拟行结构体
*
*/
struct textui_vline_chromatic_t
{
struct textui_char_chromatic_t *chars;
int16_t index; // 当前操作的位置
};
/**
* @brief textu ui 框架的文本窗口结构体
*
*/
struct textui_window_t
{
struct List list;
uint32_t id; // 窗口id
int16_t vlines_num; // 虚拟行总数
int16_t vlines_used; // 当前已经使用了的虚拟行总数
// 指向虚拟行的数组的指针(二选一)
union
{
struct textui_vline_normal_t *normal;
struct textui_vline_chromatic_t *chromatic;
} vlines;
int16_t top_vline; // 位于最顶上的那一个虚拟行的行号
int16_t vline_operating; // 正在操作的vline
int16_t chars_per_line; // 每行最大容纳的字符数
uint8_t flags; // 窗口flag
spinlock_t lock; // 窗口操作锁
};
struct textui_private_info_t
{
int16_t actual_line; // 真实行的数量
struct textui_window_t *current_window; // 当前的主窗口
struct textui_window_t *default_window; // 默认print到的窗口
};
/**
* @brief 重新渲染整个虚拟行
*
* @param window 窗口结构体
* @param vline_id 虚拟行号
* @return int 错误码
*/
int textui_refresh_vline(struct textui_window_t *window, uint16_t vline_id);
int textui_refresh_vlines(struct textui_window_t *window, uint16_t start, uint16_t count);
/**
* @brief 刷新某个虚拟行的连续n个字符对象
*
* @param window 窗口结构体
* @param vline_id 虚拟行号
* @param start 起始字符号
* @param count 要刷新的字符数量
* @return int 错误码
*/
int textui_refresh_characters(struct textui_window_t *window, uint16_t vline_id, uint16_t start, uint16_t count);
/**
* @brief 在指定窗口上输出一个字符
*
* @param window 窗口
* @param character 字符
* @param FRcolor 前景色RGB
* @param BKcolor 背景色RGB
* @return int
*/
int textui_putchar_window(struct textui_window_t *window, uint16_t character, uint32_t FRcolor, uint32_t BKcolor);
/**
* @brief 在默认窗口上输出一个字符
*
* @param character 字符
* @param FRcolor 前景色RGB
* @param BKcolor 背景色RGB
* @return int
*/
int textui_putchar(uint16_t character, uint32_t FRcolor, uint32_t BKcolor);
/**
* @brief 获取textui的帧缓冲区能容纳的内容的行数
*
* @return uint16_t
*/
uint16_t __textui_get_actual_lines();
/**
* @brief 获取当前渲染的窗口的id
*
* @return uint16_t
*/
uint32_t __textui_get_current_window_id();
/**
* @brief 初始化text ui框架
*
* @return int
*/
int textui_init();

224
kernel/src/libs/lockref.c Normal file
View File

@ -0,0 +1,224 @@
#include <common/lockref.h>
#include <common/compiler.h>
#ifdef __LOCKREF_ENABLE_CMPXCHG__
#include <arch/x86_64/asm/cmpxchg.h>
#define CMPXCHG_LOOP(__lock_ref, CODE, SUCCESS) \
{ \
int retry = 100; \
struct lockref old; \
BUILD_BUG_ON(sizeof(old) != sizeof(uint64_t)); \
old.lock_count = READ_ONCE(__lock_ref->lock_count); \
while (likely(!spin_is_locked(&old.lock))) \
{ \
struct lockref new = old; \
CODE; \
if (likely(arch_try_cmpxchg(&__lock_ref->lock_count, &old.lock_count, new.lock_count))) \
{ \
SUCCESS; \
} \
if (!--retry) \
break; \
pause(); \
} \
}
#else
#define CMPXCHG_LOOP(__lock_ref, CODE, SUCCESS) \
do \
{ \
} while (0)
#endif
/**
* @brief 原子的将引用计数加1
*
* @param lock_ref 指向要被操作的lockref变量的指针
*/
void lockref_inc(struct lockref *lock_ref)
{
// 先尝试使用cmpxchg进行无锁操作若成功则返回
CMPXCHG_LOOP(lock_ref, ++new.count;, return;);
// 无锁操作超时,或当前是上锁的状态,则退化为有锁操作
spin_lock(&lock_ref->lock);
++lock_ref->count;
spin_unlock(&lock_ref->lock);
}
/**
* @brief 原子地将引用计数加1.如果原来的count≤0则操作失败。
*
* @param lock_ref 指向要被操作的lockref变量的指针
* @return int 操作成功=>true
* 操作失败=>false
*/
bool lockref_inc_not_zero(struct lockref *lock_ref)
{
CMPXCHG_LOOP(lock_ref,
if (old.count <= 0) return false;
++new.count;
,
return true;)
bool retval;
spin_lock(&lock_ref->lock);
retval = false;
if (lock_ref->count > 0)
{
++lock_ref->count;
retval = true;
}
spin_unlock(&lock_ref->lock);
return retval;
}
/**
* @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)
{
CMPXCHG_LOOP(lock_ref,
if (old.count <= 0) break;
--new.count;
,
return new.count;);
// 如果xchg时处于已加锁的状态或者检测到old.count <= 0则采取加锁处理
int retval = -1;
spin_lock(&lock_ref->lock);
if (lock_ref->count > 0)
{
--lock_ref->count;
retval = lock_ref->count;
}
spin_unlock(&lock_ref->lock);
return retval;
}
/**
* @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)
{
CMPXCHG_LOOP(lock_ref,
if (old.count <= 0) return -1;
--new.count;
,
return new.count;);
return -1;
}
/**
* @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)
{
CMPXCHG_LOOP(lock_ref,
if (old.count <= 1) return false;
--new.count;
,
return true;)
bool retval = false;
spin_lock(&lock_ref->lock);
if (lock_ref->count > 1)
{
--lock_ref->count;
retval = true;
}
spin_unlock(&lock_ref->lock);
return retval;
}
/**
* @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)
{
CMPXCHG_LOOP(lock_ref,
if (old.count <= 1) break;
--new.count;
,
return true;);
bool retval = false;
spin_lock(&lock_ref->lock);
if (lock_ref->count > 1)
{
--lock_ref->count;
retval = true;
}
spin_unlock(&lock_ref->lock);
return retval;
}
/**
* @brief 将lockref变量标记为已经死亡将count设置为负值
*
* @param lock_ref 指向要被操作的lockref变量的指针
*/
void lockref_mark_dead(struct lockref *lock_ref)
{
// 需要自旋锁先被加锁,若没有被加锁,则会抛出错误信息
assert_spin_locked(&lock_ref->lock);
lock_ref->count = -128;
}
/**
* @brief 自增引用计数。除非该lockref已经死亡
*
* @param lock_ref 指向要被操作的lockref变量的指针
* @return true 操作成功
* @return false 操作失败lockref已死亡
*/
bool lockref_inc_not_dead(struct lockref *lock_ref)
{
CMPXCHG_LOOP(lock_ref,
if (old.count < 0) return false;
++new.count;
,
return true;)
bool retval = false;
// 快捷路径操作失败,尝试加锁
spin_lock(&lock_ref->lock);
if (lock_ref->count >= 0)
{
++lock_ref->count;
retval = true;
}
spin_unlock(&lock_ref->lock);
return retval;
}

3155
kernel/src/libs/lz4.c Normal file

File diff suppressed because it is too large Load Diff

1
kernel/src/libs/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod printk;

120
kernel/src/libs/mutex.c Normal file
View File

@ -0,0 +1,120 @@
#include <common/mutex.h>
#include <mm/slab.h>
#include <sched/sched.h>
/**
* @brief 初始化互斥量
*
* @param lock mutex结构体
*/
void mutex_init(mutex_t *lock)
{
atomic_set(&lock->count, 1);
spin_init(&lock->wait_lock);
list_init(&lock->wait_list);
}
static void __mutex_sleep()
{
current_pcb->state = PROC_UNINTERRUPTIBLE;
sched();
}
static void __mutex_acquire(mutex_t *lock)
{
}
/**
* @brief 对互斥量加锁
*
* @param lock mutex结构体
*/
void mutex_lock(mutex_t *lock)
{
bool lock_ok = 0;
while (lock_ok == false)
{
spin_lock(&lock->wait_lock);
if (likely(mutex_is_locked(lock)))
{
struct mutex_waiter_t *waiter = (struct mutex_waiter_t *)kzalloc(sizeof(struct mutex_waiter_t), 0);
if (waiter == NULL)
{
kerror("In mutex_lock: no memory to alloc waiter. Program's behaviour might be indetermined!");
spin_unlock(&lock->wait_lock);
return;
}
// memset(waiter, 0, sizeof(struct mutex_waiter_t));
waiter->pcb = current_pcb;
list_init(&waiter->list);
list_append(&lock->wait_list, &waiter->list);
spin_unlock(&lock->wait_lock);
__mutex_sleep();
}
else
{
atomic_dec(&lock->count);
spin_unlock(&lock->wait_lock);
lock_ok = true;
}
}
}
/**
* @brief 对互斥量解锁
*
* @param lock mutex结构体
*/
void mutex_unlock(mutex_t *lock)
{
if (unlikely(!mutex_is_locked(lock)))
return;
spin_lock(&lock->wait_lock);
struct mutex_waiter_t *wt = NULL;
if (mutex_is_locked(lock))
{
if (!list_empty(&lock->wait_list))
wt = container_of(list_next(&lock->wait_list), struct mutex_waiter_t, list);
atomic_inc(&lock->count);
if (wt != NULL)
list_del(&wt->list);
}
spin_unlock(&lock->wait_lock);
if (wt != NULL)
{
process_wakeup(wt->pcb);
kfree(wt);
}
}
/**
* @brief 尝试对互斥量加锁
*
* @param lock mutex结构体
*
* @return 成功加锁->1, 加锁失败->0
*/
int mutex_trylock(mutex_t *lock)
{
if (mutex_is_locked(lock))
return 0;
spin_lock(&lock->wait_lock);
if (mutex_is_locked(lock))
{
spin_unlock(&lock->wait_lock);
return 0;
}
else
{
atomic_dec(&lock->count);
spin_unlock(&lock->wait_lock);
return 1;
}
}

627
kernel/src/libs/printk.c Normal file
View File

@ -0,0 +1,627 @@
//
// Created by longjin on 2022/1/22.
//
#include <common/kprint.h>
#include <common/printk.h>
#include <common/spinlock.h>
#include <libs/libUI/textui.h>
#include <mm/mm.h>
#include <common/math.h>
#include <common/string.h>
static spinlock_t __printk_lock = {1};
/**
* @brief 将数字按照指定的要求转换成对应的字符串2~36进制
*
* @param str 要返回的字符串
* @param num 要打印的数值
* @param base 基数
* @param field_width 区域宽度
* @param precision 精度
* @param flags 标志位
*/
static char *write_num(char *str, ul num, int base, int field_width, int precision, int flags);
static char *write_float_point_num(char *str, double num, int field_width, int precision, int flags);
static int skip_and_atoi(const char **s)
{
/**
* @brief 获取连续的一段字符对应整数的值
* @param:**s 指向 指向字符串的指针 的指针
*/
int ans = 0;
while (is_digit(**s))
{
ans = ans * 10 + (**s) - '0';
++(*s);
}
return ans;
}
/**
* @brief 将字符串按照fmt和args中的内容进行格式化当buf_size为-1时字符串直接保存到buf中
* 否则将字符串前buf_size-1个字符放入大小为buf_size的buf数组中
*
* @param buf 结果缓冲区
* @param fmt 格式化字符串
* @param args 内容
* @param buf_size buf_size为-1时不指定buf的大小否则buf大小为buf_size
* @return 最终字符串的长度
*/
static int __do_vsprintf(char *buf, const char *fmt, int buf_size, va_list args)
{
// 当需要输出的字符串的指针为空时,使用该字符填充目标字符串的指针
static const char __end_zero_char = '\0';
char *str = NULL, *s = NULL, *end = NULL;
str = buf;
int flags; // 用来存储格式信息的bitmap
int field_width; //区域宽度
int precision; //精度
int qualifier; //数据显示的类型
int len;
if (buf_size != -1)
{
end = buf + buf_size;
}
//开始解析字符串
for (; *fmt; ++fmt)
{
//内容不涉及到格式化,直接输出
if (*fmt != '%')
{
*str = *fmt;
++str;
continue;
}
//开始格式化字符串
//清空标志位和field宽度
field_width = flags = 0;
bool flag_tmp = true;
bool flag_break = false;
++fmt;
while (flag_tmp)
{
switch (*fmt)
{
case '\0':
//结束解析
flag_break = true;
flag_tmp = false;
break;
case '-':
// 左对齐
flags |= LEFT;
++fmt;
break;
case '+':
//在正数前面显示加号
flags |= PLUS;
++fmt;
break;
case ' ':
flags |= SPACE;
++fmt;
break;
case '#':
//在八进制数前面显示 '0o',在十六进制数前面显示 '0x' 或 '0X'
flags |= SPECIAL;
++fmt;
break;
case '0':
//显示的数字之前填充0来取代空格
flags |= PAD_ZERO;
++fmt;
break;
default:
flag_tmp = false;
break;
}
}
if (flag_break)
break;
//获取区域宽度
field_width = -1;
if (*fmt == '*')
{
field_width = va_arg(args, int);
++fmt;
}
else if (is_digit(*fmt))
{
field_width = skip_and_atoi(&fmt);
if (field_width < 0)
{
field_width = -field_width;
flags |= LEFT;
}
}
//获取小数精度
precision = -1;
if (*fmt == '.')
{
++fmt;
if (*fmt == '*')
{
precision = va_arg(args, int);
++fmt;
}
else if (is_digit(*fmt))
{
precision = skip_and_atoi(&fmt);
}
}
//获取要显示的数据的类型
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z')
{
qualifier = *fmt;
++fmt;
}
//为了支持lld
if (qualifier == 'l' && *fmt == 'l', *(fmt + 1) == 'd')
++fmt;
//转化成字符串
long long *ip;
switch (*fmt)
{
//输出 %
case '%':
*str++ = '%';
break;
// 显示一个字符
case 'c':
//靠右对齐
if (!(flags & LEFT))
{
while (--field_width > 0)
{
*str = ' ';
++str;
}
}
*str++ = (unsigned char)va_arg(args, int);
while (--field_width > 0)
{
*str = ' ';
++str;
}
break;
//显示一个字符串
case 's':
s = va_arg(args, char *);
if (!s)
s = &__end_zero_char;
len = strlen(s);
if (precision < 0)
{
//未指定精度
precision = len;
}
else if (len > precision)
{
len = precision;
}
//靠右对齐
if (!(flags & LEFT))
while (len < field_width--)
{
*str = ' ';
++str;
}
for (int i = 0; i < len; i++)
{
*str = *s;
++s;
++str;
}
while (len < field_width--)
{
*str = ' ';
++str;
}
break;
//以八进制显示字符串
case 'o':
flags |= SMALL;
case 'O':
flags |= SPECIAL;
if (qualifier == 'l')
str = write_num(str, va_arg(args, long long), 8, field_width, precision, flags);
else
str = write_num(str, va_arg(args, int), 8, field_width, precision, flags);
break;
//打印指针指向的地址
case 'p':
if (field_width == 0)
{
field_width = 2 * sizeof(void *);
flags |= PAD_ZERO;
}
str = write_num(str, (unsigned long)va_arg(args, void *), 16, field_width, precision, flags);
break;
//打印十六进制
case 'x':
flags |= SMALL;
case 'X':
// flags |= SPECIAL;
if (qualifier == 'l')
str = write_num(str, va_arg(args, ll), 16, field_width, precision, flags);
else
str = write_num(str, va_arg(args, int), 16, field_width, precision, flags);
break;
//打印十进制有符号整数
case 'i':
case 'd':
flags |= SIGN;
if (qualifier == 'l')
str = write_num(str, va_arg(args, long long), 10, field_width, precision, flags);
else
str = write_num(str, va_arg(args, int), 10, field_width, precision, flags);
break;
//打印十进制无符号整数
case 'u':
if (qualifier == 'l')
str = write_num(str, va_arg(args, unsigned long long), 10, field_width, precision, flags);
else
str = write_num(str, va_arg(args, unsigned int), 10, field_width, precision, flags);
break;
//输出有效字符数量到*ip对应的变量
case 'n':
if (qualifier == 'l')
ip = va_arg(args, long long *);
else
ip = (ll *)va_arg(args, int *);
*ip = str - buf;
break;
case 'f':
// 默认精度为3
// printk("1111\n");
// va_arg(args, double);
// printk("222\n");
if (precision < 0)
precision = 3;
str = write_float_point_num(str, va_arg(args, double), field_width, precision, flags);
break;
//对于不识别的控制符,直接输出
default:
*str++ = '%';
if (*fmt)
*str++ = *fmt;
else
--fmt;
break;
}
}
//实现vsnprintf 的功能
if (buf_size > 0)
{
if (str < end)
{
*str = '\0';
}
else
{
*(end-1) = '\0';
}
return buf_size;
}
else
{
*str = '\0';
}
//返回缓冲区已有字符串的长度。
return str - buf;
}
/**
* 将字符串按照fmt和args中的内容进行格式化然后保存到buf中
* @param buf 结果缓冲区
* @param fmt 格式化字符串
* @param args 内容
* @return 最终字符串的长度
*/
int vsprintf(char *buf, const char *fmt, va_list args)
{
return __do_vsprintf(buf, fmt, -1, 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)
{
return __do_vsprintf(buf, fmt, buf_size, args);
}
static char *write_num(char *str, ul num, int base, int field_width, int precision, int flags)
{
/**
* @brief 将数字按照指定的要求转换成对应的字符串
*
* @param str 要返回的字符串
* @param num 要打印的数值
* @param base 基数
* @param field_width 区域宽度
* @param precision 精度
* @param flags 标志位
*/
// 首先判断是否支持该进制
if (base < 2 || base > 36)
return 0;
char pad, sign, tmp_num[100];
const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// 显示小写字母
if (flags & SMALL)
digits = "0123456789abcdefghijklmnopqrstuvwxyz";
if (flags & LEFT)
flags &= ~PAD_ZERO;
// 设置填充元素
pad = (flags & PAD_ZERO) ? '0' : ' ';
sign = 0;
if (flags & SIGN)
{
int64_t signed_num = (int64_t)num;
if (signed_num < 0)
{
sign = '-';
num = -signed_num;
}
else
num = signed_num;
}
else
{
// 设置符号
sign = (flags & PLUS) ? '+' : ((flags & SPACE) ? ' ' : 0);
}
// sign占用了一个宽度
if (sign)
--field_width;
if (flags & SPECIAL)
if (base == 16) // 0x占用2个位置
field_width -= 2;
else if (base == 8) // O占用一个位置
--field_width;
int js_num = 0; // 临时数字字符串tmp_num的长度
if (num == 0)
tmp_num[js_num++] = '0';
else
{
num = ABS(num);
//进制转换
while (num > 0)
{
tmp_num[js_num++] = digits[num % base]; // 注意这里,输出的数字,是小端对齐的。低位存低位
num /= base;
}
}
if (js_num > precision)
precision = js_num;
field_width -= precision;
// 靠右对齐
if (!(flags & (LEFT + PAD_ZERO)))
while (field_width-- > 0)
*str++ = ' ';
if (sign)
*str++ = sign;
if (flags & SPECIAL)
if (base == 16)
{
*str++ = '0';
*str++ = digits[33];
}
else if (base == 8)
*str++ = digits[24]; //注意这里是英文字母O或者o
if (!(flags & LEFT))
while (field_width-- > 0)
*str++ = pad;
while (js_num < precision)
{
--precision;
*str++ = '0';
}
while (js_num-- > 0)
*str++ = tmp_num[js_num];
while (field_width-- > 0)
*str++ = ' ';
return str;
}
static char *write_float_point_num(char *str, double num, int field_width, int precision, int flags)
{
/**
* @brief 将浮点数按照指定的要求转换成对应的字符串
*
* @param str 要返回的字符串
* @param num 要打印的数值
* @param field_width 区域宽度
* @param precision 精度
* @param flags 标志位
*/
char pad, sign, tmp_num_z[100], tmp_num_d[350];
const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// 显示小写字母
if (flags & SMALL)
digits = "0123456789abcdefghijklmnopqrstuvwxyz";
// 设置填充元素
pad = (flags & PAD_ZERO) ? '0' : ' ';
sign = 0;
if (flags & SIGN && num < 0)
{
sign = '-';
num = -num;
}
else
{
// 设置符号
sign = (flags & PLUS) ? '+' : ((flags & SPACE) ? ' ' : 0);
}
// sign占用了一个宽度
if (sign)
--field_width;
int js_num_z = 0, js_num_d = 0; // 临时数字字符串tmp_num_z tmp_num_d的长度
uint64_t num_z = (uint64_t)(num); // 获取整数部分
uint64_t num_decimal = (uint64_t)(round(1.0 * (num - num_z) * pow(10, precision))); // 获取小数部分
if (num == 0 || num_z == 0)
tmp_num_z[js_num_z++] = '0';
else
{
//存储整数部分
while (num_z > 0)
{
tmp_num_z[js_num_z++] = digits[num_z % 10]; // 注意这里,输出的数字,是小端对齐的。低位存低位
num_z /= 10;
}
}
while (num_decimal > 0)
{
tmp_num_d[js_num_d++] = digits[num_decimal % 10];
num_decimal /= 10;
}
field_width -= (precision + 1 + js_num_z);
// 靠右对齐
if (!(flags & LEFT))
while (field_width-- > 0)
*str++ = pad;
if (sign)
*str++ = sign;
// 输出整数部分
while (js_num_z > 0)
{
*str++ = tmp_num_z[js_num_z - 1];
--js_num_z;
}
*str++ = '.';
// 输出小数部分
int total_dec_count = js_num_d;
for (int i = 0; i < precision && js_num_d-- > 0; ++i)
*str++ = tmp_num_d[js_num_d];
while (total_dec_count < precision)
{
++total_dec_count;
*str++ = '0';
}
while (field_width-- > 0)
*str++ = ' ';
return str;
}
/**
* @brief 格式化打印字符串
*
* @param FRcolor 前景色
* @param BKcolor 背景色
* @param ... 格式化字符串
*/
int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ...)
{
uint64_t rflags;
spin_lock_irqsave(&__printk_lock, rflags);
va_list args;
va_start(args, fmt);
char buf[4096]; // vsprintf()的缓冲区
int len = vsprintf(buf, fmt, args);
va_end(args);
unsigned char current;
int i; // 总共输出的字符数
for (i = 0; i < len; ++i)
{
current = *(buf + i);
// 输出
textui_putchar(current, FRcolor, BKcolor);
}
spin_unlock_irqrestore(&__printk_lock, rflags);
return i;
}
int sprintk(char *buf, const char *fmt, ...)
{
int count = 0;
va_list args;
va_start(args, fmt);
count = vsprintf(buf, fmt, args);
va_end(args);
return count;
}

54
kernel/src/libs/printk.rs Normal file
View File

@ -0,0 +1,54 @@
use crate::include::bindings::bindings::{printk_color, BLACK, WHITE};
use ::core::ffi::c_char;
use alloc::vec::Vec;
use core::fmt;
pub struct PrintkWriter;
impl PrintkWriter {
/// 调用C语言编写的printk_color,并输出白底黑字暂时只支持ascii字符
/// @param str: 要写入的字符
pub fn __write_string(&mut self, s: &str) {
let str_to_print = self.__utf8_to_ascii(s);
unsafe {
printk_color(WHITE, BLACK, str_to_print.as_ptr() as *const c_char);
}
}
pub fn __write_string_color(&self, fr_color: u32, bk_color: u32, s: &str) {
let str_to_print = self.__utf8_to_ascii(s);
unsafe {
printk_color(fr_color, bk_color, str_to_print.as_ptr() as *const c_char);
}
}
/// 将s这个utf8字符串转换为ascii字符串
/// @param s 待转换的utf8字符串
/// @return Vec<u8> 转换结束后的Ascii字符串
pub fn __utf8_to_ascii(&self, s: &str) -> Vec<u8> {
let mut ascii_str: Vec<u8> = Vec::with_capacity(s.len() + 1);
for byte in s.bytes() {
match byte {
0..=127 => {
ascii_str.push(byte);
}
_ => {}
}
}
ascii_str.push(b'\0');
return ascii_str;
}
}
/// 为Printk Writer实现core::fmt::Write, 使得能够借助Rust自带的格式化组件格式化字符并输出
impl fmt::Write for PrintkWriter {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.__write_string(s);
Ok(())
}
}
#[doc(hidden)]
pub fn __printk(args: fmt::Arguments) {
use fmt::Write;
PrintkWriter.write_fmt(args).unwrap();
}

View File

@ -0,0 +1,13 @@
rust_helloworld_objs:=
ifneq ("$(RUSTC)", "")
rust_helloworld_objs += helloworld.o
endif
all: $(rust_helloworld_objs)
helloworld.o: helloworld.rs
@echo Compile helloworld.o
@echo rustc=$(which rustc)
$(shell $(RUSTC) --crate-type staticlib --target x86_64-unknown-none -o helloworld.o helloworld.rs)

View File

@ -0,0 +1,17 @@
#![no_std]
#![no_main]
use core::panic::PanicInfo;
#[no_mangle]
pub extern "C" fn rust_helloworld_a_plus_b(a: i32, b: i32) -> i32 {
return a+b;
}
/// 这个函数将在panic时被调用
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
// rustc --crate-type staticlib --target x86_64-unknown-none -o helloworld.o helloworld.rs

View File

@ -0,0 +1,43 @@
#include <common/semaphore.h>
#include <sched/sched.h>
#include <process/process.h>
void semaphore_down(semaphore_t *sema)
{
if (atomic_read(&sema->counter) > 0) // 信号量大于0资源充足
atomic_dec(&sema->counter);
else // 资源不足,进程休眠
{
// 将当前进程加入信号量的等待队列
wait_queue_node_t wait;
wait_queue_init(&wait, current_pcb);
current_pcb->state = PROC_UNINTERRUPTIBLE;
list_append(&sema->wait_queue.wait_list, &wait.wait_list);
// 执行调度
sched();
}
}
void semaphore_up(semaphore_t *sema)
{
if (list_empty(&sema->wait_queue.wait_list)) // 没有进程在等待资源
{
atomic_inc(&sema->counter);
}
else // 有进程在等待资源,唤醒进程
{
wait_queue_node_t *wq = container_of(list_next(&sema->wait_queue.wait_list), wait_queue_node_t, wait_list);
list_del(&wq->wait_list);
wq->pcb->state = PROC_RUNNING;
sched_enqueue(wq->pcb);
// 当前进程缺少需要的资源,立即标为需要被调度
current_pcb->flags |= PF_NEED_SCHED;
}
};

29
kernel/src/libs/stdlib.c Normal file
View File

@ -0,0 +1,29 @@
#include <common/stdlib.h>
/**
* @brief 将长整型转换为字符串
*
* @param input 输入的数据
* @return const char* 结果字符串
*/
const char *ltoa(long input)
{
/* large enough for -9223372036854775808 */
static char buffer[21] = {0};
char *pos = buffer + sizeof(buffer) - 1;
int neg = input < 0;
unsigned long n = neg ? -input : input;
*pos-- = '\0';
do
{
*pos-- = '0' + n % 10;
n /= 10;
if (pos < buffer)
return pos + 1;
} while (n);
if (neg)
*pos-- = '-';
return pos + 1;
}

109
kernel/src/libs/string.c Normal file
View File

@ -0,0 +1,109 @@
#include <common/string.h>
#include <common/glib.h>
/**
* @brief 拷贝整个字符串
*
* @param dst 目标地址
* @param src 源地址
* @return char* 目标字符串
*/
char *strcpy(char *dst, const char *src)
{
while (*src)
{
*(dst++) = *(src++);
}
*dst = 0;
return dst;
}
long strnlen(const char *src, unsigned long maxlen)
{
if (src == NULL)
return 0;
register int __res = 0;
while (src[__res] != '\0' && __res < maxlen)
{
++__res;
}
return __res;
}
/*
比较字符串 FirstPart and SecondPart
FirstPart = SecondPart => 0
FirstPart > SecondPart => 1
FirstPart < SecondPart => -1
*/
int strcmp(const char *FirstPart, const char *SecondPart)
{
register int __res;
__asm__ __volatile__("cld \n\t"
"1: \n\t"
"lodsb \n\t"
"scasb \n\t"
"jne 2f \n\t"
"testb %%al, %%al \n\t"
"jne 1b \n\t"
"xorl %%eax, %%eax \n\t"
"jmp 3f \n\t"
"2: \n\t"
"movl $1, %%eax \n\t"
"jl 3f \n\t"
"negl %%eax \n\t"
"3: \n\t"
: "=a"(__res)
: "D"(FirstPart), "S"(SecondPart)
:);
return __res;
}
char *strncpy(char *dst, const char *src, long count)
{
__asm__ __volatile__("cld \n\t"
"1: \n\t"
"decq %2 \n\t"
"js 2f \n\t"
"lodsb \n\t"
"stosb \n\t"
"testb %%al, %%al \n\t"
"jne 1b \n\t"
"rep \n\t"
"stosb \n\t"
"2: \n\t"
:
: "S"(src), "D"(dst), "c"(count)
: "ax", "memory");
return dst;
}
long strncpy_from_user(char *dst, const char *src, unsigned long size)
{
if (!verify_area((uint64_t)src, size))
return 0;
strncpy(dst, src, size);
return size;
}
/**
* @brief 测量来自用户空间的字符串的长度,会检验地址空间是否属于用户空间
* @param src
* @param maxlen
* @return long
*/
long strnlen_user(const char *src, unsigned long maxlen)
{
unsigned long size = strlen(src);
// 地址不合法
if (!verify_area((uint64_t)src, size))
return 0;
return size <= maxlen ? size : maxlen;
}

View File

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

View File

@ -0,0 +1,15 @@
#include <syscall/syscall_num.h>
#include <syscall/syscall.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)
{
return (pid_t)enter_syscall_int(SYS_WAIT4, (uint64_t)pid, (uint64_t)stat_loc, options, 0, 0, 0, 0, 0);
}

39
kernel/src/libs/unistd.c Normal file
View File

@ -0,0 +1,39 @@
#include <common/unistd.h>
#include <common/glib.h>
/**
* @brief fork当前进程
*
* @return pid_t
*/
pid_t fork(void)
{
return (pid_t)enter_syscall_int(SYS_FORK, 0, 0, 0, 0, 0, 0, 0, 0);
}
/**
* @brief vfork当前进程
*
* @return pid_t
*/
pid_t vfork(void)
{
return (pid_t)enter_syscall_int(SYS_VFORK, 0, 0, 0, 0, 0, 0, 0, 0);
}
void swab(void *restrict src, void *restrict dest, ssize_t nbytes)
{
unsigned char buf[32];
char *_src = src;
char *_dest = dest;
uint32_t transfer;
for (; nbytes > 0; nbytes -= transfer)
{
transfer = (nbytes > 32) ? 32 : nbytes;
memcpy(buf, _src, transfer);
memcpy(_src, _dest, transfer);
memcpy(_dest, buf, transfer);
_src += transfer;
_dest += transfer;
}
}

View File

@ -0,0 +1,84 @@
#include <common/spinlock.h>
#include <common/wait_queue.h>
#include <mm/slab.h>
#include <process/process.h>
#include <sched/sched.h>
/**
* @brief 初始化等待队列
*
* @param wait_queue 等待队列
* @param pcb pcb
*/
void wait_queue_init(wait_queue_node_t *wait_queue, struct process_control_block *pcb)
{
list_init(&wait_queue->wait_list);
wait_queue->pcb = pcb;
}
/**
* @brief 在等待队列上进行等待
*
* @param wait_queue_head 队列头指针
*/
void wait_queue_sleep_on(wait_queue_node_t *wait_queue_head)
{
wait_queue_node_t *wait = (wait_queue_node_t *)kzalloc(sizeof(wait_queue_node_t), 0);
wait_queue_init(wait, current_pcb);
current_pcb->state = PROC_UNINTERRUPTIBLE;
list_append(&wait_queue_head->wait_list, &wait->wait_list);
sched();
}
/**
* @brief 在等待队列上进行等待,同时释放自旋锁
*
* @param wait_queue_head 队列头指针
*/
void wait_queue_sleep_on_unlock(wait_queue_node_t *wait_queue_head,
void *lock)
{
wait_queue_node_t *wait = (wait_queue_node_t *)kzalloc(sizeof(wait_queue_node_t), 0);
wait_queue_init(wait, current_pcb);
current_pcb->state = PROC_UNINTERRUPTIBLE;
list_append(&wait_queue_head->wait_list, &wait->wait_list);
spin_unlock((spinlock_t *)lock);
sched();
}
/**
* @brief 在等待队列上进行等待(允许中断)
*
* @param wait_queue_head 队列头指针
*/
void wait_queue_sleep_on_interriptible(wait_queue_node_t *wait_queue_head)
{
wait_queue_node_t *wait = (wait_queue_node_t *)kzalloc(sizeof(wait_queue_node_t), 0);
wait_queue_init(wait, current_pcb);
current_pcb->state = PROC_INTERRUPTIBLE;
list_append(&wait_queue_head->wait_list, &wait->wait_list);
sched();
}
/**
* @brief 唤醒在等待队列的头部的进程
*
* @param wait_queue_head
* @param state
*/
void wait_queue_wakeup(wait_queue_node_t *wait_queue_head, int64_t state)
{
if (list_empty(&wait_queue_head->wait_list))
return;
wait_queue_node_t *wait = container_of(list_next(&wait_queue_head->wait_list), wait_queue_node_t, wait_list);
// 符合唤醒条件
if (wait->pcb->state & state)
{
list_del(&wait->wait_list);
process_wakeup(wait->pcb);
kfree(wait);
}
}

View File

@ -0,0 +1,82 @@
#include <common/wait_queue_head.h>
#include <process/process.h>
#include <sched/sched.h>
/**
* @brief 初始化等待队列
*
* @param wait_queue 等待队列
* @param pcb pcb
*/
void wait_queue_head_init(wait_queue_head_t *wait_queue)
{
list_init(&wait_queue->wait_list);
spin_init(&wait_queue->lock);
}
/**
* @brief 在等待队列上进行等待, 但是你需要确保wait已经被init, 同时wakeup只能使用wake_up_on_stack函数。
*
* @param wait_queue_head 队列头指针
*/
void wait_queue_sleep_with_node(wait_queue_head_t *q, wait_queue_node_t *wait)
{
BUG_ON(wait->pcb == NULL);
wait->pcb->state = PROC_UNINTERRUPTIBLE;
list_append(&q->wait_list, &wait->wait_list);
sched();
}
/**
* @brief 在等待队列上进行等待,同时释放自旋锁, 但是你需要确保wait已经被init, 同时wakeup只能使用wake_up_on_stack函数。
*
* @param wait_queue_head 队列头指针
*/
void wait_queue_sleep_with_node_unlock(wait_queue_head_t *q, wait_queue_node_t *wait, void *lock)
{
BUG_ON(wait->pcb == NULL);
wait->pcb->state = PROC_UNINTERRUPTIBLE;
list_append(&q->wait_list, &wait->wait_list);
spin_unlock((spinlock_t *)lock);
sched();
}
/**
* @brief 在等待队列上进行等待(允许中断), 但是你需要确保wait已经被init, 同时wakeup只能使用wake_up_on_stack函数。
*
* @param wait_queue_head 队列头指针
*/
void wait_queue_sleep_with_node_interriptible(wait_queue_head_t *q, wait_queue_node_t *wait)
{
BUG_ON(wait->pcb == NULL);
wait->pcb->state = PROC_INTERRUPTIBLE;
list_append(&q->wait_list, &wait->wait_list);
sched();
}
/**
* @brief 唤醒在等待队列的头部的进程, 但是不会free掉这个节点的空间(默认这个节点在栈上创建)
*
* @param wait_queue_head
* @param state
*/
void wait_queue_wakeup_on_stack(wait_queue_head_t *q, int64_t state)
{
if (list_empty(&q->wait_list))
return;
wait_queue_node_t *wait = container_of(list_next(&q->wait_list), wait_queue_node_t, wait_list);
// 符合唤醒条件
if (wait->pcb->state & state)
{
list_del_init(&wait->wait_list);
process_wakeup(wait->pcb);
}
}