设备虚拟化基础 - PCI

2023-11-20

目录

1. 配置空间概念和作用

2. 通过配置空间发现设备

3. Linux读取PCI配置空间接口

4. 内核中具体读取配置空间实例

5. Virtion设备自定义空间

6. Linux读取Capabilities List代码解析


1. 配置空间概念和作用

详细的定义可以参考PCI Spec的第六章《Configuration Space》中的描述,这里仅摘抄关键点

  • 所有的PCI设备必须实现配置空间,配置空间的本质是一堆寄存器
  • 配置空间可以用来发现设备
  • pci local bus spec规定的配置空间最大256字节,前64字节是spec中定义好的,称预定义空间,其中前16字节对所有类型的pci设备都相同(是指格式,而不其中具体的值),之后的空间格式因类型而不同,对前16字节空间,我称它为通用配置空间。

 上面是摘自PCI3.0规范的配置空间,一共64字节,即预定义空间,其中前16字节对应通用配置空间。

预定义空间解析

vendor id:厂商ID,用来标识pci设备出自哪个厂商,这里是0x1af4,来自Red Hat。
device id:厂商下的产品ID,传统virtio-blk设备,这里是0x1001
revision id:厂商决定是否使用,设备版本ID,这里未使用
header type:pci设备类型,0x00(普通设备),0x01(pci bridge),0x02(CardBus bridge)。virtio是普通设备,这里是0x00

status: 描述pci设备状态的寄存器

 其中有一位是Capabilities List,它是pci规范定义的附加空间标志位,Capabilities List的意义是允许在pci设备配置空间之后加上额外的寄存器,这些寄存器由Capability List组织起来,用来实现特定的功能,附加空间在64字节配置空间之后,最大不能超过256字节。以virtio-blk为例,它标记了这个位,因此在virtio-blk设备配置空间之后,还有一段空间用来实现virtio-blk的一些特有功能。1表示capabilities pointer字段(0x34)存放了附加寄存器组的起始地址。这里的地址表示附加空间在pci设备空间内的偏移。具体Capability List怎么理解本文后面分析。

2. 通过配置空间发现设备

发下设备需要确定两个事情:PCI设备地址,以及确定地址之后具体怎么通过该地址访问。

PCI设备地址 : 参考PCI规范3.2.2.3.2章节

设备地址可以通过Bus号,Device号,功能号和寄存器号唯一确定:

 

 Linux内核中确定该地址可以通过宏:

/*
 * Functions for accessing PCI base (first 256 bytes) and extended
 * (4096 bytes per PCI function) configuration space with type 1
 * accesses.
 */

#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
	(0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) \
	| (devfn << 8) | (reg & 0xFC))

访问配置空间

  • 配置空间寄存器偏移

PCI_CONF1_ADDRES宏确定了配置空间的基地址(Base Address),还要结合配置空间偏移具体访问具体的功能,比如访问配置空间的Command对应的offset:04h,Capabilities pointer偏移:0x34h。

  • 端口访问

配置空间地址无法直接访问,需要通过特定的端口来访问:

CONFIG_ADDRESS(CF8h) : 将需要访问的配置空间地址设置到该端口

CONFIG_DATA(CFCh):从该端口读取配置空间的值。

3. Linux读取PCI配置空间接口
//参数dev : pci 设备
//where : 配置空间寄存器对应的偏移offset
int pci_read_config_byte(const struct pci_dev *dev, int where, u8 *val);
int pci_read_config_word(const struct pci_dev *dev, int where, u16 *val);
int pci_read_config_dword(const struct pci_dev *dev, int where, u32 *val);
int pci_write_config_byte(const struct pci_dev *dev, int where, u8 val);
int pci_write_config_word(const struct pci_dev *dev, int where, u16 val);
int pci_write_config_dword(const struct pci_dev *dev, int where, u32 val);

上面API实现路径:drivers/pci/access.c

int pci_read_config_byte(const struct pci_dev *dev, int where, u8 *val)                                                                                                  
{
    if (pci_dev_is_disconnected(dev)) {
        *val = ~0;
        return PCIBIOS_DEVICE_NOT_FOUND;
    }
    return pci_bus_read_config_byte(dev->bus, dev->devfn, where, val);
}

上面已pci_read_config_byte为例:我们知道要读取配置空间必须通过CONFIG_ADDRESS,地址需要bus number, device number, function number和offset,这些值通过dev和where获取,可以想象pci_bus_read_config_byte最终应该也是要调用out汇编指令访问CONFIG_DDRESS端口,层层跟进最终调用到如下函数:

arch/x86/pci/direct.c

#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
    (0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) \
    | (devfn << 8) | (reg & 0xFC))

static int pci_conf1_read(unsigned int seg, unsigned int bus,
              unsigned int devfn, int reg, int len, u32 *value)
{
    unsigned long flags;

    if (seg || (bus > 255) || (devfn > 255) || (reg > 4095)) {
        *value = -1;
        return -EINVAL;
    }

    raw_spin_lock_irqsave(&pci_config_lock, flags);

    outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);

    switch (len) {
    case 1:
        *value = inb(0xCFC + (reg & 3));
        break;
    case 2:
        *value = inw(0xCFC + (reg & 2));
        break;
    case 4:
        *value = inl(0xCFC);
        break;
    }

    raw_spin_unlock_irqrestore(&pci_config_lock, flags);

    return 0;
}
4. Linux内核中具体读取配置空间实例
static void __iomem *map_capability(struct pci_dev *dev, int off,
				    size_t minlen,
				    u32 align,
				    u32 start, u32 size,
				    size_t *len)
{
	u8 bar;
	u32 offset, length;
	void __iomem *p;

	pci_read_config_byte(dev, off + offsetof(struct virtio_pci_cap,
						 bar),
			     &bar);
	pci_read_config_dword(dev, off + offsetof(struct virtio_pci_cap, offset),
			     &offset);
	pci_read_config_dword(dev, off + offsetof(struct virtio_pci_cap, length),
			      &length);
    ...
}

这里off对应每个capbility的offset(具体怎么理解参见本文下面capbility相关章节),每个capbility用struct virtio_pci_cap结构体描述:

/* This is the PCI capability header: */
struct virtio_pci_cap {
    __u8 cap_vndr;      /* Generic PCI field: PCI_CAP_ID_VNDR */
    __u8 cap_next;      /* Generic PCI field: next ptr. */
    __u8 cap_len;       /* Generic PCI field: capability length */
    __u8 cfg_type;      /* Identifies the structure. */
    __u8 bar;       /* Where to find it. */
    __u8 padding[3];    /* Pad to full dword. */
    __le32 offset;      /* Offset within bar. */
    __le32 length;      /* Length of the structure, in bytes. */
};
5. Virtion设备自定义空间

每个PCI具有不同的功能和配置,所以除了64字节的预定义空间之外,每个PCI设备可以自定义配置空间,配置设备的能力,pci spec规范中有个很重要的Capabilities List概念,即设备的能力列表。有几个重要的问题:

5.1. 能力列表的位置(地址)

        还记着预定义配置空间中有个Capability list么,这里面存储的就是能力列表的位置(offset)。

5.2 . 能力列表项格式

/* This is the PCI capability header: */
struct virtio_pci_cap {
    __u8 cap_vndr;      /* Generic PCI field: PCI_CAP_ID_VNDR */
    __u8 cap_next;      /* Generic PCI field: next ptr. */
    __u8 cap_len;       /* Generic PCI field: capability length */
    __u8 cfg_type;      /* Identifies the structure. */
    __u8 bar;       /* Where to find it. */
    __u8 padding[3];    /* Pad to full dword. */
    __le32 offset;      /* Offset within bar. */
    __le32 length;      /* Length of the structure, in bytes. */
};

vndr :capability类型,取值可参考pci spec H附录:

next:表示下一个capability在pci配置空间的位置

len:capability这个数据结构的长度

type : 取值范围如下

 Capabilities List图示:

在这里插入图片描述

                                                                (引用自参考文章)

6. Linux读取Capabilities List代码解析

drivers/virtio/virtio_pci_modern.c:

/* the PCI probing function */
int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev)
{
    struct pci_dev *pci_dev = vp_dev->pci_dev;
    int err, common, isr, notify, device;
    u32 notify_length;
    u32 notify_offset;

    check_offsets();

    /* We only own devices >= 0x1000 and <= 0x107f: leave the rest. */
    if (pci_dev->device < 0x1000 || pci_dev->device > 0x107f)
        return -ENODEV;

    if (pci_dev->device < 0x1040) {
        /* Transitional devices: use the PCI subsystem device id as
         * virtio device id, same as legacy driver always did.
         */
        vp_dev->vdev.id.device = pci_dev->subsystem_device;
    } else {
        /* Modern devices: simply use PCI device id, but start from 0x1040. */
        vp_dev->vdev.id.device = pci_dev->device - 0x1040;
    }
    vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor;

    /* check for a common config: if not, use legacy mode (bar 0). */
    //遍历配置空间的Capabilities List列表,查找是否存在VIRTIO_PCI_CAP_COMMON_CFG这种
    //Type类型的能力。
    common = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_COMMON_CFG,
                        IORESOURCE_IO | IORESOURCE_MEM,
                        &vp_dev->modern_bars);
    if (!common) {
        dev_info(&pci_dev->dev,
             "virtio_pci: leaving for legacy driver\n");
        return -ENODEV;
    }

    /* If common is there, these should be too... */
    isr = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_ISR_CFG,
                     IORESOURCE_IO | IORESOURCE_MEM,
                     &vp_dev->modern_bars);
    notify = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_NOTIFY_CFG,
                        IORESOURCE_IO | IORESOURCE_MEM,
                        &vp_dev->modern_bars);
    if (!isr || !notify) {
        dev_err(&pci_dev->dev,
            "virtio_pci: missing capabilities %i/%i/%i\n",
            common, isr, notify);
        return -EINVAL;
    }

    err = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(64));
    if (err)
        err = dma_set_mask_and_coherent(&pci_dev->dev,
                        DMA_BIT_MASK(32));
    if (err)
        dev_warn(&pci_dev->dev, "Failed to enable 64-bit or 32-bit DMA.  Trying to continue, but this might not work.\n");

    /* Device capability is only mandatory for devices that have
     * device-specific configuration.
     */
    device = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_DEVICE_CFG,
                        IORESOURCE_IO | IORESOURCE_MEM,
                        &vp_dev->modern_bars);

    err = pci_request_selected_regions(pci_dev, vp_dev->modern_bars,
                       "virtio-pci-modern");
    if (err)
        return err;

    err = -EINVAL;
    vp_dev->common = map_capability(pci_dev, common,
                    sizeof(struct virtio_pci_common_cfg), 4,
                    0, sizeof(struct virtio_pci_common_cfg),
                    NULL);
    if (!vp_dev->common)
        goto err_map_common;
    vp_dev->isr = map_capability(pci_dev, isr, sizeof(u8), 1,
                     0, 1,
                     NULL);
    if (!vp_dev->isr)
        goto err_map_isr;

    /* Read notify_off_multiplier from config space. */
    pci_read_config_dword(pci_dev,
                  notify + offsetof(struct virtio_pci_notify_cap,
                        notify_off_multiplier),
                  &vp_dev->notify_offset_multiplier);
    /* Read notify length and offset from config space. */
    pci_read_config_dword(pci_dev,
                  notify + offsetof(struct virtio_pci_notify_cap,
                        cap.length),
                  &notify_length);

    pci_read_config_dword(pci_dev,
                  notify + offsetof(struct virtio_pci_notify_cap,
                        cap.offset),
                  &notify_offset);

    /* We don't know how many VQs we'll map, ahead of the time.
     * If notify length is small, map it all now.
     * Otherwise, map each VQ individually later.
     */
    if ((u64)notify_length + (notify_offset % PAGE_SIZE) <= PAGE_SIZE) {
        vp_dev->notify_base = map_capability(pci_dev, notify, 2, 2,
                             0, notify_length,
                             &vp_dev->notify_len);
        if (!vp_dev->notify_base)
            goto err_map_notify;
    } else {
        vp_dev->notify_map_cap = notify;
    }

    /* Again, we don't know how much we should map, but PAGE_SIZE
     * is more than enough for all existing devices.
     */
    if (device) {
        vp_dev->device = map_capability(pci_dev, device, 0, 4,
                        0, PAGE_SIZE,
                        &vp_dev->device_len);
        if (!vp_dev->device)
            goto err_map_device;

        vp_dev->vdev.config = &virtio_pci_config_ops;
    } else {
        vp_dev->vdev.config = &virtio_pci_config_nodev_ops;
    }

    vp_dev->config_vector = vp_config_vector;
    vp_dev->setup_vq = setup_vq;
    vp_dev->del_vq = del_vq;

    return 0;
    ...
    return err;
}

