Linux 中断管理之ARM GIC V3 初始化

news/2024/11/6 11:06:15/

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-MAXLPI是基于消息的中断,它们的配置保存在表中而不是寄存器

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;
}

 

 


http://www.ppmy.cn/news/806874.html

相关文章

GICv3和GICv4虚拟化

本文档翻译自文档Arm Generic Interrupt Controller v3 and v4 - Virtualization 1 虚拟化 Armv8-A选择性的支持虚拟化。为了完成该功能&#xff0c;GICv3也支持虚拟化。GICv3中对虚拟化的支持包括如下功能&#xff1a; CPU Interface寄存器的硬件虚拟化产生和发送虚拟中断的…

GICv3/v4-软件概述

目录内容 2 介绍→主要介绍GIC架构历史3 GICv3基础→概念理解&#xff0c;尤其是编程模型的理解4 GIC配置→如何配置GIC的各种寄存器&#xff0c;使其正常工作5 处理中断→讲解中断的处理流程6 LPI配置→理解ITS服务和基于消息的中断7 SGI中断→如何发送接收软中断8 虚拟化→如…

[gic]-ARM gicv3/gicv4的详细介绍-2020/08

快速链接: . &#x1f449;&#x1f449;&#x1f449; 个人博客笔记导读目录(全部) &#x1f448;&#x1f448;&#x1f448; 付费专栏-付费课程 【购买须知】: 【精选】ARMv8/ARMv9架构入门到精通-[目录] &#x1f448;&#x1f448;&#x1f448; gic目录 1、gic概念(1)、…

【转】ARM GIC中断系列(八):gicv3架构-波形为例、系列总结

花了一天&#xff0c;边玩边看&#xff0c;把这个系列看完了。感叹确实卢俊前辈对于gic的掌握程度。 肯定很多的东西看了就忘了&#xff0c;这是正常的&#xff0c;在以后如果有用到的话&#xff0c;再回过头来&#xff0c;结合实践应该会映像深刻。 1、波形 以下以gic600与…

【k8s】k8s的yaml文件解释,如何部署一个java.jar包

前言&#xff1a; k8s的yaml文件解释&#xff0c;如何部署一个java,jar包 YAML语法格式&#xff1a; 大小写敏感&#xff1b;使用缩进表示层级关系&#xff1b;不支持Tab键制表符缩进&#xff0c;只使用空格缩进&#xff1b;缩进的空格数目不重要&#xff0c;只要相同层级的元…

黑苹果 intel 4600 解决 驱动 花屏 7m显存

更新&#xff1a;2020年06月16日 星期二 中文圈里找了一圈&#xff0c;要么解决办法过时了&#xff0c;要么花屏 从tonymacx86找到了解决办法&#xff0c;就2张图

极客日报:腾讯回应旗下App暂停更新传闻;小米称被苹果反超只因iPhone 13太强;下一代AMD CPU或将有12个CCD

一分钟速览新闻点&#xff01; 腾讯回应旗下App将暂停更新传闻小米奖励计划人均获得超56万元台积电或将成为苹果5G芯片供应商小米称被苹果反超只因iPhone 13太强元宇宙相关商标申请超过4400条微软为VMware、Hyper-V等虚拟机推出Win11企业版镜像马斯克亲自测试特斯拉最新版自动…

极客日报:爆字节跳动日均进账10.07亿元;iPhone 13粉屏上热搜;英特尔跌落神坛,CEO回应:是我们骄傲自大了

一分钟速览新闻点&#xff01; 消息人士&#xff1a;字节跳动日均进账10.07亿QQ音乐App测试看广告免费听歌&#xff0c;仅限部分受邀用户有赞被曝第一轮裁员将超1500人 副总裁已离职罗永浩宣布春节后回归科技界继绿屏、红绿屏后&#xff0c;iPhone13粉屏再遭用户投诉英特尔跌落…