Микропроцессоры и микрокомпьютеры

МИНИСТЕРСТВО  ОБРАЗОВАНИЯ РЕСПУБЛИКИ БЕЛАРУСЬ 

Белорусский национальный технический университет 

Международный институт дистанционного образования 
 

Кафедра «Информационные  системы и технологии» 
 
 
 
 
 
 
 
 

Контрольная работа 
 

по дисциплине:  «Микропроцессоры и микрокомпьютеры» 

ВАРИАНТ № 8 
 
 
 
 

Выполнил:                                                                                             Шумель В.В.

Студент 2 курса, группы 417437/8                                                       

Специальность 53.01.02 «Автоматизированные

 системы обработки  информации» 
 
 

Адрес:

Гродненская область  и район, г. Скидель

ул. Шеремета 12/7

тел. 8868354 
 
 
 
 

Преподаватель:                                                                                      Масальская Т. И. 
 
 
 
 
 
 
 
 
 
 

Гродно 2009г.

    Теоретический вопрос. 

    Механизм  шлюзов для передачи управления на сегменты кода с другими  уровнями привилегий 

    Поскольку межсегментные переходы контролируются с использованием уровней привилегий, а потребность в передаче управления с одного уровня привилегий на другой уровень имеется, в микропроцессорах i80x86 реализован механизм шлюзов. Шлюзование позволяет организовать обращение к так называемым подчиненным сегментам кода, которые выполняют часто встречающиеся функции и должны быть доступны многим задачам, располагающимся на том же или нижележащем уровне привилегий. Часто уровни привилегий называют кольцами зашиты, поскольку это иногда помогает объяснить принцип действия самого механизма. Часто говорят, что некоторый программный модуль «исполняется в кольце защиты с номером ...».

    Помимо  дескрипторов сегментов системными объектами, с которыми работает микропроцессор, являются специальные системные  дескрипторы, названные шлюзами (gates). Главное различие между дескриптором сегмента и шлюзом вызова подчиненного сегмента кода заключается в том, что содержимое дескриптора указывает на сегмент в памяти, а шлюз обращается к дескриптору. Другими словами, если дескриптор служит механизмом отображения памяти, то шлюз служит механизмом перенаправления вычислений.

    Для доступа к более привилегированному коду задача должна обратиться к нему не непосредственно (путем указания дескриптора этого кода), а через шлюз этого сегмента.

    В этом дескрипторе вместо адреса сегмента указываются селектор, позволяющий найти дескриптор искомого сегмента кода, и адрес (смещение назначения), с которого будет выполняться подчиненный сегмент, то есть полный 32-разрядный адрес. Адресовать шлюз вызова можно с помощью команды CALL или FAR CALL (межсегментный вызов процедуры). По существу, дескрипторы шлюзов вызова не являются дескрипторами сегментов, но могут располагаться среди обычных дескрипторов (в дескриптор-ных таблицах) процесса. Смещение, указываемое в команде перехода на другой сегмент (FAR CALL), игнорируется, и фактически осуществляется переход на команду, адрес которой определяется через смещение из шлюза вызова. Этим гарантируется попадание только на разрешенные точки входа в подчиненные сегменты.

    Введены следующие правила использования  шлюзов:

    - значение DPL шлюза вызова должно быть больше или равно значению текущего уровня привилегий С PL;

    - значение DPL шлюза вызова должно быть больше или равно значению поля RPL селектора шлюза;

    - значение DPL шлюза вызова должно быть больше или равно значению DPL целевого сегмента кода;

    - значение DPL целевого сегмента кода должно быть меньше или равно значению текущего уровня привилегий CPL.

    Требование  наличия и доступности шлюза  вызова для перехода на более привилегированный  код ограничивает менее привилегированный  код заданным набором точек входа. Так как шлюзы вызова являются элементами дескрипторных таблиц (а мы говорили, что их не только можно, но и желательно там располагать), то менее привилегированная программа не может создать дополнительных (а значит, и неконтролируемых) шлюзов. Таким образом, рассмотренный механизм шлюзов дает следующие преимущества в организации среды надежных вычислений.

    Привилегированный код надежно защищен, и вызывающие его программы не могут его  разрушить. Естественно, что такой  системный код должен быть особенно тщательно отлаженным, не содержать ошибок, быть максимально эффективным.

    Шлюзы межсегментных переходов для  вызова системных функций делают эти самые системные функции  невидимыми для программных модулей, расположенных на внешних (более низких) уровнях привилегий.

    Поскольку вызывающая программа непосредственно  адресует только шлюз вызова, реализуемые  вызываемым модулем (сегментным кодом) функции можно изменить или переместить  в адресном пространстве, не затрагивая интерфейс со шлюзом.

    Легко реализуется вызов программных  модулей с более привилегированного уровня.

    Изложенный  вкратце аппаратный механизм защиты по привилегиям оказывается довольно сложным и жестким. Однако поскольку  все практические ситуации учесть в  схемах микропроцессора невозможно, то при разработке процедур операционных систем и иного привилегированного кода следует придерживаться приведенных ниже рекомендаций, заимствованных из [8].

    Основной  риск связан с передачей управления через шлюз вызова более привилегированной процедуре. Нельзя предоставлять вызывающей программе никаких преимуществ, вытекающих из-за временного повышения привилегий. Это особенно важно для процедур нулевого уровня привилегий (PLO-процедур).

    Вызывающая  программа может нарушить работу процедуры, передавая ей «плохие» параметры. Поэтому целесообразно как можно раньше проконтролировать передаваемые процедуре параметры. Шлюз вызова сам по себе не проверяет значений параметров, которые копируются в новый стек, поэтому достоверность каждого передаваемого параметра должна контролировать вызванная процедура. Ниже перечислены некоторые рекомендации по контролю передаваемых параметров.

    Следует проверять счетчики циклов и повторений на минимальные и максимальные значения.

    Необходимо  проверить 8- и 16-разрядные параметры, передаваемые в 32-разрядных регистрах. Когда процедуре передается короткий параметр, его следует расширить знаковым разрядом или нулем для заполнения всего 32-разрядного регистра.

    Следует стремиться свести к минимуму время  работы процессора с запрещенными прерываниями. Если процедуре требуется запрещать прерывания, необходимо, чтобы вызывающая программа не могла влиять на время нахождения процессора с запрещенными прерываниями (флаг IF = 0).

    Процедура никогда не должна воспринимать как  параметр код или указатель на код.

    В операциях процессора следует явно задавать состояние флага направления DF для цепочечных команд.

    Заключительная  команда RET или RET n в процедуре должна точно соответствовать полю WC (Word Counter — счетчик слов) шлюза вызова; при этом n = 4 х WC, так как счетчик задает число двойных слов, а п соответствует байтам.

    Не  следует применять шлюзы вызовов  для функций, которым передается переменное число параметров (см. предыдущую рекомендацию). При необходимости  нужно воспользоваться счетчиком и указателем параметров.

    Функции не могут возвращать значения в стеке (см. предыдущую рекомендацию), так как  после возврата стеки процедуры  и вызывающей программы находятся  точно в таком состоянии, в  каком они были до вызова.

    В процедуре следует сохранять и восстанавливать все сегментные регистры. Без этого, если какой-либо сегментный регистр привлекался для адресации данных, недоступных вызывающей программе, процессор автоматически загрузит в него пустой селектор. Рекомендуется контролировать все обращения к памяти.

    Нетрудно  представить себе ситуацию, когда PLS-программа передает PLO-процедуре указатель селектор-смещение и запрашивает считать или записать несколько байтов по этому адресу. Типичным примером может служить процедура дискового ввода-вывода, которая воспринимает как параметр системный номер файла, счетчик байтов и адрес, по которому записываются данные с диска. Хотя PLO-процедура имеет привилегии для производства такой операции, у PLS-программы разрешения на это может не быть. 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

    Практические  задания. 

    Задание 1. 

    Дан виртуальный  адрес операнда 000С5АВ7:00050321h. Определить какой тип таблицы дескрипторов используется, уровень привилегий выполняемой задачи. Поле в таблице дескрипторов содержит 2D31F000h. Определить линейный адрес операнда.

    Тип таблицы  дескрипторов – локальная (LDT).

    Тип привилегий выполняемой задачи – 3.

    Линейный  адрес операнда – CAAE91h. 
 

    Задание 2. 

    При помощи логического сдвига получить в регистре BL значение 16h вместо B6h. Определить внутренний формат команды. Установить флаги.

    Машинный  формат данной команды    shr  bl, 3   =    C0EB03

    Состояние флагов:

    0F = 0

    DF = 0

    IF   = 1

    SF = 0

    ZF = 0

    AF = 1

    PF = 0

    CF = 1 

    Задание 3. 

    Вычесть из операнда А3В1h  операнд 8D95h. Будет ли осуществлен переход на метку L1  по команде Jg L1, следующей за командой вычитания? Установить флаги. Определить машинные форматы команд. 

    Переход будет осуществлён.

    Состояние флагов:

    0F = 0

    DF = 0

    IF = 1

    SF = 0

    ZF = 0

    AF = 1

    PF = 0

    CF = 0

    Машинные  форматы команд:

    Sub   ax, bx    =     2BC3

    JG     L1       =     7F0E (в данной команде 0E – смещение для метки в конкретной программе. В другой программе смещение может быть другое, потому и машинный формат команды будет выглядеть по другому) 
 

    Задание 4. 

    Написать  две программы на языке ассемблера для каждого варианта. 

    Программа Pro8_4_1.

    Ввести  массив целых чисел. Вывести на другой строке остатки от деления элементов  массива на 10, а в следующей  – исходные числа, умноженные на 2. 

    Листинг программы: 

     CSEG segment  ; даём сегменту, в котором находится программа,      ; имя CSEG

      org  100h   ; сообщаем, что код программы (как и смещения       ; внутри сегмента CSEG) необходимо отсчитывать с      ; 100h. По этому адресу в память всегда        ; загружаются программы типа *.com.

Begin:    ; метка начала программы   

      mov  ah, 9   ; будем выводить строку символов

      lea  dx, StartMessage ; с адресом в dx

      int  21h   ; вызываем прерывание DOS

                              ;

Main:     ; метка основного цикла программы

      mov  ah, 9   ; будем выводить строку символов

      lea  dx, MainMessage ; с адресом в dx

      int  21h   ; вызываем прерывание DOS

                              

;****************************************************************************

;**** Ввод символа  с клавиатуры в регистр AL ********************************

;****************************************************************************

GetKey:     ; метка подпрограммы вводва символа  

   Mov ah, 1   ; код функции "проверка готовности"

      Int 16h   ; обращение к BIOS

      Jz GetKey  ; символ не введён, возвращаемся на начало

                              ; подпрограммы

      Xor ah, ah  ; код функции "чтение символа в AL"

      Int 16h   ; обращение к BIOS

   Cmp al, '0'  ; код символа < кода нуля?

   jb    nodig   ; -> да, символ не цифра

   cmp   al, '9'  ; код символа > кода девятки?

   ja    nodig   ; -> да, символ не цифра

   clc         ; символ - цифра, C=0

   jmp   massiv_in  ; возврат на вызывающий модуль

nodig:      ; метка

  stc    ; символ - не цифра, C=1

