1.ARM GIC V3中断控制器介绍

GIC(Generic Interrupt Controller)是一个通用的中断控制器,用来接收硬件中断信号,并经过一定处理后,分发给对应的CPU进行处理。GIC V3是其中一个版本,支持的中断类型如下表:

中断类型

中断号 描述
SGI (Software Generated Interrupt) 0-15

软件触发中断,通常用于多核之间通讯,在Linux内核中通常被用作IPI(inter

-process interrupts)中断,并送达到系统指定的CPU,最多支持16个SGI中断,中断号0-15

PPI (Private Peripheral Interrupt) 16-31 每个处理器的私有外设中断,最多支持16个PPI中断,中断号16-31,PPI通常会送达到指定的CPU上
SPI (Shared Peripheral Interrupt) 32-1019 系统共享的外设中断

LPI (Locality-specific Peripheral

Interrupt)

8192-MAX LPI是基于消息的中断,它们的配置保存在表中而不是寄存器

GIC V3中断控制器的组成部分包括:distributor,redistributor,cpu interface,ITS,GIC V3中断控制器和处理器核心之间的关系图如下:

SPI 中断检测流程

  • 外设发起SPI中断,GIC检测到这个中断,并标记为pending状态
  • distributor对所有处于pending状态的中断确定目标CPU
  • 对每个CPU,distributor会从众多pending状态的中断中,选择优先级高的发送到对应的redistributor
  • redistributor将中断发送到目标CPU的CPU Interface上
  • CPU Interface将满足要求的中断发送给CPU
  • CPU进入中断异常后,内核中断处理程序读取GICC_IAR寄存器来响应该中断,寄存器返回硬件中断号
  • CPU处理完中断服务后,通过写GICC_EOIR寄存器,来给GIC发送一个EOI完成信号

PPI和SGI中断检测流程

  • GIC检测到PPI或者SGI中断,并标记为pending状态
  • redistributor选择优先级高的中断发送到对应的CPU Interface
  • CPU Interface将满足要求的中断发送给CPU
  • CPU进入中断异常后,内核中断处理程序读取GICC_IAR寄存器来响应该中断,寄存器返回硬件中断号
  • CPU处理完中断服务后,通过写GICC_EOIR寄存器,来给GIC发送一个EOI完成信号

LPI中断检测流程

1.forwarding方式,由以下寄存器实现

  • GICR_SERLPIR:将指定的LPI中断,设置为pending状态
  • GICR_INVLPIR:将指定的LPI中断,清除pending状态。寄存器内容和GICR_SERLPIR一致
  • GICR_INVLPIR:将缓存中,指定LPI的缓存给无效掉,使GIC重新从memory中载入LPI的配置
  • GICR_INVALLR:将缓存中,所有LPI的缓存给无效掉,使GIC重新从memory中,载入LPI中断的配
  • GICR_SYNCR:对redistributor的操作是否完成

2.使用ITS方式

  • 外设写GITS_TRANSLATER寄存器,给ITS提供中断事件类型EventID和发起中断的外设的DeviceID
  • ITS用DeviceID,通过查设备表,得到中断映射表的位置
  • ITS用EventID,通过查中断映射表,得到LPI中断号,以及中断所属的collection号
  • 使用collection号,从collection表格中redistributor的映射信息
  • ITS将中断信息发送给对应的redistributor
  • redistributor将该中断信息发送给CPU Interface
  • CPU Interface将满足要求的中断发送给CPU

2 ARM Linux系统中GIC V3初始化

以下所有内核源码来自Linux5.5.8

2.1 Linux系统中 gic-v3 DTS定义和设备节点

Device Tree是用来描述硬件的数据结构,DTS即Device Tree Source 设备树源码,Linux源码中DTS对应的文件名后缀为.dts。 DTC是将.dts编译为.dtb的工具,.dtb是.dts被DTC编译后的二进制格式的Device Tree描述,可由Linux内核解析。Bootloader在引导Linux内核的时候会将.dtb地址告知内核。之后内核会展开Device Tree并创建和注册相关的设备。

