/* Copyright (C) 2008 Emmanuel Varoquaux This file is part of XOS. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include /* descripteurs */ static void get_segment_descr_data(const struct descr_struct *descr, struct descr_data_struct *descr_data) { descr_data->base = (descr->base3 << 24) | (descr->base2 << 16) | descr->base1; descr_data->limit = ((descr->limit2_flags2 & 0xf) << 16) | descr->limit1; descr_data->granularity = (descr->limit2_flags2 >> 7) & 0x1; descr_data->avl = (descr->limit2_flags2 >> 4) & 0x1; switch (descr_data->type) { case 0: /* system */ descr_data->x = (descr->limit2_flags2 >> 6) & 0x1; break; case 1: /* segment */ switch (descr_data->segment_type) { case 0: /* data */ descr_data->big = (descr->limit2_flags2 >> 6) & 0x1; break; case 1: /* code */ descr_data->def = (descr->limit2_flags2 >> 6) & 0x1; break; } break; } } static void get_gate_descr_data(const struct descr_struct *descr, struct descr_data_struct *descr_data) { descr_data->selector = descr->selector; switch (descr_data->system_type) { case SDT_386CALLGT: /* 386 Call Gate */ descr_data->dword_count = descr->dword_count & 0x1f; case SDT_386INTGT: /* 386 Interrupt Gate */ case SDT_386TRAPGT: /* 386 Trap Gate */ descr_data->offset = (descr->offset2 << 16) | descr->offset1; case SDT_TASKGT: /* Task Gate */ break; } } void get_descr(const struct descr_struct *descr, struct descr_data_struct *descr_data) { descr_data->type = (descr->flags1 >> 4) & 0x1; switch (descr_data->type) { case 0: /* system */ descr_data->system_type = descr->flags1 & 0xf; break; case 1: /* segment */ descr_data->accessed = descr->flags1 & 0x1; descr_data->segment_type = (descr->flags1 >> 3) & 0x1; switch (descr_data->segment_type) { case 0: /* data */ descr_data->writable = (descr->flags1 >> 1) & 0x1; descr_data->expand_down = (descr->flags1 >> 2) & 0x1; break; case 1: /* code */ descr_data->readable = (descr->flags1 >> 1) & 0x1; descr_data->conforming = (descr->flags1 >> 2) & 0x1; break; } break; } descr_data->dpl = (descr->flags1 >> 5) & 0x2; descr_data->present = (descr->flags1 >> 7) & 0x1; switch (descr_data->present) { case 1: /* present */ switch (descr_data->type) { case 0: /* system */ switch (descr_data->system_type) { case SDT_LDT: /* LDT */ case SDT_AVL386TSS: /* Available 386 TSS */ get_segment_descr_data(descr, descr_data); break; case SDT_TASKGT: /* Task Gate */ case SDT_386CALLGT: /* 386 Call Gate */ case SDT_386INTGT: /* 386 Interrupt Gate */ case SDT_386TRAPGT: /* 386 Trap Gate */ get_gate_descr_data(descr, descr_data); break; default: panic("get_descr: Descriptor not supported"); } break; case 1: /* segment */ get_segment_descr_data(descr, descr_data); break; } } } void set_segment_descr(struct descr_struct *descr, const struct descr_data_struct *descr_data) { descr->flags1 = (descr_data->present << 7) | (descr_data->dpl << 5); switch (descr_data->type) { case 0: /* system */ descr->flags1 |= descr_data->system_type; break; case 1: /* segment */ descr->flags1 |= 0x10 | descr_data->accessed; switch (descr_data->segment_type) { case 0: /* data */ descr->flags1 |= (descr_data->expand_down << 2) | (descr_data->writable << 1); break; case 1: /* code */ descr->flags1 |= 0x8 | (descr_data->conforming << 2) | (descr_data->readable << 1); break; } break; } switch (descr_data->present) { case 1: /* present */ descr->limit1 = descr_data->limit & 0xffff; descr->base1 = descr_data->base & 0xffff; descr->base2 = (descr_data->base >> 16) & 0xff; descr->limit2_flags2 = (descr_data->granularity << 7) | (descr_data->avl << 4) | ((descr_data->limit >> 16) & 0xf); descr->base3 = (descr_data->base >> 24) & 0xff; switch (descr_data->type) { case 0: /* system */ descr->limit2_flags2 |= descr_data->x << 6; break; case 1: /* segment */ switch (descr_data->segment_type) { case 0: /* data */ descr->limit2_flags2 |= descr_data->big << 6; break; case 1: /* code */ descr->limit2_flags2 |= descr_data->def << 6; break; } break; } break; } } void set_gate_descr(struct descr_struct *descr, const struct descr_data_struct *descr_data) { descr->flags = (descr_data->present << 7) | (descr_data->dpl << 5) | descr_data->system_type; descr->selector = descr_data->selector; switch (descr_data->system_type) { case SDT_386CALLGT: /* 386 Call Gate */ descr->dword_count = descr_data->dword_count; descr->offset1 = descr_data->offset & 0xffff; descr->offset2 = (descr_data->offset >> 16) & 0xffff; break; case SDT_386INTGT: /* 386 Interrupt Gate */ case SDT_386TRAPGT: /* 386 Trap Gate */ descr->dword_count = 0; descr->offset1 = descr_data->offset & 0xffff; descr->offset2 = (descr_data->offset >> 16) & 0xffff; break; case SDT_TASKGT: /* Task Gate */ break; } } void set_descr(struct descr_struct *descr, const struct descr_data_struct *descr_data) { switch (descr_data->type) { case 0: /* system */ switch (descr_data->system_type) { case SDT_LDT: /* LDT */ case SDT_AVL386TSS: /* Available 386 TSS */ set_segment_descr(descr, descr_data); break; case SDT_TASKGT: /* Task Gate */ case SDT_386CALLGT: /* 386 Call Gate */ case SDT_386INTGT: /* 386 Interrupt Gate */ case SDT_386TRAPGT: /* 386 Trap Gate */ set_gate_descr(descr, descr_data); break; default: panic("set_descr: Descriptor not supported"); } break; case 1: /* segment */ set_segment_descr(descr, descr_data); break; } } /* selecteurs */ void get_sel(const unsigned short *sel, struct sel_data_struct *sel_data) { sel_data->rpl = *sel & 0x3; sel_data->table_ind = (*sel >> 2) & 0x1; sel_data->index = (*sel >> 3) & 0x1fff; } void set_sel(unsigned short *sel, const struct sel_data_struct *sel_data) { *sel = (sel_data->index << 3) | (sel_data->table_ind << 2) | sel_data->rpl; } /* adresses lineaires */ void get_linear_address(const unsigned long *linear_address, struct linear_address_data_struct *linear_address_data) { linear_address_data->dir = (*linear_address >> 22) & 0x3ff; linear_address_data->page = (*linear_address >> 12) & 0x3ff; linear_address_data->offset = *linear_address & 0xfff; } void set_linear_address(unsigned long *linear_address, const struct linear_address_data_struct *linear_address_data) { *linear_address = (linear_address_data->dir << 22) | (linear_address_data->page << 12) | linear_address_data->offset; } /* entrees de table des pages */ void get_page_table_entry(const unsigned long *page_table_entry, struct page_table_entry_data_struct *page_table_entry_data) { page_table_entry_data->present = *page_table_entry & 0x1; if (page_table_entry_data->present) { page_table_entry_data->rw = (*page_table_entry >> 1) & 0x1; page_table_entry_data->us = (*page_table_entry >> 2) & 0x1; page_table_entry_data->accessed = (*page_table_entry >> 5) & 0x1; page_table_entry_data->dirty = (*page_table_entry >> 6) & 0x1; page_table_entry_data->avail = (*page_table_entry >> 9) & 0x7; page_table_entry_data->page_frame_addr = *page_table_entry & 0xfffff000; } } void set_page_table_entry(unsigned long *page_table_entry, const struct page_table_entry_data_struct *page_table_entry_data) { *page_table_entry &= 0x198; /* on efface page_table_entry sauf les bits reserves */ *page_table_entry |= page_table_entry_data->present; if (page_table_entry_data->present) *page_table_entry |= (page_table_entry_data->page_frame_addr & 0xfffff000) | (page_table_entry_data->avail << 9) | (page_table_entry_data->dirty << 6) | (page_table_entry_data->accessed << 5) | (page_table_entry_data->us << 2) | (page_table_entry_data->rw << 1); } void clear_page_table(unsigned long *page_table) { memset(page_table, 0, PAGE_SIZE); } /* segments d'etat de tache */ void get_tss(const struct tss_struct *tss, struct tss_data_struct *tss_data) { tss_data->pdbr = tss->cr3; tss_data->ldt = tss->ldt; tss_data->ss0 = tss->ss0; tss_data->esp0 = tss->esp0; tss_data->ss1 = tss->ss1; tss_data->esp1 = tss->esp1; tss_data->ss2 = tss->ss2; tss_data->esp2 = tss->esp2; tss_data->trap = tss->trap_res12 & 0x1; tss_data->iomap_base = tss->iomap_base; tss_data->eax = tss->eax; tss_data->ebx = tss->ebx; tss_data->ecx = tss->ecx; tss_data->edx = tss->edx; tss_data->ebp = tss->ebp; tss_data->esp = tss->esp; tss_data->esi = tss->esi; tss_data->edi = tss->edi; tss_data->cs = tss->cs; tss_data->ds = tss->ds; tss_data->es = tss->es; tss_data->fs = tss->fs; tss_data->gs = tss->gs; tss_data->ss = tss->ss; tss_data->eflags = tss->eflags; tss_data->eip = tss->eip; tss_data->previous = tss->previous; } void set_tss(struct tss_struct *tss, const struct tss_data_struct *tss_data) { tss->previous = tss_data->previous; tss->esp0 = tss_data->esp0; tss->ss0 = tss_data->ss0; tss->esp1 = tss_data->esp1; tss->ss1 = tss_data->ss1; tss->esp2 = tss_data->esp2; tss->ss2 = tss_data->ss2; tss->cr3 = tss_data->pdbr; tss->eip = tss_data->eip; tss->eflags = tss_data->eflags; tss->eax = tss_data->eax; tss->ecx = tss_data->ecx; tss->edx = tss_data->edx; tss->ebx = tss_data->ebx; tss->esp = tss_data->esp; tss->ebp = tss_data->ebp; tss->esi = tss_data->esi; tss->edi = tss_data->edi; tss->es = tss_data->es; tss->cs = tss_data->cs; tss->ss = tss_data->ss; tss->ds = tss_data->ds; tss->fs = tss_data->fs; tss->gs = tss_data->gs; tss->ldt = tss_data->ldt; tss->trap_res12 = (tss->trap_res12 & 0xfffe) | tss_data->trap; tss->iomap_base = tss_data->iomap_base; } /* code d'erreur */ void get_error_code(const unsigned long *error_code, struct error_code_data_struct *error_code_data) { error_code_data->ext = *error_code & 0x1; error_code_data->idt = (*error_code >> 1) & 0x1; error_code_data->table_ind = (*error_code >> 2) & 0x1; error_code_data->index = (*error_code >> 3) & 0x1fff; } void set_error_code(unsigned long *error_code, const struct error_code_data_struct *error_code_data) { *error_code = (error_code_data->index << 3) | (error_code_data->table_ind << 2) | (error_code_data->idt << 1) | error_code_data->ext; } /* code d'erreur des defauts de page */ void get_page_fault_error_code(const unsigned long *error_code, struct page_fault_error_code_data_struct *error_code_data) { error_code_data->cause = *error_code & 0x1; error_code_data->access = (*error_code >> 1) & 0x1; error_code_data->mode = (*error_code >> 2) & 0x1; } void set_page_fault_error_code(unsigned long *error_code, const struct page_fault_error_code_data_struct *error_code_data) { *error_code = (error_code_data->mode << 2) | (error_code_data->access << 1) | error_code_data->cause; }