DMA Remapping简介

DMA(Direct Nemory Access) Remapping是一种用来限制硬件设备只能使用DMA访问预先分配的内存区域(domain or physical memory regions)的技术。DMA Remapping会把DMA请求里的地址转化成正确的物理内存地址,同时还会检查设备是否允许访问指定的内存。请看下图:

dma_remapping

虚拟机的操作系统(Guest OS)所提供的物理地址称为Guest Physical Address (GPA) ,它不一定与实际的物理地址一致,也就是Host Physical Address (HPA),而DMA技术则要求访问真实的物理地址。DMA Remapping技术可以把Guest OS提供的GPA转化成HPA,然后数据就可以直接发送到Guest OS的缓冲区(buffer)了。

主机平台(host platform)可以支持一个或多个DMA remapping硬件单元(hardware unit),每个硬件单元remapping从它控制的作用域内发出的DMA remapping请求。主机固件(BIOS)需要把每个DMA remapping硬件单元报给系统软件(比如操作系统)。

DMA remapping硬件单元使用source-id来标示发出DMA请求的设备。对一个PCI Express设备,source-id就是resource identifier

 ________________________________________________________
|____Bus(8 bits)_________|__Device(5 bits)|_func(3 bits)_|

Root-entry作为最顶层的数据结构,会把某特定PCI总线上的设备映射到对应的domain。一个context-entry会把一个地址总线上的某个具体设备映射到对应的domain。参考下图:

root-entry

每个root-entry会有一个指向一个context-entry的表的指针,而每个context-entry则会包含如何用来进行地址转化的结构。

Linux kernel 笔记 (1) ——CPU在做什么?

In fact, in Linux, we can generalize that each processor is doing exactly one of three things at any given moment:
a) In user-space, executing user code in a process
b) In kernel-space, in process context, executing on behalf of a specific process
c) In kernel-space, in interrupt context, not associated with a process, handling an
interrupt

Linux中,任何时候,CPU都在做下面三件事中的一件:

a)运行进程的用户空间代码;
b)运行进程的内核空间代码;
c)处理中断(也是工作在内核空间,但不与任何进程关联)。

Go语言字符串浅析

Go语言中,字符串就是一个只读(read-only)的,可以包含任意字节(byte)的切片(slice)。由于Go源码文件都是使用UTF-8编码的,所以直接在源码中输入的字符串也都是用UTF-8编码的(前提是字符串里没有byte-level escapes,即字节层面上的转义)。请看下面这个例子:

package main
import "fmt"

func main() {
    s := "日志log"

    fmt.Println(len(s))
}

执行结果:

9

s是一个UTF-8编码的字符串,“日志”两个汉字各占3个字节,所以一共是9个字节。

再看一个例子:

package main
import "fmt"

func main() {
    s:="\xFF\xFF"

    fmt.Println(len(s))
}

执行结果:

2

虽然0xFF不是一个合法的UTF-8编码字符,但是因为字符串可以包含任意字节,所以s仍是一个合法的字符串。

Go语言引入rune类型(实际就是int32)来表示字符(character),“日志log”这个字符串包含了5个字符,9个字节。 可以用for range循环来遍历UTF-8编码字符串的每个字符:

package main
import "fmt"

func main() {
    s := "日志log"
    for index, runeValue := range s {
        fmt.Printf("%#U starts at byte position %d\n", runeValue, index)
    }
}

执行结果:

U+65E5 '日' starts at byte position 0
U+5FD7 '志' starts at byte position 3
U+006C 'l' starts at byte position 6
U+006F 'o' starts at byte position 7
U+0067 'g' starts at byte position 8

参考资料:
Strings, bytes, runes and characters in Go