2.1.1 Linux系统中 gic-v3 DTS定义

 gic: interrupt-controller@2c010000 {compatible = "arm,gic-v3";#interrupt-cells = <3>;#address-cells = <2>;#size-cells = <2>;ranges;interrupt-controller;redistributor-stride = <0x0 0x40000>;   // 256kB stride#redistributor-regions = <2>;reg = <0x0 0x2c010000 0 0x10000>, // GICD<0x0 0x2d000000 0 0x800000>,   // GICR 1: CPUs 0-31<0x0 0x2e000000 0 0x800000>;  // GICR 2: CPUs 32-63<0x0 0x2c040000 0 0x2000>,   // GICC<0x0 0x2c060000 0 0x2000>, // GICH<0x0 0x2c080000 0 0x2000>; // GICVinterrupts = <1 9 4>;gic-its@2c200000 {compatible = "arm,gic-v3-its";msi-controller;#msi-cells = <1>;reg = <0x0 0x2c200000 0 0x200000>;};gic-its@2c400000 {compatible = "arm,gic-v3-its";msi-controller;#msi-cells = <1>;reg = <0x0 0x2c400000 0 0x200000>;};};

1) gic-v3设备节点中必须的属性:

  • interrupt-controller:该设备节点为中断控制器
  • compatible:必须包含字符串"arm,gic-v3",表示该设备为中断控制器arm gic-v3
  • #interrupt-cells :指定编码中断源所需的单元格数目,必须至少3个单元格,单元格的详细描述如下表
   单元格                                      描述
        1 第一个单元格中的是中断类型:0 SPI,1 PPI,其他为保留值
        2 第二个单元格中的值是中断号
        3 第三个单元格中的值是一些中断标志,1为边沿触发,4为电平触发
  • reg:指定了GIC寄存器的物理基地址,这些寄存器包括:Distributor(GICD),Redistributors (GICR),CPU interface (GICC),Hypervisor interface (GICH),Virtual CPU interface (GICV),其中 GICC, GICH ,GICV 是可选的。
  • interrupts:中断源

2) gic-v3设备节点中可选的属性:

  • redistributor-stride:指定redistributor的步长,必须是64KB的倍数
  • #redistributor-regions:如果系统中有多个redistributor时,需要这个属性来描述多个redistributor区域

3) gic-v3设备节点中的子设备节点ITS(Interrupt Translation Services):一个GIC中有1到多个ITS设备,ITS设备用于将消息信号中断(MSI)路由到cpu,ITS设备节点的描述如下:

  • compatible:必须包含字符串"arm,gic-v3-its",表示这是一个ITS设备
  • msi-controller:标识该设备节点为MSI控制器
  • #msi-cells:必须是1,这里面是MSI设备的DeviceID
  • reg:ITS寄存器的物理基地址

2.1.2 Linux系统中 gic-v3 设备节点

内核在创建设备节点的时候的主要数据结构为struct device_node,该结构体通过解析.dtb得到,以下是struct device_node的源码和注释:

struct property {/*该property的名称*/char    *name;/*该property的长度*/int   length;/*该property的值*/void  *value;/*和该property相连接的下一个property*/struct property *next;
#if defined(CONFIG_OF_DYNAMIC) || defined(CONFIG_SPARC)unsigned long _flags;
#endif
#if defined(CONFIG_OF_PROMTREE)unsigned int unique_id;
#endif
#if defined(CONFIG_OF_KOBJ)struct bin_attribute attr;
#endif
};#if defined(CONFIG_SPARC)
struct of_irq_controller;
#endifstruct device_node {/*设备节点名称*/const char *name;phandle phandle;/*设备节点名称和地址*/const char *full_name;/*操作该设备节点的一些回调函数*/struct fwnode_handle fwnode;/*节点中的每一组数据( 比如compatible = "arm,cortex-a9-gic")通过结构体property表示,* property->next指向另外一组数据。*/struct  property *properties;/*节点中被移除的property*/struct  property *deadprops;    /* removed properties *//*该设备结点的父设备节点*/struct   device_node *parent;/*该设备结点的子设备节点*/struct   device_node *child;/*该设备结点的兄弟设备节点*/struct   device_node *sibling;
#if defined(CONFIG_OF_KOBJ)struct   kobject kobj;
#endifunsigned long _flags;void *data;
#if defined(CONFIG_SPARC)unsigned int unique_id;struct of_irq_controller *irq_trans;
#endif
};

系统解析2.1.1中的 gic-v3 DTS后得到的struct device_node如下:

  • device_node->name = "interrupt-controller"
  • device_node->full_name = "interrupt-controller@2c010000"
  • device_node->properties->name = "compatible"
  • device_node->properties->value = "arm,gic-v3"
  • device_node->properties->length = 10 (字符串"arm,gic-v3"的长度)
  • device_node->properties->next->name = "redistributor-stride"
  • device_node->properties->next->value = {0x0,0x0,0x0,0x0, 0x0,0x04,0x0,0x0}
  • device_node->properties->next->length = 4(一个字段占4个字节)
  • device_node->properties->next->next->name = "reg"

......

  • device_node->child->name = "gic-its"
  • device_node->child->full_name = "gic-itss@2c200000"

......

  • device_node->child->next->name = "gic-its"
  • device_node->child->next->full_name = "gic-itss@2c400000"

......

2.2 Linux系统中gic-v3初始化

2.2.1 struct of_device_id结构体

struct of_device_id {char    name[32];char   type[32];char   compatible[128];const void *data;
};/** This special of_device_id is the sentinel at the end of the* of_device_id[] array of all irqchips. It is automatically placed at* the end of the array by the linker, thanks to being part of a* special section.*/
static const struct of_device_id
irqchip_of_match_end __used __section(__irqchip_of_table_end);extern struct of_device_id __irqchip_of_table[];

1) struct of_device_id结构体

  • name:设备名称
  • type:设备类型
  • compatible:对应DTS文件中设备结点的compatible,用来匹配适合的device node
  • data:对于GIC来说,data字段为初始化GIC的函数地址

2) __irqchip_of_table:一个系统全局数组,数组中的每个对象是一个全局struct of_device_id静态常量,IRQCHIP_DECLARE宏用于初始化一个struct of_device_id的静态常量,并放置在__irqchip_of_table中。

2.2.2 宏IRQCHIP_DECLARE

/** This macro must be used by the different irqchip drivers to declare* the association between their DT compatible string and their* initialization function.** @name: name that must be unique across all IRQCHIP_DECLARE of the* same file.* @compstr: compatible string of the irqchip driver* @fn: initialization function*/
#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)#define OF_DECLARE_2(table, name, compat, fn) \_OF_DECLARE(table, name, compat, fn, of_init_fn_2)#define _OF_DECLARE(table, name, compat, fn, fn_type)         \static const struct of_device_id __of_table_##name     \__used __section(__##table##_of_table)         \= { .compatible = compat,                \.data = (fn == (fn_type)NULL) ? fn : fn  }

以上是linux系统中宏IRQCHIP_DECLARE的定义,这个宏初始化了一个struct of_device_id的静态常量,并放置在__irqchip_of_table中。

IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);

如上代码所示,IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init)声明了一个__of_table_gic_v3的struct of_device_id结构体,放在__irqchip_of_table中。__of_table_gic_v3.compatible为"arm,gic-v3",__of_table_gic_v3.data指向函数gic_of_init()的地址。

2.2.3 gic_of_init()函数分析

