[PATCH 3/6] i386: global descriptor table manipulation functions
Gedare Bloom
gedare at rtems.org
Wed Nov 12 15:42:10 UTC 2014
On Wed, Nov 12, 2014 at 10:07 AM, Jan Dolezal <dolezj21 at fel.cvut.cz> wrote:
> ---
> 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)
Break apart lines > 80 characters, or shorten the line (by shortening
variable names).
> {
> - 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;
Why write the present field separately from the rest?
> /*
> - * 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)
Anytime you use inline, you should use static. If the function should
be available to other files, it should go in a header. The same goes
for any non-static function, they should have prototypes declared in a
header.
> +{
> + 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)
Prefer to avoid camelNotation. Also check for lines longer than 80 characters.
Is there a reason that sometimes you are using unsigned, and sometimes
unsigned short? I don't like seeing the mixing of int types, and I
would prefer to see explicit-width (e.g. uint32_t and uint16_t) types
if the width is important.
> +{
> + 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));
> +}
use static inline. There is a macro RTEMS_INLINE_ROUTINE that probably
should be used. also, using bitwise-or instead of addition seems
better for composing this field, although I don't have any
particularly compelling reason.
> +
> +/**
> + * 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
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel
More information about the devel
mailing list