GIC

GIC Trace32

이 문서는 Trace32 디버거 사용시, GIC 관련 유용한 내용을 정리했습니다.
GICv3 기준입니다.

Peribrowser

GIC CPU interface는 ARMv8-A architecture의 시스템 레지스터 일부여서
CPU attach 순간 peribrowse가능하다.
그 외에, Distributor나 Redistributor 레지스터는 peri reprogram이 필요하다.

peri 등록은 다음과 같다.

B:: sys.config.gicd type gic600
B:: sys.config.gicd base a:{gicd base address}
B:: sys.config.gicr base a:{gicr base address}
B:: per.reprogram


CMM script

GICv3 하드웨어 인터럽트 동작을 확인할 수 있는
CMM 스크립트

Chip boot 직후(core0 only) GIC ON script


/////////////////////////////
// tcc807x gicv3 init script
//
// - for using gic
//     in bare-metal
/////////////////////////////


////////////////////////
// User Configuration //
////////////////////////
&gicd_base={gicd base addr}
&gicr_base={gicd base addr}
&gicr_num_of_regs=1.


////////////////
// GIC offset //
////////////////
&sgi_offset=0x10000


/////////////
// Example //
/////////////
GOSUB GICV3_DISTIF_INIT &gicd_base
GOSUB GICV3_RDISTIF_INIT &gicr_base &gicr_num_of_regs
GOSUB GICV3_CPUIF_INIT &gicr_base
ENDDO


///////////////
// functions //
///////////////
GICV3_DISTIF_INIT:
        ENTRY &arg_gicd_ctlr
        LOCAL &rwp_true
        LOCAL &index &value

        &value=D.Long(AD:&arg_gicd_ctlr)
        &value=&value|(1<<0) ;enable G0
        &value=&value|(1<<1) ;enable G1
        &value=&value|(1<<2) ;enable G1NS
        // enable G0, G1, G1NS before enable ARE_S //
        D.S AD:&arg_gicd_ctlr %LE %Long &value

        &value=&value|(1<<4)
        &value=&value|(1<<5)
        D.S AD:&arg_gicd_ctlr %LE %Long &value
        &rwp_true=1
        while &rwp_true==1
        (
                &rwp_true=D.Long(AD:&arg_gicd_ctlr)
                &rwp_true=&rwp_true>>31.
        )

        RETURN
GICV3_RDISTIF_INIT:
        ENTRY &arg_gicr_ctlr &arg_num_of_reg
        LOCAL &gicr_pwrr &pwrr_offset
        LOCAL &gicr_icenabler &enable_clr_offset
        LOCAL &rwp_true
        LOCAL &index

        &pwrr_offset=0x24
        &enable_clr_offset=&sgi_offset+0x180

        // Redistributor Power On //
        &gicr_pwrr=&arg_gicr_ctlr+&pwrr_offset
        D.S AD:&gicr_pwrr %LE %Long 0x0

        // All clear enable registers //
        &index=1.
        &gicr_icenabler=&arg_gicr_ctlr+&enable_clr_offset
        D.S AD:&gicr_icenabler %LE %Long 0xFFFFFFFF
        &rwp_true=1
        while &rwp_true==1
        (
                &rwp_true=D.Long(AD:&arg_gicr_ctlr)
                &rwp_true=&rwp_true>>31.
        )

        // Set Groups G1NS as default //
        &gicr_igroupr=&arg_gicr_ctlr+&sgi_offset+0x80
        D.S AD:&gicr_igroupr %LE %Long 0xFFFFFFFF

        RETURN

        GICV3_CPUIF_INIT:
        ENTRY &arg_gicr_ctlr
        LOCAL &gicr_waker
        LOCAL &icc_sre_el1 &icc_sre_el3
        LOCAL &icc_pmr_el1
        LOCAL &ca_bit

        &gicr_waker=&arg_gicr_ctlr+0x14

        // gicr core awake //
        &ca_bit=0.
        while &ca_bit==0
        (
                &ca_bit=D.Long(AD:&gicr_waker)
                &ca_bit=&ca_bit&0x7
                &ca_bit=&ca_bit>>2.
        )
        // clear PS bit and wait till ca_bit is 0 //
        D.S AD:&gicr_waker %LE %Long 0x4
        while &ca_bit!=0
                &ca_bit=D.Long(AD:&gicr_waker)

        // set SRE by exception levels //
        &icc_sre_el1=0x30CC5
        &icc_sre_el3=0x36CC5
        D.S SPR:&icc_sre_el3 %Quad 0xF ; auto set 0x7 in icc_sre_el1
        //////////////////////////////////////
        //                     //
        // scr_el3 <- SCR_NS_BIT            //
        // icc_sre_el2 <- read(icc_sre_el3) //
        // scr_el3 <- ~SCR_NS_BIT           //
        // icc_sre_el1 <- 0x7               //
        //////////////////////////////////////

        // set pmr //
        &icc_pmr_el1=0x30460
        D.S SPR:&icc_pmr_el1 %Quad 0xF0 ; num of priority level: 16

        // set group enable for virtual IRQ //
        &icc_igrpen0_el1=0x30CC6
        D.S SPR:&icc_igrpen0_el1 %Quad 0x1
        &icc_igrpen1_el1=0x30CC7
        D.S SPR:&icc_igrpen1_el1 %Quad 0x1
        &icc_igrpen1_el3=0x36CC7
        D.S SPR:&icc_igrpen1_el3 %Quad 0x3

        RETURN
  </code></pre>
사용자는 User Configuration 파트만 수정해주면 된다.
User Configuration
gicd_base: gicd base address를 작성한다.
gicr_base: gicr core 0 lpi base address를 작성한다.
gicr_num_of_regs: Chip boot 직후는 core 0 만 켜져있기 때문에 거의 1 고정

</details>

GIC PPIs SPIs 테스트 스크립트


/////////////////////////////
// gicv3 test script
//
// - delete WDT kernel configs
// B:: sys.config.gicd type gic600
// B:: sys.config.gicd base a:{GICD base address}
// B:: sys.config.gicr type a:{GICR base address}
// B:: per.reprogram
/////////////////////////////

&main=0x0
&sub=0x1

////////////////////////
// User Configuration //
////////////////////////
&num_of_chip=
&cluster=&main ; &main or &sub
&gicd_base_addr=
&gicr_base_addr=
&in_el3=0.
&eoi_mode=0.

//////////////////////////
// User Configuration 2 //
//////////////////////////
&start_irq=16. ; PPIs ~
&gic_max_irq=512.+1. ; 480(SPIs) + 32(SGIs, PPIs)

//////////////////////////
// User Configuration 3 //
//////////////////////////
&gic_target_core=0.


////////////////////////////
// ARM-A System Registers //
// addr prefix: "spr"     //
////////////////////////////
// EL3 //
&scr_el3=0x36110
// GIC CPU Interfaces //
&icc_iar0_el1=0x30c80
&icc_iar1_el1=0x30cc0
&icc_hppir0_el1=0x30c82
&icc_hppir1_el1=0x30cc2
&icc_eoir0_el1=0x30c81
&icc_eoir1_el1=0x30cc1
&icc_dir_el1=0x30cb1
&icc_sgi0r_el1=0x30cb7
&icc_sgi1r_el1=0x30cb5
// System Counter //
&cntp_ctl_el0=0x33e21
&cntv_ctl_el0=0x33e31
&cntps_ctl_el1=0x37e21
&cnthp_ctl_el2=0x34e20
&cntkctl_el1=0x30e10
&cnthctl_el2=0x34e10

