📄 intremap.c
字号:
/* * Copyright (c) 2006, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. * * Copyright (C) Allen Kay <allen.m.kay@intel.com> * Copyright (C) Xiaohui Xin <xiaohui.xin@intel.com> */#include <xen/irq.h>#include <xen/sched.h>#include <xen/iommu.h>#include <xen/time.h>#include <xen/pci.h>#include <xen/pci_regs.h>#include <asm/msi.h>#include "iommu.h"#include "dmar.h"#include "vtd.h"#include "extern.h"u16 apicid_to_bdf(int apic_id){ struct acpi_drhd_unit *drhd = ioapic_to_drhd(apic_id); struct acpi_ioapic_unit *acpi_ioapic_unit; list_for_each_entry ( acpi_ioapic_unit, &drhd->ioapic_list, list ) if ( acpi_ioapic_unit->apic_id == apic_id ) return acpi_ioapic_unit->ioapic.info; dprintk(XENLOG_ERR VTDPREFIX, "Didn't find the bdf for the apic_id!\n"); return 0;}static void remap_entry_to_ioapic_rte( struct iommu *iommu, struct IO_APIC_route_entry *old_rte){ struct iremap_entry *iremap_entry = NULL, *iremap_entries; struct IO_APIC_route_remap_entry *remap_rte; int index = 0; unsigned long flags; struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu); if ( ir_ctrl == NULL ) { dprintk(XENLOG_ERR VTDPREFIX, "remap_entry_to_ioapic_rte: ir_ctl is not ready\n"); return; } remap_rte = (struct IO_APIC_route_remap_entry *) old_rte; index = (remap_rte->index_15 << 15) | remap_rte->index_0_14; if ( index > ir_ctrl->iremap_index ) panic("%s: index (%d) is larger than remap table entry size (%d)!\n", __func__, index, ir_ctrl->iremap_index); spin_lock_irqsave(&ir_ctrl->iremap_lock, flags); iremap_entries = (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr); iremap_entry = &iremap_entries[index]; old_rte->vector = iremap_entry->lo.vector; old_rte->delivery_mode = iremap_entry->lo.dlm; old_rte->dest_mode = iremap_entry->lo.dm; old_rte->trigger = iremap_entry->lo.tm; old_rte->__reserved_2 = 0; old_rte->dest.logical.__reserved_1 = 0; old_rte->dest.logical.logical_dest = iremap_entry->lo.dst >> 8; unmap_vtd_domain_page(iremap_entries); spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);}static void ioapic_rte_to_remap_entry(struct iommu *iommu, int apic_id, struct IO_APIC_route_entry *old_rte, unsigned int rte_upper, unsigned int value){ struct iremap_entry *iremap_entry = NULL, *iremap_entries; struct iremap_entry new_ire; struct IO_APIC_route_remap_entry *remap_rte; struct IO_APIC_route_entry new_rte; int index; unsigned long flags; struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu); remap_rte = (struct IO_APIC_route_remap_entry *) old_rte; spin_lock_irqsave(&ir_ctrl->iremap_lock, flags); if ( remap_rte->format == 0 ) { ir_ctrl->iremap_index++; index = ir_ctrl->iremap_index; } else index = (remap_rte->index_15 << 15) | remap_rte->index_0_14; if ( index > IREMAP_ENTRY_NR - 1 ) panic("ioapic_rte_to_remap_entry: intremap index is more than 256!\n"); iremap_entries = (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr); iremap_entry = &iremap_entries[index]; memcpy(&new_ire, iremap_entry, sizeof(struct iremap_entry)); if ( rte_upper ) new_ire.lo.dst = (value >> 24) << 8; else { *(((u32 *)&new_rte) + 0) = value; new_ire.lo.fpd = 0; new_ire.lo.dm = new_rte.dest_mode; new_ire.lo.rh = 0; new_ire.lo.tm = new_rte.trigger; new_ire.lo.dlm = new_rte.delivery_mode; new_ire.lo.avail = 0; new_ire.lo.res_1 = 0; new_ire.lo.vector = new_rte.vector; new_ire.lo.res_2 = 0; new_ire.hi.sid = apicid_to_bdf(apic_id); new_ire.hi.sq = 0; /* comparing all 16-bit of SID */ new_ire.hi.svt = 1; /* requestor ID verification SID/SQ */ new_ire.hi.res_1 = 0; new_ire.lo.p = 1; /* finally, set present bit */ /* now construct new ioapic rte entry */ remap_rte->vector = new_rte.vector; remap_rte->delivery_mode = 0; /* has to be 0 for remap format */ remap_rte->index_15 = (index >> 15) & 0x1; remap_rte->index_0_14 = index & 0x7fff; remap_rte->delivery_status = new_rte.delivery_status; remap_rte->polarity = new_rte.polarity; remap_rte->irr = new_rte.irr; remap_rte->trigger = new_rte.trigger; remap_rte->mask = new_rte.mask; remap_rte->reserved = 0; remap_rte->format = 1; /* indicate remap format */ } memcpy(iremap_entry, &new_ire, sizeof(struct iremap_entry)); iommu_flush_cache_entry(iremap_entry); iommu_flush_iec_index(iommu, 0, index); invalidate_sync(iommu); unmap_vtd_domain_page(iremap_entries); spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags); return;}unsigned int io_apic_read_remap_rte( unsigned int apic, unsigned int reg){ struct IO_APIC_route_entry old_rte = { 0 }; struct IO_APIC_route_remap_entry *remap_rte; int rte_upper = (reg & 1) ? 1 : 0; struct iommu *iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid); struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu); if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 || ir_ctrl->iremap_index == -1 ) { *IO_APIC_BASE(apic) = reg; return *(IO_APIC_BASE(apic)+4); } if ( rte_upper ) reg--; /* read lower and upper 32-bits of rte entry */ *IO_APIC_BASE(apic) = reg; *(((u32 *)&old_rte) + 0) = *(IO_APIC_BASE(apic)+4); *IO_APIC_BASE(apic) = reg + 1; *(((u32 *)&old_rte) + 1) = *(IO_APIC_BASE(apic)+4); remap_rte = (struct IO_APIC_route_remap_entry *) &old_rte; if ( remap_rte->mask || (remap_rte->format == 0) ) { *IO_APIC_BASE(apic) = reg; return *(IO_APIC_BASE(apic)+4); } remap_entry_to_ioapic_rte(iommu, &old_rte); if ( rte_upper ) { *IO_APIC_BASE(apic) = reg + 1; return (*(((u32 *)&old_rte) + 1)); } else { *IO_APIC_BASE(apic) = reg; return (*(((u32 *)&old_rte) + 0)); }}void io_apic_write_remap_rte( unsigned int apic, unsigned int reg, unsigned int value){ struct IO_APIC_route_entry old_rte = { 0 }; struct IO_APIC_route_remap_entry *remap_rte; unsigned int rte_upper = (reg & 1) ? 1 : 0; struct iommu *iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid); struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu); int saved_mask; if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 ) { *IO_APIC_BASE(apic) = reg; *(IO_APIC_BASE(apic)+4) = value; return; } if ( rte_upper ) reg--; /* read both lower and upper 32-bits of rte entry */ *IO_APIC_BASE(apic) = reg; *(((u32 *)&old_rte) + 0) = *(IO_APIC_BASE(apic)+4); *IO_APIC_BASE(apic) = reg + 1; *(((u32 *)&old_rte) + 1) = *(IO_APIC_BASE(apic)+4); remap_rte = (struct IO_APIC_route_remap_entry *) &old_rte; /* mask the interrupt while we change the intremap table */ saved_mask = remap_rte->mask; remap_rte->mask = 1; *IO_APIC_BASE(apic) = reg; *(IO_APIC_BASE(apic)+4) = *(((int *)&old_rte)+0); remap_rte->mask = saved_mask; ioapic_rte_to_remap_entry(iommu, mp_ioapics[apic].mpc_apicid, &old_rte, rte_upper, value); /* write new entry to ioapic */ *IO_APIC_BASE(apic) = reg; *(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+0); *IO_APIC_BASE(apic) = reg + 1; *(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+1);}static void remap_entry_to_msi_msg(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -