实验五 时钟Tick
Arm的中断系统
中断是一种硬件机制。借助于中断,CPU可以不必再采用轮询这种低效的方式访问外部设备。将所有的外部设备与CPU直接相连是不现实的,外部设备的中断请求一般经由中断控制器,由中断控制器仲裁后再转发给CPU。如下图所示Arm的中断系统。
其中nIRQ是普通中断,nFIQ是快速中断。 Arm采用的中断控制器叫做GIC,即general interrupt controller。gic包括多个版本,如GICv1(已弃用),GICv2,GICv3,GICv4。简单起见,我们实验将选用GICv2版本。
为了配置好gicv2中断控制器,与pl011串口一样,我们需要阅读其技术参考手册。访问Arm官网在 这里 下载ARM Generic Interrupt Controller Architecture Specification - version 2.0 的pdf版本。
从上图(来源于ARM Generic Interrupt Controller Architecture Specification - version 2.0中的Chapter 2 GIC Partitioning)可以看出:
GICv2 最多支持8个核的中断管理。
GIC包括两大主要部分(由图中蓝色虚竖线分隔,Distributor和CPU Interface由蓝色虚矩形框标示),分别是:
Distributor,其通过GICD_开头的寄存器进行控制(蓝色实矩形框标示)
CPU Interface,其通过GICC_开头的寄存器进行控制(蓝色实矩形框标示)
中断类型分为以下几类(由图中红色虚线椭圆标示):
SPI:(shared peripheral interrupt),共享外设中断。该中断来源于外设,通过Distributor分发给特定的core,其中断编号为32-1019。从图中可以看到所有核共享SPI。
PPI:(private peripheral interrupt),私有外设中断。该中断来源于外设,但只对指定的core有效,中断信号只会发送给指定的core,其中断编号为16-31。从图中可以看到每个core都有自己的PPI。
SGI:(software-generated interrupt),软中断。软件产生的中断,用于给其他的core发送中断信号,其中断编号为0-15。
virtual interrupt,虚拟中断,用于支持虚拟机。图中也可以看到,因为我们暂时不关心,所以没有标注。
此外可以看到(FIQ, IRQ)可通过b进行旁路,我们也不关心。如感兴趣可以查看技术手册了解细节。
此外,由ARM Generic Interrupt Controller Architecture Specification - version 2.0 (section 1.4.2)可知,外设中断可由两种方式触发:
edge-triggered: 边沿触发,当检测到中断信号上升沿时中断有效。
level-sensitive:电平触发,当中断源为指定电平时中断有效。
因为soc中,中断有很多,为了方便对中断的管理,对每个中断,附加了中断优先级。在中断仲裁时,高优先级的中断,会优于低优先级的中断,发送给cpu处理。当cpu在响应低优先级中断时,如果此时来了高优先级中断,那么高优先级中断会抢占低优先级中断,而被处理器响应。
由ARM Generic Interrupt Controller Architecture Specification - version 2.0 (section 3.3)可知,GICv2最多支持256个中断优先级。GICv2中规定,所支持的中断优先级别数与GIC的具体实现有关,如果支持的中断优先级数比256少(最少为16),则8位优先级的低位为0,且遵循RAZ/WI(Read-As-Zero, Writes Ignored)原则。
GICv2初始化
由下图中virt.dts中intc和timer的部分
intc@8000000 {
phandle = <0x8001>;
reg = <0x00 0x8000000 0x00 0x10000 0x00 0x8010000 0x00 0x10000>;
compatible = "arm,cortex-a15-gic";
ranges;
#size-cells = <0x02>;
#address-cells = <0x02>;
interrupt-controller;
#interrupt-cells = <0x03>;
v2m@8020000 {
phandle = <0x8002>;
reg = <0x00 0x8020000 0x00 0x1000>;
msi-controller;
compatible = "arm,gic-v2m-frame";
};
};
timer {
interrupts = <0x01 0x0d 0x104 0x01 0x0e 0x104 0x01 0x0b 0x104 0x01 0x0a 0x104>;
always-on;
compatible = "arm,armv8-timer\0arm,armv7-timer";
};
并结合kernel.org中关于 ARM Generic Interrupt Controller 和 ARM architected timer 的devicetree的说明可知:
intc中的
reg指明GICD寄存器映射到内存的位置为0x8000000,长度为0x10000, GICC寄存器映射到内存的位置为0x8010000,长度为0x10000intc中的
#interrupt-cells指明 interrupts 包括3个cells。第一个文档 指明:第一个cell为中断类型,0表示SPI,1表示PPI;第二个cell为中断号,SPI范围为[0-987],PPI为[0-15];第三个cell为flags,其中[3:0]位表示触发类型,4表示高电平触发,[15:8]为PPI的cpu中断掩码,每1位对应一个cpu,为1表示该中断会连接到对应的cpu。以timer设备为例,其中包括4个中断。以第二个中断的参数
0x01 0x0e 0x104为例,其指明该中断为PPI类型的中断,中断号14, 路由到第一个cpu,且高电平触发。但注意到PPI的起始中断号为16,所以实际上该中断在GICv2中的中断号应为16 + 14 = 30。
阅读ARM Generic Interrupt Controller Architecture Specification - version 2.0,在其Chapter 4 Programmers’ Model部分有关于GICD和GICC寄存器的描述,以及如何使能Distributor和CPU Interfaces的方法。
新建 src/bsp/hwi_init.c 文件,初始化 GIC
1#include "prt_typedef.h"
2#include "os_attr_armv8_external.h"
3
4#define OS_GIC_VER 2
5
6#define GIC_DIST_BASE 0x08000000
7#define GIC_CPU_BASE 0x08010000
8
9#define GICD_CTLR (GIC_DIST_BASE + 0x0000U)
10#define GICD_TYPER (GIC_DIST_BASE + 0x0004U)
11#define GICD_IIDR (GIC_DIST_BASE + 0x0008U)
12#define GICD_IGROUPRn (GIC_DIST_BASE + 0x0080U)
13#define GICD_ISENABLERn (GIC_DIST_BASE + 0x0100U)
14#define GICD_ICENABLERn (GIC_DIST_BASE + 0x0180U)
15#define GICD_ISPENDRn (GIC_DIST_BASE + 0x0200U)
16#define GICD_ICPENDRn (GIC_DIST_BASE + 0x0280U)
17#define GICD_ISACTIVERn (GIC_DIST_BASE + 0x0300U)
18#define GICD_ICACTIVERn (GIC_DIST_BASE + 0x0380U)
19#define GICD_IPRIORITYn (GIC_DIST_BASE + 0x0400U)
20#define GICD_ICFGR (GIC_DIST_BASE + 0x0C00U)
21
22
23#define GICD_CTLR_ENABLE 1 /* Enable GICD */
24#define GICD_CTLR_DISABLE 0 /* Disable GICD */
25#define GICD_ISENABLER_SIZE 32
26#define GICD_ICENABLER_SIZE 32
27#define GICD_ICPENDR_SIZE 32
28#define GICD_IPRIORITY_SIZE 4
29#define GICD_IPRIORITY_BITS 8
30#define GICD_ICFGR_SIZE 16
31#define GICD_ICFGR_BITS 2
32
33#define GICC_CTLR (GIC_CPU_BASE + 0x0000U)
34#define GICC_PMR (GIC_CPU_BASE + 0x0004U)
35#define GICC_BPR (GIC_CPU_BASE + 0x0008U)
36#define IAR_MASK 0x3FFU
37#define GICC_IAR (GIC_CPU_BASE + 0xc)
38#define GICC_EOIR (GIC_CPU_BASE + 0x10)
39#define GICD_SGIR (GIC_DIST_BASE + 0xf00)
40
41#define BIT(n) (1 << (n))
42
43#define GICC_CTLR_ENABLEGRP0 BIT(0)
44#define GICC_CTLR_ENABLEGRP1 BIT(1)
45#define GICC_CTLR_FIQBYPDISGRP0 BIT(5)
46#define GICC_CTLR_IRQBYPDISGRP0 BIT(6)
47#define GICC_CTLR_FIQBYPDISGRP1 BIT(7)
48#define GICC_CTLR_IRQBYPDISGRP1 BIT(8)
49
50#define GICC_CTLR_ENABLE_MASK (GICC_CTLR_ENABLEGRP0 | \
51 GICC_CTLR_ENABLEGRP1)
52
53#define GICC_CTLR_BYPASS_MASK (GICC_CTLR_FIQBYPDISGRP0 | \
54 GICC_CTLR_IRQBYPDISGRP0 | \
55 GICC_CTLR_FIQBYPDISGRP1 | \
56 GICC_CTLR_IRQBYPDISGRP1)
57
58#define GICC_CTLR_ENABLE 1
59#define GICC_CTLR_DISABLE 0
60// Priority Mask Register. interrupt priority filter, Higher priority corresponds to a lower Priority field value.
61#define GICC_PMR_PRIO_LOW 0xff
62// The register defines the point at which the priority value fields split into two parts,
63// the group priority field and the subpriority field. The group priority field is used to
64// determine interrupt preemption. NO GROUP.
65#define GICC_BPR_NO_GROUP 0x00
66
67#define GIC_REG_READ(addr) (*(volatile U32 *)((uintptr_t)(addr)))
68#define GIC_REG_WRITE(addr, data) (*(volatile U32 *)((uintptr_t)(addr)) = (U32)(data))
69
70
71// src/arch/drv/gic/prt_gic_init.c
72/*
73* 描述: 去使能(禁用)指定中断
74*/
75OS_SEC_L4_TEXT void OsGicDisableInt(U32 intId)
76{
77 // Interrupt Clear-Enable Registers
78}
79
80/*
81* 描述: 使能指定中断
82*/
83OS_SEC_L4_TEXT void OsGicEnableInt(U32 intId)
84{
85 // Interrupt Set-Enable Registers
86}
87
88// 直接清除中断的pending状态
89OS_SEC_L4_TEXT void OsGicClearIntPending(uint32_t interrupt)
90{
91 // Interrupt Clear-Pending state of an interrupt Registers
92 GIC_REG_WRITE(GICD_ICPENDRn + (interrupt / GICD_ICPENDR_SIZE)*sizeof(U32), 1 << (interrupt % GICD_ICPENDR_SIZE));
93}
94
95// 设置中断号为interrupt的中断的优先级为priority
96OS_SEC_L4_TEXT void OsGicIntSetPriority(uint32_t interrupt, uint32_t priority) {
97 uint32_t shift = (interrupt % GICD_IPRIORITY_SIZE) * GICD_IPRIORITY_BITS;
98 volatile uint32_t* addr = ((volatile U32 *)(uintptr_t)(GICD_IPRIORITYn + (interrupt / GICD_IPRIORITY_SIZE) * sizeof(U32))) ;
99 uint32_t value = GIC_REG_READ(addr);
100 value &= ~(0xff << shift); // 每个中断占8位,所以掩码为 0xFF
101 value |= priority << shift;
102 GIC_REG_WRITE(addr, value);
103}
104
105// 设置中断号为interrupt的中断的属性为config
106OS_SEC_L4_TEXT void OsGicIntSetConfig(uint32_t interrupt, uint32_t config) {
107 uint32_t shift = (interrupt % GICD_ICFGR_SIZE) * GICD_ICFGR_BITS;
108 volatile uint32_t* addr = ((volatile U32 *)(uintptr_t)(GICD_ICFGR + (interrupt / GICD_ICFGR_SIZE)*sizeof(U32)));
109 uint32_t value = GIC_REG_READ(addr);
110 value &= ~(0x03 << shift);
111 value |= config << shift;
112 GIC_REG_WRITE(addr, value);
113}
114
115/*
116* 描述: 中断确认
117*/
118OS_SEC_L4_TEXT U32 OsGicIntAcknowledge(void)
119{
120 // reads this register to obtain the interrupt ID of the signaled interrupt.
121 // This read acts as an acknowledge for the interrupt.
122 U32 value = GIC_REG_READ(GICC_IAR);
123 return value;
124}
125
126/*
127* 描述: 标记中断完成,清除相应中断位
128*/
129OS_SEC_L4_TEXT void OsGicIntClear(U32 value)
130{
131 // A processor writes to this register to inform the CPU interface either:
132 // • that it has completed the processing of the specified interrupt
133 // • in a GICv2 implementation, when the appropriate GICC_CTLR.EOImode bit is set to 1, to indicate that the interface should perform priority drop for the specified interrupt.
134 GIC_REG_WRITE(GICC_EOIR, value);
135}
136
137U32 OsHwiInit(void)
138{
139
140 // 初始化Gicv2的distributor和cpu interface
141 // 禁用distributor和cpu interface后进行相应配置
142 GIC_REG_WRITE(GICD_CTLR, GICD_CTLR_DISABLE);
143 GIC_REG_WRITE(GICC_CTLR, GICC_CTLR_DISABLE);
144 GIC_REG_WRITE(GICC_PMR, GICC_PMR_PRIO_LOW);
145 GIC_REG_WRITE(GICC_BPR, GICC_BPR_NO_GROUP);
146
147
148 // 启用distributor和cpu interface
149 GIC_REG_WRITE(GICD_CTLR, GICD_CTLR_ENABLE);
150 GIC_REG_WRITE(GICC_CTLR, GICC_CTLR_ENABLE);
151
152 return OS_OK;
153}
在 hwi_init.c 中 OsHwiInit 函数实现 GIC 的初始化,此外还提供了其他函数实现开关指定中断、设置中断属性、确认中断和标记中断完成等功能。
注意
你需要参照 OsGicIntSetPriority 等函数实现 OsGicEnableInt 和 OsGicDisableInt 函数。
使能时钟中断
新建 src/include/prt_config.h
1/* Tick中断时间间隔,tick处理时间不能超过1/OS_TICK_PER_SECOND(s) */
2#define OS_TICK_PER_SECOND 1000
新建 src/include/os_cpu_armv8.h。
1#ifndef OS_CPU_ARMV8_H
2#define OS_CPU_ARMV8_H
3
4#include "prt_typedef.h"
5
6// CurrentEl等级
7#define CURRENT_EL_2 0x8
8#define CURRENT_EL_1 0x4
9#define CURRENT_EL_0 0x0
10
11#define DAIF_DBG_BIT (1U << 3)
12#define DAIF_ABT_BIT (1U << 2)
13#define DAIF_IRQ_BIT (1U << 1)
14#define DAIF_FIQ_BIT (1U << 0)
15
16#define INT_MASK (1U << 7)
17
18#define PRT_DSB() OS_EMBED_ASM("DSB sy" : : : "memory")
19#define PRT_DMB() OS_EMBED_ASM("DMB sy" : : : "memory")
20#define PRT_ISB() OS_EMBED_ASM("ISB" : : : "memory")
21
22#endif /* OS_CPU_ARMV8_H */
新建 src/bsp/timer.c 文件,对定时器和对应的中断进行配置
1#include "prt_typedef.h"
2#include "prt_config.h"
3#include "os_cpu_armv8.h"
4
5U64 g_timerFrequency;
6extern void OsGicIntSetConfig(uint32_t interrupt, uint32_t config);
7extern void OsGicIntSetPriority(uint32_t interrupt, uint32_t priority);
8extern void OsGicEnableInt(U32 intId);
9extern void OsGicClearIntPending(uint32_t interrupt);
10
11void CoreTimerInit(void)
12{
13 // 配置中断控制器
14 OsGicIntSetConfig(30, 0); // 配置为电平触发
15 OsGicIntSetPriority(30, 0); // 优先级为0
16 OsGicClearIntPending(30); // 清除中断pending
17 OsGicEnableInt(30); // 启用中断
18
19 // 配置定时器
20 OS_EMBED_ASM("MRS %0, CNTFRQ_EL0" : "=r"(g_timerFrequency) : : "memory", "cc"); //读取时钟频率
21
22 U32 cfgMask = 0x0;
23 U64 cycle = g_timerFrequency / OS_TICK_PER_SECOND;
24
25 OS_EMBED_ASM("MSR CNTP_CTL_EL0, %0" : : "r"(cfgMask) : "memory");
26 PRT_ISB();
27 OS_EMBED_ASM("MSR CNTP_TVAL_EL0, %0" : : "r"(cycle) : "memory", "cc"); //设置中断周期
28
29 cfgMask = 0x1;
30 OS_EMBED_ASM("MSR CNTP_CTL_EL0, %0" : : "r"(cfgMask) : "memory"); //启用定时器 enable=1, imask=0, istatus= 0,
31 OS_EMBED_ASM("MSR DAIFCLR, #2");
32}
时钟中断处理
将 prt_vector.S 中的 EXC_HANDLE 5 OsExcDispatch 改为 EXC_HANDLE 5 OsHwiDispatcher,表明我们将对 IRQ 类型的异常(即中断)使用 OsHwiDispatcher 处理。
提示
需修改为 EXC_HANDLE 5 OsHwiDispatcher ,否则还是 OsExcDispatch 函数处理,仅会输出 “Catch a exception.” 信息
在 prt_vector.S 中加入 OsHwiDispatcher 处理代码,其类似于之前的 OsExcDispatch ,因此不再说明。
1 .globl OsHwiDispatcher 2 .type OsHwiDispatcher, @function 3 .align 4 4OsHwiDispatcher: 5 mrs x5, esr_el1 6 mrs x4, far_el1 7 mrs x3, spsr_el1 8 mrs x2, elr_el1 9 stp x4, x5, [sp,#-16]! 10 stp x2, x3, [sp,#-16]! 11 12 mov x0, x1 // 异常类型0~15,参见异常向量表 13 mov x1, sp // 异常时寄存器信息,通过栈及其sp指针提供 14 bl OsHwiDispatch 15 16 ldp x2, x3, [sp],#16 17 add sp, sp, #16 // 跳过far, esr, HCR_EL2.TRVM==1的时候,EL1不能写far, esr 18 msr spsr_el1, x3 19 msr elr_el1, x2 20 dsb sy 21 isb 22 23 RESTORE_EXC_REGS // 恢复上下文 24 25 eret //从异常返回
在 prt_exc.c 中引用头文件 os_attr_armv8_external.h , os_cpu_armv8.h , OsHwiDispatch 处理 IRQ 类型的中断。
1extern void OsTickDispatcher(void); 2OS_SEC_ALW_INLINE INLINE void OsHwiHandleActive(U32 irqNum) 3{ 4 switch(irqNum){ 5 case 30: 6 OsTickDispatcher(); 7 // PRT_Printf("."); 8 break; 9 default: 10 break; 11 } 12} 13 14extern U32 OsGicIntAcknowledge(void); 15extern void OsGicIntClear(U32 value); 16// src/arch/cpu/armv8/common/hwi/prt_hwi.c OsHwiDispatch(),OsHwiDispatchHandle() 17/* 18* 描述: 中断处理入口, 调用处外部已关中断 19*/ 20OS_SEC_L0_TEXT void OsHwiDispatch( U32 excType, struct ExcRegInfo *excRegs) //src/arch/cpu/armv8/common/hwi/prt_hwi.c 21{ 22 // 中断确认,相当于OsHwiNumGet() 23 U32 value = OsGicIntAcknowledge(); 24 U32 irq_num = value & 0x1ff; 25 U32 core_num = value & 0xe00; 26 27 OsHwiHandleActive(irq_num); 28 29 // 清除中断,相当于 OsHwiClear(hwiNum); 30 OsGicIntClear(irq_num|core_num); 31}
src/bsp/os_attr_armv8_external.h 头文件可以在 此处 下载。
新建 src/kernel/tick/prt_tick.c 文件,提供 OsTickDispatcher 时钟中断处理函数。
1#include "os_attr_armv8_external.h" 2#include "prt_typedef.h" 3#include "prt_config.h" 4#include "os_cpu_armv8_external.h" 5 6extern U64 g_timerFrequency; 7 8/* Tick计数 */ 9OS_SEC_BSS U64 g_uniTicks; //src/core/kernel/sys/prt_sys.c 10 11/* 12* 描述:Tick中断的处理函数。扫描任务超时链表、扫描超时软件定时器、扫描TSKMON等。 13*/ 14OS_SEC_TEXT void OsTickDispatcher(void) 15{ 16 uintptr_t intSave; 17 18 intSave = OsIntLock(); 19 g_uniTicks++; 20 OsIntRestore(intSave); 21 22 U64 cycle = g_timerFrequency / OS_TICK_PER_SECOND; 23 OS_EMBED_ASM("MSR CNTP_TVAL_EL0, %0" : : "r"(cycle) : "memory", "cc"); //设置中断周期 24 25} 26 27/* 28* 描述:获取当前的tick计数 29*/ 30OS_SEC_L2_TEXT U64 PRT_TickGetCount(void) //src/core/kernel/sys/prt_sys_time.c 31{ 32 return g_uniTicks; 33}
注意需将 hwi_init.c timer.c prt_tick.c 等文件加入构建系统。
提示
src/kernel, src/kernel/tick 目录下均需加入 CMakeLists.txt, src/ 和 src/bsp/ 下的 CMakeLists.txt 需修改。其中,
src/kernel/tick/CMakeLists.txt 类似 src/bsp/CMakeLists.txt
src/kernel/CMakeLists.txt 内容为: add_subdirectory(tick)
src/CMakeLists.txt 需修改增加include目录、包含子目录和编译目标:
... ... include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/include # 增加 src/include 目录 ${CMAKE_CURRENT_SOURCE_DIR}/bsp ) add_subdirectory(bsp) add_subdirectory(kernel) # 增加 kernel 子目录 list(APPEND OBJS $<TARGET_OBJECTS:bsp> $<TARGET_OBJECTS:tick>) # 增加 $<TARGET_OBJECTS:tick> 目标 add_executable(${APP} main.c ${OBJS})
后续实验中若新增文件加入构建系统不再赘述,请参照此处。
在 OsTickDispatcher 中调用了 OsIntLock 和 OsIntRestore 函数,这两个函数用于关中断和开中断。简单起见,将其放入 prt_exc.c 中。
1/* 2* 描述: 开启全局可屏蔽中断。 3*/ 4OS_SEC_L0_TEXT uintptr_t PRT_HwiUnLock(void) //src/arch/cpu/armv8/common/hwi/prt_hwi.c 5{ 6 uintptr_t state = 0; 7 8 OS_EMBED_ASM( 9 "mrs %0, DAIF \n" 10 "msr DAIFClr, %1 \n" 11 : "=r"(state) 12 : "i"(DAIF_IRQ_BIT) 13 : "memory", "cc"); 14 15 return state & INT_MASK; 16} 17 18/* 19* 描述: 关闭全局可屏蔽中断。 20*/ 21OS_SEC_L0_TEXT uintptr_t PRT_HwiLock(void) //src/arch/cpu/armv8/common/hwi/prt_hwi.c 22{ 23 uintptr_t state = 0; 24 OS_EMBED_ASM( 25 "mrs %0, DAIF \n" 26 "msr DAIFSet, %1 \n" 27 : "=r"(state) 28 : "i"(DAIF_IRQ_BIT) 29 : "memory", "cc"); 30 return state & INT_MASK; 31} 32 33/* 34* 描述: 恢复原中断状态寄存器。 35*/ 36OS_SEC_L0_TEXT void PRT_HwiRestore(uintptr_t intSave) //src/arch/cpu/armv8/common/hwi/prt_hwi.c 37{ 38 if ((intSave & INT_MASK) == 0) { 39 OS_EMBED_ASM( 40 "msr DAIFClr, %0\n" 41 : 42 : "i"(DAIF_IRQ_BIT) 43 : "memory", "cc"); 44 } else { 45 OS_EMBED_ASM( 46 "msr DAIFSet, %0\n" 47 : 48 : "i"(DAIF_IRQ_BIT) 49 : "memory", "cc"); 50 } 51 return; 52}
头文件 src/bsp/os_cpu_armv8_external.h
1#ifndef OS_CPU_ARMV8_EXTERNAL_H 2#define OS_CPU_ARMV8_EXTERNAL_H 3 4extern uintptr_t PRT_HwiUnLock(void); 5extern uintptr_t PRT_HwiLock(void); 6extern void PRT_HwiRestore(uintptr_t intSave); 7 8#define OsIntUnLock() PRT_HwiUnLock() 9#define OsIntLock() PRT_HwiLock() 10#define OsIntRestore(intSave) PRT_HwiRestore(intSave) 11 12#endif
读取系统Tick值
新建 prt_tick.h,声明 Tick 相关的接口函数.
1#ifndef PRT_TICK_H
2#define PRT_TICK_H
3
4#include "prt_typedef.h"
5
6extern U64 PRT_TickGetCount(void);
7
8#endif /* PRT_TICK_H */
main.c 修改为:
1#include "prt_typedef.h"
2#include "prt_tick.h"
3
4extern U32 PRT_Printf(const char *format, ...);
5extern void PRT_UartInit(void);
6extern void CoreTimerInit(void);
7extern U32 OsHwiInit(void);
8
9U64 delay_time = 10000;
10
11S32 main(void)
12{
13 // 初始化GIC
14 OsHwiInit();
15 // 启用Timer
16 CoreTimerInit();
17
18 PRT_UartInit();
19
20 PRT_Printf(" _ _ _____ _ _ _ _ _ _ _ _ \n");
21 PRT_Printf(" _ __ ___ (_)_ __ (_) ____| _| | ___ _ __ | |__ _ _ | | | | \\ | | | | | ___ _ __ \n");
22 PRT_Printf(" | '_ ` _ \\| | '_ \\| | _|| | | | |/ _ \\ '__| | '_ \\| | | | | |_| | \\| | | | |/ _ \\ '__|\n");
23 PRT_Printf(" | | | | | | | | | | | |__| |_| | | __/ | | |_) | |_| | | _ | |\\ | |_| | __/ | \n");
24 PRT_Printf(" |_| |_| |_|_|_| |_|_|_____\\__,_|_|\\___|_| |_.__/ \\__, | |_| |_|_| \\_|\\___/ \\___|_| \n");
25 PRT_Printf(" |___/ \n");
26
27 PRT_Printf("ctr-a h: print help of qemu emulator. ctr-a x: quit emulator.\n\n");
28
29 for(int i = 0; i < 10; i++)
30 {
31
32 U32 tick = PRT_TickGetCount();
33 PRT_Printf("[%d] current tick: %u\n", i, tick);
34
35 //delay
36 int delay_time = 10000000; // 根据自己机器计算能力不同调整该值
37 while(delay_time>0){
38 PRT_TickGetCount(); //消耗时间,防止延时代码被编译器优化
39 delay_time--;
40 }
41
42 }
43
44 while(1);
45 return 0;
46
47}
lab5 作业
作业1
实现 hwi_init.c 中缺失的 OsGicEnableInt 和 OsGicDisableInt 函数。
- 1
https://developer.arm.com/documentation/den0024/a/Fundamentals-of-ARMv8/Execution-states
- 2
- 3
https://developer.arm.com/documentation/den0024/a/AArch64-Exception-Handling/AArch64-exception-table
- 4
- 5
https://www.ic.unicamp.br/~celio/mc404-2014/docs/gnu-arm-directives.pdf
- 6
- 7
https://doc.rust-lang.org/reference/inline-assembly.html#register-operands
- 8