Hi guys,
Let's say that I want to learn how the serial port, PCI bus, or some other device works, with the intent of learning how to write a driver for it. I've got the spec and any other documentation I could find off the internet, as well as drivers from other OSes written for the device. So I'm covered when it comes to information. However, this is still not quite enough to make me (or anyone else) confident enough to just whip out a driver in one go. Many devices are particularly complex, and a more "hands-on" approach, as opposed to just reading about how a device is supposed to work, would be beneficial.
The only method I know of right now, and one which most people seem to use also, is to go and write a bunch of little code snippets that do something with the device to see if you really understand what the spec is saying (and to see if the device really does what the spec says it should do...) I have a little barebones OS set up that provides an environment for running this code, but unfortunately, this still is a rather inefficient approach for me at least. More or less, I write a little code snippet to test something about the device, compile it, reinstall the OS, reset the computer, wait for GRUB to come up, choose to boot my OS, and see the results. Then I reset the computer, wait for Linux to boot up, open up my code snippet in the text editor, and stare at my code trying to figure out why I didn't see what I wanted to see (I've pulled my hair out enough times over this one.) This whole cycle can take up to a minute or more just to perform once, not to mention the time it takes to write the code snippet in the first place and fix the bugs afterwards.
So what I'd really like to do is get rid off all of that and just focus on how to work with the device. Mostly it would be just writing to I/O ports and reading from them, just as I would do in those code snippets I was writing. So perhaps I could just type a command, into a program, like "read port 0x3F8" and the program would tell me what's in there. As easy as that.
I was wondering if there was a tool out there for doing that? I do know that a kernel debugger could do something like this, or I could just read from /dev/port or /dev/mem (/dev/kmem? I forget which one gives you physical addresses) on Linux, and I have used those approaches, but the problem is that I need a running operating system to do that, and many of the devices I want to "play around with", like the PCI bus, are needed by the OS to even allow me to do what I want. So the tool would have to allow me access to literally any device on my system.
Any thoughts?
Is there a tool for "playing around" with devices?
Re: Is there a tool for "playing around" with devices?
This basically depends upon the device you want to play with. If it's just a basic device(floppy disk, hard drive etc) you can use an emulator. You don't need to reboot every time you want to test a code snippet to see if it's actually working. If you have a different device to play with, you rather buy a test bed and connect the device to it. This is significantly faster approach to driver devlopment especially when you are writing drivers for the devices that emulators don't support.kabure wrote: have a little barebones OS set up that provides an environment for running this code, but unfortunately, this still is a rather inefficient approach for me at least. More or less, I write a little code snippet to test something about the device, compile it, reinstall the OS, reset the computer, wait for GRUB to come up, choose to boot my OS, and see the results. Then I reset the computer, wait for Linux to boot up, open up my code snippet in the text editor, and stare at my code trying to figure out why I didn't see what I wanted to see (I've pulled my hair out enough times over this one.)
Cheers.
Programming is not about using a language to solve a problem, it's about using logic to find a solution !
- xenos
- Member
- Posts: 1121
- Joined: Thu Aug 11, 2005 11:00 pm
- Libera.chat IRC: xenos1984
- Location: Tartu, Estonia
- Contact:
Re: Is there a tool for "playing around" with devices?
When I tested / debugged my OS on a real computer, I used to have two machines set up. One computer was the test machine which booted my OS. The other one was running the development environment - editor, compiler and so on. Each time I recompiled my OS, I simply needed to transfer the new version of the binaries to the test machine. First I did that with floppies, later I copied the files across the network. Another rather elegant way would be to set up an TFTP server on the development machine, put the OS binaries on that server and boot the test machine via PXE network boot.
Of course it would be much better if one could completely avoid any reboot. Perhaps you could try to write something like a Linux device driver / kernel module first, that can simple be loaded / unloaded without rebooting the machine? But I don't know how much effort it requires (I have not written any Linux device drivers yet, just played around with some source code for a USB device driver) and how deep one needs to dig into Linux internals. Also in this case I would use different machines for testing and compiling because I don't want my development machine trashed by some nasty bug in my code...
Of course it would be much better if one could completely avoid any reboot. Perhaps you could try to write something like a Linux device driver / kernel module first, that can simple be loaded / unloaded without rebooting the machine? But I don't know how much effort it requires (I have not written any Linux device drivers yet, just played around with some source code for a USB device driver) and how deep one needs to dig into Linux internals. Also in this case I would use different machines for testing and compiling because I don't want my development machine trashed by some nasty bug in my code...
Re: Is there a tool for "playing around" with devices?
I'm using something like this to muck around: https://github.com/schilds/Serial-BootLoader
I can work on just the bit I'm interested in and as long as I don't make too much of a hash of things, I don't need to reboot.
It's pretty minimal but the client and/or boot loader can always be extended to provide more support.
I can work on just the bit I'm interested in and as long as I don't make too much of a hash of things, I don't need to reboot.
It's pretty minimal but the client and/or boot loader can always be extended to provide more support.
Re: Is there a tool for "playing around" with devices?
Avoiding reboot is one of my requirements, yes. But I can't really have a full-on operating system running on the same machine I am playing around with. For stuff like USB drivers, yes that's fine (and even beneficial considering that the USB bus is fully taken care of), but if I want to learn to write a USB host controller driver, then I might run into problems if Linux needs the USB bus to support me.XenOS wrote:Of course it would be much better if one could completely avoid any reboot. Perhaps you could try to write something like a Linux device driver / kernel module first, that can simple be loaded / unloaded without rebooting the machine? But I don't know how much effort it requires (I have not written any Linux device drivers yet, just played around with some source code for a USB device driver) and how deep one needs to dig into Linux internals. Also in this case I would use different machines for testing and compiling because I don't want my development machine trashed by some nasty bug in my code...
Your project here looks like just a way to boot an operating system over the serial port (which is pretty cool. ). Wouldn't I have to reboot the target machine every time I made a change to one of my code snippets? I was thinking of a method using the serial port (or parallel port or some communications device not sitting on a bus), but I'd like it so I didn't have to reboot either of the machines.schilds wrote:I'm using something like this to muck around: https://github.com/schilds/Serial-BootLoader
I can work on just the bit I'm interested in and as long as I don't make too much of a hash of things, I don't need to reboot.
It's pretty minimal but the client and/or boot loader can always be extended to provide more support.
Ok, so let me give you guys an example. One of the solutions I was thinking about uses two computers connected by the serial or parallel port. One computer would be the host, which ran a simple command-line program that took commands like "read to port" or "write to port". This computer would send these commands over to the other computer, the target computer or "playpen", and this computer would interpret the commands and do what was asked. Then it would report the results back to the host, which would then display them to the user.
Really, the key here is interactivity. There is no compile cycle or reboot cycle or pulling-my-hair-out cycle. It's a tool that allows you to tell the processor to read/write from devices any time you feel like it, almost like you could just inject individual in/out instructions directly into the processor. And just as much, I should be able to access any device on the target machine that I feel like, at any time.
I have been designing a program to do just that, but I wanted to check this place in case anyone knew of a tool like that that already existed.
Re: Is there a tool for "playing around" with devices?
Well, as long as the code you send across returns when it's finished, it will return to the loop waiting for more input from the serial port. Data can be sent back by including that code in the code you send across. Functions can be stored as hex in text files and cut and pasted into the client.
Naturally any of this could be made nicer, but what's there is the (almost) bare minimum needed to interactively control one machine from another across a serial port.
I should mention I make no guarantees about correctness, since I haven't had time to do much with it yet. However, the included text file (containing a few bytes in hex) seems to work to append an M on the screen each time I send it using the client, so it must be somewhat correct :p.
Naturally any of this could be made nicer, but what's there is the (almost) bare minimum needed to interactively control one machine from another across a serial port.
I should mention I make no guarantees about correctness, since I haven't had time to do much with it yet. However, the included text file (containing a few bytes in hex) seems to work to append an M on the screen each time I send it using the client, so it must be somewhat correct :p.
Re: Is there a tool for "playing around" with devices?
Ah, ok, I see. I'll check it out then.schilds wrote:Naturally any of this could be made nicer, but what's there is the (almost) bare minimum needed to interactively control one machine from another across a serial port.
- DavidCooper
- Member
- Posts: 1150
- Joined: Wed Oct 27, 2010 4:53 pm
- Location: Scotland
Re: Is there a tool for "playing around" with devices?
I designed my OS to make doing this kind of thing easier, though you do have to work directly with machine code and with all values in decimal form. By working in Machine Editor you can write short snippets of code directly into memory such as 176 x 230 y 195 to send the value x to port y, and you can run it at any time simply by putting the cursor on the first byte (the 176 in this case) and pressing r followed by return. You can read a port in the same way with another code snippet: 228 y 162 n n n n 195 which will collect a value from port y and wrtie it to memory at the four-byte address n n n n (working in 32-bit mode) - the result will be instantly be visible on the screen if you point the address at the byte after the 195 ret instruction. This way of doing things lets you hold direct conversations with ports at a reasonable speed, and you can repeatedly edit the value x and run the modified snippet again in a matter of seconds every time.
If the port has a two-byte address, the equivalent code snippets are 176 x 102 186 y y 238 195 (to write a byte to a port) and 102 186 y y 236 162 n n n n 195 (to read a byte from it). I'm not sure what happens if you need to send or collect two bytes at a time because I've never done it, but, 102 184 x x (102) 239 195 and 102 186 y y (102) 237 102 163 n n n n 195 should do the job - it looks as if you may be able to send four bytes at a time in 32-bit mode if you miss out the 102s, but you can experiment with that yourself.
You can write out as many snippets as you think you'll need and you can write more of them at any time as soon as you realise you need them - you just type the numbers straight into memory and then run them using r followed by return. The indexing system can be used to calculate the nnnn addresses for you and to link them to named variables. You can name a variable by typing i (i for index) followed by a name of up to 4 chars, followed by Return; then link to it by putting the cursor on the first byte of the n n n n (the address of the variable in your code snippet) and type p (p for point) followed by the name of the variable followed by Return - the correct address will appear by magic.
I don't know if this is actually up to the specific tasks you have in mind, but you can try it out in Bochs and see what you think. If you reckon this approach might be what you're looking for but you aren't happy about working with decimals, just let me know and I can write a hex converter into Machine Editor for you so that you can input values to send to ports as hex and read the replies as hex too.
[Edit: to use the indexing system you have to work within certain areas, and that means you have to be within a code cell and in front of its eoc byte (end of code) - when you go into Machine Editor you have to type F9 and to select the OS1 module from the menu, then hit the Caps Lock key and type the keys e o c Return to search for eoc, then scroll up a bit with the Page Up key, put the cursor one byte to the left of eoc and type m, then move the cursor down the screen, type m again and then Return. You will now have made some empty space ahead of eoc to work in where the indexing system will function. You can save any code you write simply by typing F2 and selecting OS1 from the menu. If you need it, the manual can be accessed via the text editor - just press F11 to return to the control room and hit Return to enter the text editor before pressing F1 for a list of manual files. A new version will be available in a few days with much more documentation, improved functionality and a proper guide to all the Machine Editor functions.]
[Edit 2: I meant to say before, my OS can run with the interrupts disabled without losing any vital functionality, so you can even hack around with the PICs, RTC, etc without causing a crash - once it's going, it doesn't depend on any ports other than the 8042 (which is obviously essential for keyboard input), so you're free to talk to any port you like.]
[Edit 3: I've had to rewrite a couple of parts of Edit 1 above, so follow the new instructions there instead of the original ones. While the key m is used for opening up space to put code in, shift+c is used for closing any gaps - this may save you time when rewriting code snippets. You can also move a chunk of code around by marking its ends with the w key, the intended destination with the e key, and make the move happen with shift+q and Return. Short range jumps may also be useful, and the distances can be calulated automatically for you by typing f (f for from) on the jump distance byte and t (t for to) on the byte it's to jump to.]
[Edit 4: I've just spent today (Sunday) writing a hex mode for Machine Editor so you can work entirely through hex now - this version will be available in a day or two once I've fixed a few other things.]
[Edit 5 on 28 June: new version with hex mode available now.]
Click the link below to get the floppy disk image.
If the port has a two-byte address, the equivalent code snippets are 176 x 102 186 y y 238 195 (to write a byte to a port) and 102 186 y y 236 162 n n n n 195 (to read a byte from it). I'm not sure what happens if you need to send or collect two bytes at a time because I've never done it, but, 102 184 x x (102) 239 195 and 102 186 y y (102) 237 102 163 n n n n 195 should do the job - it looks as if you may be able to send four bytes at a time in 32-bit mode if you miss out the 102s, but you can experiment with that yourself.
You can write out as many snippets as you think you'll need and you can write more of them at any time as soon as you realise you need them - you just type the numbers straight into memory and then run them using r followed by return. The indexing system can be used to calculate the nnnn addresses for you and to link them to named variables. You can name a variable by typing i (i for index) followed by a name of up to 4 chars, followed by Return; then link to it by putting the cursor on the first byte of the n n n n (the address of the variable in your code snippet) and type p (p for point) followed by the name of the variable followed by Return - the correct address will appear by magic.
I don't know if this is actually up to the specific tasks you have in mind, but you can try it out in Bochs and see what you think. If you reckon this approach might be what you're looking for but you aren't happy about working with decimals, just let me know and I can write a hex converter into Machine Editor for you so that you can input values to send to ports as hex and read the replies as hex too.
[Edit: to use the indexing system you have to work within certain areas, and that means you have to be within a code cell and in front of its eoc byte (end of code) - when you go into Machine Editor you have to type F9 and to select the OS1 module from the menu, then hit the Caps Lock key and type the keys e o c Return to search for eoc, then scroll up a bit with the Page Up key, put the cursor one byte to the left of eoc and type m, then move the cursor down the screen, type m again and then Return. You will now have made some empty space ahead of eoc to work in where the indexing system will function. You can save any code you write simply by typing F2 and selecting OS1 from the menu. If you need it, the manual can be accessed via the text editor - just press F11 to return to the control room and hit Return to enter the text editor before pressing F1 for a list of manual files. A new version will be available in a few days with much more documentation, improved functionality and a proper guide to all the Machine Editor functions.]
[Edit 2: I meant to say before, my OS can run with the interrupts disabled without losing any vital functionality, so you can even hack around with the PICs, RTC, etc without causing a crash - once it's going, it doesn't depend on any ports other than the 8042 (which is obviously essential for keyboard input), so you're free to talk to any port you like.]
[Edit 3: I've had to rewrite a couple of parts of Edit 1 above, so follow the new instructions there instead of the original ones. While the key m is used for opening up space to put code in, shift+c is used for closing any gaps - this may save you time when rewriting code snippets. You can also move a chunk of code around by marking its ends with the w key, the intended destination with the e key, and make the move happen with shift+q and Return. Short range jumps may also be useful, and the distances can be calulated automatically for you by typing f (f for from) on the jump distance byte and t (t for to) on the byte it's to jump to.]
[Edit 4: I've just spent today (Sunday) writing a hex mode for Machine Editor so you can work entirely through hex now - this version will be available in a day or two once I've fixed a few other things.]
[Edit 5 on 28 June: new version with hex mode available now.]
Click the link below to get the floppy disk image.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c
MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming