RTC 驱动程序

QEMU aarch64 虚拟机在 0x9010000 地址处 配备了 PL031 实时时钟。对于本练习,应该为其编写驱动程序。

  1. 使用该时钟可将当前时间输出到串行控制台。您可以使用 chrono crate 设置日期/时间格式。
  2. 通过匹配寄存器和原始中断状态,使得系统在某段指定的时间内一直进行繁忙等待(例如 3 秒后)。(在循环操作中调用 core::hint::spin_loop。)
  3. _进行扩展(如有时间):_启用并处理由 RTC 匹配产生的中断。可以使用 arm-gic crate 中提供的驱动程序来配置 Arm 通用中断控制器。
    • 请使用 RTC 中断,将其作为 IntId::spi(2) 连接到 GIC。
    • 启用中断后,可以通过 arm_gic::wfi() 让核心进入休眠状态,直到它收到中断信号。

下载 练习模板 并在 rtc 目录中查找以下文件。

src/main.rs:

  1. #![no_main]
  2. #![no_std]
  3. mod exceptions;
  4. mod logger;
  5. mod pl011;
  6. use crate::pl011::Uart;
  7. use arm_gic::gicv3::GicV3;
  8. use core::panic::PanicInfo;
  9. use log::{error, info, trace, LevelFilter};
  10. use smccc::psci::system_off;
  11. use smccc::Hvc;
  12. /// Base addresses of the GICv3.
  13. const GICD_BASE_ADDRESS: *mut u64 = 0x800_0000 as _;
  14. const GICR_BASE_ADDRESS: *mut u64 = 0x80A_0000 as _;
  15. /// Base address of the primary PL011 UART.
  16. const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;
  17. #[no_mangle]
  18. extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
  19. // SAFETY: `PL011_BASE_ADDRESS` is the base address of a PL011 device, and
  20. // nothing else accesses that address range.
  21. let uart = unsafe { Uart::new(PL011_BASE_ADDRESS) };
  22. logger::init(uart, LevelFilter::Trace).unwrap();
  23. info!("main({:#x}, {:#x}, {:#x}, {:#x})", x0, x1, x2, x3);
  24. // SAFETY: `GICD_BASE_ADDRESS` and `GICR_BASE_ADDRESS` are the base
  25. // addresses of a GICv3 distributor and redistributor respectively, and
  26. // nothing else accesses those address ranges.
  27. let mut gic = unsafe { GicV3::new(GICD_BASE_ADDRESS, GICR_BASE_ADDRESS) };
  28. gic.setup();
  29. // TODO: Create instance of RTC driver and print current time.
  30. // TODO: Wait for 3 seconds.
  31. system_off::<Hvc>().unwrap();
  32. }
  33. #[panic_handler]
  34. fn panic(info: &PanicInfo) -> ! {
  35. error!("{info}");
  36. system_off::<Hvc>().unwrap();
  37. loop {}
  38. }

src/exceptions.rs(只需在本练习的第 3 部分更改此项):

  1. #![allow(unused)]
  2. fn main() {
  3. // Copyright 2023 Google LLC
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. use arm_gic::gicv3::GicV3;
  17. use log::{error, info, trace};
  18. use smccc::psci::system_off;
  19. use smccc::Hvc;
  20. #[no_mangle]
  21. extern "C" fn sync_exception_current(_elr: u64, _spsr: u64) {
  22. error!("sync_exception_current");
  23. system_off::<Hvc>().unwrap();
  24. }
  25. #[no_mangle]
  26. extern "C" fn irq_current(_elr: u64, _spsr: u64) {
  27. trace!("irq_current");
  28. let intid =
  29. GicV3::get_and_acknowledge_interrupt().expect("No pending interrupt");
  30. info!("IRQ {intid:?}");
  31. }
  32. #[no_mangle]
  33. extern "C" fn fiq_current(_elr: u64, _spsr: u64) {
  34. error!("fiq_current");
  35. system_off::<Hvc>().unwrap();
  36. }
  37. #[no_mangle]
  38. extern "C" fn serr_current(_elr: u64, _spsr: u64) {
  39. error!("serr_current");
  40. system_off::<Hvc>().unwrap();
  41. }
  42. #[no_mangle]
  43. extern "C" fn sync_lower(_elr: u64, _spsr: u64) {
  44. error!("sync_lower");
  45. system_off::<Hvc>().unwrap();
  46. }
  47. #[no_mangle]
  48. extern "C" fn irq_lower(_elr: u64, _spsr: u64) {
  49. error!("irq_lower");
  50. system_off::<Hvc>().unwrap();
  51. }
  52. #[no_mangle]
  53. extern "C" fn fiq_lower(_elr: u64, _spsr: u64) {
  54. error!("fiq_lower");
  55. system_off::<Hvc>().unwrap();
  56. }
  57. #[no_mangle]
  58. extern "C" fn serr_lower(_elr: u64, _spsr: u64) {
  59. error!("serr_lower");
  60. system_off::<Hvc>().unwrap();
  61. }
  62. }

src/logger.rs(无需对此进行更改):

  1. #![allow(unused)]
  2. fn main() {
  3. // Copyright 2023 Google LLC
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. // ANCHOR: main
  17. use crate::pl011::Uart;
  18. use core::fmt::Write;
  19. use log::{LevelFilter, Log, Metadata, Record, SetLoggerError};
  20. use spin::mutex::SpinMutex;
  21. static LOGGER: Logger = Logger { uart: SpinMutex::new(None) };
  22. struct Logger {
  23. uart: SpinMutex<Option<Uart>>,
  24. }
  25. impl Log for Logger {
  26. fn enabled(&self, _metadata: &Metadata) -> bool {
  27. true
  28. }
  29. fn log(&self, record: &Record) {
  30. writeln!(
  31. self.uart.lock().as_mut().unwrap(),
  32. "[{}] {}",
  33. record.level(),
  34. record.args()
  35. )
  36. .unwrap();
  37. }
  38. fn flush(&self) {}
  39. }
  40. /// Initialises UART logger.
  41. pub fn init(uart: Uart, max_level: LevelFilter) -> Result<(), SetLoggerError> {
  42. LOGGER.uart.lock().replace(uart);
  43. log::set_logger(&LOGGER)?;
  44. log::set_max_level(max_level);
  45. Ok(())
  46. }
  47. }

src/pl011.rs(无需对此进行更改):

  1. #![allow(unused)]
  2. fn main() {
  3. // Copyright 2023 Google LLC
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. #![allow(unused)]
  17. use core::fmt::{self, Write};
  18. use core::ptr::{addr_of, addr_of_mut};
  19. // ANCHOR: Flags
  20. use bitflags::bitflags;
  21. bitflags! {
  22. /// Flags from the UART flag register.
  23. #[repr(transparent)]
  24. #[derive(Copy, Clone, Debug, Eq, PartialEq)]
  25. struct Flags: u16 {
  26. /// Clear to send.
  27. const CTS = 1 << 0;
  28. /// Data set ready.
  29. const DSR = 1 << 1;
  30. /// Data carrier detect.
  31. const DCD = 1 << 2;
  32. /// UART busy transmitting data.
  33. const BUSY = 1 << 3;
  34. /// Receive FIFO is empty.
  35. const RXFE = 1 << 4;
  36. /// Transmit FIFO is full.
  37. const TXFF = 1 << 5;
  38. /// Receive FIFO is full.
  39. const RXFF = 1 << 6;
  40. /// Transmit FIFO is empty.
  41. const TXFE = 1 << 7;
  42. /// Ring indicator.
  43. const RI = 1 << 8;
  44. }
  45. }
  46. // ANCHOR_END: Flags
  47. bitflags! {
  48. /// Flags from the UART Receive Status Register / Error Clear Register.
  49. #[repr(transparent)]
  50. #[derive(Copy, Clone, Debug, Eq, PartialEq)]
  51. struct ReceiveStatus: u16 {
  52. /// Framing error.
  53. const FE = 1 << 0;
  54. /// Parity error.
  55. const PE = 1 << 1;
  56. /// Break error.
  57. const BE = 1 << 2;
  58. /// Overrun error.
  59. const OE = 1 << 3;
  60. }
  61. }
  62. // ANCHOR: Registers
  63. #[repr(C, align(4))]
  64. struct Registers {
  65. dr: u16,
  66. _reserved0: [u8; 2],
  67. rsr: ReceiveStatus,
  68. _reserved1: [u8; 19],
  69. fr: Flags,
  70. _reserved2: [u8; 6],
  71. ilpr: u8,
  72. _reserved3: [u8; 3],
  73. ibrd: u16,
  74. _reserved4: [u8; 2],
  75. fbrd: u8,
  76. _reserved5: [u8; 3],
  77. lcr_h: u8,
  78. _reserved6: [u8; 3],
  79. cr: u16,
  80. _reserved7: [u8; 3],
  81. ifls: u8,
  82. _reserved8: [u8; 3],
  83. imsc: u16,
  84. _reserved9: [u8; 2],
  85. ris: u16,
  86. _reserved10: [u8; 2],
  87. mis: u16,
  88. _reserved11: [u8; 2],
  89. icr: u16,
  90. _reserved12: [u8; 2],
  91. dmacr: u8,
  92. _reserved13: [u8; 3],
  93. }
  94. // ANCHOR_END: Registers
  95. // ANCHOR: Uart
  96. /// Driver for a PL011 UART.
  97. #[derive(Debug)]
  98. pub struct Uart {
  99. registers: *mut Registers,
  100. }
  101. impl Uart {
  102. /// Constructs a new instance of the UART driver for a PL011 device at the
  103. /// given base address.
  104. ///
  105. /// # Safety
  106. ///
  107. /// The given base address must point to the MMIO control registers of a
  108. /// PL011 device, which must be mapped into the address space of the process
  109. /// as device memory and not have any other aliases.
  110. pub unsafe fn new(base_address: *mut u32) -> Self {
  111. Self { registers: base_address as *mut Registers }
  112. }
  113. /// Writes a single byte to the UART.
  114. pub fn write_byte(&self, byte: u8) {
  115. // Wait until there is room in the TX buffer.
  116. while self.read_flag_register().contains(Flags::TXFF) {}
  117. // SAFETY: We know that self.registers points to the control registers
  118. // of a PL011 device which is appropriately mapped.
  119. unsafe {
  120. // Write to the TX buffer.
  121. addr_of_mut!((*self.registers).dr).write_volatile(byte.into());
  122. }
  123. // Wait until the UART is no longer busy.
  124. while self.read_flag_register().contains(Flags::BUSY) {}
  125. }
  126. /// Reads and returns a pending byte, or `None` if nothing has been
  127. /// received.
  128. pub fn read_byte(&self) -> Option<u8> {
  129. if self.read_flag_register().contains(Flags::RXFE) {
  130. None
  131. } else {
  132. // SAFETY: We know that self.registers points to the control
  133. // registers of a PL011 device which is appropriately mapped.
  134. let data = unsafe { addr_of!((*self.registers).dr).read_volatile() };
  135. // TODO: Check for error conditions in bits 8-11.
  136. Some(data as u8)
  137. }
  138. }
  139. fn read_flag_register(&self) -> Flags {
  140. // SAFETY: We know that self.registers points to the control registers
  141. // of a PL011 device which is appropriately mapped.
  142. unsafe { addr_of!((*self.registers).fr).read_volatile() }
  143. }
  144. }
  145. // ANCHOR_END: Uart
  146. impl Write for Uart {
  147. fn write_str(&mut self, s: &str) -> fmt::Result {
  148. for c in s.as_bytes() {
  149. self.write_byte(*c);
  150. }
  151. Ok(())
  152. }
  153. }
  154. // Safe because it just contains a pointer to device memory, which can be
  155. // accessed from any context.
  156. unsafe impl Send for Uart {}
  157. }

Cargo.toml(无需对此进行更改):

  1. [workspace]
  2. [package]
  3. name = "rtc"
  4. version = "0.1.0"
  5. edition = "2021"
  6. publish = false
  7. [dependencies]
  8. arm-gic = "0.1.0"
  9. bitflags = "2.5.0"
  10. chrono = { version = "0.4.37", default-features = false }
  11. log = "0.4.21"
  12. smccc = "0.1.1"
  13. spin = "0.9.8"
  14. [build-dependencies]
  15. cc = "1.0.94"

build.rs(无需对此进行更改):

  1. // Copyright 2023 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. use cc::Build;
  15. use std::env;
  16. fn main() {
  17. #[cfg(target_os = "linux")]
  18. env::set_var("CROSS_COMPILE", "aarch64-linux-gnu");
  19. #[cfg(not(target_os = "linux"))]
  20. env::set_var("CROSS_COMPILE", "aarch64-none-elf");
  21. Build::new()
  22. .file("entry.S")
  23. .file("exceptions.S")
  24. .file("idmap.S")
  25. .compile("empty")
  26. }

entry.S(无需对此进行更改):

  1. /*
  2. * Copyright 2023 Google LLC
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * https://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. .macro adr_l, reg:req, sym:req
  17. adrp \reg, \sym
  18. add \reg, \reg, :lo12:\sym
  19. .endm
  20. .macro mov_i, reg:req, imm:req
  21. movz \reg, :abs_g3:\imm
  22. movk \reg, :abs_g2_nc:\imm
  23. movk \reg, :abs_g1_nc:\imm
  24. movk \reg, :abs_g0_nc:\imm
  25. .endm
  26. .set .L_MAIR_DEV_nGnRE, 0x04
  27. .set .L_MAIR_MEM_WBWA, 0xff
  28. .set .Lmairval, .L_MAIR_DEV_nGnRE | (.L_MAIR_MEM_WBWA << 8)
  29. /* 4 KiB granule size for TTBR0_EL1. */
  30. .set .L_TCR_TG0_4KB, 0x0 << 14
  31. /* 4 KiB granule size for TTBR1_EL1. */
  32. .set .L_TCR_TG1_4KB, 0x2 << 30
  33. /* Disable translation table walk for TTBR1_EL1, generating a translation fault instead. */
  34. .set .L_TCR_EPD1, 0x1 << 23
  35. /* Translation table walks for TTBR0_EL1 are inner sharable. */
  36. .set .L_TCR_SH_INNER, 0x3 << 12
  37. /*
  38. * Translation table walks for TTBR0_EL1 are outer write-back read-allocate write-allocate
  39. * cacheable.
  40. */
  41. .set .L_TCR_RGN_OWB, 0x1 << 10
  42. /*
  43. * Translation table walks for TTBR0_EL1 are inner write-back read-allocate write-allocate
  44. * cacheable.
  45. */
  46. .set .L_TCR_RGN_IWB, 0x1 << 8
  47. /* Size offset for TTBR0_EL1 is 2**39 bytes (512 GiB). */
  48. .set .L_TCR_T0SZ_512, 64 - 39
  49. .set .Ltcrval, .L_TCR_TG0_4KB | .L_TCR_TG1_4KB | .L_TCR_EPD1 | .L_TCR_RGN_OWB
  50. .set .Ltcrval, .Ltcrval | .L_TCR_RGN_IWB | .L_TCR_SH_INNER | .L_TCR_T0SZ_512
  51. /* Stage 1 instruction access cacheability is unaffected. */
  52. .set .L_SCTLR_ELx_I, 0x1 << 12
  53. /* SP alignment fault if SP is not aligned to a 16 byte boundary. */
  54. .set .L_SCTLR_ELx_SA, 0x1 << 3
  55. /* Stage 1 data access cacheability is unaffected. */
  56. .set .L_SCTLR_ELx_C, 0x1 << 2
  57. /* EL0 and EL1 stage 1 MMU enabled. */
  58. .set .L_SCTLR_ELx_M, 0x1 << 0
  59. /* Privileged Access Never is unchanged on taking an exception to EL1. */
  60. .set .L_SCTLR_EL1_SPAN, 0x1 << 23
  61. /* SETEND instruction disabled at EL0 in aarch32 mode. */
  62. .set .L_SCTLR_EL1_SED, 0x1 << 8
  63. /* Various IT instructions are disabled at EL0 in aarch32 mode. */
  64. .set .L_SCTLR_EL1_ITD, 0x1 << 7
  65. .set .L_SCTLR_EL1_RES1, (0x1 << 11) | (0x1 << 20) | (0x1 << 22) | (0x1 << 28) | (0x1 << 29)
  66. .set .Lsctlrval, .L_SCTLR_ELx_M | .L_SCTLR_ELx_C | .L_SCTLR_ELx_SA | .L_SCTLR_EL1_ITD | .L_SCTLR_EL1_SED
  67. .set .Lsctlrval, .Lsctlrval | .L_SCTLR_ELx_I | .L_SCTLR_EL1_SPAN | .L_SCTLR_EL1_RES1
  68. /**
  69. * This is a generic entry point for an image. It carries out the operations required to prepare the
  70. * loaded image to be run. Specifically, it zeroes the bss section using registers x25 and above,
  71. * prepares the stack, enables floating point, and sets up the exception vector. It preserves x0-x3
  72. * for the Rust entry point, as these may contain boot parameters.
  73. */
  74. .section .init.entry, "ax"
  75. .global entry
  76. entry:
  77. /* Load and apply the memory management configuration, ready to enable MMU and caches. */
  78. adrp x30, idmap
  79. msr ttbr0_el1, x30
  80. mov_i x30, .Lmairval
  81. msr mair_el1, x30
  82. mov_i x30, .Ltcrval
  83. /* Copy the supported PA range into TCR_EL1.IPS. */
  84. mrs x29, id_aa64mmfr0_el1
  85. bfi x30, x29, #32, #4
  86. msr tcr_el1, x30
  87. mov_i x30, .Lsctlrval
  88. /*
  89. * Ensure everything before this point has completed, then invalidate any potentially stale
  90. * local TLB entries before they start being used.
  91. */
  92. isb
  93. tlbi vmalle1
  94. ic iallu
  95. dsb nsh
  96. isb
  97. /*
  98. * Configure sctlr_el1 to enable MMU and cache and don't proceed until this has completed.
  99. */
  100. msr sctlr_el1, x30
  101. isb
  102. /* Disable trapping floating point access in EL1. */
  103. mrs x30, cpacr_el1
  104. orr x30, x30, #(0x3 << 20)
  105. msr cpacr_el1, x30
  106. isb
  107. /* Zero out the bss section. */
  108. adr_l x29, bss_begin
  109. adr_l x30, bss_end
  110. 0: cmp x29, x30
  111. b.hs 1f
  112. stp xzr, xzr, [x29], #16
  113. b 0b
  114. 1: /* Prepare the stack. */
  115. adr_l x30, boot_stack_end
  116. mov sp, x30
  117. /* Set up exception vector. */
  118. adr x30, vector_table_el1
  119. msr vbar_el1, x30
  120. /* Call into Rust code. */
  121. bl main
  122. /* Loop forever waiting for interrupts. */
  123. 2: wfi
  124. b 2b

exceptions.S(无需对此进行更改):

  1. /*
  2. * Copyright 2023 Google LLC
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * https://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /**
  17. * Saves the volatile registers onto the stack. This currently takes 14
  18. * instructions, so it can be used in exception handlers with 18 instructions
  19. * left.
  20. *
  21. * On return, x0 and x1 are initialised to elr_el2 and spsr_el2 respectively,
  22. * which can be used as the first and second arguments of a subsequent call.
  23. */
  24. .macro save_volatile_to_stack
  25. /* Reserve stack space and save registers x0-x18, x29 & x30. */
  26. stp x0, x1, [sp, #-(8 * 24)]!
  27. stp x2, x3, [sp, #8 * 2]
  28. stp x4, x5, [sp, #8 * 4]
  29. stp x6, x7, [sp, #8 * 6]
  30. stp x8, x9, [sp, #8 * 8]
  31. stp x10, x11, [sp, #8 * 10]
  32. stp x12, x13, [sp, #8 * 12]
  33. stp x14, x15, [sp, #8 * 14]
  34. stp x16, x17, [sp, #8 * 16]
  35. str x18, [sp, #8 * 18]
  36. stp x29, x30, [sp, #8 * 20]
  37. /*
  38. * Save elr_el1 & spsr_el1. This such that we can take nested exception
  39. * and still be able to unwind.
  40. */
  41. mrs x0, elr_el1
  42. mrs x1, spsr_el1
  43. stp x0, x1, [sp, #8 * 22]
  44. .endm
  45. /**
  46. * Restores the volatile registers from the stack. This currently takes 14
  47. * instructions, so it can be used in exception handlers while still leaving 18
  48. * instructions left; if paired with save_volatile_to_stack, there are 4
  49. * instructions to spare.
  50. */
  51. .macro restore_volatile_from_stack
  52. /* Restore registers x2-x18, x29 & x30. */
  53. ldp x2, x3, [sp, #8 * 2]
  54. ldp x4, x5, [sp, #8 * 4]
  55. ldp x6, x7, [sp, #8 * 6]
  56. ldp x8, x9, [sp, #8 * 8]
  57. ldp x10, x11, [sp, #8 * 10]
  58. ldp x12, x13, [sp, #8 * 12]
  59. ldp x14, x15, [sp, #8 * 14]
  60. ldp x16, x17, [sp, #8 * 16]
  61. ldr x18, [sp, #8 * 18]
  62. ldp x29, x30, [sp, #8 * 20]
  63. /* Restore registers elr_el1 & spsr_el1, using x0 & x1 as scratch. */
  64. ldp x0, x1, [sp, #8 * 22]
  65. msr elr_el1, x0
  66. msr spsr_el1, x1
  67. /* Restore x0 & x1, and release stack space. */
  68. ldp x0, x1, [sp], #8 * 24
  69. .endm
  70. /**
  71. * This is a generic handler for exceptions taken at the current EL while using
  72. * SP0. It behaves similarly to the SPx case by first switching to SPx, doing
  73. * the work, then switching back to SP0 before returning.
  74. *
  75. * Switching to SPx and calling the Rust handler takes 16 instructions. To
  76. * restore and return we need an additional 16 instructions, so we can implement
  77. * the whole handler within the allotted 32 instructions.
  78. */
  79. .macro current_exception_sp0 handler:req
  80. msr spsel, #1
  81. save_volatile_to_stack
  82. bl \handler
  83. restore_volatile_from_stack
  84. msr spsel, #0
  85. eret
  86. .endm
  87. /**
  88. * This is a generic handler for exceptions taken at the current EL while using
  89. * SPx. It saves volatile registers, calls the Rust handler, restores volatile
  90. * registers, then returns.
  91. *
  92. * This also works for exceptions taken from EL0, if we don't care about
  93. * non-volatile registers.
  94. *
  95. * Saving state and jumping to the Rust handler takes 15 instructions, and
  96. * restoring and returning also takes 15 instructions, so we can fit the whole
  97. * handler in 30 instructions, under the limit of 32.
  98. */
  99. .macro current_exception_spx handler:req
  100. save_volatile_to_stack
  101. bl \handler
  102. restore_volatile_from_stack
  103. eret
  104. .endm
  105. .section .text.vector_table_el1, "ax"
  106. .global vector_table_el1
  107. .balign 0x800
  108. vector_table_el1:
  109. sync_cur_sp0:
  110. current_exception_sp0 sync_exception_current
  111. .balign 0x80
  112. irq_cur_sp0:
  113. current_exception_sp0 irq_current
  114. .balign 0x80
  115. fiq_cur_sp0:
  116. current_exception_sp0 fiq_current
  117. .balign 0x80
  118. serr_cur_sp0:
  119. current_exception_sp0 serr_current
  120. .balign 0x80
  121. sync_cur_spx:
  122. current_exception_spx sync_exception_current
  123. .balign 0x80
  124. irq_cur_spx:
  125. current_exception_spx irq_current
  126. .balign 0x80
  127. fiq_cur_spx:
  128. current_exception_spx fiq_current
  129. .balign 0x80
  130. serr_cur_spx:
  131. current_exception_spx serr_current
  132. .balign 0x80
  133. sync_lower_64:
  134. current_exception_spx sync_lower
  135. .balign 0x80
  136. irq_lower_64:
  137. current_exception_spx irq_lower
  138. .balign 0x80
  139. fiq_lower_64:
  140. current_exception_spx fiq_lower
  141. .balign 0x80
  142. serr_lower_64:
  143. current_exception_spx serr_lower
  144. .balign 0x80
  145. sync_lower_32:
  146. current_exception_spx sync_lower
  147. .balign 0x80
  148. irq_lower_32:
  149. current_exception_spx irq_lower
  150. .balign 0x80
  151. fiq_lower_32:
  152. current_exception_spx fiq_lower
  153. .balign 0x80
  154. serr_lower_32:
  155. current_exception_spx serr_lower

idmap.S(无需对此进行更改)

  1. /*
  2. * Copyright 2023 Google LLC
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * https://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. .set .L_TT_TYPE_BLOCK, 0x1
  17. .set .L_TT_TYPE_PAGE, 0x3
  18. .set .L_TT_TYPE_TABLE, 0x3
  19. /* Access flag. */
  20. .set .L_TT_AF, 0x1 << 10
  21. /* Not global. */
  22. .set .L_TT_NG, 0x1 << 11
  23. .set .L_TT_XN, 0x3 << 53
  24. .set .L_TT_MT_DEV, 0x0 << 2 // MAIR #0 (DEV_nGnRE)
  25. .set .L_TT_MT_MEM, (0x1 << 2) | (0x3 << 8) // MAIR #1 (MEM_WBWA), inner shareable
  26. .set .L_BLOCK_DEV, .L_TT_TYPE_BLOCK | .L_TT_MT_DEV | .L_TT_AF | .L_TT_XN
  27. .set .L_BLOCK_MEM, .L_TT_TYPE_BLOCK | .L_TT_MT_MEM | .L_TT_AF | .L_TT_NG
  28. .section ".rodata.idmap", "a", %progbits
  29. .global idmap
  30. .align 12
  31. idmap:
  32. /* level 1 */
  33. .quad .L_BLOCK_DEV | 0x0 // 1 GiB of device mappings
  34. .quad .L_BLOCK_MEM | 0x40000000 // 1 GiB of DRAM
  35. .fill 254, 8, 0x0 // 254 GiB of unmapped VA space
  36. .quad .L_BLOCK_DEV | 0x4000000000 // 1 GiB of device mappings
  37. .fill 255, 8, 0x0 // 255 GiB of remaining VA space

image.ld(无需对此进行更改):

  1. /*
  2. * Copyright 2023 Google LLC
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * https://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * Code will start running at this symbol which is placed at the start of the
  18. * image.
  19. */
  20. ENTRY(entry)
  21. MEMORY
  22. {
  23. image : ORIGIN = 0x40080000, LENGTH = 2M
  24. }
  25. SECTIONS
  26. {
  27. /*
  28. * Collect together the code.
  29. */
  30. .init : ALIGN(4096) {
  31. text_begin = .;
  32. *(.init.entry)
  33. *(.init.*)
  34. } >image
  35. .text : {
  36. *(.text.*)
  37. } >image
  38. text_end = .;
  39. /*
  40. * Collect together read-only data.
  41. */
  42. .rodata : ALIGN(4096) {
  43. rodata_begin = .;
  44. *(.rodata.*)
  45. } >image
  46. .got : {
  47. *(.got)
  48. } >image
  49. rodata_end = .;
  50. /*
  51. * Collect together the read-write data including .bss at the end which
  52. * will be zero'd by the entry code.
  53. */
  54. .data : ALIGN(4096) {
  55. data_begin = .;
  56. *(.data.*)
  57. /*
  58. * The entry point code assumes that .data is a multiple of 32
  59. * bytes long.
  60. */
  61. . = ALIGN(32);
  62. data_end = .;
  63. } >image
  64. /* Everything beyond this point will not be included in the binary. */
  65. bin_end = .;
  66. /* The entry point code assumes that .bss is 16-byte aligned. */
  67. .bss : ALIGN(16) {
  68. bss_begin = .;
  69. *(.bss.*)
  70. *(COMMON)
  71. . = ALIGN(16);
  72. bss_end = .;
  73. } >image
  74. .stack (NOLOAD) : ALIGN(4096) {
  75. boot_stack_begin = .;
  76. . += 40 * 4096;
  77. . = ALIGN(4096);
  78. boot_stack_end = .;
  79. } >image
  80. . = ALIGN(4K);
  81. PROVIDE(dma_region = .);
  82. /*
  83. * Remove unused sections from the image.
  84. */
  85. /DISCARD/ : {
  86. /* The image loads itself so doesn't need these sections. */
  87. *(.gnu.hash)
  88. *(.hash)
  89. *(.interp)
  90. *(.eh_frame_hdr)
  91. *(.eh_frame)
  92. *(.note.gnu.build-id)
  93. }
  94. }

Makefile(无需对此进行更改):

  1. # Copyright 2023 Google LLC
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. UNAME := $(shell uname -s)
  15. ifeq ($(UNAME),Linux)
  16. TARGET = aarch64-linux-gnu
  17. else
  18. TARGET = aarch64-none-elf
  19. endif
  20. OBJCOPY = $(TARGET)-objcopy
  21. .PHONY: build qemu_minimal qemu qemu_logger
  22. all: rtc.bin
  23. build:
  24. cargo build
  25. rtc.bin: build
  26. $(OBJCOPY) -O binary target/aarch64-unknown-none/debug/rtc $@
  27. qemu: rtc.bin
  28. qemu-system-aarch64 -machine virt,gic-version=3 -cpu max -serial mon:stdio -display none -kernel $< -s
  29. clean:
  30. cargo clean
  31. rm -f *.bin

.cargo/config.toml(无需对此进行更改):

  1. [build]
  2. target = "aarch64-unknown-none"
  3. rustflags = ["-C", "link-arg=-Timage.ld"]

使用 make qemu 在 QEMU 中运行代码。