NASM Forum > Programming with NASM

Changing entry of Interrupt Vector Table

(1/2) > >>

patdes20:
Hi everyone, I am trying to change the entry at 0x000:0x0020 (Timer Interrupt) of the Interrupt Vector Table and replace it with an own interrupt handler that jumps to the old interrupt handler after it finishes. My method needs to be executed every 55ms. The program is in real mode and works without OS. Could anybody help me and give me some code examples? Thank you.  :)
With best regards, Patrick

fredericopissarra:

--- Code: ---; boot.asm - Legacy boot sector.
  bits  16
  cpu   386
 
  org   0x7c00

_start:
  ; Since CS is always zero at this point, just copy
  ; CS to DS and ES.
  mov   ax,cs
  mov   ds,ax
  mov   es,ax

  ; Disable interrupts.
  cli

  ; Change int 0x1c to new handler.
  ; if there is an old handler, store it.
  ;
  ; int 0x1c is called by irq8, which is adjusted to
  ; occur 18.2 times/sec (timer 0 is 18.2 Hz rate generator
  ; by default - roughly 55 ms).
  mov   eax,es:[0x1c*4]
  test  eax,eax
  jz    .no_old_handler
  mov   dword es:[oldint],eax
.no_old_handler:
  mov   word es:[0x1c*4],newint
  mov   word es:[0x1c*4+2],cs

  ; Re-enable interrupts
  sti

.loop:
  hlt
  jmp   .loop

; --- Our interrupt handler.
  align 2
newint:
  pushf
  push  ds
  push  ax
  push  bx
  push  si

  mov ax,cs
  mov ds,ax

  ; We'll print 'tick' on string each second (roughly).
  inc   byte [cnt]
  cmp   byte [cnt],18
  jne   .not_time_yet

  cld
  mov   byte [cnt],0
  mov   ax,cs
  mov   ds,ax
  lea   si,[msg]
  call  puts
.not_time_yet:
  pop   si
  pop   bx
  pop   ax
  pop   ds

  ; if there is an old handler, jump to it.
  ; Otherwise iret.
  cmp   dword cs:[oldint],0
  je    .retfromint
  popf
  jmp   far [cs:oldint]
.retfromint:
  popf
  iret

  align 2
puts:
  lodsb
  test  al,al
  je    .exit
  mov   bx,7
  mov   ah,0x0e
  int   0x10
  jmp   puts
.exit:
  ret

  align 4
oldint:
  dd  0
cnt:
  db  0
msg:
  db  `tick\r\n`,0

  times 510-($-$$) db 0
  dw    0xaa55
--- End code ---

--- Code: ---$ nasm -f bin boot.asm -o boot.bin
$ qemu-system-i386 -drive file=boot.bin,index=0,media=disk,format=raw
--- End code ---

debs3759:
My boot sector was written with the assumption that CS can be either 0000 or 07C0. I believe both are possible, so I use org 0, copy the boot sector and do a far jump to the copy, setting CS up how I want it. I'm pretty sure I did that based on research that showed you can't guarantee the values of CS:IP when the boot sector is first loaded.

debs3759:
It's also important to set up the stack at the start of a boot sector, to be safe on all systems.

The start of my boot sector has the following code:


--- Code: ---org 0
BootSector:
jmp short start ; There should always be 3 bytes of code
nop ; followed by the start of the data.

<insert BPD data here>
start:
push WORD stackseg ; set up the stack
pop SS
mov SP,stacksize ;

push WORD 07C0h
pop DS

push WORD moveseg ; where I move my boot sector to
pop ES

xor SI,SI ; Starting from bottom of each segment
xor DI,DI

mov CX,100h ; 256 words to be transferred
cld
rep movsw ; Move the code

;-----------------------------------------------------------------------+
;  Now we jump to the next instruction in the copy of the code +
;-----------------------------------------------------------------------+

jmp moveseg:next ; CS is now set to moveseg
next:

--- End code ---

That way I make no assumptions about the initial values of any segment register, and I don't do anything (other than a short jump over the BPD) before executing any other code.

debs3759:
See https://wiki.osdev.org/Boot_Sequence for confirmation that the boot sector could be loaded at either 0:07C00 or 07C0:0000

Navigation

[0] Message Index

[#] Next page

Go to full version