|
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 | +//! - You must **NOT** use the `a1-a2` registers, as they are required later by the runtime. |
| 352 | +//! |
| 353 | +//! **Violating these constraints will result in incorrect arguments being passed to `main()`.** |
| 354 | +//! |
| 355 | +//! ### Implementation example |
| 356 | +//! |
| 357 | +//! The following example shows how to implement the `_mp_hook` function in assembly. |
| 358 | +//! |
| 359 | +//! ``` no_run |
| 360 | +//! core::arch::global_asm!( |
| 361 | +//! r#".section .init.mp_hook, "ax" |
| 362 | +//! .global _mp_hook |
| 363 | +//! _mp_hook: |
| 364 | +//! beqz a0, 2f // check if hartid is 0 |
| 365 | +//! 1: wfi // If not, wait for interrupt in a loop |
| 366 | +//! j 1b |
| 367 | +//! 2: li a0, 1 // Otherwise, return true |
| 368 | +//! ret |
| 369 | +//! "# |
| 370 | +//! ); |
| 371 | +//! ``` |
| 372 | +//! |
353 | 373 | //! ## `_setup_interrupts` |
354 | 374 | //! |
355 | 375 | //! This function is called right before the main function and is responsible for setting up |
|
506 | 526 | //! If the feature is enabled, the `__pre_init` function must be defined in the user code (i.e., no default implementation is |
507 | 527 | //! provided by this crate). If the feature is disabled, the `__pre_init` function is not required. |
508 | 528 | //! |
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. |
| 529 | +//! ### Important implementation guidelines |
| 530 | +//! |
| 531 | +//! This function is called during the early boot process. Thus, when implementing it, you **MUST** follow these guidelines: |
| 532 | +//! |
| 533 | +//! - Implement it in assembly (no Rust code is allowed at this point). |
| 534 | +//! - Allocate this function within the `.init` section. |
| 535 | +//! - You must **NOT** modify the `a1-a2` registers, as they are required later by the runtime. |
511 | 536 | //! |
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. |
| 537 | +//! **Violating these constraints will result in incorrect arguments being passed to `main()`.** |
| 538 | +//! |
| 539 | +//! ### Implementation example |
| 540 | +//! |
| 541 | +//! The following example shows how to implement the `__pre_init` function in assembly. |
| 542 | +//! |
| 543 | +//! ``` no_run |
| 544 | +//! core::arch::global_asm!( |
| 545 | +//! r#".section .init.__pre_init, "ax" |
| 546 | +//! .global __pre_init |
| 547 | +//! __pre_init: |
| 548 | +//! // Do some pre-initialization work here and return |
| 549 | +//! ret |
| 550 | +//! "# |
| 551 | +//! ); |
| 552 | +//! ``` |
515 | 553 | //! |
516 | 554 | //! ## `single-hart` |
517 | 555 | //! |
|
0 commit comments