cortex-m: add feature struct (unused) start to set up the hardware

Change-Id: Ie12381efe614ec034c4dcdafddef15a29724d203
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/maize/+/261714
Lint: Lint 🤖 <android-build-ayeaye@system.gserviceaccount.com>
Commit-Queue: Erik Gilling <konkers@google.com>
Reviewed-by: Erik Gilling <konkers@google.com>
Presubmit-Verified: CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/kernel/BUILD.bazel b/kernel/BUILD.bazel
index c3a9a5f..ec798df 100644
--- a/kernel/BUILD.bazel
+++ b/kernel/BUILD.bazel
@@ -17,6 +17,7 @@
 package(default_visibility = ["//visibility:public"])
 
 CORTEX_M_DEPS = [
+    "@rust_crates//:cortex-m",
     "@rust_crates//:cortex-m-rt",
 ]
 
@@ -24,6 +25,7 @@
     name = "kernel",
     srcs = [
         "kernel/arch/arm_cortex_m/exceptions.rs",
+        "kernel/arch/arm_cortex_m/features.rs",
         "kernel/arch/arm_cortex_m/mod.rs",
         "kernel/arch/host/mod.rs",
         "kernel/arch/mod.rs",
diff --git a/kernel/kernel/arch/arm_cortex_m/features.rs b/kernel/kernel/arch/arm_cortex_m/features.rs
new file mode 100644
index 0000000..f1d8721
--- /dev/null
+++ b/kernel/kernel/arch/arm_cortex_m/features.rs
@@ -0,0 +1,65 @@
+// Copyright 2025 The Pigweed Authors
+//
+// 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.
+#![no_std]
+
+use cortex_m::peripheral::Peripherals;
+use pw_log::info;
+
+// Start of trying to read features out of CPUID and other registers in hardware.
+
+// Not complete and currently unused.
+
+#[derive(PartialEq, PartialOrd)]
+pub enum ArchVersion {
+    ArmV6m = 0,
+    ArmV7m = 1,
+    ARMv8m = 2,
+}
+pub struct Features {
+    arch_version: ArchVersion,
+    has_vtor: bool,
+}
+
+impl Features {
+    pub const fn new() -> Features {
+        return Features {
+            arch_version: ArchVersion::ArmV6m,
+            has_vtor: false,
+        };
+    }
+
+    pub fn read_features(&mut self) {
+        let p = Peripherals::take().unwrap();
+        let cpuid = p.CPUID.base.read();
+        info!("CPUID 0x{:x}", cpuid);
+
+        let mut f = Features::new();
+        if (cpuid >> 16 & 0xf) != 0xf {
+            // ARMv6m has an architecture field of 0xc
+            f.arch_version = ArchVersion::ArmV6m;
+            f.has_vtor = true;
+        } else {
+            // TODO: figure out more arch version bits here
+            f.arch_version = ArchVersion::ArmV7m;
+            f.has_vtor = true;
+        }
+    }
+
+    pub fn at_least_version(&self, version: ArchVersion) -> bool {
+        if version <= self.arch_version {
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/kernel/kernel/arch/arm_cortex_m/mod.rs b/kernel/kernel/arch/arm_cortex_m/mod.rs
index 84db20c..bdd1157 100644
--- a/kernel/kernel/arch/arm_cortex_m/mod.rs
+++ b/kernel/kernel/arch/arm_cortex_m/mod.rs
@@ -12,6 +12,9 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
+use cortex_m::peripheral::Peripherals;
+use pw_log::info;
+
 use super::ArchInterface;
 
 mod exceptions;
@@ -31,12 +34,33 @@
 
     fn early_init() {
         // TODO: set up the cpu here:
-        // interrupt vector table
-        // irq priority levels
-        // clear pending interrupts
-        // FPU initial state
-        // enable cache (if present)
-        // enable cycle counter?
+        //  interrupt vector table
+        //  irq priority levels
+        //  clear pending interrupts
+        //  FPU initial state
+        //  enable cache (if present)
+        //  enable cycle counter?
+        let p = Peripherals::take().unwrap();
+        let cpuid = p.CPUID.base.read();
+        info!("CPUID 0x{:x}", cpuid);
+
+        // Set the VTOR (assumes it exists)
+        unsafe {
+            extern "C" {
+                fn pw_boot_vector_table_addr();
+            }
+            let vector_table = pw_boot_vector_table_addr as *const ();
+            p.SCB.vtor.write(vector_table as u32);
+        }
+
+        // Intentionally trigger a hard fault to make sure the VTOR is working.
+        // use core::arch::asm;
+        // unsafe {
+        //     asm!("bkpt");
+        // }
     }
-    fn init() {}
+
+    fn init() {
+        info!("arch init");
+    }
 }