0
votes

I'm using QTCreator 3.5.1 and a virtual OS which is Linux Mint 18.3 Cinnamon 32-bit, GCC Compiler.

I have to write a code that uses interruptions, obtaining a key pressed on the keyboard using assembly commands.

The code that should've been working on windows is like this:

#include <iostream>
unsigned char x;
int main()
{
 do {
 __asm {
 mov ah, 00h
 int 16h
 mov x, ah
 };
 std::cout <<"The pressed key code is "<< x << std::endl;
 } while (true);
}

Although it doesn't work on either Windows 98, compiled using Visual Studio 2003 on Windows 7x32, and any other Windows systems, giving me a runtime error or shutting my system down (on Windows 98).

So I switched to Linux and the following assembly example code from http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html (part 7) is working pretty much fine :

#include <iostream>
using std::cout;
int main(void)
{
        int foo = 10, bar = 15;
        __asm__ __volatile__("addl  %%ebx,%%eax"
                             :"=a"(foo)
                             :"a"(foo), "b"(bar)
                             );
        printf("foo+bar=%d\n", foo);
        return 0;
}

(For it to work properly I also had to specify the compiler version (GCC x86 32bit in usr/bin) on "Desktop Kit" in QT Creator Tool->Options and a working QT version which is 4.8.7, the last version 5.5.1 giving me a "non properly installed, please run make install" error)

Although I struggle to understand the concept of interruptions and how should the "int 16h" interruption work on linux with GCC inline assembly, what is the syntax and how I can obtain any pressed keyboard key code?

2
As you're working with Qt (apparently), wouldn't it be more appropriate to use something like this, rather trying to capture keyboard events at bios level (which is unlikely to be configured at the same interrupt in different operating systems).πάντα ῥεῖ
int 16h is a BIOS service. It only works in real mode and is usually used in boot loaders or DOS programs. It cannot be accessed from neither Windows (any version, unless executing a DOS program in which case the service is emulated) or Linux (any version) or any other protected mode operating system for that matter.fuz
Does the exercise specify that you have to use int 16h? What other details are given? You can read input using inline assembly on Linux (though I would not recommend doing so outside of an academic exercise). On Windows, this too is possible but the correct call depends on the Windows version.fuz
@fuz, yes. This is the problem, my academic exercise does specify that I have to use int 16hIvan Silkin
@IvanSilkin Try coaxing Visual Studio into generating a Win16 or DOS application.fuz

2 Answers

3
votes

The service int 16h is a BIOS service. It only works in real mode and is usually used in boot loaders or DOS programs. It cannot be accessed from neither Windows (any version, unless executing a DOS program in which case the service is emulated) or Linux (any version) or any other protected mode operating system for that matter.

According to the folks on #winapi at Freenode, it might have been possible to call int 16h from a Win32 program on Windows 98, but the call might then produce a hang in the BIOS. Anyway, this is not useful for achieving your goal.

To solve your problem, either write a DOS program using a DOS toolchain such as ia16-gcc, Open Watcom, or an old version of MSVC, or use a protected mode service supported by the operating system you are programming for.

3
votes

For modern systems; during boot the OS takes control of all hardware from the firmware, and after that point the firmware is unusable (because none of the hardware can be assumed to be in a state that the firmware expects). Then the OS starts its own drivers that are designed for the OS, and use IRQs and work with the operating systems scheduler (and don't waste CPU time polling), and work for multi-CPU, and support memory properly (and aren't restricted to 640 KiB).

This means that the BIOS interrupt "int 0x16" can only work if either:

a) You're using an OS that became irrelevant 20+ years ago (MS-DOS)

b) You're using an OS that does a lot of extra work to emulate an OS that became irrelevant 20+ years ago (e.g. "legacy DOS compatibility" built into Windows95, and not any Windows executable intended for Windows).

c) You're not using an OS, and the computer is so old that the firmware is BIOS (newer computers switched to UEFI instead).

I have to write a code that uses interruptions, obtaining a key pressed on the keyboard using assembly commands.

I would double check what you're supposed to be doing. E.g. "uses interruption" could mean "using the old 32-bit Linux kernel API (int 0x80) and not the obsolete BIOS functions" (and it could mean "using the obsolete PS/2 controller chip IRQ (like a device driver would)", or something else).

More specifically; I'm guessing that you followed instructions that included "install an old 32-bit version of Linux in a virtual machine" because you're supposed to be using the old Linux kernel API ("int 0x80") to do the equivalent of "read(STDIN_FILENO, buffer, 1);" in assembly language (to get a byte from whatever stdin is, which might or might not come from the keyboard depending on how your executable is started/used).