// Copyright (c) 2025 shibedrill
// SPDX-License-Identifier: MIT

use core::arch::asm;
use core::ptr::addr_of_mut;

use intbits::Bits;
use x86_64::structures::gdt::*;

#[allow(dead_code)]
pub trait GdtEntryRead {
    fn base(&self) -> usize;
    fn limit(&self) -> usize;
    fn flags(&self) -> u8;
    fn access(&self) -> u8;
}

impl GdtEntryRead for Entry {
    fn base(&self) -> usize {
        ((self.raw().bits(56..=63) << 24) & self.raw().bits(16..=39)) as usize
    }
    fn limit(&self) -> usize {
        ((self.raw().bits(48..=51) << 16) & self.raw().bits(16..=31)) as usize
    }
    fn access(&self) -> u8 {
        self.raw().bits(40..=47) as u8
    }
    fn flags(&self) -> u8 {
        self.raw().bits(52..=55) as u8
    }
}

#[allow(dead_code)]
pub fn read_gdt() -> GlobalDescriptorTable {
    let mut addr: u128 = 0;
    unsafe {
        asm! {
            "sgdt [rax]",
            in("rax") addr_of_mut!(addr),
        }
    }
    // x86 gdtr: Lower 2 8-bit bytes (lower 16 bits) is the size of the GDT,
    // in 8-bit bytes, minus one.
    // Bits 16 through 79 are the virtual address of the GDT.
    let (limit, addr) = (addr.bits(0..=15) as usize + 1, addr.bits(16..=79) as u64);
    let gdt_raw: &[u64] = unsafe { core::slice::from_raw_parts(addr as *const u64, limit / 8) };
    GlobalDescriptorTable::from_raw_entries(gdt_raw)
}
