从零开始的操作系统生活05-port

github

1、介绍

操作系统想要实现键盘写入或者其他硬件的相关操作时,需要用到端口读写。

本节内容较为单一,也没有太多前置知识,主要实现向固定的端口中写入数据以及读取数据。

2、code

新建文件port.h,port.cpp

我们需要实现8Bit、16Bit以及32Bit数据的读写

首先是port.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#ifndef __PORT_H
#define __PORT_H

#include "types.h"

class Port{
protected:
uint16_t portnumber;
Port(uint16_t portnumber);
~Port();
};

class Port8Bit : public Port {
public:
Port8Bit(uint16_t portnumber);
~Port8Bit();
virtual void write(uint8_t data);
virtual uint8_t read();
};


class Port16Bit : public Port {
public:
Port16Bit(uint16_t portnumber);
~Port16Bit();
virtual void write(uint16_t data);
virtual uint16_t read();
};

class Port32Bit : public Port {
public:
Port32Bit(uint16_t portnumber);
~Port32Bit();
virtual void write(uint32_t data);
virtual uint32_t read();
};

#endif

我们首先创建一个port类表示需要写入的端口,端口长度位16Bit,然后使用具体的8Bit,16Bit,32Bit的类继承并实现读写功能。

接下来是实现port.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include "port.h"


Port::Port(uint16_t portnumber)
: portnumber(portnumber){}

Port::~Port() {}

//8Bit
Port8Bit::Port8Bit(uint16_t portnumber)
: Port(portnumber){}

Port8Bit::~Port8Bit() {}

void Port8Bit::Write(uint8_t data){
__asm__ volatile("outb %0, %1" : : "a" (data), "Nd" (portnumber));
}

uint8_t Port8Bit::Read(){
uint8_t data;
__asm__ volatile("inb %1, %0" : "=a" (data) : "Nd" (portnumber));
return data;
}

// 16 Bit
Port16Bit::Port16Bit(uint16_t portnumber)
: Port(portnumber){}

Port16Bit::~Port16Bit() {}

void Port16Bit::Write(uint16_t data){
__asm__ volatile("outw %0, %1" : : "a" (data) , "Nd" (portnumber));
}

uint16_t Port16Bit::Read(){
uint16_t data;
__asm__ volatile("inw %1, %0" : "=a" (data) : "Nd" (portnumber));
return data;
}

// 32Bit
Port32Bit::Port32Bit(uint16_t portnumber)
: Port(portnumber){}

Port32Bit::~Port32Bit() {}

void Port32Bit::Write(uint32_t data){
__asm__ volatile("outl %0, %1" : : "a" (data) , "Nd" (portnumber));
}

uint32_t Port32Bit::Read(){
uint32_t data;
__asm__ volatile("inl %1, %0" : "=a" (data) : "Nd" (portnumber));
return data;
}

我们这里仍然采用内嵌汇编的方法实现功能,其中outb以及inb分别表示向固定的端口写入以及读取端口数据

3、slow write

最后,我们需要实现一个慢写入,这里面由于未查到资料,所以并不清楚实现慢写入的原因,暂时码住。

port.h

1
2
3
4
5
6
class Port8BitSlow : public Port8Bit {
public:
Port8BitSlow(uint16_t portnumber);
~Port8BitSlow();
virtual void write(uint8_t data);
};

port.cpp

1
2
3
4
5
6
7
8
Port8BitSlow::Port8BitSlow(uint16_t portnumber)
: Port8Bit(portnumber){}

Port8BitSlow::~Port8BitSlow() {}

void Port8BitSlow::Write(uint8_t data){
__asm__ volatile("outb %0, %1\njmp 1f\n1: jmp 1f\n1:" : : "a" (data) , "Nd" (portnumber));
}

可以看出,慢写入的汇编语句如下:

1
2
3
4
outb data, portnumber
jmp 1f
1: jmp 1f
1:

上面的data以及portnumber不是真实的汇编语句,这里只是为了说明汇编语句的操作,而且主要目的是介绍下面的内容

jmp 1f,f表示向下跳转,跳转到1这个位置,到达1这个位置之后又出现了一句jmp 1f,再次向下跳转无汇编语句,执行结束。

我们通过两次跳转指令实现了慢写入,也就是在执行outb汇编指令之后做一些无用功,然后再返回,应该是为了等待一些工作的完成。


从零开始的操作系统生活05-port
http://example.com/2022/09/30/wyoos005/
作者
Anhongzhan
发布于
2022年9月30日
许可协议