1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Macro to define register layout and accessors. 4 //! 5 //! The [`register!`](kernel::io::register!) macro provides an intuitive and readable syntax for 6 //! defining a dedicated type for each register and accessing it using [`Io`](super::Io). Each such 7 //! type comes with its own field accessors that can return an error if a field's value is invalid. 8 //! 9 //! Note: most of the items in this module are public so they can be referenced by the macro, but 10 //! most are not to be used directly by users. Outside of the `register!` macro itself, the only 11 //! items you might want to import from this module are [`WithBase`] and [`Array`]. 12 //! 13 //! # Simple example 14 //! 15 //! ```no_run 16 //! use kernel::io::register; 17 //! 18 //! register! { 19 //! /// Basic information about the chip. 20 //! pub BOOT_0(u32) @ 0x00000100 { 21 //! /// Vendor ID. 22 //! 15:8 vendor_id; 23 //! /// Major revision of the chip. 24 //! 7:4 major_revision; 25 //! /// Minor revision of the chip. 26 //! 3:0 minor_revision; 27 //! } 28 //! } 29 //! ``` 30 //! 31 //! This defines a 32-bit `BOOT_0` type which can be read from or written to offset `0x100` of an 32 //! `Io` region, with the described bitfields. For instance, `minor_revision` consists of the 4 33 //! least significant bits of the type. 34 //! 35 //! Fields are instances of [`Bounded`](kernel::num::Bounded) and can be read by calling their 36 //! getter method, which is named after them. They also have setter methods prefixed with `with_` 37 //! for runtime values and `with_const_` for constant values. All setters return the updated 38 //! register value. 39 //! 40 //! Fields can also be transparently converted from/to an arbitrary type by using the `=>` and 41 //! `?=>` syntaxes. 42 //! 43 //! If present, doc comments above register or fields definitions are added to the relevant item 44 //! they document (the register type itself, or the field's setter and getter methods). 45 //! 46 //! Note that multiple registers can be defined in a single `register!` invocation. This can be 47 //! useful to group related registers together. 48 //! 49 //! Here is how the register defined above can be used in code: 50 //! 51 //! 52 //! ```no_run 53 //! use kernel::{ 54 //! io::{ 55 //! register, 56 //! Io, 57 //! IoLoc, 58 //! }, 59 //! num::Bounded, 60 //! }; 61 //! # use kernel::io::Mmio; 62 //! # register! { 63 //! # pub BOOT_0(u32) @ 0x00000100 { 64 //! # 15:8 vendor_id; 65 //! # 7:4 major_revision; 66 //! # 3:0 minor_revision; 67 //! # } 68 //! # } 69 //! # fn test(io: &Mmio<0x1000>) { 70 //! # fn obtain_vendor_id() -> u8 { 0xff } 71 //! 72 //! // Read from the register's defined offset (0x100). 73 //! let boot0 = io.read(BOOT_0); 74 //! pr_info!("chip revision: {}.{}", boot0.major_revision().get(), boot0.minor_revision().get()); 75 //! 76 //! // Update some fields and write the new value back. 77 //! let new_boot0 = boot0 78 //! // Constant values. 79 //! .with_const_major_revision::<3>() 80 //! .with_const_minor_revision::<10>() 81 //! // Runtime value. 82 //! .with_vendor_id(obtain_vendor_id()); 83 //! io.write_reg(new_boot0); 84 //! 85 //! // Or, build a new value from zero and write it: 86 //! io.write_reg(BOOT_0::zeroed() 87 //! .with_const_major_revision::<3>() 88 //! .with_const_minor_revision::<10>() 89 //! .with_vendor_id(obtain_vendor_id()) 90 //! ); 91 //! 92 //! // Or, read and update the register in a single step. 93 //! io.update(BOOT_0, |r| r 94 //! .with_const_major_revision::<3>() 95 //! .with_const_minor_revision::<10>() 96 //! .with_vendor_id(obtain_vendor_id()) 97 //! ); 98 //! 99 //! // Constant values can also be built using the const setters. 100 //! const V: BOOT_0 = pin_init::zeroed::<BOOT_0>() 101 //! .with_const_major_revision::<3>() 102 //! .with_const_minor_revision::<10>(); 103 //! # } 104 //! ``` 105 //! 106 //! For more extensive documentation about how to define registers, see the 107 //! [`register!`](kernel::io::register!) macro. 108 109 use core::marker::PhantomData; 110 111 use crate::io::IoLoc; 112 113 use kernel::build_assert; 114 115 /// Trait implemented by all registers. 116 pub trait Register: Sized { 117 /// Backing primitive type of the register. 118 type Storage: Into<Self> + From<Self>; 119 120 /// Start offset of the register. 121 /// 122 /// The interpretation of this offset depends on the type of the register. 123 const OFFSET: usize; 124 } 125 126 /// Trait implemented by registers with a fixed offset. 127 pub trait FixedRegister: Register {} 128 129 /// Allows `()` to be used as the `location` parameter of [`Io::write`](super::Io::write) when 130 /// passing a [`FixedRegister`] value. 131 impl<T> IoLoc<T> for () 132 where 133 T: FixedRegister, 134 { 135 type IoType = T::Storage; 136 137 #[inline(always)] offset(self) -> usize138 fn offset(self) -> usize { 139 T::OFFSET 140 } 141 } 142 143 /// A [`FixedRegister`] carries its location in its type. Thus `FixedRegister` values can be used 144 /// as an [`IoLoc`]. 145 impl<T> IoLoc<T> for T 146 where 147 T: FixedRegister, 148 { 149 type IoType = T::Storage; 150 151 #[inline(always)] offset(self) -> usize152 fn offset(self) -> usize { 153 T::OFFSET 154 } 155 } 156 157 /// Location of a fixed register. 158 pub struct FixedRegisterLoc<T: FixedRegister>(PhantomData<T>); 159 160 impl<T: FixedRegister> FixedRegisterLoc<T> { 161 /// Returns the location of `T`. 162 #[inline(always)] 163 // We do not implement `Default` so we can be const. 164 #[expect(clippy::new_without_default)] new() -> Self165 pub const fn new() -> Self { 166 Self(PhantomData) 167 } 168 } 169 170 impl<T> IoLoc<T> for FixedRegisterLoc<T> 171 where 172 T: FixedRegister, 173 { 174 type IoType = T::Storage; 175 176 #[inline(always)] offset(self) -> usize177 fn offset(self) -> usize { 178 T::OFFSET 179 } 180 } 181 182 /// Trait providing a base address to be added to the offset of a relative register to obtain 183 /// its actual offset. 184 /// 185 /// The `T` generic argument is used to distinguish which base to use, in case a type provides 186 /// several bases. It is given to the `register!` macro to restrict the use of the register to 187 /// implementors of this particular variant. 188 pub trait RegisterBase<T> { 189 /// Base address to which register offsets are added. 190 const BASE: usize; 191 } 192 193 /// Trait implemented by all registers that are relative to a base. 194 pub trait WithBase { 195 /// Family of bases applicable to this register. 196 type BaseFamily; 197 198 /// Returns the absolute location of this type when using `B` as its base. 199 #[inline(always)] of<B: RegisterBase<Self::BaseFamily>>() -> RelativeRegisterLoc<Self, B> where Self: Register,200 fn of<B: RegisterBase<Self::BaseFamily>>() -> RelativeRegisterLoc<Self, B> 201 where 202 Self: Register, 203 { 204 RelativeRegisterLoc::new() 205 } 206 } 207 208 /// Trait implemented by relative registers. 209 pub trait RelativeRegister: Register + WithBase {} 210 211 /// Location of a relative register. 212 /// 213 /// This can either be an immediately accessible regular [`RelativeRegister`], or a 214 /// [`RelativeRegisterArray`] that needs one additional resolution through 215 /// [`RelativeRegisterLoc::at`]. 216 pub struct RelativeRegisterLoc<T: WithBase, B: ?Sized>(PhantomData<T>, PhantomData<B>); 217 218 impl<T, B> RelativeRegisterLoc<T, B> 219 where 220 T: Register + WithBase, 221 B: RegisterBase<T::BaseFamily> + ?Sized, 222 { 223 /// Returns the location of a relative register or register array. 224 #[inline(always)] 225 // We do not implement `Default` so we can be const. 226 #[expect(clippy::new_without_default)] new() -> Self227 pub const fn new() -> Self { 228 Self(PhantomData, PhantomData) 229 } 230 231 // Returns the absolute offset of the relative register using base `B`. 232 // 233 // This is implemented as a private const method so it can be reused by the [`IoLoc`] 234 // implementations of both [`RelativeRegisterLoc`] and [`RelativeRegisterArrayLoc`]. 235 #[inline] offset(self) -> usize236 const fn offset(self) -> usize { 237 B::BASE + T::OFFSET 238 } 239 } 240 241 impl<T, B> IoLoc<T> for RelativeRegisterLoc<T, B> 242 where 243 T: RelativeRegister, 244 B: RegisterBase<T::BaseFamily> + ?Sized, 245 { 246 type IoType = T::Storage; 247 248 #[inline(always)] offset(self) -> usize249 fn offset(self) -> usize { 250 RelativeRegisterLoc::offset(self) 251 } 252 } 253 254 /// Trait implemented by arrays of registers. 255 pub trait RegisterArray: Register { 256 /// Number of elements in the registers array. 257 const SIZE: usize; 258 /// Number of bytes between the start of elements in the registers array. 259 const STRIDE: usize; 260 } 261 262 /// Location of an array register. 263 pub struct RegisterArrayLoc<T: RegisterArray>(usize, PhantomData<T>); 264 265 impl<T: RegisterArray> RegisterArrayLoc<T> { 266 /// Returns the location of register `T` at position `idx`, with build-time validation. 267 #[inline(always)] new(idx: usize) -> Self268 pub fn new(idx: usize) -> Self { 269 build_assert!(idx < T::SIZE); 270 271 Self(idx, PhantomData) 272 } 273 274 /// Attempts to return the location of register `T` at position `idx`, with runtime validation. 275 #[inline(always)] try_new(idx: usize) -> Option<Self>276 pub fn try_new(idx: usize) -> Option<Self> { 277 if idx < T::SIZE { 278 Some(Self(idx, PhantomData)) 279 } else { 280 None 281 } 282 } 283 } 284 285 impl<T> IoLoc<T> for RegisterArrayLoc<T> 286 where 287 T: RegisterArray, 288 { 289 type IoType = T::Storage; 290 291 #[inline(always)] offset(self) -> usize292 fn offset(self) -> usize { 293 T::OFFSET + self.0 * T::STRIDE 294 } 295 } 296 297 /// Trait providing location builders for [`RegisterArray`]s. 298 pub trait Array { 299 /// Returns the location of the register at position `idx`, with build-time validation. 300 #[inline(always)] at(idx: usize) -> RegisterArrayLoc<Self> where Self: RegisterArray,301 fn at(idx: usize) -> RegisterArrayLoc<Self> 302 where 303 Self: RegisterArray, 304 { 305 RegisterArrayLoc::new(idx) 306 } 307 308 /// Returns the location of the register at position `idx`, with runtime validation. 309 #[inline(always)] try_at(idx: usize) -> Option<RegisterArrayLoc<Self>> where Self: RegisterArray,310 fn try_at(idx: usize) -> Option<RegisterArrayLoc<Self>> 311 where 312 Self: RegisterArray, 313 { 314 RegisterArrayLoc::try_new(idx) 315 } 316 } 317 318 /// Trait implemented by arrays of relative registers. 319 pub trait RelativeRegisterArray: RegisterArray + WithBase {} 320 321 /// Location of a relative array register. 322 pub struct RelativeRegisterArrayLoc< 323 T: RelativeRegisterArray, 324 B: RegisterBase<T::BaseFamily> + ?Sized, 325 >(RelativeRegisterLoc<T, B>, usize); 326 327 impl<T, B> RelativeRegisterArrayLoc<T, B> 328 where 329 T: RelativeRegisterArray, 330 B: RegisterBase<T::BaseFamily> + ?Sized, 331 { 332 /// Returns the location of register `T` from the base `B` at index `idx`, with build-time 333 /// validation. 334 #[inline(always)] new(idx: usize) -> Self335 pub fn new(idx: usize) -> Self { 336 build_assert!(idx < T::SIZE); 337 338 Self(RelativeRegisterLoc::new(), idx) 339 } 340 341 /// Attempts to return the location of register `T` from the base `B` at index `idx`, with 342 /// runtime validation. 343 #[inline(always)] try_new(idx: usize) -> Option<Self>344 pub fn try_new(idx: usize) -> Option<Self> { 345 if idx < T::SIZE { 346 Some(Self(RelativeRegisterLoc::new(), idx)) 347 } else { 348 None 349 } 350 } 351 } 352 353 /// Methods exclusive to [`RelativeRegisterLoc`]s created with a [`RelativeRegisterArray`]. 354 impl<T, B> RelativeRegisterLoc<T, B> 355 where 356 T: RelativeRegisterArray, 357 B: RegisterBase<T::BaseFamily> + ?Sized, 358 { 359 /// Returns the location of the register at position `idx`, with build-time validation. 360 #[inline(always)] at(self, idx: usize) -> RelativeRegisterArrayLoc<T, B>361 pub fn at(self, idx: usize) -> RelativeRegisterArrayLoc<T, B> { 362 RelativeRegisterArrayLoc::new(idx) 363 } 364 365 /// Returns the location of the register at position `idx`, with runtime validation. 366 #[inline(always)] try_at(self, idx: usize) -> Option<RelativeRegisterArrayLoc<T, B>>367 pub fn try_at(self, idx: usize) -> Option<RelativeRegisterArrayLoc<T, B>> { 368 RelativeRegisterArrayLoc::try_new(idx) 369 } 370 } 371 372 impl<T, B> IoLoc<T> for RelativeRegisterArrayLoc<T, B> 373 where 374 T: RelativeRegisterArray, 375 B: RegisterBase<T::BaseFamily> + ?Sized, 376 { 377 type IoType = T::Storage; 378 379 #[inline(always)] offset(self) -> usize380 fn offset(self) -> usize { 381 self.0.offset() + self.1 * T::STRIDE 382 } 383 } 384 385 /// Trait implemented by items that contain both a register value and the absolute I/O location at 386 /// which to write it. 387 /// 388 /// Implementors can be used with [`Io::write_reg`](super::Io::write_reg). 389 pub trait LocatedRegister { 390 /// Register value to write. 391 type Value: Register; 392 /// Full location information at which to write the value. 393 type Location: IoLoc<Self::Value>; 394 395 /// Consumes `self` and returns a `(location, value)` tuple describing a valid I/O write 396 /// operation. into_io_op(self) -> (Self::Location, Self::Value)397 fn into_io_op(self) -> (Self::Location, Self::Value); 398 } 399 400 impl<T> LocatedRegister for T 401 where 402 T: FixedRegister, 403 { 404 type Location = FixedRegisterLoc<Self::Value>; 405 type Value = T; 406 407 #[inline(always)] into_io_op(self) -> (FixedRegisterLoc<T>, T)408 fn into_io_op(self) -> (FixedRegisterLoc<T>, T) { 409 (FixedRegisterLoc::new(), self) 410 } 411 } 412 413 /// Defines a dedicated type for a register, including getter and setter methods for its fields and 414 /// methods to read and write it from an [`Io`](kernel::io::Io) region. 415 /// 416 /// This documentation focuses on how to declare registers. See the [module-level 417 /// documentation](mod@kernel::io::register) for examples of how to access them. 418 /// 419 /// There are 4 possible kinds of registers: fixed offset registers, relative registers, arrays of 420 /// registers, and relative arrays of registers. 421 /// 422 /// ## Fixed offset registers 423 /// 424 /// These are the simplest kind of registers. Their location is simply an offset inside the I/O 425 /// region. For instance: 426 /// 427 /// ```ignore 428 /// register! { 429 /// pub FIXED_REG(u16) @ 0x80 { 430 /// ... 431 /// } 432 /// } 433 /// ``` 434 /// 435 /// This creates a 16-bit register named `FIXED_REG` located at offset `0x80` of an I/O region. 436 /// 437 /// These registers' location can be built simply by referencing their name: 438 /// 439 /// ```no_run 440 /// use kernel::{ 441 /// io::{ 442 /// register, 443 /// Io, 444 /// }, 445 /// }; 446 /// # use kernel::io::Mmio; 447 /// 448 /// register! { 449 /// FIXED_REG(u32) @ 0x100 { 450 /// 16:8 high_byte; 451 /// 7:0 low_byte; 452 /// } 453 /// } 454 /// 455 /// # fn test(io: &Mmio<0x1000>) { 456 /// let val = io.read(FIXED_REG); 457 /// 458 /// // Write from an already-existing value. 459 /// io.write(FIXED_REG, val.with_low_byte(0xff)); 460 /// 461 /// // Create a register value from scratch. 462 /// let val2 = FIXED_REG::zeroed().with_high_byte(0x80); 463 /// 464 /// // The location of fixed offset registers is already contained in their type. Thus, the 465 /// // `location` argument of `Io::write` is technically redundant and can be replaced by `()`. 466 /// io.write((), val2); 467 /// 468 /// // Or, the single-argument `Io::write_reg` can be used. 469 /// io.write_reg(val2); 470 /// # } 471 /// 472 /// ``` 473 /// 474 /// It is possible to create an alias of an existing register with new field definitions by using 475 /// the `=> ALIAS` syntax. This is useful for cases where a register's interpretation depends on 476 /// the context: 477 /// 478 /// ```no_run 479 /// use kernel::io::register; 480 /// 481 /// register! { 482 /// /// Scratch register. 483 /// pub SCRATCH(u32) @ 0x00000200 { 484 /// 31:0 value; 485 /// } 486 /// 487 /// /// Boot status of the firmware. 488 /// pub SCRATCH_BOOT_STATUS(u32) => SCRATCH { 489 /// 0:0 completed; 490 /// } 491 /// } 492 /// ``` 493 /// 494 /// In this example, `SCRATCH_BOOT_STATUS` uses the same I/O address as `SCRATCH`, while providing 495 /// its own `completed` field. 496 /// 497 /// ## Relative registers 498 /// 499 /// Relative registers can be instantiated several times at a relative offset of a group of bases. 500 /// For instance, imagine the following I/O space: 501 /// 502 /// ```text 503 /// +-----------------------------+ 504 /// | ... | 505 /// | | 506 /// 0x100--->+------------CPU0-------------+ 507 /// | | 508 /// 0x110--->+-----------------------------+ 509 /// | CPU_CTL | 510 /// +-----------------------------+ 511 /// | ... | 512 /// | | 513 /// | | 514 /// 0x200--->+------------CPU1-------------+ 515 /// | | 516 /// 0x210--->+-----------------------------+ 517 /// | CPU_CTL | 518 /// +-----------------------------+ 519 /// | ... | 520 /// +-----------------------------+ 521 /// ``` 522 /// 523 /// `CPU0` and `CPU1` both have a `CPU_CTL` register that starts at offset `0x10` of their I/O 524 /// space segment. Since both instances of `CPU_CTL` share the same layout, we don't want to define 525 /// them twice and would prefer a way to select which one to use from a single definition. 526 /// 527 /// This can be done using the `Base + Offset` syntax when specifying the register's address: 528 /// 529 /// ```ignore 530 /// register! { 531 /// pub RELATIVE_REG(u32) @ Base + 0x80 { 532 /// ... 533 /// } 534 /// } 535 /// ``` 536 /// 537 /// This creates a register with an offset of `0x80` from a given base. 538 /// 539 /// `Base` is an arbitrary type (typically a ZST) to be used as a generic parameter of the 540 /// [`RegisterBase`] trait to provide the base as a constant, i.e. each type providing a base for 541 /// this register needs to implement `RegisterBase<Base>`. 542 /// 543 /// The location of relative registers can be built using the [`WithBase::of`] method to specify 544 /// its base. All relative registers implement [`WithBase`]. 545 /// 546 /// Here is the above layout translated into code: 547 /// 548 /// ```no_run 549 /// use kernel::{ 550 /// io::{ 551 /// register, 552 /// register::{ 553 /// RegisterBase, 554 /// WithBase, 555 /// }, 556 /// Io, 557 /// }, 558 /// }; 559 /// # use kernel::io::Mmio; 560 /// 561 /// // Type used to identify the base. 562 /// pub struct CpuCtlBase; 563 /// 564 /// // ZST describing `CPU0`. 565 /// struct Cpu0; 566 /// impl RegisterBase<CpuCtlBase> for Cpu0 { 567 /// const BASE: usize = 0x100; 568 /// } 569 /// 570 /// // ZST describing `CPU1`. 571 /// struct Cpu1; 572 /// impl RegisterBase<CpuCtlBase> for Cpu1 { 573 /// const BASE: usize = 0x200; 574 /// } 575 /// 576 /// // This makes `CPU_CTL` accessible from all implementors of `RegisterBase<CpuCtlBase>`. 577 /// register! { 578 /// /// CPU core control. 579 /// pub CPU_CTL(u32) @ CpuCtlBase + 0x10 { 580 /// 0:0 start; 581 /// } 582 /// } 583 /// 584 /// # fn test(io: Mmio<0x1000>) { 585 /// // Read the status of `Cpu0`. 586 /// let cpu0_started = io.read(CPU_CTL::of::<Cpu0>()); 587 /// 588 /// // Stop `Cpu0`. 589 /// io.write(WithBase::of::<Cpu0>(), CPU_CTL::zeroed()); 590 /// # } 591 /// 592 /// // Aliases can also be defined for relative register. 593 /// register! { 594 /// /// Alias to CPU core control. 595 /// pub CPU_CTL_ALIAS(u32) => CpuCtlBase + CPU_CTL { 596 /// /// Start the aliased CPU core. 597 /// 1:1 alias_start; 598 /// } 599 /// } 600 /// 601 /// # fn test2(io: Mmio<0x1000>) { 602 /// // Start the aliased `CPU0`, leaving its other fields untouched. 603 /// io.update(CPU_CTL_ALIAS::of::<Cpu0>(), |r| r.with_alias_start(true)); 604 /// # } 605 /// ``` 606 /// 607 /// ## Arrays of registers 608 /// 609 /// Some I/O areas contain consecutive registers that share the same field layout. These areas can 610 /// be defined as an array of identical registers, allowing them to be accessed by index with 611 /// compile-time or runtime bound checking: 612 /// 613 /// ```ignore 614 /// register! { 615 /// pub REGISTER_ARRAY(u8)[10, stride = 4] @ 0x100 { 616 /// ... 617 /// } 618 /// } 619 /// ``` 620 /// 621 /// This defines `REGISTER_ARRAY`, an array of 10 byte registers starting at offset `0x100`. Each 622 /// register is separated from its neighbor by 4 bytes. 623 /// 624 /// The `stride` parameter is optional; if unspecified, the registers are placed consecutively from 625 /// each other. 626 /// 627 /// A location for a register in a register array is built using the [`Array::at`] trait method. 628 /// All arrays of registers implement [`Array`]. 629 /// 630 /// ```no_run 631 /// use kernel::{ 632 /// io::{ 633 /// register, 634 /// register::Array, 635 /// Io, 636 /// }, 637 /// }; 638 /// # use kernel::io::Mmio; 639 /// # fn get_scratch_idx() -> usize { 640 /// # 0x15 641 /// # } 642 /// 643 /// // Array of 64 consecutive registers with the same layout starting at offset `0x80`. 644 /// register! { 645 /// /// Scratch registers. 646 /// pub SCRATCH(u32)[64] @ 0x00000080 { 647 /// 31:0 value; 648 /// } 649 /// } 650 /// 651 /// # fn test(io: &Mmio<0x1000>) 652 /// # -> Result<(), Error>{ 653 /// // Read scratch register 0, i.e. I/O address `0x80`. 654 /// let scratch_0 = io.read(SCRATCH::at(0)).value(); 655 /// 656 /// // Write scratch register 15, i.e. I/O address `0x80 + (15 * 4)`. 657 /// io.write(Array::at(15), SCRATCH::from(0xffeeaabb)); 658 /// 659 /// // This is out of bounds and won't build. 660 /// // let scratch_128 = io.read(SCRATCH::at(128)).value(); 661 /// 662 /// // Runtime-obtained array index. 663 /// let idx = get_scratch_idx(); 664 /// // Access on a runtime index returns an error if it is out-of-bounds. 665 /// let some_scratch = io.read(SCRATCH::try_at(idx).ok_or(EINVAL)?).value(); 666 /// 667 /// // Alias to a specific register in an array. 668 /// // Here `SCRATCH[8]` is used to convey the firmware exit code. 669 /// register! { 670 /// /// Firmware exit status code. 671 /// pub FIRMWARE_STATUS(u32) => SCRATCH[8] { 672 /// 7:0 status; 673 /// } 674 /// } 675 /// 676 /// let status = io.read(FIRMWARE_STATUS).status(); 677 /// 678 /// // Non-contiguous register arrays can be defined by adding a stride parameter. 679 /// // Here, each of the 16 registers of the array is separated by 8 bytes, meaning that the 680 /// // registers of the two declarations below are interleaved. 681 /// register! { 682 /// /// Scratch registers bank 0. 683 /// pub SCRATCH_INTERLEAVED_0(u32)[16, stride = 8] @ 0x000000c0 { 684 /// 31:0 value; 685 /// } 686 /// 687 /// /// Scratch registers bank 1. 688 /// pub SCRATCH_INTERLEAVED_1(u32)[16, stride = 8] @ 0x000000c4 { 689 /// 31:0 value; 690 /// } 691 /// } 692 /// # Ok(()) 693 /// # } 694 /// ``` 695 /// 696 /// ## Relative arrays of registers 697 /// 698 /// Combining the two features described in the sections above, arrays of registers accessible from 699 /// a base can also be defined: 700 /// 701 /// ```ignore 702 /// register! { 703 /// pub RELATIVE_REGISTER_ARRAY(u8)[10, stride = 4] @ Base + 0x100 { 704 /// ... 705 /// } 706 /// } 707 /// ``` 708 /// 709 /// Like relative registers, they implement the [`WithBase`] trait. However the return value of 710 /// [`WithBase::of`] cannot be used directly as a location and must be further specified using the 711 /// [`at`](RelativeRegisterLoc::at) method. 712 /// 713 /// ```no_run 714 /// use kernel::{ 715 /// io::{ 716 /// register, 717 /// register::{ 718 /// RegisterBase, 719 /// WithBase, 720 /// }, 721 /// Io, 722 /// }, 723 /// }; 724 /// # use kernel::io::Mmio; 725 /// # fn get_scratch_idx() -> usize { 726 /// # 0x15 727 /// # } 728 /// 729 /// // Type used as parameter of `RegisterBase` to specify the base. 730 /// pub struct CpuCtlBase; 731 /// 732 /// // ZST describing `CPU0`. 733 /// struct Cpu0; 734 /// impl RegisterBase<CpuCtlBase> for Cpu0 { 735 /// const BASE: usize = 0x100; 736 /// } 737 /// 738 /// // ZST describing `CPU1`. 739 /// struct Cpu1; 740 /// impl RegisterBase<CpuCtlBase> for Cpu1 { 741 /// const BASE: usize = 0x200; 742 /// } 743 /// 744 /// // 64 per-cpu scratch registers, arranged as a contiguous array. 745 /// register! { 746 /// /// Per-CPU scratch registers. 747 /// pub CPU_SCRATCH(u32)[64] @ CpuCtlBase + 0x00000080 { 748 /// 31:0 value; 749 /// } 750 /// } 751 /// 752 /// # fn test(io: &Mmio<0x1000>) -> Result<(), Error> { 753 /// // Read scratch register 0 of CPU0. 754 /// let scratch = io.read(CPU_SCRATCH::of::<Cpu0>().at(0)); 755 /// 756 /// // Write the retrieved value into scratch register 15 of CPU1. 757 /// io.write(WithBase::of::<Cpu1>().at(15), scratch); 758 /// 759 /// // This won't build. 760 /// // let cpu0_scratch_128 = io.read(CPU_SCRATCH::of::<Cpu0>().at(128)).value(); 761 /// 762 /// // Runtime-obtained array index. 763 /// let scratch_idx = get_scratch_idx(); 764 /// // Access on a runtime index returns an error if it is out-of-bounds. 765 /// let cpu0_scratch = io.read( 766 /// CPU_SCRATCH::of::<Cpu0>().try_at(scratch_idx).ok_or(EINVAL)? 767 /// ).value(); 768 /// # Ok(()) 769 /// # } 770 /// 771 /// // Alias to `SCRATCH[8]` used to convey the firmware exit code. 772 /// register! { 773 /// /// Per-CPU firmware exit status code. 774 /// pub CPU_FIRMWARE_STATUS(u32) => CpuCtlBase + CPU_SCRATCH[8] { 775 /// 7:0 status; 776 /// } 777 /// } 778 /// 779 /// // Non-contiguous relative register arrays can be defined by adding a stride parameter. 780 /// // Here, each of the 16 registers of the array is separated by 8 bytes, meaning that the 781 /// // registers of the two declarations below are interleaved. 782 /// register! { 783 /// /// Scratch registers bank 0. 784 /// pub CPU_SCRATCH_INTERLEAVED_0(u32)[16, stride = 8] @ CpuCtlBase + 0x00000d00 { 785 /// 31:0 value; 786 /// } 787 /// 788 /// /// Scratch registers bank 1. 789 /// pub CPU_SCRATCH_INTERLEAVED_1(u32)[16, stride = 8] @ CpuCtlBase + 0x00000d04 { 790 /// 31:0 value; 791 /// } 792 /// } 793 /// 794 /// # fn test2(io: &Mmio<0x1000>) -> Result<(), Error> { 795 /// let cpu0_status = io.read(CPU_FIRMWARE_STATUS::of::<Cpu0>()).status(); 796 /// # Ok(()) 797 /// # } 798 /// ``` 799 #[macro_export] 800 macro_rules! register { 801 // Entry point for the macro, allowing multiple registers to be defined in one call. 802 // It matches all possible register declaration patterns to dispatch them to corresponding 803 // `@reg` rule that defines a single register. 804 ( 805 $( 806 $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) 807 $([ $size:expr $(, stride = $stride:expr)? ])? 808 $(@ $($base:ident +)? $offset:literal)? 809 $(=> $alias:ident $(+ $alias_offset:ident)? $([$alias_idx:expr])? )? 810 { $($fields:tt)* } 811 )* 812 ) => { 813 $( 814 $crate::register!( 815 @reg $(#[$attr])* $vis $name ($storage) $([$size $(, stride = $stride)?])? 816 $(@ $($base +)? $offset)? 817 $(=> $alias $(+ $alias_offset)? $([$alias_idx])? )? 818 { $($fields)* } 819 ); 820 )* 821 }; 822 823 // All the rules below are private helpers. 824 825 // Creates a register at a fixed offset of the MMIO space. 826 ( 827 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $offset:literal 828 { $($fields:tt)* } 829 ) => { 830 $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 831 $crate::register!(@io_base $name($storage) @ $offset); 832 $crate::register!(@io_fixed $(#[$attr])* $vis $name($storage)); 833 }; 834 835 // Creates an alias register of fixed offset register `alias` with its own fields. 836 ( 837 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $alias:ident 838 { $($fields:tt)* } 839 ) => { 840 $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 841 $crate::register!( 842 @io_base $name($storage) @ 843 <$alias as $crate::io::register::Register>::OFFSET 844 ); 845 $crate::register!(@io_fixed $(#[$attr])* $vis $name($storage)); 846 }; 847 848 // Creates a register at a relative offset from a base address provider. 849 ( 850 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $base:ident + $offset:literal 851 { $($fields:tt)* } 852 ) => { 853 $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 854 $crate::register!(@io_base $name($storage) @ $offset); 855 $crate::register!(@io_relative $vis $name($storage) @ $base); 856 }; 857 858 // Creates an alias register of relative offset register `alias` with its own fields. 859 ( 860 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $base:ident + $alias:ident 861 { $($fields:tt)* } 862 ) => { 863 $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 864 $crate::register!( 865 @io_base $name($storage) @ <$alias as $crate::io::register::Register>::OFFSET 866 ); 867 $crate::register!(@io_relative $vis $name($storage) @ $base); 868 }; 869 870 // Creates an array of registers at a fixed offset of the MMIO space. 871 ( 872 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) 873 [ $size:expr, stride = $stride:expr ] @ $offset:literal { $($fields:tt)* } 874 ) => { 875 ::kernel::static_assert!(::core::mem::size_of::<$storage>() <= $stride); 876 877 $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 878 $crate::register!(@io_base $name($storage) @ $offset); 879 $crate::register!(@io_array $vis $name($storage) [ $size, stride = $stride ]); 880 }; 881 882 // Shortcut for contiguous array of registers (stride == size of element). 883 ( 884 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) [ $size:expr ] @ $offset:literal 885 { $($fields:tt)* } 886 ) => { 887 $crate::register!( 888 $(#[$attr])* $vis $name($storage) [ $size, stride = ::core::mem::size_of::<$storage>() ] 889 @ $offset { $($fields)* } 890 ); 891 }; 892 893 // Creates an alias of register `idx` of array of registers `alias` with its own fields. 894 ( 895 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $alias:ident [ $idx:expr ] 896 { $($fields:tt)* } 897 ) => { 898 ::kernel::static_assert!($idx < <$alias as $crate::io::register::RegisterArray>::SIZE); 899 900 $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 901 $crate::register!( 902 @io_base $name($storage) @ 903 <$alias as $crate::io::register::Register>::OFFSET 904 + $idx * <$alias as $crate::io::register::RegisterArray>::STRIDE 905 ); 906 $crate::register!(@io_fixed $(#[$attr])* $vis $name($storage)); 907 }; 908 909 // Creates an array of registers at a relative offset from a base address provider. 910 ( 911 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) 912 [ $size:expr, stride = $stride:expr ] 913 @ $base:ident + $offset:literal { $($fields:tt)* } 914 ) => { 915 ::kernel::static_assert!(::core::mem::size_of::<$storage>() <= $stride); 916 917 $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 918 $crate::register!(@io_base $name($storage) @ $offset); 919 $crate::register!( 920 @io_relative_array $vis $name($storage) [ $size, stride = $stride ] @ $base + $offset 921 ); 922 }; 923 924 // Shortcut for contiguous array of relative registers (stride == size of element). 925 ( 926 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) [ $size:expr ] 927 @ $base:ident + $offset:literal { $($fields:tt)* } 928 ) => { 929 $crate::register!( 930 $(#[$attr])* $vis $name($storage) [ $size, stride = ::core::mem::size_of::<$storage>() ] 931 @ $base + $offset { $($fields)* } 932 ); 933 }; 934 935 // Creates an alias of register `idx` of relative array of registers `alias` with its own 936 // fields. 937 ( 938 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) 939 => $base:ident + $alias:ident [ $idx:expr ] { $($fields:tt)* } 940 ) => { 941 ::kernel::static_assert!($idx < <$alias as $crate::io::register::RegisterArray>::SIZE); 942 943 $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 944 $crate::register!( 945 @io_base $name($storage) @ 946 <$alias as $crate::io::register::Register>::OFFSET + 947 $idx * <$alias as $crate::io::register::RegisterArray>::STRIDE 948 ); 949 $crate::register!(@io_relative $vis $name($storage) @ $base); 950 }; 951 952 // Generates the bitfield for the register. 953 // 954 // `#[allow(non_camel_case_types)]` is added since register names typically use 955 // `SCREAMING_CASE`. 956 ( 957 @bitfield $(#[$attr:meta])* $vis:vis struct $name:ident($storage:ty) { $($fields:tt)* } 958 ) => { 959 $crate::register!(@bitfield_core 960 #[allow(non_camel_case_types)] 961 $(#[$attr])* $vis $name $storage 962 ); 963 $crate::register!(@bitfield_fields $vis $name $storage { $($fields)* }); 964 }; 965 966 // Implementations shared by all registers types. 967 (@io_base $name:ident($storage:ty) @ $offset:expr) => { 968 impl $crate::io::register::Register for $name { 969 type Storage = $storage; 970 971 const OFFSET: usize = $offset; 972 } 973 }; 974 975 // Implementations of fixed registers. 976 (@io_fixed $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)) => { 977 impl $crate::io::register::FixedRegister for $name {} 978 979 $(#[$attr])* 980 $vis const $name: $crate::io::register::FixedRegisterLoc<$name> = 981 $crate::io::register::FixedRegisterLoc::<$name>::new(); 982 }; 983 984 // Implementations of relative registers. 985 (@io_relative $vis:vis $name:ident ($storage:ty) @ $base:ident) => { 986 impl $crate::io::register::WithBase for $name { 987 type BaseFamily = $base; 988 } 989 990 impl $crate::io::register::RelativeRegister for $name {} 991 }; 992 993 // Implementations of register arrays. 994 (@io_array $vis:vis $name:ident ($storage:ty) [ $size:expr, stride = $stride:expr ]) => { 995 impl $crate::io::register::Array for $name {} 996 997 impl $crate::io::register::RegisterArray for $name { 998 const SIZE: usize = $size; 999 const STRIDE: usize = $stride; 1000 } 1001 }; 1002 1003 // Implementations of relative array registers. 1004 ( 1005 @io_relative_array $vis:vis $name:ident ($storage:ty) [ $size:expr, stride = $stride:expr ] 1006 @ $base:ident + $offset:literal 1007 ) => { 1008 impl $crate::io::register::WithBase for $name { 1009 type BaseFamily = $base; 1010 } 1011 1012 impl $crate::io::register::RegisterArray for $name { 1013 const SIZE: usize = $size; 1014 const STRIDE: usize = $stride; 1015 } 1016 1017 impl $crate::io::register::RelativeRegisterArray for $name {} 1018 }; 1019 1020 // Defines the wrapper `$name` type and its conversions from/to the storage type. 1021 (@bitfield_core $(#[$attr:meta])* $vis:vis $name:ident $storage:ty) => { 1022 $(#[$attr])* 1023 #[repr(transparent)] 1024 #[derive(Clone, Copy, PartialEq, Eq)] 1025 $vis struct $name { 1026 inner: $storage, 1027 } 1028 1029 #[allow(dead_code)] 1030 impl $name { 1031 /// Creates a bitfield from a raw value. 1032 #[inline(always)] 1033 $vis const fn from_raw(value: $storage) -> Self { 1034 Self{ inner: value } 1035 } 1036 1037 /// Turns this bitfield into its raw value. 1038 /// 1039 /// This is similar to the [`From`] implementation, but is shorter to invoke in 1040 /// most cases. 1041 #[inline(always)] 1042 $vis const fn into_raw(self) -> $storage { 1043 self.inner 1044 } 1045 } 1046 1047 // SAFETY: `$storage` is `Zeroable` and `$name` is transparent. 1048 unsafe impl ::pin_init::Zeroable for $name {} 1049 1050 impl ::core::convert::From<$name> for $storage { 1051 #[inline(always)] 1052 fn from(val: $name) -> $storage { 1053 val.into_raw() 1054 } 1055 } 1056 1057 impl ::core::convert::From<$storage> for $name { 1058 #[inline(always)] 1059 fn from(val: $storage) -> $name { 1060 Self::from_raw(val) 1061 } 1062 } 1063 }; 1064 1065 // Definitions requiring knowledge of individual fields: private and public field accessors, 1066 // and `Debug` implementation. 1067 (@bitfield_fields $vis:vis $name:ident $storage:ty { 1068 $($(#[doc = $doc:expr])* $hi:literal:$lo:literal $field:ident 1069 $(?=> $try_into_type:ty)? 1070 $(=> $into_type:ty)? 1071 ; 1072 )* 1073 } 1074 ) => { 1075 #[allow(dead_code)] 1076 impl $name { 1077 $( 1078 $crate::register!(@private_field_accessors $vis $name $storage : $hi:$lo $field); 1079 $crate::register!( 1080 @public_field_accessors $(#[doc = $doc])* $vis $name $storage : $hi:$lo $field 1081 $(?=> $try_into_type)? 1082 $(=> $into_type)? 1083 ); 1084 )* 1085 } 1086 1087 $crate::register!(@debug $name { $($field;)* }); 1088 }; 1089 1090 // Private field accessors working with the exact `Bounded` type for the field. 1091 ( 1092 @private_field_accessors $vis:vis $name:ident $storage:ty : $hi:tt:$lo:tt $field:ident 1093 ) => { 1094 ::kernel::macros::paste!( 1095 $vis const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi; 1096 $vis const [<$field:upper _MASK>]: $storage = 1097 ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1); 1098 $vis const [<$field:upper _SHIFT>]: u32 = $lo; 1099 ); 1100 1101 ::kernel::macros::paste!( 1102 fn [<__ $field>](self) -> 1103 ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> { 1104 // Left shift to align the field's MSB with the storage MSB. 1105 const ALIGN_TOP: u32 = $storage::BITS - ($hi + 1); 1106 // Right shift to move the top-aligned field to bit 0 of the storage. 1107 const ALIGN_BOTTOM: u32 = ALIGN_TOP + $lo; 1108 1109 // Extract the field using two shifts. `Bounded::shr` produces the correctly-sized 1110 // output type. 1111 let val = ::kernel::num::Bounded::<$storage, { $storage::BITS }>::from( 1112 self.inner << ALIGN_TOP 1113 ); 1114 val.shr::<ALIGN_BOTTOM, { $hi + 1 - $lo } >() 1115 } 1116 1117 const fn [<__with_ $field>]( 1118 mut self, 1119 value: ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>, 1120 ) -> Self 1121 { 1122 const MASK: $storage = <$name>::[<$field:upper _MASK>]; 1123 const SHIFT: u32 = <$name>::[<$field:upper _SHIFT>]; 1124 1125 let value = value.get() << SHIFT; 1126 self.inner = (self.inner & !MASK) | value; 1127 1128 self 1129 } 1130 ); 1131 }; 1132 1133 // Public accessors for fields infallibly (`=>`) converted to a type. 1134 ( 1135 @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty : 1136 $hi:literal:$lo:literal $field:ident => $into_type:ty 1137 ) => { 1138 ::kernel::macros::paste!( 1139 1140 $(#[doc = $doc])* 1141 #[doc = "Returns the value of this field."] 1142 #[inline(always)] 1143 $vis fn $field(self) -> $into_type 1144 { 1145 self.[<__ $field>]().into() 1146 } 1147 1148 $(#[doc = $doc])* 1149 #[doc = "Sets this field to the given `value`."] 1150 #[inline(always)] 1151 $vis fn [<with_ $field>](self, value: $into_type) -> Self 1152 { 1153 self.[<__with_ $field>](value.into()) 1154 } 1155 1156 ); 1157 }; 1158 1159 // Public accessors for fields fallibly (`?=>`) converted to a type. 1160 ( 1161 @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty : 1162 $hi:tt:$lo:tt $field:ident ?=> $try_into_type:ty 1163 ) => { 1164 ::kernel::macros::paste!( 1165 1166 $(#[doc = $doc])* 1167 #[doc = "Returns the value of this field."] 1168 #[inline(always)] 1169 $vis fn $field(self) -> 1170 Result< 1171 $try_into_type, 1172 <$try_into_type as ::core::convert::TryFrom< 1173 ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> 1174 >>::Error 1175 > 1176 { 1177 self.[<__ $field>]().try_into() 1178 } 1179 1180 $(#[doc = $doc])* 1181 #[doc = "Sets this field to the given `value`."] 1182 #[inline(always)] 1183 $vis fn [<with_ $field>](self, value: $try_into_type) -> Self 1184 { 1185 self.[<__with_ $field>](value.into()) 1186 } 1187 1188 ); 1189 }; 1190 1191 // Public accessors for fields not converted to a type. 1192 ( 1193 @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty : 1194 $hi:tt:$lo:tt $field:ident 1195 ) => { 1196 ::kernel::macros::paste!( 1197 1198 $(#[doc = $doc])* 1199 #[doc = "Returns the value of this field."] 1200 #[inline(always)] 1201 $vis fn $field(self) -> 1202 ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> 1203 { 1204 self.[<__ $field>]() 1205 } 1206 1207 $(#[doc = $doc])* 1208 #[doc = "Sets this field to the compile-time constant `VALUE`."] 1209 #[inline(always)] 1210 $vis const fn [<with_const_ $field>]<const VALUE: $storage>(self) -> Self { 1211 self.[<__with_ $field>]( 1212 ::kernel::num::Bounded::<$storage, { $hi + 1 - $lo }>::new::<VALUE>() 1213 ) 1214 } 1215 1216 $(#[doc = $doc])* 1217 #[doc = "Sets this field to the given `value`."] 1218 #[inline(always)] 1219 $vis fn [<with_ $field>]<T>( 1220 self, 1221 value: T, 1222 ) -> Self 1223 where T: Into<::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>>, 1224 { 1225 self.[<__with_ $field>](value.into()) 1226 } 1227 1228 $(#[doc = $doc])* 1229 #[doc = "Tries to set this field to `value`, returning an error if it is out of range."] 1230 #[inline(always)] 1231 $vis fn [<try_with_ $field>]<T>( 1232 self, 1233 value: T, 1234 ) -> ::kernel::error::Result<Self> 1235 where T: ::kernel::num::TryIntoBounded<$storage, { $hi + 1 - $lo }>, 1236 { 1237 Ok( 1238 self.[<__with_ $field>]( 1239 value.try_into_bounded().ok_or(::kernel::error::code::EOVERFLOW)? 1240 ) 1241 ) 1242 } 1243 1244 ); 1245 }; 1246 1247 // `Debug` implementation. 1248 (@debug $name:ident { $($field:ident;)* }) => { 1249 impl ::kernel::fmt::Debug for $name { 1250 fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result { 1251 f.debug_struct(stringify!($name)) 1252 .field("<raw>", &::kernel::prelude::fmt!("{:#x}", self.inner)) 1253 $( 1254 .field(stringify!($field), &self.$field()) 1255 )* 1256 .finish() 1257 } 1258 } 1259 }; 1260 } 1261