/* * segments.c * * Copyright (C) 2013 Aleksandar Andrejevic * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include static gdt_descriptor_t gdt_table[GDT_MAX_ENTRIES]; static dword_t gdt_entry_count = 0; static word_t system_code_sel, system_data_sel, user_code_sel, user_data_sel, tss_sel; static tss_entry_t tss; extern void init_cpu_gdt(gdt_descriptor_t *table, dword_t size, word_t code_selector, word_t data_selector, word_t tss_selector); dword_t get_kernel_esp(void) { return tss.esp0; } void set_kernel_esp(dword_t esp) { tss.esp0 = esp; } word_t get_kernel_code_selector(void) { return system_code_sel; } word_t get_kernel_data_selector(void) { return system_data_sel; } word_t get_user_code_selector(void) { return user_code_sel; } word_t get_user_data_selector(void) { return user_data_sel; } word_t gdt_create_segment(dword_t base, dword_t limit, bool_t executable, byte_t priv_level, bool_t readwrite, bool_t dirconf, bool_t large) { word_t selector; bool_t granularity = FALSE; if (gdt_entry_count == GDT_MAX_ENTRIES) return 0; if (priv_level > 3) return 0; if (limit > 0xFFFFF) { limit >>= 12; granularity = TRUE; } gdt_table[gdt_entry_count].base = base & 0x00FFFFFF; gdt_table[gdt_entry_count].base_high = base >> 24; gdt_table[gdt_entry_count].limit = limit & 0xFFFF; gdt_table[gdt_entry_count].limit_high = limit >> 16; gdt_table[gdt_entry_count].present = TRUE; gdt_table[gdt_entry_count].accessed = FALSE; gdt_table[gdt_entry_count].executable = executable ? TRUE : FALSE; gdt_table[gdt_entry_count].readwrite = readwrite ? TRUE : FALSE; gdt_table[gdt_entry_count].dirconf = dirconf ? TRUE : FALSE; gdt_table[gdt_entry_count].rpl = priv_level; gdt_table[gdt_entry_count].size = large ? TRUE : FALSE; gdt_table[gdt_entry_count].granularity = granularity; gdt_table[gdt_entry_count].standard = 1; gdt_table[gdt_entry_count].always_zero = 0; selector = (gdt_entry_count << 3) | priv_level; gdt_entry_count++; return selector; } word_t gdt_create_tss(tss_entry_t *base, dword_t limit) { word_t selector; if (gdt_entry_count == GDT_MAX_ENTRIES) return 0; if (limit < sizeof(tss_entry_t)) return 0; gdt_table[gdt_entry_count].base = (dword_t)base & 0x00FFFFFF; gdt_table[gdt_entry_count].base_high = (dword_t)base >> 24; gdt_table[gdt_entry_count].limit = limit & 0xFFFF; gdt_table[gdt_entry_count].limit_high = limit >> 16; gdt_table[gdt_entry_count].present = TRUE; gdt_table[gdt_entry_count].accessed = TRUE; gdt_table[gdt_entry_count].executable = TRUE; gdt_table[gdt_entry_count].readwrite = FALSE; gdt_table[gdt_entry_count].dirconf = FALSE; gdt_table[gdt_entry_count].rpl = 0; gdt_table[gdt_entry_count].size = TRUE; gdt_table[gdt_entry_count].granularity = FALSE; gdt_table[gdt_entry_count].standard = 0; gdt_table[gdt_entry_count].always_zero = 0; selector = gdt_entry_count << 3; gdt_entry_count++; return selector; } void segments_init(void) { gdt_entry_count = 0; memset(gdt_table, 0, sizeof(gdt_table)); gdt_create_segment(0, 0, FALSE, 0, FALSE, FALSE, FALSE); system_code_sel = gdt_create_segment(0x00000000, 0xFFFFFFFF, TRUE, 0, TRUE, FALSE, TRUE); system_data_sel = gdt_create_segment(0x00000000, 0xFFFFFFFF, FALSE, 0, TRUE, FALSE, TRUE); user_code_sel = gdt_create_segment(0x00000000, 0xFFFFFFFF, TRUE, 3, TRUE, FALSE, TRUE); user_data_sel = gdt_create_segment(0x00000000, 0xFFFFFFFF, FALSE, 3, TRUE, FALSE, TRUE); tss_sel = gdt_create_tss(&tss, sizeof(tss)); memset(&tss, 0, sizeof(tss)); tss.ss0 = system_data_sel; tss.iopb = sizeof(tss_entry_t); init_cpu_gdt(gdt_table, sizeof(gdt_table), system_code_sel, system_data_sel, tss_sel); }