mirror of
https://github.com/tailix/libkernaux.git
synced 2025-08-07 22:04:16 -04:00
i386 IDT (#135)
This commit is contained in:
parent
b7f8a70d46
commit
9921e8784c
7 changed files with 250 additions and 47 deletions
|
@ -47,7 +47,7 @@ endif
|
||||||
#######
|
#######
|
||||||
|
|
||||||
if WITH_ARCH_I386
|
if WITH_ARCH_I386
|
||||||
libkernaux_la_SOURCES += src/arch/i386.c
|
libkernaux_la_SOURCES += src/arch/i386/idt.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
#######
|
#######
|
||||||
|
|
|
@ -17,7 +17,7 @@ nobase_include_HEADERS = \
|
||||||
########
|
########
|
||||||
|
|
||||||
if WITH_ARCH_I386
|
if WITH_ARCH_I386
|
||||||
nobase_include_HEADERS += kernaux/arch/i386.h
|
nobase_include_HEADERS += kernaux/arch/i386.h kernaux/arch/i386-idt.h
|
||||||
endif
|
endif
|
||||||
if WITH_ARCH_RISCV64
|
if WITH_ARCH_RISCV64
|
||||||
nobase_include_HEADERS += kernaux/arch/riscv64.h
|
nobase_include_HEADERS += kernaux/arch/riscv64.h
|
||||||
|
|
62
include/kernaux/arch/i386-idt.h
Normal file
62
include/kernaux/arch/i386-idt.h
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#ifndef KERNAUX_INCLUDED_ARCH_I386_IDT
|
||||||
|
#define KERNAUX_INCLUDED_ARCH_I386_IDT
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <kernaux/macro.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <kernaux/macro/packing_start.run>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Interrupt Descriptor Table entry
|
||||||
|
*
|
||||||
|
* @see https://en.wikibooks.org/wiki/X86_Assembly/Advanced_Interrupts#The_Interrupt_Descriptor_Table
|
||||||
|
*/
|
||||||
|
typedef struct KernAux_Arch_I386_IDTE {
|
||||||
|
uint16_t offset_low;
|
||||||
|
uint16_t selector;
|
||||||
|
uint8_t _;
|
||||||
|
uint8_t flags;
|
||||||
|
uint16_t offset_high;
|
||||||
|
}
|
||||||
|
KERNAUX_PACKED
|
||||||
|
KERNAUX_ALIGNED(8)
|
||||||
|
*KernAux_Arch_I386_IDTE;
|
||||||
|
|
||||||
|
KERNAUX_STATIC_TEST_STRUCT_SIZE(KernAux_Arch_I386_IDTE, 8);
|
||||||
|
|
||||||
|
#include <kernaux/macro/packing_end.run>
|
||||||
|
|
||||||
|
void KernAux_Arch_I386_IDTE_init_intr(
|
||||||
|
KernAux_Arch_I386_IDTE idte,
|
||||||
|
uint32_t offset,
|
||||||
|
uint16_t cs_selector,
|
||||||
|
uint8_t dpl
|
||||||
|
);
|
||||||
|
void KernAux_Arch_I386_IDTE_init_task(
|
||||||
|
KernAux_Arch_I386_IDTE idte,
|
||||||
|
uint16_t tss_selector,
|
||||||
|
uint8_t dpl
|
||||||
|
);
|
||||||
|
void KernAux_Arch_I386_IDTE_init_trap(
|
||||||
|
KernAux_Arch_I386_IDTE idte,
|
||||||
|
uint32_t offset,
|
||||||
|
uint16_t cs_selector,
|
||||||
|
uint8_t dpl
|
||||||
|
);
|
||||||
|
|
||||||
|
uint32_t KernAux_Arch_I386_IDTE_offset(KernAux_Arch_I386_IDTE idte);
|
||||||
|
uint8_t KernAux_Arch_I386_IDTE_dpl (KernAux_Arch_I386_IDTE idte);
|
||||||
|
|
||||||
|
void
|
||||||
|
KernAux_Arch_I386_IDTE_set_offset(KernAux_Arch_I386_IDTE idte, uint32_t offset);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -5,6 +5,7 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <kernaux/arch/i386-idt.h>
|
||||||
#include <kernaux/arch/x86.h>
|
#include <kernaux/arch/x86.h>
|
||||||
#include <kernaux/macro.h>
|
#include <kernaux/macro.h>
|
||||||
|
|
||||||
|
@ -91,25 +92,6 @@ KERNAUX_PACKED;
|
||||||
|
|
||||||
KERNAUX_STATIC_TEST_STRUCT_SIZE(KernAux_Arch_I386_DTE, 8);
|
KERNAUX_STATIC_TEST_STRUCT_SIZE(KernAux_Arch_I386_DTE, 8);
|
||||||
|
|
||||||
// Interrupt descriptor table entry
|
|
||||||
// TODO: validate this according to spec
|
|
||||||
typedef struct KernAux_Arch_I386_IDTE {
|
|
||||||
uint16_t offset_low;
|
|
||||||
uint16_t selector;
|
|
||||||
uint8_t _zero0;
|
|
||||||
uint8_t flags;
|
|
||||||
uint16_t offset_high;
|
|
||||||
}
|
|
||||||
KERNAUX_PACKED
|
|
||||||
*KernAux_Arch_I386_IDTE;
|
|
||||||
|
|
||||||
KERNAUX_STATIC_TEST_STRUCT_SIZE(KernAux_Arch_I386_IDTE, 8);
|
|
||||||
|
|
||||||
void KernAux_Arch_I386_IDTE_set_offset(
|
|
||||||
KernAux_Arch_I386_IDTE idte,
|
|
||||||
uint32_t address
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Task state segment
|
* @brief Task state segment
|
||||||
* @see The manual, page 132, figure 7-1
|
* @see The manual, page 132, figure 7-1
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <kernaux/arch/i386.h>
|
|
||||||
|
|
||||||
void KernAux_Arch_I386_IDTE_set_offset(
|
|
||||||
const KernAux_Arch_I386_IDTE idte,
|
|
||||||
const uint32_t address
|
|
||||||
)
|
|
||||||
{
|
|
||||||
idte->offset_low = 0xFFFF & address;
|
|
||||||
idte->offset_high = 0xFFFF & (address >> 16);
|
|
||||||
}
|
|
74
src/arch/i386/idt.c
Normal file
74
src/arch/i386/idt.c
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <kernaux/arch/i386.h>
|
||||||
|
#include <kernaux/assert.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define DPL (0x60u & (dpl << 5))
|
||||||
|
|
||||||
|
void KernAux_Arch_I386_IDTE_init_intr(
|
||||||
|
const KernAux_Arch_I386_IDTE idte,
|
||||||
|
const uint32_t offset,
|
||||||
|
const uint16_t cs_selector,
|
||||||
|
const uint8_t dpl
|
||||||
|
) {
|
||||||
|
KERNAUX_ASSERT(idte);
|
||||||
|
|
||||||
|
memset(idte, 0, sizeof(*idte));
|
||||||
|
KernAux_Arch_I386_IDTE_set_offset(idte, offset);
|
||||||
|
idte->selector = cs_selector;
|
||||||
|
idte->flags |= 0x80u | DPL | 0xeu; // 1-00-01110
|
||||||
|
}
|
||||||
|
|
||||||
|
void KernAux_Arch_I386_IDTE_init_task(
|
||||||
|
const KernAux_Arch_I386_IDTE idte,
|
||||||
|
const uint16_t tss_selector,
|
||||||
|
const uint8_t dpl
|
||||||
|
) {
|
||||||
|
KERNAUX_ASSERT(idte);
|
||||||
|
|
||||||
|
memset(idte, 0, sizeof(*idte));
|
||||||
|
idte->selector = tss_selector;
|
||||||
|
idte->flags |= 0x80u | DPL | 0x5u; // 1-00-00101
|
||||||
|
}
|
||||||
|
|
||||||
|
void KernAux_Arch_I386_IDTE_init_trap(
|
||||||
|
const KernAux_Arch_I386_IDTE idte,
|
||||||
|
const uint32_t offset,
|
||||||
|
const uint16_t cs_selector,
|
||||||
|
const uint8_t dpl
|
||||||
|
) {
|
||||||
|
KERNAUX_ASSERT(idte);
|
||||||
|
|
||||||
|
memset(idte, 0, sizeof(*idte));
|
||||||
|
KernAux_Arch_I386_IDTE_set_offset(idte, offset);
|
||||||
|
idte->selector = cs_selector;
|
||||||
|
idte->flags |= 0x80u | DPL | 0xfu; // 1-00-01111
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t KernAux_Arch_I386_IDTE_offset(const KernAux_Arch_I386_IDTE idte)
|
||||||
|
{
|
||||||
|
KERNAUX_ASSERT(idte);
|
||||||
|
|
||||||
|
return (idte->offset_high << 16) | idte->offset_low;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t KernAux_Arch_I386_IDTE_dpl(const KernAux_Arch_I386_IDTE idte)
|
||||||
|
{
|
||||||
|
KERNAUX_ASSERT(idte);
|
||||||
|
|
||||||
|
return 3 & (idte->flags >> 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KernAux_Arch_I386_IDTE_set_offset(
|
||||||
|
const KernAux_Arch_I386_IDTE idte,
|
||||||
|
const uint32_t offset
|
||||||
|
) {
|
||||||
|
KERNAUX_ASSERT(idte);
|
||||||
|
|
||||||
|
idte->offset_low = 0xffffu & offset;
|
||||||
|
idte->offset_high = 0xffffu & (offset >> 16);
|
||||||
|
}
|
|
@ -7,27 +7,126 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static void test_idte_set_offset();
|
static void test_idte_init_intr();
|
||||||
|
static void test_idte_init_task();
|
||||||
|
static void test_idte_init_trap();
|
||||||
|
static void test_idte_get_and_set_offset();
|
||||||
|
static void test_idte_get_dpl();
|
||||||
|
|
||||||
void test_main()
|
void test_main()
|
||||||
{
|
{
|
||||||
test_idte_set_offset();
|
test_idte_init_intr();
|
||||||
|
test_idte_init_task();
|
||||||
|
test_idte_init_trap();
|
||||||
|
test_idte_get_and_set_offset();
|
||||||
|
test_idte_get_dpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_idte_set_offset()
|
void test_idte_init_intr()
|
||||||
|
{
|
||||||
|
struct KernAux_Arch_I386_IDTE idte;
|
||||||
|
memset(&idte, 0xff, sizeof(idte));
|
||||||
|
|
||||||
|
KernAux_Arch_I386_IDTE_init_intr(&idte, 0x12345678, 0xcafe, 0);
|
||||||
|
assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0x12345678);
|
||||||
|
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 0);
|
||||||
|
assert(idte.selector == 0xcafe);
|
||||||
|
assert(idte._ == 0);
|
||||||
|
assert(idte.flags == 0x8e); // 1-00-01110
|
||||||
|
|
||||||
|
KernAux_Arch_I386_IDTE_init_intr(&idte, 0x12345678, 0xcafe, 3);
|
||||||
|
assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0x12345678);
|
||||||
|
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 3);
|
||||||
|
assert(idte.selector == 0xcafe);
|
||||||
|
assert(idte._ == 0);
|
||||||
|
assert(idte.flags == 0xee); // 1-11-01110
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_idte_init_task()
|
||||||
|
{
|
||||||
|
struct KernAux_Arch_I386_IDTE idte;
|
||||||
|
memset(&idte, 0xff, sizeof(idte));
|
||||||
|
|
||||||
|
KernAux_Arch_I386_IDTE_init_task(&idte, 0xcafe, 0);
|
||||||
|
assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0);
|
||||||
|
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 0);
|
||||||
|
assert(idte.selector == 0xcafe);
|
||||||
|
assert(idte._ == 0);
|
||||||
|
assert(idte.flags == 0x85); // 1-00-00101
|
||||||
|
|
||||||
|
KernAux_Arch_I386_IDTE_init_task(&idte, 0xcafe, 3);
|
||||||
|
assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0);
|
||||||
|
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 3);
|
||||||
|
assert(idte.selector == 0xcafe);
|
||||||
|
assert(idte._ == 0);
|
||||||
|
assert(idte.flags == 0xe5); // 1-11-00101
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_idte_init_trap()
|
||||||
|
{
|
||||||
|
struct KernAux_Arch_I386_IDTE idte;
|
||||||
|
memset(&idte, 0xff, sizeof(idte));
|
||||||
|
|
||||||
|
KernAux_Arch_I386_IDTE_init_trap(&idte, 0x12345678, 0xcafe, 0);
|
||||||
|
assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0x12345678);
|
||||||
|
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 0);
|
||||||
|
assert(idte.selector == 0xcafe);
|
||||||
|
assert(idte._ == 0);
|
||||||
|
assert(idte.flags == 0x8f); // 1-00-01111
|
||||||
|
|
||||||
|
KernAux_Arch_I386_IDTE_init_trap(&idte, 0x12345678, 0xcafe, 3);
|
||||||
|
assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0x12345678);
|
||||||
|
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 3);
|
||||||
|
assert(idte.selector == 0xcafe);
|
||||||
|
assert(idte._ == 0);
|
||||||
|
assert(idte.flags == 0xef); // 1-11-01111
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_idte_get_and_set_offset()
|
||||||
|
{
|
||||||
|
struct KernAux_Arch_I386_IDTE idte;
|
||||||
|
|
||||||
|
memset(&idte, 0xff, sizeof(idte));
|
||||||
|
KernAux_Arch_I386_IDTE_set_offset(&idte, 0);
|
||||||
|
assert(idte.offset_high == 0);
|
||||||
|
assert(idte.offset_low == 0);
|
||||||
|
assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0);
|
||||||
|
|
||||||
|
memset(&idte, 0, sizeof(idte));
|
||||||
|
KernAux_Arch_I386_IDTE_set_offset(&idte, 0xffffffff);
|
||||||
|
assert(idte.offset_high == 0xffff);
|
||||||
|
assert(idte.offset_low == 0xffff);
|
||||||
|
assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0xffffffff);
|
||||||
|
|
||||||
|
memset(&idte, 0, sizeof(idte));
|
||||||
|
KernAux_Arch_I386_IDTE_set_offset(&idte, 0x12345678);
|
||||||
|
assert(idte.offset_high == 0x1234);
|
||||||
|
assert(idte.offset_low == 0x5678);
|
||||||
|
assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0x12345678);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_idte_get_dpl()
|
||||||
{
|
{
|
||||||
struct KernAux_Arch_I386_IDTE idte;
|
struct KernAux_Arch_I386_IDTE idte;
|
||||||
memset(&idte, 0, sizeof(idte));
|
memset(&idte, 0, sizeof(idte));
|
||||||
|
|
||||||
KernAux_Arch_I386_IDTE_set_offset(&idte, 0);
|
idte.flags = 0; // 0-00-00000
|
||||||
assert(idte.offset_high == 0);
|
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 0);
|
||||||
assert(idte.offset_low == 0);
|
idte.flags = 0x80; // 1-00-00000
|
||||||
|
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 0);
|
||||||
|
|
||||||
KernAux_Arch_I386_IDTE_set_offset(&idte, 0xFFFFFFFF);
|
idte.flags = 0x20; // 0-01-00000
|
||||||
assert(idte.offset_high == 0xFFFF);
|
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 1);
|
||||||
assert(idte.offset_low == 0xFFFF);
|
idte.flags = 0xa0; // 1-01-00000
|
||||||
|
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 1);
|
||||||
|
|
||||||
KernAux_Arch_I386_IDTE_set_offset(&idte, 0x12345678);
|
idte.flags = 0x40; // 0-10-00000
|
||||||
assert(idte.offset_high == 0x1234);
|
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 2);
|
||||||
assert(idte.offset_low == 0x5678);
|
idte.flags = 0xc0; // 1-10-00000
|
||||||
|
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 2);
|
||||||
|
|
||||||
|
idte.flags = 0x60; // 0-11-00000
|
||||||
|
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 3);
|
||||||
|
idte.flags = 0xe0; // 1-11-00000
|
||||||
|
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 3);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue