[英]Assembly 16-bit interrupts
; another attempt to terminate program with Esc that hooks
; keyboard interrupt
[org 0x100]
jmp start
oldisr: dd 0 ; space for saving old isr
; keyboard interrupt service routine
kbisr: push ax
push es
mov ax, 0xb800
mov es, ax ; point es to video memory
in al, 0x60 ; read a char from keyboard port
cmp al, 0x2a ; is the key left shift
jne nextcmp ; no, try next comparison
mov byte [es:0], 'L' ; yes, print L at top left
jmp nomatch ; leave interrupt routine
nextcmp: cmp al, 0x36 ; is the key right shift
jne nomatch ; no, leave interrupt routine
mov byte [es:0], 'R' ; yes, print R at top left
nomatch: ; mov al, 0x20
; out 0x20, al
pop es
pop ax
jmp far [cs:oldisr] ; call the original ISR
; iret
start: xor ax, ax
mov es, ax ; point es to IVT base
mov ax, [es:9*4]
mov [oldisr], ax ; save offset of old routine
mov ax, [es:9*4+2]
mov [oldisr+2], ax ; save segment of old routine
cli ; disable interrupts
mov word [es:9*4], kbisr ; store offset at n*4
mov [es:9*4+2], cs ; store segment at n*4+2
sti ; enable interrupts
l1: mov ah, 0 ; service 0 – get keystroke
int 0x16 ; call BIOS keyboard service
cmp al, 27 ; is the Esc key pressed
jne l1 ; if no, check for next key
mov ax, 0x4c00 ; terminate program
int 0x21
I'm wonder that why we can only use cs:offset for the purpose to call oldIsr in this program. 我想知道为什么我们只能使用cs:offset来调用这个程序中的oldIsr。 Why just CS ???
为什么只是CS ???
AT THIS LINE 在这条线上
jmp far [cs:oldisr] ; call the original ISR
WHAT is the purpose behind the it? 这背后的目的是什么? Please explain it!!!
请解释一下!!!
Inside 16b real mode interrupt handler code you don't know the values of segment registers, they can be anything. 在16b实模式中断处理程序代码中你不知道段寄存器的值,它们可以是任何东西。 Usually you can expect at least stack (
ss:sp
) to be reasonably valid and large enough to store return address and few bytes for handler, and also cs
is fixed to the handler code, because in case of different cs
value the CPU would execute some different instructions, not yours. 通常你可以期望至少stack(
ss:sp
)合理有效并且足够大以存储返回地址和少量字节用于处理程序,并且cs
也固定到处理程序代码,因为在cs
值不同的情况下CPU将执行一些不同的指示,而不是你的。
So to avoid hassle of storing old/unknown ds
, setting up data segment of handler variables, and accessing them through ds:
prefixes, then restoring ds
back, it is easier to have the variable next to the code itself, and address it by cs:oldisr
, as the value of cs
is known to be what you need. 因此,为了避免存储旧的/未知的
ds
,设置处理程序变量的数据段,并通过ds:
前缀访问它们,然后将ds
还原,更容易将变量放在代码本身旁边,并通过cs:oldisr
解决它cs:oldisr
,因为cs
的值已知是你需要的。
I will try to write it in more simple way: 我将尝试以更简单的方式编写它:
mov ax,[si]
is by default using ds
(*1), ie it is actually doing mov ax,[ds:si]
. mov ax,[si]
默认使用ds
(* 1),即它实际上是做mov ax,[ds:si]
。
You can override the default by writing the segment register explicitly like mov ax,[cs:si]
. 您可以通过显式写入段寄存器来覆盖默认值,如
mov ax,[cs:si]
。
Physical memory address in 16b real mode is: segment_value*16+offset_value 16b实模式下的物理内存地址为:segment_value * 16 + offset_value
When the code does enter your ISR handler, you do NOT know, what the running code had in ds
or es
at the moment of interrupt. 当代码进入你的ISR处理程序时,你不知道在中断时
ds
/ es
中正在运行的代码是什么。 It may point anywhere in the memory (NOT to your variables!). 它可能指向内存中的任何位置(而不是你的变量!)。
But you know, that cs
points to your handler instructions (otherwise CPU would execute instructions elsewhere, because CPU does execute next instruction from memory at cs:ip
). 但是你知道,
cs
指向你的处理程序指令(否则CPU会在别处执行指令,因为CPU确实在cs:ip
执行来自内存的下一条指令)。
Just look how your handler has to preserve/set/restore es
, that's example what you would have to do with ds
, to be able to use the ds
. 只需看看你的处理程序如何保存/设置/恢复
es
,这就是你必须使用ds
做的一个例子,以便能够使用ds
。
The cs
is already preserved on stack, set to your code segment, and IRET
(in old handler) will restore it. cs
已经保存在堆栈中,设置为您的代码段,而IRET
(在旧处理程序中)将恢复它。
1) The bp
is using by default ss
, the stos/movs/cmps
are using by default both ds
and es
, and only the source ds
can be overridden, the es
for target is fixed. 1)
bp
默认使用ss
, stos/movs/cmps
默认使用ds
和es
,只有源ds
可以被覆盖,目标的es
是固定的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.