forked from Imagelibrary/rtems
i386: global descriptor table manipulation functions
This commit is contained in:
committed by
Gedare Bloom
parent
b2db1f5c76
commit
74d2d94041
@@ -229,50 +229,37 @@ int i386_get_idt_config (rtems_raw_irq_global_settings** config)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
uint32_t i386_raw_gdt_entry (uint16_t segment_selector_index,
|
||||||
* Caution this function assumes the GDTR has been already set.
|
segment_descriptors* sd)
|
||||||
*/
|
|
||||||
int i386_set_gdt_entry (unsigned short segment_selector, unsigned base,
|
|
||||||
unsigned limit)
|
|
||||||
{
|
{
|
||||||
unsigned gdt_limit;
|
uint16_t gdt_limit;
|
||||||
unsigned short tmp_segment = 0;
|
uint16_t tmp_segment = 0;
|
||||||
unsigned int limit_adjusted;
|
|
||||||
segment_descriptors* gdt_entry_tbl;
|
segment_descriptors* gdt_entry_tbl;
|
||||||
|
uint8_t present;
|
||||||
|
|
||||||
i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
|
i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
|
||||||
|
|
||||||
if (segment_selector > limit) {
|
if (segment_selector_index >= (gdt_limit+1)/8) {
|
||||||
|
/* index to GDT table out of bounds */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*
|
if (segment_selector_index == 0) {
|
||||||
* set up limit first
|
/* index 0 is not usable */
|
||||||
*/
|
return 0;
|
||||||
limit_adjusted = limit;
|
|
||||||
if ( limit > 4095 ) {
|
|
||||||
gdt_entry_tbl[segment_selector].granularity = 1;
|
|
||||||
limit_adjusted /= 4096;
|
|
||||||
}
|
}
|
||||||
gdt_entry_tbl[segment_selector].limit_15_0 = limit_adjusted & 0xffff;
|
|
||||||
gdt_entry_tbl[segment_selector].limit_19_16 = (limit_adjusted >> 16) & 0xf;
|
|
||||||
/*
|
|
||||||
* set up base
|
|
||||||
*/
|
|
||||||
gdt_entry_tbl[segment_selector].base_address_15_0 = base & 0xffff;
|
|
||||||
gdt_entry_tbl[segment_selector].base_address_23_16 = (base >> 16) & 0xff;
|
|
||||||
gdt_entry_tbl[segment_selector].base_address_31_24 = (base >> 24) & 0xff;
|
|
||||||
/*
|
|
||||||
* set up descriptor type (this may well becomes a parameter if needed)
|
|
||||||
*/
|
|
||||||
gdt_entry_tbl[segment_selector].type = 2; /* Data R/W */
|
|
||||||
gdt_entry_tbl[segment_selector].descriptor_type = 1; /* Code or Data */
|
|
||||||
gdt_entry_tbl[segment_selector].privilege = 0; /* ring 0 */
|
|
||||||
gdt_entry_tbl[segment_selector].present = 1; /* not present */
|
|
||||||
|
|
||||||
|
/* put prepared descriptor into the GDT */
|
||||||
|
present = sd->present;
|
||||||
|
sd->present = 0;
|
||||||
|
gdt_entry_tbl[segment_selector_index].present = 0;
|
||||||
|
RTEMS_COMPILER_MEMORY_BARRIER();
|
||||||
|
gdt_entry_tbl[segment_selector_index] = *sd;
|
||||||
|
RTEMS_COMPILER_MEMORY_BARRIER();
|
||||||
|
gdt_entry_tbl[segment_selector_index].present = present;
|
||||||
|
sd->present = present;
|
||||||
/*
|
/*
|
||||||
* Now, reload all segment registers so the limit takes effect.
|
* Now, reload all segment registers so that the possible changes takes effect.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
__asm__ volatile( "movw %%ds,%0 ; movw %0,%%ds\n\t"
|
__asm__ volatile( "movw %%ds,%0 ; movw %0,%%ds\n\t"
|
||||||
"movw %%es,%0 ; movw %0,%%es\n\t"
|
"movw %%es,%0 ; movw %0,%%es\n\t"
|
||||||
"movw %%fs,%0 ; movw %0,%%fs\n\t"
|
"movw %%fs,%0 ; movw %0,%%fs\n\t"
|
||||||
@@ -281,6 +268,103 @@ int i386_set_gdt_entry (unsigned short segment_selector, unsigned base,
|
|||||||
: "=r" (tmp_segment)
|
: "=r" (tmp_segment)
|
||||||
: "0" (tmp_segment)
|
: "0" (tmp_segment)
|
||||||
);
|
);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void i386_fill_segment_desc_base(uint32_t base,
|
||||||
|
segment_descriptors* sd)
|
||||||
|
{
|
||||||
|
sd->base_address_15_0 = base & 0xffff;
|
||||||
|
sd->base_address_23_16 = (base >> 16) & 0xff;
|
||||||
|
sd->base_address_31_24 = (base >> 24) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void i386_fill_segment_desc_limit(uint32_t limit,
|
||||||
|
segment_descriptors* sd)
|
||||||
|
{
|
||||||
|
sd->granularity = 0;
|
||||||
|
if (limit > 65535) {
|
||||||
|
sd->granularity = 1;
|
||||||
|
limit /= 4096;
|
||||||
|
}
|
||||||
|
sd->limit_15_0 = limit & 0xffff;
|
||||||
|
sd->limit_19_16 = (limit >> 16) & 0xf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Caution this function assumes the GDTR has been already set.
|
||||||
|
*/
|
||||||
|
uint32_t i386_set_gdt_entry (uint16_t segment_selector_index, uint32_t base,
|
||||||
|
uint32_t limit)
|
||||||
|
{
|
||||||
|
segment_descriptors gdt_entry;
|
||||||
|
memset(&gdt_entry, 0, sizeof(gdt_entry));
|
||||||
|
|
||||||
|
i386_fill_segment_desc_limit(limit, &gdt_entry);
|
||||||
|
i386_fill_segment_desc_base(base, &gdt_entry);
|
||||||
|
/*
|
||||||
|
* set up descriptor type (this may well becomes a parameter if needed)
|
||||||
|
*/
|
||||||
|
gdt_entry.type = 2; /* Data R/W */
|
||||||
|
gdt_entry.descriptor_type = 1; /* Code or Data */
|
||||||
|
gdt_entry.privilege = 0; /* ring 0 */
|
||||||
|
gdt_entry.present = 1; /* not present */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now, reload all segment registers so the limit takes effect.
|
||||||
|
*/
|
||||||
|
return i386_raw_gdt_entry(segment_selector_index, &gdt_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t i386_next_empty_gdt_entry ()
|
||||||
|
{
|
||||||
|
uint16_t gdt_limit;
|
||||||
|
segment_descriptors* gdt_entry_tbl;
|
||||||
|
/* initial amount of filled descriptors */
|
||||||
|
static uint16_t segment_selector_index = 2;
|
||||||
|
|
||||||
|
segment_selector_index += 1;
|
||||||
|
i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
|
||||||
|
if (segment_selector_index >= (gdt_limit+1)/8) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return segment_selector_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t i386_cpy_gdt_entry(uint16_t segment_selector_index,
|
||||||
|
segment_descriptors* struct_to_fill)
|
||||||
|
{
|
||||||
|
uint16_t gdt_limit;
|
||||||
|
segment_descriptors* gdt_entry_tbl;
|
||||||
|
|
||||||
|
i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
|
||||||
|
|
||||||
|
if (segment_selector_index >= (gdt_limit+1)/8) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*struct_to_fill = gdt_entry_tbl[segment_selector_index];
|
||||||
|
return segment_selector_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
segment_descriptors* i386_get_gdt_entry(uint16_t segment_selector_index)
|
||||||
|
{
|
||||||
|
uint16_t gdt_limit;
|
||||||
|
segment_descriptors* gdt_entry_tbl;
|
||||||
|
|
||||||
|
i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
|
||||||
|
|
||||||
|
if (segment_selector_index >= (gdt_limit+1)/8) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return &gdt_entry_tbl[segment_selector_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t i386_limit_gdt_entry(segment_descriptors* gdt_entry)
|
||||||
|
{
|
||||||
|
uint32_t lim = (gdt_entry->limit_15_0 + (gdt_entry->limit_19_16<<16));
|
||||||
|
if (gdt_entry->granularity) {
|
||||||
|
return lim*4096+4095;
|
||||||
|
}
|
||||||
|
return lim;
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
*/
|
*/
|
||||||
#include <rtems/score/interrupts.h>
|
#include <rtems/score/interrupts.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <rtems/score/basedefs.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Segment Access Routines
|
* Segment Access Routines
|
||||||
@@ -256,7 +256,7 @@ typedef struct {
|
|||||||
unsigned int operation_size : 1;
|
unsigned int operation_size : 1;
|
||||||
unsigned int granularity : 1;
|
unsigned int granularity : 1;
|
||||||
unsigned int base_address_31_24 : 8;
|
unsigned int base_address_31_24 : 8;
|
||||||
}segment_descriptors;
|
} RTEMS_COMPILER_PACKED_ATTRIBUTE segment_descriptors;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* C callable function enabling to get easilly usable info from
|
* C callable function enabling to get easilly usable info from
|
||||||
@@ -271,11 +271,94 @@ extern void i386_get_info_from_GDTR (segment_descriptors** table,
|
|||||||
extern void i386_set_GDTR (segment_descriptors*,
|
extern void i386_set_GDTR (segment_descriptors*,
|
||||||
uint16_t limit);
|
uint16_t limit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C callable function:
|
||||||
|
* Puts global descriptor @sd to the global descriptor table on index
|
||||||
|
* @segment_selector_index
|
||||||
|
*
|
||||||
|
* @retval 0 FAILED out of GDT range or index is 0, which is not valid
|
||||||
|
* index in GDT
|
||||||
|
* 1 SUCCESS
|
||||||
|
*/
|
||||||
|
extern uint32_t i386_raw_gdt_entry (uint16_t segment_selector_index,
|
||||||
|
segment_descriptors* sd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C callable function
|
||||||
|
* fills @sd with provided @base in appropriate fields of @sd
|
||||||
|
*
|
||||||
|
* @param base 32-bit address to be set as descriptor's base
|
||||||
|
* @param sd descriptor being filled with @base
|
||||||
|
*/
|
||||||
|
extern void i386_fill_segment_desc_base (uint32_t base,
|
||||||
|
segment_descriptors* sd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C callable function
|
||||||
|
* fills @sd with provided @limit in appropriate fields of @sd
|
||||||
|
* also influences granularity bit
|
||||||
|
*
|
||||||
|
* @param limit 32-bit value representing number of limit bytes
|
||||||
|
* @param sd descriptor being filled with @limit
|
||||||
|
*/
|
||||||
|
extern void i386_fill_segment_desc_limit (uint32_t limit,
|
||||||
|
segment_descriptors* sd);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* C callable function enabling to set up one raw interrupt handler
|
* C callable function enabling to set up one raw interrupt handler
|
||||||
*/
|
*/
|
||||||
extern int i386_set_gdt_entry (unsigned short segment_selector, unsigned base,
|
extern uint32_t i386_set_gdt_entry (uint16_t segment_selector,
|
||||||
unsigned limit);
|
uint32_t base,
|
||||||
|
uint32_t limit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C callable function returns next empty descriptor in GDT.
|
||||||
|
*
|
||||||
|
* @retval 0 FAILED GDT is full
|
||||||
|
* <1;65535> segment_selector number as index to GDT
|
||||||
|
*/
|
||||||
|
extern uint16_t i386_next_empty_gdt_entry (void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies GDT entry at index @segment_selector to structure
|
||||||
|
* pointed to by @struct_to_fill
|
||||||
|
*
|
||||||
|
* @param segment_selector index to GDT table for specifying descriptor to copy
|
||||||
|
* @retval 0 FAILED segment_selector out of GDT range
|
||||||
|
* <1;65535> retrieved segment_selector
|
||||||
|
*/
|
||||||
|
extern uint16_t i386_cpy_gdt_entry (uint16_t segment_selector,
|
||||||
|
segment_descriptors* struct_to_fill);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns pointer to GDT table at index given by @segment_selector
|
||||||
|
*
|
||||||
|
* @param segment_selector index to GDT table for specifying descriptor to get
|
||||||
|
* @retval NULL FAILED segment_selector out of GDT range
|
||||||
|
* pointer to GDT table at @segment_selector
|
||||||
|
*/
|
||||||
|
extern segment_descriptors* i386_get_gdt_entry (uint16_t sgmnt_selector);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts base address from GDT entry pointed to by @gdt_entry
|
||||||
|
*
|
||||||
|
* @param gdt_entry pointer to entry from which base should be retrieved
|
||||||
|
* @retval base address from GDT entry
|
||||||
|
*/
|
||||||
|
RTEMS_INLINE_ROUTINE void* i386_base_gdt_entry (segment_descriptors* gdt_entry)
|
||||||
|
{
|
||||||
|
return (void*)(gdt_entry->base_address_15_0 |
|
||||||
|
(gdt_entry->base_address_23_16<<16) |
|
||||||
|
(gdt_entry->base_address_31_24<<24));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts limit in bytes from GDT entry pointed to by @gdt_entry
|
||||||
|
*
|
||||||
|
* @param gdt_entry pointer to entry from which limit should be retrieved
|
||||||
|
* @retval limit value in bytes from GDT entry
|
||||||
|
*/
|
||||||
|
extern uint32_t i386_limit_gdt_entry (segment_descriptors* gdt_entry);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See page 11.18 Figure 11-12.
|
* See page 11.18 Figure 11-12.
|
||||||
|
|||||||
Reference in New Issue
Block a user