mirror of
https://github.com/tailix/libkernaux.git
synced 2024-11-20 11:06:41 -05: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
|
||||
libkernaux_la_SOURCES += src/arch/i386.c
|
||||
libkernaux_la_SOURCES += src/arch/i386/idt.c
|
||||
endif
|
||||
|
||||
#######
|
||||
|
|
|
@ -17,7 +17,7 @@ nobase_include_HEADERS = \
|
|||
########
|
||||
|
||||
if WITH_ARCH_I386
|
||||
nobase_include_HEADERS += kernaux/arch/i386.h
|
||||
nobase_include_HEADERS += kernaux/arch/i386.h kernaux/arch/i386-idt.h
|
||||
endif
|
||||
if WITH_ARCH_RISCV64
|
||||
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" {
|
||||
#endif
|
||||
|
||||
#include <kernaux/arch/i386-idt.h>
|
||||
#include <kernaux/arch/x86.h>
|
||||
#include <kernaux/macro.h>
|
||||
|
||||
|
@ -91,25 +92,6 @@ KERNAUX_PACKED;
|
|||
|
||||
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
|
||||
* @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 <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()
|
||||
{
|
||||
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;
|
||||
memset(&idte, 0, sizeof(idte));
|
||||
|
||||
KernAux_Arch_I386_IDTE_set_offset(&idte, 0);
|
||||
assert(idte.offset_high == 0);
|
||||
assert(idte.offset_low == 0);
|
||||
idte.flags = 0; // 0-00-00000
|
||||
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 0);
|
||||
idte.flags = 0x80; // 1-00-00000
|
||||
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 0);
|
||||
|
||||
KernAux_Arch_I386_IDTE_set_offset(&idte, 0xFFFFFFFF);
|
||||
assert(idte.offset_high == 0xFFFF);
|
||||
assert(idte.offset_low == 0xFFFF);
|
||||
idte.flags = 0x20; // 0-01-00000
|
||||
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 1);
|
||||
idte.flags = 0xa0; // 1-01-00000
|
||||
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 1);
|
||||
|
||||
KernAux_Arch_I386_IDTE_set_offset(&idte, 0x12345678);
|
||||
assert(idte.offset_high == 0x1234);
|
||||
assert(idte.offset_low == 0x5678);
|
||||
idte.flags = 0x40; // 0-10-00000
|
||||
assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 2);
|
||||
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…
Reference in a new issue