| 1 | |
| 2 |
|
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | |
| 17 | |
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 | |
| 25 | |
| 26 | |
| 27 | |
| 28 | |
| 29 | |
| 30 | |
| 31 | |
| 32 | |
| 33 | |
| 34 | |
| 35 | |
| 36 | |
| 37 | |
| 38 | |
| 39 | |
| 40 | |
| 41 | |
| 42 | |
| 43 | |
| 44 | |
| 45 | |
| 46 | |
| 47 | |
| 48 | |
| 49 | |
| 50 | |
| 51 | |
| 52 | |
| 53 | |
| 54 | |
| 55 | |
| 56 | |
| 57 | |
| 58 | |
| 59 | |
| 60 | |
| 61 | |
| 62 | |
| 63 | |
| 64 | |
| 65 | |
| 66 | |
| 67 | |
| 68 | |
| 69 | |
| 70 | |
| 71 | |
| 72 | |
| 73 | |
| 74 | |
| 75 | |
| 76 | |
| 77 | |
| 78 | |
| 79 | |
| 80 | |
| 81 | |
| 82 | |
| 83 | |
| 84 | |
| 85 | |
| 86 | |
| 87 | |
| 88 | |
| 89 | |
| 90 | |
| 91 | |
| 92 | |
| 93 | |
| 94 | |
| 95 | |
| 96 | |
| 97 | |
| 98 | |
| 99 | |
| 100 | |
| 101 | |
| 102 | |
| 103 | |
| 104 | |
| 105 | |
| 106 | |
| 107 | |
| 108 | |
| 109 | |
| 110 | |
| 111 | |
| 112 | |
| 113 | |
| 114 | |
| 115 | |
| 116 | |
| 117 | |
| 118 | |
| 119 | |
| 120 | |
| 121 | |
| 122 | |
| 123 | |
| 124 | |
| 125 | |
| 126 | |
| 127 | |
| 128 | |
| 129 | |
| 130 | |
| 131 | |
| 132 | |
| 133 | |
| 134 | |
| 135 | |
| 136 | |
| 137 | |
| 138 | |
| 139 | |
| 140 | |
| 141 | |
| 142 | |
| 143 | |
| 144 | |
| 145 | |
| 146 | |
| 147 | |
| 148 | |
| 149 | |
| 150 | |
| 151 | |
| 152 | |
| 153 | |
| 154 | |
| 155 | |
| 156 | |
| 157 | |
| 158 | |
| 159 | |
| 160 | |
| 161 | |
| 162 | |
| 163 | |
| 164 | |
| 165 | |
| 166 | |
| 167 | |
| 168 | |
| 169 | |
| 170 | |
| 171 | |
| 172 | |
| 173 | |
| 174 | |
| 175 | |
| 176 | |
| 177 | |
| 178 | |
| 179 | |
| 180 | |
| 181 | |
| 182 | |
| 183 | |
| 184 | |
| 185 | |
| 186 | |
| 187 | |
| 188 | |
| 189 | |
| 190 | |
| 191 | |
| 192 | |
| 193 | |
| 194 | |
| 195 | |
| 196 | |
| 197 | |
| 198 | |
| 199 | |
| 200 | |
| 201 | |
| 202 | |
| 203 | |
| 204 | |
| 205 | |
| 206 | |
| 207 | |
| 208 | |
| 209 | |
| 210 | |
| 211 | |
| 212 | |
| 213 | |
| 214 | |
| 215 | |
| 216 | |
| 217 | |
| 218 | |
| 219 | |
| 220 | |
| 221 | |
| 222 | |
| 223 | |
| 224 | |
| 225 | |
| 226 | |
| 227 | |
| 228 | |
| 229 | |
| 230 | |
| 231 | |
| 232 | |
| 233 | |
| 234 | |
| 235 | |
| 236 | |
| 237 | |
| 238 | |
| 239 | |
| 240 | |
| 241 | |
| 242 | |
| 243 | |
| 244 | |
| 245 | |
| 246 | |
| 247 | |
| 248 | |
| 249 | |
| 250 | |
| 251 | |
| 252 | |
| 253 | |
| 254 | |
| 255 | |
| 256 | |
| 257 | |
| 258 | |
| 259 | |
| 260 | |
| 261 | |
| 262 | |
| 263 | |
| 264 | |
| 265 | |
| 266 | |
| 267 | |
| 268 | |
| 269 | |
| 270 | |
| 271 | |
| 272 | |
| 273 | |
| 274 | |
| 275 | |
| 276 | |
| 277 | |
| 278 | |
| 279 | |
| 280 | |
| 281 | |
| 282 | |
| 283 | |
| 284 | |
| 285 | |
| 286 | |
| 287 |
|
| 288 | |
| 289 | |
| 290 | |
| 291 | #[macro_export]
|
| 292 | macro_rules! bitfield {
|
| 293 | |
| 294 | (
|
| 295 | $(#[$attr:meta])* $vis:vis struct $name:ident($storage:ty) { $($fields:tt)* }
|
| 296 | ) => {
|
| 297 | $crate::bitfield!(@core
|
| 298 | #[allow(non_camel_case_types)]
|
| 299 | $(#[$attr])* $vis $name $storage
|
| 300 | );
|
| 301 | $crate::bitfield!(@fields $vis $name $storage { $($fields)* });
|
| 302 | };
|
| 303 |
|
| 304 | // All rules below are helpers.
|
| 305 |
|
| 306 | // Defines the wrapper `$name` type and its conversions from/to the storage type.
|
| 307 | (@core $(#[$attr:meta])* $vis:vis $name:ident $storage:ty) => {
|
| 308 | $(#[$attr])*
|
| 309 | #[repr(transparent)]
|
| 310 | #[derive(Clone, Copy, PartialEq, Eq)]
|
| 311 | $vis struct $name {
|
| 312 | inner: $storage,
|
| 313 | }
|
| 314 |
|
| 315 | #[allow(dead_code)]
|
| 316 | impl $name {
|
| 317 | |
| 318 | #[inline(always)]
|
| 319 | $vis const fn from_raw(value: $storage) -> Self {
|
| 320 | Self{ inner: value }
|
| 321 | }
|
| 322 |
|
| 323 | |
| 324 | |
| 325 | |
| 326 | |
| 327 | #[inline(always)]
|
| 328 | $vis const fn into_raw(self) -> $storage {
|
| 329 | self.inner
|
| 330 | }
|
| 331 | }
|
| 332 |
|
| 333 | |
| 334 | unsafe impl ::pin_init::Zeroable for $name {}
|
| 335 |
|
| 336 | impl ::core::convert::From<$name> for $storage {
|
| 337 | #[inline(always)]
|
| 338 | fn from(val: $name) -> $storage {
|
| 339 | val.into_raw()
|
| 340 | }
|
| 341 | }
|
| 342 |
|
| 343 | impl ::core::convert::From<$storage> for $name {
|
| 344 | #[inline(always)]
|
| 345 | fn from(val: $storage) -> $name {
|
| 346 | Self::from_raw(val)
|
| 347 | }
|
| 348 | }
|
| 349 | };
|
| 350 |
|
| 351 | |
| 352 | |
| 353 | (@fields $vis:vis $name:ident $storage:ty {
|
| 354 | $($(#[doc = $doc:expr])* $hi:literal:$lo:literal $field:ident
|
| 355 | $(?=> $try_into_type:ty)?
|
| 356 | $(=> $into_type:ty)?
|
| 357 | ;
|
| 358 | )*
|
| 359 | }
|
| 360 | ) => {
|
| 361 | #[allow(dead_code)]
|
| 362 | impl $name {
|
| 363 | $(
|
| 364 | $crate::bitfield!(@private_field_accessors $vis $name $storage : $hi:$lo $field);
|
| 365 | $crate::bitfield!(
|
| 366 | @public_field_accessors $(#[doc = $doc])* $vis $name $storage : $hi:$lo $field
|
| 367 | $(?=> $try_into_type)?
|
| 368 | $(=> $into_type)?
|
| 369 | );
|
| 370 | )*
|
| 371 | }
|
| 372 |
|
| 373 | $crate::bitfield!(@debug $name { $($field;)* });
|
| 374 | };
|
| 375 |
|
| 376 | |
| 377 | (
|
| 378 | @private_field_accessors $vis:vis $name:ident $storage:ty : $hi:tt:$lo:tt $field:ident
|
| 379 | ) => {
|
| 380 | ::kernel::macros::paste!(
|
| 381 | $vis const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi;
|
| 382 | $vis const [<$field:upper _MASK>]: $storage =
|
| 383 | ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1);
|
| 384 | $vis const [<$field:upper _SHIFT>]: u32 = $lo;
|
| 385 | );
|
| 386 |
|
| 387 | ::kernel::macros::paste!(
|
| 388 | #[inline(always)]
|
| 389 | fn [<__ $field>](self) ->
|
| 390 | ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> {
|
| 391 | |
| 392 | const ALIGN_TOP: u32 = $storage::BITS - ($hi + 1);
|
| 393 | |
| 394 | const ALIGN_BOTTOM: u32 = ALIGN_TOP + $lo;
|
| 395 |
|
| 396 | |
| 397 | |
| 398 | let val = ::kernel::num::Bounded::<$storage, { $storage::BITS }>::from(
|
| 399 | self.inner << ALIGN_TOP
|
| 400 | );
|
| 401 | val.shr::<ALIGN_BOTTOM, { $hi + 1 - $lo } >()
|
| 402 | }
|
| 403 |
|
| 404 | #[inline(always)]
|
| 405 | const fn [<__with_ $field>](
|
| 406 | mut self,
|
| 407 | value: ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>,
|
| 408 | ) -> Self
|
| 409 | {
|
| 410 | const MASK: $storage = <$name>::[<$field:upper _MASK>];
|
| 411 | const SHIFT: u32 = <$name>::[<$field:upper _SHIFT>];
|
| 412 |
|
| 413 | let value = value.get() << SHIFT;
|
| 414 | self.inner = (self.inner & !MASK) | value;
|
| 415 |
|
| 416 | self
|
| 417 | }
|
| 418 | );
|
| 419 | };
|
| 420 |
|
| 421 | |
| 422 | (
|
| 423 | @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
|
| 424 | $hi:literal:$lo:literal $field:ident => $into_type:ty
|
| 425 | ) => {
|
| 426 | ::kernel::macros::paste!(
|
| 427 |
|
| 428 | $(#[doc = $doc])*
|
| 429 | #[doc = "Returns the value of this field."]
|
| 430 | #[inline(always)]
|
| 431 | $vis fn $field(self) -> $into_type
|
| 432 | {
|
| 433 | self.[<__ $field>]().into()
|
| 434 | }
|
| 435 |
|
| 436 | $(#[doc = $doc])*
|
| 437 | #[doc = "Sets this field to the given `value`."]
|
| 438 | #[inline(always)]
|
| 439 | $vis fn [<with_ $field>](self, value: $into_type) -> Self
|
| 440 | {
|
| 441 | self.[<__with_ $field>](value.into())
|
| 442 | }
|
| 443 |
|
| 444 | );
|
| 445 | };
|
| 446 |
|
| 447 | |
| 448 | (
|
| 449 | @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
|
| 450 | $hi:tt:$lo:tt $field:ident ?=> $try_into_type:ty
|
| 451 | ) => {
|
| 452 | ::kernel::macros::paste!(
|
| 453 |
|
| 454 | $(#[doc = $doc])*
|
| 455 | #[doc = "Returns the value of this field."]
|
| 456 | #[inline(always)]
|
| 457 | $vis fn $field(self) ->
|
| 458 | ::core::result::Result<
|
| 459 | $try_into_type,
|
| 460 | <$try_into_type as ::core::convert::TryFrom<
|
| 461 | ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>
|
| 462 | >>::Error
|
| 463 | >
|
| 464 | {
|
| 465 | self.[<__ $field>]().try_into()
|
| 466 | }
|
| 467 |
|
| 468 | $(#[doc = $doc])*
|
| 469 | #[doc = "Sets this field to the given `value`."]
|
| 470 | #[inline(always)]
|
| 471 | $vis fn [<with_ $field>](self, value: $try_into_type) -> Self
|
| 472 | {
|
| 473 | self.[<__with_ $field>](value.into())
|
| 474 | }
|
| 475 |
|
| 476 | );
|
| 477 | };
|
| 478 |
|
| 479 | |
| 480 | (
|
| 481 | @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
|
| 482 | $hi:tt:$lo:tt $field:ident
|
| 483 | ) => {
|
| 484 | ::kernel::macros::paste!(
|
| 485 |
|
| 486 | $(#[doc = $doc])*
|
| 487 | #[doc = "Returns the value of this field."]
|
| 488 | #[inline(always)]
|
| 489 | $vis fn $field(self) ->
|
| 490 | ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>
|
| 491 | {
|
| 492 | self.[<__ $field>]()
|
| 493 | }
|
| 494 |
|
| 495 | $(#[doc = $doc])*
|
| 496 | #[doc = "Sets this field to the compile-time constant `VALUE`."]
|
| 497 | #[inline(always)]
|
| 498 | $vis const fn [<with_const_ $field>]<const VALUE: $storage>(self) -> Self {
|
| 499 | self.[<__with_ $field>](
|
| 500 | ::kernel::num::Bounded::<$storage, { $hi + 1 - $lo }>::new::<VALUE>()
|
| 501 | )
|
| 502 | }
|
| 503 |
|
| 504 | $(#[doc = $doc])*
|
| 505 | #[doc = "Sets this field to the given `value`."]
|
| 506 | #[inline(always)]
|
| 507 | $vis fn [<with_ $field>]<T>(
|
| 508 | self,
|
| 509 | value: T,
|
| 510 | ) -> Self
|
| 511 | where T: ::core::convert::Into<::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>>,
|
| 512 | {
|
| 513 | self.[<__with_ $field>](value.into())
|
| 514 | }
|
| 515 |
|
| 516 | $(#[doc = $doc])*
|
| 517 | #[doc = "Tries to set this field to `value`, returning an error if it is out of range."]
|
| 518 | #[inline(always)]
|
| 519 | $vis fn [<try_with_ $field>]<T>(
|
| 520 | self,
|
| 521 | value: T,
|
| 522 | ) -> ::kernel::error::Result<Self>
|
| 523 | where T: ::kernel::num::TryIntoBounded<$storage, { $hi + 1 - $lo }>,
|
| 524 | {
|
| 525 | Ok(
|
| 526 | self.[<__with_ $field>](
|
| 527 | value.try_into_bounded().ok_or(::kernel::error::code::EOVERFLOW)?
|
| 528 | )
|
| 529 | )
|
| 530 | }
|
| 531 |
|
| 532 | );
|
| 533 | };
|
| 534 |
|
| 535 | |
| 536 | (@debug $name:ident { $($field:ident;)* }) => {
|
| 537 | impl ::kernel::fmt::Debug for $name {
|
| 538 | #[inline]
|
| 539 | fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {
|
| 540 | f.debug_struct(stringify!($name))
|
| 541 | .field("<raw>", &::kernel::prelude::fmt!("{:#x}", self.inner))
|
| 542 | $(
|
| 543 | .field(stringify!($field), &self.$field())
|
| 544 | )*
|
| 545 | .finish()
|
| 546 | }
|
| 547 | }
|
| 548 | };
|
| 549 | }
|
| 550 |
|
| 551 | #[cfg(CONFIG_RUST_BITFIELD_KUNIT_TEST)]
|
| 552 | #[::kernel::macros::kunit_tests(rust_kernel_bitfield)]
|
| 553 | mod tests {
|
| 554 | use core::convert::TryFrom;
|
| 555 |
|
| 556 | use pin_init::Zeroable;
|
| 557 |
|
| 558 | use kernel::num::Bounded;
|
| 559 |
|
| 560 | |
| 561 |
|
| 562 | #[derive(Debug, Clone, Copy, PartialEq)]
|
| 563 | enum MemoryType {
|
| 564 | Unmapped = 0,
|
| 565 | Normal = 1,
|
| 566 | Device = 2,
|
| 567 | Reserved = 3,
|
| 568 | }
|
| 569 |
|
| 570 | impl TryFrom<Bounded<u64, 4>> for MemoryType {
|
| 571 | type Error = u64;
|
| 572 | fn try_from(value: Bounded<u64, 4>) -> Result<Self, Self::Error> {
|
| 573 | match value.get() {
|
| 574 | 0 => Ok(MemoryType::Unmapped),
|
| 575 | 1 => Ok(MemoryType::Normal),
|
| 576 | 2 => Ok(MemoryType::Device),
|
| 577 | 3 => Ok(MemoryType::Reserved),
|
| 578 | _ => Err(value.get()),
|
| 579 | }
|
| 580 | }
|
| 581 | }
|
| 582 |
|
| 583 | impl From<MemoryType> for Bounded<u64, 4> {
|
| 584 | #[inline(always)]
|
| 585 | fn from(mt: MemoryType) -> Bounded<u64, 4> {
|
| 586 | Bounded::from_expr(mt as u64)
|
| 587 | }
|
| 588 | }
|
| 589 |
|
| 590 | #[derive(Debug, Clone, Copy, PartialEq)]
|
| 591 | enum Priority {
|
| 592 | Low = 0,
|
| 593 | Medium = 1,
|
| 594 | High = 2,
|
| 595 | Critical = 3,
|
| 596 | }
|
| 597 |
|
| 598 | impl From<Bounded<u16, 2>> for Priority {
|
| 599 | fn from(value: Bounded<u16, 2>) -> Self {
|
| 600 | match value & 0x3 {
|
| 601 | 0 => Priority::Low,
|
| 602 | 1 => Priority::Medium,
|
| 603 | 2 => Priority::High,
|
| 604 | _ => Priority::Critical,
|
| 605 | }
|
| 606 | }
|
| 607 | }
|
| 608 |
|
| 609 | impl From<Priority> for Bounded<u16, 2> {
|
| 610 | #[inline(always)]
|
| 611 | fn from(p: Priority) -> Bounded<u16, 2> {
|
| 612 | Bounded::from_expr(p as u16)
|
| 613 | }
|
| 614 | }
|
| 615 |
|
| 616 | bitfield! {
|
| 617 | struct TestU64(u64) {
|
| 618 | 63:63 field_63;
|
| 619 | 61:52 field_61_52;
|
| 620 | 51:16 field_51_16;
|
| 621 | 15:12 field_15_12 ?=> MemoryType;
|
| 622 | 11:9 field_11_9;
|
| 623 | 1:1 field_1;
|
| 624 | 0:0 field_0;
|
| 625 | }
|
| 626 | }
|
| 627 |
|
| 628 | bitfield! {
|
| 629 | struct TestU16(u16) {
|
| 630 | 15:8 field_15_8;
|
| 631 | 7:4 field_7_4; |
| 632 | 5:4 field_5_4 => Priority;
|
| 633 | 3:1 field_3_1;
|
| 634 | 0:0 field_0;
|
| 635 | }
|
| 636 | }
|
| 637 |
|
| 638 | bitfield! {
|
| 639 | struct TestU8(u8) {
|
| 640 | 7:0 field_7_0; |
| 641 | 7:4 field_7_4;
|
| 642 | 3:2 field_3_2;
|
| 643 | 1:1 field_1;
|
| 644 | 0:0 field_0;
|
| 645 | }
|
| 646 | }
|
| 647 |
|
| 648 | |
| 649 | #[test]
|
| 650 | fn test_basic_access() {
|
| 651 | |
| 652 | let mut val = TestU64::zeroed();
|
| 653 | assert_eq!(val.into_raw(), 0x0);
|
| 654 |
|
| 655 | val = val.with_field_0(true);
|
| 656 | assert!(val.field_0().into_bool());
|
| 657 | assert_eq!(val.into_raw(), 0x1);
|
| 658 |
|
| 659 | val = val.with_field_1(true);
|
| 660 | assert!(val.field_1().into_bool());
|
| 661 | val = val.with_field_1(false);
|
| 662 | assert!(!val.field_1().into_bool());
|
| 663 | assert_eq!(val.into_raw(), 0x1);
|
| 664 |
|
| 665 | val = val.with_const_field_11_9::<0x5>();
|
| 666 | assert_eq!(val.field_11_9(), 0x5);
|
| 667 | assert_eq!(val.into_raw(), 0xA01);
|
| 668 |
|
| 669 | val = val.with_const_field_51_16::<0x123456>();
|
| 670 | assert_eq!(val.field_51_16(), 0x123456);
|
| 671 | assert_eq!(val.into_raw(), 0x0012_3456_0A01);
|
| 672 |
|
| 673 | const MAX_FIELD_51_16: u64 = ::kernel::bits::genmask_u64(0..=35);
|
| 674 | val = val.with_const_field_51_16::<{ MAX_FIELD_51_16 }>();
|
| 675 | assert_eq!(val.field_51_16(), MAX_FIELD_51_16);
|
| 676 |
|
| 677 | val = val.with_const_field_61_52::<0x3FF>();
|
| 678 | assert_eq!(val.field_61_52(), 0x3FF);
|
| 679 |
|
| 680 | val = val.with_field_63(true);
|
| 681 | assert!(val.field_63().into_bool());
|
| 682 |
|
| 683 | |
| 684 | let mut val = TestU16::zeroed();
|
| 685 | assert_eq!(val.into_raw(), 0x0);
|
| 686 |
|
| 687 | val = val.with_field_0(true);
|
| 688 | assert!(val.field_0().into_bool());
|
| 689 | assert_eq!(val.into_raw(), 0x1);
|
| 690 |
|
| 691 | val = val.with_const_field_3_1::<0x5>();
|
| 692 | assert_eq!(val.field_3_1(), 0x5);
|
| 693 | assert_eq!(val.into_raw(), 0xB);
|
| 694 |
|
| 695 | val = val.with_const_field_7_4::<0xA>();
|
| 696 | assert_eq!(val.field_7_4(), 0xA);
|
| 697 | assert_eq!(val.into_raw(), 0xAB);
|
| 698 |
|
| 699 | val = val.with_const_field_15_8::<0x42>();
|
| 700 | assert_eq!(val.field_15_8(), 0x42);
|
| 701 | assert_eq!(val.into_raw(), 0x42AB);
|
| 702 |
|
| 703 | |
| 704 | let mut val = TestU8::zeroed();
|
| 705 | assert_eq!(val.into_raw(), 0x0);
|
| 706 |
|
| 707 | val = val.with_field_0(true);
|
| 708 | assert!(val.field_0().into_bool());
|
| 709 | assert_eq!(val.into_raw(), 0x1);
|
| 710 |
|
| 711 | val = val.with_field_1(true);
|
| 712 | assert!(val.field_1().into_bool());
|
| 713 | assert_eq!(val.into_raw(), 0x3);
|
| 714 |
|
| 715 | val = val.with_const_field_3_2::<0x3>();
|
| 716 | assert_eq!(val.field_3_2(), 0x3);
|
| 717 | assert_eq!(val.into_raw(), 0xF);
|
| 718 |
|
| 719 | val = val.with_const_field_7_4::<0xA>();
|
| 720 | assert_eq!(val.field_7_4(), 0xA);
|
| 721 | assert_eq!(val.into_raw(), 0xAF);
|
| 722 | }
|
| 723 |
|
| 724 | |
| 725 | #[test]
|
| 726 | fn test_infallible_conversion() {
|
| 727 | let mut val = TestU16::zeroed();
|
| 728 |
|
| 729 | val = val.with_field_5_4(Priority::Low);
|
| 730 | assert_eq!(val.field_5_4(), Priority::Low);
|
| 731 | assert_eq!(val.into_raw() & 0x30, 0x00);
|
| 732 |
|
| 733 | val = val.with_field_5_4(Priority::Medium);
|
| 734 | assert_eq!(val.field_5_4(), Priority::Medium);
|
| 735 | assert_eq!(val.into_raw() & 0x30, 0x10);
|
| 736 |
|
| 737 | val = val.with_field_5_4(Priority::High);
|
| 738 | assert_eq!(val.field_5_4(), Priority::High);
|
| 739 | assert_eq!(val.into_raw() & 0x30, 0x20);
|
| 740 |
|
| 741 | val = val.with_field_5_4(Priority::Critical);
|
| 742 | assert_eq!(val.field_5_4(), Priority::Critical);
|
| 743 | assert_eq!(val.into_raw() & 0x30, 0x30);
|
| 744 | }
|
| 745 |
|
| 746 | |
| 747 | #[test]
|
| 748 | fn test_fallible_conversion() {
|
| 749 | let mut val = TestU64::zeroed();
|
| 750 |
|
| 751 | val = val.with_field_15_12(MemoryType::Unmapped);
|
| 752 | assert_eq!(val.field_15_12(), Ok(MemoryType::Unmapped));
|
| 753 | val = val.with_field_15_12(MemoryType::Normal);
|
| 754 | assert_eq!(val.field_15_12(), Ok(MemoryType::Normal));
|
| 755 | val = val.with_field_15_12(MemoryType::Device);
|
| 756 | assert_eq!(val.field_15_12(), Ok(MemoryType::Device));
|
| 757 | val = val.with_field_15_12(MemoryType::Reserved);
|
| 758 | assert_eq!(val.field_15_12(), Ok(MemoryType::Reserved));
|
| 759 |
|
| 760 | |
| 761 | let raw = (val.into_raw() & !::kernel::bits::genmask_u64(12..=15)) | (0x7 << 12);
|
| 762 | assert_eq!(TestU64::from_raw(raw).field_15_12(), Err(0x7));
|
| 763 | }
|
| 764 |
|
| 765 | |
| 766 | #[test]
|
| 767 | fn test_overlapping_fields() {
|
| 768 | let mut val = TestU16::zeroed();
|
| 769 |
|
| 770 | val = val.with_field_5_4(Priority::High); |
| 771 | assert_eq!(val.field_5_4(), Priority::High);
|
| 772 | assert_eq!(val.field_7_4(), 0x2); |
| 773 |
|
| 774 | val = val.with_const_field_7_4::<0xF>();
|
| 775 | assert_eq!(val.field_7_4(), 0xF);
|
| 776 | assert_eq!(val.field_5_4(), Priority::Critical); |
| 777 |
|
| 778 | |
| 779 | let mut val = TestU8::zeroed()
|
| 780 | .with_field_0(true)
|
| 781 | .with_field_1(true)
|
| 782 | .with_const_field_3_2::<0x3>()
|
| 783 | .with_const_field_7_4::<0xA>();
|
| 784 | assert_eq!(val.into_raw(), 0xAF);
|
| 785 |
|
| 786 | val = val.with_field_7_0(0x55);
|
| 787 | assert_eq!(val.field_7_0(), 0x55);
|
| 788 | assert!(val.field_0().into_bool());
|
| 789 | assert!(!val.field_1().into_bool());
|
| 790 | assert_eq!(val.field_3_2(), 0x1);
|
| 791 | assert_eq!(val.field_7_4(), 0x5);
|
| 792 | }
|
| 793 |
|
| 794 | |
| 795 | #[test]
|
| 796 | fn test_unallocated_bits() {
|
| 797 | let gap_bits = (1u64 << 62) | 0x1FC;
|
| 798 |
|
| 799 | let set_all_fields = |val: TestU64| {
|
| 800 | val.with_field_63(true)
|
| 801 | .with_const_field_61_52::<0x155>()
|
| 802 | .with_const_field_51_16::<0x123456>()
|
| 803 | .with_field_15_12(MemoryType::Device)
|
| 804 | .with_const_field_11_9::<0x5>()
|
| 805 | .with_field_1(true)
|
| 806 | .with_field_0(true)
|
| 807 | };
|
| 808 |
|
| 809 | |
| 810 | let val = set_all_fields(TestU64::from_raw(0));
|
| 811 | assert_eq!(val.into_raw() & gap_bits, 0);
|
| 812 |
|
| 813 | |
| 814 | let val = set_all_fields(TestU64::from_raw(gap_bits));
|
| 815 | assert_eq!(val.into_raw() & gap_bits, gap_bits);
|
| 816 | }
|
| 817 |
|
| 818 | #[test]
|
| 819 | fn test_try_with() {
|
| 820 | let val = TestU64::zeroed().try_with_field_51_16(0x123456).unwrap();
|
| 821 | assert_eq!(val.field_51_16(), 0x123456);
|
| 822 |
|
| 823 | let err = TestU64::zeroed().try_with_field_51_16(u64::MAX);
|
| 824 | assert_eq!(err, Err(::kernel::error::code::EOVERFLOW));
|
| 825 |
|
| 826 | let val = TestU64::zeroed()
|
| 827 | .try_with_field_51_16(0xABCDEF)
|
| 828 | .and_then(|p| p.try_with_field_0(1))
|
| 829 | .unwrap();
|
| 830 | assert_eq!(val.field_51_16(), 0xABCDEF);
|
| 831 | assert!(val.field_0().into_bool());
|
| 832 | }
|
| 833 |
|
| 834 | |
| 835 | #[test]
|
| 836 | fn test_raw() {
|
| 837 | let raw: u64 = 0xBFF0_0000_3123_3E03;
|
| 838 | let val = TestU64::from_raw(raw);
|
| 839 | assert_eq!(u64::from(val), raw);
|
| 840 | assert!(val.field_0().into_bool());
|
| 841 | assert!(val.field_1().into_bool());
|
| 842 | assert_eq!(val.field_11_9(), 0x7);
|
| 843 | assert_eq!(val.field_51_16(), 0x3123);
|
| 844 | assert_eq!(val.field_15_12(), Ok(MemoryType::Reserved));
|
| 845 | assert_eq!(val.field_61_52(), 0x3FF);
|
| 846 | assert!(val.field_63().into_bool());
|
| 847 |
|
| 848 | let raw: u16 = 0x42AB;
|
| 849 | let val = TestU16::from_raw(raw);
|
| 850 | assert_eq!(u16::from(val), raw);
|
| 851 | assert!(val.field_0().into_bool());
|
| 852 | assert_eq!(val.field_3_1(), 0x5);
|
| 853 | assert_eq!(val.field_7_4(), 0xA);
|
| 854 | assert_eq!(val.field_15_8(), 0x42);
|
| 855 |
|
| 856 | let raw: u8 = 0xAF;
|
| 857 | let val = TestU8::from_raw(raw);
|
| 858 | assert_eq!(u8::from(val), raw);
|
| 859 | assert!(val.field_0().into_bool());
|
| 860 | assert!(val.field_1().into_bool());
|
| 861 | assert_eq!(val.field_3_2(), 0x3);
|
| 862 | assert_eq!(val.field_7_4(), 0xA);
|
| 863 | assert_eq!(val.field_7_0(), 0xAF);
|
| 864 | }
|
| 865 | }
|