mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-04-21 07:27:01 +02:00
Start on AP UART driver example.
This commit is contained in:
parent
76ad4b2939
commit
7eee892195
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,4 +3,4 @@ target/
|
|||||||
po/messages.pot
|
po/messages.pot
|
||||||
po/*.mo
|
po/*.mo
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
*.bin
|
||||||
|
@ -257,7 +257,8 @@
|
|||||||
|
|
||||||
- [Application processors](bare-metal/aps.md)
|
- [Application processors](bare-metal/aps.md)
|
||||||
- [MMIO](bare-metal/aps/mmio.md)
|
- [MMIO](bare-metal/aps/mmio.md)
|
||||||
- [Let's write a UART driver]()
|
- [Let's write a UART driver](bare-metal/aps/uart.md)
|
||||||
|
- [More traits](bare-metal/aps/uart/traits.md)
|
||||||
- [Logging]()
|
- [Logging]()
|
||||||
- [Other projects](bare-metal/aps/other-projects.md)
|
- [Other projects](bare-metal/aps/other-projects.md)
|
||||||
- [Useful crates]()
|
- [Useful crates]()
|
||||||
|
3
src/bare-metal/aps/examples/.cargo/config.toml
Normal file
3
src/bare-metal/aps/examples/.cargo/config.toml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[build]
|
||||||
|
target = "aarch64-unknown-none"
|
||||||
|
rustflags = ["-C", "link-arg=-Timage.ld"]
|
71
src/bare-metal/aps/examples/Cargo.lock
generated
Normal file
71
src/bare-metal/aps/examples/Cargo.lock
generated
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ap-examples"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"log",
|
||||||
|
"psci",
|
||||||
|
"spin",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.79"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "psci"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3374e3ae47f134467227a48be93b929e5d304efcd25ce5d176006403ca1d9bab"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7dccf47db1b41fa1573ed27ccf5e08e3ca771cb994f776668c5ebda893b248fc"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
]
|
14
src/bare-metal/aps/examples/Cargo.toml
Normal file
14
src/bare-metal/aps/examples/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[workspace]
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "ap-examples"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4.17"
|
||||||
|
psci = "0.1.1"
|
||||||
|
spin = "0.9.4"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cc = "1.0.73"
|
24
src/bare-metal/aps/examples/Makefile
Normal file
24
src/bare-metal/aps/examples/Makefile
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Copyright 2023 Google LLC
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
.PHONY: build qemu
|
||||||
|
|
||||||
|
build:
|
||||||
|
cargo build
|
||||||
|
|
||||||
|
ap-examples.bin: build
|
||||||
|
aarch64-linux-gnu-objcopy -O binary target/aarch64-unknown-none/debug/ap-examples ap-examples.bin
|
||||||
|
|
||||||
|
qemu: ap-examples.bin
|
||||||
|
qemu-system-aarch64 -machine virt -cpu max -serial mon:stdio -display none -kernel ap-examples.bin -s
|
25
src/bare-metal/aps/examples/build.rs
Normal file
25
src/bare-metal/aps/examples/build.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2023 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
use cc::Build;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
env::set_var("CROSS_COMPILE", "aarch64-linux-gnu");
|
||||||
|
Build::new()
|
||||||
|
.file("entry.S")
|
||||||
|
.file("exceptions.S")
|
||||||
|
.file("idmap.S")
|
||||||
|
.compile("empty")
|
||||||
|
}
|
142
src/bare-metal/aps/examples/entry.S
Normal file
142
src/bare-metal/aps/examples/entry.S
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Google LLC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.macro adr_l, reg:req, sym:req
|
||||||
|
adrp \reg, \sym
|
||||||
|
add \reg, \reg, :lo12:\sym
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro mov_i, reg:req, imm:req
|
||||||
|
movz \reg, :abs_g3:\imm
|
||||||
|
movk \reg, :abs_g2_nc:\imm
|
||||||
|
movk \reg, :abs_g1_nc:\imm
|
||||||
|
movk \reg, :abs_g0_nc:\imm
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.set .L_MAIR_DEV_nGnRE, 0x04
|
||||||
|
.set .L_MAIR_MEM_WBWA, 0xff
|
||||||
|
.set .Lmairval, .L_MAIR_DEV_nGnRE | (.L_MAIR_MEM_WBWA << 8)
|
||||||
|
|
||||||
|
/* 4 KiB granule size for TTBR0_EL1. */
|
||||||
|
.set .L_TCR_TG0_4KB, 0x0 << 14
|
||||||
|
/* 4 KiB granule size for TTBR1_EL1. */
|
||||||
|
.set .L_TCR_TG1_4KB, 0x2 << 30
|
||||||
|
/* Disable translation table walk for TTBR1_EL1, generating a translation fault instead. */
|
||||||
|
.set .L_TCR_EPD1, 0x1 << 23
|
||||||
|
/* Translation table walks for TTBR0_EL1 are inner sharable. */
|
||||||
|
.set .L_TCR_SH_INNER, 0x3 << 12
|
||||||
|
/*
|
||||||
|
* Translation table walks for TTBR0_EL1 are outer write-back read-allocate write-allocate
|
||||||
|
* cacheable.
|
||||||
|
*/
|
||||||
|
.set .L_TCR_RGN_OWB, 0x1 << 10
|
||||||
|
/*
|
||||||
|
* Translation table walks for TTBR0_EL1 are inner write-back read-allocate write-allocate
|
||||||
|
* cacheable.
|
||||||
|
*/
|
||||||
|
.set .L_TCR_RGN_IWB, 0x1 << 8
|
||||||
|
/* Size offset for TTBR0_EL1 is 2**39 bytes (512 GiB). */
|
||||||
|
.set .L_TCR_T0SZ_512, 64 - 39
|
||||||
|
.set .Ltcrval, .L_TCR_TG0_4KB | .L_TCR_TG1_4KB | .L_TCR_EPD1 | .L_TCR_RGN_OWB
|
||||||
|
.set .Ltcrval, .Ltcrval | .L_TCR_RGN_IWB | .L_TCR_SH_INNER | .L_TCR_T0SZ_512
|
||||||
|
|
||||||
|
/* Stage 1 instruction access cacheability is unaffected. */
|
||||||
|
.set .L_SCTLR_ELx_I, 0x1 << 12
|
||||||
|
/* SP alignment fault if SP is not aligned to a 16 byte boundary. */
|
||||||
|
.set .L_SCTLR_ELx_SA, 0x1 << 3
|
||||||
|
/* Stage 1 data access cacheability is unaffected. */
|
||||||
|
.set .L_SCTLR_ELx_C, 0x1 << 2
|
||||||
|
/* EL0 and EL1 stage 1 MMU enabled. */
|
||||||
|
.set .L_SCTLR_ELx_M, 0x1 << 0
|
||||||
|
/* Privileged Access Never is unchanged on taking an exception to EL1. */
|
||||||
|
.set .L_SCTLR_EL1_SPAN, 0x1 << 23
|
||||||
|
/* SETEND instruction disabled at EL0 in aarch32 mode. */
|
||||||
|
.set .L_SCTLR_EL1_SED, 0x1 << 8
|
||||||
|
/* Various IT instructions are disabled at EL0 in aarch32 mode. */
|
||||||
|
.set .L_SCTLR_EL1_ITD, 0x1 << 7
|
||||||
|
.set .L_SCTLR_EL1_RES1, (0x1 << 11) | (0x1 << 20) | (0x1 << 22) | (0x1 << 28) | (0x1 << 29)
|
||||||
|
.set .Lsctlrval, .L_SCTLR_ELx_M | .L_SCTLR_ELx_C | .L_SCTLR_ELx_SA | .L_SCTLR_EL1_ITD | .L_SCTLR_EL1_SED
|
||||||
|
.set .Lsctlrval, .Lsctlrval | .L_SCTLR_ELx_I | .L_SCTLR_EL1_SPAN | .L_SCTLR_EL1_RES1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a generic entry point for an image. It carries out the operations required to prepare the
|
||||||
|
* loaded image to be run. Specifically, it zeroes the bss section using registers x25 and above,
|
||||||
|
* prepares the stack, enables floating point, and sets up the exception vector. It preserves x0-x3
|
||||||
|
* for the Rust entry point, as these may contain boot parameters.
|
||||||
|
*/
|
||||||
|
.section .init.entry, "ax"
|
||||||
|
.global entry
|
||||||
|
entry:
|
||||||
|
/* Load and apply the memory management configuration, ready to enable MMU and caches. */
|
||||||
|
adrp x30, idmap
|
||||||
|
msr ttbr0_el1, x30
|
||||||
|
|
||||||
|
mov_i x30, .Lmairval
|
||||||
|
msr mair_el1, x30
|
||||||
|
|
||||||
|
mov_i x30, .Ltcrval
|
||||||
|
/* Copy the supported PA range into TCR_EL1.IPS. */
|
||||||
|
mrs x29, id_aa64mmfr0_el1
|
||||||
|
bfi x30, x29, #32, #4
|
||||||
|
|
||||||
|
msr tcr_el1, x30
|
||||||
|
|
||||||
|
mov_i x30, .Lsctlrval
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure everything before this point has completed, then invalidate any potentially stale
|
||||||
|
* local TLB entries before they start being used.
|
||||||
|
*/
|
||||||
|
isb
|
||||||
|
tlbi vmalle1
|
||||||
|
ic iallu
|
||||||
|
dsb nsh
|
||||||
|
isb
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure sctlr_el1 to enable MMU and cache and don't proceed until this has completed.
|
||||||
|
*/
|
||||||
|
msr sctlr_el1, x30
|
||||||
|
isb
|
||||||
|
|
||||||
|
/* Disable trapping floating point access in EL1. */
|
||||||
|
mrs x30, cpacr_el1
|
||||||
|
orr x30, x30, #(0x3 << 20)
|
||||||
|
msr cpacr_el1, x30
|
||||||
|
isb
|
||||||
|
|
||||||
|
/* Zero out the bss section. */
|
||||||
|
adr_l x29, bss_begin
|
||||||
|
adr_l x30, bss_end
|
||||||
|
0: cmp x29, x30
|
||||||
|
b.hs 1f
|
||||||
|
stp xzr, xzr, [x29], #16
|
||||||
|
b 0b
|
||||||
|
|
||||||
|
1: /* Prepare the stack. */
|
||||||
|
adr_l x30, boot_stack_end
|
||||||
|
mov sp, x30
|
||||||
|
|
||||||
|
/* Set up exception vector. */
|
||||||
|
adr x30, vector_table_el1
|
||||||
|
msr vbar_el1, x30
|
||||||
|
|
||||||
|
/* Call into Rust code. */
|
||||||
|
bl main
|
||||||
|
|
||||||
|
/* Loop forever waiting for interrupts. */
|
||||||
|
2: wfi
|
||||||
|
b 2b
|
178
src/bare-metal/aps/examples/exceptions.S
Normal file
178
src/bare-metal/aps/examples/exceptions.S
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Google LLC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the volatile registers onto the stack. This currently takes 14
|
||||||
|
* instructions, so it can be used in exception handlers with 18 instructions
|
||||||
|
* left.
|
||||||
|
*
|
||||||
|
* On return, x0 and x1 are initialised to elr_el2 and spsr_el2 respectively,
|
||||||
|
* which can be used as the first and second arguments of a subsequent call.
|
||||||
|
*/
|
||||||
|
.macro save_volatile_to_stack
|
||||||
|
/* Reserve stack space and save registers x0-x18, x29 & x30. */
|
||||||
|
stp x0, x1, [sp, #-(8 * 24)]!
|
||||||
|
stp x2, x3, [sp, #8 * 2]
|
||||||
|
stp x4, x5, [sp, #8 * 4]
|
||||||
|
stp x6, x7, [sp, #8 * 6]
|
||||||
|
stp x8, x9, [sp, #8 * 8]
|
||||||
|
stp x10, x11, [sp, #8 * 10]
|
||||||
|
stp x12, x13, [sp, #8 * 12]
|
||||||
|
stp x14, x15, [sp, #8 * 14]
|
||||||
|
stp x16, x17, [sp, #8 * 16]
|
||||||
|
str x18, [sp, #8 * 18]
|
||||||
|
stp x29, x30, [sp, #8 * 20]
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save elr_el1 & spsr_el1. This such that we can take nested exception
|
||||||
|
* and still be able to unwind.
|
||||||
|
*/
|
||||||
|
mrs x0, elr_el1
|
||||||
|
mrs x1, spsr_el1
|
||||||
|
stp x0, x1, [sp, #8 * 22]
|
||||||
|
.endm
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores the volatile registers from the stack. This currently takes 14
|
||||||
|
* instructions, so it can be used in exception handlers while still leaving 18
|
||||||
|
* instructions left; if paired with save_volatile_to_stack, there are 4
|
||||||
|
* instructions to spare.
|
||||||
|
*/
|
||||||
|
.macro restore_volatile_from_stack
|
||||||
|
/* Restore registers x2-x18, x29 & x30. */
|
||||||
|
ldp x2, x3, [sp, #8 * 2]
|
||||||
|
ldp x4, x5, [sp, #8 * 4]
|
||||||
|
ldp x6, x7, [sp, #8 * 6]
|
||||||
|
ldp x8, x9, [sp, #8 * 8]
|
||||||
|
ldp x10, x11, [sp, #8 * 10]
|
||||||
|
ldp x12, x13, [sp, #8 * 12]
|
||||||
|
ldp x14, x15, [sp, #8 * 14]
|
||||||
|
ldp x16, x17, [sp, #8 * 16]
|
||||||
|
ldr x18, [sp, #8 * 18]
|
||||||
|
ldp x29, x30, [sp, #8 * 20]
|
||||||
|
|
||||||
|
/* Restore registers elr_el1 & spsr_el1, using x0 & x1 as scratch. */
|
||||||
|
ldp x0, x1, [sp, #8 * 22]
|
||||||
|
msr elr_el1, x0
|
||||||
|
msr spsr_el1, x1
|
||||||
|
|
||||||
|
/* Restore x0 & x1, and release stack space. */
|
||||||
|
ldp x0, x1, [sp], #8 * 24
|
||||||
|
.endm
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a generic handler for exceptions taken at the current EL while using
|
||||||
|
* SP0. It behaves similarly to the SPx case by first switching to SPx, doing
|
||||||
|
* the work, then switching back to SP0 before returning.
|
||||||
|
*
|
||||||
|
* Switching to SPx and calling the Rust handler takes 16 instructions. To
|
||||||
|
* restore and return we need an additional 16 instructions, so we can implement
|
||||||
|
* the whole handler within the allotted 32 instructions.
|
||||||
|
*/
|
||||||
|
.macro current_exception_sp0 handler:req
|
||||||
|
msr spsel, #1
|
||||||
|
save_volatile_to_stack
|
||||||
|
bl \handler
|
||||||
|
restore_volatile_from_stack
|
||||||
|
msr spsel, #0
|
||||||
|
eret
|
||||||
|
.endm
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a generic handler for exceptions taken at the current EL while using
|
||||||
|
* SPx. It saves volatile registers, calls the Rust handler, restores volatile
|
||||||
|
* registers, then returns.
|
||||||
|
*
|
||||||
|
* This also works for exceptions taken from EL0, if we don't care about
|
||||||
|
* non-volatile registers.
|
||||||
|
*
|
||||||
|
* Saving state and jumping to the Rust handler takes 15 instructions, and
|
||||||
|
* restoring and returning also takes 15 instructions, so we can fit the whole
|
||||||
|
* handler in 30 instructions, under the limit of 32.
|
||||||
|
*/
|
||||||
|
.macro current_exception_spx handler:req
|
||||||
|
save_volatile_to_stack
|
||||||
|
bl \handler
|
||||||
|
restore_volatile_from_stack
|
||||||
|
eret
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.section .text.vector_table_el1, "ax"
|
||||||
|
.global vector_table_el1
|
||||||
|
.balign 0x800
|
||||||
|
vector_table_el1:
|
||||||
|
sync_cur_sp0:
|
||||||
|
current_exception_sp0 sync_exception_current
|
||||||
|
|
||||||
|
.balign 0x80
|
||||||
|
irq_cur_sp0:
|
||||||
|
current_exception_sp0 irq_current
|
||||||
|
|
||||||
|
.balign 0x80
|
||||||
|
fiq_cur_sp0:
|
||||||
|
current_exception_sp0 fiq_current
|
||||||
|
|
||||||
|
.balign 0x80
|
||||||
|
serr_cur_sp0:
|
||||||
|
current_exception_sp0 serr_current
|
||||||
|
|
||||||
|
.balign 0x80
|
||||||
|
sync_cur_spx:
|
||||||
|
current_exception_spx sync_exception_current
|
||||||
|
|
||||||
|
.balign 0x80
|
||||||
|
irq_cur_spx:
|
||||||
|
current_exception_spx irq_current
|
||||||
|
|
||||||
|
.balign 0x80
|
||||||
|
fiq_cur_spx:
|
||||||
|
current_exception_spx fiq_current
|
||||||
|
|
||||||
|
.balign 0x80
|
||||||
|
serr_cur_spx:
|
||||||
|
current_exception_spx serr_current
|
||||||
|
|
||||||
|
.balign 0x80
|
||||||
|
sync_lower_64:
|
||||||
|
current_exception_spx sync_lower
|
||||||
|
|
||||||
|
.balign 0x80
|
||||||
|
irq_lower_64:
|
||||||
|
current_exception_spx irq_lower
|
||||||
|
|
||||||
|
.balign 0x80
|
||||||
|
fiq_lower_64:
|
||||||
|
current_exception_spx fiq_lower
|
||||||
|
|
||||||
|
.balign 0x80
|
||||||
|
serr_lower_64:
|
||||||
|
current_exception_spx serr_lower
|
||||||
|
|
||||||
|
.balign 0x80
|
||||||
|
sync_lower_32:
|
||||||
|
current_exception_spx sync_lower
|
||||||
|
|
||||||
|
.balign 0x80
|
||||||
|
irq_lower_32:
|
||||||
|
current_exception_spx irq_lower
|
||||||
|
|
||||||
|
.balign 0x80
|
||||||
|
fiq_lower_32:
|
||||||
|
current_exception_spx fiq_lower
|
||||||
|
|
||||||
|
.balign 0x80
|
||||||
|
serr_lower_32:
|
||||||
|
current_exception_spx serr_lower
|
42
src/bare-metal/aps/examples/idmap.S
Normal file
42
src/bare-metal/aps/examples/idmap.S
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Google LLC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.set .L_TT_TYPE_BLOCK, 0x1
|
||||||
|
.set .L_TT_TYPE_PAGE, 0x3
|
||||||
|
.set .L_TT_TYPE_TABLE, 0x3
|
||||||
|
|
||||||
|
/* Access flag. */
|
||||||
|
.set .L_TT_AF, 0x1 << 10
|
||||||
|
/* Not global. */
|
||||||
|
.set .L_TT_NG, 0x1 << 11
|
||||||
|
.set .L_TT_XN, 0x3 << 53
|
||||||
|
|
||||||
|
.set .L_TT_MT_DEV, 0x0 << 2 // MAIR #0 (DEV_nGnRE)
|
||||||
|
.set .L_TT_MT_MEM, (0x1 << 2) | (0x3 << 8) // MAIR #1 (MEM_WBWA), inner shareable
|
||||||
|
|
||||||
|
.set .L_BLOCK_DEV, .L_TT_TYPE_BLOCK | .L_TT_MT_DEV | .L_TT_AF | .L_TT_XN
|
||||||
|
.set .L_BLOCK_MEM, .L_TT_TYPE_BLOCK | .L_TT_MT_MEM | .L_TT_AF | .L_TT_NG
|
||||||
|
|
||||||
|
.section ".rodata.idmap", "a", %progbits
|
||||||
|
.global idmap
|
||||||
|
.align 12
|
||||||
|
idmap:
|
||||||
|
/* level 1 */
|
||||||
|
.quad .L_BLOCK_DEV | 0x0 // 1 GiB of device mappings
|
||||||
|
.quad .L_BLOCK_MEM | 0x40000000 // 1 GiB of DRAM
|
||||||
|
.fill 254, 8, 0x0 // 254 GiB of unmapped VA space
|
||||||
|
.quad .L_BLOCK_DEV | 0x4000000000 // 1 GiB of device mappings
|
||||||
|
.fill 255, 8, 0x0 // 255 GiB of remaining VA space
|
104
src/bare-metal/aps/examples/image.ld
Normal file
104
src/bare-metal/aps/examples/image.ld
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Google LLC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Code will start running at this symbol which is placed at the start of the
|
||||||
|
* image.
|
||||||
|
*/
|
||||||
|
ENTRY(entry)
|
||||||
|
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
image : ORIGIN = 0x40080000, LENGTH = 2M
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Collect together the code.
|
||||||
|
*/
|
||||||
|
.init : ALIGN(4096) {
|
||||||
|
text_begin = .;
|
||||||
|
*(.init.entry)
|
||||||
|
*(.init.*)
|
||||||
|
} >image
|
||||||
|
.text : {
|
||||||
|
*(.text.*)
|
||||||
|
} >image
|
||||||
|
text_end = .;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Collect together read-only data.
|
||||||
|
*/
|
||||||
|
.rodata : ALIGN(4096) {
|
||||||
|
rodata_begin = .;
|
||||||
|
*(.rodata.*)
|
||||||
|
} >image
|
||||||
|
.got : {
|
||||||
|
*(.got)
|
||||||
|
} >image
|
||||||
|
rodata_end = .;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Collect together the read-write data including .bss at the end which
|
||||||
|
* will be zero'd by the entry code.
|
||||||
|
*/
|
||||||
|
.data : ALIGN(4096) {
|
||||||
|
data_begin = .;
|
||||||
|
*(.data.*)
|
||||||
|
/*
|
||||||
|
* The entry point code assumes that .data is a multiple of 32
|
||||||
|
* bytes long.
|
||||||
|
*/
|
||||||
|
. = ALIGN(32);
|
||||||
|
data_end = .;
|
||||||
|
} >image
|
||||||
|
|
||||||
|
/* Everything beyond this point will not be included in the binary. */
|
||||||
|
bin_end = .;
|
||||||
|
|
||||||
|
/* The entry point code assumes that .bss is 16-byte aligned. */
|
||||||
|
.bss : ALIGN(16) {
|
||||||
|
bss_begin = .;
|
||||||
|
*(.bss.*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(16);
|
||||||
|
bss_end = .;
|
||||||
|
} >image
|
||||||
|
|
||||||
|
.stack (NOLOAD) : ALIGN(4096) {
|
||||||
|
boot_stack_begin = .;
|
||||||
|
. += 40 * 4096;
|
||||||
|
. = ALIGN(4096);
|
||||||
|
boot_stack_end = .;
|
||||||
|
} >image
|
||||||
|
|
||||||
|
. = ALIGN(4K);
|
||||||
|
PROVIDE(dma_region = .);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove unused sections from the image.
|
||||||
|
*/
|
||||||
|
/DISCARD/ : {
|
||||||
|
/* The image loads itself so doesn't need these sections. */
|
||||||
|
*(.gnu.hash)
|
||||||
|
*(.hash)
|
||||||
|
*(.interp)
|
||||||
|
*(.eh_frame_hdr)
|
||||||
|
*(.eh_frame)
|
||||||
|
*(.note.gnu.build-id)
|
||||||
|
}
|
||||||
|
}
|
64
src/bare-metal/aps/examples/src/exceptions.rs
Normal file
64
src/bare-metal/aps/examples/src/exceptions.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// Copyright 2023 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
use log::error;
|
||||||
|
use psci::system_off;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn sync_exception_current(_elr: u64, _spsr: u64) {
|
||||||
|
error!("sync_exception_current");
|
||||||
|
system_off().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn irq_current(_elr: u64, _spsr: u64) {
|
||||||
|
error!("irq_current");
|
||||||
|
system_off().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn fiq_current(_elr: u64, _spsr: u64) {
|
||||||
|
error!("fiq_current");
|
||||||
|
system_off().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn serr_current(_elr: u64, _spsr: u64) {
|
||||||
|
error!("serr_current");
|
||||||
|
system_off().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn sync_lower(_elr: u64, _spsr: u64) {
|
||||||
|
error!("sync_lower");
|
||||||
|
system_off().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn irq_lower(_elr: u64, _spsr: u64) {
|
||||||
|
error!("irq_lower");
|
||||||
|
system_off().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn fiq_lower(_elr: u64, _spsr: u64) {
|
||||||
|
error!("fiq_lower");
|
||||||
|
system_off().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn serr_lower(_elr: u64, _spsr: u64) {
|
||||||
|
error!("serr_lower");
|
||||||
|
system_off().unwrap();
|
||||||
|
}
|
35
src/bare-metal/aps/examples/src/main.rs
Normal file
35
src/bare-metal/aps/examples/src/main.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2023 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
mod exceptions;
|
||||||
|
mod uart;
|
||||||
|
|
||||||
|
use core::panic::PanicInfo;
|
||||||
|
use log::error;
|
||||||
|
use psci::system_off;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
|
||||||
|
system_off().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
|
error!("{}", info);
|
||||||
|
system_off().unwrap();
|
||||||
|
loop {}
|
||||||
|
}
|
66
src/bare-metal/aps/examples/src/uart.rs
Normal file
66
src/bare-metal/aps/examples/src/uart.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// Copyright 2023 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// ANCHOR: Example
|
||||||
|
use core::ptr::write_volatile;
|
||||||
|
|
||||||
|
/// Minimal driver for an 8250 UART. This only implements enough to work with
|
||||||
|
/// the emulated 8250 provided by crosvm, and won't work with real hardware.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Uart {
|
||||||
|
base_address: *mut u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Uart {
|
||||||
|
/// Constructs a new instance of the UART driver for a device at the given
|
||||||
|
/// base address.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The given base address must point to the 8 MMIO control registers of an
|
||||||
|
/// appropriate UART device, which must be mapped into the address space of
|
||||||
|
/// the process as device memory and not have any other aliases.
|
||||||
|
pub unsafe fn new(base_address: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
base_address: base_address as *mut u8,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes a single byte to the UART.
|
||||||
|
pub fn write_byte(&self, byte: u8) {
|
||||||
|
// Safe because we know that the base address points to the control
|
||||||
|
// registers of a UART device which is appropriately mapped.
|
||||||
|
unsafe {
|
||||||
|
write_volatile(self.base_address, byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ANCHOR_END: Example
|
||||||
|
|
||||||
|
// ANCHOR: Traits
|
||||||
|
use core::fmt::{self, Write};
|
||||||
|
|
||||||
|
impl Write for Uart {
|
||||||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
|
for c in s.as_bytes() {
|
||||||
|
self.write_byte(*c);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safe because it just contains a pointer to device memory, which can be
|
||||||
|
// accessed from any context.
|
||||||
|
unsafe impl Send for Uart {}
|
||||||
|
// ANCHOR_END: Traits
|
5
src/bare-metal/aps/uart.md
Normal file
5
src/bare-metal/aps/uart.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Let's write a UART driver
|
||||||
|
|
||||||
|
```rust,editable,compile_fail
|
||||||
|
{{#include examples/src/uart.rs:Example}}
|
||||||
|
```
|
5
src/bare-metal/aps/uart/traits.md
Normal file
5
src/bare-metal/aps/uart/traits.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# More traits
|
||||||
|
|
||||||
|
```rust,editable,compile_fail
|
||||||
|
{{#include ../examples/src/uart.rs:Traits}}
|
||||||
|
```
|
@ -22,7 +22,7 @@ To get started, install some tools we'll need later:
|
|||||||
```bash
|
```bash
|
||||||
sudo apt install gdb-multiarch picocom libudev-dev
|
sudo apt install gdb-multiarch picocom libudev-dev
|
||||||
rustup update
|
rustup update
|
||||||
rustup target add thumbv7em-none-eabihf
|
rustup target add thumbv7em-none-eabihf aarch64-unknown-none
|
||||||
cargo install cargo-binutils cargo-embed
|
cargo install cargo-binutils cargo-embed
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user