obrabotka:    ; метка

   jc  _nodigit     ; если символ - не цифра, идём на соответствующую                ; ему обработку

;****************************************************************************

;***** Ввод и "редактирование" нововводимого элемента массива  ***************

;****************************************************************************

Massiv_in:    ; метка куска программы для ввода элемента массива

      Xor bl, bl  ; обнуляем регистр bl

      Mov _flag,bl  ; заносим 0 в регистр флага (снимаем признак       ; введённого пробела)

Call  OutSym   ; вызываем эхоотображение символа

      Mov  bl, 30h  ; заносим в bl число 30h

      Xor ah, ah  ; обнуляем старшую часть регистр ax

      Sub  al, bl  ; получаем из ASCII кода число

      Push ax   ; сохраняем его в стеке

      Xor dx, dx  ; обнуляем регистр dx

      Mov SI,_counter  ; Заносим номер числа для работы с числом массива

      Mov  AX, In_massiv[SI] ; Заносим в AX элемент массива, с которым теперь

                  ; будем работать

      Mov  BX, 10  ; Заносим в регистр bx число 10

   Mul  BX       ; Умножаем регистр с элементом на десять

  Pop bx   ; восстанавливаем из стека в регистр bx

          ; нововведённую цифру

    Add  AX,BX   ; прибавляем к элементу массива нововведённое

           ; число

      Cmp dx,0   ; сравниваем старшую часть произведения с 0

      Ja bigdigit  ; если больше 0, то идём на обработку

           ; слишком большого числа; а также

      Cmp ax,10000  ; сравниваем элемент массива с 10000

      Ja bigdigit  ; если получившееся число больше 10000, то идём на

           ; обработку слишком большого числа; иначе

      Mov  In_massiv[SI],AX ; Заносим обратно в массив элемент, с которым

                    ; работали

   Jmp  GetKey  ; идём на подпрограмму ожидания ввода символа

