summaryrefslogblamecommitdiffstats
path: root/arch/x86_64/gdt.c
blob: 07a80975a2eebec649ae8c5f179a295b04bcd27d (plain) (tree)


























                                                           
                                                                 



                           
                 

                 
               










                                              



                 











                                              



                 





                                              
                                                                 



                           
                 

                 
               


                         
                        


                                         
                 



                         
               




























                                                                         





                                                 




                         





                                                 
#include "tables.h"
#include "tss.h"

enum
{
    GDT_SEGMENT_KERNEL_NULL = 0,
    GDT_SEGMENT_KERNEL_CODE,
    GDT_SEGMENT_KERNEL_DATA,

    GDT_SEGMENT_USER_NULL,
    GDT_SEGMENT_USER_DATA,
    GDT_SEGMENT_USER_CODE,

    GDT_SEGMENT_TSS_LOW,
    GDT_SEGMENT_TSS_HIGH,

    GDT_SEGMENT_COUNT
};

__attribute__((aligned(0x1000)))
static struct SegmentDescriptor s_gdtd[GDT_SEGMENT_COUNT] =
{
    { 0 },  /* Kernel NULL */
    {       /* Kernel Code (64-bit RO EX DPL0) */
        .limit_0_15 = 0xFFFF,
        .base_0_15 = 0,
        .base_16_23 = 0,
        .type = CD_SEGMENT_TYPE_CODE | CD_SEGMENT_TYPE_WRITEABLE,
        .s = 1,
        .dpl = 0,
        .p = 1,
        .limit_16_19 = 0xF,
        .avl = 0,
        .l = 1,
        .d_b = 0,
        .g = 1,
        .base_24_31 = 0
    },
    {       /* Kernel Data (64-bit RW DPL0) */
        .limit_0_15 = 0xFFFF,
        .base_0_15 = 0,
        .base_16_23 = 0,
        .type = CD_SEGMENT_TYPE_WRITEABLE,
        .s = 1,
        .dpl = 0,
        .p = 1,
        .limit_16_19 = 0xF,
        .avl = 0,
        .l = 0,
        .d_b = 1,
        .g = 1,
        .base_24_31 = 0
    },
    { 0 },  /* User NULL */
    {       /* User Data (64-bit RO EX DPL3)*/
        .limit_0_15 = 0xFFFF,
        .base_0_15 = 0,
        .base_16_23 = 0,
        .type = CD_SEGMENT_TYPE_WRITEABLE,
        .s = 1,
        .dpl = 3,
        .p = 1,
        .limit_16_19 = 0xF,
        .avl = 0,
        .l = 0,
        .d_b = 1,
        .g = 1,
        .base_24_31 = 0,
    },
    {       /* User Code (64-bit RO EX DPL3)*/
        .limit_0_15 = 0xFFFF,
        .base_0_15 = 0,
        .base_16_23 = 0,
        .type = CD_SEGMENT_TYPE_CODE | CD_SEGMENT_TYPE_WRITEABLE,
        .s = 1,
        .dpl = 3,
        .p = 1,
        .limit_16_19 = 0xF,
        .avl = 0,
        .l = 1,
        .d_b = 0,
        .g = 1,
        .base_24_31 = 0,
    },
    {       /* TSS Low */
        .limit_0_15 = 0,
        .base_0_15 = 0,
        .base_16_23 = 0,
        .type = S_SEGMENT_TYPE_TSS_AVAIL,
        .avl = 0,
        .s = 0,
        .dpl = 0,
        .p = 1,
        .limit_16_19 = 0,
        .l = 0,
        .d_b = 0,
        .g = 0,
        .base_24_31 = 0,
    },
    { 0 }
};
static struct XDTR s_gdtr = {
    .length = sizeof(s_gdtd) - 1,
    .address = (uintptr_t)&s_gdtd
};

static struct TSS s_tss = {
    
};

extern void x86_64_lgdt(struct XDTR *gdtr);
extern void x86_64_flush_tss(void);
void
x86_64_load_gdt(void)
{
    {
        struct SegmentDescriptor *tss_lo = &s_gdtd[GDT_SEGMENT_TSS_LOW];
        struct SegmentDescriptor *tss_hi = &s_gdtd[GDT_SEGMENT_TSS_HIGH];
        uintptr_t tssb = (uintptr_t)&s_tss;
        tss_lo->base_0_15 = tssb & 0xFFFF;
        tss_lo->base_16_23 = (tssb >> 16) & 0xFF;
        tss_lo->base_24_31 = (tssb >> 24) & 0xFF;
        tss_hi->limit_0_15 = (tssb >> 32) & 0xFFFF;
        tss_hi->base_0_15 = (tssb >> 48) & 0xFFFF;

        size_t tssl = sizeof(struct TSS) - 1;
        tss_lo->limit_0_15 = tssl & 0xFFFF;
        tss_lo->limit_16_19 = (tssl >> 16) & 0xF;

        s_tss.iobp = sizeof(struct TSS);
    }

    x86_64_lgdt(&s_gdtr);
    x86_64_flush_tss();
}

void tss_set_rsp(uint8_t dpl, uintptr_t rsp)
{
    s_tss.rsp[dpl][0] = rsp & 0xFFFFFFFF;
    s_tss.rsp[dpl][1] = (rsp >> 32) & 0xFFFFFFFF;
}