# GSI subsystem

## Introduction

This subsystem is responsible for registering all the interrupts sources overrides (ISO) and providing an abstraction to manipulate all the GSI lines and legacy IRQs.

## ISOs registering

The subsystem can be initialized using `sh_gsi_iso_array_init()`. This allocate an array of 256 `sh_gsi_ISO` in which all the ISOs will be stored.

The ISO struct is the following:
``` C
typedef struct {
  sh_uint32 gsi;
  sh_bool valid;
  sh_uint8 source_irq;
  enum sh_gsi_POLARITY polarity;
  enum sh_gsi_TRIGGER_MODE trigger_mode;
  sh_uint8 bus;
} sh_gsi_ISO;
```

Any `sh_gsi_ISO` without the valid boolean to `SH_TRUE` should be considered as not occupied in the array. 

The `sh_gsi_POLARITY` enum can take the following values:
``` C
enum sh_gsi_POLARITY {
  SH_GSI_POLARITY_NOT_SET=0,
  SH_GSI_POLARITY_BUS_DEFAULT,
  SH_GSI_POLARITY_ACTIVE_HIGH,
  SH_GSI_POLARITY_ACTIVE_LOW
};
```

The `sh_gsi_TRIGGER_MODE` enum can take the following values:
``` C
enum sh_gsi_TRIGGER_MODE {
  SH_GSI_TRIGGER_MODE_NOT_SET=0,
  SH_GSI_TRIGGER_MODE_BUS_DEFAULT,
  SH_GSI_TRIGGER_MODE_EDGE,
  SH_GSI_TRIGGER_MODE_LEVEL
};
```

Bus defaults are resolved when configuring the IOREDTBL of each IOAPIC.

During the MADT table parsing, ISOs are registered using the `sh_gsi_iso_register(sh_uint8 bus,sh_uint8 source,sh_uint32 gsi,sh_uint16 flags)` function, which expects the arguments as they are parsed in the MADT table.

Two functions can be used to search for ISOs:
- `sh_gsi_get_iso_by_irq(sh_uint8 irq)`: return a `*sh_gsi_ISO` with the provided legacy IRQ number. Return `SH_NULLPTR` if not found or error
- `sh_gsi_get_iso_by_gsi(sh_uint32 gsi)`: return a `*sh_gsi_ISO` with the provided GSI number. Return `SH_NULLPTR` if not found or error

## IOAPIC abstraction

The GSI subsystem provides an abstraction to manipulate IOREDTBL entries based on the GSI or legacy IRQ number without interacting directly with the IOAPIC subsystem. The following functions are provided:
- `sh_gsi_get(sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry)`: return the IOREDTBL entry corresponding to the provided GSI
- `sh_gsi_set(sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry)`: set the IOREDTBL entry corresponding to the provided GSI with the provided entry. Automatically mask the IOREDTBL entry before writing the entry
- `sh_gsi_irq_set(sh_uint8 irq,sh_ioapic_IOREDTBL_ENTRY *entry)`: do the same as `sh_gsi_set()` but retrieves the original GSI before hand, taking into account registered ISOs
- `sh_gsi_mask(sh_uint32 gsi)`: mask the IOREDTBL entry corresponding to the provided GSI
- `sh_gsi_unmask(sh_uint32 gsi)`: unmask the IOREDTBL entry corresponding to the provided GSI
- `sh_gsi_irq_mask(sh_uint8 irq)`: do the same as `sh_gsi_mask()` but retrieves the original GSI before hand, taking into account registered ISOs
- `sh_gsi_irq_unmask(sh_uint8 irq)`: do the same as `sh_gsi_unmask()` but retrieves the original GSI before hand, taking into account registered ISOs

## Legacy IRQs switch

What we call the legacy IRQs switch is the mapping of all the legacy IRQs to interrupt vectors 32 to 47, exactly like the PIT, and the transfer of legacy IRQs management from the PIT to the IOAPIC. 

It's operated by `sh_gsi_irq_switch()`. This is the only function that is allowed to call `sh_irq_switch_irq_management()`. By default, all the IOREDTBL entries corresponding to the GSI lines used by all legacy IRQs will be mask.
