[PATCH 3/6] i386: global descriptor table manipulation functions
Jan Dolezal
dolezj21 at fel.cvut.cz
Wed Nov 12 15:07:53 UTC 2014
---
c/src/lib/libbsp/i386/shared/irq/idt.c | 147 +++++++++++++++++++++++++--------
c/src/lib/libcpu/i386/cpu.h | 83 ++++++++++++++++++-
2 files changed, 194 insertions(+), 36 deletions(-)
diff --git a/c/src/lib/libbsp/i386/shared/irq/idt.c b/c/src/lib/libbsp/i386/shared/irq/idt.c
index b79c60a..e6f1d57 100644
--- a/c/src/lib/libbsp/i386/shared/irq/idt.c
+++ b/c/src/lib/libbsp/i386/shared/irq/idt.c
@@ -229,50 +229,33 @@ int i386_get_idt_config (rtems_raw_irq_global_settings** config)
return 1;
}
-/*
- * Caution this function assumes the GDTR has been already set.
- */
-int i386_set_gdt_entry (unsigned short segment_selector, unsigned base,
- unsigned limit)
+int i386_raw_gdt_entry (unsigned short segment_selector_index, segment_descriptors* sd)
{
- unsigned gdt_limit;
+ unsigned gdt_limit;
unsigned short tmp_segment = 0;
- unsigned int limit_adjusted;
- segment_descriptors* gdt_entry_tbl;
+ segment_descriptors* gdt_entry_tbl;
+ unsigned int present;
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;
}
- /*
- * set up limit first
- */
- limit_adjusted = limit;
- if ( limit > 4095 ) {
- gdt_entry_tbl[segment_selector].granularity = 1;
- limit_adjusted /= 4096;
+ if (segment_selector_index == 0) {
+ /* index 0 is not usable */
+ return 0;
}
- 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] = *sd;
+ sd->present = present;
+ gdt_entry_tbl[segment_selector_index].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"
"movw %%es,%0 ; movw %0,%%es\n\t"
"movw %%fs,%0 ; movw %0,%%fs\n\t"
@@ -280,7 +263,101 @@ int i386_set_gdt_entry (unsigned short segment_selector, unsigned base,
"movw %%ss,%0 ; movw %0,%%ss"
: "=r" (tmp_segment)
: "0" (tmp_segment)
- );
-
+ );
return 1;
}
+
+inline void i386_fill_segment_desc_base(unsigned 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;
+}
+
+inline void i386_fill_segment_desc_limit(unsigned 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.
+ */
+int i386_set_gdt_entry (unsigned short segment_selector_index, unsigned base,
+ unsigned 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);
+}
+
+unsigned short i386_next_empty_gdt_entry ()
+{
+ unsigned gdt_limit;
+ segment_descriptors* gdt_entry_tbl;
+ /* initial amount of filled descriptors */
+ static unsigned short 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;
+}
+
+unsigned short i386_cpy_gdt_entry(unsigned short segment_selector_index, segment_descriptors* strucToFill)
+{
+ unsigned 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;
+ }
+
+ *strucToFill = gdt_entry_tbl[segment_selector_index];
+ return segment_selector_index;
+}
+
+segment_descriptors* i386_get_gdt_entry(unsigned short segment_selector_index)
+{
+ unsigned 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];
+}
+
+unsigned i386_limit_gdt_entry(segment_descriptors* gdt_entry)
+{
+ unsigned lim = (gdt_entry->limit_15_0 + (gdt_entry->limit_19_16<<16));
+ if (gdt_entry->granularity) {
+ return lim*4096+4095;
+ }
+ return lim;
+}
diff --git a/c/src/lib/libcpu/i386/cpu.h b/c/src/lib/libcpu/i386/cpu.h
index 4c56731..049a35c 100644
--- a/c/src/lib/libcpu/i386/cpu.h
+++ b/c/src/lib/libcpu/i386/cpu.h
@@ -269,11 +269,92 @@ extern void i386_get_info_from_GDTR (segment_descriptors** table,
extern void i386_set_GDTR (segment_descriptors*,
unsigned limit);
+/**
+ * C callable function:
+ * Puts global descriptor @sd to the global descriptor table on index
+ * @segment_selector_index
+ *
+ * @return 0 FAILED out of GDT range or index is 0, which is not valid
+ * index in GDT
+ * 1 SUCCESS
+ */
+extern int i386_raw_gdt_entry ( unsigned short 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(unsigned 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(unsigned limit,
+ segment_descriptors* sd);
+
/*
* C callable function enabling to set up one raw interrupt handler
*/
extern int i386_set_gdt_entry (unsigned short segment_selector, unsigned base,
- unsigned limit);
+ unsigned limit);
+
+/**
+ * C callable function returns next empty descriptor in GDT.
+ *
+ * @return 0 FAILED GDT is full
+ * <1;65535> segment_selector number as index to GDT
+ */
+extern unsigned short i386_next_empty_gdt_entry (void);
+
+/**
+ * Copies GDT entry at index @segment_selector to structure
+ * pointed to by @strucToFill
+ *
+ * @param segment_selector index to GDT table for specifying descriptor to copy
+ * @return 0 FAILED segment_selector out of GDT range
+ * <1;65535> retrieved segment_selector
+ */
+extern unsigned short i386_cpy_gdt_entry(unsigned short segment_selector,
+ segment_descriptors* strucToFill);
+
+/**
+ * Returns pointer to GDT table at index given by @segment_selector
+ *
+ * @param segment_selector index to GDT table for specifying descriptor to get
+ * @return NULL FAILED segment_selector out of GDT range
+ * pointer to GDT table at @segment_selector
+ */
+extern segment_descriptors* i386_get_gdt_entry(unsigned short segment_selector);
+
+/**
+ * Extracts base address from GDT entry pointed to by @gdt_entry
+ *
+ * @param gdt_entry pointer to entry from which base should be retrieved
+ * @return base address from GDT entry
+*/
+extern inline 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
+ * @return limit value in bytes from GDT entry
+ */
+extern unsigned i386_limit_gdt_entry(segment_descriptors* gdt_entry);
/*
* See page 11.18 Figure 11-12.
--
1.9.1
More information about the devel
mailing list