《操作系统真象还原》从零开始自制操作系统 自写源码实现 (lib相关文件)


专栏博客链接


《操作系统真象还原》从零开始自制操作系统 全章节博客链接


lib/kernel相关文件


编写完的bitmap.c


#include "bitmap.h"            //函数定义
#include "global.h"            //global.h 不清楚
#include "string.h"            //memset函数要用
#include "interrupt.h"         
#include "print.h"             
#include "debug.h"

#define BITMAP_MASK 1

void bitmap_init(struct bitmap* btmp)
{
    memset(btmp->bits,0,btmp->btmp_bytes_len);
    return;
}

bool bitmap_scan_test(struct bitmap* btmp,uint32_t bit_idx)  //一个8位的数 bit_idx/8 找数组下标 %得索引下的具体位置
{
    uint32_t byte_idx = bit_idx/8;
    uint32_t byte_pos = bit_idx%8;
    return (btmp->bits[byte_idx] & (BITMAP_MASK << byte_pos));
}

/*
   这个函数写很多的原因 是因为刚开始先用一个字节的快速扫描
   看是否每个字节中存在 位为0的位置 然后紧接着再看连续位 挺有意思 自己先写写看
*/

int bitmap_scan(struct bitmap* btmp, uint32_t cnt) {
   uint32_t idx_byte = 0;	 // 用于记录空闲位所在的字节
/* 先逐字节比较,蛮力法 */
   while (( 0xff == btmp->bits[idx_byte]) && (idx_byte < btmp->btmp_bytes_len)) {
/* 1表示该位已分配,所以若为0xff,则表示该字节内已无空闲位,向下一字节继续找 */
      idx_byte++;
   }

   ASSERT(idx_byte < btmp->btmp_bytes_len);
   if (idx_byte == btmp->btmp_bytes_len) {  // 若该内存池找不到可用空间		
      return -1;
   }

 /* 若在位图数组范围内的某字节内找到了空闲位,
  * 在该字节内逐位比对,返回空闲位的索引。*/
   int idx_bit = 0;
 /* 和btmp->bits[idx_byte]这个字节逐位对比 */
   while ((uint8_t)(BITMAP_MASK << idx_bit) & btmp->bits[idx_byte]) { 
	 idx_bit++;
   }
	 
   int bit_idx_start = idx_byte * 8 + idx_bit;    // 空闲位在位图内的下标
   if (cnt == 1) {
      return bit_idx_start;
   }

   uint32_t bit_left = (btmp->btmp_bytes_len * 8 - bit_idx_start);   // 记录还有多少位可以判断
   uint32_t next_bit = bit_idx_start + 1;
   uint32_t count = 1;	      // 用于记录找到的空闲位的个数

   bit_idx_start = -1;	      // 先将其置为-1,若找不到连续的位就直接返回
   while (bit_left-- > 0) {
      if (!(bitmap_scan_test(btmp, next_bit))) {	 // 若next_bit为0
	 count++;
      } else {
	 count = 0;
      }
      if (count == cnt) {	    // 若找到连续的cnt个空位
	 bit_idx_start = next_bit - cnt + 1;
	 break;
      }
      next_bit++;          
   }
   return bit_idx_start;
}

void bitmap_set(struct bitmap* btmp,uint32_t bit_idx,int8_t value)
{
    ASSERT(value == 1 || value == 0);
    uint32_t byte_idx = bit_idx/8;
    uint32_t byte_pos = bit_idx%8;
    if(value)	btmp->bits[byte_idx] |=  (BITMAP_MASK << byte_pos);
    else	btmp->bits[byte_idx] &= ~(BITMAP_MASK << byte_pos);
    return;
}


编写完的bitmap.h


#ifndef __LIB_KERNEL_BITMAP_H
#define __LIB_KERNEL_BITMAP_H
#include "global.h"
#include "stdint.h"
#define BITMAP_MASK 1

struct bitmap
{
    uint32_t btmp_bytes_len;
    uint8_t* bits;
};

void bitmap_init(struct bitmap* btmp);
bool bitmap_scan_test(struct bitmap* btmp,uint32_t bit_idx);
int  bitmap_scan(struct bitmap* btmp,uint32_t cnt);
void bitmap_set(struct bitmap* btmp,uint32_t bit_idx,int8_t value); 

