This commit is contained in:
michael 1999-06-04 19:22:35 +00:00
parent 02b01b04be
commit ac1563bb64
3 changed files with 0 additions and 319 deletions

View File

@ -1,72 +0,0 @@
{ example for :
set_pm_interrupt()
get_pm_interrupt()
Interrupt redirection
Software interrupt
tseginfo record
get_cs()
}
{ This example shows how to redirect a software interrupt by changing the
protected mode handler of the DPMI host.
In more detail it hooks interrupt 1Ch which is called every time the timer
interrupt (int 08) is executed. This is the preferred way to hook the timer,
because int 1Ch is a software interrupt which doesn't need so much
initialization stuff compared to hooking a hardware interrupt.
}
uses crt, { wherey(), keypressed() }
go32;
const int1c = $1c; { interrupt number we want to hook }
var oldint1c : tseginfo; { 48 bit pointer to old interrupt handler }
newint1c : tseginfo; { 48 bit pointer to new interrupt handler }
int1c_counter : Longint; { increased every time the interrupt is called }
{$ASMMODE DIRECT}
{ the actual handler code }
procedure int1c_handler; assembler;
asm
cli
{ save all registers }
pushw %ds
pushw %ax
{ prepare segment registers for FPC procedure }
movw %cs:INT1C_DS, %ax
movw %ax, %ds
{ simply increase the counter by one }
incl _INT1C_COUNTER
{ restore registers }
popw %ax
popw %ds
sti
iret
INT1C_DS: .word 0
end;
var i : Longint;
begin
{ insert right handler data into new handler variable }
newint1c.offset := @int1c_handler;
newint1c.segment := get_cs;
{ get the old handler }
get_pm_interrupt(int1c, oldint1c);
{ store necessary data into the handler }
asm
movw %ds, %ax
movw %ax, INT1C_DS
end;
Writeln('-- Press any key to exit --');
{ set new handler }
set_pm_interrupt(int1c, newint1c);
{ write the number of interrupts occured }
while (not keypressed) do begin
gotoxy(1, wherey); write('Number of interrupts occured : ', int1c_counter);
end;
{ restore old handler }
set_pm_interrupt(int1c, oldint1c);
end.

View File

@ -1,120 +0,0 @@
{ example for :
interrupt redirection
software vs. hardware interrupts
set_pm_interrupt()
get_pm_interrupt()
get_cs()
tseginfo
trealregs
processor access
get_cs(), get_ds(), get_ss()
}
{ This example shows the difference between protected and real mode
interrupts; it redirects the protected mode handler to an own handler which
returns an impossible function result and calls it afterwards. Then the real
mode handler is called directly, to show the difference between the two.
Used Interrupt:
get DOS version Int 21h / function 30h
Input: AH = $30
AL = $1
Return: AL = major version number
AH = minor version number
}
uses crt, { used for clreol(), gotoxy() }
go32;
{$ASMMODE DIRECT}
var r : trealregs;
axreg : Word; { temporary variable used for the protected mode int call }
oldint21h : tseginfo;
newint21h : tseginfo;
{ this is our int 21h protected mode interupt handler. It catches the function
call to get the DOS version, all other int 21h calls are redirected to the
old handler; it is written in assembly because the old handler can't be
called with pascal }
procedure int21h_handler; assembler;
asm
cmpw $0x3001, %ax
jne CallOld
movw $0x3112, %ax
iret
CallOld:
ljmp %cs:OLDHANDLER
OLDHANDLER: .long 0
.word 0
end;
{ a small helper procedure, which waits for a keypress }
procedure resume;
begin
Writeln;
Write('-- press any key to resume --'); readkey;
gotoxy(1, wherey); clreol;
end;
begin
{ see the text messages for further detail }
clrscr;
Writeln('Executing real mode interrupt');
resume;
r.ah := $30; r.al := $01; realintr($21, r);
Writeln('DOS v', r.al,'.',r.ah, ' detected');
resume;
Writeln('Executing protected mode interrupt without our own handler');
Writeln;
asm
movb $0x30, %ah
movb $0x01, %al
int $0x21
movw %ax, _AXREG
end;
Writeln('DOS v', r.al,'.',r.ah, ' detected');
resume;
Writeln('As you can see the DPMI hosts default protected mode handler');
Writeln('simply redirects it to the real mode handler');
resume;
Writeln('Now exchanging the protected mode interrupt with our own handler');
resume;
newint21h.offset := @int21h_handler;
newint21h.segment := get_cs;
get_pm_interrupt($21, oldint21h);
{ storing old handler address in interrupt handler }
asm
movl _OLDINT21H, %eax
movl %eax, OLDHANDLER
movw 4+_OLDINT21H, %ax
movw %ax, 4+OLDHANDLER
end;
set_pm_interrupt($21, newint21h);
Writeln('Executing real mode interrupt again');
resume;
r.ah := $30; r.al := $01; realintr($21, r);
Writeln('DOS v', r.al,'.',r.ah, ' detected');
Writeln;
Writeln('See, it didn''t change in any way.');
resume;
Writeln('Now calling protected mode interrupt');
resume;
asm
movb $0x30, %ah
movb $0x01, %al
int $0x21
movw %ax, _AXREG
end;
Writeln('DOS v', lo(axreg),'.',hi(axreg), ' detected');
Writeln;
Writeln('Now you can see that there''s a distinction between the two ways of ');
Writeln('calling interrupts...');
set_pm_interrupt($21, oldint21h);
end.

