Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to configure GIC on qemu(cortex-a57+virt)? #1

Closed
NienfengYao opened this issue Jul 10, 2018 · 5 comments
Closed

How to configure GIC on qemu(cortex-a57+virt)? #1

NienfengYao opened this issue Jul 10, 2018 · 5 comments

Comments

@NienfengYao
Copy link

Hi,
I am study timer irq in qemu(cortex-a57+virt), so I reference your project. But I have some problem, the timer irq doesn't work currently in my study. If could, can you give me some suggestion? I am very appreciate it.

My study is armv8-bare-metal (commit 80cdcd3aec00942b5af28acaf350c136abf1a730),

# how to run 
make run

Current status is I can set timer and can read timeout from CNTV_CTL_EL0[2]: ISTATUS. But I am not familiar with GIC of armv8, so I reference your gic-pl390 and call init_gicd()/init_gicc()/gicd_enable_int(27) to do test. But still can get the interrupt exception and call the exception handler. The log is blow

$ make run
qemu-system-aarch64 -machine virt -cpu cortex-a57 -nographic -kernel kernel.elf

/* init_gicd( ) */
REG_GIC_GICD_CTLR: 0x00000000 08000000 = 0x00000000 00000000
Write REG_GIC_GICD_ICENABLER:
0x00000000 08000180 = 0x00000000 FFFFFFFF
0x00000000 08000184 = 0x00000000 FFFFFFFF
Write REG_GIC_GICD_ICPENDR:
0x00000000 08000280 = 0x00000000 FFFFFFFF
0x00000000 08000284 = 0x00000000 FFFFFFFF
REG_GIC_GICD_IPRIORITYR:
0x00000000 08000400 = 0x00000000 FFFFFFFF
0x00000000 08000404 = 0x00000000 FFFFFFFF
0x00000000 08000408 = 0x00000000 FFFFFFFF
0x00000000 0800040C = 0x00000000 FFFFFFFF
0x00000000 08000410 = 0x00000000 FFFFFFFF
0x00000000 08000414 = 0x00000000 FFFFFFFF
0x00000000 08000418 = 0x00000000 FFFFFFFF
0x00000000 0800041C = 0x00000000 FFFFFFFF
0x00000000 08000420 = 0x00000000 FFFFFFFF
0x00000000 08000424 = 0x00000000 FFFFFFFF
0x00000000 08000428 = 0x00000000 FFFFFFFF
0x00000000 0800042C = 0x00000000 FFFFFFFF
0x00000000 08000430 = 0x00000000 FFFFFFFF
0x00000000 08000434 = 0x00000000 FFFFFFFF
0x00000000 08000438 = 0x00000000 FFFFFFFF
0x00000000 0800043C = 0x00000000 FFFFFFFF
REG_GIC_GICD_ITARGETSR:
0x00000000 08000820 = 0x00000000 00000000
0x00000000 08000824 = 0x00000000 00000000
0x00000000 08000828 = 0x00000000 00000000
0x00000000 0800082C = 0x00000000 00000000
0x00000000 08000830 = 0x00000000 00000000
0x00000000 08000834 = 0x00000000 00000000
0x00000000 08000838 = 0x00000000 00000000
0x00000000 0800083C = 0x00000000 00000000
REG_GIC_GICD_ICFGR:
0x00000000 08000C04 = 0x00000000 00000000
0x00000000 08000C08 = 0x00000000 00000000
0x00000000 08000C0C = 0x00000000 00000000
REG_GIC_GICD_CTLR: 0x00000000 08000000 = 0x00000000 00000001

/* init_gicc( ) */
GICC_CTLR: 0x00000000 08010000 = 0x00000000 00000000
REG_GIC_GICC_PMR: 0x00000000 08010004 = 0x00000000 000000FF
REG_GIC_GICC_BPR : 0x00000000 08010008 = 0x00000000 00000000
REG_GIC_GICC_EOI : Clear all of the active interrupts
REG_GIC_GICC_CTLR : 0x00000000 08010000 = 0x00000000 00000001

/* gicd_enable_int(27) */
REG_GIC_GICD_ISENABLER: 0x00000000 08000100 = 0x00000000 0800FFFF