#endif

编写完的io.h


/**************	 机器模式   ***************
	 b -- 输出寄存器QImode名称,即寄存器中的最低8位:[a-d]l。
	 w -- 输出寄存器HImode名称,即寄存器中2个字节的部分,如[a-d]x。

	 HImode
	     “Half-Integer”模式,表示一个两字节的整数。 
	 QImode
	     “Quarter-Integer”模式,表示一个一字节的整数。 
*******************************************/ 

#ifndef __LIB_IO_H
#define __LIB_IO_H
#include "stdint.h"

/* 向端口port写入一个字节*/
static inline void outb(uint16_t port, uint8_t data) {
/*********************************************************
 a表示用寄存器al或ax或eax,对端口指定N表示0~255, d表示用dx存储端口号, 
 %b0表示对应al,%w1表示对应dx */ 
   asm volatile ( "outb %b0, %w1" : : "a" (data), "Nd" (port));    
/******************************************************/
}

/* 将addr处起始的word_cnt个字写入端口port */
static inline void outsw(uint16_t port, const void* addr, uint32_t word_cnt) {
/*********************************************************
   +表示此限制即做输入又做输出.
   outsw是把ds:esi处的16位的内容写入port端口, 我们在设置段描述符时, 
   已经将ds,es,ss段的选择子都设置为相同的值了,此时不用担心数据错乱。*/
   asm volatile ("cld; rep outsw" : "+S" (addr), "+c" (word_cnt) : "d" (port));
/******************************************************/
}

/* 将从端口port读入的一个字节返回 */
static inline uint8_t inb(uint16_t port) {
   uint8_t data;
   asm volatile ("inb %w1, %b0" : "=a" (data) : "Nd" (port));
   return data;
}

/* 将从端口port读入的word_cnt个字写入addr */
static inline void insw(uint16_t port, void* addr, uint32_t word_cnt) {
/******************************************************
   insw是将从端口port处读入的16位内容写入es:edi指向的内存,
   我们在设置段描述符时, 已经将ds,es,ss段的选择子都设置为相同的值了,
   此时不用担心数据错乱。*/
   asm volatile ("cld; rep insw" : "+D" (addr), "+c" (word_cnt) : "d" (port) : "memory");
/******************************************************/
}

#endif

编写完的list.c


#include "list.h"
#include "interrupt.h"
#include "stdint.h"
#include "debug.h"

#define NULL 0

//初始化双向链表
void list_init(struct list* list)
{
    list->head.prev = NULL;
    list->head.next = &list->tail;
    list->tail.prev = &list->head;
    list->tail.next = NULL;
}

//把链表 elem放在 before前面
void list_insert_before(struct list_elem* before,struct list_elem* elem)
{
    enum intr_status old_status = intr_disable();
       
    before->prev->next = elem;
    elem->prev = before->prev;
    elem->next = before;
    before->prev = elem;
    
    intr_set_status(old_status); 
    
}

//添加元素到链表队首
void list_push(struct list* plist,struct list_elem* elem)
{
    list_insert_before(plist->head.next,elem);
}

//添加元素到链表队尾
void list_append(struct list* plist,struct list_elem* elem)
{
    list_insert_before(&plist->tail,elem);
}

//让pelem脱离链表
void list_remove(struct list_elem* pelem)
{
    enum intr_status old_status = intr_disable();
    
    pelem->prev->next = pelem->next;
    pelem->next->prev = pelem->prev;
    
    intr_set_status(old_status);
}

//让链表的第一个元素脱离链表
struct list_elem* list_pop(struct list* plist)
{
    struct list_elem* ret = plist->head.next;
    list_remove(ret);
    return ret;
}

bool list_empty(struct list* plist)
{
    return (plist->head.next == &plist->tail ? true : false);
}

uint32_t list_len(struct list* plist)
{
    uint32_t ret = 0;
    struct list_elem* next = plist->head.next;
    while(next != &plist->tail)
    {
    	next = next->next;
    	++ret;
    }
    return ret;
}

