当前位置:网站首页>QEMU ARM interrupt system architecture
QEMU ARM interrupt system architecture
2022-06-22 05:40: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.
边栏推荐
- 大厂晋升学习方法四:Play 学习法
- Global and Chinese carbon conductive filler market demand trend and future prospect report 2022-2027
- Tensorflow 2.x(keras)源码详解之第十四章:keras中的回调及自定义回调
- 独立站优化清单丨如何有效提升站内转化率?
- Jedissentinel tool class
- 《MATLAB 神经网络43个案例分析》:第28章 决策树分类器的应用研究——乳腺癌诊断
- P1160 队列安排
- Shenzhen Nanshan District specialized special new small giant enterprise declaration index, with a subsidy of 500000 yuan
- Record local project startup error: invalid source distribution: 8
- Current market situation analysis and investment analysis prospect report of global and Chinese ceramic capacitor industry 2022-2027
猜你喜欢

Hide symbol of dynamic library

Record local project startup error: invalid source distribution: 8

大厂晋升学习方法三:链式学习法
Wanzi detailed data warehouse, data lake, data middle platform and lake warehouse are integrated

Tongda OA vulnerability analysis collection

Delete the packaging use of pop-up components

Working method: 3C scheme design method

大厂晋升学习方法四:Play 学习法

搜狗输入法无法输出中文

Talk about MySQL's locking rule "hard hitting MySQL series 15"
随机推荐
The benefits of implementing the standard of intellectual property in Miyun District, Beijing, with a subsidy of 50000-100000 yuan
Sourcetree reported an error SSH failure
Global and Chinese aluminum electrolytic capacitor market survey and future development strategic planning report 2022-2027
在线文本代码对比工具
Development planning and investment strategy analysis report of global and Chinese microwave ablation industry during the 14th Five Year Plan period 2022-2027
深圳南山区专精特新小巨人企业申报指标,补贴50万
【云原生】2.2 kubeadm创建集群
nacos server 源码运行实现
跨境政策频调整 “ 独立站&平台 ” 哪个才是趋势所在?
Parameter serialization
P1318 积水面积
为什么说“ CPS联盟营销 ” 是性价比最高的推广方式?
Detailed explanation of OpenCV function usage 11~20, including code examples
Implementation of lazy loading of pictures (summary and sorting)
Amazon and independent station are not simply two choices
A piece of code to solve the problem of automatic disconnection of Google colab
Go语言使用zap日志库
北京密云区知识产权贯标的好处,补贴5-10万
Opencv function usage details 1~10, including code examples
long start = currentTimeMillis();