TSOS/include/cpu/idt.h

95 lines
3.4 KiB
C

/*
Copyright 2022 Mattia Giambirtone & Contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef TSOS_CPU_IDT_H
#define TSOS_CPU_IDT_H
#include "kernel/types.h"
#define KERNEL_CODE_SEGMENT_SELECTOR 0x8
typedef struct {
/*
An entry in the Interrupt
Descriptor Table of the CPU
*/
u16 handlerOffsetLow; /* Low 16 bits of handler's address */
u16 segmentSelector; /* Kernel segment selector */
u8 _unused; /* This is always zero! (padding?) */
u8 flags; /* Flags of this handler */
u16 handlerOffsetHigh; /* High 16 bits of handler's address */
/*
The flags byte is structured as follows:
- Bit 7 : "Interrupt is present". Serves to make the whole structure valid
- Bits 6-5: Privilege level ("ring") of the caller. Ring zero is the kernel,
ring one is usually reserved for driver code, ring two is unused and ring 3
is userland code
- Bits 4-0: The gate's type and attributes. They are structured as follows:
- Bit 4 : Set to zero for interrupts and one for traps (traps are usually used for exceptions)
- Bit 3-0: The type of the gate (whether it's 16- or 32-bit, etc.)
The only valid values for bits 4-0 are five (taken from the OSDev wiki):
- 0b0101 or 0x5: Task Gate. Note that in this case, the offset value is unused and should be set to zero.
- 0b0110 or 0x6: 16-bit Interrupt Gate
- 0b0111 or 0x7: 16-bit Trap Gate
- 0b1110 or 0xE: 32-bit Interrupt Gate
- 0b1111 or 0xF: 32-bit Trap Gate
*/
} __attribute__((packed)) GateDescriptor;
// The packed attribute tells gcc not to align
// or reorder the struct's fields in memory.
// Doing so in normal code is fine and speeds up
// memory accessing, but the CPU expects the structure
// of a GDT entry to be exactly in this order, with no
// padding (besides, each entry is exactly 8 bytes long
// already, so the performance hit is probably neglibible)
typedef struct {
/*
The Interrupt Descriptor Table
Register. Stores the location
of the IDT in memory
*/
u16 size; /* Size of the IDT. Always one less than its true size*/
u32 loc;
} __attribute__((packed)) IDTRegister;
/*
Note: While the IDT can contain up to 2 ** 16 entries, only the first
256 are considered and the rest is ignored; However, if there's less than
256 entries in the table, when the CPU then tries to fetch an interrupt gate
and doesn't find one, a GP (General Protection) fault is triggered. This may
cause the CPU to triple fault if the GP handler itself hasn't been set, as it
is one of the interrupt handlers the CPU expects to be present
*/
#define IDT_SIZE 256
/* These are the IDT and IDTR (We'll access these from asm) */
GateDescriptor idt[IDT_SIZE];
IDTRegister idtReg;
/* Prototypes */
void setIDTGate(i32 n, u32 handler);
void setIDT(void);
#endif