struct list_elem* list_traversal(struct list* plist,function func,int arg)
{
    struct list_elem* elem = plist->head.next;
    if(list_empty(plist))	return NULL;
    while(elem != &plist->tail)
    {
    	if(func(elem,arg))	return elem;
    	elem = elem->next;
    }
    return NULL;
}

bool elem_find(struct list* plist,struct list_elem* obj_elem)
{
    struct list_elem* ptr = plist->head.next;
    while(ptr != &plist->tail)
    {
    	if(ptr == obj_elem)	return true; 
    	ptr = ptr->next;
    }
    return false;
}


编写完的list.h


#ifndef __LIB_KERNEL_LIST_H
#define __LIB_KERNEL_LIST_H
#include "stdint.h"
	
struct list_elem
{
    struct list_elem* prev; //前面的节点
    struct list_elem* next; //后面的节点
};

struct list
{
    struct list_elem head; // 亘古不变的头部
    struct list_elem tail; // 亘古不变的尾部
};

typedef bool (function) (struct list_elem*,int arg);

void list_init(struct list*);
void list_insert_before(struct list_elem* before,struct list_elem* elem);
void list_push(struct list* plist,struct list_elem* elem);
void list_append(struct list* plist,struct list_elem* elem);
void list_remove(struct list_elem* pelem);
struct list_elem* list_pop(struct list* plist);
bool list_empty(struct list* plist);
uint32_t list_len(struct list* plist);
struct list_elem* list_traversal(struct list* plist,function func,int arg);
bool elem_find(struct list* plist,struct list_elem* obj_elem);

#endif

编写完的print.h


#ifndef __LIB_KERNEL_PRINT_H
#define __LIB_KERNEL_PRINT_H
#include "stdint.h"
void put_char(uint8_t char_asci);
void put_str(char* message);
void put_int(uint32_t num);	 // 以16进制打印
void cls_screen(void);
 
#endif


编写完的print.S


TI_GDT equ  0
RPL0  equ   0
SELECTOR_VIDEO equ (0x0003<<3) + TI_GDT + RPL0

section .data
put_int_buffer    dq    0     ; 定义8字节缓冲区用于数字到字符的转换

[bits 32]
section .text
;--------------------------------------------
;put_str 通过put_char来打印以0字符结尾的字符串
;--------------------------------------------
global put_str
put_str:
;由于本函数中只用到了ebx和ecx,只备份这两个寄存器
   push ebx
   push ecx
   xor ecx, ecx		      ; 准备用ecx存储参数,清空
   mov ebx, [esp + 12]	      ; 从栈中得到待打印的字符串地址 
.goon:
   mov cl, [ebx]
   cmp cl, 0		      ; 如果处理到了字符串尾,跳到结束处返回
   jz .str_over
   push ecx		      ; 为put_char函数传递参数
   call put_char
   add esp, 4		      ; 回收参数所占的栈空间
   inc ebx		      ; 使ebx指向下一个字符
   jmp .goon
.str_over:
   pop ecx
   pop ebx
   ret


;--------------------   将小端字节序的数字变成对应的ascii后,倒置   -----------------------
;输入:栈中参数为待打印的数字
;输出:在屏幕上打印16进制数字,并不会打印前缀0x,如打印10进制15时,只会直接打印f,不会是0xf
;------------------------------------------------------------------------------------------
global put_int
put_int:
   pushad
   mov ebp, esp
   mov eax, [ebp+4*9]		       ; call的返回地址占4字节+pushad的84字节
   mov edx, eax
   mov edi, 7                          ; 指定在put_int_buffer中初始的偏移量
   mov ecx, 8			       ; 32位数字中,16进制数字的位数是8个
   mov ebx, put_int_buffer

;32位数字按照16进制的形式从低位到高位逐个处理,共处理816进制数字
.16based_4bits:			       ;4位二进制是16进制数字的1,遍历每一位16进制数字
   and edx, 0x0000000F		       ; 解析16进制数字的每一位。and与操作后,edx只有低4位有效
   cmp edx, 9			       ; 数字09和a~f需要分别处理成对应的字符
   jg .is_A2F 
   add edx, '0'			       ; ascii码是8位大小。add求和操作后,edx低8位有效。
   jmp .store
.is_A2F:
   sub edx, 10			       ; A~F 减去10 所得到的差,再加上字符A的ascii码,便是A~F对应的ascii码
   add edx, 'A'

;将每一位数字转换成对应的字符后,按照类似“大端”的顺序存储到缓冲区put_int_buffer
;高位字符放在低地址,低位字符要放在高地址,这样和大端字节序类似,只不过咱们这里是字符序.
.store:
; 此时dl中应该是数字对应的字符的ascii码
   mov [ebx+edi], dl		       
   dec edi
   shr eax, 4
   mov edx, eax 
   loop .16based_4bits

;现在put_int_buffer中已全是字符,打印之前,
;把高位连续的字符去掉,比如把字符000123变成123
.ready_to_print:
   inc edi			       ; 此时edi退减为-1(0xffffffff),1使其为0
.skip_prefix_0:  
   cmp edi,8			       ; 若已经比较第9个字符了,表示待打印的字符串为全0 
   je .full0 
;找出连续的0字符, edi做为非0的最高位字符的偏移
.go_on_skip:   
   mov cl, [put_int_buffer+edi]
   inc edi
   cmp cl, '0' 
   je .skip_prefix_0		       ; 继续判断下一位字符是否为字符0(不是数字0)
   dec edi			       ;edi在上面的inc操作中指向了下一个字符,若当前字符不为'0',要恢复edi指向当前字符		       
   jmp .put_each_num

.full0:
   mov cl,'0'			       ; 输入的数字为全0时,则只打印0
.put_each_num:
   push ecx			       ; 此时cl中为可打印的字符
   call put_char
   add esp, 4
   inc edi			       ; 使edi指向下一个字符
   mov cl, [put_int_buffer+edi]	       ; 获取下一个字符到cl寄存器
   cmp edi,8
   jl .put_each_num
   popad
   ret

;------------------------   put_char   -----------------------------
;功能描述:把栈中的1个字符写入光标所在处
;-------------------------------------------------------------------   
global put_char
put_char:
   pushad	   ;备份32位寄存器环境
   ;需要保证gs中为正确的视频段选择子,为保险起见,每次打印时都为gs赋值
   mov ax, SELECTOR_VIDEO	       ; 不能直接把立即数送入段寄存器
   mov gs, ax

;;;;;;;;;  获取当前光标位置 ;;;;;;;;;
   ;先获得高8位
   mov dx, 0x03d4  ;索引寄存器
   mov al, 0x0e	   ;用于提供光标位置的高8位
   out dx, al
   mov dx, 0x03d5  ;通过读写数据端口0x3d5来获得或设置光标位置 
   in al, dx	   ;得到了光标位置的高8位
   mov ah, al

   ;再获取低8位
   mov dx, 0x03d4
   mov al, 0x0f
   out dx, al
   mov dx, 0x03d5 
   in al, dx

   ;将光标存入bx
   mov bx, ax	  
   ;下面这行是在栈中获取待打印的字符
   mov ecx, [esp + 36]	      ;pushad压入4×832字节,加上主调函数的返回地址4字节,故esp+36字节
   cmp cl, 0xd				  ;CR是0x0d,LF是0x0a
   jz .is_carriage_return
   cmp cl, 0xa
   jz .is_line_feed

   cmp cl, 0x8				  ;BS(backspace)的asc码是8
   jz .is_backspace
   jmp .put_other	   
;;;;;;;;;;;;;;;;;;

 .is_backspace:		      
;;;;;;;;;;;;       backspace的一点说明	     ;;;;;;;;;;
; 当为backspace时,本质上只要将光标移向前一个显存位置即可.后面再输入的字符自然会覆盖此处的字符
; 但有可能在键入backspace后并不再键入新的字符,这时在光标已经向前移动到待删除的字符位置,但字符还在原处,
; 这就显得好怪异,所以此处添加了空格或空字符0
   dec bx
   shl bx,1
   mov byte [gs:bx], 0x20		  ;将待删除的字节补为0或空格皆可
   inc bx
   mov byte [gs:bx], 0x07
   shr bx,1
   jmp set_cursor
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 .put_other:
   shl bx, 1				  ; 光标位置是用2字节表示,将光标值乘2,表示对应显存中的偏移字节
   mov [gs:bx], cl			  ; ascii字符本身
   inc bx
   mov byte [gs:bx],0x07		  ; 字符属性
   shr bx, 1				  ; 恢复老的光标值
   inc bx				  ; 下一个光标值
   cmp bx, 2000		   
   jl set_cursor			  ; 若光标值小于2000,表示未写到显存的最后,则去设置新的光标值
					  ; 若超出屏幕字符数大小(2000)则换行处理
 .is_line_feed:				  ; 是换行符LF(\n)
 .is_carriage_return:			  ; 是回车符CR(\r)
					  ; 如果是CR(\r),只要把光标移到行首就行了。
   xor dx, dx				  ; dx是被除数的高16,0.
   mov ax, bx				  ; ax是被除数的低16.
   mov si, 80				  ; 由于是效仿linux,linux中\n便表示下一行的行首,所以本系统中,
   div si				  ; 把\n和\r都处理为linux中\n的意思,也就是下一行的行首。
   sub bx, dx				  ; 光标值减去除80的余数便是取整
					  ; 以上4行处理\r的代码

 .is_carriage_return_end:                 ; 回车符CR处理结束
   add bx, 80
   cmp bx, 2000
 .is_line_feed_end:			  ; 若是LF(\n),将光标移+80便可。  
   jl set_cursor

;屏幕行范围是0~24,滚屏的原理是将屏幕的1~24行搬运到0~23,再将第24行用空格填充
 .roll_screen:				  ; 若超出屏幕大小,开始滚屏
   cld  
   mov ecx, 960				  ; 一共有2000-80=1920个字符要搬运,1920*2=3840字节.一次搬4字节,3840/4=960次 
   mov esi, 0xc00b80a0			  ;1行行首
   mov edi, 0xc00b8000			  ;0行行首
   rep movsd				  

;;;;;;;将最后一行填充为空白
   mov ebx, 3840			  ; 最后一行首字符的第一个字节偏移= 1920 * 2
   mov ecx, 80				  ;一行是80字符(160字节),每次清理1字符(2字节),一行需要移动80.cls:
   mov word [gs:ebx], 0x0720		  ;0x0720是黑底白字的空格键
   add ebx, 2
   loop .cls 
   mov bx,1920				  ;将光标值重置为1920,最后一行的首字符.
   
global set_cursor:
set_cursor:   
					  ;将光标设为bx值
;;;;;;; 1 先设置高8;;;;;;;;
   mov dx, 0x03d4			  ;索引寄存器
   mov al, 0x0e		          ;用于提供光标位置的高8位
   out dx, al
   mov dx, 0x03d5			  ;通过读写数据端口0x3d5来获得或设置光标位置 
   mov al, bh
   out dx, al

;;;;;;; 2 再设置低8;;;;;;;;;
   mov dx, 0x03d4
   mov al, 0x0f
   out dx, al
   mov dx, 0x03d5 
   mov al, bl
   out dx, al
 .put_char_done: 
   popad
   ret

                    
global cls_screen: 
cls_screen:                               ; 连着set_cursor
   pushad                                ; 用户态不允许访问显存 只能由中断后进入内核态 故此为系统调用
   mov ax,SELECTOR_VIDEO                 ; ax做中转
   mov gs,ax                             ; 先放到gs里面 进入中断后再
   
   mov ebx,0
   mov ecx,80*25                         ;清屏幕
   
 .cls:
   mov word [gs:ebx],0x720		   ;黑底白字空格键
   add ebx,2                              ;一次两字节
   loop .cls        
   mov ebx,0
   jmp set_cursor
  

编写完的stdio-kernel.c


#include "stdio-kernel.h"
#include "stdint.h"
#include "stdio.h"
#include "console.h"

void printk(const char* format, ...)
{
    va_list args;
    va_start(args,format);
    char buf[1024] = {0};
    vsprintf(buf,format,args);
    va_end(args);
    console_put_str(buf);
}

void sys_putchar(const char chr)
{
    console_put_char(chr);
}

编写完的stdio-kernel.h


