animation gets halted due to interrupt call in assembly - animation

in assembly, i am trying to do a animation. In the below code, move_object animates an object, while move_arrow animates another object. however, the problem is both uses the same timer function ( which i actually didn't understand how works, I just copied it from a source.) both runs finely in norma case. but what i want to do is that the object will keep animating from the start but the arrow will wait for user to press a specific key. when user presses that key, then the arrow will start. but whenever i call the interrupt function for keyboard press (MOV AH,0 INT 16H) the program gets halted there and waits for the user to press a key. but i want to have the previous to object to still move in that time. but no matter however i write the code it seems like the code gets halted in that line and no other lines get executed. below is the fragment of my code.
; dont know how it works , just know that it works as a timer :D
TIMER_TICK PROC
PUSH DS ; SAVE DS
PUSH AX
MOV AX,SEG TIMER_FLAG ; GET SEGMENT OF FLAG
MOV DS,AX ; PUT IN DS
MOV TIMER_FLAG,1 ; SET FLAG
; RESTORE REGISTER
POP AX
POP DS
IRET ; IT IS DIFFERENT FROM "RET". IF WE USE "IRET" THEN
; IF WILL REMAIN 1 WHICH MEANS IT CAN BE INTERRUPT AGAIN
TIMER_TICK ENDP
;; other codes
;WAIT FOR TIMER TICK BEFORE MOVING THE OBJECT
TT:
CMP TIMER_FLAG,1 ; TIMER TICKED?
JNE TT ; NO , KEEP TESTING
MOV TIMER_FLAG,0 ; YES, CLEAR FLAG
CMP LAP,1 ; CHECKS IF ARROW HAVE FINISHED CROSSING
JE GAME
CALL MOVE_OBJECT ;animates the object to a new position
CMP KEY,0
JNE CONT
MOV AH,0
INT 16H ;**whole program gets halted here untill user presses a key**
OR AL,AL
JNE EXIT
CMP AH,3BH
JNE GAME
MOV KEY,1
CONT:
; CHECK FOR KEYBOARD
CALL MOVE_ARROW ;animates the object in a new position
; DELAY 1 TIMER CLICK
TT2:
CMP TIMER_FLAG,1 ; TIMER TICKED?
JNE TT2 ; NO , KEEP TESTING
MOV TIMER_FLAG,0 ; YES , CLEAR FLAG
JMP TT ; GO GET NEXT OBJECT POSITION
;; other codes

The BIOS function you're using does indeed halt until a key is available from the keyboard. It's meant to work like that.
Consider using function 1 instead. That one will return immediately and report through the zero flag ZF if a key is waiting. So if ZF=1 you would probably jump back to TT.
mov ah,1
int 16h
jz TT
mov ah,0
int 16h

Use the function ah=1 in int 16h. If a key was pressed until the moment, when the function ah=1 was called, the ZF is set and AX contains the values that would be set, if you had used ah=0. Otherwise, if no key had been pressed, the ZF is not set and AX won't contain a useful value. Notice: If you use the function ah=1, you have to use function ah=0 if a key had been pressed, cause the keybuffer wouldn't be changed otherwise.

Related

Cannot modify data segment register. When tried General Protection Error is thrown

I have been trying to create an ISR handler following this
tutorial by James Molloy but I got stuck. Whenever I throw a software interrupt, general purpose registers and the data segment register is pushed onto the stack with the variables automatically pushed by the CPU. Then the data segment is changed to the value of 0x10 (Kernel Data Segment Descriptor) so the privilege levels are changed. Then after the handler returns those values are poped. But whenever the value in ds is changed a GPE is thrown with the error code 0x2544 and after a few seconds the VM restarts. (linker and compiler i386-elf-gcc , assembler nasm)
I tried placing hlt instructions in between instructions to locate which instruction was throwing the GPE. After that I was able to find out that the the `mov ds,ax' instruction. I tried various things like removing the stack which was initialized by the bootstrap code to deleting the privilege changing parts of the code. The only way I can return from the common stub is to remove the parts of my code which change the privilege levels but as I want to move towards user mode I still want them to stay.
Here is my common stub:
isr_common_stub:
pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
xor eax,eax
mov ax, ds ; Lower 16-bits of eax = ds.
push eax ; save the data segment descriptor
mov ax, 0x10 ; load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
call isr_handler
xor eax,eax
pop eax
mov ds, ax ; This is the instruction everything fails;
mov es, ax
mov fs, ax
mov gs, ax
popa
iret
My ISR handler macros:
extern isr_handler
%macro ISR_NOERRCODE 1
global isr%1 ; %1 accesses the first parameter.
isr%1:
cli
push byte 0
push %1
jmp isr_common_stub
%endmacro
%macro ISR_ERRCODE 1
global isr%1
isr%1:
cli
push byte %1
jmp isr_common_stub
%endmacro
ISR_NOERRCODE 0
ISR_NOERRCODE 1
ISR_NOERRCODE 2
ISR_NOERRCODE 3
...
My C handler which results in "Received interrupt: 0xD err. code 0x2544"
#include <stdio.h>
#include <isr.h>
#include <tty.h>
void isr_handler(registers_t regs) {
printf("ds: %x \n" ,regs.ds);
printf("Received interrupt: %x with err. code: %x \n", regs.int_no, regs.err_code);
}
And my main function:
void kmain(struct multiboot *mboot_ptr) {
descinit(); // Sets up IDT and GDT
ttyinit(TTY0); // Sets up the VGA Framebuffer
asm volatile ("int $0x1"); // Triggers a software interrupt
printf("Wow"); // After that its supposed to print this
}
As you can see the code was supposed to output,
ds: 0x10
Received interrupt: 0x1 with err. code: 0
but results in,
...
ds: 0x10
Received interrupt: 0xD with err. code: 0x2544
ds: 0x10
Received interrupt: 0xD with err. code: 0x2544
...
Which goes on until the VM restarts itself.
What am I doing wrong?
The code isn't complete but I'm going to guess what you are seeing is a result of a well known bug in James Molloy's OSDev tutorial. The OSDev community has compiled a list of known bugs in an errata list. I recommend reviewing and fixing all the bugs mentioned there. Specifically in this case I believe the bug that is causing problems is this one:
Problem: Interrupt handlers corrupt interrupted state
This article previously told you to know the ABI. If you do you will
see a huge problem in the interrupt.s suggested by the tutorial: It
breaks the ABI for structure passing! It creates an instance of the
struct registers on the stack and then passes it by value to the
isr_handler function and then assumes the structure is intact
afterwards. However, the function parameters on the stack belongs to
the function and it is allowed to trash these values as it sees fit
(if you need to know whether the compiler actually does this, you are
thinking the wrong way, but it actually does). There are two ways
around this. The most practical method is to pass the structure as a
pointer instead, which allows you to explicitly edit the register
state when needed - very useful for system calls, without having the
compiler randomly doing it for you. The compiler can still edit the
pointer on the stack when it's not specifically needed. The second
option is to make another copy the structure and pass that
The problem is that the 32-bit System V ABI doesn't guarantee that data passed by value will be unmodified on the stack! The compiler is free to reuse that memory for whatever purposes it chooses. The compiler probably generated code that trashed the area on the stack where DS is stored. When DS was set with the bogus value it crashed. What you should be doing is passing by reference rather than value. I'd recommend these code changes in the assembly code:
irq_common_stub:
pusha
mov ax, ds
push eax
mov ax, 0x10 ;0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
push esp ; At this point ESP is a pointer to where GS (and the rest
; of the interrupt handler state resides)
; Push ESP as 1st parameter as it's a
; pointer to a registers_t
call irq_handler
pop ebx ; Remove the saved ESP on the stack. Efficient to just pop it
; into any register. You could have done: add esp, 4 as well
pop ebx
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
popa
add esp, 8
sti
iret
And then modify irq_handler to use registers_t *regs instead of registers_t regs :
void irq_handler(registers_t *regs) {
if (regs->int_no >= 40) port_byte_out(0xA0, 0x20);
port_byte_out(0x20, 0x20);
if (interrupt_handlers[regs->int_no] != 0) {
interrupt_handlers[regs->int_no](*regs);
}
else
{
klog("ISR: Unhandled IRQ%u!\n", regs->int_no);
}
}
I'd actually recommend each interrupt handler take a pointer to registers_t to avoid unnecessary copying. If your interrupt handlers and the interrupt_handlers array used function that took registers_t * as the parameter (instead of registers_t) then you'd modify the code:
interrupt_handlers[r->int_no](*regs);
to be:
interrupt_handlers[r->int_no](regs);
Important: You have to make these same type of changes for your ISR handlers as well. Both the IRQ and ISR handlers and associated code have this same problem.

Assembling some code out-of-line with nasm macros

Consider a nasm macro that is used to inject some assembly whenever it is called, in this case to test whether the passed argument is equal to 42:
%macro special_handler_if_42 1
cmp 42, %1
jne %%skip
; some additional assembly to handle the %1 == 42 case
push %1
push 42
call some_func
%%skip:
%endmacro
In the case it is equal we perform some additional action, otherwise we just continue with the code following the macro. So far, so good.
Now I want to write the macro in a way that's functionally identical, except that the "equals 42" case, which happens to be very rare, is moved "out of line", so that the fall-through (no jump) case is the default one, something like (not shown in macro form now):
cmp 42, rax
je equals_42
jump_back:
; the rest of the code that follows the macro
ret
; somewhere outside the current function
equals_42:
push rax
push 42
call some_func
jmp jump_back
This will be more efficient at execution time and also potentially conserve i-cache space. I'm not sure how to write a macro with a non-local effect like that. Ideas welcome.
If you don't mind splitting the macro into two macros, one performing the test and one handling the assertion, then you can use NASM's context stack.
I imagined a system of macros of the form assert_XXX that are all pretty similar and perform specific tests.
A single assertions_handler past the end of the function will generate any handler needed.
Since this system uses the context stack, you should be able to use it multiple times for different functions.
Basically, each assert_XXX function will push a context on the stack and the assertions_handler will consume them all.
assert_XXX will also define context local macros argX to pass its argument to the handler, so there is no need to hardcode anything.
BITS 64
%macro assert_not_equal 2
;Create and push a new context (The name is optional but goodpractice)
%push assert_equal_ctx
%define %$arg1 %1
%define %$arg2 %2
cmp %1, %2
je %$handler
%$jump_back:
%endmacro
%macro assert_greater 2
%push assert_greater_ctx
%define %$arg1 %1
%define %$arg2 %2
cmp %1, %2
jbe %$handler
%$jump_back:
%endmacro
%macro assertions_handler 0
%rep 1000
%ifctx assert_equal_ctx
%$handler:
push %$arg1
push %$arg2
call somefunc
jmp %$jump_back
%pop assert_equal_ctx
%elifctx assert_greater_ctx
%$handler:
push %$arg1
push %$arg2
call somefunc2
%pop assert_greater_ctx
%else
%exitrep
%endif
%endrep
%endmacro
;
;TEST TEST TEST TEST TEST TEST TEST TEST
;
assert_not_equal rax, 5
nop
nop
nop
assert_greater rax, 8
nop
nop
nop
ret
assertions_handler
;
; Handler functions
;
somefunc:
ret
somefunc2:
ret
The maximum number of assertions per function is set to 1000, you can increment it up to 262.

How to properly use PUSH and POP

I have a code that has 3 procedures, one to get an input from the user, one to display a multiplication result, and lastly one for an error message. I am trying to implement the PUSH and POP operations and get my code in to the stack. It will seem long but it makes sense to me, here it is...
.data
line BYTE "The answer is ",0
line2 BYTE "Enter a number",0
kline3 BYTE Wrong.",0
int SWORD ?
.code
Val PROC
call ReadInt
mov int,edx
cmp int, 10000
jl 1
jmp end
L1: cmp intVal1, -10000
jg 2
call error
jmp end
2: ret
Val ENDP
main PROC
call Val
call Val
imul val, val
exit
main ENDP
END main
All this simply does it call to get 2 inputs twice and then call to display the the multiplied result. My question is how do you implement push and pop in to here to have it all make sense?
I would assume that you need to push in the GetValue procedure to put in input in to the stack and then pop it after each call in the main procedure and maybe do the same with the display procedure?
I am just struggling to figure it out so any help would be great!
PS. This code is an asm file in visual studio 2010
Your first call to GetValue stores its result in intVal. But then your second call to GetValue also stores its result in intVal, so the first result is forever lost.
Your MultiplyAndDisplay function expects one of the operands in intVal, and the other operand in eax. So, what you need to do is push [intVal] after the first call to GetValue, and pop eax after the second call to GetValue.
Note that the square brackets in push [intVal] are in some notation that actually makes sense, but if I remember correctly the microsoft assembler does not support that notation which actually makes sense, so you might have to code push intVal instead, or push dword ptr intVal, or something nonsensical like that to get it to work.
Because your question is tagged MASM, this is a MASM answer:
Your code can be restructured in a way that uses the MASM directive PROC with parameters and the INVOKE directive for parameter passing:
MultiplyAndDisplay PROC val1: SDWORD, val2: SDWORD
mov eax, val1
imul eax, val2 ; signed multiply of val1 by val2
mov edx, OFFSET prompt
call WriteString ; Writes the prompt in edx
call WriteDec ; Writes the value in eax
ret
MultiplyAndDisplay ENDP
main PROC
call GetValue
push [intVal] ; PUSH firstParam to the stack
call GetValue
pop eax ; POP previous param/intVal to EAX
invoke MultiplyAndDisplay, eax, intVal ; MultiplyAndDisplay, firstParam(EAX), secondParam(intVal)
exit
main ENDP

Prevent winapi from accumulating the key pressed

I am programming a WinApi in assembly language in which the program reacts to keypress, problem is, if the routine is not completed and the key is pressed in meantime again, it starts accumulate, which means once the routine gets finished, it goes again and again given the times user pressed the key while the routine was in progress.
Classic message loop:
.MessageLoop:
invoke PeekMessage,Message,NULL,0,0,PM_REMOVE
test eax,eax
jz near .NoMess
cmp dword [Message + MSG.message],WM_QUIT
jz near .Finish
invoke TranslateMessage,Message
invoke DispatchMessage,Message
.NoMess:
; some code
jmp .MessageLoop
And handle for messages:
function WndProc,hWnd,wMsg,wParam,lParam
begin
mov eax,dword [wMsg]
cmp eax,WM_DESTROY
je near .Destroy
cmp eax,WM_CLOSE
je near .Destroy
cmp eax, WM_KEYDOWN
je near .keyDown ; when key is pressed, then it is checked what key it is, meanwhile I need program to ignore all keypressed
cmp eax, WM_PAINT
je near .Paint
invoke DefWindowProc,[hWnd],[wMsg],[wParam],[lParam]
return eax
Let's say I have routine to handle W button, in proccess of the routine I want all other W keys to be ignored.

Assembly - Moving data from Register to Memory in MASM

I am trying to move stuff from a register to a variable in .CODE, but trying to do so makes my program start over in an infinite loop (no crash and no error message, but obviously broken). I don't understand what I'm doing wrong. Here is the beginning of my code where I am trying to move data; the program never even gets past this part when I include it:
.CODE
screenX DWORD 0
screenY DWORD 0
...
ProcName PROC
mov ebx, edx ;; Copy srcBitmap into ebx
mov eax, edi ;; Take given y-location (edi)
mov edx, (EECS205BITMAP PTR [ebx]).dwHeight
shr edx, 1 ;; Subtract dwHeight/2 to center
sub eax, edx
mov screenY, eax ;; Program jumps back to beginning with no error message
Seems like I'm missing something obvious, anyone have a clue?
Your application's code segment (which is actually it's .text section under Windows) isn't writable. If you want to modify these variables you need to put them in the data segment.

Resources