Linux系统启动后初始化GIC V3的函数调用顺序为init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()。以下是rqchip_init(),of_irq_init()函数相关代码及其注释:

extern struct of_device_id __irqchip_of_table[];void __init irqchip_init(void)
{of_irq_init(__irqchip_of_table);acpi_probe_device_table(irqchip);
}/*** of_irq_init - 在DT中扫描并初始化匹配的中断控制器* @matches: 用于扫描并匹配的中断控制器的所有设备节点的一个数据,即__irqchip_of_table** 该函数扫描设备树以查找匹配的中断控制器节点,并执行它们的初始化函数。*/
void __init of_irq_init(const struct of_device_id *matches)
{const struct of_device_id *match;struct device_node *np, *parent = NULL;struct of_intc_desc *desc, *temp_desc;struct list_head intc_desc_list, intc_parent_list;INIT_LIST_HEAD(&intc_desc_list);INIT_LIST_HEAD(&intc_parent_list);/*遍历__irqchip_of_table得到的中断控制器设备信息,并为每个中断控*制器设备分配一个struct of_intc_desc 结构体*/for_each_matching_node_and_match(np, matches, &match) {if (!of_property_read_bool(np, "interrupt-controller") ||!of_device_is_available(np))continue;if (WARN(!match->data, "of_irq_init: no init function for %s\n",match->compatible))continue;/** Here, we allocate and populate an of_intc_desc with the node* pointer, interrupt-parent device_node etc.*/desc = kzalloc(sizeof(*desc), GFP_KERNEL);if (!desc) {of_node_put(np);goto err;}/* match->data 中的内容是gic_of_init()函数地址,* 这里设置of_intc_desc的irq_init_cb 回调函数为gic_of_init()*/desc->irq_init_cb = match->data;desc->dev = of_node_get(np);desc->interrupt_parent = of_irq_find_parent(np);if (desc->interrupt_parent == np)desc->interrupt_parent = NULL;/*将of_intc_desc放到intc_desc_list链表中*/list_add_tail(&desc->list, &intc_desc_list);}/** The root irq controller is the one without an interrupt-parent.* That one goes first, followed by the controllers that reference it,* followed by the ones that reference the 2nd level controllers, etc.*/while (!list_empty(&intc_desc_list)) {/** Process all controllers with the current 'parent'.* First pass will be looking for NULL as the parent.* The assumption is that NULL parent means a root controller.*/list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {int ret;if (desc->interrupt_parent != parent)continue;list_del(&desc->list);of_node_set_flag(desc->dev, OF_POPULATED);pr_debug("of_irq_init: init %pOF (%p), parent %p\n",desc->dev,desc->dev, desc->interrupt_parent);/*执行初始化中断控制器设备的回调函数gic_of_init()*/ret = desc->irq_init_cb(desc->dev,desc->interrupt_parent);if (ret) {of_node_clear_flag(desc->dev, OF_POPULATED);kfree(desc);continue;}/** This one is now set up; add it to the parent list so* its children can get processed in a subsequent pass.*/list_add_tail(&desc->list, &intc_parent_list);}/* Get the next pending parent that might have children */desc = list_first_entry_or_null(&intc_parent_list,typeof(*desc), list);if (!desc) {pr_err("of_irq_init: children remain, but no parents\n");break;}list_del(&desc->list);parent = desc->dev;kfree(desc);}list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) {list_del(&desc->list);kfree(desc);}
err:list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {list_del(&desc->list);of_node_put(desc->dev);kfree(desc);}
}

以下是gic_of_init()函数的代码和注释,gic_of_init()中调用gic_init_bases()来处理GIC V3初始化的核心工作:

struct redist_region {/*指向Redistributor域内存区间的地址*/void __iomem        *redist_base;/*Redistributor域物理地址*/phys_addr_t      phys_base;/*是否只有一个Redistributor域*/bool          single_redist;
};
/*GIC V3硬件设备相关的数据结构*/
struct gic_chip_data {/*操作该设备的一些回调方法*/struct fwnode_handle  *fwnode;/*指向Distributor内存区间的地址*/void __iomem        *dist_base;/*该gic中所有Redistributor域的信息*/struct redist_region *redist_regions;/*该gic中所有Redistributor的信息*/struct rdists        rdists;/*该GIC对应的irq_domain,Linux系统中每个GIC对应一个irq_domain,* 用于解析硬件中断号*/struct irq_domain *domain;/*Redistributor域之间的步长,64KB的倍数*/u64           redist_stride;/*Redistributor域个数*/u32           nr_redist_regions;u64           flags;bool          has_rss;unsigned int        ppi_nr;struct partition_desc    **ppi_descs;
};static struct gic_chip_data gic_data __read_mostly;static int __init gic_of_init(struct device_node *node, struct device_node *parent)
{void __iomem *dist_base;struct redist_region *rdist_regs;u64 redist_stride;u32 nr_redist_regions;int err, i;/*为node映射内存区间,这里返回的dist_base是Distributor的地址*/dist_base = of_iomap(node, 0);if (!dist_base) {pr_err("%pOF: unable to map gic dist registers\n", node);return -ENXIO;}/*检查GIC硬件版本是否是V3或者V4*/err = gic_validate_dist_version(dist_base);if (err) {pr_err("%pOF: no distributor detected, giving up\n", node);goto out_unmap_dist;}/*读取该设备节点中redistributor个数,如果该设备DT中没有"#redistributor-regions"字段,* 那就只有一个redistributor*/if (of_property_read_u32(node, "#redistributor-regions", &nr_redist_regions))nr_redist_regions = 1;/*根据redistributor个数分配redistributor数组*/rdist_regs = kcalloc(nr_redist_regions, sizeof(*rdist_regs),GFP_KERNEL);if (!rdist_regs) {err = -ENOMEM;goto out_unmap_dist;}for (i = 0; i < nr_redist_regions; i++) {struct resource res;int ret;ret = of_address_to_resource(node, 1 + i, &res);/*已分配的每个redistributor区域映射内存区间*/rdist_regs[i].redist_base = of_iomap(node, 1 + i);if (ret || !rdist_regs[i].redist_base) {pr_err("%pOF: couldn't map region %d\n", node, i);err = -ENODEV;goto out_unmap_rdist;}rdist_regs[i].phys_base = res.start;}/*读取该设备节点中每个redistributor区域之间的步长,如果该设备DT中* 没有"#redistributor-stride"字段,redist_stride大小为0*/if (of_property_read_u64(node, "redistributor-stride", &redist_stride))redist_stride = 0;gic_enable_of_quirks(node, gic_quirks, &gic_data);/*开始正式初始化GIC V3设备*/err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions,redist_stride, &node->fwnode);if (err)goto out_unmap_rdist;gic_populate_ppi_partitions(node);if (static_branch_likely(&supports_deactivate_key))gic_of_setup_kvm_info(node);return 0;out_unmap_rdist:for (i = 0; i < nr_redist_regions; i++)if (rdist_regs[i].redist_base)iounmap(rdist_regs[i].redist_base);kfree(rdist_regs);
out_unmap_dist:iounmap(dist_base);return err;
}/*@dist_base:Distributor的地址,*@rdist_regs:GIC设备中所有Redistributor的地址信息*@nr_redist_regions:Redistributor的个数*@redist_stride:Redistributor区域之间的步长,*@handle:是该设备节点对应的数据结构struct device_node中的fwnode,*         指向与irq_domain关联的固件节点的指针*/
static int __init gic_init_bases(void __iomem *dist_base,struct redist_region *rdist_regs,u32 nr_redist_regions,u64 redist_stride,struct fwnode_handle *handle)
{u32 typer;int err;if (!is_hyp_mode_available())static_branch_disable(&supports_deactivate_key);if (static_branch_likely(&supports_deactivate_key))pr_info("GIC: Using split EOI/Deactivate mode\n");/*gic_data是一个静态的全局变量,这里对其进行一些初始化*/gic_data.fwnode = handle;gic_data.dist_base = dist_base;gic_data.redist_regions = rdist_regs;gic_data.nr_redist_regions = nr_redist_regions;gic_data.redist_stride = redist_stride;/** Find out how many interrupts are supported.*/typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);gic_data.rdists.gicd_typer = typer;gic_enable_quirks(readl_relaxed(gic_data.dist_base + GICD_IIDR),gic_quirks, &gic_data);pr_info("%d SPIs implemented\n", GIC_LINE_NR - 32);pr_info("%d Extended SPIs implemented\n", GIC_ESPI_NR);/*在系统中为GIC V3注册一个irq domain的数据结构. irq_domain主要作用是映射硬件中断号*/gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops,&gic_data);/*一个设备节点中可能有多个irq_domain,这些irq_domain用于不同的目的,DOMAIN_BUS_WIRED* 表示该irq_domain用于wired IRQS*/irq_domain_update_bus_token(gic_data.domain, DOMAIN_BUS_WIRED);gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist));gic_data.rdists.has_vlpis = true;gic_data.rdists.has_direct_lpi = true;if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {err = -ENOMEM;goto out_free;}/*rss表示SGI中断亲和性的范围,GICD_TYPER_RSS值为GICD_TYPER寄存器的bit[26],*  0表示中断路由(IRI) 支持affinity 0-15的SGI*  1表示支持affinity 0 - 255的SGI*/gic_data.has_rss = !!(typer & GICD_TYPER_RSS);pr_info("Distributor has %sRange Selector support\n",gic_data.has_rss ? "" : "no ");if (typer & GICD_TYPER_MBIS) {err = mbi_init(handle, gic_data.domain);if (err)pr_err("Failed to initialize MBIs\n");}/* 设置中断回调函数gic_handle_irq,当发生中断时,* 系统会执行gic_handle_irq来处理中断*/set_handle_irq(gic_handle_irq);/*更新Redistributor相关的属性*/gic_update_rdist_properties();/*1.设置核间通信,2.设置CPU启动时动态注册gic的回调函数gic_cpu_init*/gic_smp_init();/*初始化Distributor*/gic_dist_init();/*初始化CPU Interface*/gic_cpu_init();/*初始化GIC电源管理*/gic_cpu_pm_init();if (gic_dist_supports_lpis()) {/*初始化ITS*/its_init(handle, &gic_data.rdists, gic_data.domain);its_cpu_init();} else {if (IS_ENABLED(CONFIG_ARM_GIC_V2M))gicv2m_init(handle, gic_data.domain);}gic_enable_nmi_support();return 0;out_free:if (gic_data.domain)irq_domain_remove(gic_data.domain);free_percpu(gic_data.rdists.rdist);return err;
}err;
}

