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 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
//! 共享 RISC-V 内部函数
mod p;
pub use p::*;
use crate::arch::asm;
/// 生成 `PAUSE` 指令
///
/// PAUSE 指令是一个提示,指示当前 hart 的指令退出率应该暂时降低或暂停。
/// 其影响的持续时间必须有界,并且可以为零。
#[inline]
pub fn pause() {
unsafe { asm!(".insn i 0x0F, 0, x0, x0, 0x010", options(nomem, nostack)) }
}
/// 生成 `NOP` 指令
///
/// 除了推进 `pc` 和增加任何适用的性能计数器外,NOP 指令不会改变任何架构可见的状态。
///
#[inline]
pub fn nop() {
unsafe { asm!("nop", options(nomem, nostack)) }
}
/// 生成 `WFI` 指令
///
/// WFI 指令为实现提供了一个提示,即当前的 hart 可以暂停,直到可能需要服务中断。
///
/// 该指令是一个提示,合法的实现是简单地将 WFI 实现为 NOP。
#[inline]
pub unsafe fn wfi() {
asm!("wfi", options(nomem, nostack))
}
/// 生成 `FENCE.I` 指令
///
/// FENCE.I 指令可确保 RISC-V hart 上的后续指令提取将看到任何先前对同一 RISC-V hart 可见的数据存储。
///
///
/// FENCE.I 不确保其他 RISC-V hart 的指令提取会观察多处理器系统中本地 hart 的存储。
///
#[inline]
pub unsafe fn fence_i() {
asm!("fence.i", options(nostack))
}
/// 给定虚拟地址和地址空间的内存管理栅栏
///
/// 对于由整数参数 `asid` 标识的地址空间,栅栏命令仅对与参数 `vaddr` 中的虚拟地址相对应的叶页表条目进行读取和写入。对全局映射的访问没有排序。
/// 除了包含全局映射的条目外,该栅栏还使所有包含与参数 `vaddr` 中的虚拟地址相对应的叶页表条目并且匹配由整数参数 `asid` 标识的地址空间的所有地址转换缓存条目无效。
///
///
///
///
#[inline]
pub unsafe fn sfence_vma(vaddr: usize, asid: usize) {
asm!("sfence.vma {}, {}", in(reg) vaddr, in(reg) asid, options(nostack))
}
/// 给定虚拟地址的主管内存管理栅栏
///
/// 对于所有地址空间,栅栏命令仅对与参数 `vaddr` 中的虚拟地址相对应的叶页表条目进行读取和写入。
/// 对于所有地址空间,栅栏还使包含与参数 `vaddr` 中的虚拟地址相对应的叶页表条目的所有地址转换缓存条目无效。
///
///
#[inline]
pub unsafe fn sfence_vma_vaddr(vaddr: usize) {
asm!("sfence.vma {}, x0", in(reg) vaddr, options(nostack))
}
/// 给定地址空间的主管内存管理栅栏
///
/// 栅栏命令对任何级别的页表进行的所有读取和写入,但仅限于由整数参数 `asid` 标识的地址空间。
///
/// 对全局映射的访问没有排序。
/// 栅栏还使所有与整数参数 `asid` 标识的地址空间匹配的地址转换缓存条目无效,但包含外部映射的条目除外。
///
///
#[inline]
pub unsafe fn sfence_vma_asid(asid: usize) {
asm!("sfence.vma x0, {}", in(reg) asid, options(nostack))
}
/// 所有地址空间和虚拟地址的主管内存管理栅栏
///
/// 栅栏对所有地址空间的页表的任何级别进行的所有读取和写入排序。
///
/// 栅栏还使所有地址空间的所有地址转换缓存条目无效。
#[inline]
pub unsafe fn sfence_vma_all() {
asm!("sfence.vma", options(nostack))
}
/// 使给定虚拟地址和地址空间的主管转换缓存无效
///
/// 该指令使具有相同 `vaddr` 和 `asid` 值的 `SFENCE.VMA` 指令无效的任何地址转换缓存条目无效。
///
#[inline]
pub unsafe fn sinval_vma(vaddr: usize, asid: usize) {
// asm!("sinval.vma {}, {}", in(reg) vaddr, in(reg) asid, options(nostack))
asm!(".insn r 0x73, 0, 0x0B, x0, {}, {}", in(reg) vaddr, in(reg) asid, options(nostack))
}
/// 使给定虚拟地址的主管转换缓存无效
///
/// 该指令使具有相同 `vaddr` 和 `asid` 值的 `SFENCE.VMA` 指令无效的任何地址转换缓存条目无效。
///
#[inline]
pub unsafe fn sinval_vma_vaddr(vaddr: usize) {
asm!(".insn r 0x73, 0, 0x0B, x0, {}, x0", in(reg) vaddr, options(nostack))
}
/// 使给定地址空间的主管转换缓存无效
///
/// 该指令使具有相同 `vaddr` 和 `asid` 值的 `SFENCE.VMA` 指令无效的任何地址转换缓存条目无效。
///
#[inline]
pub unsafe fn sinval_vma_asid(asid: usize) {
asm!(".insn r 0x73, 0, 0x0B, x0, x0, {}", in(reg) asid, options(nostack))
}
/// 使所有地址空间和虚拟地址的主管转换缓存无效
///
/// 该指令使具有相同 `vaddr` 和 `asid` 值的 `SFENCE.VMA` 指令无效的任何地址转换缓存条目无效。
///
#[inline]
pub unsafe fn sinval_vma_all() {
asm!(".insn r 0x73, 0, 0x0B, x0, x0, x0", options(nostack))
}
/// 生成 `SFENCE.W.INVAL` 指令
///
/// 该指令保证对当前 RISC-V hart 已经可见的任何先前存储在同一 hart 执行的后续 `SINVAL.VMA` 指令之前排序。
///
#[inline]
pub unsafe fn sfence_w_inval() {
// asm!("sfence.w.inval", options(nostack))
asm!(".insn i 0x73, 0, x0, x0, 0x180", options(nostack))
}
/// 生成 `SFENCE.INVAL.IR` 指令
///
/// 该指令保证当前 hart 执行的任何先前的 SINVAL.VMA 指令在该 hart 对内存管理数据结构的后续隐式引用之前被排序。
///
#[inline]
pub unsafe fn sfence_inval_ir() {
// asm!("sfence.inval.ir", options(nostack))
asm!(".insn i 0x73, 0, x0, x0, 0x181", options(nostack))
}
/// 按有符号字节整数加载虚拟机内存
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 即,具有地址转换和保护以及字节序,适用于 VS 模式或 VU 模式下的内存访问。
///
/// 这个函数是不安全的,因为它通过 `HLV.B` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hlv_b(src: *const i8) -> i8 {
let value: i8;
asm!(".insn i 0x73, 0x4, {}, {}, 0x600", out(reg) value, in(reg) src, options(readonly, nostack));
value
}
/// 按无符号字节整数加载虚拟机内存
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 即,具有地址转换和保护以及字节序,适用于 VS 模式或 VU 模式下的内存访问。
///
/// 这个函数是不安全的,因为它通过 `HLV.BU` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hlv_bu(src: *const u8) -> u8 {
let value: u8;
asm!(".insn i 0x73, 0x4, {}, {}, 0x601", out(reg) value, in(reg) src, options(readonly, nostack));
value
}
/// 通过有符号的半整数加载虚拟机内存
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 即,具有地址转换和保护以及字节序,适用于 VS 模式或 VU 模式下的内存访问。
///
/// 这个函数是不安全的,因为它通过 `HLV.H` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hlv_h(src: *const i16) -> i16 {
let value: i16;
asm!(".insn i 0x73, 0x4, {}, {}, 0x640", out(reg) value, in(reg) src, options(readonly, nostack));
value
}
/// 按无符号半整数加载虚拟机内存
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 即,具有地址转换和保护以及字节序,适用于 VS 模式或 VU 模式下的内存访问。
///
/// 这个函数是不安全的,因为它通过 `HLV.HU` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hlv_hu(src: *const u16) -> u16 {
let value: u16;
asm!(".insn i 0x73, 0x4, {}, {}, 0x641", out(reg) value, in(reg) src, options(readonly, nostack));
value
}
/// 通过无符号半整数访问虚拟机指令
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 被读取的内存在地址转换的两个阶段都必须是可执行的,但不需要读取权限。
///
/// 这个函数是不安全的,因为它通过 `HLVX.HU` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hlvx_hu(src: *const u16) -> u16 {
let insn: u16;
asm!(".insn i 0x73, 0x4, {}, {}, 0x643", out(reg) insn, in(reg) src, options(readonly, nostack));
insn
}
/// 按有符号字整数加载虚拟机内存
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 即,具有地址转换和保护以及字节序,适用于 VS 模式或 VU 模式下的内存访问。
///
/// 这个函数是不安全的,因为它通过 `HLV.W` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hlv_w(src: *const i32) -> i32 {
let value: i32;
asm!(".insn i 0x73, 0x4, {}, {}, 0x680", out(reg) value, in(reg) src, options(readonly, nostack));
value
}
/// 通过无符号字整数访问虚拟机指令
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 被读取的内存在地址转换的两个阶段都必须是可执行的,但不需要读取权限。
///
/// 这个函数是不安全的,因为它通过 `HLVX.WU` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hlvx_wu(src: *const u32) -> u32 {
let insn: u32;
asm!(".insn i 0x73, 0x4, {}, {}, 0x683", out(reg) insn, in(reg) src, options(readonly, nostack));
insn
}
/// 按字节整数存储虚拟机内存
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 即,具有地址转换和保护以及字节序,适用于 VS 模式或 VU 模式下的内存访问。
///
/// 这个函数是不安全的,因为它通过 `HSV.B` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hsv_b(dst: *mut i8, src: i8) {
asm!(".insn r 0x73, 0x4, 0x31, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack));
}
/// 按半整数存储虚拟机内存
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 即,具有地址转换和保护以及字节序,适用于 VS 模式或 VU 模式下的内存访问。
///
/// 这个函数是不安全的,因为它通过 `HSV.H` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hsv_h(dst: *mut i16, src: i16) {
asm!(".insn r 0x73, 0x4, 0x33, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack));
}
/// 按字整数存储虚拟机内存
///
/// 该指令执行显式内存访问,就像 `V=1` 一样;
/// 即,具有地址转换和保护以及字节序,适用于 VS 模式或 VU 模式下的内存访问。
///
/// 这个函数是不安全的,因为它通过 `HSV.W` 指令访问虚拟 supervisor 或用户,这实际上是对任何内存地址的解引用。
///
///
#[inline]
pub unsafe fn hsv_w(dst: *mut i32, src: i32) {
asm!(".insn r 0x73, 0x4, 0x35, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack));
}
/// 给定来宾虚拟地址和来宾地址空间的管理程序内存管理栅栏
///
/// 保证在该 hart 为 VS 阶段地址转换完成指令的所有隐式读取之前,对当前 hart 已经可见的任何先前存储进行排序:
///
/// - 在 `HFENCE.VVMA` 之后,并且
/// - 当 `hgatp.VMID` 具有与执行 `HFENCE.VVMA` 时相同的设置时执行。
///
/// 这个栅栏指定了一个单一的客户虚拟地址和一个单一的客户地址空间标识符。
#[inline]
pub unsafe fn hfence_vvma(vaddr: usize, asid: usize) {
// asm!("hfence.vvma {}, {}", in(reg) vaddr, in(reg) asid)
asm!(".insn r 0x73, 0, 0x11, x0, {}, {}", in(reg) vaddr, in(reg) asid, options(nostack))
}
/// 给定来宾虚拟地址的管理程序内存管理栅栏
///
/// 保证在该 hart 为 VS 阶段地址转换完成指令的所有隐式读取之前,对当前 hart 已经可见的任何先前存储进行排序:
///
/// - 在 `HFENCE.VVMA` 之后,并且
/// - 当 `hgatp.VMID` 具有与执行 `HFENCE.VVMA` 时相同的设置时执行。
///
/// 此栅栏指定单个访客虚拟地址。
#[inline]
pub unsafe fn hfence_vvma_vaddr(vaddr: usize) {
asm!(".insn r 0x73, 0, 0x11, x0, {}, x0", in(reg) vaddr, options(nostack))
}
/// 给定来宾地址空间的管理程序内存管理栅栏
///
/// 保证在该 hart 为 VS 阶段地址转换完成指令的所有隐式读取之前,对当前 hart 已经可见的任何先前存储进行排序:
///
/// - 在 `HFENCE.VVMA` 之后,并且
/// - 当 `hgatp.VMID` 具有与执行 `HFENCE.VVMA` 时相同的设置时执行。
///
/// 这个栅栏指定了一个单一的客户地址空间标识符。
#[inline]
pub unsafe fn hfence_vvma_asid(asid: usize) {
asm!(".insn r 0x73, 0, 0x11, x0, x0, {}", in(reg) asid, options(nostack))
}
/// 所有来宾地址空间和来宾虚拟地址的管理程序内存管理栅栏
///
/// 保证在该 hart 为 VS 阶段地址转换完成指令的所有隐式读取之前,对当前 hart 已经可见的任何先前存储进行排序:
///
/// - 在 `HFENCE.VVMA` 之后,并且
/// - 当 `hgatp.VMID` 具有与执行 `HFENCE.VVMA` 时相同的设置时执行。
///
/// 此栅栏适用于任何访客地址空间和访客虚拟地址。
#[inline]
pub unsafe fn hfence_vvma_all() {
asm!(".insn r 0x73, 0, 0x11, x0, x0, x0", options(nostack))
}
/// 来宾物理地址和虚拟机的管理程序内存管理栅栏
///
/// 保证对当前 hart 已经可见的任何先前存储在该 hart 为跟在 HFENCE.GVMA 之后的指令的 G 级地址转换完成的所有隐式读取之前排序。
///
///
/// 这个栅栏指定了一个单一的来宾物理地址,**右移 2 位**,以及一个虚拟机标识符 (VMID) 的虚拟机。
///
#[inline]
pub unsafe fn hfence_gvma(gaddr: usize, vmid: usize) {
// asm!("hfence.gvma {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack))
asm!(".insn r 0x73, 0, 0x31, x0, {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack))
}
/// 来宾物理地址的虚拟机管理程序内存管理栅栏
///
/// 保证对当前 hart 已经可见的任何先前存储在该 hart 为跟在 HFENCE.GVMA 之后的指令的 G 级地址转换完成的所有隐式读取之前排序。
///
///
/// 这个栅栏指定了一个单一的访客物理地址; **物理地址应右移 2 位**。
#[inline]
pub unsafe fn hfence_gvma_gaddr(gaddr: usize) {
asm!(".insn r 0x73, 0, 0x31, x0, {}, x0", in(reg) gaddr, options(nostack))
}
/// 给定虚拟机的管理程序内存管理栅栏
///
/// 保证对当前 hart 已经可见的任何先前存储在该 hart 为跟在 HFENCE.GVMA 之后的指令的 G 级地址转换完成的所有隐式读取之前排序。
///
///
/// 此栅栏通过虚拟机标识符 (VMID) 指定单个虚拟机。
#[inline]
pub unsafe fn hfence_gvma_vmid(vmid: usize) {
asm!(".insn r 0x73, 0, 0x31, x0, x0, {}", in(reg) vmid, options(nostack))
}
/// 适用于所有虚拟机和来宾物理地址的管理程序内存管理栅栏
///
/// 保证对当前 hart 已经可见的任何先前存储在该 hart 为跟在 HFENCE.GVMA 之后的指令的 G 级地址转换完成的所有隐式读取之前排序。
///
///
/// 此栅栏指定所有来宾物理地址和所有虚拟机。
#[inline]
pub unsafe fn hfence_gvma_all() {
asm!(".insn r 0x73, 0, 0x31, x0, x0, x0", options(nostack))
}
/// 使给定来宾虚拟地址和来宾地址空间的管理程序转换缓存无效
///
/// 该指令使具有相同 `vaddr` 和 `asid` 值的 `HFENCE.VVMA` 指令无效的任何地址转换缓存条目无效。
///
///
/// 这个栅栏指定了一个单一的客户虚拟地址和一个单一的客户地址空间标识符。
#[inline]
pub unsafe fn hinval_vvma(vaddr: usize, asid: usize) {
// asm!("hinval.vvma {}, {}", in(reg) vaddr, in(reg) asid, options(nostack))
asm!(".insn r 0x73, 0, 0x13, x0, {}, {}", in(reg) vaddr, in(reg) asid, options(nostack))
}
/// 使给定来宾虚拟地址的管理程序转换缓存无效
///
/// 该指令使具有相同 `vaddr` 和 `asid` 值的 `HFENCE.VVMA` 指令无效的任何地址转换缓存条目无效。
///
///
/// 此栅栏指定单个访客虚拟地址。
#[inline]
pub unsafe fn hinval_vvma_vaddr(vaddr: usize) {
asm!(".insn r 0x73, 0, 0x13, x0, {}, x0", in(reg) vaddr, options(nostack))
}
/// 使给定来宾地址空间的管理程序转换缓存无效
///
/// 该指令使具有相同 `vaddr` 和 `asid` 值的 `HFENCE.VVMA` 指令无效的任何地址转换缓存条目无效。
///
///
/// 这个栅栏指定了一个单一的客户地址空间标识符。
#[inline]
pub unsafe fn hinval_vvma_asid(asid: usize) {
asm!(".insn r 0x73, 0, 0x13, x0, x0, {}", in(reg) asid, options(nostack))
}
/// 使所有来宾地址空间和来宾虚拟地址的管理程序转换缓存无效
///
/// 该指令使具有相同 `vaddr` 和 `asid` 值的 `HFENCE.VVMA` 指令无效的任何地址转换缓存条目无效。
///
///
/// 此栅栏适用于任何访客地址空间和访客虚拟地址。
#[inline]
pub unsafe fn hinval_vvma_all() {
asm!(".insn r 0x73, 0, 0x13, x0, x0, x0", options(nostack))
}
/// 使来宾物理地址和虚拟机的管理程序转换缓存无效
///
/// 该指令使具有相同 `gaddr` 和 `vmid` 值的 `HFENCE.GVMA` 指令无效的任何地址转换缓存条目无效。
///
///
/// 这个栅栏指定了一个单一的来宾物理地址,**右移 2 位**,以及一个虚拟机标识符 (VMID) 的虚拟机。
///
#[inline]
pub unsafe fn hinval_gvma(gaddr: usize, vmid: usize) {
// asm!("hinval.gvma {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack))
asm!(".insn r 0x73, 0, 0x33, x0, {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack))
}
/// 使来宾物理地址的管理程序转换缓存无效
///
/// 该指令使具有相同 `gaddr` 和 `vmid` 值的 `HFENCE.GVMA` 指令无效的任何地址转换缓存条目无效。
///
///
/// 这个栅栏指定了一个单一的访客物理地址; **物理地址应右移 2 位**。
#[inline]
pub unsafe fn hinval_gvma_gaddr(gaddr: usize) {
asm!(".insn r 0x73, 0, 0x33, x0, {}, x0", in(reg) gaddr, options(nostack))
}
/// 使给定虚拟机的管理程序转换缓存无效
///
/// 该指令使具有相同 `gaddr` 和 `vmid` 值的 `HFENCE.GVMA` 指令无效的任何地址转换缓存条目无效。
///
///
/// 此栅栏通过虚拟机标识符 (VMID) 指定单个虚拟机。
#[inline]
pub unsafe fn hinval_gvma_vmid(vmid: usize) {
asm!(".insn r 0x73, 0, 0x33, x0, x0, {}", in(reg) vmid, options(nostack))
}
/// 使所有虚拟机和来宾物理地址的管理程序转换缓存无效
///
/// 该指令使具有相同 `gaddr` 和 `vmid` 值的 `HFENCE.GVMA` 指令无效的任何地址转换缓存条目无效。
///
///
/// 此栅栏指定所有来宾物理地址和所有虚拟机。
#[inline]
pub unsafe fn hinval_gvma_all() {
asm!(".insn r 0x73, 0, 0x33, x0, x0, x0", options(nostack))
}
/// 读取浮点控制和状态寄存器 `fcsr`
///
/// 寄存器 `fcsr` 是一个 32 位的读写寄存器,它为浮点算术运算选择动态舍入模式并保存应计异常标志。
///
///
/// 根据 "F" Standard Extension for Single-Precision Floating-Point, Version 2.2,寄存器 `fcsr` 定义为:
///
/// | Bit index | Meaning |
/// |:----------|:--------|
/// | 0..=4 | Accrued Exceptions (`fflags`) |
/// | 5..=7 | Rounding Mode (`frm`) |
/// | 8..=31 | _Reserved_ |
///
/// 有关每个字段的定义,请访问 [`frrm`] 和 [`frflags`]。
///
/// [`frrm`]: fn.frrm.html
/// [`frflags`]: fn.frflags.html
///
#[inline]
pub fn frcsr() -> u32 {
let value: u32;
unsafe { asm!("frcsr {}", out(reg) value, options(nomem, nostack)) };
value
}
/// 交换浮点控制和状态寄存器 `fcsr`
///
/// 该函数通过复制要返回的原始值来交换 `fcsr` 中的值,然后将从输入变量 `value` 获得的新值写入 `fcsr`。
///
#[inline]
pub fn fscsr(value: u32) -> u32 {
let original: u32;
unsafe { asm!("fscsr {}, {}", out(reg) original, in(reg) value, options(nomem, nostack)) }
original
}
/// 读取浮点舍入模式的寄存器 `frm`
///
/// 根据 "F" 单精度浮点标准扩展,版本 2.2,舍入模式字段定义如下表所示:
///
///
/// | Rounding Mode | Mnemonic | Meaning |
/// |:-------------|:----------|:---------|
/// | 000 | RNE | Round to Nearest, ties to Even |
/// | 001 | RTZ | Round towards Zero |
/// | 010 | RDN | Round Down (towards −∞) |
/// | 011 | RUP | Round Up (towards +∞) |
/// | 100 | RMM | Round to Nearest, ties to Max Magnitude |
/// | 101 | | _Reserved for future use._ |
/// | 110 | | _Reserved for future use._ |
/// | 111 | DYN | In Rounding Mode register, _reserved_. |
#[inline]
pub fn frrm() -> u32 {
let value: u32;
unsafe { asm!("frrm {}", out(reg) value, options(nomem, nostack)) };
value
}
/// 交换浮点舍入模式的寄存器 `frm`
///
/// 该函数通过复制要返回的原始值来交换 `frm` 中的值,然后将从输入变量 `value` 的三个最低有效位获得的新值写入 `frm`。
///
///
#[inline]
pub fn fsrm(value: u32) -> u32 {
let original: u32;
unsafe { asm!("fsrm {}, {}", out(reg) original, in(reg) value, options(nomem, nostack)) }
original
}
/// 读取浮点应计异常标志寄存器 `fflags`
///
/// 累积的异常标志指示自上次由软件复位该字段以来在任何浮点算术指令上出现的异常情况。
///
///
/// 根据 "F" 单精度浮点标准扩展 2.2 版,应计异常标志定义为 5 位的位 vector。
/// 下表列出了每个二进制位的含义。
///
/// | Bit index | Mnemonic | Meaning |
/// |:--|:---|:-----------------|
/// | 4 | NV | Invalid Operation |
/// | 3 | DZ | Divide by Zero |
/// | 2 | OF | Overflow |
/// | 1 | UF | Underflow |
/// | 0 | NX | Inexact |
///
#[inline]
pub fn frflags() -> u32 {
let value: u32;
unsafe { asm!("frflags {}", out(reg) value, options(nomem, nostack)) };
value
}
/// 交换浮点累积异常标志寄存器 `fflags`
///
/// 该函数通过复制要返回的原始值来交换 `fflags` 中的值,然后将从输入变量 `value` 的五个最低有效位获得的新值写入 `fflags`。
///
///
#[inline]
pub fn fsflags(value: u32) -> u32 {
let original: u32;
unsafe { asm!("fsflags {}, {}", out(reg) original, in(reg) value, options(nomem, nostack)) }
original
}
/// SM3 哈希算法中使用的 `P0` 转换函数
///
/// 该函数包含在 `Zksh` 扩展中。它被定义为:
///
/// ```text
/// P0(X) = X ⊕ (X ≪ 9) ⊕ (X ≪ 17)
/// ```
///
/// 其中 `⊕` 表示 32 位异或,`≪ k` 表示左移 `k` 位。
///
/// 在 SM3 算法中,当压缩函数 `CF` 使用中间值 `TT2` 计算变量 `E` 一次迭代时,将 `P0` 转换作为 `E ← P0(TT2)` 用于后续处理。
///
///
/// 根据 RISC-V Cryptography Extensions, Volume I,该指令的执行延迟必须始终独立于它所操作的数据。
///
///
#[inline]
#[target_feature(enable = "zksh")]
pub fn sm3p0(x: u32) -> u32 {
let ans: u32;
unsafe { asm!("sm3p0 {}, {}", lateout(reg) ans, in(reg) x, options(pure, nomem, nostack)) };
ans
}
/// SM3 哈希算法中使用的 `P1` 转换函数
///
/// 该函数包含在 `Zksh` 扩展中。它被定义为:
///
/// ```text
/// P1(X) = X ⊕ (X ≪ 15) ⊕ (X ≪ 23)
/// ```
///
/// 其中 `⊕` 表示 32 位异或,`≪ k` 表示左移 `k` 位。
///
/// 在 SM3 算法中,`P1` 转换用于扩展消息,其中扩展词 `Wj` 可以从前面的词生成。
/// 整个过程可以用下面的伪代码来描述:
///
/// ```text
/// FOR j=16 TO 67
/// Wj ← P1(Wj−16 ⊕ Wj−9 ⊕ (Wj−3 ≪ 15)) ⊕ (Wj−13 ≪ 7) ⊕ Wj−6
/// ENDFOR
/// ```
///
/// 根据 RISC-V Cryptography Extensions, Volume I,该指令的执行延迟必须始终独立于它所操作的数据。
///
///
#[inline]
#[target_feature(enable = "zksh")]
pub fn sm3p1(x: u32) -> u32 {
let ans: u32;
unsafe { asm!("sm3p1 {}, {}", lateout(reg) ans, in(reg) x, options(pure, nomem, nostack)) };
ans
}
/// 加速 SM4 分组密码算法中的舍入函数 `F`
///
/// 该指令包含在扩展 `Zksed` 中。它被定义为:
///
/// ```text
/// SM4ED(x, a, BS) = x ⊕ T(ai)
/// ... where
/// ai = a.bytes[BS]
/// T(ai) = L(τ(ai))
/// bi = τ(ai) = SM4-S-Box(ai)
/// ci = L(bi) = bi ⊕ (bi ≪ 2) ⊕ (bi ≪ 10) ⊕ (bi ≪ 18) ⊕ (bi ≪ 24)
/// SM4ED = (ci ≪ (BS * 8)) ⊕ x
/// ```
///
/// 其中 `⊕` 表示 32 位异或,`≪ k` 表示左移 `k` 位。
/// 如上所述,`T` 是非线性 S-Box 转换 `τ` 和线性层转换 `L` 的组合转换。
///
/// 在 SM4 算法中,舍入函数 `F` 定义为:
///
/// ```text
/// F(x0, x1, x2, x3, rk) = x0 ⊕ T(x1 ⊕ x2 ⊕ x3 ⊕ rk)
/// ... where
/// T(A) = L(τ(A))
/// B = τ(A) = (SM4-S-Box(a0), SM4-S-Box(a1), SM4-S-Box(a2), SM4-S-Box(a3))
/// C = L(B) = B ⊕ (B ≪ 2) ⊕ (B ≪ 10) ⊕ (B ≪ 18) ⊕ (B ≪ 24)
/// ```
///
/// 它可以通过 `sm4ed` 指令来实现,例如:
///
/// ```no_run
/// # #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
/// # fn round_function(x0: u32, x1: u32, x2: u32, x3: u32, rk: u32) -> u32 {
/// # #[cfg(target_arch = "riscv32")] use core::arch::riscv32::sm4ed;
/// # #[cfg(target_arch = "riscv64")] use core::arch::riscv64::sm4ed;
/// let a = x1 ^ x2 ^ x3 ^ rk;
/// let c0 = sm4ed::<0>(x0, a);
/// let c1 = sm4ed::<1>(c0, a); // c1 代表 c[0..=1],等。
/// let c2 = sm4ed::<2>(c1, a);
/// let c3 = sm4ed::<3>(c2, a);
/// return c3; // c3 代表 c[0..=3]
/// # }
/// ```
///
/// 根据 RISC-V Cryptography Extensions, Volume I,该指令的执行延迟必须始终独立于它所操作的数据。
///
///
#[inline]
#[target_feature(enable = "zksed")]
pub fn sm4ed<const BS: u8>(x: u32, a: u32) -> u32 {
static_assert!(BS <= 3);
let ans: u32;
unsafe {
asm!("sm4ed {}, {}, {}, {}", lateout(reg) ans, in(reg) x, in(reg) a, const BS, options(pure, nomem, nostack))
};
ans
}
/// 加速 SM4 分组密码算法中的密钥调度操作
///
/// 该指令包含在扩展 `Zksed` 中。它被定义为:
///
/// ```text
/// SM4KS(x, k, BS) = x ⊕ T'(ki)
/// ... where
/// ki = k.bytes[BS]
/// T'(ki) = L'(τ(ki))
/// bi = τ(ki) = SM4-S-Box(ki)
/// ci = L'(bi) = bi ⊕ (bi ≪ 13) ⊕ (bi ≪ 23)
/// SM4KS = (ci ≪ (BS * 8)) ⊕ x
/// ```
///
/// 其中 `⊕` 表示 32 位异或,`≪ k` 表示左移 `k` 位。
/// 如上所述,`T'` 是非线性 S-Box 转换 `τ` 和替换线性层转换 `L'` 的组合转换。
///
/// 在 SM4 算法中,密钥调度定义为:
///
/// ```text
/// rk[i] = K[i+4] = K[i] ⊕ T'(K[i+1] ⊕ K[i+2] ⊕ K[i+3] ⊕ CK[i])
/// ... where
/// K[0..=3] = MK[0..=3] ⊕ FK[0..=3]
/// T'(K) = L'(τ(K))
/// B = τ(K) = (SM4-S-Box(k0), SM4-S-Box(k1), SM4-S-Box(k2), SM4-S-Box(k3))
/// C = L'(B) = B ⊕ (B ≪ 13) ⊕ (B ≪ 23)
/// ```
///
/// 其中 `MK` 表示 128 位加密密钥,常量 `FK` 和 `CK` 是由 SM4 算法定义的固定系统配置特性值。
///
/// 因此,按键调度操作可以通过 `sm4ks` 指令来实现,例如:
///
/// ```no_run
/// # #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
/// # fn key_schedule(k0: u32, k1: u32, k2: u32, k3: u32, ck_i: u32) -> u32 {
/// # #[cfg(target_arch = "riscv32")] use core::arch::riscv32::sm4ks;
/// # #[cfg(target_arch = "riscv64")] use core::arch::riscv64::sm4ks;
/// let k = k1 ^ k2 ^ k3 ^ ck_i;
/// let c0 = sm4ks::<0>(k0, k);
/// let c1 = sm4ks::<1>(c0, k); // c1 代表 c[0..=1],等。
/// let c2 = sm4ks::<2>(c1, k);
/// let c3 = sm4ks::<3>(c2, k);
/// return c3; // c3 代表 c[0..=3]
/// # }
/// ```
///
/// 根据 RISC-V Cryptography Extensions, Volume I,该指令的执行延迟必须始终独立于它所操作的数据。
///
///
#[inline]
#[target_feature(enable = "zksed")]
pub fn sm4ks<const BS: u8>(x: u32, k: u32) -> u32 {
static_assert!(BS <= 3);
let ans: u32;
unsafe {
asm!("sm4ks {}, {}, {}, {}", lateout(reg) ans, in(reg) x, in(reg) k, const BS, options(pure, nomem, nostack))
};
ans
}