View File

@ -1,127 +0,0 @@
{ example for :
Selectors and descriptors
DOS memory access
allocate_ldt_descriptors()
free_ldt_descriptors()
get_segment_base_address()
set_segment_base_address()
get_segment_limit()
set_segment_limit()
seg_move()
seg_fillword()
}
{ This example demonstrates the usage of descriptors and the effects of
changing its limit and base address.
In more detail, the program fills the region described by an allocated
descriptor in text screen memory with various characters.
Before doing this it saves the entire screen contents to the heap and
restores it afterwards.
Some additional background:
The text screen of a VGA card has it's address space at $B800:0; screen
memory is organized in a linear fashion, e.g. the second line comes
directly after the first, where each cell occupies 2 bytes of memory
(1 byte character data, 1 byte attributes). It is 32 kb in size.
Hence the offset of a single memory cell from its origin is:
Y * columns * 2 + X * 2
where X and Y mark the point and columns is the number of character cells
per line
}
uses crt, { color constants, clreol(), gotoxy(), wherex(), wherey() }
go32;
const maxx = 80; { screen x and y dimensions }
maxy = 25;
bytespercell = 2; { bytes used for every character cell }
screensize = maxx * maxy * bytespercell; { screen size in bytes }
linB8000 = $B800 * 16; { the linear address of $B800:0 }
type string80 = string[80];
var
text_save : array[0..screensize-1] of byte; { holds the old screen contents }
text_oldx, text_oldy : Word; { old cursor x and y coordinates }
text_sel : Word; { selector to the text mode screen }
{ prints a status message on the first line of the screen and then waits for
a keypress }
procedure status(s : string80);
begin
gotoxy(1, 1); clreol; write(s); readkey;
end;
{ writes some descriptor info on the last 2 lines }
procedure selinfo(sel : Word);
begin
gotoxy(1, 24);
clreol; writeln('Descriptor base address : $', hexstr(get_segment_base_address(sel), 8));
clreol; write('Descriptor limit : ', get_segment_limit(sel));
end;
{ returns a 2 byte character cell, which includes character data and its
color attributes }
function makechar(ch : char; color : byte) : Word;
begin
result := byte(ch) or (color shl 8);
end;
begin
{ save original screen contents to variable, this time by using seg_move()
and the dosmemselector variable }
seg_move(dosmemselector, linB8000, get_ds, longint(@text_save), screensize);
{ additionally we have to save the old screen cursor coordinates }
text_oldx := wherex; text_oldy := wherey;
{ clear the whole screen }
seg_fillword(dosmemselector, linB8000, screensize div 2, makechar(' ', Black or (Black shl 4)));
{ output message }
status('Creating selector ''text_sel'' to a part of text screen memory');
{ allocate descriptor }
text_sel := allocate_ldt_descriptors(1);
{ set its base address to the linear address of the text screen + the
byte size of one line (=maxx * bytespercell * 1) }
set_segment_base_address(text_sel, linB8000 + bytespercell * maxx * 1);
{ the limit is set to the screensize reduced by one (a must be) and the
number of lines we don't want to have touched (first line + lower 2 lines) }
set_segment_limit(text_sel, screensize - 1 - bytespercell * maxx * 3);
{ write descriptor info }
selinfo(text_sel);
status('and clearing entire memory selected by ''text_sel'' descriptor');
{ fill the entire selected memory with single characters }
seg_fillword(text_sel, 0, (get_segment_limit(text_sel)+1) div 2, makechar(' ', LightBlue shl 4));
status('Notice that only the memory described by the descriptor changed, nothing else');
status('Now reducing it''s limit and base and setting it''s described memory');
{ set the base address of the descriptor (increase it by the byte size of one line) }
set_segment_base_address(text_sel, get_segment_base_address(text_sel) + bytespercell * maxx);
{ decrease the limit by byte size of 2 lines (1 line because base address changed,
one line on the lower end) }
set_segment_limit(text_sel, get_segment_limit(text_sel) - bytespercell * maxx * 2);
{ write descriptor info }
selinfo(text_sel);
status('Notice that the base addr increased by one line but the limit decreased by 2 lines');
status('This should give you the hint that the limit is relative to the base');
{ fill the descriptor area }
seg_fillword(text_sel, 0, (get_segment_limit(text_sel)+1) div 2, makechar(#176, LightMagenta or Brown shl 4));
status('Now let''s get crazy and copy 10 lines of data from the previously saved screen');
{ copy memory from the data segment to screen }
seg_move(get_ds, longint(@text_save), text_sel, maxx * bytespercell * 2, maxx * bytespercell * 10);
status('At last freeing the descriptor and restoring the old screen contents..');
status('I hope this little program may give you some hints on working with descriptors');
{ free the descriptor so that it can be used for things }
free_ldt_descriptor(text_sel);
{ restore old state }
seg_move(get_ds, longint(@text_save), dosmemselector, linB8000, screensize);
gotoxy(text_oldx, text_oldy);
end.