From OSDev Wiki
Jump to: navigation, search


Who am I?

I go by many aliases on the interwebs... The top among them being hckr83 and earlz. My real name is Jordan Earls. I have no formal programming training. I am working at Fostech Solutions however, where I am a lead programmer. I have been programming since I was 13, starting with Dark Basic Pro. I am now 18. So, I have been programming a while... My spectrum of language knowledge includes

  • C (my favorite)
  • PHP (second favorite)
  • Assembly (x86, intel syntax)
  • C++ (everything but heavy templates.)
  • Java (only used cause it's what the AP test requires)
  • Hex (my EPBP project doesn't have an assembler yet :D )
  • Ruby (I'm still learning, but it's an awesome language, my next Project: System Ruby for systems programming)

My Projects

This is a list of the projects I've worked on so far(or am still working on) that amounted to anything(in chronological order):

  • Mplayer 3.1a. My first project was mplayer 1.0, and it was made in about 2004. This version, 3.1a, was made around 2005. It had a half decent GUI and could play single songs and repeat them and such. It had no playlist support.
  • X-Explorer/X-CMD 0.5. This never really got anywhere. It was my first experience at making a command line and creating an interpreter. The interpreter even had a port of mplayer in it.. it was a horrible language though.
  • JuleOS. A 16bit OS made in Turbo C. It has horrible coding cause I was learning C while I made it. It's at
  • JouleOS. A 32bit OS made in gcc. It wasn't a very good OS but it did make it to multitasking and I think it read from a floppy disk once.. last_jouleos.tar.gz
  • Open86. An attempt at a PC emulator.. It never got much further than emulating the basic opcodes and being able to display the ascii character set on the video screen. open86 @ This was then taken over by alboin but then it died..
  • Robot AI. This was a little attempt at instead of trying to create an AI human-like, just eliminate all the ones that aren't. It didn't get very far.. Robot AI @ google-code
  • SecOS. This was a little 512 byte bootloader OS. It got pretty far for so few bytes, it had a basic command line and it had a very basic filesystem and could read files and execute files. Good luck with this one, I think there was like 5 bytes of space left
  • Niche. A little CMS thing that was suppose to let you develop your own plugins so that you could edit your site with ease and with basically no installation. It got to beta, but really it was a lost cause. niche @
  • x86Lib. This actually got half-complete. It is a library for emulating an 8086 CPU. It emulates every opcode, and possibly will be used in some academic software later. x86lib @
  • EPBP. This is a little bytecode project I had going on that was meaning to take down Java (because I hate it) but never got too far.. did get a few simple programs going in it though, and a basic module system EPBP @ Google-Code
  • AlloyOS. This little OS got pretty far, got into ring 0 and had a few very simple devices working.. svn:// (no website is up for it anymore)

and.. I think that's it for right now.. not counting the CERTSS project that I'm involved with at work(I can't say much about it anyway though)..

My Pages

Using the RTC

OpenBSD's bootloader --WIP

Getting to Ring 3 --WIP

Linker Scripts --have I started yet?


The TSS can be used for multitasking, though it is recommended to use software multitasking for these reasons:

  • Software task switching is faster(usually)
  • When you port your OS to a different CPU, it won't have the TSS, so you'll have to implement software task switching anyway
  • x86 64bit mode does not allow you to use the TSS for task switching.

Since we will be using the software multitasking approach, the TSS will contain a lot of junk we don't need. Here is the structure of the TSS

// A struct describing a Task State Segment.

typedef struct tss_entry_struct tss_entry_t;

As you can see.. a lot of wasted crap you don't need. But, intel demands it be used, so... Basically what we want to do to setup this TSS structure is give it an initial esp0 stack and setup the segments to point to our kernel segments, and really that's it.. so we can do something like this:

/**Ok, this is going to be hackish, but we will salvage the gdt_entry_bits struct to form our TSS descriptor
So some of these names of the fields will actually be different.. maybe I'll fix this later..**/
tss_entry_t tss_entry;

void write_tss(gdt_entry_bits *g)
   // Firstly, let's compute the base and limit of our entry into the GDT.
   uint32_t base = (uint32_t) &tss_entry;
   uint32_t limit = base + sizeof(tss_entry);

   // Now, add our TSS descriptor's address to the GDT.
   g->base_low=base&0xFFFFFF; //isolate bottom 24 bits
   g->accessed=1; //This indicates it's a TSS and not a LDT. This is a changed meaning
   g->read_write=0; //This indicates if the TSS is busy or not. 0 for not busy
   g->conforming_expand_down=0; //always 0 for TSS
   g->code=1; //For TSS this is 1 for 32bit usage, or 0 for 16bit.
   g->always_1=0; //indicate it is a TSS
   g->DPL=3; //same meaning
   g->present=1; //same meaning
   g->limit_high=(limit&0xF0000)>>16; //isolate top nibble
   g->always_0=0; //same thing
   g->big=0; //should leave zero according to manuals. No effect
   g->gran=0; //so that our computed GDT limit is in bytes, not pages
   g->base_high=(base&0xFF000000)>>24; //isolate top byte.

   // Ensure the TSS is initially zero'd.
   memset(&tss_entry, 0, sizeof(tss_entry));

   //note that CS is loaded from the IDT entry and should be the regular kernel code segment

Now, I know you may spend a while looking at that atrocious code..but I do believe it works. Oh, and here is our flush_tss function: (in yasm/nasm syntax)

GLOBAL tss_flush   ; Allows our C code to call tss_flush().

Ok, so now we are just about ready to do some ring 3 fun stuff!!

Entering Ring 3

Ok, the x86 is really a tricky CPU. The only way to get to ring 3 is to fool the processor into thinking it was already in ring 3 to start with. We effectively do this using an iret. I'll give you a simple example on how to execute something as ring 3:(yasm/nasm syntax)

GLOBAL _jump_usermode ;you may need to remove this _ to work right.. 
EXTERN _test_user_function
     mov ax,0x23
     mov ds,ax
     mov es,ax 
     mov fs,ax 
     mov gs,ax ;we don't need to worry about SS. it's handled by iret                
     mov eax,esp
     push 0x23 ;user data segment with bottom 2 bits set for ring 3
     push eax ;push our current stack just for the heck of it
     push 0x1B; ;user data segment with bottom 2 bits set for ring 3
     push _test_user_function ;may need to remove the _ for this to work right 
     iret ;is there really a different way to make this?

Now then, this will call the C function test_user_function and it will be operating in user mode! There is no easy way of getting back to ring 0(excluding IRQs) except for by setting up a task switching system, which you really should have in place to properly appreciate ring 3 in the first place.. But if you would like to test things out in user mode, just have the test_user_function execute a cli or other privileged instruction and you'll be pleased by a GPF. I won't give you source examples on implementing this into your task switching system, as these vary a lot by operating system.

Personal tools