#ifndef __LIB__STDIO_KERNEL_H
#define __LIB__STDIO_KERNEL_H

void printk(const char* format, ...);
void sys_putchar(const char chr);

#endif

lib/user相关文件


编写完的syscall.c


#include "syscall.h"

#define _syscall0(NUMBER) ({ \
    int retval;		\
    asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) : "memory"); retval; \
    })

#define _syscall1(NUMBER, ARG1) ({ \
    int retval;		\
    asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) , "b"(ARG1) : "memory"); retval; \
    })
    
#define _syscall2(NUMBER, ARG1, ARG2) ({ \
    int retval;		\
    asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) , "b"(ARG1) , "c"(ARG2): "memory"); retval; \
    })

#define _syscall3(NUMBER, ARG1, ARG2, ARG3) ({ \
    int retval;		\
    asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) , "b"(ARG1) , "c"(ARG2), "d"(ARG3): "memory"); retval; \
    })

uint32_t getpid(void)
{
    return _syscall0(SYS_GETPID);
}

uint32_t write(int fd,const void* buf,int count)
{
    return _syscall3(SYS_WRITE,fd,buf,count);
}

void* malloc(uint32_t size)
{
    return _syscall1(SYS_MALLOC,size);
}

void free(void* ptr)
{
    return _syscall1(SYS_FREE,ptr);
}

int32_t fork(void)
{
    return _syscall0(SYS_FORK);
}

int32_t read(int32_t fd,void* buf,uint32_t count)
{
    return _syscall3(SYS_READ,fd,buf,count);
}

void putchar(const char chr)
{
    return _syscall1(SYS_PUTCHAR,chr);
}

void clear(void)
{
    return _syscall0(SYS_CLEAR);
}

char* getcwd(char* buf,uint32_t size)
{
    return (char*)_syscall2(SYS_GETCWD,buf,size);
}

int32_t open(char* pathname,uint8_t flag)
{
    return _syscall2(SYS_OPEN,pathname,flag);
}

int32_t close(int32_t fd)
{
    return _syscall1(SYS_CLOSE,fd);
}

int32_t lseek(int32_t fd,int32_t offset,uint8_t whence)
{
    return _syscall3(SYS_LSEEK,fd,offset,whence);
}

int32_t unlink(const char* pathname)
{
    return _syscall1(SYS_UNLINK,pathname);
}

int32_t mkdir(const char* pathname)
{
    return _syscall1(SYS_MKDIR,pathname);
}

struct dir* opendir(const char* name)
{
    return (struct dir*)_syscall1(SYS_OPENDIR,name);
}

int32_t closedir(struct dir* dir)
{
    return _syscall1(SYS_CLOSEDIR,dir);
}

int32_t rmdir(const char* pathname)
{
    return _syscall1(SYS_RMDIR,pathname);
}

struct dir_entry* readdir(struct dir* dir)
{
    return (struct dir_entry*)_syscall1(SYS_READDIR,dir);
}

void rewinddir(struct dir* dir)
{
    _syscall1(SYS_REWINDDIR,dir);
}

int32_t stat(const char* path,struct stat* buf)
{
    return _syscall2(SYS_STAT,path,buf);
}

int32_t chdir(const char* path)
{
    return _syscall1(SYS_CHDIR,path);
}

void ps(void)
{
    return _syscall0(SYS_PS);
}

int32_t execv(const char* path,const char* argv[])
{
    return _syscall2(SYS_EXECV,path,argv);
}

编写完的syscall.h


#ifndef __LIB_USER_SCSCALL_H
#define __LIB_USER_SCSCALL_H
#include "stdint.h"
#include "../fs/file.h"

enum SYSCALL_NR
{
    SYS_GETPID,
    SYS_WRITE,
    SYS_MALLOC,
    SYS_FREE,
    SYS_FORK,
    SYS_READ,
    SYS_PUTCHAR,
    SYS_CLEAR,
    SYS_GETCWD,
    SYS_OPEN,
    SYS_CLOSE,
    SYS_LSEEK,
    SYS_UNLINK,
    SYS_MKDIR,
    SYS_OPENDIR,
    SYS_CLOSEDIR,
    SYS_CHDIR,
    SYS_RMDIR,
    SYS_READDIR,
    SYS_REWINDDIR,
    SYS_STAT,
    SYS_PS,
    SYS_EXECV
};

uint32_t getpid(void);
uint32_t write(int fd,const void* buf,int count);
void* malloc(uint32_t size);
void free(void* ptr);
int32_t fork(void);
int32_t read(int32_t fd,void* buf,uint32_t count);
void putchar(const char chr);
void clear(void);
char* getcwd(char* buf,uint32_t size);
int32_t open(char* pathname,uint8_t flag);
int32_t close(int32_t fd);
int32_t lseek(int32_t fd,int32_t offset,uint8_t whence);
int32_t unlink(const char* pathname);
int32_t mkdir(const char* pathname);
struct dir* opendir(const char* name);
int32_t closedir(struct dir* dir);
int32_t rmdir(const char* pathname);
struct dir_entry* readdir(struct dir* dir);
void rewinddir(struct dir* dir);
int32_t stat(const char* path,struct stat* buf);
int32_t chdir(const char* path);
void ps(void);
int32_t execv(const char* path,const char* argv[]);

#endif

lib直接相关子文件


编写完的stdint.h


#ifndef __LIB_STDINT_H
#define __LIB_STDINT_H

#define true 1
#define false 0
#define NULL 0

typedef int bool;
typedef signed char int8_t;
typedef signed short int int16_t;
typedef signed int int32_t;
typedef signed long long int int64_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long int uint64_t;
#endif

编写完的stdio.c


#include "stdio.h"
#include "stdint.h"
#include "string.h"
#include "syscall.h"

void itoa(uint32_t value,char** buf_ptr_addr,uint8_t base)//这里有理解的 为了修改一级指针的值 再取一次& 即可修改一级指针本身的值
{
    uint32_t m = value % base;
    uint32_t i = value / base;  //除数为0即最高位了 输出即可 没到零继续即可
    if(i)
    	itoa(i,buf_ptr_addr,base);
    if(m < 10)                  //m小于10的数
    	*((*buf_ptr_addr)++) = m + '0';
    else			 //m大于10的数
    	*((*buf_ptr_addr)++) = m + 'A' - 10;
}

uint32_t vsprintf(char* str,const char* format,va_list ap)
{
    char* buf_ptr = str;
    const char* index_ptr = format;
    char index_char = *index_ptr;
    int32_t arg_int;
    char* arg_str;
    while(index_char)		//挨个挨个字符来弄
    {
    	if(index_char != '%')
    	{
    	    *(buf_ptr++) = index_char;
    	    index_char = *(++index_ptr);
    	    continue;
    	}
    	index_char = *(++index_ptr);
    	switch(index_char)
    	{
    	    case 's':
    	    	arg_str = va_arg(ap,char*);
    	    	strcpy(buf_ptr,arg_str);
    	    	buf_ptr += strlen(arg_str);
    	    	index_char = *(++index_ptr);
    	    	break;
    	    case 'x':
    	    	arg_int = va_arg(ap,int);
    	    	itoa(arg_int,&buf_ptr,16);
    	    	index_char = *(++index_ptr);
    	    	break;
    	    case 'd':
    	    	arg_int = va_arg(ap,int);
    	    	if(arg_int < 0)
    	    	{
    	    	    arg_int = 0 - arg_int;
    	    	    *(buf_ptr++) = '-';
    	    	}
    	    	itoa(arg_int,&buf_ptr,10);
    	    	index_char = *(++index_ptr);
    	    	break;
    	    case 'c':
    	    	*(buf_ptr++) = va_arg(ap,char);
    	    	index_char = *(++index_ptr);
    	}
    }
    return strlen(str);
}

uint32_t printf(const char* format, ...)
{
    va_list args;
    va_start(args,format);		//args指向char* 的指针 方便指向下一个栈参数
    char buf[1024] = {0};
    vsprintf(buf,format,args);
    va_end(args);
    return write(1,buf,strlen(buf));
}

uint32_t sprintf(char* _des,const char* format, ...)
{
    va_list args;
    uint32_t retval;
    va_start(args,format);		//args指向char* 的指针 方便指向下一个栈参数
    retval = vsprintf(_des,format,args);
    va_end(args);
    return retval;
}

编写完的stdio.h


#ifndef __LIB__STDIO_H
#define __LIB__STDIO_H
#include "stdint.h"

#define va_start(ap,v) ap = (va_list)&v          //这里把第一个char*地址赋给ap 强制转换一下
#define va_arg(ap,t)   *((t*)(ap +=4))	   //强制类型转换 得到栈中参数
#define va_end(ap)	ap = NULL   

typedef void* va_list;
void itoa(uint32_t value,char** buf_ptr_addr,uint8_t base);
uint32_t vsprintf(char* str,const char* format,va_list ap);
uint32_t sprintf(char* _des,const char* format, ...);
uint32_t printf(const char* format, ...);

#endif

编写完的string.c


#include "string.h"
#include "debug.h"
#include "global.h"

void memset(void* dst_,uint8_t value,uint32_t size)
{
    ASSERT(dst_ != NULL);
    uint8_t* dst = (uint8_t*) dst_;
    while((size--) > 0)
    	*(dst++) = value;
    return;
}

void memcpy(void* dst_,const void* src_,uint32_t size)
{
    ASSERT(dst_ != NULL && src_ != NULL);
    uint8_t* dst = dst_;
    const uint8_t* src = src_;
    while((size--) > 0)
    	*(dst++) = *(src++);
    return;
}

int memcmp(const void* a_,const void* b_, uint32_t size)
{
    const char* a = a_;
    const char* b = b_;
    ASSERT(a != NULL || b != NULL);
    while((size--) > 0)
    {
    	if(*a != *b)	return (*a > *b) ? 1 : -1;
   	++a,++b;
    }
    return 0;
}

char* strcpy(char* dsc_,const char* src_)
{
    ASSERT(dsc_ != NULL && src_ != NULL);
    char* dsc = dsc_;
    while((*(dsc_++) = *(src_++) ));
    return dsc;     
}

uint32_t strlen(const char* str)
{
    ASSERT(str != NULL);
    const char* ptr = str;
    while(*(ptr++));
    return (ptr - str - 1);             //例如一个字 1 '\0' ptr会指向'\0'后面一位
}

int8_t strcmp(const char* a,const char* b)
{
    ASSERT(a != NULL && b != NULL);
    while(*a && *a == *b)
    {
    	a++,b++;
    }   
    return (*a < *b) ? -1 : (*a > *b) ; //这个表达式太猛了 用活了
}

char* strchr(const char* str,const char ch)
{
    ASSERT(str != NULL);
    while(*str != 0)
    {
    	if(*str == ch)	return (char*)str;
    	++str;
    } 
    return NULL;
}

char* strrchr(const char* str,const uint8_t ch)
{
    ASSERT(str != NULL);
    char* last_chrptr = NULL;
    while(*str != 0)
    {
    	if(ch == *str)	last_chrptr = (char*)str;
    	str++;
    }
    return last_chrptr;   
}

char* strcat(char* dsc_,const char* src_)
{
    ASSERT(dsc_ != NULL && src_ != NULL);
    char* str = dsc_;
    while(*(str++));
    str--;
    while(*(str++) = *(src_++));
    return dsc_;
}

char* strchrs(const char* str,uint8_t ch)
{
    ASSERT(str != NULL);
    uint32_t ch_cnt = 0;
    while(*str)
    {
    	if(*str == ch) ++ch_cnt;
    	++str;
    }
    return ch_cnt;
}

编写完的string.h


#ifndef __LIB_STRING_H
#define __LIB_STRING_H

#include "stdint.h"

void memset(void* dst_,uint8_t value,uint32_t size);
void memcpy(void* dst_,const void* src_,uint32_t size);
int memcmp(const void* a_,const void* b_, uint32_t size);
char* strcpy(char* dsc_,const char* src_);
uint32_t strlen(const char* str);
int8_t strcmp(const char* a,const char* b);
char* strchr(const char* str,const char ch);
char* strrchr(const char* str,const uint8_t ch);
char* strcat(char* dsc_,const char* src_);
char* strchrs(const char* str,uint8_t ch);

#endif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Love 6

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值