/* 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;
}