Changeset 74d2d940 in rtems


Ignore:
Timestamp:
Nov 20, 2014, 2:00:30 PM (5 years ago)
Author:
Jan Dolezal <dolezj21@…>
Branches:
4.11, master
Children:
586c86c7
Parents:
b2db1f5c
git-author:
Jan Dolezal <dolezj21@…> (11/20/14 14:00:30)
git-committer:
Gedare Bloom <gedare@…> (11/20/14 14:52:39)
Message:

i386: global descriptor table manipulation functions

Location:
c/src/lib
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • c/src/lib/libbsp/i386/shared/irq/idt.c

    rb2db1f5c r74d2d940  
    230230}
    231231
    232 /*
    233  * Caution this function assumes the GDTR has been already set.
    234  */
    235 int i386_set_gdt_entry (unsigned short segment_selector, unsigned base,
    236                         unsigned limit)
    237 {
    238     unsigned                    gdt_limit;
    239     unsigned short              tmp_segment = 0;
    240     unsigned int                limit_adjusted;
    241     segment_descriptors*        gdt_entry_tbl;
     232uint32_t i386_raw_gdt_entry (uint16_t segment_selector_index,
     233                             segment_descriptors* sd)
     234{
     235    uint16_t                gdt_limit;
     236    uint16_t                tmp_segment = 0;
     237    segment_descriptors*    gdt_entry_tbl;
     238    uint8_t                 present;
    242239
    243240    i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
    244241
    245     if (segment_selector > limit) {
    246       return 0;
    247     }
    248     /*
    249      * set up limit first
    250      */
    251     limit_adjusted = limit;
    252     if ( limit > 4095 ) {
    253       gdt_entry_tbl[segment_selector].granularity = 1;
    254       limit_adjusted /= 4096;
    255     }
    256     gdt_entry_tbl[segment_selector].limit_15_0  = limit_adjusted & 0xffff;
    257     gdt_entry_tbl[segment_selector].limit_19_16 = (limit_adjusted >> 16) & 0xf;
    258     /*
    259      * set up base
    260      */
    261     gdt_entry_tbl[segment_selector].base_address_15_0  = base & 0xffff;
    262     gdt_entry_tbl[segment_selector].base_address_23_16 = (base >> 16) & 0xff;
    263     gdt_entry_tbl[segment_selector].base_address_31_24 = (base >> 24) & 0xff;
    264     /*
    265      * set up descriptor type (this may well becomes a parameter if needed)
    266      */
    267     gdt_entry_tbl[segment_selector].type                = 2;    /* Data R/W */
    268     gdt_entry_tbl[segment_selector].descriptor_type     = 1;    /* Code or Data */
    269     gdt_entry_tbl[segment_selector].privilege           = 0;    /* ring 0 */
    270     gdt_entry_tbl[segment_selector].present             = 1;    /* not present */
    271 
    272     /*
    273      * Now, reload all segment registers so the limit takes effect.
    274      */
    275 
     242    if (segment_selector_index >= (gdt_limit+1)/8) {
     243      /* index to GDT table out of bounds */
     244      return 0;
     245    }
     246    if (segment_selector_index == 0) {
     247      /* index 0 is not usable */
     248      return 0;
     249    }
     250
     251    /* put prepared descriptor into the GDT */
     252    present = sd->present;
     253    sd->present = 0;
     254    gdt_entry_tbl[segment_selector_index].present = 0;
     255    RTEMS_COMPILER_MEMORY_BARRIER();
     256    gdt_entry_tbl[segment_selector_index] = *sd;
     257    RTEMS_COMPILER_MEMORY_BARRIER();
     258    gdt_entry_tbl[segment_selector_index].present = present;
     259    sd->present = present;
     260    /*
     261     * Now, reload all segment registers so that the possible changes takes effect.
     262     */
    276263    __asm__ volatile( "movw %%ds,%0 ; movw %0,%%ds\n\t"
    277264                  "movw %%es,%0 ; movw %0,%%es\n\t"
     
    281268                   : "=r" (tmp_segment)
    282269                   : "0"  (tmp_segment)
    283                   );
    284 
    285     return 1;
    286 }
     270                 );
     271    return 1;
     272}
     273
     274void i386_fill_segment_desc_base(uint32_t base,
     275                                 segment_descriptors* sd)
     276{
     277    sd->base_address_15_0  = base & 0xffff;
     278    sd->base_address_23_16 = (base >> 16) & 0xff;
     279    sd->base_address_31_24 = (base >> 24) & 0xff;
     280}
     281
     282void i386_fill_segment_desc_limit(uint32_t limit,
     283                                  segment_descriptors* sd)
     284{
     285    sd->granularity = 0;
     286    if (limit > 65535) {
     287      sd->granularity = 1;
     288      limit /= 4096;
     289    }
     290    sd->limit_15_0  = limit & 0xffff;
     291    sd->limit_19_16 = (limit >> 16) & 0xf;
     292}
     293
     294/*
     295 * Caution this function assumes the GDTR has been already set.
     296 */
     297uint32_t i386_set_gdt_entry (uint16_t segment_selector_index, uint32_t base,
     298                             uint32_t limit)
     299{
     300    segment_descriptors     gdt_entry;
     301    memset(&gdt_entry, 0, sizeof(gdt_entry));
     302
     303    i386_fill_segment_desc_limit(limit, &gdt_entry);
     304    i386_fill_segment_desc_base(base, &gdt_entry);
     305    /*
     306     * set up descriptor type (this may well becomes a parameter if needed)
     307     */
     308    gdt_entry.type              = 2;    /* Data R/W */
     309    gdt_entry.descriptor_type   = 1;    /* Code or Data */
     310    gdt_entry.privilege         = 0;    /* ring 0 */
     311    gdt_entry.present           = 1;    /* not present */
     312
     313    /*
     314     * Now, reload all segment registers so the limit takes effect.
     315     */
     316    return i386_raw_gdt_entry(segment_selector_index, &gdt_entry);
     317}
     318
     319uint16_t i386_next_empty_gdt_entry ()
     320{
     321    uint16_t                gdt_limit;
     322    segment_descriptors*    gdt_entry_tbl;
     323    /* initial amount of filled descriptors */
     324    static uint16_t         segment_selector_index = 2;
     325
     326    segment_selector_index += 1;
     327    i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
     328    if (segment_selector_index >= (gdt_limit+1)/8) {
     329      return 0;
     330    }
     331    return segment_selector_index;
     332}
     333
     334uint16_t i386_cpy_gdt_entry(uint16_t segment_selector_index,
     335                            segment_descriptors* struct_to_fill)
     336{
     337    uint16_t                gdt_limit;
     338    segment_descriptors*    gdt_entry_tbl;
     339
     340    i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
     341
     342    if (segment_selector_index >= (gdt_limit+1)/8) {
     343      return 0;
     344    }
     345
     346    *struct_to_fill = gdt_entry_tbl[segment_selector_index];
     347    return segment_selector_index;
     348}
     349
     350segment_descriptors* i386_get_gdt_entry(uint16_t segment_selector_index)
     351{
     352    uint16_t                gdt_limit;
     353    segment_descriptors*    gdt_entry_tbl;
     354
     355    i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
     356
     357    if (segment_selector_index >= (gdt_limit+1)/8) {
     358      return 0;
     359    }
     360    return &gdt_entry_tbl[segment_selector_index];
     361}
     362
     363uint32_t i386_limit_gdt_entry(segment_descriptors* gdt_entry)
     364{
     365    uint32_t lim = (gdt_entry->limit_15_0 + (gdt_entry->limit_19_16<<16));
     366    if (gdt_entry->granularity) {
     367      return lim*4096+4095;
     368    }
     369    return lim;
     370}
  • c/src/lib/libcpu/i386/cpu.h

    rb2db1f5c r74d2d940  
    2929#include <rtems/score/interrupts.h>
    3030
    31 #include <stdint.h>
     31#include <rtems/score/basedefs.h>
    3232
    3333/*
     
    257257  unsigned int granularity              : 1;
    258258  unsigned int base_address_31_24       : 8;
    259 }segment_descriptors;
     259} RTEMS_COMPILER_PACKED_ATTRIBUTE segment_descriptors;
    260260
    261261/*
     
    272272                           uint16_t limit);
    273273
     274/**
     275 * C callable function:
     276 * Puts global descriptor @sd to the global descriptor table on index
     277 * @segment_selector_index
     278 *
     279 * @retval  0 FAILED out of GDT range or index is 0, which is not valid
     280 *                   index in GDT
     281 *          1 SUCCESS
     282 */
     283extern uint32_t i386_raw_gdt_entry (uint16_t segment_selector_index,
     284                               segment_descriptors* sd);
     285
     286/**
     287 * C callable function
     288 * fills @sd with provided @base in appropriate fields of @sd
     289 *
     290 * @param base 32-bit address to be set as descriptor's base
     291 * @param sd descriptor being filled with @base
     292 */
     293extern void i386_fill_segment_desc_base (uint32_t base,
     294                                         segment_descriptors* sd);
     295
     296/**
     297 * C callable function
     298 * fills @sd with provided @limit in appropriate fields of @sd
     299 * also influences granularity bit
     300 *
     301 * @param limit 32-bit value representing number of limit bytes
     302 * @param sd descriptor being filled with @limit
     303 */
     304extern void i386_fill_segment_desc_limit (uint32_t limit,
     305                                          segment_descriptors* sd);
     306
    274307/*
    275308 * C callable function enabling to set up one raw interrupt handler
    276309 */
    277 extern int i386_set_gdt_entry (unsigned short segment_selector, unsigned base,
    278                                              unsigned limit);
     310extern uint32_t i386_set_gdt_entry (uint16_t segment_selector,
     311                                    uint32_t base,
     312                                    uint32_t limit);
     313
     314/**
     315 * C callable function returns next empty descriptor in GDT.
     316 *
     317 * @retval  0 FAILED GDT is full
     318 *          <1;65535> segment_selector number as index to GDT
     319 */
     320extern uint16_t i386_next_empty_gdt_entry (void);
     321
     322/**
     323 * Copies GDT entry at index @segment_selector to structure
     324 * pointed to by @struct_to_fill
     325 *
     326 * @param  segment_selector index to GDT table for specifying descriptor to copy
     327 * @retval  0 FAILED segment_selector out of GDT range
     328 *          <1;65535> retrieved segment_selector
     329 */
     330extern uint16_t i386_cpy_gdt_entry (uint16_t segment_selector,
     331                                    segment_descriptors* struct_to_fill);
     332
     333/**
     334 * Returns pointer to GDT table at index given by @segment_selector
     335 *
     336 * @param   segment_selector index to GDT table for specifying descriptor to get
     337 * @retval  NULL FAILED segment_selector out of GDT range
     338 *          pointer to GDT table at @segment_selector
     339 */
     340extern segment_descriptors* i386_get_gdt_entry (uint16_t sgmnt_selector);
     341
     342/**
     343 * Extracts base address from GDT entry pointed to by @gdt_entry
     344 *
     345 * @param  gdt_entry pointer to entry from which base should be retrieved
     346 * @retval base address from GDT entry
     347*/
     348RTEMS_INLINE_ROUTINE void* i386_base_gdt_entry (segment_descriptors* gdt_entry)
     349{
     350    return (void*)(gdt_entry->base_address_15_0 |
     351            (gdt_entry->base_address_23_16<<16) |
     352            (gdt_entry->base_address_31_24<<24));
     353}
     354
     355/**
     356 * Extracts limit in bytes from GDT entry pointed to by @gdt_entry
     357 *
     358 * @param  gdt_entry pointer to entry from which limit should be retrieved
     359 * @retval limit value in bytes from GDT entry
     360 */
     361extern uint32_t i386_limit_gdt_entry (segment_descriptors* gdt_entry);
    279362
    280363/*
Note: See TracChangeset for help on using the changeset viewer.