最近在看github上一个微os的代码,freeNOS.走读的过程中顺便记一下学习的点
枚举用位偏移定义来提高效率
/**
* Memory access flags.
*/
typedef enum Access
{
None = 0,
Readable = 1 << 0,
Writable = 1 << 1,
Executable = 1 << 2,
User = 1 << 3,
Uncached = 1 << 4,
InnerCached = 1 << 5,
OuterCached = 1 << 6,
Device = 1 << 7
}
读,写是通过port口地址加offset值来定位具体内存地址,再进行具体的内存操作
为了提高效率所有的IO操作函数全部都是inline
//IntelIO.h
inline u8 inb(u16 port)
{
u8 b;
port += m_base;
asm volatile ("inb %%dx, %%al" : "=a" (b) : "d" (port));
return b;
}
/**
* Read a word from a port.
* @param port The I/O port to read from.
* @return Word read from the port.
*/
inline u16 inw(u16 port)
{
u16 w;
port += m_base;
asm volatile ("inw %%dx, %%ax" : "=a" (w) : "d" (port));
return w;
}
/**
* Output a byte to a port.
* @param port Port to write to.
* @param byte The byte to output.
*/
inline void outb(u16 port, u8 byte)
{
port += m_base;
asm volatile ("outb %%al,%%dx"::"a" (byte),"d" (port));
}
/**
* Output a word to a port.
* @param port Port to write to.
* @param byte The word to output.
*/
inline void outw(u16 port, u16 word)
{
port += m_base;
asm volatile ("outw %%ax,%%dx"::"a" (word),"d" (port));
}
/**
* Output a long to a I/O port.
* @param port Target I/O port.
* @param l The long 32-bit number to output.
*/
inline void outl(u16 port, u32 l)
{
port += m_base;
asm volatile ("outl %%eax,%%dx"::"a" (l),"d" (port));
}
/**
* Read memory mapped register.
*
* @param addr Address of the register to read.
* @return 32-bit value of the register.
*/
inline u32 read(Address addr)
{
addr += m_base;
return *(volatile u32 *) addr;
}
/**
* Read a number of 32-bit values.
*
* @param addr Address of the starting 32-bit value.
* @param count Number of bytes to read.
* @param buf Output buffer.
*/
inline void read(Address addr, Size count, void *buf)
{
for (Size i = 0; i < count; i+= sizeof(u32))
{
*(u32 *)(((u8 *)buf) + i) = read(addr + i);
}
}
/**
* Write memory mapped register.
*
* @param addr Address of the register to write.
* @param data 32-bit value to write in the register.
*/
inline void write(Address addr, u32 data)
{
addr += m_base;
*(volatile u32 *) addr = data;
}
寄存器对应bit置1 set()和置0 unset():
/**
* Set bits in memory mapped register.
*
* @param addr Address of the register to write.
* @param data 32-bit value containing the bits to set (bitwise or).
*/
inline void set(Address addr, u32 data)
{
u32 current = read(addr);
current |= data;
write(addr, current);
}
/**
* Unset bits in memory mapped register.
*
* @param addr Address of the register to write.
* @param data 32-bit value containing the bits to set (bitwise or).
*/
inline void unset(Address addr, u32 data)
{
u32 current = read(addr);
current &= ~(data);
write(addr, current);
}
地址等关键变量类型通过typedef来定义,提高可读性和健壮性。大量采用了switch-case操作,基本没有if判断操作,通过state去串联(状态机?)。
函数返回值只返回当前操作的状态,其他逻辑信息全部用出参表示。
函数内基本没有任何合法性判断和异常处理流程代码。