/* Virtual Timer config */
CurrentEL = 0x00000000 00000004    /* EL1 */
DAIF = 0x00000000 000003C0         /* DAIF bits are set */
CNTV_CTL_EL0 = 0x00000000 00000000
Disable the timer, CNTV_CTL_EL0 = 0x00000000 00000000 /* Clear bits of ENABLE/IMASK */
CNTFRQ_EL0 = 0x00000000 03B9ACA0   /* frequency of the system counter = 62.5MHz */ 
CNTVCT_EL0 = 0x00000000 000242C5   /* current 64-bit virtual count value */
Set it as next 1 sec, CNTV_CVAL_EL0 = 0x00000000 03BBEF65 /* set compare value */
Enable the timer, CNTV_CTL_EL0 = 0x00000000 00000001  /* Set bit ENABLE */
Enable IRQ, DAIF = 0x00000000 00000340  /* Clear IRQ mask bit */

/* we observe the CNTVCT_EL0 and CNTV_CTL_EL0 */
/* if time up, CNTV_CTL_EL0[2] = 1 */
CNTVCT_EL0 = 0x00000000 000390CA, CNTV_CTL_EL0 = 0x00000000 00000001
CNTVCT_EL0 = 0x00000000 0003D41F, CNTV_CTL_EL0 = 0x00000000 00000001
...
/* time up, CNTV_CTL_EL0[2]: ISTATUS = 1*/
CNTVCT_EL0 = 0x00000000 03BCE5C4, CNTV_CTL_EL0 = 0x00000000 00000005
SPSR_EL1 = 0x00000000 00000000
ISR_EL1 = 0x00000000 00000000
/* But the irq_handler doesn't be called and ISR_EL1[7] = 0 */
/* there is no IRQ interrupt pending detected */
EMU: Terminated
@takeharukato
Copy link
Owner

takeharukato commented Jul 10, 2018

Hi, Nienfeng

Thank you for having interest in my sample codes.
First of all, would you please notice that the vector base address on AArch64 should be aligned to 4096 byte NOT 0x80.

Would you please see macros in include/hal-aarch64/exception.h of my codes.
These macros are defined as follows.

#define vector_base_align .align 12  /* The vector base must be placed in 4096 bytes align */
#define vector_entry_align .align 7  /* Each vector entry must be placed in 256 bytes align */
#define text_align      .align  2    /* Text alignment */

And I use them like this:

vectors:
        /*
         * Current EL with SP0(e.g.,Trapped from User Task in EL1)
         */
        vector_entry_align
        b       _el1_user_sync  /* Synchronous */
        vector_entry_align
        b       _el1_user_irq   /* IRQ/vIRQ */
        vector_entry_align
        b       _el1_user_fiq   /* FIQ/vFIQ */
        vector_entry_align
        b       _el1_user_error /* SError/vSError */

        /*
         * Current EL with SPx(e.g.,Interrupted from Kernel in EL1)
         */
        vector_entry_align
        b       _el1_sync       /* Synchronous */
        vector_entry_align
        b       _el1_irq        /* IRQ/vIRQ */
        vector_entry_align
        b       _el1_fiq        /* FIQ/vFIQ */
        vector_entry_align
        b       _el1_error      /* SError/vSError */

I tried to fix you vector entry with the following patch.

diff --git a/boot.S b/boot.S
index c7814a7..14cae13 100644
--- a/boot.S
+++ b/boot.S
@@ -91,7 +91,8 @@ curr_el_spx_serror:                   // The exception handler for the system
        bl      serror_test                     // exception from the current EL using the
                                                        // current SP.

-.balign        0x80
+//.balign      0x80
+.balign        0x1000  // vector base should be aligned to 4096 byte.
 vector_table_el1:
 lower_el_aarch64_sync:         // The exception handler for the synchronous
        bl      sync_test                       // exception from a lower EL (AArch64).
diff --git a/kernel.c b/kernel.c
index 138f372..5a714d8 100644
--- a/kernel.c
+++ b/kernel.c
@@ -349,8 +349,11 @@ void timer_test(void)
 /*
 *      Main
 */
 int main() {
        uart_puts("Hello world!\n");
+       asm("svc #0xdead\n\t");
        timer_test();
 }

And then I saw the following result.

qemu-system-aarch64  -machine virt -cpu cortex-a57 -n
ographic -kernel kernel.elf
Hello world!
sync_test

But it seems that this svc call entered into the lower_el_aarch32_sync entry.
I think that it say some bugs around vector handling exist.
I might look into the cause of this problem if I can spare my time( I cannot promise this ).

$ aarch64-none-elf-gdb
GNU gdb (GDB) 7.12.50.20160823-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=aarch64-none-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) symbol-file kernel.elf
Reading symbols from kernel.elf...done.
(gdb) b curr_el_sp0_sync
Breakpoint 1 at 0x40000800: file boot.S, line 61.
(gdb) b curr_el_sp0_irq
Breakpoint 2 at 0x40000880: file boot.S, line 65.
(gdb) b curr_el_sp0_fiq
Breakpoint 3 at 0x40000900: file boot.S, line 69.
(gdb) b curr_el_sp0_serror
Breakpoint 4 at 0x40000980: file boot.S, line 73.
(gdb) b curr_el_spx_sync
Breakpoint 5 at 0x40000a00: file boot.S, line 78.
(gdb) b curr_el_spx_irq
Breakpoint 6 at 0x40000a80: file boot.S, line 83.
(gdb) b curr_el_spx_fiq
Breakpoint 7 at 0x40000b00: file boot.S, line 87.
(gdb) b curr_el_spx_serror
Breakpoint 8 at 0x40000b80: file boot.S, line 91.
(gdb) b lower_el_aarch64_sync
Breakpoint 9 at 0x40001000: file boot.S, line 99.
(gdb) b lower_el_aarch64_irq
Breakpoint 10 at 0x40001080: file boot.S, line 104.
(gdb) b lower_el_aarch64_fiq
Breakpoint 11 at 0x40001100: file boot.S, line 109.
(gdb) b lower_el_aarch64_serror
Breakpoint 12 at 0x40001180: file boot.S, line 114.
(gdb) b lower_el_aarch32_sync
Breakpoint 13 at 0x40001200: file boot.S, line 119.
(gdb) b lower_el_aarch32_irq
Breakpoint 14 at 0x40001280: file boot.S, line 124.
(gdb) b lower_el_aarch32_fiq
Breakpoint 15 at 0x40001300: file boot.S, line 129.
(gdb) b lower_el_aarch32_sync
Note: breakpoint 13 also set at pc 0x40001200.
Breakpoint 16 at 0x40001200: file boot.S, line 119.
(gdb) remote_target
warning: No executable has been specified and target does not support
determining executable automatically.  Try using the "file" command.
_start () at boot.S:7
7               mrs     x0, mpidr_el1
(gdb) c
Continuing.

Breakpoint 13, lower_el_aarch32_sync () at boot.S:119
119             bl      sync_test                       // exception from a lower EL(AArch32).

I hope this comment will help your study.

Thanks,
Regards,

@takeharukato
Copy link
Owner

takeharukato commented Jul 10, 2018

Hi, Nienfeng

After all, I noticed that the code I shew above was correct.
lower_el_aarch32_sync did not have correct name, It should have been el1_sync.

And I found the reason why your codes could not receive any interrupts.
The reason is that you should have set up the irq line for the timer correctly (e.g., priority, trigger type, and so on) .
I fixed your code roughly.
Would you please see below.

diff --git a/gic-pl390.c b/gic-pl390.c
index 890bbd4..36e896e 100644
--- a/gic-pl390.c
+++ b/gic-pl390.c
@@ -309,7 +309,7 @@ static void gicd_enable_int(irq_no irq) {
        #endif
 }

-#if 0 //RyanYao
+
 /** Clear a pending interrupt
     @param[in] irq IRQ number
  */
@@ -330,19 +330,6 @@ gicd_set_pending(irq_no irq) {
                1U << ( irq % GIC_GICD_ISPENDR_PER_REG );
 }

