[PATCH 4/6] i386/shared/int16: real mode interrupt interface

Jan Dolezal dolezj21 at fel.cvut.cz
Tue Nov 18 15:47:00 UTC 2014


On 12.11.2014 16:54, Gedare Bloom wrote:
> On Wed, Nov 12, 2014 at 10:07 AM, Jan Dolezal <dolezj21 at fel.cvut.cz> wrote:
>> ---
>>   c/src/lib/libbsp/i386/pc386/Makefile.am    |   2 +
>>   c/src/lib/libbsp/i386/pc386/preinstall.am  |   4 +
>>   c/src/lib/libbsp/i386/shared/int16/int16.c | 397 +++++++++++++++++++++++++++++
>>   c/src/lib/libbsp/i386/shared/int16/int16.h |  93 +++++++
>>   4 files changed, 496 insertions(+)
>>   create mode 100644 c/src/lib/libbsp/i386/shared/int16/int16.c
>>   create mode 100644 c/src/lib/libbsp/i386/shared/int16/int16.h
> These new files should probably go under i386/shared/irq  ?
I am using i386/shared/realmode_int/realmode_int.* now as suggested
in conversation with Mr. Pisa

>
>>
>> diff --git a/c/src/lib/libbsp/i386/pc386/Makefile.am b/c/src/lib/libbsp/i386/pc386/Makefile.am
>> index 9c901df..6042b5b 100644
>> --- a/c/src/lib/libbsp/i386/pc386/Makefile.am
>> +++ b/c/src/lib/libbsp/i386/pc386/Makefile.am
>> @@ -29,6 +29,7 @@ SUBDIRS = . tools
>>   include_bsp_HEADERS  = ../../i386/shared/irq/irq.h
>>   include_bsp_HEADERS += ../../i386/shared/irq/irq_asm.h
>>   include_bsp_HEADERS += ../../i386/shared/comm/tty_drv.h
>> +include_bsp_HEADERS += ../../i386/shared/int16/int16.h
>>   include_bsp_HEADERS += ../../shared/include/irq-generic.h
>>   include_bsp_HEADERS += ../../shared/include/irq-info.h
>>   include_bsp_HEADERS += console/rtd316.h
>> @@ -94,6 +95,7 @@ libbsp_a_SOURCES += console/kbd_parser.c
>>   libbsp_a_SOURCES += console/serial_mouse_config.c
>>   libbsp_a_SOURCES += ../../i386/shared/comm/uart.c
>>   libbsp_a_SOURCES += ../../i386/shared/comm/tty_drv.c
>> +libbsp_a_SOURCES += ../../i386/shared/int16/int16.c
>>   libbsp_a_SOURCES += ../../shared/console.c
>>   libbsp_a_SOURCES += console/console_select.c
>>   libbsp_a_SOURCES += ../../shared/console_read.c
>> diff --git a/c/src/lib/libbsp/i386/pc386/preinstall.am b/c/src/lib/libbsp/i386/pc386/preinstall.am
>> index aff01dc..1ff9fb8 100644
>> --- a/c/src/lib/libbsp/i386/pc386/preinstall.am
>> +++ b/c/src/lib/libbsp/i386/pc386/preinstall.am
>> @@ -69,6 +69,10 @@ $(PROJECT_INCLUDE)/bsp/tty_drv.h: ../../i386/shared/comm/tty_drv.h $(PROJECT_INC
>>          $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/tty_drv.h
>>   PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/tty_drv.h
>>
>> +$(PROJECT_INCLUDE)/bsp/int16.h: ../../i386/shared/int16/int16.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
>> +       $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/int16.h
>> +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/int16.h
>> +
>>   $(PROJECT_INCLUDE)/bsp/irq-generic.h: ../../shared/include/irq-generic.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
>>          $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-generic.h
>>   PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-generic.h
>> diff --git a/c/src/lib/libbsp/i386/shared/int16/int16.c b/c/src/lib/libbsp/i386/shared/int16/int16.c
>> new file mode 100644
>> index 0000000..380188f
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/i386/shared/int16/int16.c
>> @@ -0,0 +1,397 @@
>> +/*
>> + *  Realmode interrupt call implementation.
>> + *
>> + *
>> + *  Copyright (c) 2014 - CTU in Prague
>> + *                       Jan Doležal ( dolezj21 at fel.cvut.cz )
>> + *
>> + *  The license and distribution terms for this file may be
>> + *  found in the file LICENSE in this distribution or at
>> + *  http://www.rtems.org/license/LICENSE.
>> + *
>> + */
>> +
>> +#include <bsp/int16.h>
>> +#include <string.h>
> Why include string.h?
It is here because later there are used functions memset() and memcpy(),
which have their prototypes in string.h

>
> I have more comments below in the .h file. I am not reviewing this .c
> file due to time constraints and my lack of confidence in x86
> assembly, but I will say if the below macros and struct defines are
> useful outside this file, then they should go into a header file
> instead. Also, I think we use __volatile__ for declaring ASM blocks.
> (We ought to have an RTEMS macro for this, e.g. RTEMS_INLINE_ASM(),
> but I don't think we do.)
I don't think these macros are useful outside, they are used in inline
asm and defined only for better readability of the inline asm.

Quick grep over whole rtems source directory shows that
'__asm__ __volatile__' is used ~110 times and
'__asm__ volatile' is used ~680 times, but if __volatile__ is a better
choice I will gladly use that one.

>
>> +#include <rtems/score/cpu.h>
>> +
>> +#define IR_EAX_OFF      "0x00"
>> +#define IR_EBX_OFF      "0x04"
>> +#define IR_ECX_OFF      "0x08"
>> +#define IR_EDX_OFF      "0x0C"
>> +#define IR_ESI_OFF      "0x10"
>> +#define IR_EDI_OFF      "0x14"
>> +#define IR_DS_OFF       "0x18"
>> +#define IR_ES_OFF       "0x1A"
>> +#define IR_FS_OFF       "0x1C"
>> +#define IR_GS_OFF       "0x1E"
>> +
>> +#define BKP_ESP_OFF     "0x20"
>> +#define BKP_SS_OFF      "0x24"
>> +#define BKP_DS_OFF      "0x26"
>> +#define RM_ENTRY        "0x28"
>> +#define PM_ENTRY        "0x2C"
>> +
>> +/* parameters, results, backup values accessible in real mode */
>> +struct rm_int_regs_bkp_param {
>> +    struct interrupt_registers inoutregs;
>> +    uint32_t pm_esp_bkp;
>> +    uint16_t pm_ss_bkp;
>> +    uint16_t ds_bkp;
>> +    uint16_t rm_entry;
>> +    uint16_t rm_code_segment;
>> +    uint32_t pm_entry;
>> +    uint16_t pm_code_selector;
>> +    /* if modifying update offset definitions as well */
>> +}__attribute__((__packed__));
>> +
>> +#define BKP_IDTR_LIM    "0x00"
>> +#define BKP_IDTR_BASE   "0x02"
>> +#define BKP_ES_OFF      "0x06"
>> +#define BKP_FS_OFF      "0x08"
>> +#define BKP_GS_OFF      "0x0A"
>> +#define RML_ENTRY       "0x0C"
>> +#define RML_D_SEL       "0x12"
>> +#define RM_SS           "0x14"
>> +#define RM_SP           "0x16"
>> +#define RM_DS           "0x18"
>> +/* backup values, pointers/parameters accessible in protected mode */
>> +struct pm_bkp_and_param {
>> +    uint16_t idtr_lim_bkp;
>> +    uint32_t idtr_base_bkp;
>> +    uint16_t es_bkp;
>> +    uint16_t fs_bkp;
>> +    uint16_t gs_bkp;
>> +    uint32_t rml_entry;
>> +    uint16_t rml_code_selector;
>> +    uint16_t rml_data_selector;
>> +    uint16_t rm_stack_segment;
>> +    uint16_t rm_stack_pointer;
>> +    uint16_t rm_data_segment;
>> +}__attribute__((__packed__));
>> +
>> +/* addresses where we are going to put Interrupt buffer,
>> + * parameter/returned/preserved values, stack and copy code
>> + * for calling BIOS interrupt real mode interface
>> + * The value is chosen arbitrarily in the first 640kB
>> + * to be accessible for real mode. It should be out of range
>> + * used by RTEMS because its base address is above 1MB.
>> + * It has to be above first 4kB (or better 64kB) which could
>> + * be used by BIOS.
>> + */
>> +#define REAL_MODE_SPOT   0x12000
>> +/* REAL_MODE_SPOT value is also top of real mode stack */
>> +
>> +/* buffers positions and lengths */
>> +#define DEFAULT_BUFFER_SIZE             512
>> +static void *first_rm_buffer_spot = (void *)REAL_MODE_SPOT;
>> +static uint16_t first_rm_buffer_size = DEFAULT_BUFFER_SIZE;
>> +
>> +/* real mode stack */
>> +#define STACK_SIZE                      8192
>> +#define INT_STACK_TOP                   REAL_MODE_SPOT
>> +
>> +/******************************
>> + * STACK            *         *
>> + ****************************** REAL_MODE_SPOT
>> + * INT_BUF          * 512 B   *
>> + ******************************
>> + * INT_REGs         *  50 B   *
>> + ******************************
>> + * INT_FNC          *~149 B   *
>> + ******************************/
>> +
>> +#define __DP_TYPE       uint8_t
>> +#define __DP_YES        ((__DP_TYPE)1)
>> +#define __DP_NO         ((__DP_TYPE)-1)
>> +#define __DP_FAIL       ((__DP_TYPE)0)
>> +static __DP_TYPE descsPrepared = __DP_NO;
>> +
>> +/* rml - real mode alike */
>> +#define rml_limit 0xFFFF
>> +static uint16_t rml_code_dsc_index = 0;
>> +static uint16_t rml_data_dsc_index = 0;
>> +
>> +/*
>> + * Prepares real-mode like descriptors to be used for switching
>> + * to real mode.
>> + *
>> + * @return __DP_YES descriptors are prepared
>> + * @return __DP_FAIL descriptors allocation failed (GDT too small)
>> + */
>> +static __DP_TYPE prepareRMDescriptors (void *base32) {
>> +    static void *prevBase = (void *)-1;
>> +    /* check if descriptors were prepared already */
>> +    if (descsPrepared == __DP_YES && prevBase == base32)
>> +        return descsPrepared;
>> +
>> +    if (descsPrepared == __DP_FAIL)
>> +        return descsPrepared;
>> +
>> +    /* create 'real mode like' segment descriptors, for switching to real mode */
>> +    rml_code_dsc_index = i386_next_empty_gdt_entry();
>> +    if (rml_code_dsc_index == 0)
>> +    {
>> +        /* not enough space in GDT */
>> +        descsPrepared = __DP_FAIL;
>> +        return descsPrepared;
>> +    }
>> +
>> +    segment_descriptors flags_desc;
>> +    memset(&flags_desc, 0, sizeof(flags_desc));
>> +    flags_desc.type                = 0xE;      /* bits 4  */
>> +    flags_desc.descriptor_type     = 0x1;      /* bits 1  */
>> +    flags_desc.privilege           = 0x0;      /* bits 2  */
>> +    flags_desc.present             = 0x1;      /* bits 1  */
>> +    flags_desc.available           = 0x0;      /* bits 1  */
>> +    flags_desc.fixed_value_bits    = 0x0;      /* bits 1  */
>> +    flags_desc.operation_size      = 0x0;      /* bits 1  */
>> +    flags_desc.granularity         = 0x0;      /* bits 1  */
>> +    i386_fill_segment_desc_base((unsigned)base32, &flags_desc);
>> +    i386_fill_segment_desc_limit(rml_limit, &flags_desc);
>> +    if (i386_raw_gdt_entry(rml_code_dsc_index, &flags_desc) == 0)
>> +    {
>> +        /* selector to GDT out of range */
>> +        descsPrepared = __DP_FAIL;
>> +        return descsPrepared;
>> +    }
>> +
>> +    rml_data_dsc_index = i386_next_empty_gdt_entry();
>> +    if (rml_data_dsc_index == 0)
>> +    {
>> +        /* not enough space in GDT for both descriptors */
>> +        descsPrepared = __DP_FAIL;
>> +        return descsPrepared;
>> +    }
>> +
>> +    flags_desc.type                = 0x2;      /* bits 4  */
>> +    if (i386_raw_gdt_entry(rml_data_dsc_index, &flags_desc) == 0)
>> +    {
>> +        /* selector to GDT out of range */
>> +        descsPrepared = __DP_FAIL;
>> +        return descsPrepared;
>> +    }
>> +    prevBase = base32;
>> +    descsPrepared = __DP_YES;
>> +    return descsPrepared;
>> +}
>> +
>> +inline void *i386_get_primary_rm_buffer() {
>> +    return first_rm_buffer_spot;
>> +}
>> +
>> +inline uint16_t i386_get_primary_rm_buffer_size() {
>> +    return first_rm_buffer_size;
>> +}
>> +
>> +int i386_real_interrupt_call(uint8_t interruptNumber, struct interrupt_registers *ir){
>> +    uint32_t pagingon;
>> +    struct rm_int_regs_bkp_param *int_passed_regs_spot;
>> +    /* place where the code switching to realmode and executing
>> +       interrupt is coppied */
>> +    void *rm_swtch_code_dst;
>> +    void *rm_stack_top;
>> +
>> +    size_t cpLength;
>> +    void *cpBeg;
>> +
>> +    /* values that can be passed from protected mode are stored in this struct
>> +       and they are passed later to the inline assembler executing interrupt */
>> +    volatile struct pm_bkp_and_param pm_bkp, *pm_bkp_addr;
>> +    unsigned short unused_offset;
>> +
>> +    __asm__ volatile(   "\t"
>> +        "movl    %%cr0, %%eax\n\t"
>> +        "andl    %1, %%eax\n"
>> +        : "=a"(pagingon)
>> +        : "i"(CR0_PAGING)
>> +    );
>> +    if (pagingon)
>> +        return 0;
>> +
>> +    /* located under 1MB for real mode to be able to get/set values */
>> +    int_passed_regs_spot = (struct rm_int_regs_bkp_param *)
>> +                                (first_rm_buffer_spot+first_rm_buffer_size);
>> +    /* position for real mode code reallocation to the first 1MB of RAM */
>> +    rm_swtch_code_dst = (void *)((uint32_t)int_passed_regs_spot+sizeof(*int_passed_regs_spot));
>> +    rm_stack_top = (void *)INT_STACK_TOP;
>> +
>> +    if (prepareRMDescriptors(int_passed_regs_spot) != __DP_YES)
>> +        return 0;
>> +
>> +    pm_bkp_addr = &pm_bkp;
>> +    i386_Physical_to_real_mode_ptr(
>> +        rm_stack_top - STACK_SIZE,
>> +        (unsigned short *)&pm_bkp.rm_stack_segment,
>> +        (unsigned short *)&pm_bkp.rm_stack_pointer
>> +    );
>> +    pm_bkp.rm_stack_pointer += STACK_SIZE;
>> +    pm_bkp.rml_code_selector = (rml_code_dsc_index<<3);
>> +    pm_bkp.rml_entry = ((uint32_t)rm_swtch_code_dst-(uint32_t)int_passed_regs_spot);
>> +    pm_bkp.rml_data_selector = (rml_data_dsc_index<<3);
>> +    i386_Physical_to_real_mode_ptr(
>> +        int_passed_regs_spot,
>> +        (unsigned short *)&pm_bkp.rm_data_segment,
>> +        &unused_offset
>> +    );
>> +
>> +    int_passed_regs_spot->inoutregs = *ir;
>> +    /* offset from the beginning of coppied code */
>> +    uint16_t rm_entry_offset;
>> +    __asm__ volatile(
>> +        "movw   $(rment-cp_beg), %0\n\t"
>> +        : "=r"(rm_entry_offset)
>> +    );
>> +    i386_Physical_to_real_mode_ptr(
>> +        rm_swtch_code_dst+rm_entry_offset,
>> +        (unsigned short *)&int_passed_regs_spot->rm_code_segment,
>> +        (unsigned short *)&int_passed_regs_spot->rm_entry
>> +    );
>> +    __asm__ volatile(
>> +        "movl   $(cp_end), %0\n\t"
>> +        "movw   %%cs, %1\n\t"
>> +        : "=mr"(int_passed_regs_spot->pm_entry), "=mr"(int_passed_regs_spot->pm_code_selector)
>> +    );
>> +    /* copy code for switch to real mode and executing interrupt to first MB of RAM */
>> +    __asm__ volatile(   "\t"
>> +        "mov    $cp_end-cp_beg, %0\n\t"
>> +        "mov    $cp_beg, %1\n\t"
>> +        : "=rm"(cpLength), "=rm"(cpBeg)
>> +    );
>> +    memcpy(rm_swtch_code_dst, cpBeg, cpLength);
>> +    /* write interrupt number to be executed */
>> +    uint16_t interrupt_number_off;
>> +    uint8_t *interrupt_number_ptr;
>> +    __asm__ volatile(   "\t"
>> +        "movw   $intnum-cp_beg, %0\n\t"
>> +        : "=rm"(interrupt_number_off)
>> +    );
>> +    interrupt_number_ptr = (uint8_t *) (rm_swtch_code_dst+interrupt_number_off);
>> +    *interrupt_number_ptr = interruptNumber;
>> +    /* execute code that jumps to coppied function, which switches to real mode,
>> +       loads registers with values passed to interrupt and executes interrupt */
>> +    __asm__ volatile(   "\t"
>> +        /* backup stack */
>> +        "movl    %[regs_spot], %%ebx\n\t"
>> +        "movl    %%esp, "BKP_ESP_OFF"(%%ebx)\n\t"
>> +        "movw    %%ss,  "BKP_SS_OFF"(%%ebx)\n\t"
>> +        /* backup data selector */
>> +        "movw    %%ds,  "BKP_DS_OFF"(%%ebx)\n\t"
>> +        /* backup other selectors */
>> +        "movl    %[pm_bkp], %%esi\n\t"
>> +        "movw    %%es, "BKP_ES_OFF"(%%esi)\n\t"
>> +        "movw    %%fs, "BKP_FS_OFF"(%%esi)\n\t"
>> +        "movw    %%gs, "BKP_GS_OFF"(%%esi)\n\t"
>> +        /* hopefully loader does not damage interrupt table on the beginning of memory; that means length: 0x3FF, base: 0x0 */
>> +        /* preserve idtr */
>> +        "movl    %%esi, %%eax\n\t"
>> +        "addl    $"BKP_IDTR_LIM", %%eax\n\t"
>> +        "cli\n\t"
>> +        "sidt    (%%eax)\n\t"
>> +        "movl    $rmidt, %%eax\n\t"
>> +        "lidt    (%%eax)\n\t"
>> +        /* prepare 'real mode like' data selector */
>> +        "movw    "RML_D_SEL"(%%esi), %%ax\n\t"
>> +        /* prepare real mode data segment value */
>> +        "xorl    %%edx,%%edx\n\t"
>> +        "movw    "RM_DS"(%%esi), %%dx\n\t"
>> +        /* prepare real mode stack values */
>> +        "movw    "RM_SS"(%%esi), %%cx\n\t"
>> +        "movzwl  "RM_SP"(%%esi), %%esp\n\t"
>> +        /* jump to copied function and */
>> +        /* load 'real mode like' code selector */
>> +        "ljmp   *"RML_ENTRY"(%%esi)\n"
>> +"rmidt:"/* limit and base for realmode interrupt descriptor table */
>> +        ".word 0x3FF\n\t"
>> +        ".long 0\n\t"
>> +        /* load 'real mode like' data selectors */
>> +"cp_beg: .code16\n\t"
>> +        "movw    %%ax, %%ss\n\t"
>> +        "movw    %%ax, %%ds\n\t"
>> +        "movw    %%ax, %%es\n\t"
>> +        "movw    %%ax, %%fs\n\t"
>> +        "movw    %%ax, %%gs\n\t"
>> +        /* disable protected mode */
>> +        "movl    %%cr0, %%eax\n\t"
>> +        "and     %[cr0_prot_dis], %%ax\n\t"
>> +        "movl    %%eax, %%cr0\n\t"
>> +        /* base for data selector of 16-bit protected mode is at beginning of passed regs */
>> +        /* flush prefetch queue by far jumping */
>> +        "ljmp    *"RM_ENTRY"\n\t"
>> +"rment: "
>> +        /* establish rm stack - esp was already set in 32-bit protected mode*/
>> +        "movw    %%cx, %%ss\n\t"
>> +        /* set data segment (value prepared in 32-bit prot mode) */
>> +        "movw    %%dx, %%ds\n\t"
>> +        /* count real mode pointer so we don't need to overuse address prefix (by using 32bit address) */
>> +        "shll    $4,%%edx\n\t"
>> +        "subl    %%edx,%%ebx\n\t"
>> +        /* prepare values to be used after interrupt call */
>> +        "pushw   %%bx\n\t"
>> +        "pushw   %%ds\n\t"
>> +        /* fill registers with parameters */
>> +        "movw    " IR_DS_OFF"(%%bx), %%ax\n\t"
>> +        "pushw   %%ax\n\t"
>> +        "movl    "IR_EAX_OFF"(%%bx), %%eax\n\t"
>> +        "movl    "IR_ECX_OFF"(%%bx), %%ecx\n\t"
>> +        "movl    "IR_EDX_OFF"(%%bx), %%edx\n\t"
>> +        "movl    "IR_EDI_OFF"(%%bx), %%edi\n\t"
>> +        "movl    "IR_ESI_OFF"(%%bx), %%esi\n\t"
>> +        "movw    " IR_ES_OFF"(%%bx), %%es\n\t"
>> +        "movw    " IR_FS_OFF"(%%bx), %%fs\n\t"
>> +        "movw    " IR_GS_OFF"(%%bx), %%gs\n\t"
>> +        /* prepare ebx register */
>> +        "movl    "IR_EBX_OFF"(%%bx), %%ebx\n\t"
>> +        /* prepare ds */
>> +        "popw    %%ds\n\t"
>> +        /* interrupt instruction */
>> +        ".byte   0xCD\n\t"
>> +"intnum: .byte   0x0\n\t"
>> +        /* fill return structure */
>> +        "pushw   %%ds\n\t"
>> +        "pushl   %%ebx\n\t"
>> +        "movw    0x6(%%esp), %%ds\n\t"
>> +        "movw    0x8(%%esp),%%bx\n\t" /* regs_spot */
>> +        "movl    %%eax,"IR_EAX_OFF"(%%bx)\n\t"
>> +        "popl    %%eax\n\t"
>> +        "movl    %%eax,"IR_EBX_OFF"(%%bx)\n\t"
>> +        "movl    %%ecx,"IR_ECX_OFF"(%%bx)\n\t"
>> +        "movl    %%edx,"IR_EDX_OFF"(%%bx)\n\t"
>> +        "movl    %%esi,"IR_ESI_OFF"(%%bx)\n\t"
>> +        "movl    %%edi,"IR_EDI_OFF"(%%bx)\n\t"
>> +        "popw    %%ax\n\t"
>> +        "movw    %%ax, " IR_DS_OFF"(%%bx)\n\t"
>> +        "movw    %%es, " IR_ES_OFF"(%%bx)\n\t"
>> +        "movw    %%fs, " IR_FS_OFF"(%%bx)\n\t"
>> +        "movw    %%gs, " IR_GS_OFF"(%%bx)\n\t"
>> +        /* prepare protected mode data segment */
>> +        "movw    "BKP_DS_OFF"(%%bx), %%ax\n\t"
>> +        /* restore protected mode stack values */
>> +        "movl    "BKP_ESP_OFF"(%%bx),%%esp\n\t"
>> +        "movw    "BKP_SS_OFF"(%%bx), %%dx\n\t"
>> +        /* return to protected mode */
>> +        "movl    %%cr0, %%ecx     \n\t"
>> +        "or      %[cr0_prot_ena], %%cx\n\t"
>> +        "movl    %%ecx, %%cr0     \n\t"
>> +        "ljmpl   *"PM_ENTRY"(%%bx)\n\t"
>> +        ".code32\n"
>> +        /* reload segmentation registers */
>> +"cp_end:"
>> +        "movw    %%ax, %%ds\n\t"
>> +        /* restore stack segment in protected mode context */
>> +        "movw    %%dx, %%ss\n\t"
>> +        "movl    %[pm_bkp], %%esi\n\t"
>> +        "movw    "BKP_ES_OFF"(%%esi), %%es\n\t"
>> +        "movw    "BKP_FS_OFF"(%%esi), %%fs\n\t"
>> +        "movw    "BKP_GS_OFF"(%%esi), %%gs\n\t"
>> +        /* restore IDTR */
>> +        "addl    $"BKP_IDTR_LIM", %%esi\n\t"
>> +        "lidt    (%%esi)\n\t"
>> +        :
>> +        : [regs_spot]"m"(int_passed_regs_spot), [pm_bkp]"m"(pm_bkp_addr), [cr0_prot_ena]"i"(CR0_PROTECTION_ENABLE), [cr0_prot_dis]"i"(~CR0_PROTECTION_ENABLE)
>> +        : "memory", "ebx", "ecx", "edx", "esi", "edi"
>> +    );
>> +    *ir = int_passed_regs_spot->inoutregs;
>> +    return 1;
>> +}
>> +
>> diff --git a/c/src/lib/libbsp/i386/shared/int16/int16.h b/c/src/lib/libbsp/i386/shared/int16/int16.h
>> new file mode 100644
>> index 0000000..96025ef
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/i386/shared/int16/int16.h
>> @@ -0,0 +1,93 @@
>> +/**
>> + * @file int16.h
>> + *
>> + * @ingroup i386_shared
>> + *
>> + * @brief Definitioins supporting real mode interrupt calls.
>> + */
>> +
>> +/*
>> + *  Interface allows calling given interrupt number with content of the
>> + *  registers defined. For passing or receiving higher amounts of the data
>> + *  there is a buffer accessible from real mode available. Real mode pointer
>> + *  to this buffer is passed to the interrupt in the registers.
>> + *
>> + * Copyright (C) 2014  Jan Doležal (dolezj21 at fel.cvut.cz)
>> + *                     CTU in Prague.
>> + *
>> + *  The license and distribution terms for this file may be
>> + *  found in the file LICENSE in this distribution or at
>> + *  http://www.rtems.org/license/LICENSE.
>> + */
>> +
>> +#ifndef _INT16_H
>> +#define _INT16_H
>> +
>> +#include <libcpu/cpu.h>
>> +#include <stdint.h>
>> +
>> +#ifndef ASM /* ASM */
>> +
>> +#ifdef __cplusplus
>> +extern "C" {
>> +#endif /* __cplusplus */
>> +
>> +/* --- BIOS service interrupt number --- */
>> +/* number of interrupt servicing video functions */
>> +#define INTERRUPT_NO_VIDEO_SERVICES 0x10
>> +
>> +struct interrupt_registers { /* used for passing parameters, fetching results and preserving values */
>> +    uint32_t reg_eax;
>> +    uint32_t reg_ebx;
>> +    uint32_t reg_ecx;
>> +    uint32_t reg_edx;
>> +    uint32_t reg_esi;
>> +    uint32_t reg_edi;
>> +    uint16_t reg_ds;
>> +    uint16_t reg_es;
>> +    uint16_t reg_fs;
>> +    uint16_t reg_gs;
>> +}__attribute__((__packed__));
>> +
> RTEMS prefers to use typedef on struct names. Also, the name should be
> "namespaced", for example, i386_interrupt_registers. Usually I would
> expect to see this kind of structure in
> score/cpu/i386/rtems/score/i386.h defined as an interrupt context
> structure. I think ARM has an example.
I've chosen i386_realmode_interrupt_registers
I believe the reasons from conversation with Mr. Pisa also apply
here - to keep this separately from x86 protected mode runtime support.

>
> Is __packed__ necessary? We avoid compiler attributes where possible,
> and where necessary we should use a macro e.g. RTEMS_PACKED_STRUCT (or
> something, if it exists).
for moxie and h8300 there is
#define nogap __attribute__ ((packed))
in score - cpu.h
and for arm bsp
#define PACKED __attribute__ ((packed))
in jtypes.h
but I have not found such thing for i386

>
>> +/**
>> + * provides position to real mode buffer, which is buffer
>> + * accessible from real mode context - it is located below
>> + * address ~0x100000 in order for it to be accessible
>> + * This buffer is meant to be pointed to by segReg:GenPurpReg
>> + * and through this get bigger portion of information to/from
>> + * interrupt service routine.
>> + *
>> + * @return pointer to buffer
>> + */
>> +extern void *i386_get_primary_rm_buffer(void);
>> +
> avoid abbreviations, use realmode
>
> What does "primary"  mean? Is there a "secondary"? If not, just use
> i386_get_realmode_buffer().
If there was ever need to add another buffer this could make things
easier.
Is it ok if I use i386_get_default_realmode_buffer()?

>
>
>> +/**
>> + * returns size of real mode buffer
>> + *
>> + * @return size of buffer
>> + */
>> +extern uint16_t i386_get_primary_rm_buffer_size(void);
>> +
> The above two functions can be merged together, where the buffer is
> returned and the size gets set as a side-effect, if that is useful.
ok

>
>> +/* if there is ever need to have more buffers or setting size of the buffer,
>> + * feel free to modify the code */
>> +
>> +/**
>> + * This function allows calling interrupts in real mode and to set processor
>> + * registers as desired before interrupt call is made and to retrieve the
>> + * registers content after call was made.
>> + *
>> + * @param interruptNumber interrupt number to be called
>> + * @param ir pointer to structure containing registers to be passed to interrupt
>> + *        and to retrieve register content after call was made.
>> + * @return  0 call failed (GDT too small or pagin is on)
>> + *          1 call successful
>> + */
>> +extern int i386_real_interrupt_call(uint8_t interruptNumber, struct interrupt_registers *ir);
>> +
>> +#ifdef __cplusplus
>> +}
>> +#endif /* __cplusplus */
>> +
>> +#endif /* ASM */
>> +
>> +#endif /* _INT16_H */
>> --
>> 1.9.1
>>
>> _______________________________________________
>> devel mailing list
>> devel at rtems.org
>> http://lists.rtems.org/mailman/listinfo/devel


Thank you,
Jan Dolezal


More information about the devel mailing list