probe函数连续调用virtio_pci_find_capability通过遍历Capabilities List查找PCI设备是否存其第二个参数指定的能力,第二个参数对应virtio_pci_cap结构体中的cfg_type。

static inline int virtio_pci_find_capability(struct pci_dev *dev, u8 cfg_type,
					     u32 ioresource_types, int *bars)
{
	int pos;

	for (pos = pci_find_capability(dev, PCI_CAP_ID_VNDR);
	     pos > 0;
	     pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_VNDR)) {
		u8 type, bar;
		pci_read_config_byte(dev, pos + offsetof(struct virtio_pci_cap,
							 cfg_type),
				     &type);
		pci_read_config_byte(dev, pos + offsetof(struct virtio_pci_cap,
							 bar),
				     &bar);

		/* Ignore structures with reserved BAR values */
		if (bar > 0x5)
			continue;

		if (type == cfg_type) {
			if (pci_resource_len(dev, bar) &&
			    pci_resource_flags(dev, bar) & ioresource_types) {
				*bars |= (1 << bar);
				return pos;
			}
		}
	}
	return 0;
}

pci_find_capability :返回Capabilities List列表中的一个能力pos (配置空间的offset),其内部是通过配置空间的34h偏移处的Capabilities Pointer确定的。

/**
 * pci_find_capability - query for devices' capabilities
 * @dev: PCI device to query
 * @cap: capability code
 *
 * Tell if a device supports a given PCI capability.
 * Returns the address of the requested capability structure within the
 * device's PCI configuration space or 0 in case the device does not
 * support it.  Possible values for @cap:
 *
 *  %PCI_CAP_ID_PM           Power Management
 *  %PCI_CAP_ID_AGP          Accelerated Graphics Port
 *  %PCI_CAP_ID_VPD          Vital Product Data
 *  %PCI_CAP_ID_SLOTID       Slot Identification
 *  %PCI_CAP_ID_MSI          Message Signalled Interrupts
 *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap
 *  %PCI_CAP_ID_PCIX         PCI-X
 *  %PCI_CAP_ID_EXP          PCI Express
 */
int pci_find_capability(struct pci_dev *dev, int cap)
{
    int pos;

    //pos值是配置空间对应的Capabilities Pointer的offset,即0x34h
    pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type);

    //如果开启了Capabilities List功能,__pci_find_nex_cap找到0x34H处对应的能力的pos
    //如果是第一次查找,以5.2中图为例,__pci_find_next_cap返回的是第一个能力的pos 0x98
    if (pos)
        pos = __pci_find_next_cap(dev->bus, dev->devfn, pos, cap);

    return pos;
}

static int __pci_bus_find_cap_start(struct pci_bus *bus,                                                                                                                 
                    unsigned int devfn, u8 hdr_type)
{
    u16 status;

    pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status);
    if (!(status & PCI_STATUS_CAP_LIST))
        return 0;

    switch (hdr_type) {
    case PCI_HEADER_TYPE_NORMAL:
    case PCI_HEADER_TYPE_BRIDGE:
        return PCI_CAPABILITY_LIST; //宏的值为0x34h
    case PCI_HEADER_TYPE_CARDBUS:
        return PCI_CB_CAPABILITY_LIST;
    }

    return 0;
}

static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
                   u8 pos, int cap, int *ttl)
{
    u8 id;
    u16 ent;

    pci_bus_read_config_byte(bus, devfn, pos, &pos);

    while ((*ttl)--) {
        if (pos < 0x40)
            break;
        pos &= ~3;
        pci_bus_read_config_word(bus, devfn, pos, &ent);

        id = ent & 0xff;
        if (id == 0xff)
            break;
        if (id == cap)
            return pos;
        pos = (ent >> 8);
    }
    return 0;
}

参考文章:

https://blog.csdn.net/fouweng/article/details/62890979