///////////////////
// GIC registers //
///////////////////
// GIC offsets //
&iroute_offset=0x6100
&enable_offset=0x100
&enable_clr_offset=0x180
&grp_offset=0x80
&grpmod_offset=0xd00
&pend_offset=0x200
&pend_clr_offset=0x280
&active_offset=0x300
&active_clr_offset=0x380
&sgi_offset=0x10000
&num_of_reg=((&active_clr_offset-&active_offset)/4)+1
&num_of_spi=(&gic_max_irq-32.)
// GIC interrupt registers //
Var.NEWLOCAL long [&num_of_reg] \gic_isenabler
Var.NEWLOCAL long [&num_of_reg] \gic_icenabler
Var.NEWLOCAL long [&num_of_reg] \gic_groupr
Var.NEWLOCAL long [&num_of_reg] \gic_grpmodr
Var.NEWLOCAL long [&num_of_reg] \gic_ispendr
Var.NEWLOCAL long [&num_of_reg] \gic_icpendr
Var.NEWLOCAL long [&num_of_reg] \gic_isactiver
Var.NEWLOCAL long [&num_of_reg] \gic_icactiver
// GICD //
&gicd_base_addr=&gicd_base_addr+(&cluster*0x20000)
&gicd_route_base_addr=&gicd_base_addr+&iroute_offset
&gicd_enable_base_addr=&gicd_base_addr+&enable_offset
&gicd_enable_clr_base_addr=&gicd_base_addr+&enable_clr_offset
&gicd_grp_base_addr=&gicd_base_addr+&grp_offset
&gicd_grpmod_base_addr=&gicd_base_addr+&grpmod_offset
&gicd_pend_base_addr=&gicd_base_addr+&pend_offset
&gicd_pend_clr_base_addr=&gicd_base_addr+&pend_clr_offset
&gicd_active_base_addr=&gicd_base_addr+&active_offset
&gicd_active_clr_base_addr=&gicd_base_addr+&active_clr_offset
// GICR //
&gicr_base_addr=&gicr_base_addr+(&cluster*0x20000)+(&gic_target_core*0x20000)
&gicr_lpi_base_addr=&gicr_base_addr
&gicr_sgi_base_addr=&gicr_base_addr+&sgi_offset
&gicr_isenabler=&gicr_sgi_base_addr+&enable_offset
&gicr_icenabler=&gicr_sgi_base_addr+&enable_clr_offset
&gicr_groupr=&gicr_sgi_base_addr+&grp_offset
&gicr_grpmodr=&gicr_sgi_base_addr+&grpmod_offset
&gicr_ispendr=&gicr_sgi_base_addr+&pend_offset
&gicr_icpendr=&gicr_sgi_base_addr+&pend_clr_offset
&gicr_isactiver=&gicr_sgi_base_addr+&active_offset
&gicr_icactiver=&gicr_sgi_base_addr+&active_clr_offset

//////////
// Etc. //
//////////
// common //
&addr=0x0
&index=0.
&irq=0.
// group //
Var.NEWLOCAL long [&gic_max_irq] \irq_group
&irq_group_flag=1.


GOSUB ENV_PRESET

// GIC Verification //
GOSUB GIC_SETUP
GOSUB GIC_STATUS_INIT
GOSUB GIC_AFFINITY_SETUP

sys.log.ON
&irq=&start_irq
WHILE &irq<&gic_max_irq
(
	//////////////////////////////////////////////////
	// Use '> continue' in script debug mode        //
	// <---------------------- (Break.Set)          //
	//////////////////////////////////////////////////
	GOSUB GIC_IRQ_HANDLE &irq
	&irq=&irq+1.
)
sys.log.OFF

ENDDO


ENV_PRESET:
	LOCAL &cpsr
	LOCAL &cpsr_nzcv &cpsr_endian &cpsr_async &cpsr_int &cpsr_mode
	LOCAL &scr
	LOCAL &scr_irq &scr_fiq &scr_ns

	Core.select &gic_target_core

	&cpsr=0x0
	&cpsr_nzcv=(0x4<<28.)
	&cpsr_endian=(0x1<<9.)
	&cpsr_async=(0x1<<8.)
	&cpsr_int=(0x3<<6.)
	&cpsr_mode=0xd ; EL3h

	&secure=0x0
	&scr_irq=(0x1<<1.)
	&scr_fiq=(0x1<<2.)
	&scr_ns=(0x1<<0.)

	&cpsr=&cpsr_nzcv|&cpsr_endian|&cpsr_async|&cpsr_int|&cpsr_mode
	Register.Set CPSR &cpsr

	&secure=D.Long(SPR:&scr_el3)
	&secure=&secure|&scr_irq|&scr_fiq
	&secure=&secure&(~&scr_ns)
	Data.Set SPR:&scr_el3 &secure

	// EL3 -> EL1 //
	if &in_el3==0
	(
		&secure=D.Long(SPR:&scr_el3)
		&secure=&secure&(~&scr_irq)
		&secure=&secure&(~&scr_fiq)
		Data.Set SPR:&scr_el3 &secure

		&cpsr_mode=0x5 ; EL1h
		&cpsr=&cpsr&0xFFFFFFF0
		&cpsr=&cpsr|&cpsr_mode
		Register.Set CPSR &cpsr
	)

	RETURN


GIC_REG_SETUP:
	&index=0.
	WHILE &index<&num_of_reg
	(
		if &index==0.
		(
			Var.set \gic_isenabler[&index]=&gicr_isenabler
			Var.set \gic_icenabler[&index]=&gicr_icenabler
			Var.set \gic_groupr[&index]=&gicr_groupr
			Var.set \gic_grpmodr[&index]=&gicr_grpmodr
			Var.set \gic_ispendr[&index]=&gicr_ispendr
			Var.set \gic_icpendr[&index]=&gicr_icpendr
			Var.set \gic_isactiver[&index]=&gicr_isactiver
			Var.set \gic_icactiver[&index]=&gicr_icactiver
		)
		else
		(
			Var.set \gic_isenabler[&index]=&gicd_enable_base_addr+(&index*0x4)
			Var.set \gic_icenabler[&index]=&gicd_enable_clr_base_addr+(&index*0x4)
			Var.set \gic_groupr[&index]=&gicd_grp_base_addr+(&index*0x4)
			Var.set \gic_grpmodr[&index]=&gicd_grpmod_base_addr+(&index*0x4)
			Var.set \gic_ispendr[&index]=&gicd_pend_base_addr+(&index*0x4)
			Var.set \gic_icpendr[&index]=&gicd_pend_clr_base_addr+(&index*0x4)
			Var.set \gic_isactiver[&index]=&gicd_active_base_addr+(&index*0x4)
			Var.set \gic_icactiver[&index]=&gicd_active_clr_base_addr+(&index*0x4)
		)
		&index=&index+1.
	)

	RETURN

GIC_AFFINITY_SETUP:
	Data.Set ASD:&gicd_route_base_addr++(&num_of_spi*8) %LE %Long (&gic_target_core<<8.)

	RETURN

EOI_MODE_SETUP:
	ENTRY &mode
	LOCAL &icc_ctlr_el1 &icc_ctlr_el3
	LOCAL &eoi_mode_el1 &eoi_mode_el3

	if &mode==0
	(
		&icc_ctlr_el1=0x30cc4
		&eoi_mode_el1=D.Long(SPR:&icc_ctlr_el1)
		&eoi_mode_el1=&eoi_mode_el1&(~0x2)
		PER.Set.simple SPR:&icc_ctlr_el1 %Quad &eoi_mode_el1
		if &in_el3==1.
		(
			&icc_ctlr_el3=0x36cc4
			&eoi_mode_el3=D.Long(SPR:&icc_ctlr_el3)
			&eoi_mode_el3=&eoi_mode_el1&(~0x10)
			PER.Set.simple SPR:&icc_ctlr_el3 %Quad &eoi_mode_el3
		)
	)

	RETURN


IRQ_GROUP_SETUP: // GICD_CTLR.DS == 0
	ENTRY &arg_id &arg_index
	LOCAL &val_groupr &val_grpmodr

	&val_groupr=D.Long(ASD:Var.value(\gic_groupr[&arg_index]))
	&val_groupr=&val_groupr>>(&arg_id%32.)
	&val_groupr=&val_groupr&0x1
	&val_grpmodr=D.Long(ASD:Var.value(\gic_grpmodr[&arg_index]))
	&val_grpmodr=&val_grpmodr>>(&arg_id%32.)
	&val_grpmodr=&val_grpmodr&0x1

	if (&val_groupr|&val_grpmodr)==1
		Var.set \irq_group[&arg_id]=1.
	else
		Var.set \irq_group[&arg_id]=0.

	RETURN


DS_IRQ_GROUP_SETUP: // GICD_CTLR.DS == 1
	ENTRY &arg_id &arg_index
	LOCAL &val_groupr

	&val_groupr=D.Long(ASD:Var.value(\gic_groupr[&arg_index]))
	&val_groupr=&val_groupr>>(&arg_id%32.)
	&val_groupr=&val_groupr&0x1

	if &val_groupr==1
		Var.set \irq_group[&arg_id]=1.
	else
		Var.set \irq_group[&arg_id]=0.

	RETURN


GIC_SETUP:
	LOCAL &gicd_ctlr &gicd_ctlr_ds

	GOSUB EOI_MODE_SETUP &eoi_mode
	GOSUB GIC_REG_SETUP

	&gicd_ctlr=D.Long(ASD:&gicd_base_addr)
	&gicd_ctlr=&gicd_ctlr&(1<<6)
	&gicd_ctlr_ds=&gicd_ctlr>>6
	if &gicd_ctlr_ds==0
	(
		&index=0.
		&id=0.
		WHILE &id<&gic_max_irq
		(
			GOSUB IRQ_GROUP_SETUP &id &index
			&id=&id+1.
			&index=(&id/32.)
		)
	)
	else
	(
		&index=0.
		&id=0.
		WHILE &id<&gic_max_irq
		(
			GOSUB DS_IRQ_GROUP_SETUP &id &index
			&id=id+1.
			&index=(&id/32.)
		)
	)

	RETURN


GIC_SET_IRQ:
	ENTRY &arg_id

	Data.Set ASD:Var.Value(\gic_isenabler[&arg_id/32.]) %LE %Long (1<<(&arg_id%32.))
	Data.Set ASD:Var.Value(\gic_ispendr[&arg_id/32.]) %LE %Long (1<<(&arg_id%32.))

	RETURN


GIC_CLR_IRQ:
	ENTRY &arg_id

	Data.Set ASD:Var.Value(\gic_icpendr[&arg_id/32.]) %LE %Long (1<<(&arg_id%32.))
	Data.Set ASD:Var.Value(\gic_icenabler[&arg_id/32.]) %LE %Long (1<<(&arg_id%32.))

	RETURN


GIC_IRQ_HANDLE:
	ENTRY &arg_irq
	LOCAL &iar &restore_iar
	LOCAL &val_enabler &val_pendr &val_activer
	LOCAL &special_id

	if &arg_irq==32.
		GOSUB OFF_SYS_COUNTER &gic_target_core

	&irq_group_flag=Var.value(\irq_group[&arg_irq])
	&special_id=0.
	&spurious_cnt=0.

	if &irq_group_flag==0.
	(
		&icc_iar=&icc_iar0_el1
		&icc_eoi=&icc_eoir0_el1
	)
	else
	(
		&icc_iar=&icc_iar1_el1
		&icc_eoi=&icc_eoir1_el1
	)

	GOSUB GIC_SET_IRQ &arg_irq

	&iar=D.Long(SPR:&icc_iar)

	if (&iar&(~0x3))==1020.
		&special_id=1
	else
		&special_id=0

	if &special_id==0
	(
		// Check active status //
		&val_activer=D.Long(ASD:Var.Value(\gic_isactiver[&iar/32.]))
		&val_activer=&val_activer>>(&iar%32.)
		&val_activer=&val_activer&0x1

		// Check interrupt life-cycle pending -> active //
		if &val_activer==1
		(
			PRINT "Pass interrupt active irq: &iar"
			GOSUB GIC_CLR_IRQ &iar

			PER.Set.simple SPR:&icc_eoi %Quad &iar

			// set dir (eoi mode 1) //
			if &eoi_mode==1
				PER.Set.simple SPR:&icc_dir_el1 %Quad &iar

			// Check active status //
			&val_activer=D.Long(ASD:Var.Value(\gic_isactiver[&iar/32.]))
			&val_activer=&val_activer>>(&iar%32.)
			&val_activer=&val_activer&0x1

			// Check interrupt life-cycle active -> end //
			if &val_activer==0
				PRINT "Pass interrupt handle irq: &iar"
			else
				PRINT "Fail interrupt handle irq: &iar"
		)
		else
		(
			PRINT "Fail interrupt active irq: &iar"
			GOSUB GIC_CLR_IRQ &iar
		)
	)
	else
	(
		PRINT "Spurious interrupt! Check GIC status and irq group"
		PRINT "Recommand RESET and SYStem.Down"
		ENDDO
	)

	RETURN


GIC_STATUS_INIT:
	&index=0.
	WHILE &index<&num_of_reg
	(
		Data.Set ASD:Var.Value(\gic_icenabler[&index]) %LE %Long 0xFFFFFFFF
		Data.Set ASD:Var.Value(\gic_icpendr[&index]) %LE %Long 0xFFFFFFFF
		Data.Set ASD:Var.Value(\gic_icactiver[&index]) %LE %Long 0xFFFFFFFF
		&index=&index+1.
	)

	RETURN


OFF_SYS_COUNTER:
	ENTRY &arg_chip

	Core.select &arg_chip

	Data.Set spr:&cntp_ctl_el0 %LE %Long 0x2
	Data.Set spr:&cntv_ctl_el0 %LE %Long 0x2
	Data.Set spr:&cntps_ctl_el1 %LE %Long 0x2
	Data.Set spr:&cnthp_ctl_el2 %LE %Long 0x2

	Data.Set spr:&cntkctl_el1 %LE %Long 0x3
	Data.Set spr:&cnthctl_el2 %LE %Long 0x303

	RETURN
  