Bigdigit:    ; метка подпрограммы обработки слишком большого

           ; числа

      Push ax   ; сохраняем в стеке регистр ax

      Mov al,08   ; заносим в регистр al код символа BackSpace

      call  OutSym  ; вызываем подпрограмму вывода символа на экран

      mov   al, 20h   ; заносим в регистр al код символа Space

      call  Outsym  ; вызываем подпрограмму вывода символа на экран

      Mov ah, 1   ; делаем признак введённого пробела

      Mov _flag, ah  ;

                              ; таким образом,  последние четыре команды стирали       ; последний введённый символ

      pop ax   ; сохраняем из стека регистр ax

      sub ax, bx  ; вычитаем из элемента массива нововведённое число

      mov bx, 10  ; заносим в регистр bx число 10

      div bx   ; делим элемент массива на 10

      Mov  In_massiv[SI],AX ; Заносим обратно в массив элемент, с которым

                              ; работали

  Inc  _counter  ; дважды

   Inc  _counter     ; инкрементируем счётчик элементов, и

      Jmp  GetKey   ; идём на ожидание нажатия очередной клавиши

;****************************************************************************

;**** Обработка символов, которые не цифры **********************************

;****************************************************************************

_nodigit:    ; метка подпрограммы

      Cmp  al, 1Bh  ; введён символ Esc ?

      Jnz _nodigit1  ; идём дальше, если не Esc

      int  20h   ; если Esc, то выходим из программы

_nodigit1:    ; просто метка "дальше"

      Cmp  ah, 1Ch   ; введён символ Enter?

      Jnz  _nodigit2  ; нет; идём на метку

      Mov ah, _flag  ; проверяем признак введённого пробела

      Cmp ah, 0   ;

      Jne _nodigit1_1  ; если введён, то пропускаем, иначе

      Inc  _counter     ; дважды

      Inc  _counter   ; инкрементируем счётчик элементов,

_nodigit1_1: 

      mov  ah, 9   ; делаем

      lea  dx,AbzacMessage ; "абзац"

   int  21h   ; и

   Jmp  Massiv_out  ; идём на обработку и вывод массивов

_nodigit2:    ; очередная метка "дальше"

      Cmp  al, 20h  ; введён символ Space?

   Jnz  GetKey  ; нет, не введён ни один из правильных символов,               ; идём на ожидание очередного символа

   Mov ah, _flag  ; заносим в ah признак введённого пробела

      Cmp ah, 0   ; сравниваем его с 0

      Jne Getkey  ; если введён, то идём на ожидание нажатия клавиши

      Xor  al, al  ; да, обнуляем регистр AL

  Call  OutSym   ; выводим пробел

   Inc  _counter     ; дважды

   Inc  _counter   ; инкрементируем регистр счётчика элементов

      Mov ah, 1   ; делаем признак введённого пробела

      Mov _flag, ah  ;

   Jmp  GetKey    ; идём на ожидание нажатия клавиши

;****************************************************************************

;**** Вывод массивов ********************************************************

;****************************************************************************

