原创 PCI声卡在DOS下的发声研究(一)、OPL、波表、DOS下捕获IO端口、V86

2011-4-9 13:37 8595 9 9 分类: 工程师职场

PCI声卡在DOS下的发声研究(一)、OPL、波表、DOS下捕获IO端口、V86

wxleasyland

2011.3

 

DOS下,ISA 声卡的基地址是2XXH端口,比如220H等。而声卡的ADLIB FM合成端口是388H、389H口。声卡的UART端口一般是330H。

ISA声卡一般用中断IRQ5,DMA 1。

DOS下的老游戏一般是直接操作ISA声卡的这些I/O端口(220H、388H等)、IRQ寄存器、DMA寄存器、中断向量,这样ISA声卡就能发声了。挺简单的吧。ISA的访问就是这么简单,所以用ISA做一个采集卡什么的应用,是比较简单的。

到了PCI声卡,就完全不一样了。PCI协议非常复杂!

PCI声卡的基地址由BIOS动态分配了,而且基地址在64KB范围以外了(比如端口地址在E400H),要在CPU保护模式下才能访问了,实模式访问不了。IRQ、DMA也不一样了。OS也转成WINDOWS了,声卡要装厂家的驱动了,游戏软件不直接操作声卡了,而是使用WINDOWS的API了。所以,WINDOWS下游戏没问题了,但在DOS下老游戏不能发声了。

有的声卡厂家开发了DOS下使用PCI声卡的驱动,但是有的声卡厂家又没有DOS驱动。

AC97 PCI声卡一般由声卡控制器芯片、AC97 CODEC 芯片组成。声卡控制器芯片同时管理PCI总线。比如下面的PCI声卡,ES1373就是控制器芯片,CS4297就是CODEC芯片。这个声卡是板载的,即做到了主板上,它不是集成声卡!

集成AC97声卡是,主板南桥集成了声卡控制器芯片。集成AC97声卡的CODEC芯片是外置的,但声卡的控制器是集成在南桥内的,南桥厂家是不会提供DOS下的声卡驱动的,理论上是做得到的,但没人做。声卡驱动一般是声卡厂家做的,南桥厂家不做这个,虽然想做也是可以做。所以,集成的AC97声卡肯定是没有DOS驱动的!

而ES1373是声卡厂家做的芯片,所以声卡厂家开发了DOS下的驱动,所以DOS下可以用。

 

什么叫DOS下可以用:就是DOS下有I/O端口220H、388H等,同时IRQ、DMA也能工作正常。就好像有一个ISA声卡存在一样。DOS驱动将PCI声卡模拟成ISA声卡,模拟出了I/O端口220H、388H等!

 

 

声卡的ADLIB FM合成端口是388H,ISA时,FM合成由FM合成芯片OPL来完成。

OPL有OPL2、OPL3,OPL3更高级。OP指 FM运算器(OPERATOR),L2指型号2,L3指型号3!!

到了PCI时,FM合成可以由OPL芯片来完成(比如YMF724声卡),也可以由软波表来完成(比如ES1373声卡)!

软波表的波表文件是先加载在内存中的(长度为1MB、2MB、4MB或8MB等的一个文件),然后声卡读内存中的波表文件,来发出声音。因为PCI总线速度很快,所以声卡读取内存中的波表文件没有问题。ISA总线速度很慢,用软波表就没办法弄了,所以ISA声卡没有软波表,有带了FM芯片来合成声音。

集成AC97声卡肯定是没有带OPL合成芯片,只有软波表这种方式。

带OPL合成芯片的PCI声卡会贵些。YMF724声卡的控制器芯片中内置了FM功能(OPL3),当然它应也可以用软波表合成。

 

 

为什么PCI声卡带OPL芯片会更好?因为在DOS游戏下,OPL芯片FM合成的声音才是正宗的。软波表发出的声音,惨不忍睹。

OPL实际功能是完成二个波形的FM运算。软波表中是存放了各个波形吗?不清楚。按理要这样吧。

但是,通常的理解是,软波表是将各种真实乐器所能发出的所有声音(包括各个音域、声调)录制下来,存贮为一个波表文件。播放时,根据MIDI文件纪录的乐曲信息向波表发出指令,从“表格”中逐一找出对应的声音信息,经过合成、加工后回放出来。这样看来,软波表又是乐器的声音,用来MIDI播放用的。

那软波表的FM合成是如何实现?

DOS下播放仙剑的RIX,是直接控制388H口发声,与MIDI无关,与388H口的控制指令有关,发出的声音不一定是乐器的,可以是任意的,灵活性很大,比如可以仅仅是一个正弦波。

DOS下播放MIDI,是MIDI播放器模拟出某种乐器的音色,模拟的方法是控制388H口来产生各种音色,比如钢琴声等,但肯定是一种乐器的,不会任意发声,不会只发声一个正弦波,那样没什么意义。  MIDI播放器本身是不知道有软波表存在的,最终是通过388H口来完成音乐模拟。

所以,这样看来,波表文件中存放的应该只是波形,而不是乐器的声音,如果存放的是乐器的声音,那播放器如何知道怎么来用这些乐器的声音?播放器只知道去使用388H口而已。

388H口的指令并没有定义乐器!也没有定义MIDI指令!乐器是MIDI定义的!388H口的指令中只有定义了音调!

所以,DOS/WIN98声卡驱动程序中的波表文件和乐器无关!(后面的英文说明也证明了这一点)

 

 

到了WINDOWS XP,PCI声卡就没有模拟出388H口了,不能随意发声了。软波表中就可以是存放乐器的声音了,播放MIDI可以直接用软波表中的乐器声音了。所以可能又不一样了。我的理解。

 

 

另外,ISA的硬波表(如AWE32),存放的肯定是乐器的声音!  The EMU8000 comes integrated with 1MB of General MIDI samples and 512kB of DRAM for additional sample downloading. 这时,要有专门针对硬波表编制的软件来让硬波表发声!基地址也不一样了,不是388H口了! EMU8000 地址是 6xxH, AxxH and ExxH。  硬波表AWE32与OPL是不同的设备了!  另外,EMU8000不认识MIDI指令,可以用一个AWEUTIL程序来进行MIDI指令解析,再通过EMU8000发出硬波表的声音。To support existing games that use MPU-401, AWEUTIL works by trapping data going out to the MPU-401 port and program the EMU8000 using the data.  可以参考http://www.gamedev.net/page/resources/_/reference/programming/legacy-articles/audio/faq-on-soundblaster-awe-32-r445  《EMU8000-Programming the Soundblaster AWE-32》。

也就是说,仙剑DOS是支持通过MPU401来传送MIDI音乐的(不是RIX音乐),可以用AWE32声卡的AWEUTIL软件,完成MPU401转硬波表发声的功能。这样游戏的音乐就是硬波表的音乐了。没有这个声卡,无法试验。

 

 

 

板载声卡CREATIVE ES1373的研究

 

正好MS6199主板,AWARD BIOS,有ISA、PCI插槽,SLOT1的CELERON,300MHZ。发现板载的声卡是CREATIVE ES1373,(CODEC编解码器是CS4297),只要对ES1373驱动就行。所以实际这个声卡是一个独立的PCI声卡,不是集成在南桥内的。

电脑启动,开机时显示PCI设备,BUS号0,设备号12,功能号0,VENDOR ID=1274,DEVICE ID=1371,DEVICE CLASS是“MULTIMEDIA DEVICE”,IRQ=12。  用我编的FINDPCI1.exe看,CLASS值为0401H,INITPIN=1。

这时,DOS下运行我编的FINDSB.exe,找不到声卡220H口等,也找不到MPU401,也没有MIDI口388H。

这时,WIN98里已经安装了驱动,在WIN98设备里,声卡是“SB PCI128”,同时有模拟出一个“SB PCI128 LEGACY DEVICE”,这个就是DOS可用的。

在WIN98 DOS BOX下,运行我编的FINDSB.exe,可以找到声卡220H口!MIDI 388H口也能发声!

再关闭WIN98,退出到MSDOS,这时WIN98的DOSSTART.BAT自动运行了SBINIT.COM,然后DOS下就可以找到声卡220H和388H!

 

驱动程序只提供了WIN98里的驱动,安装后,就会有DOS的驱动出来,这时,可以在WIN98 DOS BOX里运行,或者要先进入WIN98,再退出来MSDOS状态,这样DOS就能用。

驱动程序没有专门的DOS版本。实际上WIN98的驱动中就带了DOS的驱动了。

 

微星的驱动没有说明文件,不知道原理。ENSONIQ ESS1373的驱动,好像是1373的原版驱动,有说明文件manual.doc,知道驱动文件要怎么用。微星的驱动应该是根据它修改来的。

 

如何不进入WIN98,直接开机启动到DOS就能用声卡的方法:

WIN98驱动程序会将

SET BLASTER=A220 I5 D1 H7 P330 T6

SET SBPCI=C:\SBPCI       

添加到AUTOEXEC.BAT。(SBPCI目录是声卡驱动的目录)

HIMEM中一定要有HIMEM.SYS和EMM386.EXE。EMM386一定要有!