사용자는 User Configuration 파트만 수정해주면 된다.
User Configuration
num_of_chip: 디버거 사용 타겟 칩의 최대 core 수를 작성한다.
cluster: 멀티 클러스터 구조가 아니라면 main이 디폴트 값이다.
gicd_base_addr: gicd의 시작 주소를 작성한다.
gicr_base_addr: gicr core0 lpi 시작 주소를 작성한다.
in_el3: el3 환경에서 테스트하면 1. 작성, el1 환경에서 테스트하면 0. 을 작성한다.
eoi_mode: eoi mode 0 이면 0., 1이면 1.

User Configuration 2
start_irq: 테스트 시작 인터럽트 번호를 작성한다. 보통은 PPIs 시작주소인 16을 쓴다.
gic_max_irq: SoC에서 제공하는 SPI 인터럽트 최대 수를 작성한다. +1. 은 수정하지 않는다.
User Configuration 3
gic_target_core: 인터럽트 테스트할 타겟 cpu 번호를 작성한다. num_of_chip값 보다 크면 안된다.


GIC SGIs GENERATE & ROUTING 테스트 스크립트


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// gicv3 sgi generate script
//
// - kernel 6.1 or later
// - delete WDT kernel configs
//
// - As of T32 Debugger 2023,
//   there is a difference between triggering SGI generation through step execution and using debugger commands to write.
//   Since verification is conducted through step execution, it is essential to load the Linux ELF before running this script.
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

&main=0x0
&sub=0x1

////////////////////////
// User Configuration //
////////////////////////
&num_of_chip=8.
&cluster=&main
&gicd_base_addr=
&gicr_base_addr=
&in_el3=0.
&eoi_mode=0.

//////////////////////////
// User Configuration 2 //
//////////////////////////
&remote_storage=1.
&vmlinux="Z:\work1\tcc807x\main\kernel-6.1\vmlinux"
&invalid_part="/home/user"
&correct_part="Z:"

//////////////////////////
// User Configuration 3 //
//////////////////////////
&sgi_create_core=0.
&sgi_target_core=1.

////////////////////////////
// ARM-A System Registers //
// addr prefix: "spr"     //
////////////////////////////
// EL3 //
&scr_el3=0x36110
// GIC CPU Interfaces //
&icc_iar0_el1=0x30c80
&icc_iar1_el1=0x30cc0
&icc_hppir0_el1=0x30c82
&icc_hppir1_el1=0x30cc2
&icc_eoir0_el1=0x30c81
&icc_eoir1_el1=0x30cc1
&icc_dir_el1=0x30cb1
&icc_sgi0r_el1=0x30cb7
&icc_sgi1r_el1=0x30cb5
// System Counter //
&cntp_ctl_el0=0x33e21
&cntv_ctl_el0=0x33e31
&cntps_ctl_el1=0x37e21
&cntkctl_el1=0x30e10
&cnthctl_el2=0x34e10

///////////////////
// GIC registers //
///////////////////
// GIC offsets //
&enable_offset=0x100
&enable_clr_offset=0x180
&grp_offset=0x80
&grpmod_offset=0xd00
&pend_offset=0x200
&pend_clr_offset=0x280
&active_offset=0x300
&active_clr_offset=0x380
&sgi_offset=0x10000
// GICR //
&gicr_base_addr=&gicr_base_addr+(&cluster*0x20000)+(&sgi_target_core*0x20000)
&gicr_lpi_base_addr=&gicr_base_addr
&gicr_sgi_base_addr=&gicr_base_addr+&sgi_offset
&gicr_isenabler=&gicr_sgi_base_addr+&enable_offset
&gicr_icenabler=&gicr_sgi_base_addr+&enable_clr_offset
&gicr_groupr=&gicr_sgi_base_addr+&grp_offset
&gicr_grpmodr=&gicr_sgi_base_addr+&grpmod_offset
&gicr_ispendr=&gicr_sgi_base_addr+&pend_offset
&gicr_icpendr=&gicr_sgi_base_addr+&pend_clr_offset
&gicr_isactiver=&gicr_sgi_base_addr+&active_offset
&gicr_icactiver=&gicr_sgi_base_addr+&active_clr_offset

/////////////
// vmlinux //
/////////////

/////////////////////////////////////////////////////////////////////////////////////////////////////////
// diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c                            //
// index 11f7c53e4b63..7d5937c375a8 100644                                                             //
// --- a/drivers/irqchip/irq-gic-v3.c                                                                  //
// +++ b/drivers/irqchip/irq-gic-v3.c                                                                  //
// @@ -1298,7 +1298,7 @@ static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask, //
//         (MPIDR_AFFINITY_LEVEL(cluster_id, level) \                                                  //
//                 << ICC_SGI1R_AFFINITY_## level ##_SHIFT)                                            //
//                                                                                                     //
// -static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq)                              //
// +void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq)                                     //
//  {                                                                                                  //
//         u64 val;                                                                                    //
/////////////////////////////////////////////////////////////////////////////////////////////////////////
&break_point=gic_send_sgi+0x40

//////////
// Etc. //
//////////
// common //
&addr=0x0
&core=0
&gic_max_irq=15.
&mpidr_el1=0x30005
&irq=0

GOSUB GIC_SGI_PRESET

sys.log.ON

// GIC SGI generate //
WHILE &irq<=&gic_max_irq
(
	//////////////////////////////////////////////////
	// Use '> continue' in script debug mode        //
	// <---------------------- (Break.Set)          //
	//////////////////////////////////////////////////

	GOSUB GIC_SGI_GENERATE &sgi_create_core &sgi_target_core &irq
	GOSUB GIC_SGI_HANDLE &sgi_target_core &irq
	&irq=&irq+1.
)

sys.log.OFF

ENDDO


GIC_SGI_PRESET:
	Data.LOAD.elf &vmlinux /NoCode
	if &remote_storage==1.
		sYmbol.sourcePATH.translate "&invalid_part" "&correct_part"

	WHILE &core<&num_of_chip
	(
		GOSUB OFF_SYS_COUNTER &core
		&core=&core+1.
	)

	Break.set &break_point

	RETURN


GIC_SGI_GENERATE:
	ENTRY &arg_dpt &arg_dst &arg_id
	LOCAL &aff1 &irq_id &tlist
	LOCAL &sgi_cmd &sgi_staus

	Core.select &arg_dst

	&irq_id=24.
	&aff1=16.
	&tlist=0x1
	&tlist=&tlist|D.Long(SPR:&mpidr_el1)&0xf

	Core.select &arg_dpt

	&sgi_cmd=(&arg_dst<<&aff1)
	&sgi_cmd=&sgi_cmd|(&arg_id<<&irq_id)
	&sgi_cmd=&sgi_cmd|&tlist

	Data.Set ASD:&gicr_isenabler %LE %Long (1<<&arg_id)
	Register.Set PC &break_point
	Register.Set X0 &sgi_cmd
	STEP

	&val_pendr=D.Long(ASD:&gicr_ispendr)>>&arg_id
	&val_pendr=&val_pendr&0x1

	if &val_pendr==1
		PRINT "Pass interrupt pending irq: &arg_id"
	else
		PRINT "Fail interrupt pending irq: &arg_id"

	RETURN


GIC_SET_IRQ:
	ENTRY &arg_id

	Data.Set ASD:&gicr_isenabler %LE %Long (1<<&arg_id)
	Data.Set ASD:&gicr_ispendr %LE %Long (1<<&arg_id)

	RETURN


GIC_CLR_IRQ:
	ENTRY &arg_id

	Data.Set ASD:&gicr_icenabler %LE %Long (1<<&arg_id)
	Data.Set ASD:&gicr_icpendr %LE %Long (1<<&arg_id)

	RETURN


GIC_SGI_HANDLE:
	ENTRY &arg_dst &arg_id

	Core.select &arg_dst
	&iar=D.Long(SPR:&icc_iar1_el1)
	// special ID: 1020 ~ 1023 //
	if (&iar&(~0x3))==1020.
		&special_id=1
	else
		&special_id=0

	if &special_id==0
	(
		&val_activer=D.Long(ASD:&gicr_isactiver)
		&val_activer=&val_activer>>&arg_id
		&val_activer=&val_activer&0x1

		if &val_activer==1
		(
			PRINT "Pass interrupt active irq: &iar"
			GOSUB GIC_CLR_IRQ &iar

			PER.Set.simple SPR:&icc_eoir1_el1 %Quad &iar

			// set dir (eoi mode 1) //
			if &eoi_mode==1.
				PER.Set.simple SPR:&icc_dir_el1 %Quad &iar

			&val_activer=D.Long(ASD:&gicr_isactiver)
			&val_activer=&val_activer>>&arg_id
			&val_activer=&val_activer&0x1

			// Check interrupt life-cycle active -> end //
			if &val_activer==0
			(
				PRINT "Pass interrupt handle irq: &iar"
				PRINT "Pass Core[&sgi_create_core] ===> Core[&sgi_target_core] [SGI:&iar]"
			)
			else
				PRINT "Fail interrupt handle irq: &iar"
		)
		else
		(
			PRINT "Fail interrupt active irq: &iar"
			GOSUB GIC_CLR_IRQ &iar
		)
	)
	else
	(
		PRINT "Spurious interrupt! Check GIC status and irq group"
		PRINT "Recommand RESET and SYStem.Down"
		ENDDO
	)

	RETURN


EOI_MODE_SETUP:
	ENTRY &mode
	LOCAL &icc_ctlr_el1 &icc_ctlr_el3
	LOCAL &eoi_mode_el1 &eoi_mode_el3

	if &mode==0
	(
		&icc_ctlr_el1=0x30cc4
		&eoi_mode_el1=D.Long(SPR:&icc_ctlr_el1)
		&eoi_mode_el1=&eoi_mode_el1&(~0x2)
		PER.Set.simple SPR:&icc_ctlr_el1 %Quad &eoi_mode_el1
		if &in_el3==1.
		(
			&icc_ctlr_el3=0x36cc4
			&eoi_mode_el3=D.Long(SPR:&icc_ctlr_el3)
			&eoi_mode_el3=&eoi_mode_el1&(~0x10)
			PER.Set.simple SPR:&icc_ctlr_el3 %Quad &eoi_mode_el3
		)
	)

	RETURN


GIC_RESET:
	ENTRY &arg_dst
	LOCAL &sgi_cenabler &sgi_cpendr &sgi_cactiver

	&sgi_cenabler=&gicr_icenabler+(0x20000*&arg_dst)
	&sgi_cpendr=&gicr_icpendr+(0x20000*&arg_dst)
	&sgi_cactiver=&gicr_icactiver+(0x20000*&arg_dst)

	Data.Set ASD:&sgi_cenabler %LE %Long 0xFFFFFFFF
	Data.Set ASD:&sgi_cpendr %LE %Long 0xFFFFFFFF
	Data.Set ASD:&sgi_cactiver %LE %Long 0xFFFFFFFF

	RETURN


OFF_SYS_COUNTER:
	ENTRY &arg_chip

	Core.select &arg_chip

	Data.Set spr:&cntp_ctl_el0 %LE %Long 0x2
	Data.Set spr:&cntv_ctl_el0 %LE %Long 0x2
	Data.Set spr:&cntps_ctl_el1 %LE %Long 0x2

	Data.Set spr:&cntkctl_el1 %LE %Long 0x3
	Data.Set spr:&cnthctl_el2 %LE %Long 0x303

	RETURN
  
사용자는 User Configuration 파트만 수정해주면 된다.
User Configuration
num_of_chip: 디버거 사용 타겟 칩의 최대 core 수를 작성한다.
cluster: 멀티 클러스터 구조가 아니라면 main이 디폴트 값이다.
gicd_base_addr: gicd의 시작 주소를 작성한다.
gicr_base_addr: gicr core0 lpi 시작 주소를 작성한다.
in_el3: el3 환경에서 테스트하면 1. 작성, el1 환경에서 테스트하면 0. 을 작성한다.
eoi_mode: eoi mode 0 이면 0., 1이면 1.

User Configuration 2
remote_storage: nfs나 samaba 같은 remote 환경 사용 시, 1. 아니면 0.을 작성한다.
vmlinux: remote_storage가 1일 경우, 빌드한 커널의 vmlinux 경로를 작성한다.
invalid_part: remote_storage가 1일 경우, remote 입장에서의 변환이 필요한 경로를 작성한다.
correct_part: remote_storage가 1일 경우, cmm script 실행 경로에서의 변환이 필요한 경로를 작성한다.
User Configuration 3
&sgi_create_core: SGI를 트리거할 core 번호를 작성한다.
&sgi_target_core: SGI를 처리할 core 번호를 작성한다.


Updated: