/* * Copyright (C) 2017 Robin Krahl * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. */ #include #include #include #include struct gdt_sgmt { uint16_t limit_lo; uint16_t base_lo; uint8_t base_hi; uint8_t access; uint8_t flags_limit_h; uint8_t base_vhi; } __attribute__((packed)); enum gdt_sgmts { GDT_SGMT_NULL, GDT_SGMT_CODE, GDT_SGMT_DATA, GDT_SGMT_COUNT }; struct gdt_sgmt gdt[GDT_SGMT_COUNT]; struct gdtp gdtp = { .limit = GDT_SGMT_COUNT * sizeof(*gdt) - 1, .pointer = gdt, }; static void gdt_sgmt_set(uint32_t base, uint32_t limit, uint8_t access, struct gdt_sgmt *s) { if (limit <= 0xFFFF) { s->flags_limit_h = 0x40; } else { if ((limit & 0xFFF) != 0xFFF) { limit = (limit >> 12) - 1; } else { limit >>= 12; } s->flags_limit_h = 0xC0; } s->limit_lo = limit & 0xFFFF; s->flags_limit_h |= (limit >> 16) & 0xF; s->base_lo = base & 0xFFFF; s->base_hi = (base >> 16) & 0xFF; s->base_vhi = (base >> 24) & 0xFF; s->access = access; } void gdt_init(void) { ker_dbg("Initializing GDT ..."); gdt_sgmt_set(0, 0, 0, &gdt[GDT_SGMT_NULL]); gdt_sgmt_set(0, 64 * 1024 * 1024, 0x9A, &gdt[GDT_SGMT_CODE]); gdt_sgmt_set(0, 64 * 1024 * 1024, 0x92, &gdt[GDT_SGMT_NULL]); gdtset(gdtp); } uint16_t gdt_get_code_offset(void) { return GDT_SGMT_CODE * sizeof(*gdt); }