当前位置:网站首页>QEMU ARM interrupt system architecture
QEMU ARM interrupt system architecture
2022-06-22 05:24:00 【alex_mianmian】
QEMU interrupt system use GPIO to implement interrupt system. We can understand it by a simple model:
Device.[GPIO_OUT] ->[GPIO_IN].GIC.[GPIO_OUT]->[GPIO_IN].core
GPIO_IN IRQ is created by qdev_init_gpio_in()
GPIO_OUT IRQ is initialized by sysbus_init_irq()->qdev_init_gpio_out_named(). Attention, GPIO_OUT IRQ is not created. Actually it is just a IRQ pointer, and the IRQ pointer will point to the GPIO_IN IRQ which connected. sysbus_connect_irq() connects GPIO_OUT and GPIO_IN IRQ.
Here let's take vexpress-a9 as the example.
ARM core:
ARM core has irq,fiq,virq,vfiq for GPIO_IN IRQ. they are created at:
arm_cpu_initfn()->qdev_init_gpio_in(DEVICE(cpu), arm_cpu_set_irq, 4);
GIC:
GIC has 96 GPIO_IN IRQs and 4 GPIO_OUT IRQs, and they are created at:
arm_gic_realize()->gic_init_irqs_and_mmio()
void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler,
const MemoryRegionOps *ops,
const MemoryRegionOps *virt_ops)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(s);
int i = s->num_irq - GIC_INTERNAL;
/* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
* GPIO array layout is thus:
* [0..N-1] SPIs
* [N..N+31] PPIs for CPU 0
* [N+32..N+63] PPIs for CPU 1
* ...
*/
i += (GIC_INTERNAL * s->num_cpu);
qdev_init_gpio_in(DEVICE(s), handler, i); // GPIO_IN IRQs
// GPIO_OUT IRQs
for (i = 0; i < s->num_cpu; i++) {
sysbus_init_irq(sbd, &s->parent_irq[i]);
}
for (i = 0; i < s->num_cpu; i++) {
sysbus_init_irq(sbd, &s->parent_fiq[i]);
}
for (i = 0; i < s->num_cpu; i++) {
sysbus_init_irq(sbd, &s->parent_virq[i]);
}
for (i = 0; i < s->num_cpu; i++) {
sysbus_init_irq(sbd, &s->parent_vfiq[i]);
}
....
}GICState is GIC state logic. We can see it has parent_irq[],parent_fiq[],parent_virq[],parent_vfiq[] 4 GPIO_OUT IRQs.
Actually they are all IRQ pointers. They will point to core's 4 GPIO_IN IRQs. Where do them connect? in init_cpus().
static void init_cpus(MachineState *ms, const char *cpu_type,
const char *privdev, hwaddr periphbase,
qemu_irq *pic, bool secure, bool virt)
{
DeviceState *dev;
SysBusDevice *busdev;
.....
.....
dev = qdev_create(NULL, privdev);
busdev = SYS_BUS_DEVICE(dev); /*here busdev is a9mpcore_priv*/
.....
for (n = 0; n < smp_cpus; n++) {
DeviceState *cpudev = DEVICE(qemu_get_cpu(n));
sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
sysbus_connect_irq(busdev, n + smp_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
sysbus_connect_irq(busdev, n + 2 * smp_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
sysbus_connect_irq(busdev, n + 3 * smp_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
}
.....
}sysbus_connect_irq() connect device's GPIO_OUT IRQ to CPU's GPIO_IN IRQ. But here device is a9mpcore_priv, not GIC.
How does it work?
In a9mp_priv_realize(), there is a IRQ pass code:
sysbus_pass_irq(sbd, gicbusdev);
Here sbd presents a9mpcore_priv, gicbusdev presents GIC. This function make them connect, and a9mpcore_priv can use GIC's GPIO_OUT IRQ.
Device:
let's take UART as example.
Device need initialize GPIO_OUT IRQ and connect to GIC GPIO_IN IRQ.
Initialzation at:
static void pl011_init(Object *obj)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
PL011State *s = PL011(obj);
int i;
.....
for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
sysbus_init_irq(sbd, &s->irq[i]);
printf("alexxie:%s, uart irq at %p\n",__func__,s->irq[i]);
}
.....
}
Connection at:
static void vexpress_common_init(MachineState *machine)
{
qemu_irq pic[64];
pl011_create(map[VE_UART0], pic[5], serial_hd(0));
pl011_create(map[VE_UART1], pic[6], serial_hd(1));
pl011_create(map[VE_UART2], pic[7], serial_hd(2));
pl011_create(map[VE_UART3], pic[8], serial_hd(3));
}map[] is address map of the vexpress. pic[] is the GIC GPIO_IN IRQ.
Let's read pl011_create firstly, then back to pic[].
static inline DeviceState *pl011_create(hwaddr addr,
qemu_irq irq,
Chardev *chr)
{
DeviceState *dev;
SysBusDevice *s;
PL011State *uart_s ;
dev = qdev_create(NULL, "pl011");
s = SYS_BUS_DEVICE(dev);
.....
sysbus_connect_irq(s, 0, irq); //connect irq
uart_s = PL011(dev);
printf("alexdebug:%s, uart irq is at %p,%p,%p,%p,%p,%p\n",__func__,uart_s->irq[0],uart_s->irq[1],uart_s->irq[2],uart_s->irq[3],uart_s->irq[4],uart_s->irq[5]);
return dev;
}Here we can see sysbus_connect_irq() is called to connect pl011 to irq. irq is from pic[5],pic[6],pic[7] and pic[8].
How do we know pic[] is from GIC GPIO_IN? let's check the code.
static void vexpress_common_init(MachineState *machine)
{
VexpressMachineClass *vmc = VEXPRESS_MACHINE_GET_CLASS(machine);
VEDBoardInfo *daughterboard = vmc->daughterboard;
qemu_irq pic[64];
.....
daughterboard->init(vms, machine->ram_size, machine->cpu_type, pic);
.....
}daughterboard->init is a9_daughterboard_init()
static void a9_daughterboard_init(const VexpressMachineState *vms,
ram_addr_t ram_size,
const char *cpu_type,
qemu_irq *pic)
{
/* 0x1e000000 A9MPCore (SCU) private memory region */
init_cpus(machine, cpu_type, TYPE_A9MPCORE_PRIV, 0x1e000000, pic,
vms->secure, vms->virt);
}keep dive into init_cpus()
static void init_cpus(MachineState *ms, const char *cpu_type,
const char *privdev, hwaddr periphbase,
qemu_irq *pic, bool secure, bool virt)
{
DeviceState *dev;
.....
dev = qdev_create(NULL, privdev);
.....
{
a9_s = A9MPCORE_PRIV(dev);
printf("alexdebug:%s, GIC parent_irq at %p\n",__func__,a9_s->gic.parent_irq[0]);
}
for (n = 0; n < 64; n++) {
DeviceState* gicdev=DEVICE(&a9_s->gic);
pic[n] = qdev_get_gpio_in(gicdev, n); //get gic gpio_in
//pic[n] = qdev_get_gpio_in(dev, n);
printf("alexxie:%s, pic[%d] at %p\n",__func__,n,pic[n]);
}
.....
}OK, here we can see pic[] is from GIC by function qdev_get_gpio_in(). You may noticed the code is changed by me. Yes, the origin code pic[] is from a9mpcore_priv and a9mpcore_priv will call GIC. I modified it because I want to try if I can make it simpler to remove one layer of GPIO. it works. So the code is current look.
OK, to here, the question is answered.
边栏推荐
- 北京密云区知识产权贯标的好处,补贴5-10万
- How to find the source of goods for novice stores and how to find high-quality sources of goods?
- C language data type conversion rules (implicit conversion + explicit conversion)
- 《MATLAB 神经网络43个案例分析》:第28章 决策树分类器的应用研究——乳腺癌诊断
- YARN 应用提交过程
- Squoosh - Google's free open source image compression tool, reducing the image size by 90%! Support API development calls
- postmanUtils工具类,模拟postman的get,post请求
- Kubernetes -- setting up an environment using minicube
- P1318 积水面积
- 1108. Defanging an IP Address
猜你喜欢

Liunx virtual machine environment uses docker to install Oracle database and Navicat to connect

Free questions for polymerization process and test papers for polymerization process in 2022

Six sides tmall has already offered. After a review of my experience, is it really that difficult to enter a big factory?
Graph calculation on nlive:nepal's graph calculation practice

Contents of 2022 tea master (intermediate) examination and tea master (intermediate) examination

汉诺塔问题
![P1077 [NOIP2012 普及组] 摆花](/img/0d/f74a2036aa261ed327d9d74291aacc.png)
P1077 [NOIP2012 普及组] 摆花

The prediction made ten years ago by the glacier has now been realized by Ali, which is very shocking
![Force buckle 33 [search rotation sort array]](/img/0f/d7e2f2fdf48bcd70e6c69bca7d4002.png)
Force buckle 33 [search rotation sort array]

使用keytool从.jks文件获取SSL certificate
随机推荐
DeformConv
Monorepo silk slide methodology: reference module hot update
Monorepo Sliding methodology: Reference module Hot Update
Some notes on the use of C language strings
[cloud native] 2.2 kubeadm create cluster
C语言自定义函数的一些注意事项
1108. Defanging an IP Address
Topic selection system of college graduation design based on SSM
花式优化器整理
深圳南山区专精特新小巨人企业申报指标,补贴50万
Hash type of redis
Force buckle 33 [search rotation sort array]
Get jedis from jedissentinelpool
从JedisSentinelPool获取jedis
Which methods are not allowed to be overridden?
TIDB-performance overview面板
DTS migration script sqlserver
部署SuperMap iServer war包时的服务迁移
Jedispool tool class
JedisSentinel 工具类