AMD IOMMU与Linux (2) -- IVRS及AMD IOMMU硬件初始化

介绍AMD IOMMU driver基于IVRS的硬件初始化情况

1. I/O Virtualization ACPI table

2. drivers/iommu/amd/init.c

1. I/O Virtualization ACPI table [1]

AMD IOMMU的ACPI数据结构,这里只列出一个大概

IVRS (I/O Virtualization Reporting Struct)

        -> 48-byte header

        -> IVDB:IVHD (I/O Virtualizaiton Hardware Definition) -- info about IOMMU and devices

                Types 10h, 11h, 40h, IVHD是关于IOMMU与downstream设备的信息

        -> IVDB:IVMD (I/O Virtualizaiton Memory Definition, optional) -- special memory constraints

                Types 20h, 21h, 22h, IVMD是相关设备的memory信息

Header:

 IVHD:

        Flags: PPR,PreF, Coherenet, Iotbl, Isoc, ResPassPW, PassPW, HtTunEn (AMD IOMMU独有)

        IOMMU info: UnitID, MSInum (AMD IOMMU独有)

        IOMMU feature: HATS, GATS, MSInumPPR, PASmax, GASup, GLXSup, GTSup, XTSup, ...                                    etc. (AMD IOMMU独有)

IVHD Device Entry: (4 or 8 bytes)

 DTE settings: Lint0/1Pass, SysMtg[1:0], NMIPass, EIntPass, INITPass (AMD IOMMU独有)

IVMD:

2. drivers/iommu/amd/init.c

注释一下上篇的AMD IOMMU硬件初始化函数

                early_amd_iommu_init (case IOMMU_IVRS_DETECTED) : 

                解析(parse) IVRS

                early_enable_iommus (case IOMMU_ACPI_FINISHED):

                enable IOMMUs, 主要是针对cmd/event buffer, ga(guest trans)/xt (32 bit APIC dest ID), DT (device table)等的设置 

                register_syscore_ops/amd_iommu_init_pci/enable_iommus_v2 (case IOMMU_ENABLED)

                        amd_iommu_init_pci ->

                                iommu_init_pci: 

                                根据IOMMU PCI CFG,EFRSup (IOMMU Extended Feature Register),设置IOTLB, GT, PPR, V2, GA log, 等变量

                                amd_iommu_init_api ->

                                        amd_iommu_init_dma_ops : 

                                        设置变量swiotlb (0 pt/sme me mask or 1)me: memory encryption

                                        bus_set_iommu: 

                                        设置amd_iommu_ops

                                init_device_table_dma : 

                                使能DTE.V/TV

                                iommu_flush_all_caches :

                                flush the caches of all IOMMUs, 包括DTE,  IRT, TLB (pages)

                                enable_iommus_v2: 

                                对于ppr, gt (guest trans)

                amd_iommu_enable_interrupts (case IOMMU_PCI_INIT)

3. summary

AMD IOMMU硬件的初始化,首先要解析IVRS表,得到IOMMUs, 及其下属devices的相关信息,根据这些信息,建立数据结构,使能IOMMUs。

根据Cfg space中的Capability以及EFRSup (extended feature register),  设置相应变量,以供后续使用

amd_iommu_ops是amd iommu driver的具体实现

设置DET中的V, TV是允许DMA remapping功能起作用

Reference:

【1】

AMD I/O Virtualization Technology (IOMMU) Specification, 48882

[2] IOMMU(三)-初始化 - 云+社区 - 腾讯云 (tencent.com)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这里我提供一个简单的64位RISC-V IOMMU模块的verilog代码示例。这个模块支持基本的输入输出设备和主存之间的数据传输,并提供了虚拟化和内存隔离支持。 ``` module riscv_iommu( input clk, input rst, input [63:0] in_addr, input [63:0] out_addr, input [2:0] access_mode, input [63:0] page_table_base, input [63:0] page_table_mask, output [63:0] data_in, input [63:0] data_out ); /* 定义一些常量 */ localparam PAGE_SIZE = 8192; localparam PAGE_OFFSET_BITS = 13; localparam PAGE_TABLE_SIZE = 4096; /* 定义一些寄存器 */ reg [63:0] mem[1024]; // 主存 reg [63:0] in_data; // 输入数据 reg [63:0] out_data; // 输出数据 reg [63:0] page_table[PAGE_TABLE_SIZE]; // 页表 reg [63:0] page_table_entry; // 页表项 /* 定义一些辅助函数 */ function [63:0] translate_address; input [63:0] addr; input [63:0] page_table_base; input [63:0] page_table_mask; reg [63:0] translated_addr; reg [31:0] page_offset; reg [31:0] page_index; reg [31:0] page_table_index; page_offset = addr[PAGE_OFFSET_BITS-1:0]; page_index = addr[63:PAGE_OFFSET_BITS]; page_table_index = page_index % PAGE_TABLE_SIZE; page_table_entry = page_table[page_table_index]; if (page_table_entry[0]) begin // 检查页表项的有效位 translated_addr = {page_table_entry[62:13], page_offset}; end else begin translated_addr = 64'h0; // 无效地址 end if ((addr & page_table_mask) != (translated_addr & page_table_mask)) begin translated_addr = 64'h0; // 无效地址 end return translated_addr; endfunction /* 主要的IOMMU功能 */ always @(posedge clk) begin if (rst) begin in_data <= 0; out_data <= 0; end else begin case(access_mode) 3'b000: in_data <= data_in; // 读模式 3'b001: mem[in_addr] <= in_data; // 写模式 3'b010: out_data <= mem[out_addr]; // 读取主存中的数据 3'b011: out_data <= data_out; // 直接输出数据 3'b100: begin // 页表读模式 out_data <= page_table[in_addr[31:3]]; end 3'b101: begin // 页表写模式 page_table[in_addr[31:3]] <= data_in; end 3'b110: begin // 虚拟地址翻译 out_data <= translate_address(in_addr, page_table_base, page_table_mask); end endcase end end endmodule ``` 这个模块包含了一个主存数组、一个输入输出端口和一个页表。在读模式下,数据输入端口的数据会被存储在in_data寄存器中;在写模式下,in_data寄存器中的数据会被写入到主存中。在读取主存中的数据时,out_addr指定了要读取的地址;在直接输出数据模式下,data_out端口中的数据会被直接输出到外部。在页表读写模式下,in_addr指定了要读写的页表项地址。在虚拟地址翻译模式下,in_addr指定了要翻译的虚拟地址,page_table_base和page_table_mask分别指定了页表的基地址和掩码。在翻译过程中,模块会根据页表和掩码计算出物理地址,并将其输出到out_data端口中。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值