然后进入SBPCI目录,运行SBINIT.COM,会提示:

SB PCI @ PORT e400, IRQ 12

OUTPUT MODE IS ANALOG

然后DOS中就可以使用这个PCI声卡了!!

运行我编的FINDSB.exe,可以找到声卡220H口!MIDI 388H口也能发声!

这时用MEM命令会发现, XMS内存已经用掉了近3MB!这之前只用掉0.6MB。EMS内存仍是32MB,没有用掉。说明应是加载了波表文件,只加载到XMS,没有加载到EMS中,EMM386的功能可能是用来进入保护模式用的,这样才能访问到声卡的基地址。

 

SBPCI=C:\SBPCI,指定了SBPCI.INI这个文件所在的目录!SBPCI.INI在WIN98安装完声卡驱动后,被修改过,主要是里面的:

PCIPort=0000 变成了 e400

PCIIRQ=00 变成了 12

SynthFile=c:\WINDOWS\SYSTEM\eapci2m.ecw  这是波表文件的位置

 

所以如果WIN98中没有安装过驱动程序,则DOS下不能直接用,因为SBPCI.INI在不同的电脑中值不一样!在WIN98中安装过驱动程序后,SBPCI.INI的值才正确。(主要是SynthFile的值)

但BIOS给PCI设备的基地址、IRQ等可能也会改变,所以厂家要求先运行WIN98,再退出到DOS,这样来使用声卡!(这个基地址、IRQ值,SBINIT.COM会自动检测,问题不大)

 

但经试验:

如果PCIPort值改成别的,则没有关系!仍然sbinit.com会使用正确的PORT(e400)!!!

如果SynthFile值不对,则不行!sbinit.com会提示找不到文件,不会加载声卡驱动!!

说明SBPCI.INI文件的主要作用是指定波表文件的位置!

同时波表文件一定要存在!

同时,验证了ES1373没有自带FM合成芯片!DOS下也是用软波表来模拟MIDI的FM发音的!!

manual.doc也说明了,ES1373没有FM芯片。

 

经试,播放仙剑RIX文件,挺难听的。

 

而用ISA声卡CT2502播放仙剑RIX文件,声音好听啊,FM音乐原汁原味。

 

 

这也说明了,DOS下可以用软件虚拟出I/O端口出来!!!具体原理不清楚,但一定要有EMM386.EXE。见后述。

 

 

DOS下的一些工具:

详见manual.doc

SBTEST.EXE 播放声音和MIDI,看是否正常

SBLEGACY.EXE 检测传统的I/O是否有冲突(只能在sbinit.com加载之前运行)

SBCFG.EXE 显示当前配置值(可以在sbinit.com加载之前或之后运行,显示的值不受SBPCI.INI影响)

SBMIXER.EXE 设置混音器的音量

MT32.EXE 在MIDI模式和Roland的MT32模式间切换

 

 

 

引用manual.doc中的一些内容:

 

How MS-DOS Mode works

When the system enters DOS Mode the DOSSTART.BAT file is run.  DOSSTART.BAT contains any MS-DOS Mode drivers that must be loaded, including the SBAPCI64V MS-DOS Mode driver APINIT.Com.

Windows 98 will add the necessary lines for the SBAPCI64V to initialize the AUTOEXEC.BAT, CONFIG.SYS, and DOSSTART.BAT each time it loads, even creating these files if those files are missing.

 

 

AUTOEXEC.BAT

The Install Wizard adds a few lines to the AUTOEXEC.BAT file to initialize SBAPCI64V.  If the AUTOEXEC.BAT file is missing it will be created.  The lines added are described below.

Note: In Windows 3.x the only line added to the AUTOEXEC.BAT is “CALL C:\<path>\INITAP.BAT”, where <path> refers to the SBAPCI64V destination folder (i.e., C:\SBAP64V) indicated during installation.  This batch file contains the lines described below as well as “<SBAPCI64V Path>\APINIT.COM”, which are necessary for the SBAPCI64V to function.

1.    SET SNDSCAPE=<SNDSCAPE.INI location>

The SNDSCAPE environment variable points to the location of the SNDSCAPE.INI file.  This file is installed when the Windows 98 driver is installed.  The driver typically resides in the Windows 98 directory.

 (I.e., SET SNDSCAPE=C:\WINDOWS). 

The SNDSCAPE.INI file is used for backward compatibility with ENSONIQ Soundscape cards and should not be removed.

2.    SET BLASTER=Axxx Ixx Dx T2

This is included for SoundBlaster Pro compatibility.  The A (SoundBlaster Port Address), I (Digital Audio Interrupt), and D (DMA Channel) values can be changed in the Device Manager of Windows 98.  See the section entitled SBAPCI64V Legacy Device Properties Tabs on page 13 for more details.  T2 indicates stereo SoundBlaster Pro I digital audio.

 

 

CONFIG.SYS

The Install Wizard adds a few lines to the CONFIG.SYS file to initialize SBAPCI64V.  If the CONFIG.SYS file is missing it will be created.  The lines added are listed below.

1.    DEVICE=C:\WINDOWS\HIMEM.SYS

2.    DEVICE=C:\WINDOWS\EMM386.EXE

 

DOSSTART.BAT

The Install Wizard adds a line to the DOSSTART.BAT file to initialize SBAPCI64V.  If the DOSSTART.BAT file is missing it will be created.  The line added is listed below.

<SBAPCI64V Path>\APINIT.COM

APINIT.COM is the SBAPCI64V MS-DOS driver.  It is required for the SBAPCI64V card to function properly under MS-DOS Mode.

APINIT.COM requires that EMM386.EXE or another memory manager, such as QEMM.SYS, is loaded.  If needed the Install Wizard adds the necessary EMM386.EXE and HIMEM.SYS lines to your CONFIG.SYS file, creating CONFIG.SYS if it isn’t present. 

This driver may be loaded into high memory in the AUTOEXEC.BAT, though by default it is not.

(I.e., LOADHIGH C:\SBAP64V\APINIT.COM)

Do not remove the memory manager all together.  Do not attempt to load APINIT.COM into high memory when using the NOEMS option if APINIT.COM fails to run APLOAD.EXE or APCONFIG.EXE. 

In the rare case that a program will not work with a memory manager the SBAPCI64V will not function with that game.

 

 

 

I need Pure DOS drivers for my SBAPCI64V.  Where can I get them?

The SBAPCI64V soundcard supports MSDOS through Win98 and Win3.1x, by first booting to Windows and then shutting down to an MSDOS prompt.  These DOS utilities are installed automatically with the Windows drivers.

 

 

 

The FM Synthesis does not sound correct. Why?

Some older computer games with Sound Blaster support are actually written for sound cards with an OPL or FM (frequency modulation) chip on the board.   Sound Blaster cards has these chips.   Creative’s Sound Blaster emulation is done through software, not hardware, and there is no FM chip on the board.   Creative uses wavetable synthesis to generate sounds.    Therefore, when certain sounds play through the Soundscape card, what is being heard is the wavetable representation or "closest match" of the original FM sounds.   Therefore, instead of a crash, you may hear a drum roll.   This is a hardware issue and the only way to hear the correct sounds would be to use a sound card with an FM chip.

 

 

 

 

 

 

 

=====================================

 

YMF724 PCI声卡,它有自带了FM合成芯片!不过手上没有,无法试。

 

 

 

 

 

 

====================================

 

DOS下用软件虚拟出I/O端口(模拟出I/O端口、捕获I/O端口)

 

上面可见,DOS下原来没有220H这个I/O端口,后来声卡的驱动程序SBINIT.COM运行后,就有220H这个端口了!可见这个端口是SBINIT.COM虚拟出来的!

但上网找了很长时间,都没有找到DOS下虚拟出I/O端口方法。PCI总线的MMIO好像不是这个功能。

后来想到,由于SBINIT.COM一定要用到EMM386,肯定与EMM386有关联。于是用GOOGLE搜索EMM386,果然发现它有TRAP I/O端口的功能!!这是非常重要的信息!

EMM386使CPU进入V86模式。SBINIT.COM调用EMM386的功能,这样就可以捕获I/O端口了!!

就是这么简单的原理,我找了非常久的时间。原理了解了,具体的实现细节不太了解,太深奥。

 

见:

http://www.programmersheaven.com/mb/x86_asm/376018/376018/virtualize-io-in-dos/

 

 

Virtualize I/O In DOS Posted by Bret on 25 Sept 2008 at 8:16 AM

This may be an unreasonably tall order, but here goes.

I'm trying to figure out a way to virtualize (trap) I/O requests in "real" DOS.  It seems the only way to do it may be using INT 2Fh, Function 4A15h with MS's EMM386.EXE (excerpt from Ralf Brown's Interrupt List below).

Has anybody ever tried to trap I/O requests, either this way or any other way, and have some sample code to go along with it? Any other ideas on approaches that might work?

***************

 

INT 2F - MS EMM386.EXE v4.46+ - INSTALL I/O VIRTUALIZATION HANDLER

        AX = 4A15h

        BX = 0000h (function number)

        DX = starting I/O address

        EDX high word = ending I/O address

        CX = number of ports to trap

        DS:SI -> I/O dispatch table (see #02815)

        DI = size of client's code and data (size of DS segment which must be

              made available to I/O dispatch function in protected mode)

Return: CF clear if successful

        CF set on error

Notes:              this interface is only available in virtual-86 mode;   the I/O handlers

          will be called in protected mode

        only ports 0100h-FFFFh may be trapped; EMM386 reserved ports 0000h-

          00FFh

 

Format of EMM386 I/O dispatch table [array]:

Offset            Size         Description             (Table 02815)

 00h               WORD    I/O port number

 02h               WORD    offset of I/O handler for port (see #02816)

 

(Table 02816)

Values EMM386 I/O dispatch function is called with:

        CX = Ring0 code selector for I/O handler's segment

        DS = Ring0 data selector for I/O handler's segment (alias of CS)

        EDX = faulting I/O address

        ECX = direction (00000008h for byte output, 00000000h for byte input)

                        (reportedly 00h for byte/word input, 04h for byte/word output

                          under DOS 6.22 EMM386)

        EAX = data in/out

Return: (via FAR RET)

        CF clear if I/O access successfully virtualized

        CF set if access not virtualized (default handler will be called to

              perform the I/O)

BUG:               32-bit I/O on trapped ports hangs the DOS 6.22 EMM386

 

***************

 

Re: Virtualize I/O In DOS Posted by jeffleyda on 26 Sept 2008 at 12:15 PM

I'm pretty dumb with this stuff, but it's always been something I've wanted to play with too. Do IRC, the I/O access map is essentially just a large bitfield inside the CPU, and this emm386 function is merely providing access to it? That's actually kinda cool-I didn't even know this function existed.

Obviously it's possible to do it w/o emm386, since soft-ice is able to trap I/O and it's incompatible with emm386. It does put the cpu into it's own protected mode though.

So, sorry that I don't have any help for you, but just wanted to tell you that there's at least someone else who is interested in the subject at hand.

Re: Virtualize I/O In DOS Posted by Bret on 27 Sept 2008 at 10:09 AM

: I'm pretty dumb with this stuff, but it's always been something I've

: wanted to play with too. Do IRC, the I/O access map is essentially

: just a large bitfield inside the CPU, and this emm386 function is

: merely providing access to it? That's actually kinda cool-I didn't

: even know this function existed.

:

: Obviously it's possible to do it w/o emm386, since soft-ice is able

: to trap I/O and it's incompatible with emm386. It does put the cpu

: into it's own protected mode though.

:

: So, sorry that I don't have any help for you, but just wanted to

: tell you that there's at least someone else who is interested in the

: subject at hand.

 

I'll follow this up with some posts as I get things figured out. Scouring some VERY old usenet posts I managed to find some resources that look promising.

 

Re: Virtualize I/O In DOS Posted by Bret on 1 Oct 2008 at 5:36 PM

: : I'm pretty dumb with this stuff, but it's always been something I've

: : wanted to play with too. Do IRC, the I/O access map is essentially

: : just a large bitfield inside the CPU, and this emm386 function is

: : merely providing access to it? That's actually kinda cool-I didn't

: : even know this function existed.

: :

: : Obviously it's possible to do it w/o emm386, since soft-ice is able

: : to trap I/O and it's incompatible with emm386. It does put the cpu

: : into it's own protected mode though.

: :

: : So, sorry that I don't have any help for you, but just wanted to

: : tell you that there's at least someone else who is interested in the

: : subject at hand.

:

: I'll follow this up with some posts as I get things figured out.

: Scouring some VERY old usenet posts I managed to find some resources

: that look promising.

 

I've found a good resource, and possibly the only valid resource that may exist for this. He is Bob Smith, one of the founders of Qualitas (the makers of 386MAX). His current e-mail address is bsmith@sudleyplace.com. He sent the the attached Zip file with some source code and comments. In the Zip file, I renamed the executable file IOTrap.Com to IOTrap.Co_ so that I could upload it here.

 

The main thing of interest is the IOTrap.Txt file, which explains some problems with the interface, its implementation in EMM386, and the documentation. Microsoft provided a specification on MSDN many years ago (I haven't been able to find it), which is the basis for what's in the RBIL excerpt above (which is both incomplete and incorrect). Apparently, Qualitas tried to get Microsoft to update and correct the spec and EMM386, to no avail. I think 386MAX implemented an improved version of the spec (based on what I see in the Zip file), but don't have a copy of 386MAX to verify any of it. I believe that EMM386 and 386MAX are the only memory managers to implement the function at all.

 

I can tell you that it does in fact work. I've been doing some experimentation with a joystick emulator, and it seems to work fine so far (I'm testing with EMM386 version 4.48, which comes with DOS 6.20). At first, I couldn't get it to work at all. As it turns out, I was testing the function by single-stepping through with a debugger, which doesn't seem to work. I think it has something to do with the INT 03's that the debugger sticks in memory to do the single-stepping. After I stopped single-stepping and just let the program run, it started working like it was supposed to (this isn't the first time I've had a program react differently in a debugger than it does in real life). Also, FYI, the IOTRAP.COM program in the Zip file crashes on my computer, and I think it might be for the same reason (it contains INT 03's in it).

 

A few very interesting things to note (I found them very interesting, anyway). The EMM386 implementation only works correctly with byte-level I/O (IN AL,DX and OUT DX,AL). If you try to virtualize a word access (IN AX,DX), EMM386 just does a CBW on the value in AL. It doesn't return the AH that you told it to. Dword accesses (IN EAX,DX) crash the computer. Also, the I/O virtualization code is called in 16-bit protected mode, not 32-bit protected mode as you might expect on a 32-bit processor. And, the virtualization does not get "passed though" to Windows if you run Windows after setting up Virtual I/O (though it would seem logical that it should).

 

I'll need to experiment some more, but if it keeps working like it has so far, I think I'll be using this function a lot.

Attachment: IOTrap.zip (16274 Bytes | downloaded 173 times)

 

 

Re: Virtualize I/O In DOS Posted by Bret on 2 Oct 2008 at 7:37 AM

: I'm pretty dumb with this stuff, but it's always been something I've

: wanted to play with too. Do IRC, the I/O access map is essentially

: just a large bitfield inside the CPU, and this emm386 function is

: merely providing access to it? That's actually kinda cool-I didn't

: even know this function existed.

:

: Obviously it's possible to do it w/o emm386, since soft-ice is able

: to trap I/O and it's incompatible with emm386. It does put the cpu

: into it's own protected mode though.

:

: So, sorry that I don't have any help for you, but just wanted to

: tell you that there's at least someone else who is interested in the

: subject at hand.

 

Just a side note regarding Soft-ICE. I can't speak to it for sure, but based on the literature I've seen so far (not directly from Soft-ICE, since I've never used it), I think they use the Pentium Debug registers to trap I/O. Intel introduced the Debug Registers with Pentium-class CPU's, and one of the things you can do with them is Trap I/O. From my understanding (not verified in any way), there are 4 available Debug Registers, and each one can be associated with a single I/O port. Ergo, you can trap a maximum of 4 ports at the same time. The EMM386 virtualization spec allows many more than 4 ports to be trapped at the same time. In addition, I think the code associated with the Debug Registers must be called in 32-bit protected mode, which isn't possible to do from "real" DOS (it requires a virtualized DOS environment).

 

Again, that's my understanding based on some literature I've seen, with no actual experience. I could be completely wrong. Anybody who knows better is welcome to either disagree or confirm this.

 

Re: Virtualize I/O In DOS Posted by jeffleyda on 6 Oct 2008 at 2:27 PM

Amazing stuff bret, thank you for sharing all this info. Having the ability to trap I/O in DOS could lead me to converting my ancient AC97 audio player into something that could do soundblaster emulation. Things could get really interesting from there. If only I had another lifetime of hours to spend working on such a thing.

---

I've used s-ice on a 486 and could have sworn that it can trap on I/O instructions, but it's been long enough that I don't recall the results. I've still got the 486 beasty set up in my basement, so I'll give that a shot in the near future and report back here just to clarify the thread.

 

Re: Virtualize I/O In DOS Posted by Bret on 6 Oct 2008 at 4:17 PM

: Amazing stuff bret, thank you for sharing all this info. Having the

: ability to trap I/O in DOS could lead me to converting my ancient

: AC97 audio player into something that could do soundblaster

: emulation. Things could get really interesting from there. If only

: I had another lifetime of hours to spend working on such a thing.

:

: ---

:

: I've used s-ice on a 486 and could have sworn that it can trap on

: I/O instructions, but it's been long enough that I don't recall the

: results. I've still got the 486 beasty set up in my basement, so

: I'll give that a shot in the near future and report back here just

: to clarify the thread.

 

Being able to virtualize I/O in DOS opens up all kinds of possibilities with Joysticks, Sound/MIDI, Serial, Parallel, Ethernet, etc., that is normally only possible with something like Windoze.  Too bad EMM386 doesn't allow ports below 100h to be trapped, or you could also do things with Keyboards and PS/2 Mice.   Like you said, it would be nice to have another lifetime's worth of hours to spend on this stuff.

 

 

 

 

另外,这里也有一些讨论:

http://www.mombu.com/programming/ms-dos/t-io-trap-with-emm386-api-717853.html

I/O trap with EMM386 API

-I/O port access receives special handling in a virtual 8086 mode, as

with EMM386 and other memory managers.  This is likely affecting your

program's behavior. Without the source, it is difficult to suggest an

appropriate modification.

 

 

-get it with sources here: http://hw.fdd5-25.net/temp/files/Gamma2.zip

). The other version is for EMM386 and it is not working. I can trap

I/O with EMM386 API 0x4A15 of INT 0x2F, but i need to do phisical

output to same port from within my I/O handler. According to

documentation from MSDN setting carry flag befor exiting from i/o

handler will make phisical i/o to port with same values that was

trapped, but i need output other values.

 

P.S. Sorry for my terrible english.

 

 

-Three possibilities, four if you consider the possibility of a bug in

your code.  First, your version of EMM386 or other memory manager may

not support that advanced API function -- the FreeDOS version does not,

for example.   Second, your version of EMM386 may have buggy support for

that API function -- at least one version of EMM386 is documented as

having problems with it under certain conditions, and other

less-documented problems with the API function are eminently plausible

given its inherent complexity.    Third, your modern machine may have

moved past the processor state assumptions made in the original memory

manager to the point of failure.   This situation occurs on occasion

when new machines meet old drivers and memory managers.

 

Frankly, if possible I would strongly consider discarding a

version-based approach and instead writing the code to go to protected

mode, thereby gaining control over its own I/O permission bitmap, etc.

This bypasses the undersupported and potentially faulty API call you

are using. A more complicated approach than a simple API call,

certainly, but given the situation, it may well be the best solution.

 

 

-Yes, but then my programm can't work with memory managers that switch

cpu in protected mode.

 

 

-It could. You can write a native VCPI application, which is supported

by probably all the older major memory managers, or detect V86 mode

and/or VCPI presence and switch or not as needed. Easiest might to

choose one of the many pre-existing free DOS extenders or one of the

couple of free DPMI hosts, which will handle most of the heavy lifting.

It's not absolutely trivial, since doing that would require learning

how to work with a extender/host version which allowed you the

low-level access you needed for port control. But it should be pretty

clean.

 

 

 

 

 

 

 

 

 

 

EMM386及V86模式

运行了 emm386.exe 后,DOS处于V86模式,在这个模式RDMSR 和 WRMSR等特殊指令是禁止使用的。 没运行emm386.exe。DOS处于实模式,这两条指令就没问题!

 

Also, EMM386 will provide VCPI memory and switch DOS into the protected and V86 mode automatically.

同样,EMM386将提供VCPI内存,并且自动将DOS切换到保护模式和V86模式.

 

80386处理器开机或者复位时,即进入实模式。

在实模式下,可寻址的内存空间为1MB,这是为了仿真8086实模式,只用了32位地址线中的低20位。

在实模式下,修改控制寄存器CR0中的PE位,使其置1,可进入保护模式。

而在保护模式下,若将CPU状态标志寄存器中的虚拟方式标志VM置1,可进入V86模式。

 

.继推出80386之后,Intel又推出了80386、Pentium和Pentium PRO。这些处理器都具有实模式保护模式两种工作方式。实模式与8086兼容,可以运行DOS及以其为平台的几乎所有软件;但在实模式下,处理器不能发挥自身的优越性能,不能支持多用户、多任务操作系统的运行。为了充分发挥处理器的功能,同时使DOS及以其为平台的软件继续有效地运行,从80386开始增加了虚拟8086模式

....1.V86模式

....虚拟8086模式是保护模式下的一种工作方式,也称为V8086模式,或者简称为V86模式。在虚拟8086模式下,处理器类似于8086。寻址的地址空间是1M字节;段寄存器的内容作为段值解释;20位存储单元地址由段值乘以16加偏移构成。在V86模式下,代码段总是可写的,这与实模式相同,同理,数据段也是可执行的,只不过可能会发生异常。所以,在虚拟8086模式下,可以运行DOS及以其为平台的软件。但V86模式毕竟是虚拟8086的一种方式,所以不完全等同于8086。

当标志寄存器中的VM位为1时,处理器就处于V86模式。此时,其当前特权级由处理器自动设置为3。

....2.V86任务

....8086程序可以直接在V86模式下运行,而V86模式受到称为V86监控程序的控制。V86监控程序和在V86模式下的8086程序构成的任务称为虚拟8086任务,或者简称为V86任务。

V86任务形成一个由处理器硬件和属于系统软件的监控程序组成的“虚拟8086机”。V86监控程序控制V86外部界面、中断和I/O。硬件提供该任务最低端1M字节线性地址空间的虚拟存储空间,包含虚拟寄存器的TSS,并执行处理这些寄存器和地址空间的指令。

....80386把V86任务作为与其它任务具有同等地位的一个任务。它可以支持多个V86任务,每个V86任务是相对独立的。所以,通过V86模式这种形式,运行8086程序可充分发挥处理器的能力和充分利用系统资源。

....3.进入和离开V86模式

....保护模式和V86模式之间的切换情形如下图所示。图中左面部分为V86任务。从图中可见,V86模式与保护模式的切换可发生在V86任务之内,这种切换是V86模式下的8086程序与保护模式下的监控程序之间的转换;

V86模式与保护模式的切换可发生在任务之间,这种切换是V86任务与其它任务的切换。此外,V86监控程序与其它任务之间的切换是普通的任务切换。

 

(我注:EMM386使DOS进入V86模式了,这样就可以捕获I/O端口的访问了。另外,EMM386相当于V86监控程序。)

 

 

 

 

中断大全中,关于QEMM386的信息:

INT 67 U - QEMM-386 v4.23+ - INSTALLATION CHECK

       AH = 3Fh

       CX = 5145h ("QE")

       DX = 4D4Dh ("MM")

Return: AH = 00h if installed

           ES:DI -> QEMM API entry point

 

Call QEMM entry point with:

       AX = 1009h switch to protected mode

              ESI = linear address in first megabyte of system reg values

                     (see INT 67/AX=DE0Ch)

              interrupts disabled

              Return: interrupts disabled

                     GDTR, IDTR, LDTR, TR loaded

                     SS:ESP must have at least 16 bytes space, and the

                            entry point is required to set up a new stack

                            before enabling interrupts

                     EAX, ESI, DS, ES, FS, GS destroyed

       AX = 100Ah switch back to virtual-86 mode

              DS = selector for data segment from function 1000h

              SS:ESP in first megabyte of linear memory

              interrupts disabled

              STACK: QWORD  return address from FAR call to 32-bit segment

                     DWORD  EIP

                     DWORD  CS

                     DWORD  reserved for EFLAGS

                     DWORD  ESP

                     DWORD  SS

                     DWORD  ES

                     DWORD  DS

                     DWORD  FS

                     DWORD  GS

              will switch to virtual86 mode with interrupts disabled, all

                segment registers loaded, and EAX destroyed.

 

 

 

 

 

 

 

另外,这里有关于RM386的信息:

http://hdebruijn.soo.dto.tudelft.nl/newpage/interupt/out-7300.htm

 

Int 67/AX=5DEAh

RM386 - V86-MODE I/O PORT TRAPPING CONTROL

AX = 5DEAh
BX = function
00h globally disable V86-mode trapping
01h globally enable V86-mode trapping
CL = interrupt to use for trapping
02h get I/O trapping state
 

Return:

AH = status

00h successful

BX = current trapping state (function 02h)

0000h disabled, 0001h enabled

CX = interrupt used as trap interrupt (functions 00h and 02h)

Notes: RM386 traps this function on the initial transition to protected mode caused by the INT instruction, which means it can not be overridden simply by hooking the interrupt. When I/O trapping is enabled and I/O port access occurs, RM386 simulates an INT instruction for the specified interrupt; the interrupt handler is responsible for decoding the trapped instruction and performing the appropriate action. INT 2C/AX=002Dh provides a similar but more-easily used interface.

See Also: AX=5DEBh - AH=EFh"RM386" - INT 2C/AX=002Dh

Category: Memory Management - Int 67h - R


Int 67/AX=5DEBh

RM386 - V86-MODE I/O TRAPPING PORT CONTROL

AX = 5DEBh
BX = function
00h disable V86-mode trapping for specified port
01h enable V86-mode trapping for specified port
02h get V86-mode trapping state for specified port
DX = port for which to enable/disable/query trapping
 

Return:

AH = status

00h successful

BX = current trapping state (00h off, 01h on) (function 02)

A7h invalid port ID

A8h reserved port--cannot trap/untrap (DMA/INT/KBD controllers)

Notes: RM386 traps this function on the initial transition to protected mode caused by the INT instruction, which means it can not be overridden simply by hooking the interrupt

See Also: AX=5DEAh

Category: Memory Management - Int 67h - R

 

 

 

 

 

 

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
9
关闭 站长推荐上一条 /3 下一条