This commit is contained in:
Alex Kotov 2022-12-09 03:46:31 +04:00 committed by GitHub
parent b7f8a70d46
commit 9921e8784c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 250 additions and 47 deletions

View File

@ -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
#######

View File

@ -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

View 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

View File

@ -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

View File

@ -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
View 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);
}

View File

@ -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);
}