Protected Mode Keyboard Access on x86 Assembly - keyboard

I'm working on keyboard input for a very basic kernel that I'm developing and I'm completely stuck. I can't seem to find any information online that can show me the information I need to know.
My kernel is running in protected mode right now, so I can't use the real mode keyboard routines without jumping into real mode and back, which I'm trying to avoid. I want to be able to access my keyboard from protected mode. Does anyone know how to do this? The only thing I have found so far is that it involves talking to the controller directly using in/out ports, but beyond that I'm stumped. This is, of course, is not something that comes up very often. Normally, Assembly tutorials assume you're running an operating system underneath.
I'm very new to the x86 assembly, so I'm just looking for some good resources for working with the standard hardware from protected mode. I'm compiling the Assembly source code with NASM and linking it to the C source code compiled with DJGPP. Any suggestions?

The MIT operating systems class has lots of good references. In particular, check out Adam Chapweske's resources on keyboard and mouse programming.
In short, yes, you will be using the raw in/out ports, which requires either running in kernel mode, or having the I/O permission bits (IOPL) set in the EFLAGS register. See this page for more details on I/O permissions.

You work with standard legacy hardware the same way on real and protected modes. In this case, you want to talk with the 8042 at I/O ports 0x60 to 0x6f, which in turn will talk to the controller within the keyboard at the other end of the wire.
A quick Google search found me an interesting resource at http://heim.ifi.uio.no/~stanisls/helppc/8042.html (for the 8042) and http://heim.ifi.uio.no/~stanisls/helppc/keyboard_commands.html (for the keyboard).
In case you are not used to it, you talk with components at I/O ports via the IN (read) and OUT (write) opcodes, which receive the I/O port number (a 16-bit value) and the value to be read or written (either 8, 16, or 32 bits). Note that the size read or written is important! Writing 16 bits to something which is expecting 8 bits (or vice versa) is a recipe for disaster. Get used to these opcodes, since you will be using them a lot (it is the only way to talk to some peripherals, including several essential ones; other peripherals use memory-mapped I/O (MMIO) or bus-mastering DMA).

The 8042 PS/2 Controller looks like the simplest possibility.
The oszur11 OS tutorial contains a working example under https://sourceforge.net/p/oszur11/code/ci/master/tree/Chapter_06_Shell/04_Makepp/arch/i386/arch/devices/i8042.c
Just:
sudo apt-get install build-essential qemu
sudo ln -s /usr/bin/qemu-system-i386 /usr/bin/qemu
git clone git://git.code.sf.net/p/oszur11/code oszur11
cd oszur11/Chapter_06_Shell/04_Makepp
make qemu
Tested on Ubuntu 14.04 AMD64.
My GitHub mirror (upstream inactive): https://github.com/cirosantilli/oszur11-operating-system-examples
Not reproducing it here because the code it too long, will update if I manage to isolate the keyboard part in a minimal example.

Related

how do VM's virtualize HW

Suppose I have a machine running Mac OS X, which is running VMware, which is running Ubuntu, which is running the canonical helloworld.c in a shell. What are the high-level sequence of events that occur between me pressing enter and Hello World! popping up on my screen?
I can understand that everything sitting above Ubuntu acts obliviously to the virtualization occurring. Additionally, I can somewhat understand from the point of view of Mac OS X, VMware is just another program - nothing special there. However, I don't understand how Ubuntu thinks it's interacting with HW, especially if it's not actually running in kernal-mode?
I'm just learning about OS's - so may not understand the full picture. Is there an additional sw/fw layer underneath the OS which the hypervisor emulates?
What 'Ubuntu' is (or any other application) is a set of bytes that either represent instructions (opcodes long with their arguemnts) or data.
The instructions are decoded and executed by the CPU. The data is mostly read into the memory (lets say a group of constants, static variables, etc.).
VMware is basically a virtual computer hardware platform (here it's a virtualization of the x86 platform). This means that it reads all the bytes of an application (a raw binary, a PE or ELF exec, whatever) and tries to act as an x86 CPU. If done properly this is indistinguishable to anything interpreted by it.
This isn't abstraction - it doesn't hide the communication method with the hardware abstracting it to some higher-level access method (like the Linux filesystem for example). It just tries to act like a x86 CPU the best it can, an abstraction would be a clearly visible layer.
As an example - C is an abstraction over ASM/machine language, you can tell the difference between them quite clearly.

How can I get edge events via GPIO on Linux without a busy-loop?

I'm working an a system with embedded Linux (Kernel 2.6.31).
It is a AT91SAM9G20 chip inside, and some of the Pins are forwarded to the outside.
Now I want to use them as GPIO Inputs.
I read the gpio.txt documentation about using the GPIOs via filesystem, and that works very well 'til here. I connected some switches to the gpio-pins and I can see the result in /sys/class/gpio/gpioX/value. But now I'd like to react on a change without busy-waiting in a loop. (i.e echo "Switch1 was pressed").
I guess I need interrupts here, but I couldn't find out how to use them without writing my own kernel driver. I'm relatively new to Linux and C (I normally program in Java), so I'd like to handle the Interrupts via sysfs too. But my problem is, that there is no "edge"-file in my GPIO directory (I guess because this is only since Kernel version 2.6.33+). Is that right? Instead of "edge" I've got a uevent file in there, which is not described in gpio.txt.
In the gpio.txt documentation there was a Standard Kernel Driver mentioned: "gpio_keys". Is it possible to use this for my problem?
I guess it would be better to work with this driver than allowing a userspace program to manipulate kernel tasks.
I found a lot of codesnippets for writing my own driver, but I wasn't even able to find out which of the 600 gpio.h files to include, and how to refer to the library (cross compiler couldn't find the gpio.h file).
Sorry for newbie questions, I hope you could give me some advices.
Thanks in advance
See this for an example on how to do that. Basically, the thing you're missing is the usage of the select or poll system calls.

How to test the kernel for kernel panics?

I am testing the Linux Kernel on an embedded device and would like to find situations / scenarios in which Linux Kernel would issue panics.
Can you suggest some test steps (manual or code automated) to create Kernel panics?
There's a variety of tools that you can use to try to crash your machine:
crashme tries to execute random code; this is good for testing process lifecycle code.
fsx is a tool to try to exercise the filesystem code extensively; it's good for testing drivers, block io and filesystem code.
The Linux Test Project aims to create a large repository of kernel test cases; it might not be designed with crashing systems in particular, but it may go a long way towards helping you and your team keep everything working as planned. (Note that the LTP isn't proscriptive -- the kernel community doesn't treat their tests as anything important -- but the LTP team tries very hard to be descriptive about what the kernel does and doesn't do.)
If your device is network-connected, you can run nmap against it, using a variety of scanning options: -sV --version-all will try to find versions of all services running (this can be stressful), -O --osscan-guess will try to determine the operating system by throwing strange network packets at the machine and guessing by responses what the output is.
The nessus scanning tool also does version identification of running services; it may or may not offer any improvements over nmap, though.
You can also hand your device to users; they figure out the craziest things to do with software, they'll spot bugs you'd never even think to look for. :)
You can try following key combination
SysRq + c
or
echo c >/proc/sysrq-trigger
Crashme has been known to find unknown kernel panic situations, but it must be run in a potent way that creates a variety of signal exceptions handled within the process and a variety of process exit conditions.
The main purpose of the messages generated by Crashme is to determine if sufficiently interesting things are happening to indicate possible potency. For example, if the mprotect call is needed to allow memory allocated with malloc to be executed as instructions, and if you don't have the mprotect enabled in the source code crashme.c for your platform, then Crashme is impotent.
It seems that operating systems on x64 architectures tend to have execution turned off for data segments. Recently I have updated the crashme.c on http://crashme.codeplex.com/ to use mprotect in case of __APPLE__ and tested it on a MacBook Pro running MAC OS X Lion. This is the first serious update to Crashme since 1994. Expect to see updated Centos and Freebsd support soon.

ARM linux and cross toolchain issue