VirtIO实现原理——PCI基础_virtio-pci_享乐主的博客-CSDN博客

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

设备虚拟化基础 - PCI 的相关文章

  • 无法使用 linux perf 对硬件缓存事件进行采样

    由于某种原因 我无法采样 perf record 硬件缓存事件 perf record e L1 dcache stores a c 100 sleep 5 perf record Woken up 1 times to write dat
  • 安装 python-dev 和链接库后,Cython 中的 Hello World 程序因 gcc 失败

    我创建了一个简单的 hello world 程序 并尝试使用 gcc 执行生成的 C 程序 但无论我做什么 我都会得到大量未定义的引用 SO 有很多类似的问题 但他们都说安装 python dev 或其某些变体 或添加用于链接和加载库的标志
  • 无法从 Windows GUI 工具连接到远程 Linux 服务器上的 MySql 数据库

    我已经在 Amazon EC2 上的 Linux 服务器上设置了 mysql 数据库 这在本地效果很好 我可以登录 linux 盒子并管理 mysql 数据库 我正在尝试将本地 GUI 客户端连接到远程 mysql 但连接失败 我更新了 e
  • 使用 tac 和 sed 反转文件

    我有一个用例 我需要搜索并替换文件中最后一次出现的字符串并将更改写回文件 下面的案例是该用例的简化版本 我正在尝试反转该文件 进行一些更改 再次将其反转并写入该文件 我为此尝试了以下代码片段 tac test sed s a b sed i
  • Xvfb 冻结初始化 GLX 扩展

    我正在尝试运行无头 Xvfb 服务器来捕获 Amazon EC2 micro 上的屏幕截图 但它在 GLX 上陷入了困境 我使用此脚本安装了 GLX Xvfb 和所有库 https gist github com joekiller 414
  • 找出Linux上一个进程使用了​​多少内存页

    我需要找出进程分配了多少内存页 每个页面是 4096 进程内存使用情况我在查找正确值时遇到一些问题 当我查看 gome system monitor 时 内存映射下有几个值可供选择 Thanks 这样做的目的是将内存使用量除以页数并验证页大
  • 如何从脚本编辑 /etc/sudoers?

    我需要编辑 etc sudoers从脚本中添加 删除白名单中的内容 假设我有一个可以处理普通文件的命令 我如何将其应用到 etc sudoers 我可以复制并修改它 然后有visudo用修改后的副本替换原始版本 通过提供我自己的脚本 EDI
  • 如何在 Vim 中突出显示 Bash 脚本?

    我的 Vim 编辑器自动突出显示 PHP 文件 vim file php HTML 文件 vim file html 等等 但是当我输入 vim file在里面写一个Bash脚本 它不会突出显示它 我如何告诉 Vim 将其突出显示为 Bas
  • PIL 的 Image.show() 带来*两个*不同的查看器

    在 python shell 中处理图像时 我使用 image show 其中 image 是 Image 的实例 很久以前什么也没发生 但在定义了一个名为 xv 的 Mirage 符号链接后 我很高兴 最近几天 show 将显示 Imag
  • Apache 端口转发 80 到 8080 并访问 Apache (80) 中托管的应用程序,即 phpMyadmin 和 Tomcat (8080)

    我想访问托管在 tomcat 服务器 8080 中的应用程序 myapp 当前可以通过以下方式访问http example com 8080 myapp http example com 8080 myapp in http example
  • 应用程序中两个不同版本的库

    考虑一个场景 其中有两个不同版本的共享库 考虑 A 1 so 链接到 B so A 2 so 链接到 C so 现在 B so 和 C so 都链接到 d exe 当 B so 想要调用 A 1 so 中的函数时 它最终会调用 A 2 so
  • 我想在 Red Hat Linux 服务器中执行 .ps1 powershell 脚本

    我有一个在窗口中执行的 ps1 powershell 脚本 但我的整个数据都在 Linux 服务器中 有什么可能的方法可以让我在红帽服务器中执行 powershell 脚本 powershell脚本是 Clear Host path D D
  • 如何从 Bash 命令行在后台 Vim 打开另一个文件?

    我正在从使用 Gvim 过渡到使用控制台 Vim 我在 Vim 中打开一个文件 然后暂停 Vim 在命令行上运行一些命令 然后想返回到 Vim Ctrl Z 在正常模式下 暂停 Vim 并返回到控制台 fg可用于将焦点返回到 Vim job
  • MySQL 与 PHP 的连接无法正常工作

    这是我的情况 我正在尝试使用 Apache 服务器上的 PHP 文件连接到 MySQL 数据库 现在 当我从终端运行 PHP 时 我的 PHP 可以连接到 MySQL 数据库 使用 php f file php 但是当我从网页执行它时 它只
  • Linux shell 从用户输入中获取设备 ID

    我正在为一个程序编写安装脚本 该程序需要在其配置中使用 lsusb 的设备 ID 因此我正在考虑执行以下操作 usblist lsusb put the list into a array for each line use the arr
  • “git add”返回“致命:外部存储库”错误

    我刚刚进入 git 的奇妙世界 我必须提交我对程序所做的一系列更改 位于名为的目录中 var www myapp 我创建了一个新目录 home mylogin gitclone 从这个目录中 我做了一个git clone针对公共回购 我能够
  • 在 x86 汇编语言中获取文件大小的简单方法

    假设我已经在汇编中打开了一个文件 并且在寄存器 eax 中有该文件的文件句柄 我将如何获取文件的大小 以便为其分配足够的缓冲区空间 我在这里研究了另一个讨论 建议使用sys fstat 28 系统调用来获取文件统计信息但无法实现它 My a
  • 使用 libusb 输出不正确

    我用libusb编写了一个程序 我怀疑输出是否正确 因为所有条目都显示相同的供应商和产品 ID 以下是代码 include
  • 如何并行执行4个shell脚本,我不能使用GNU并行?

    我有4个shell脚本dog sh bird sh cow sh和fox sh 每个文件使用 xargs 并行执行 4 个 wget 来派生一个单独的进程 现在我希望这些脚本本身能够并行执行 由于某些我不知道的可移植性原因 我无法使用 GN
  • 如何在 Linux 上通过 FTP 递归下载文件夹 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的答案

随机推荐

  • KVM虚拟化技术的-NUMA技术和应用

    NUMA技术是解决多CPU共同工作的技术方案 多CPU共同工作主要有3中架构 SMP Symmetric Multi Processor 非统一存储访问结构 NUMA Non Uniform Memory Access 以及海量并行处理结构
  • 初识Linux(五)--vsftp的安装及常见错误

    安装 可以到官方网站去下载 http vsftpd beasts org 也可以用光盘安装 RedHat 5的安盘里自带的 所以我选择光盘安装 1 先把光盘挂载到系统上 mount dev cdrom mnt 这样光盘的内容就被挂载到 mn
  • xss-labs-master过关心得

    xss labs master通关心得 xss漏洞详解 XSS原称为CSS Cross Site Scripting 因为和层叠样式表 Cascading Style Sheets 重名 所以改称为XSS X一般有未知的含义 还有扩展的含义
  • 【Linux】Makefile中打印宏定义

    因为Makefile的嵌套关系 导致Makefile中很多宏定义是看不到的 有时编译时 会报找不到XXX h头文件 如果头文件在其他路径下 此时需要将头文件在Makefile中进行包含 那么不可能包含全路径 因为如果工程路径变化了 又会报找
  • IOS开发系列——异步绘制专题

    异步绘制专题 1 图片处理 1 1 编辑图片的几个方法 第一种 先用UIImage对象加载一张图片 然后转化成CGImageRef放到CGContext中去编辑 第二种 用CGImageCreate函数创建CGImageRef 然后把CGI
  • 通过php://filter/read=convert.base64-encode/resource= 利用LFI来查看源码

    PHP LFI读php文件源码以及直接post webshell 假设如下一个场景 1 http vulnerable fileincl example1 php page intro php 该php文件包含LFI漏洞 2 但是你没有地方
  • numpy中的argpartition

    numpy argpartition a kth axis 1 kind introselect order None 在快排算法中 有一个典型的操作 partition 这个操作指 根据一个数值x 把数组中的元素划分成两半 使得index
  • 性能测试之Jmeter集合点

    01 计数器 计数器就是按照设置可以为每个用户迭代时进行计数 可以用作参数化 jmeter计数器设置 没勾选与每用户独立跟踪计数时 计数器每用户每迭代都会往上增加数字 到最大时可重新开始 勾选与每用户独立跟踪计数器时 每个线程也就是用户会单
  • 毕业设计-基于机器视觉的数字图像处理技术研究-OpenCV

    目录 前言 课题背景和意义 实现技术思路 一 基于OpenCV数据库的程序环境构建 二 基于OpenCV的图像技术处理 实现效果图样例 最后 前言 大四是整个大学期间最忙碌的时光 一边要忙着备考或实习为毕业后面临的就业升学做准备 一边要为毕
  • CentOS Linux服务器安全设置

    转自 http www osyunwei com archives 754 html 引言 我们必须明白 最小的权限 最少的服务 最大的安全 所以 无论是配置任何服务器 我们都必须把不用的服务关闭 把系统权限设置到最小话 这样才能保证服务器
  • 华为OD机试 - 最佳植树距离(Java)

    题目描述 按照环保公司要求 小明需要在沙化严重的地区进行植树防沙工作 初步目标是种植一条直线的树带 由于有些区域目前不适合种植树木 所以只能在一些可以种植的点来种植树木 在树苗有限的情况下 要达到最佳效果 就要尽量散开种植 不同树苗之间的最
  • Pandas基础知识入门

    Pandas是基于Numpy构建的含有更高级数据结构和工具的数据分析包 类似于Numpy的核心是ndarray pandas 也是围绕着 Series 和 DataFrame两个核心数据结构展开的 Series 和 DataFrame 分别
  • ALLEGRO等长时如何将PIN DELAY和VIA长度计算在内

    在PCB设计中 对于时序要求严格的线路 Via和IC pin delay的长度必须得到重视 通过下面的操作 可将Via和Pin delay加入到线路长度的计算中 1st 计算Pin delay 打开Constraint Manager 选择
  • c语言指针入门

    1 指针是什么 1 概念 指针是一种十分重要的数据类型 利用指针变量可以直接对内存中各种不同数据结构的数据进行 快速处理 2 指针与内存的关系 指针与内存有着密切的联系 为了正确理解指针的概念 必须弄清楚计算机系统中数 据存储和读取的方式
  • OSI与TCP/IP协议

    OSI七层模型 OSI7层模型分别是 物理层 数据链路层 网络层 传输层 会话层 表示层 应用层 数据的封装与解封装过程 OSI模型vsTCP IP模型 TCP IP协议族的组成 每层常见的协议 应用层的协议 HTTP协议 HTTPS协议
  • 【ML&DL】【skimming】Global Optimality in Neural Network Training

    补了一下2017年的CVPR Global Optimality in Neural Network Training 1 论文一览 痛点 深度学习取得了很大的成功 但是对其成功原因的数学解释却还是一个难点 很大一个原因是对深度网络的参数学
  • 读《洞穴奇案》——一个人是否应该为了避免偷窃面包而挨饿致死?

    之前在功利主义与法的精神一文中提到过正当防卫 在读了今天的内容后 我觉得有必要对正当防卫的内在精神做一个深入探讨 书中说到判断是否是正当防卫 需要去判断一个人在进行自我防卫的时候是否是故意的 我认为 对这个故意的解读 是判断正当防卫的关键
  • SM2加解密、签名验签

    导论 SM2是国家密码管理局于2010年12月17日发布的椭圆曲线公钥密码算法 在我们国家商用密码体系中被用来替换RSA算法 国产SM2算法 是基于ECC的 但二者在签名验签 加密解密过程中或许有些许区别 目前鄙人还不太清楚 后期有机会的话
  • linux:http服务器搭建及实验案例

    目录 准备工作 http服务器各个配置文件大概说明 实验1 访问不同ip获得不同网页 实验2 同一ip访问不同端口获得不同网页 准备工作 1 安装http服务 2 将 etc selinux config 文件下面的 SELINUX值改为
  • 设备虚拟化基础 - PCI

    目录 1 配置空间概念和作用 2 通过配置空间发现设备 3 Linux读取PCI配置空间接口 4 内核中具体读取配置空间实例 5 Virtion设备自定义空间 6 Linux读取Capabilities List代码解析 1 配置空间概念和