Massiv_out:    ; метка подпрограммы вывода массивов

   mov   ah, 9   ; 

      lea   dx, Mass1Message ;

      int   21h        ; Выводим сообщение "второй массив..."

      xor   SI, SI   ; Обнулям регистр SI

      mov   AX,_counter  ; заносим в счётчик цикла число элементов

          ; массива, умноженное на два

      mov   bl, 2   ; заносим в регистр bl число 2

   div   bl   ; получаем правильное число элементов массива

  mov   cl, al  ; заносим его в регистр счётчика цикла

massiv1_out_loop:   ; метка цикла, выводящего на экран элементы                  ; второго массива

   xor   DX, DX  ; обнуляем регистр DX

   mov   AX, In_massiv[SI] ; извлекаем элемент массива (индекс в SI)

      inc   SI   ; дважды

  inc   SI           ; инкрементируем регистр указателя

      mov   BX, 10       ; заносим в BX число 10

  div   BX          ; делим элемент массива на десять

   mov   AX, DX        ; заносим в AL остаток от деления

  add   Al, 30h       ; получаем ASCII код символа

      call  OutSym    ; вызываем программу вывода символа на экран

   xor   AL, AL    ; обнуляем регистр AL

   call  OutSym    ; выводим символ пробела

   loop  massiv1_out_loop  ; повторяем цикл, пока счётчик элементов

          ; не обнулится

     mov  ah, 9   ; Когда закончили выводить второй массив

  lea  dx, AbzacMessage ; делаем абзац

   int  21h   ;

      mov   ah, 9   ;

      lea  dx, Mass2Message  ;

  Int   21h   ; Выводим сообщение "третий массив..."

   xor   SI, SI  ; Обнуляем регистр указателя SI

      mov   AX,_counter  ; заносим в счётчик цикла число элементов

          ; массива, умноженное на два

      mov   bl, 2   ; заносим в регистр bl число 2

   div   bl   ; получаем правильное число элементов массива

  mov   cl, al  ; заносим его в регистр счётчика цикла

massiv2_out_loop:    ; метка цикла, выводящего на экран элементы

                   ; третьего массива

      Xor   DX, DX        ; обнуляем регистр DX

      Mov   AX, In_massiv[SI] ; извлекаем элемент массива (индекс в SI)

      Cmp   ax, 0   ; сравниваем элемент массива с нулём

      Je    M2_6   ; если равно, то сразу перескакиваем на метку

      Mov   BX, 2   ; иначе заносим в BX число 2

      Mul   BX      ; Умножаем элемент массива на два

      mov   bx, 10  ; следующие команды поочерёдно сранивают с нулём

      div   bx   ; каждый разряд десятичного числа, начиная с

      push  dx   ; самого младшего, путём деления элемента на 10

      xor dx, dx  ; и сохранения в стеке разрядов.

      cmp ax, 0   ; когда в частном остаётся 0,

      je    M2_5   ; выводятся разряды числа, начиная с самого

      div   bx   ; старшего.

      push  dx   ; незначащие нули впереди числа не выводятся,

      xor dx, dx  ; первый ноль выводится, только если

      cmp ax, 0   ; всё число равно 0.

      je    M2_4   ;

      div   bx   ;

      push  dx   ;

      xor dx, dx  ;

      cmp ax, 0   ;

      je    M2_3   ;

      div   bx   ;

      push  dx   ;

      xor dx, dx  ;

      cmp ax, 0   ;

      je    M2_2   ;

      div   bx   ;

      push  dx   ;

      pop   ax   ;

      add   al, 30h  ;

      call  OutSym  ;

M2_2:     ;

      pop   ax   ;

      add   al, 30h  ;

      call  OutSym  ;

M2_3:     ;

      pop   ax   ;

      add   al, 30h  ;

      call  OutSym  ;

M2_4:     ;

      pop   ax   ;

      add   al, 30h  ;

      call  OutSym  ;

M2_5:     ;

      pop   ax   ;

      add   al, 30h  ;

      call  OutSym  ;

      jmp   M2_7   ;

M2_6:     ;

      Mov   al, 30h  ; Выводим 0

      Call  Outsym  ;

M2_7:     ;

      Xor   AL, AL  ; обнуляем регистр AL

      Call  OutSym     ; выводим пробел

      Inc   SI   ; дважды

      Inc   SI     ; инкрементируем счётчик элементов

Микропроцессоры и микрокомпьютеры