Files
jsix_import/src/kernel/idt.h
Justin C. Miller f5208d1641 [all] Remove dependencies on non-freestanding libc
This is the first of two rather big changes to clean up includes
throughout the project. In this commit, the implicit semi-dependency on
libc that bonnibel adds to every module is removed. Previously, I was
sloppy with includes of libc headers and include directory order. Now,
the freestanding headers from libc are split out into libc_free, and an
implicit real dependency is added onto this module, unless `no_libc` is
set to `True`. The full libc needs to be explicitly specified as a
dependency to be used.

Several things needed to change in order to do this:

- Many places use `memset` or `memcpy` that cannot depend on libc. The
  kernel has basic implementations of them itself for this reason. Now
  those functions are moved into the lower-level `j6/memutils.h`, and
  libc merely references them. Other modules are now free to reference
  those functions from libj6 instead.
- The kernel's `assert.h` was renamed kassert.h (matching its `kassert`
  function) so that the new `util/assert.h` can use `__has_include` to
  detect it and make sure the `assert` macro is usable in libutil code.
- Several implementation header files under `__libj6/` also moved under
  the new libc_free.
- A new `include_phase` property has been added to modules for Bonnibel,
  which can be "normal" (default) or "late" which uses `-idirafter`
  instead of `-I` for includes.
- Since `<utility>` and `<new>` are not freestanding, implementations of
  `remove_reference`, `forward`, `move`, and `swap` were added to the
  `util` namespace to replace those from `std`, and `util/new.h` was
  added to declare `operator new` and `operator delete`.
2023-07-12 19:38:31 -07:00

82 lines
2.5 KiB
C++

#pragma once
/// \file idt.h
/// Definitions relating to a CPU's IDT table
#include <stdint.h>
#include "kassert.h"
class IDT
{
public:
IDT();
/// Get the currently running CPU's IDT
static IDT & current();
/// Set the global NMI handler. Must happen before creating
/// any IDTs.
static void set_nmi_handler(uintptr_t address);
/// Install this IDT to the current CPU
void install() const;
/// Add the IST entries listed in the ISR table into the IDT.
/// This can't be done until after memory is set up so the
/// stacks can be created.
void add_ist_entries();
/// Get the IST entry used by an entry, clearing it in the process.
/// \arg i Which IDT entry to look in
/// \returns The IST index used by entry i, or 0 for none
inline uint8_t get_ist(uint8_t i) {
return __atomic_exchange_n(&m_entries[i].ist, 0, __ATOMIC_SEQ_CST);
}
/// Restore the IST entry used by an entry when done using it.
/// \arg i Which IDT entry to restore
/// \arg ist The IST index for entry i, or 0 for none
inline void return_ist(uint8_t i, uint8_t ist) {
if (!ist) return;
uint8_t expected = 0;
bool result = __atomic_compare_exchange_n(
&m_entries[i].ist, &expected, ist,
false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
kassert(result, "Tried to overwrite a non-zero IST value in IDT");
}
/// Set the IST entry used by an entry. This should not be called
/// by interrupt handlers.
/// \arg i Which IDT entry to set
/// \arg ist The IST index for entry i, or 0 for none
inline void set_ist(uint8_t i, uint8_t ist) { m_entries[i].ist = ist; }
/// Get the IST entries that are used by this table, as a bitmap
static uint8_t used_ist_entries();
/// Dump debug information about the IDT to the console.
/// \arg index Which entry to print, or -1 for all entries
void dump(unsigned index = -1) const;
private:
void set(uint8_t i, void (*handler)(), uint16_t selector, uint8_t flags);
struct descriptor
{
uint16_t base_low;
uint16_t selector;
uint8_t ist;
uint8_t flags;
uint16_t base_mid;
uint32_t base_high;
uint32_t reserved; // must be zero
} __attribute__ ((packed, aligned(16)));
struct ptr
{
uint16_t limit;
descriptor *base;
} __attribute__ ((packed, aligned(4)));
descriptor m_entries[256];
ptr m_ptr;
};