I have a problem probably with my arm toolchain but maybe there's something other that I do wrong. I have Chinese made dev board qq2440 using Samsung s3c2440 ARM9 uC. I'm using Ubuntu x86 with native gcc(4.3.3) and cross-compile version arm-unknown-linux-uclibc-gcc (crosstool-NG-1.3.2) 4.3.2
I followed tutorials from http://blog.leshak.ru/english/pages/how-to-install-u-boot-linux-2629-rootfsjffs2-busybox-1132-into-nand-qq2440/
and used Leshak's kernel patches for that board. Problem is that his binaries work perfectly and mine don't...
I communicate with my board over RS232 (serial port) and I have serial terminal configured on target Linux. I use Leshak's uboot image. To configure my kernel I use following command line:
qq2440> setenv bootargs 'noinitrd root=/dev/mtdblock2 rootfstype=jffs2 rw console=ttySAC0,115200'
For target I use vanilla Linux sources version 2.6.29, with patches created by Leshak. I don't honestly believe that this will ever be supported officially by Linux as it's not mainstream product.
My kernel image starts booting up, but it probably changes bandwidth (or CPU frequency) to some non standard value (tried all standard ones already). Instead of dots indicating loading kernel into memory I've got only trash instead. Unfortunately it doesn't probably finish the boot process as the network interface nor file system don't come up. So I figured out that it panics somewhere in the middle.
Any ideas what should I do next?
Thanks & regards,
Chris
There are a lot of different things that could be going on here.
It sounds like you are talking about a serial port, and that it appears to be giving garbage once control is passed to the kernel from uboot. Am I understanding that correctly?
Look into specifying the baud rate, parity, etc. for the serial console on the kernel commandline.
Oh, and IIRC, there was some 'early_printk' thing in the ARM Linux tree that might help you debug serial console problems. (But I'll warn you -- it's been a couple years since I dealt with that so my memory is fuzzy.)
Double-check that the memory address layout (the locations of all the various devices) matches what your board has. (I think this is probably not the issue, but wanted to mention it for completeness.)
You say that you have a binary kernel that works correctly; compare the kernel config of that kernel to the config you are using for building your kernel. Investigate every difference, particularly any specific to ARM.
You may want to double-check the endianness of your toolchain vs what your board is expecting. Some of the ARM / XScale processors can be configured to big-endian or little-endian in software, so it might be worth double-checking.
Just enable the debug build of the kernel[while building the uImage] so that you get a more clearer picture of the scenario [Just would make your boot up somewhat slow since all the printk's would be enabled].
Can you check whether you are passing the correct parameters to the UART ie. Serial Port Name, it's baud rate etc This would be provided by the board manufacturer-Samsung
WRT the network instead of DHCP can you just assign a static ip address to your system as it might be possible that the DHCP process is still not ON.
Also a better option would be to use NFS but yeah, it depends on your choice and the purpose of your application. To use NFS, your network should be UP & running and your filesystem should be shared.
As retracile has already pointed out "Endianness" could be a point to look into !!!
You can refer this link which might help you out since it is specific to S3C2440
Hope this helps.
-hjsblogger
I had a similar problem at one point when I omitted --send-cmd from picocom. this is the command I issue to picocom for serial uBoot comms with the mini2440.
picocom -b 115200 /dev/ttyS0 --send-cmd "sx -vv"

how to access sound card in linux using nasm

hello i want to know how i can access sound card from nasm assembly program using int 0x80.
and also what values should i put in the registers when to access the sound card.
is there any manual or something that has details about the arguments that we have to pass to the kernel to access the sound card or other hardware devices, please if anyone know please tell me.
i had done alot of searching and well there alot of c libraries and ALSA and OSS and stuff like that, but what i would like is that if any one know of some resources about learning from the basics up about assembly program interfacing with the hardware.
and if any one could give me a small code listing as to how the access is done i would be very thankful.
As you've observed, the interface between user-space and kernel space in Linux is INT 0x80.
In Unix, as a matter of philosophy, (almost) everything is a file, thus sound cards are treated as "Character Files." The kernel syscalls are as per the POSIX specification - so "open","close","ioctl","read","write".
Access to the soundcard is done through the driver interface, as a file under "/dev/". Some sample documentation is at OSS documentation, but I'm not sure if its current.
To observe this communication, you can use 'strace' to see what system calls are being used by any existing application.
You will likely see a sequence like:
open("/dev/dsp", ... )
ioctl()
write()
...
write()
close()
Usually you'd get to "open" through the C library, but since you want to skip that, you can find the syscalls a few ways - one way would be
objdump -d /usr/lib/libc.a
For example, you can find that open is syscall 0x5 by looking for <__libc_open>:
You'll notice that eax is 5, and the rest of the parameters are in ebx, ecx and edx.
(The usage and parameters are also listed on Linux Syscalls )
This is what sound card drivers do. They have to be custom written for each sound card, in order to implement a common API which can be used by the O/S or applications. The same goes for other hardware devices. Hardware manufacturers tend to be less than open about how to access their stuff at this level (for one thing).
Not that I'm a Linux expert, but this is a fairly fundamental issue with all O/S's.
From user mode, this won't work - you won't have direct access to the sound hardware.
If you create a kernel-mode driver, you'd be able to directly poke the sound card hardware, but at this point I think most vendors have different implementations and don't follow a consistent standard. Newer sound cards might still be Adlib & SoundBlaster 16 compatible - this was the hardware standard WAY back when games were targetting DOS and directly used the hardware, but I wouldn't be surprised if this is no longer valid. A quick search should yield ways to directly access the interface for these legacy cards. Alternatively, you could run DOS inside of a virtual machine and access the hardware - most virtual machines emulate this level of sound card.
Depending what you're trying to do, you're probably better off using an existing library to handle the interface to the sound card, unless you aim to write a sound card driver, which I doubt, and that would be best done in C on linux.
Portaudio is one (free) one that's relatively easy to use. one example lib using portaudio with a C interface (I'm the author of wwviaudio).
FMOD seems to be big with the game programming guys, though it's not free.
sdl mixer is another one that's big with the linux game developers.
JACK is big in the linux pro-audio world. (think ardour -- the linux answer to Protools.)
There's no sense in trying to talk to the audio hardware directly from user space.

Resources