Linux 中断管理之ARM GIC V3 初始化相关推荐

  1. arm Linux 中断管理机制

    关键词:GIC.IAR.EOI.SGI/PPI/SPI.中断映射.中断异常向量.中断上下文.内核中断线程.中断注册. 1.1 ARM支持中断类型 ARM GIC-v2支持三种类型的中断: SGI:软件 ...

  2. Linux 内存管理(1)--物理内存初始化

    1 内存初始化总体流程 内核版本:Linux 4.14 硬件平台:IMX6DL-SABRESD start_kernel() |----page_address_init() |----setup_a ...

  3. Linux中断管理 (3)workqueue工作队列

    关键词: 工作队列的原理是把work(需要推迟执行的函数)交由一个内核线程来执行,它总是在进程上下文中执行. 工作队列的优点是利用进程上下文来执行中断下半部操作,因此工作队列允许重新调度和睡眠,是异步 ...

  4. arm linux 中断 分析,armlinux中断异常的处理分析.pdf

    基于 ARM Linux 中断.异常的处理分析 本文是基于ARM S3C2410X 系统的Linux 2.6 中断.异常和系统调用的处理分析. 主要有以下几个部分: 1. ARM 的硬件中断机制 2. ...

  5. Linux 中断所有知识点

    目录 Linux 中断管理机制 GIC 硬件原理 GIC v3中断类别 GIC v3 组成 中断路由 中断状态机 中断处理流程 GIC 驱动 设备树 初始化 中断的映射 数据结构 中断控制器注册 ir ...

  6. 吐血整理 | 肝翻 Linux 中断所有知识点

    Linux 中断管理机制 GIC 硬件原理 GIC,Generic Interrupt Controller.是ARM公司提供的一个通用的中断控制器.主要作用为:接受硬件中断信号,并经过一定处理后,分 ...

  7. linux - 中断子系统分析(1) -- GICv3硬件架构

    目录 1. 参考文档 2. GIC Version History 3. Interrup Types 4. Interrupt State Machine 5. Programmer's Model ...

  8. 深入理解Linux内存管理--目录导航

    日期 内核版本 架构 作者 GitHub CSDN 2016-08-31 Linux-4.7 X86 & arm gatieme LinuxDeviceDrivers Linux内存管理 1 ...

  9. linux内存管理子系统采用基于内存区域,Linux 内存管理之highmem简介

    一.Linux内核地址空间 一般来说Linux 内核按照 3:1 的比率来划分虚拟内存(X86等):3 GB 的虚拟内存用于用户空间,1GB 的内存用于内核空间.当然有些体系结构如MIPS使用2:2 ...