-/** Probe pending interrupt
-    @param[in] irq IRQ number
- */
-static int
-gicd_probe_pending(irq_no irq) {
-       int is_pending;
-
-       is_pending = ( *REG_GIC_GICD_ISPENDR( (irq / GIC_GICD_ISPENDR_PER_REG) ) &
-           ( 1U << ( irq % GIC_GICD_ISPENDR_PER_REG ) ) );
-
-       return ( is_pending != 0 );
-}

 /** Set an interrupt target processor
     @param[in] irq IRQ number
     @param[in] p   Target processor mask
@@ -397,6 +384,20 @@ gicd_config(irq_no irq, unsigned int config){
        reg |= ( ( (uint32_t)config ) << shift );  /* Set the value to the field correponding t
        *REG_GIC_GICD_ICFGR( irq / 16 ) = reg;
 }
+#if 0 //RyanYao
+
+/** Probe pending interrupt
+    @param[in] irq IRQ number
+ */
+static int
+gicd_probe_pending(irq_no irq) {
+       int is_pending;
+
+       is_pending = ( *REG_GIC_GICD_ISPENDR( (irq / GIC_GICD_ISPENDR_PER_REG) ) &
+           ( 1U << ( irq % GIC_GICD_ISPENDR_PER_REG ) ) );
+
+       return ( is_pending != 0 );
+}

 /** Configure IRQ line for GIC
     @param[in] ctrlr   IRQ controller information
@@ -466,6 +467,11 @@ void gic_pl390_initialize(void){
     uart_puts("gic_pl390_initialize\n");
        init_gicd();
        init_gicc();
+
+       gicd_config(27, GIC_GICD_ICFGR_EDGE);
+       gicd_set_priority(27, 0 << GIC_PRI_SHIFT );  /* Set priority */
+       gicd_set_target(27, 0x1);  /* processor 0 */
+       gicd_clear_pending(27);
        gicd_enable_int(27);
 }
 #else
@@ -539,7 +545,7 @@ aarch64_init_interrupt(void){
            1, NULL, test_handler);
+/** Probe pending interrupt
+    @param[in] irq IRQ number
+ */
+static int
+gicd_probe_pending(irq_no irq) {
+       int is_pending;
+
+       is_pending = ( *REG_GIC_GICD_ISPENDR( (irq / GIC_GICD_ISPENDR_PER_REG) ) &
+           ( 1U << ( irq % GIC_GICD_ISPENDR_PER_REG ) ) );
+
+       return ( is_pending != 0 );
+}

 /** Configure IRQ line for GIC
     @param[in] ctrlr   IRQ controller information
@@ -466,6 +467,11 @@ void gic_pl390_initialize(void){
     uart_puts("gic_pl390_initialize\n");
        init_gicd();
        init_gicc();
+
+       gicd_config(27, GIC_GICD_ICFGR_EDGE);
+       gicd_set_priority(27, 0 << GIC_PRI_SHIFT );  /* Set priority */
+       gicd_set_target(27, 0x1);  /* processor 0 */
+       gicd_clear_pending(27);
        gicd_enable_int(27);
 }
 #else
@@ -539,7 +545,7 @@ aarch64_init_interrupt(void){
            1, NULL, test_handler);

 }

+#endif
 /** Raise Interrupt(Debugging use)
     @param[in] irq     IRQ number
  */
@@ -548,4 +554,4 @@ gic_raise_irq(irq_no irq){

        gicd_set_pending(irq);
 }
-#endif
+

I got the following result. It might be what you would like to get.

