gdt v1
This commit is contained in:
parent
8212e794f3
commit
4220f6628e
75
kernel/src/bits.rs
Normal file
75
kernel/src/bits.rs
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
use core::ops::{Bound, Range};
|
||||||
|
|
||||||
|
pub const trait Bits {
|
||||||
|
const BITS: usize;
|
||||||
|
fn get_bit(&self, index: usize) -> bool;
|
||||||
|
fn set_bit(&mut self, index: usize, value: bool) -> &mut Self;
|
||||||
|
fn get_bits(&self, range: Range<usize>) -> Self;
|
||||||
|
fn set_bits(&mut self, range: Range<usize>, value: Self) -> &mut Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn range_to_bounds<R: [const] core::ops::RangeBounds<usize>>(
|
||||||
|
range: &R,
|
||||||
|
max: usize,
|
||||||
|
) -> (usize, usize) {
|
||||||
|
let start = match range.start_bound() {
|
||||||
|
Bound::Included(&start) => start,
|
||||||
|
Bound::Excluded(&start) => start + 1,
|
||||||
|
Bound::Unbounded => 0,
|
||||||
|
};
|
||||||
|
let end = match range.end_bound() {
|
||||||
|
Bound::Included(&end) => end + 1,
|
||||||
|
Bound::Excluded(&end) => end,
|
||||||
|
Bound::Unbounded => max,
|
||||||
|
};
|
||||||
|
assert!(
|
||||||
|
start <= end,
|
||||||
|
"Start of range must be less than or equal to end"
|
||||||
|
);
|
||||||
|
assert!(end <= max, "End of range must be less than or equal to max");
|
||||||
|
(start, end)
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_bits_for {
|
||||||
|
($($t:ty),*) => {
|
||||||
|
$(
|
||||||
|
const impl Bits for $t {
|
||||||
|
const BITS: usize = <$t>::BITS as usize;
|
||||||
|
fn get_bit(&self, index: usize) -> bool {
|
||||||
|
assert!(index < <Self as Bits>::BITS, "Index out of bounds");
|
||||||
|
|
||||||
|
(*self & (1 << index)) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_bit(&mut self, index: usize, value: bool) -> &mut Self{
|
||||||
|
assert!(index < <Self as Bits>::BITS, "Index out of bounds");
|
||||||
|
|
||||||
|
if value {
|
||||||
|
*self |= 1 << index;
|
||||||
|
} else {
|
||||||
|
*self &= !(1 << index);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn get_bits(&self, range: Range<usize>) -> Self {
|
||||||
|
let (start, end) = range_to_bounds(&range, <Self as Bits>::BITS);
|
||||||
|
let leading = <Self as Bits>::BITS - end;
|
||||||
|
let bits = (*self << leading) >> (end + start);
|
||||||
|
bits
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_bits(&mut self, range: Range<usize>, value: Self) -> &mut Self{
|
||||||
|
let (start, end) = range_to_bounds(&range, <Self as Bits>::BITS);
|
||||||
|
let mask = ((1 << (end - start)) - 1);
|
||||||
|
let value = (value & mask) << start;
|
||||||
|
|
||||||
|
*self &= !(mask << start);
|
||||||
|
*self |= value;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_bits_for!(u8, u16, u32, u64, u128);
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(const_trait_impl, const_default, abi_x86_interrupt, never_type)]
|
#![feature(const_trait_impl, const_default, const_range)]
|
||||||
#![cfg_attr(test, feature(custom_test_frameworks))]
|
#![cfg_attr(test, feature(custom_test_frameworks))]
|
||||||
#![cfg_attr(test, test_runner(crate::tests::test_runner))]
|
#![cfg_attr(test, test_runner(crate::tests::test_runner))]
|
||||||
#![cfg_attr(test, no_main)]
|
#![cfg_attr(test, no_main)]
|
||||||
#![cfg_attr(test, reexport_test_harness_main = "test_main")]
|
#![cfg_attr(test, reexport_test_harness_main = "test_main")]
|
||||||
|
|
||||||
|
pub mod bits;
|
||||||
pub mod limine;
|
pub mod limine;
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
#![cfg(target_arch = "x86_64")]
|
#![cfg(target_arch = "x86_64")]
|
||||||
|
|
||||||
|
pub mod gdt;
|
||||||
pub mod idt;
|
pub mod idt;
|
||||||
pub mod instructions;
|
pub mod instructions;
|
||||||
|
|
||||||
pub use instructions::hlt;
|
pub use instructions::hlt;
|
||||||
|
|
||||||
|
pub const PAGE_SIZE: usize = 4096;
|
||||||
|
|
||||||
pub fn halt_loop() -> ! {
|
pub fn halt_loop() -> ! {
|
||||||
loop {
|
loop {
|
||||||
hlt();
|
hlt();
|
||||||
|
|
|
||||||
440
kernel/src/x86_64/gdt.rs
Normal file
440
kernel/src/x86_64/gdt.rs
Normal file
|
|
@ -0,0 +1,440 @@
|
||||||
|
use core::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
use bit_field::BitField;
|
||||||
|
|
||||||
|
use crate::{sync::LazyLock, x86_64::idt::ToAddress};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub struct GlobalDescriptorTable {
|
||||||
|
pub null: RawGdtEntry,
|
||||||
|
pub kernel_code: RawGdtEntry,
|
||||||
|
pub kernel_data: RawGdtEntry,
|
||||||
|
pub tss: TssEntry,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GlobalDescriptorTable {
|
||||||
|
pub fn set_tss(&mut self, tss: &'static TaskStateSegment) {
|
||||||
|
const TSS_SIZE: u32 = core::mem::size_of::<TaskStateSegment>() as u32;
|
||||||
|
let tss_base = tss as *const TaskStateSegment as u64;
|
||||||
|
let tss_limit = TSS_SIZE - 1;
|
||||||
|
self.tss = TssEntry::new(tss_base, tss_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let tss = &*TSS;
|
||||||
|
GlobalDescriptorTable {
|
||||||
|
null: RawGdtEntry::new(0, 0, GdtAccess(0), GdtFlags(0)),
|
||||||
|
kernel_code: RawGdtEntry::new(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
GdtAccess(0)
|
||||||
|
.with_segment(true)
|
||||||
|
.with_privilege_level(RING0)
|
||||||
|
.with_present(true)
|
||||||
|
.with_segment_kind(
|
||||||
|
CodeDataSegmentKind::CodeSegment
|
||||||
|
| CodeDataSegmentKind::Executable
|
||||||
|
| CodeDataSegmentKind::ReadWrite,
|
||||||
|
),
|
||||||
|
GdtFlags::new(0xff, false, true, DefaultOperationSize::Bit16, true),
|
||||||
|
),
|
||||||
|
kernel_data: RawGdtEntry::new(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
GdtAccess(0)
|
||||||
|
.with_segment(true)
|
||||||
|
.with_privilege_level(RING0)
|
||||||
|
.with_present(true)
|
||||||
|
.with_segment_kind(CodeDataSegmentKind::ReadWrite),
|
||||||
|
GdtFlags::new(0xff, false, false, DefaultOperationSize::Bit16, true),
|
||||||
|
),
|
||||||
|
tss: TssEntry::new(
|
||||||
|
tss as *const TaskStateSegment as u64,
|
||||||
|
core::mem::size_of::<TaskStateSegment>() as u32 - 1,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for GlobalDescriptorTable {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub struct GdtAccess(u8);
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub struct GdtFlags(u8);
|
||||||
|
|
||||||
|
impl GdtFlags {
|
||||||
|
pub fn new(
|
||||||
|
limit_high: u8,
|
||||||
|
available: bool,
|
||||||
|
code_segment64: bool,
|
||||||
|
default_operation_size: DefaultOperationSize,
|
||||||
|
granularity: bool,
|
||||||
|
) -> Self {
|
||||||
|
let mut flags = GdtFlags(0);
|
||||||
|
flags.set_limit_high(limit_high);
|
||||||
|
flags.set_available(available);
|
||||||
|
flags.set_code_segment64(code_segment64);
|
||||||
|
flags.set_default_operation_size(default_operation_size);
|
||||||
|
flags.set_granularity(granularity);
|
||||||
|
flags
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_available(mut self, available: bool) -> Self {
|
||||||
|
self.set_available(available);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn with_code_segment64(mut self, code_segment64: bool) -> Self {
|
||||||
|
self.set_code_segment64(code_segment64);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn with_default_operation_size(mut self, size: DefaultOperationSize) -> Self {
|
||||||
|
self.set_default_operation_size(size);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn with_granularity(mut self, granularity: bool) -> Self {
|
||||||
|
self.set_granularity(granularity);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn with_limit_high(mut self, limit_high: u8) -> Self {
|
||||||
|
self.set_limit_high(limit_high);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn limit_high(&self) -> u8 {
|
||||||
|
self.0.get_bits(0..4)
|
||||||
|
}
|
||||||
|
pub fn set_limit_high(&mut self, limit_high: u8) {
|
||||||
|
self.0.set_bits(0..4, limit_high);
|
||||||
|
}
|
||||||
|
pub fn available(&self) -> bool {
|
||||||
|
self.0.get_bit(4)
|
||||||
|
}
|
||||||
|
pub fn set_available(&mut self, available: bool) {
|
||||||
|
self.0.set_bit(4, available);
|
||||||
|
}
|
||||||
|
pub fn code_segment64(&self) -> bool {
|
||||||
|
self.0.get_bit(5)
|
||||||
|
}
|
||||||
|
pub fn set_code_segment64(&mut self, code_segment64: bool) {
|
||||||
|
self.0.set_bit(5, code_segment64);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `default_operation_size` is the default size of operands for this segment. If `default_operation_size` is set, the default size is 32 bits, otherwise it is 16 bits.
|
||||||
|
/// On 64-bit mode, this should be 1.
|
||||||
|
pub fn default_operation_size(&self) -> DefaultOperationSize {
|
||||||
|
DefaultOperationSize::from_bool(self.0.get_bit(6))
|
||||||
|
}
|
||||||
|
pub fn set_default_operation_size(&mut self, size: DefaultOperationSize) {
|
||||||
|
self.0.set_bit(6, size.into_u8() != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `granularity` is the unit of the limit field. If `granularity` is set,
|
||||||
|
/// the limit is in 4KiB blocks, otherwise it is in bytes.
|
||||||
|
pub fn granularity(&self) -> bool {
|
||||||
|
self.0.get_bit(7)
|
||||||
|
}
|
||||||
|
pub fn set_granularity(&mut self, granularity: bool) {
|
||||||
|
self.0.set_bit(7, granularity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum SystemSegmentKind {
|
||||||
|
Reserved = 0b0000,
|
||||||
|
Ldt = 0b0010,
|
||||||
|
TssAvailable = 0b1001,
|
||||||
|
TssBusy = 0b1011,
|
||||||
|
CallGate = 0b1100,
|
||||||
|
InterruptGate = 0b1110,
|
||||||
|
TrapGate = 0b1111,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const RING0: u8 = 0;
|
||||||
|
pub const RING1: u8 = 1;
|
||||||
|
pub const RING2: u8 = 2;
|
||||||
|
pub const RING3: u8 = 3;
|
||||||
|
|
||||||
|
bitflags::bitflags! {
|
||||||
|
pub struct CodeDataSegmentKind: u8 {
|
||||||
|
const CodeSegment = 1 << 4;
|
||||||
|
const Executable = 1 << 3;
|
||||||
|
/// `ReadWrite` is set for code segments if they are readable, and for
|
||||||
|
/// data segments if they are writable.
|
||||||
|
const ReadWrite = 1 << 1;
|
||||||
|
const Accessed = 1 << 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SystemSegmentKind {
|
||||||
|
pub fn into_u8(self) -> u8 {
|
||||||
|
self as u8
|
||||||
|
}
|
||||||
|
pub fn from_u8_or_reserved(value: u8) -> Self {
|
||||||
|
match value {
|
||||||
|
0b0010 => SystemSegmentKind::Ldt,
|
||||||
|
0b1001 => SystemSegmentKind::TssAvailable,
|
||||||
|
0b1011 => SystemSegmentKind::TssBusy,
|
||||||
|
0b1100 => SystemSegmentKind::CallGate,
|
||||||
|
0b1110 => SystemSegmentKind::InterruptGate,
|
||||||
|
0b1111 => SystemSegmentKind::TrapGate,
|
||||||
|
_ => SystemSegmentKind::Reserved,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
/// the caller must ensure that the lower 4 bits of `value` are a valid `GdtKind` discriminant.
|
||||||
|
pub unsafe fn from_u8_unchecked(value: u8) -> Self {
|
||||||
|
unsafe { core::mem::transmute(value & 0b1111) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GdtAccess {
|
||||||
|
pub fn with_segment_kind(mut self, kind: CodeDataSegmentKind) -> Self {
|
||||||
|
self.set_segment_kind(kind);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn with_system_segment_kind(mut self, kind: SystemSegmentKind) -> Self {
|
||||||
|
self.set_system_segment_kind(kind);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn with_segment(mut self, segment: bool) -> Self {
|
||||||
|
self.set_segment(segment);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn with_privilege_level(mut self, level: u8) -> Self {
|
||||||
|
self.set_privilege_level(level);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn with_present(mut self, present: bool) -> Self {
|
||||||
|
self.set_present(present);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn system_segment_kind(&self) -> SystemSegmentKind {
|
||||||
|
SystemSegmentKind::from_u8_or_reserved(self.0.get_bits(0..4))
|
||||||
|
}
|
||||||
|
pub fn set_system_segment_kind(&mut self, kind: SystemSegmentKind) {
|
||||||
|
self.0.set_bits(0..4, kind.into_u8());
|
||||||
|
}
|
||||||
|
/// `segment_kind` is valid if `segment` is set, otherwise
|
||||||
|
/// `system_segment_kind` is valid. `segment_kind` is the type of segment,
|
||||||
|
/// and is only valid for code and data segments.
|
||||||
|
pub fn segment_kind(&self) -> CodeDataSegmentKind {
|
||||||
|
CodeDataSegmentKind::from_bits_truncate(self.0.get_bits(0..4))
|
||||||
|
}
|
||||||
|
pub fn set_segment_kind(&mut self, kind: CodeDataSegmentKind) {
|
||||||
|
self.0.set_bits(0..4, kind.bits());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `segment` is set if this is a code or data segment, and clear if it is a system segment.
|
||||||
|
pub fn segment(&self) -> bool {
|
||||||
|
self.0.get_bit(4)
|
||||||
|
}
|
||||||
|
pub fn set_segment(&mut self, system_segment: bool) {
|
||||||
|
self.0.set_bit(4, system_segment);
|
||||||
|
}
|
||||||
|
pub fn privilege_level(&self) -> u8 {
|
||||||
|
self.0.get_bits(5..7)
|
||||||
|
}
|
||||||
|
pub fn set_privilege_level(&mut self, level: u8) {
|
||||||
|
self.0.set_bits(5..7, level);
|
||||||
|
}
|
||||||
|
pub fn present(&self) -> bool {
|
||||||
|
self.0.get_bit(7)
|
||||||
|
}
|
||||||
|
pub fn set_present(&mut self, present: bool) {
|
||||||
|
self.0.set_bit(7, present);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct RawGdtEntry {
|
||||||
|
pub limit_low: u16,
|
||||||
|
pub base_low: u16,
|
||||||
|
pub base_middle: u8,
|
||||||
|
pub access: GdtAccess,
|
||||||
|
pub flags: GdtFlags,
|
||||||
|
pub base_high: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum DefaultOperationSize {
|
||||||
|
Bit16 = 0,
|
||||||
|
Bit32 = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DefaultOperationSize {
|
||||||
|
pub fn into_u8(self) -> u8 {
|
||||||
|
self as u8
|
||||||
|
}
|
||||||
|
pub fn from_bool(value: bool) -> Self {
|
||||||
|
if value {
|
||||||
|
DefaultOperationSize::Bit32
|
||||||
|
} else {
|
||||||
|
DefaultOperationSize::Bit16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<RawGdtEntry> for TssEntry {
|
||||||
|
fn as_ref(&self) -> &RawGdtEntry {
|
||||||
|
&self.gdt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl AsRef<GdtAccess> for RawGdtEntry {
|
||||||
|
fn as_ref(&self) -> &GdtAccess {
|
||||||
|
&self.access
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<GdtFlags> for RawGdtEntry {
|
||||||
|
fn as_ref(&self) -> &GdtFlags {
|
||||||
|
&self.flags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawGdtEntry {
|
||||||
|
pub fn new(limit: u32, base: u32, access: GdtAccess, flags: GdtFlags) -> Self {
|
||||||
|
let limit_low = limit as u16;
|
||||||
|
let limit_high = (limit >> 16) as u8;
|
||||||
|
let base_low = base as u16;
|
||||||
|
let base_middle = (base >> 16) as u8;
|
||||||
|
let base_high = (base >> 24) as u8;
|
||||||
|
|
||||||
|
RawGdtEntry {
|
||||||
|
limit_low,
|
||||||
|
base_low,
|
||||||
|
base_middle,
|
||||||
|
access,
|
||||||
|
flags: flags.with_limit_high(limit_high),
|
||||||
|
base_high,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn access(&self) -> GdtAccess {
|
||||||
|
self.access
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn limit(&self) -> u32 {
|
||||||
|
let limit_low = self.limit_low as u32;
|
||||||
|
let limit_high = (self.flags.limit_high() as u32) << 16;
|
||||||
|
limit_low | limit_high
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn base32(&self) -> u32 {
|
||||||
|
let base_low = self.base_low as u32;
|
||||||
|
let base_middle = (self.base_middle as u32) << 16;
|
||||||
|
let base_high = (self.base_high as u32) << 24;
|
||||||
|
base_low | base_middle | base_high
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct TssEntry {
|
||||||
|
gdt: RawGdtEntry,
|
||||||
|
pub base_ext: u32,
|
||||||
|
reserved: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TssEntry {
|
||||||
|
pub fn base64(&self) -> u64 {
|
||||||
|
let base_low = self.gdt.base32() as u64;
|
||||||
|
let base_ext = self.base_ext as u64;
|
||||||
|
(base_ext << 32) | base_low
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(base: u64, limit: u32) -> Self {
|
||||||
|
let base_low = base as u32;
|
||||||
|
let base_ext = (base >> 32) as u32;
|
||||||
|
|
||||||
|
let mut access = GdtAccess(0);
|
||||||
|
access.set_system_segment_kind(SystemSegmentKind::TssAvailable);
|
||||||
|
access.set_privilege_level(RING0);
|
||||||
|
access.set_present(true);
|
||||||
|
access.set_segment(true);
|
||||||
|
|
||||||
|
let mut granularity = GdtFlags(0);
|
||||||
|
granularity.set_limit_high(limit.get_bits(16..20) as u8);
|
||||||
|
granularity.set_granularity(false);
|
||||||
|
|
||||||
|
TssEntry {
|
||||||
|
gdt: RawGdtEntry::new(limit, base_low, access, granularity),
|
||||||
|
base_ext,
|
||||||
|
reserved: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for TssEntry {
|
||||||
|
type Target = RawGdtEntry;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.gdt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for TssEntry {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.gdt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C, packed(4))]
|
||||||
|
pub struct TaskStateSegment {
|
||||||
|
_reserved1: [u8; 4],
|
||||||
|
pub privilege_stack_table: [u64; 3],
|
||||||
|
_reserved2: [u8; 8],
|
||||||
|
pub interrupt_stack_table: [u64; 7],
|
||||||
|
_reserved3: [u8; 10],
|
||||||
|
pub iomap_base: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TaskStateSegment {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
privilege_stack_table: [0; 3],
|
||||||
|
interrupt_stack_table: [0; 7],
|
||||||
|
iomap_base: size_of::<TaskStateSegment>() as u16,
|
||||||
|
_reserved1: [0; 4],
|
||||||
|
_reserved2: [0; 8],
|
||||||
|
_reserved3: [0; 10],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const impl Default for TaskStateSegment {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const DF_STACK: u8 = 0;
|
||||||
|
pub const NMI_STACK: u8 = 1;
|
||||||
|
pub const MC_STACK: u8 = 2;
|
||||||
|
|
||||||
|
static TSS: LazyLock<TaskStateSegment> = LazyLock::new(|| {
|
||||||
|
let mut tss = TaskStateSegment::new();
|
||||||
|
const STACK_SIZE: usize = super::PAGE_SIZE * 5;
|
||||||
|
static mut STACKS: [[u8; STACK_SIZE]; 3] = [[0; STACK_SIZE]; 3];
|
||||||
|
|
||||||
|
let stack_top = |n: usize| unsafe { STACKS[n].as_ptr().add(STACK_SIZE).to_address() };
|
||||||
|
|
||||||
|
tss.interrupt_stack_table[DF_STACK as usize] = stack_top(DF_STACK as usize);
|
||||||
|
tss.interrupt_stack_table[NMI_STACK as usize] = stack_top(NMI_STACK as usize);
|
||||||
|
tss.interrupt_stack_table[MC_STACK as usize] = stack_top(MC_STACK as usize);
|
||||||
|
|
||||||
|
tss
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue