Vystem 0.2
This commit is contained in:
35
docs/shelter/devs/integrated/ioapic.md
Normal file
35
docs/shelter/devs/integrated/ioapic.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# IOAPIC devices
|
||||
|
||||
This driver is defined inside `shelter/lib/include/devs/apic/ioapic.h` and implemented inside `shelter/lib/src/devs/apic/ioapic.c`.
|
||||
|
||||
## Driver initialization
|
||||
|
||||
During the MADT parsing, all IOAPIC entries are counted. Then, a call to `sh_ioapic_init_devs(sh_uint8 max_lapic_id)` is made to initialize the driver internal state. This call allocates an array indexed by IOAPIC id.
|
||||
|
||||
## Device initialization
|
||||
|
||||
After that, each time a IOAPIC entry is parsed, a call to `sh_ioapic_init(sh_uint32 base,sh_uint8 ioapic_id,sh_uint32 gsi_base,sh_ioapic_DEVICE *ioapic)` is made. This does three things:
|
||||
1) Identity map the memory space for the LAPIC
|
||||
2) Fill the structure for the LAPIC device
|
||||
3) Initialize the device without modifying the IOREDTBL for the moment
|
||||
|
||||
Then, a call to `sh_ioapic_bind(sh_ioapic_DEVICE *ioapic_dev)` is made, registering the LAPIC structure in the array.
|
||||
|
||||
## Basic IOAPIC management
|
||||
|
||||
For basic IOAPIC management, the following function are provided:
|
||||
- `sh_ioapic_get_dev_ioapic_id(sh_uint64 ioapic_id)`: return a `sh_ioapic_DEVICE*` pointing to the IOAPIC structure corresponding to the provided IOAPIC id
|
||||
- `sh_ioapic_get_dev_by_gsi(sh_uint32 gsi)`: return a `sh_ioapic_DEVICE*` pointing to the IOAPIC structure of the IOAPIC that manages the provided GSI
|
||||
- `sh_ioapic_read_ioredtbl_entry(sh_ioapic_DEVICE *ioapic_dev,sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry)`: read a IOREDTBL entry and put its value into `entry`. If the GSI isn't managed by the provided device, raise an error
|
||||
- `sh_ioapic_write_ioredtbl_entry(sh_ioapic_DEVICE *ioapic_dev,sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry)`: write and IOREDTBL entry corresponding to the provided GSI. If the GSI isn't managed by the provided device, raise an error
|
||||
|
||||
IOREDTBL read and write are thread-safe operations.
|
||||
|
||||
## Higher level operations
|
||||
|
||||
The following higher level operations are provided:
|
||||
- `sh_ioapic_mask_gsi(sh_ioapic_DEVICE *dev,sh_uint32 gsi)`: mask the provided GSI. If the GSI isn't managed by the provided device, raise an error
|
||||
- `sh_ioapic_unmask_gsi(sh_ioapic_DEVICE *dev,sh_uint32 gsi)`: unmask the provided GSI. If the GSI isn't managed by the provided device, raise an error
|
||||
- `sh_ioapic_mask_all()`: mask all the GSI for all registered IOAPIC.
|
||||
|
||||
If you are looking for an even more abstracted API, please check the GSI subsystem.
|
||||
81
docs/shelter/devs/integrated/lapic.md
Normal file
81
docs/shelter/devs/integrated/lapic.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# LAPIC devices
|
||||
|
||||
This driver is defined inside `shelter/lib/include/devs/apic/lapic.h` and implemented inside `shelter/lib/src/devs/apic/lapic.c`.
|
||||
|
||||
## Driver initialization
|
||||
|
||||
During the MADT parsing, all LAPIC entries are counted. Then, a call to `sh_lapic_init_devs(sh_uint16 max_lapic_id,sh_uint16 max_acpi_processor_id)` is made to initialize the driver internal state. This call allocates two arrays: one indexed by LAPIC id and one indexed by ACPI processors id.
|
||||
|
||||
## Device initialization
|
||||
|
||||
After that, each time a LAPIC entry is parsed, a call to `sh_lapic_init(sh_uint64 lapic_phys,sh_uint8 spurious_vector,sh_uint8 apic_id,sh_uint8 apic_processor_id,sh_uint32 flags,sh_lapic_DEVICE *lapic)` is made. This does two things:
|
||||
1) Identity map the memory space for the LAPIC
|
||||
2) Fill the structure for the LAPIC device
|
||||
|
||||
Then, a call to `sh_lapic_bind(sh_lapic_DEVICE *lapic_dev)` is made, registering the LAPIC structure in both arrays.
|
||||
|
||||
Finally, when the MADT parsing is over, a call to `sh_lapic_init_dev(sh_uint8 spurious_vector,sh_lapic_DEVICE *lapic)` initialize the LAPIC by setuping a few of its registers.
|
||||
|
||||
## Basic LAPIC management
|
||||
|
||||
For basic LAPIC management, the following functions are provided:
|
||||
- `sh_lapic_eoi(sh_lapic_DEVICE *lapic)`: send a End Of Interrupt (EOI) to the LAPIC
|
||||
- `sh_lapic_get_dev_apic_id(sh_uint64 apic_id)`: return a `sh_lapic_DEVICE*` pointing to the LAPIC structure corresponding to the provided APIC id
|
||||
- `sh_lapic_get_dev_acpi_cpu_id(sh_uint64 acpi_processor_id)`: return a `sh_lapic_DEVICE*` pointing to the LAPIC structure corresponding to the provided ACPI processor id
|
||||
- `sh_lapic_get_by_apic_id_array()`: return a `sh_lapic_DEVICE**` of the LAPIC devices pointers array, indexed by LAPIC id
|
||||
- `sh_lapic_get_max_apic_id()`: return the max LAPIC id
|
||||
- `sh_lapic_get_max_acpi_processor_id()`: return the max ACPI processor id
|
||||
- `sh_lapic_get_lapic_count()`: return the number of registered LAPICs
|
||||
- `sh_lapic_get_current_core()`: return the LAPIC id of the current core, return -1 if error happened
|
||||
|
||||
## LAPIC timer
|
||||
|
||||
To launch a one shot timer without knowing the frequency, the `sh_lapic_timer_one_shot(sh_lapic_DEVICE *lapic_dev,sh_uint32 initial_value)` can be used.
|
||||
|
||||
But the LAPIC driver provides a way to calibrate the LAPIC in order to obtain its frequency. For this, we use the following process:
|
||||
1) Launch a timer with max value
|
||||
2) Read the start TSC and current LAPIC value, iterate for 10 millions times, read the end TSC and current LAPIC value.
|
||||
3) Compute `tsc_delta` and `lapic_delta`
|
||||
4) Using the following formula, estimate the LAPIC frequency: `lapic_freq = (lapic_delta * cpu_freq) / tsc_delta`
|
||||
|
||||
This calibration process is implemented in `sh_lapic_calibrate(sh_lapic_DEVICE *lapic_dev,sh_uint64 cpu_freq)`. But the TSC frequency estimation must have been achevied before that.
|
||||
|
||||
When the LAPIC frequency is obtained, two new functions are unlocked:
|
||||
- `sh_lapic_get_frequency()`: return the estimated LAPIC frequency
|
||||
- `sh_lapic_timer_one_shot_us(sh_lapic_DEVICE *lapic_dev,sh_uint64 microseconds_count)`: launch a one shot timer by taking a value in microsecond. Compute the initial value using the estimated frequency before hand.
|
||||
|
||||
## IPI management
|
||||
|
||||
The LAPIC driver provides a helper to know if the LAPIC IPI feature is busy: `sh_lapic_ipi_is_busy(sh_lapic_DEVICE *lapic_dev)`.
|
||||
|
||||
### Sending a fixed IPI
|
||||
|
||||
The primitive to send a fixed IPI is:
|
||||
``` C
|
||||
sh_lapic_send_fixed_ipi(sh_lapic_DEVICE *lapic_dev,sh_uint8 vector,sh_uint32 destination_mode,sh_int16 target_lapic_id);
|
||||
```
|
||||
|
||||
`lapic_dev` must be the struct of the LAPIC of the current CPU.
|
||||
|
||||
`destination_mode` can either be `SH_LAPIC_IPI_DESTINATION_SPECIFIC`, `SH_LAPIC_IPI_DESTINATION_SELF`, `SH_LAPIC_IPI_DESTINATION_ALL` or `SH_LAPIC_IPI_DESTINATION_ALL_EXCLUDING_SELF`.
|
||||
|
||||
If `destination_mode` isn't `SH_LAPIC_IPI_DESTINATION_SPECIFIC`, `target_lapic_id` must be `SH_LAPIC_IPI_NO_DESTINATION`.
|
||||
|
||||
### Sending any others IPI
|
||||
|
||||
The primitive to send any other IPI than a fixed IPI is:
|
||||
``` C
|
||||
sh_lapic_send_ipi(sh_lapic_DEVICE *lapic_dev,sh_uint32 ipi_type,sh_uint32 destination_mode,sh_int16 target_lapic_id,sh_page_PHYSICAL_ADDRESS start_address);
|
||||
```
|
||||
|
||||
`lapic_dev` must be the struct of the LAPIC of the current CPU.
|
||||
|
||||
`ipi_type` can either be `SH_LAPIC_IPI_TYPE_INIT`, `SH_LAPIC_IPI_TYPE_STARTUP` or `SH_LAPIC_IPI_TYPE_NMI`.
|
||||
|
||||
If `ipi_type` is `SH_LAPIC_IPI_TYPE_STARTUP`, `start_address` must contain the starting address. Address constraint (compatible with 16 bits mode) are checked.
|
||||
|
||||
If `ipi_type` isn't `SH_LAPIC_IPI_TYPE_STARTUP`, `start_address` must be 0.
|
||||
|
||||
`destination_mode` can either be `SH_LAPIC_IPI_DESTINATION_SPECIFIC`, `SH_LAPIC_IPI_DESTINATION_SELF`, `SH_LAPIC_IPI_DESTINATION_ALL` or `SH_LAPIC_IPI_DESTINATION_ALL_EXCLUDING_SELF`.
|
||||
|
||||
If `destination_mode` isn't `SH_LAPIC_IPI_DESTINATION_SPECIFIC`, `target_lapic_id` must be `SH_LAPIC_IPI_NO_DESTINATION`.
|
||||
Reference in New Issue
Block a user