qemu-system-aarch64 -machine virt -cpu cortex-a57 -nographic -kernel kernel.elf
Hello world!
timer_test
gic_pl390_initialize
init_gicd()
REG_GIC_GICD_CTLR: 0x00000000 08000000 = 0x00000000 00000000
Write REG_GIC_GICD_ICENABLER:
0x00000000 08000180 = 0x00000000 FFFFFFFF
0x00000000 08000184 = 0x00000000 FFFFFFFF
Write REG_GIC_GICD_ICPENDR:
0x00000000 08000280 = 0x00000000 FFFFFFFF
0x00000000 08000284 = 0x00000000 FFFFFFFF
REG_GIC_GICD_IPRIORITYR:
0x00000000 08000400 = 0x00000000 FFFFFFFF
0x00000000 08000404 = 0x00000000 FFFFFFFF
0x00000000 08000408 = 0x00000000 FFFFFFFF
0x00000000 0800040C = 0x00000000 FFFFFFFF
0x00000000 08000410 = 0x00000000 FFFFFFFF
0x00000000 08000414 = 0x00000000 FFFFFFFF
0x00000000 08000418 = 0x00000000 FFFFFFFF
0x00000000 0800041C = 0x00000000 FFFFFFFF
0x00000000 08000420 = 0x00000000 FFFFFFFF
0x00000000 08000424 = 0x00000000 FFFFFFFF
0x00000000 08000428 = 0x00000000 FFFFFFFF
0x00000000 0800042C = 0x00000000 FFFFFFFF
0x00000000 08000430 = 0x00000000 FFFFFFFF
0x00000000 08000434 = 0x00000000 FFFFFFFF
0x00000000 08000438 = 0x00000000 FFFFFFFF
0x00000000 0800043C = 0x00000000 FFFFFFFF
REG_GIC_GICD_ITARGETSR:
0x00000000 08000820 = 0x00000000 00000000
0x00000000 08000824 = 0x00000000 00000000
0x00000000 08000828 = 0x00000000 00000000
0x00000000 0800082C = 0x00000000 00000000
0x00000000 08000830 = 0x00000000 00000000
0x00000000 08000834 = 0x00000000 00000000
0x00000000 08000838 = 0x00000000 00000000
0x00000000 0800083C = 0x00000000 00000000
REG_GIC_GICD_ICFGR:
0x00000000 08000C04 = 0x00000000 00000000
0x00000000 08000C08 = 0x00000000 00000000
0x00000000 08000C0C = 0x00000000 00000000
REG_GIC_GICD_CTLR: 0x00000000 08000000 = 0x00000000 00000001
GICC_CTLR: 0x00000000 08010000 = 0x00000000 00000000
REG_GIC_GICC_PMR: 0x00000000 08010004 = 0x00000000 000000FF
REG_GIC_GICC_BPR : 0x00000000 08010008 = 0x00000000 00000000
REG_GIC_GICC_EOI : Clear all of the active interrupts
REG_GIC_GICC_CTLR : 0x00000000 08010000 = 0x00000000 00000001
REG_GIC_GICD_ISENABLER: 0x00000000 08000100 = 0x00000000 0800FFFF
CurrentEL = 0x00000000 00000004
RVBAR_EL1 = 0x00000000 00000000
VBAR_EL1 = 0x00000000 40001000
DAIF = 0x00000000 000003C0
CNTV_CTL_EL0 = 0x00000000 00000000
Disable the timer, CNTV_CTL_EL0 = 0x00000000 00000000
CNTFRQ_EL0 = 0x00000000 03B9ACA0
CNTVCT_EL0 = 0x00000000 0004C7B7
Set it as next 1 sec, CNTV_CVAL_EL0 = 0x00000000 03BE7457
Enable the timer, CNTV_CTL_EL0 = 0x00000000 00000001
Enable IRQ, DAIF = 0x00000000 00000340

CNTVCT_EL0 = 0x00000000 0005BBB7, CNTV_CTL_EL0 = 0x00000000 00000001
CNTVCT_EL0 = 0x00000000 0005DA2D, CNTV_CTL_EL0 = 0x00000000 00000001
CNTVCT_EL0 = 0x00000000 0005EFFC, CNTV_CTL_EL0 = 0x00000000 00000001
CNTVCT_EL0 = 0x00000000 0006054C, CNTV_CTL_EL0 = 0x00000000 00000001
CNTVCT_EL0 = 0x00000000 00061A9B, CNTV_CTL_EL0 = 0x00000000 00000001irq_test

Thanks,
Regards,

@NienfengYao
Copy link
Author

NienfengYao commented Jul 11, 2018

Hi, Takeharukato
I am very appreciate your help. You do me a grate favor and I am studying the information.
Thanks a lot.

Best Regards.

@ghost
Copy link

ghost commented Jul 6, 2023

I'm glad I seen this I have spent nearly a week trying to figure out and debug the timer IRQ stuff. I'll check out the patches and adapt my code accordingly. Hopefully this will work!

@lzwgucas
Copy link

lzwgucas commented Oct 8, 2024

Hi, takeharukato:
when run the command: qemu-system-aarch64 -machine virt -cpu cortex-a57 -nographic -kernel kernel.elf.
what is the gic version?
I have tried as belows:
1)When add gic-version=2, the result is successful.
2)When add gic-version=2, secure=on and modify the vbar_el1 to vbar_el3 in boot.S. The ISR_EL1's value is 0x80, that means there is interrupt pending, but cpu does not handle it.
3)when add gic-version=3, there are not any results at all. The ISR_EL1‘s value is 0x0,there is no interrupt pending.

Can you help me to find the reason?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants