mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-27 10:30:44 +02:00
removed
This commit is contained in:
parent
02b01b04be
commit
ac1563bb64
@ -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.
|
@ -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.
|
@ -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.
|
Loading…
Reference in New Issue
Block a user