Files
jsix_import/src/kernel/device_manager.h
Justin C. Miller 1d30322820 [kernel] Pass objects not handles to syscall impls
This commit contains a couple large, interdependent changes:

- In preparation for capability checking, the _syscall_verify_*
  functions now load most handles passed in, and verify that they exist
  and are of the correct type. Lists and out-handles are not converted
  to objects.
- Also in preparation for capability checking, the internal
  representation of handles has changed. j6_handle_t is now 32 bits, and
  a new j6_cap_t (also 32 bits) is added. Handles of a process are now a
  util::map<j6_handle_t, handle> where handle is a new struct containing
  the id, capabilities, and object pointer.
- The kernel object definition DSL gained a few changes to support auto
  generating the handle -> object conversion in the _syscall_verify_*
  functions, mostly knowing the object type, and an optional "cname"
  attribute on objects where their names differ from C++ code.
  (Specifically vma/vm_area)
- Kernel object code and other code under kernel/objects is now in a new
  obj:: namespace, because fuck you <cstdlib> for putting "system" in
  the global namespace. Why even have that header then?
- Kernel object types constructed with the construct_handle helper now
  have a creation_caps static member to declare what capabilities a
  newly created object's handle should have.
2022-01-17 23:23:04 -08:00

176 lines
5.3 KiB
C++

#pragma once
/// \file device_manager.h
/// The device manager definition
#include <util/vector.h>
#include "apic.h"
#include "hpet.h"
#include "pci.h"
struct acpi_table_header;
class block_device;
namespace obj {
class endpoint;
}
using irq_callback = void (*)(void *);
/// Manager for all system hardware devices
class device_manager
{
public:
/// Constructor.
device_manager();
/// Get the system global device manager.
/// \returns A reference to the system device manager
static device_manager & get() { return s_instance; }
/// Get an IOAPIC
/// \arg i Index of the requested IOAPIC
/// \returns An object representing the given IOAPIC if it exists,
/// otherwise nullptr.
ioapic * get_ioapic(int i);
/// Parse ACPI tables.
/// \arg root_table Pointer to the ACPI RSDP
void parse_acpi(const void *root_table);
/// Intialize drivers for the current device list.
void init_drivers();
/// Bind an IRQ to an endpoint
/// \arg irq The IRQ number to bind
/// \arg target The endpoint to recieve messages when the IRQ is signalled
/// \returns True on success
bool bind_irq(unsigned irq, obj::endpoint *target);
/// Remove IRQ bindings for an endpoint
/// \arg target The endpoint to remove
void unbind_irqs(obj::endpoint *target);
/// Allocate an MSI IRQ for a device
/// \arg name Name of the interrupt, for display to user
/// \arg device Device this MSI is being allocated for
/// \arg cb Callback to call when the interrupt is received
/// \arg data Data to pass to the callback
/// \returns True if an interrupt was allocated successfully
bool allocate_msi(
const char *name,
pci_device &device,
irq_callback cb,
void *data);
/// Dispatch an IRQ interrupt
/// \arg irq The irq number of the interrupt
/// \returns True if the interrupt was handled
bool dispatch_irq(unsigned irq);
struct apic_nmi
{
uint8_t cpu;
uint8_t lint;
uint16_t flags;
};
struct irq_override
{
uint8_t source;
uint16_t flags;
uint32_t gsi;
};
/// Get the list of APIC ids for other CPUs
inline const util::vector<uint8_t> & get_apic_ids() const { return m_apic_ids; }
/// Get the LAPIC base address
/// \returns The physical base address of the local apic registers
uintptr_t get_lapic_base() const { return m_lapic_base; }
/// Get the NMI mapping for the given local APIC
/// \arg id ID of the local APIC
/// \returns apic_nmi structure describing the NMI configuration,
/// or null if no configuration was provided
const apic_nmi * get_lapic_nmi(uint8_t id) const;
/// Get the IRQ source override for the given IRQ
/// \arg irq IRQ number (not isr vector)
/// \returns irq_override structure describing that IRQ's
/// configuration, or null if no configuration was provided
const irq_override * get_irq_override(uint8_t irq) const;
/// Register the existance of a block device.
/// \arg blockdev Pointer to the block device
void register_block_device(block_device *blockdev);
/// Get the number of block devices in the system
/// \returns A count of devices
inline unsigned get_num_block_devices() const { return m_blockdevs.count(); }
/// Get a block device
/// \arg i Index of the device to get
/// \returns A pointer to the requested device, or nullptr
inline block_device * get_block_device(unsigned i)
{
return i < m_blockdevs.count() ?
m_blockdevs[i] : nullptr;
}
/// Get an HPET device
/// \arg i Index of the device to get
/// \returns A pointer to the requested device, or nullptr
inline hpet * get_hpet(unsigned i)
{
return i < m_hpets.count() ?
&m_hpets[i] : nullptr;
}
private:
/// Parse the ACPI XSDT and load relevant sub-tables.
/// \arg xsdt Pointer to the XSDT from the firmware
void load_xsdt(const acpi_table_header *xsdt);
/// Parse the ACPI MADT and initialize APICs from it.
/// \arg apic Pointer to the MADT from the XSDT
void load_apic(const acpi_table_header *apic);
/// Parse the ACPI MCFG and initialize PCIe from it.
/// \arg mcfg Pointer to the MCFG from the XSDT
void load_mcfg(const acpi_table_header *mcfg);
/// Parse the ACPI HPET and initialize an HPET from it.
/// \arg hpet Pointer to the HPET from the XSDT
void load_hpet(const acpi_table_header *hpet);
/// Probe the PCIe busses and add found devices to our
/// device list. The device list is destroyed and rebuilt.
void probe_pci();
/// Handle a bad IRQ. Called when an interrupt is dispatched
/// that has no callback.
void bad_irq(uint8_t irq);
uintptr_t m_lapic_base;
util::vector<ioapic> m_ioapics;
util::vector<hpet> m_hpets;
util::vector<uint8_t> m_apic_ids;
util::vector<apic_nmi> m_nmis;
util::vector<irq_override> m_overrides;
util::vector<pci_group> m_pci;
util::vector<pci_device> m_devices;
util::vector<obj::endpoint*> m_irqs;
util::vector<block_device *> m_blockdevs;
static device_manager s_instance;
device_manager(const device_manager &) = delete;
device_manager operator=(const device_manager &) = delete;
};