|
5 | 5 | //!
|
6 | 6 | //! # Features
|
7 | 7 | //!
|
8 |
| -//! This crates takes care of: |
| 8 | +//! This crate takes care of: |
9 | 9 | //!
|
10 | 10 | //! - The memory layout of the program.
|
11 | 11 | //!
|
|
327 | 327 | //! Furthermore, as this function is expected to behave like a trap handler, it is
|
328 | 328 | //! necessary to make it be 4-byte aligned.
|
329 | 329 | //!
|
330 |
| -//! ## `_mp_hook` |
| 330 | +//! ## `_mp_hook` (for multi-core targets only) |
331 | 331 | //!
|
332 | 332 | //! This function is called from all the harts and must return true only for one hart,
|
333 | 333 | //! which will perform memory initialization. For other harts it must return false
|
334 | 334 | //! and implement wake-up in platform-dependent way (e.g., after waiting for a user interrupt).
|
335 |
| -//! The parameter `hartid` specifies the hartid of the caller. |
336 |
| -//! |
337 |
| -//! This function can be redefined in the following way: |
338 |
| -//! |
339 |
| -//! ``` no_run |
340 |
| -//! #[export_name = "_mp_hook"] |
341 |
| -//! pub extern "Rust" fn mp_hook(hartid: usize) -> bool { |
342 |
| -//! // ... |
343 |
| -//! } |
344 |
| -//! ``` |
345 | 335 | //!
|
346 | 336 | //! Default implementation of this function wakes hart 0 and busy-loops all the other harts.
|
347 | 337 | //!
|
|
350 | 340 | //! `_mp_hook` is only necessary in multi-core targets. If the `single-hart` feature is enabled,
|
351 | 341 | //! `_mp_hook` is not included in the binary.
|
352 | 342 | //!
|
| 343 | +//! ### Important implementation guidelines |
| 344 | +//! |
| 345 | +//! This function is called during the early boot process. Thus, when implementing it, you **MUST** follow these guidelines: |
| 346 | +//! |
| 347 | +//! - Implement it in assembly (no Rust code is allowed at this point). |
| 348 | +//! - Allocate this function within the `.init` section. |
| 349 | +//! - You can get the hart id from the `a0` register. |
| 350 | +//! - You must set the return value in the `a0` register. |
| 351 | +//! - Do **NOT** use callee-saved registers `s0-s2`, as they are used to preserve the initial values of `a0-a2` registers. |
| 352 | +//! - In RVE targets, do **NOT** use the `a5` register, as it is used to preserve the `a2` register. |
| 353 | +//! |
| 354 | +//! **Violating these constraints will result in incorrect arguments being passed to `main()`.** |
| 355 | +//! |
| 356 | +//! ### Implementation example |
| 357 | +//! |
| 358 | +//! The following example shows how to implement the `_mp_hook` function in assembly. |
| 359 | +//! |
| 360 | +//! ``` no_run |
| 361 | +//! core::arch::global_asm!( |
| 362 | +//! r#".section .init.mp_hook, "ax" |
| 363 | +//! .global _mp_hook |
| 364 | +//! _mp_hook: |
| 365 | +//! beqz a0, 2f // check if hartid is 0 |
| 366 | +//! 1: wfi // If not, wait for interrupt in a loop |
| 367 | +//! j 1b |
| 368 | +//! 2: li a0, 1 // Otherwise, return true |
| 369 | +//! ret |
| 370 | +//! "# |
| 371 | +//! ); |
| 372 | +//! ``` |
| 373 | +//! |
353 | 374 | //! ## `_setup_interrupts`
|
354 | 375 | //!
|
355 | 376 | //! This function is called right before the main function and is responsible for setting up
|
|
506 | 527 | //! If the feature is enabled, the `__pre_init` function must be defined in the user code (i.e., no default implementation is
|
507 | 528 | //! provided by this crate). If the feature is disabled, the `__pre_init` function is not required.
|
508 | 529 | //!
|
509 |
| -//! As `__pre_init` runs before RAM is initialised, it is not sound to use a Rust function for `__pre_init`, and |
510 |
| -//! instead it should typically be written in assembly using `global_asm` or an external assembly file. |
| 530 | +//! ### Important implementation guidelines |
| 531 | +//! |
| 532 | +//! This function is called during the early boot process. Thus, when implementing it, you **MUST** follow these guidelines: |
| 533 | +//! |
| 534 | +//! - Implement it in assembly (no Rust code is allowed at this point). |
| 535 | +//! - Allocate this function within the `.init` section. |
| 536 | +//! - Do **NOT** use callee-saved registers `s0-s2`, as they are used to preserve the initial values of `a0-a2` registers. |
| 537 | +//! - In RVE targets, do **NOT** use the `a5` register, as it is used to preserve the `a2` register. |
511 | 538 | //!
|
512 |
| -//! Alternatively, you can use the [`#[pre_init]`][attr-pre-init] attribute to define a pre-init function with Rust. |
513 |
| -//! Note that using this macro is discouraged, as it may lead to undefined behavior. |
514 |
| -//! We left this option for backwards compatibility, but it is subject to removal in the future. |
| 539 | +//! **Violating these constraints will result in incorrect arguments being passed to `main()`.** |
| 540 | +//! |
| 541 | +//! ### Implementation example |
| 542 | +//! |
| 543 | +//! The following example shows how to implement the `__pre_init` function in assembly. |
| 544 | +//! |
| 545 | +//! ``` no_run |
| 546 | +//! core::arch::global_asm!( |
| 547 | +//! r#".section .init.pre_init, "ax" |
| 548 | +//! .global __pre_init |
| 549 | +//! __pre_init: |
| 550 | +//! // Do some pre-initialization work here and return |
| 551 | +//! ret |
| 552 | +//! "# |
| 553 | +//! ); |
| 554 | +//! ``` |
515 | 555 | //!
|
516 | 556 | //! ## `single-hart`
|
517 | 557 | //!
|
|
0 commit comments