Рейтинг@Mail.ru
TMT Logo

TMTSTUB
DOS ЭКСТЕНДЕР ДЛЯ TMT PASCAL

Автор: Рустам Гадеев, 15 May 98

Если вы заметили в документе
опечатки или неточности перевода,
просьба сообщить о них!
Перевод на русский язык и оформление:
Валерий Вотинцев

СОДЕРЖАНИЕ:

ВВЕДЕНИЕ
ПРОГРАММНЫЙ ИНТЕРФЕЙС (API) TMTSTUB
  1. ПОДДЕРЖКА DOS32 API
    Установка текущей позиции в файле
    Загрузить и/или выполнить программу
    Получить информацию о DOS32 адресе
    Отменить предыдущее выделение памяти
    Выделить блок памяти
  2. ПОДДЕРЖКА ИНТЕРФЕЙСА WDOSX API
    2.1. Прерывания и исключения
    2.2. Распределение памяти
  3. ПРОГРАММНЫЙ ИНТЕРФЕЙС WDOSX (API)
    3.1. Поддерживаемые функции DPMI 0.9
    3.2. Расширенный интерфейс DOS INT 21H (EXTENDED DOS API)
    3.3. Расширенные функции поддержки МЫШИ
    3.4. Прочие функции WDOSX
ПЛАНЫ НА БУДУЩЕЕ


ВВЕДЕНИЕ

TMTSTUB основан на экстендере "WDOSX 0.94 extender by TIPPACH". Он предназначен для замены экстендера PASSTUB, основанного, в свою очередь, на экстендере PMODE, поставлявшегося с TMT Pascal. Экстендер TMTSTUB поддерживает все функции, что и PASSTUB, и, плюс к этому, в него добавлены несколько новых функций и возможностей. Основное преимущество экстендера TMTSTUB v.0.31 заключается в том, что он поддерживает обработку исключений (exceptions support). Благодаря этому, при завершении "повисшей" программы в регистрах процессора будет установлено корректное значение.

В отличие от PASSTUB, экстендер TMTSTUB поддерживает функцию 800h DPMI сервиса (MapPhysicalToLinear). Эта функция необходима для поддержки режима LFB.

Заметим, однако, что LFB режимы не поддерживаются в модуле GRAPH, входящем в бесплатную версию TMT PASCAL. Если Вам нужна поддержка LFB для работы с графикой, Вам стоит приобрести полную версию компилятора.

Опция "LOGO-" в файле PLT.CFG запрещает вывод на экран логотипа TMTSTUB при старте программы.

Размер стуб-файла составляет всего 12436 байт.

Для анализа скорости работы функции MEMAVAIL приведем некоторые статитистические данные, полученные при использовании тестовой программой различных экстендеров:

program test; {$Q-,R-}
function ticks:longint;
begin
 {$ifndef __TMT__}
 ticks:=meml[$40:$6c];
 {$else}
 ticks:=memd[$40:$6c+_zero]; {Переменная "_zero"
                              не нужна для TMTSTUB}
 {$endif}
end;
var tt,i,temp:longint;
begin
 i:=0;
 tt:=ticks; while tt=ticks do;
 tt:=ticks+20;
 while tt>ticks do
 begin
  temp:=memavail;
  temp:=memavail;
  inc(i);
 end;
 writeln(i);
end.


             Голый DOS  XMS(HIMEM) VCPI (EMM386, QEMM)  DPMI(WIN95) Экстендер
PASSTUB      - 30021,   6488,      ???,         6,         47       PMODE3.07
DOS32        - 1235,    998,       749,         334,       47       DOS32
TMTSTUB31    - 16152,   16151,     16223,       16224,     82       WDOSX
PMWSTUB      - 25571,   24107,     25544,       25563,     47       PMODE/W

BP7.0 (Prot) - 143907,  143907,    143844,      143860,    143000   RTM
BP7.0 (Real) - 1147008, 1147011,   1146926,     1147000,   1130000  real

Предупреждение!
Экстендер PASSTUB не работает с оболочкой (IDE), поставляемой в составе TMT Pascal. Вы можете использовать данный экстендер только с бесплатной версией TMT Pascal для компиляции Ваших программ с помощью PLT.EXE. Экстендер TMTSTUB НЕЛЬЗЯ использовать для отладки Ваших программ. При отладке программ из оболочки следует использовать экстендер PMWSTUB.EXE (основанный на PMODE/W).


ПРОГРАММНЫЙ ИНТЕРФЕЙС (API) TMTSTUB

Как было отмечено выше, экстендер TMTSTUB поддерживает все функции, что и PASSTUB, но, плюс к этому, в него добавлены несколько новых функций и возможностей.

1. ПОДДЕРЖКА DOS32 API (на основе файла API.DOC by Adam Seychell)

Установка текущей позиции в файле (V3.0+)
Вход:
     AH = 42h
     AL = признак, откуда отсчитывать смещение (база):
         00h от начала файла
         01h от текущей позиции
         02h от конца файла
     BX = номер дескриптора файла (file handle)
     EDX = смещение относительно базы до новой позиции

Выход:
     CF сброшен, если операция прошла успешно
            EAX = новая позиция в файле относительно начала
     CF установлен, если произошла ошибка
            AX = код ошибки (01h,06h)
Примечание:
     Обычная DOS функция для реального режима использует
     пару регистров CX:DX в качестве смещения и возвращает
     новую позицию в паре регистров DX:AX.
     В защищенном режиме вместо CX:DX используется EDX,
     а вместо DX:AX - EAX.


Загрузить и/или выполнить программу (V3.0+)

Вход:
     AH = 4Bh
     AL = тип загрузки
         00h загрузить и выполнить
         01h загрузить, но не выполнять
     DS:EDX -> имя программы в коде ASCIZ
               (включая расширение)
     DS:EDI -> Окружение программы для копировани
               в дочерний процесс
               (если EDI равно нулю, то копируетс
               окружение вызывающей программы)
     DS:ESI -> указатель на параметры командной
               строки, которые должны быть скопированы
               в дочерний PSP
Выход:
     CF сброшен, если операция прошла успешно

     CF установлен, если произошла ошибка
          AX = код ошибки (01h,02h,05h,08h,0Ah,0Bh)

Примечание:
     В отличие от функции DOS 4Bh, данная функция не
     требует установки блока параметров.
     Окружение и параметры командной строки адресуютс
     через DS:EDI и DS:ESI соответственно.
     См. примеры, поставляемые с DOS32, и объясняющие
     использование данной функции.
     Казалось бы, что MS-DOS после вызова данной функции
     должна переадресовывать текущий DTA адрес,
     однако, при вызове данной функции текущий DTA
     адрес сбрасывается в значение по умолчанию,
     т.е. на 80h-байтную область в начале PSP.

Получить информацию о DOS32 адресе (V3.01+)
Вход:
     AX = EE02h

Выход:
     EBX = 32-битный линейный адрес программного сегмента
     EDX = Размер .EXE файла программы после линковки.
     ESI = Смещение для PSP ( Program Segment Prefix )
     EDI = Смещение для окружения (Program Environment)
     ECX = Смещение для имени и пути .EXE файла программы
           (в формате ASCIZ, т.е. завершающееся нулем)
     AX  = Сегмент реального режима для 8Kb буфера,
           используемого для операций чтения/записи.
Примечание:
  • Все возвращаемые смещения адресуются относительно основного сегмента программы.
  • Размер .EXE файла программы используется, в основном, для подгрузки дополнительных данных, добавленных в конец файла программы. Для получения доступа к этим данным программа может просто сместиться в файле на величину размера выполняемой части программы.
  • Имя .EXE файла, на которое указывает ECX, фактически являетс именем файла, содержащимся в последней строке сегмента окружения, на который указывает EDI.
  • Адрес PSP указывает на оригинальный PSP, создаваемый DOS. Таким образом, указатели, хранимые в нем, по прежнему содержат сегментные значения для реального режима (segment:offset). Кроме того, этот адрес PSP может отличаться от адреса, возвращаемого функцией DOS Int 21h AH=62h (Get PSP), поскольку DOS32 может загрузить стуб родительской программы.
  • Поскольку возвращаемый в AX сегментный адрес 8Kb буфера используется виртуальным сервисом 32 битного чтения/записи файлов (INT 21h AH=3Fh/40h), то содержимое этого буфера после вызова этого сервиса будет разрушено. Однако, прикладная задача все-таки может временно пользоваться этим буфером для передачи данных между реальным и защищенным режимом вместо того, чтобы отдельно выделять специальный DOS блок для этих целей. Ближний указатель на этот буфер может быть вычислен как (16*AX - EBX).
  • Эта функция может быть использована в обработчиках прерываний, работающих в защищенном режиме.

Отменить предыдущее выделение памяти (v3.00+)

Эта функция освобождает предварительно выделенный блок памяти
(функция AX =EE41h) или DMA буфер (функция AX=EE42h). При вызове этой функции несколько раз будут поочередно, в обратном порядке освобождаться блоки памяти, выделявшиес перед этим (т.е. по принципу стека). Например, если сначала был выделен блок памяти, а затем DMA буфер, то при первом вызове данной функции сначала будет освобожден DMA буфер, а при повторном вызове - ранее выделенный блок памяти. Если же вызвать функцию еще и в третий раз, то функция вернет флаг ошибки в виде выставленного флага переноса ( CF ), поскольку освобождать уже больше нечего.
Вход:
     AX = EE40h

Выход:
     CF сброшен, если операция прошла успешно
     CF установлен в случае ошибки
Примечание:
  • Функция возвращает флаг ошибки, если освобождать нечего.
  • При завершении задачи вся ранее выделенная ей память будет освобождена автоматически.
Выделить блок памяти (V3.00+)

Обычно прикладная задача вместе с кодом, данными и стеком располагается в одном большом блоке памяти. Данная функция позволяет выделить дополнительный блок памяти для программы.
Вход:
     AX  = EE42h
     EDX = Размер блока памяти в байтах,
           который нужно выделить

Выход:
     EAX = Фактический размер выделенного блока
           памяти в байтах
     EDX = Ближний указатель на базовый адрес
           выделенного блока памяти относительно
           сегмента основной программы.

     CF сброшен, если операция прошла успешно
     CF установлен в случае ошибки
        (если блок нужного размера выделить
        не удалось).
Примечание:
  • Размер фактически выделяемого блока памяти (EDX) всегда кратен 4KB. Например, если мы попросим выделить 51001h байт, то фактически будет выделено 52000h байт.
  • Данную функцию НЕЛЬЗЯ использовать в обработчиках прерываний или после выполнения команты "terminate and stay resident" ( AX=EE30h ).
  • Если в EAX возвращено нулевое значение, то это значит, что память не была выделена, и значение EDX неопределено.
  • Функция возвращает флаг ошибки, если просят выделить ноль байт.
  • Выделять память можно не более 64-х раз! Если Вашей программе требуется большее количество выделений памяти, рекомендуем использовать функции управления памятью Петера Андерсона (Peter Anderson) из библиотеки PAL. С библиотекой поставляются примеры ее использования. Данная же функция может быть использована только дл ограниченного количества выделений памяти.
  • Если программа запущена не под DPMI сервером (например, под чистым DOS, XMS или VCPI), то сначала выделяетс имеющаяся расширенная память, и только затем - основная (conventional). Т.е. основная память будет выделена только в том случае, если расширенная уже полностью исчерпана. В любом случае, DOS32 настраивает таблицу страниц памяти таким образом, чтобы выделенная память адресовалась как один линейный блок памяти, хотя физически она может быть разбросана по всему адресному пространству RAM.
Внимание!
Функции 42h и 4Bh прерывания int 21h имеют другие назначения регистров для совместимости с DOS32 и TMT Pascal. См. выше.

2. ПОДДЕРЖКА ИНТЕРФЕЙСА WDOSX API
    (см. README.TXT by Wuschel a.k.a Michael Tippach)

2.1. Прерывания и исключения

Если программа запускается под голым DOS без DPMI хоста, то WDOSX автоматически запустит свой встроенный DPMI хост. Ниже приводится описание поведения DPMI хоста WDOSX в ряде случаев. При запуске из под Windows и др. систем, имеющих свой DPMI хост, будут использоваться возможности имеющегося хоста.

Если в Вашей программе установлен обработчик IRQ в защищенном режиме, то все аппаратные прерывания реального (или V86) режима будут переданы Вашему обработчику. Если же такой обработчик не установлен, то аппаратные прерывания будут переданы обработчику прерываний реального (V86) режима.

WDOSX может обрабатывать глубину прерываний не более 16. В программе иногда важно знать, находимся ли мы всегда внутри обработчика IRQ при переключении режимов, или же работа обработчика перерываний может быть прервана другим прерыванием.

Все программные прерывания вплоть до 0Fh интерпретируются как исключения. Поэтому при попытке вызвать вызвать INT 5 для печати содержимого экрана Вы получите вместо него исключение. Для того, чтобы INT 5 выполнял то, что ему предназначено, необходимо воспользоваться сервисом трансляции прерываний в DPMI.

В отличие от спецификации DPMI, WDOSX не передает исключения с номерами 0..7 в обработчик прерываний реального режима.

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

Когда WDOSX устанавливает свой собственный DPMI хост, Ваша программа работает с нулевым уровнем привилегий. Поэтому процессор самостоятельно не переключает стек при возникновении исключения. Это может привести к краху программы, если содержимое стека в данный момент разрушено.

Исключение 0F передается обработчику реального режима в любом случае. Это сделано специально для использования замечательной возможности контроллера прерываний генерировать побочные прерывания IRQ 7.

2.2. Распределение памяти

После того, как WDOSX устанавливает свой встроенный DPMI хост, начальный линейный стартовый адрес блока памяти Вашей программы становится равным 400000h. При запуске из-под Windows или другой многозадачной операционной системы этот адрес может быть совершенно другим, но здесь мы это не рассматриваем.

При старте программы ESP будет указывать на начало блока памяти, поэтому обращение к памяти через [esp] будет недопустимой операцией, которая может вызвать ошибку адресации страницы памяти. Однако, доступ через [esp-4] (если занести какое-нибудь значение в стек) ошибки не вызовет.

Дескрипторы cs: ds: (= ss:) инициализируются на лимит в 4GB. Однако, Windows NT 3.5, например, изменяет лимиты дескрипторов по своему усмотрению. Поэтому, если Вы пожелаете узнать фактическое значение лимитов, то следует воспользоваться инструкцией LSL.

В некоторых руководствах рекомендуется использовать отрицательные смещени для доступа к видео-памяти или к блоку памяти в первом мегабайте. Обращаем Ваше внимание, что у этого метода есть свои подводные камни! DPMI хост может изменить линейный базовый адрес Вашего сегмента в случае, если Вы меняете его размер. Соответственно, вычисленные ранее отрицательные смещения станут неверными, и Вам потребуется вычислять их заново. Гораздо удобнее и предпочтительнее выделять дескриптор с нулевым базовым адресом и лимитом в 4GB, что позволит легко получать доступ к любому участку используемой памяти.

!!! Никогда не используйте функцию INT 31h/0503h для изменения размера сегмента, в котором сейчас выполняется программа. Чтобы предостеречь Вас от модификации размеров Вашего начального сегмента, мы даже не будем сообщать Вам, какой дескриптор DPMI хост возвращает, когда WDOSX выделяет блок памяти для Вашей программы.

WDOSX предоставляет удобную в использовании интерфейсную функцию (INT 21h/FFFFh), которая позволяет изменить размер Вашего начального сегмента. Эта функция ДОЛЖНА ВЫЗЫВАТЬСЯ ТОЛЬКО ИЗНУТРИ НАЧАЛЬНОГО СЕГМЕНТА! Вообще говоря, это не лучшая идея - иметь более одногоe DPMI блока памяти (правда, отладчик обычно использует два таких блока, но это совсем друга песня).


3. ПРОГРАММНЫЙ ИНТЕРФЕЙС WDOSX (API)

WDOSX API можно разделить на 3 функциональные части:

  • Интерфейс DPMI 0.9
  • Расширенный интерфейс DOS INT 21H
  • Прочие функции

В настоящее время WDOSX поддерживает практически все DPMI функции, описанные в спецификации DPMI0.9. Кроме того, "по просьбам телезрителей" специально добавлена функция 801h.

Если Вы еще не знакомы с DPMI, рекомендуем оснакомиться с его спецификацией, которую можно найти, например, здесь:

ftp://x2ftp.oulu.fi/pub/msdos/programming/specs/dpmispec.arj

Поддержка расширенного INT 21H осуществляется аналогично любому другому DOS экстендеру, поддерживающему расширенный INT 21H DOS API. Отвечая на часто задаваемый вопрос, отметим, что функции DOS, не требующие передачи сегментного регистра (в любую сторону), могут вызываться в программе напрямую, поскольку WDOSX поддерживает их "в живую"! Для многих это очевидно, но, все-таки, не для всех.

3.1. ПОДДЕРЖИВАЕМЫЕ ФУНКЦИИ DPMI 0.9

0000hВыделить дескрипторы в LDTALLOC LDT DESCRIPTORS
0001hОсвободить дескрипторы из LDTFREE LDT DESKRIPTORS
0002hПреобразовать сегмент в селекторSEGMENT -> SELECTOR
0003hПолучить инкремент селектораGET SELECTOR INCRMENT
0006hПолучить базовый адрес сегментаGET SEGMENT BASE
0007hУстановить базовый адрес сегментаSET SEGMENT BASE
0008hУстановить лимит сегментаSET SEGMENT LIMIT
0009hУстановить права доступаSET ACCESS RIGHTS
000AhСоздать псевдонимCREATE ALIAS
000BhПолучить дескрипторGET DESCRIPTOR
000ChЗадать значение дескриптораSET DESCRIPTOR
0100hВыделить блок DOS-памятиALLOC DOS- MEM
0101hОсвободить блок DOS-памятиFREE DOS- MEM
0102hИзменить размер блока DOS-памятиRESIZE DOS- MEM
0200hПолучить адрес обработчика прерывания реального режима GET REALMODE INTERRUPT VECTOR
0201hУстановить обработчик прерывания реального режима SET REALMODE INTERRUPT VECTOR
0202hПолучить адрес обработчика исключения GET EXCEPTION HANDLER
0203hУстановить обработчик исключения SET EXCEPTION HANDLER
0204hПолучить адрес обработчика прерывания защищенного режимаGET PM INTERRUPT VECTOR
0205hУстановить обработчик прерывания защищенного режима SET PM INTERRUPT VECTOR
0300hМоделировать прерывание реального режима SIMULATE REAL MODE INTERRUPT
0301hВызвать процедуру реального режима
(с возвратом по RETF)
CALL REALMODE PROCEDURE (RETF)
0302hВызвать процедуру реального режима
(с возвратом по IRET)
CALL REALMODE PROCEDURE (IRET)
0303hСоздать и возвратить адрес функции обратного вызова реального режима DOSALLOCATE REALMODE CALLBACK
0304hОсвободить адрес CallBack, созданный функцией 0303h FREE REALMODE CALLBACK
0400hПолучить версию DPMIGET DPMI VERSION
0500hОпределить количество свободной памятиGET FREE MEM
0501hВыделить блок памятиALLOC MEM
0502hОсвободить блок памятиFREE MEM
0503hИзменить размер блока памятиRESIZE MEM
0600hБлокироваить линейный участок памяти LOCK LINEAR REGION
0601hРазблокировать линейный участок памяти UNLOCK LINEAR REGION
0602hРазблокировать блок памяти реального режима UNLOCK REALMODE REGION
0603hПовторно блокировать блок памяти реального режима RELOCK REALMODE REGION
0604hПолучить физический размер страницы памяти GET PHYSICAL PAGE SIZE
0702hПометить страницу как разрешенную к выгрузке на диск MARK PAGE PAGEABLE
0703hИсключить страницу из списка занятыхDISCARD PAGE
0800hОтразить область физической памяти на линейную память MAP PHYSICAL REGION
0801hОтменить действие функции 0800hUNMAP PHYSICAL REGION
0900hВыключить виртуальный флаг прерываний
и возвратить его прежнее значение
GET AND DISABLE VI STATE
0901hВключить виртуальный флаг прерываний
и возвратить его прежнее значение
GET AND ENABLE VI STATE
0902hПолучить текущее значение виртуального флага прерываний GET VI STATE

Автор русского проекта:
Valery Votintsev

при поддержке
TMT Development Corporation.
All rights reserved.

[Новости]   [Продукты]   [Продажи]   [Скачать]   [Апдейты]   [Поддержка]
[Документация]   [FAQ]   [Contributions]   [Ссылки]   [Связь с TMT]   [Главная]