操作系统实现-进入内核

博客网址:www.shicoder.top
微信:18223081347
欢迎加群聊天 :452380935

这一次我们正式进入内核,编写相关的内核代码,也就是kernel代码

数据类型定义

因为我们在内核中会使用一些数据,因此先提前定义一些数据类型

#define EOF -1 

#define NULL ((void *)0) // 空指针
#define EOS '\0' // 字符串结尾

#define bool _Bool
#define true 1
#define false 0

#define _packed __attribute__((packed)) // 用于定义特殊的结构体 不对齐

typedef unsigned int size_t;
typedef char int8;
typedef short int16;
typedef int int32;
typedef long long int64;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;

typedef u32 time_t;
typedef u32 idx_t;

输入输出

我们知道,在操作系统启动的时候,刚开始都是黑乎乎的界面,然后光标闪烁等,那么这个是怎么实现的呢,一般这种都是通过向一些寄存器写入一些值和和获取一些值实现,因此就需要用一些输入输出函数

首先是四个函数

extern u8 inb(u16 port); // 输入1个字节 从port端口中读一个字节
extern u16 inw(u16 port); // 输入2个字节  从port端口中读2个字节

extern void outb(u16 port,u8 value); // 输出1个字节 将value值输入到port端口中
extern void outw(u16 port,u16 value); // 输出2个字节 将value值输入到port端口中

我们采用汇编实现

global inb ; 将inb导出
inb:
    ; 栈帧保存
    push ebp
    mov ebp, esp

    xor eax, eax ;清空
    mov edx, [ebp + 8] ;port [ebp + 8]就是传入进来的port
    in al, dx ;将dx所指向的端口,读取一个字放在al,也就是从port端口读一个字节

    jmp $+2 ;延迟
    jmp $+2 ;延迟
    jmp $+2 ;延迟

    leave ; 恢复栈帧
    ret
global outb ; 将outb导出
outb:
    ; 栈帧保存
    push ebp
    mov ebp, esp


    mov edx, [ebp + 8] ;port [ebp + 8]就是传入进来的port
    mov eax, [ebp + 12] ; value 参数入栈是从右往左 所以value地址更高
    out dx, al ;将al的8比特输出到dx的端口号

    jmp $+2 ;延迟
    jmp $+2 ;延迟
    jmp $+2 ;延迟

    leave ; 恢复栈帧
    ret

global inw ; 将inw导出
inw:
    ; 栈帧保存
    push ebp
    mov ebp, esp

    xor eax, eax ;清空
    mov edx, [ebp + 8] ;port [ebp + 8]就是传入进来的port
    in ax, dx ;将dx所指向的端口,读取2个字放在ax

    jmp $+2 ;延迟
    jmp $+2 ;延迟
    jmp $+2 ;延迟

    leave ; 恢复栈帧
    ret

global outw ; 将outw导出
outw:
    ; 栈帧保存
    push ebp
    mov ebp, esp


    mov edx, [ebp + 8] ;port [ebp + 8]就是传入进来的port
    mov eax, [ebp + 12] ; value 参数入栈是从右往左 所以value地址更高
    out dx, ax ;将ax的2个字输出到dx的端口号

    jmp $+2 ;延迟
    jmp $+2 ;延迟
    jmp $+2 ;延迟

    leave ; 恢复栈帧
    ret

我们在kernel中测试下获取光标的位置,相关的寄存器有以下几个

  • CRT 地址寄存器 0x3D4
  • CRT 数据寄存器 0x3D5
  • CRT 光标位置 - 高位 0xE
  • CRT 光标位置 - 低位 0xF

比如我们把光标高位位置给地址寄存器,那么就可以通过数据寄存器得到和设置光标位置的高位值

// - CRT 地址寄存器 0x3D4
// - CRT 数据寄存器 0x3D5
// - CRT 光标位置 - 高位 0xE
// - CRT 光标位置 - 低位 0xF

#define CRT_ADDR_REG 0x3d4
#define CRT_DATA_REG 0x3d5

#define CRT_CURSOR_H 0xe
#define CRT_CURSOR_L 0xf
void kernel_init()
{
   
    outb(CRT_ADDR_REG,CRT_CURSOR_H);
    u16 pos = inb(CRT_DATA_REG) << 8;
    outb(CRT_ADDR_REG,CRT_CURSOR_L);
    pos |= inb(CRT_DATA_REG); // 到这里,pos值为240,通过qemu也可以看到,光标在第4行,每行80字符
    u8 data = inb(CRT_DATA_REG);

    // 比如想把光标位置改为160
    outb(CRT_ADDR_REG,CRT_CURSOR_H);
    outb(CRT_DATA_REG,0);
    outb(CRT_ADDR_REG,CRT_CURSOR_L);
    outb(CRT_DATA_REG,160); // 到这里,就可以看到光标在第3行开始处
}

image-20220505211423561

字符串函数实现

我们在C语言中,使用过很多字符串函数,比如

char *strcpy(char *dest, const char *src);
char *strcat(char *dest, const char *src);
size_t strlen(const char *str);
int strcmp(const char *lhs, const char *rhs);
char *strchr(const char *str, int ch);
char *strrchr(const char *str, int ch);
int memcmp
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值