最新文章

  1. UIEdgeInsets 说明
  2. C#——简单的计算器(仿Windows 10计算器)
  3. SEO中HTML标签权重
  4. Git + Maven + Jenkins 实现自动化部署
  5. java拷贝文件目录结构_Java如何复制目录_Java基础教程系列
  6. 一分钟获得幸福的99个方式
  7. Jquery快速构建可拖曳的购物车-DragDrop
  8. Matlab 散点 拟合 曲率,有数据点,希望得到一条拟合曲线,再求出这条曲线的曲率,求助!...
  9. YOLOv2-darknet 内容解析
  10. partition by 和 group by
  11. jetson nano 自动调节风扇转速
  12. RMAN-06091: no channel allocated for maintenance (of an appropriate type)
  13. 穷爸爸富爸爸里面说的“现金流游戏”靠谱吗?
  14. 常用自然语言处理NLP模型原理
  15. php私有云盘,教你搭建个人/企业私有云盘-kodexplorer
  16. linux bin sh命令,linux shell中#!bin/sh的理解
  17. 基于AM5728 DSP JTAG连接调试方法
  18. MindManager 思维导图全面介绍
  19. html 自动填充缓存,禁止input密码自动填充及浏览器缓存密码账号解决方案
  20. ONNX Runtime: ubutnu16.04编译 (编到怀疑人生)

热门文章

  1. 此更新不适用您的计算机 win10,高手亲自讲解Win10系统提示此更新不适用于您的详尽处理办法...
  2. 骨传导加动圈,这款Dacom耳机有何出众之处?开箱验证
  3. 学习记录3——PMSM数学建模——simulink内数学模型搭建以及仿真
  4. 走进区块链 | 巴比特2020校招正式开启
  5. 计算机课程设计-基于ssm+vue的物资管理系统(前后端分离)-物资出库入库管理系统java代码
  6. ⌨RK61键盘使用方法
  7. 1:2000比例尺测图
  8. 阿里原来这么容易就能进去…
  9. 论文笔记(十六):Learning to Walk in Minutes Using Massively Parallel Deep Reinforcement Learning
  10. 美国回国机票多种航线任您选