feature article
Subscribe Now

Create Your Own RTOS in 1 Hour (Part 2)

Gates, Privileges, and Descriptors, Oh My!

“I believe the future is only the past again, entered through another gate.” – Arthur Wing Pinero

We know what a task state segment (TSS) is, but where does it live? The short answer is, anywhere you want it to. Like any other memory segment in the x86 world, you can place the TSS just about anywhere in physical RAM as long as you create a segment descriptor that tells the processor where to find it.

The segment descriptor for a TSS looks just like a segment descriptor for a normal code, data, or stack segment. In fact, you’d have to be an x86 processor yourself to tell the difference. As the figure shows, it’s a 64-bit structure that defines the base address of the segment, its length, and a smorgasbord of status and control bits that determine how it’s used.

The magic bit field in a TSS descriptor is in the upper half, at offsets 8–12 (decimal). You’ll want to make this 01001 (binary) to distinguish it from a code segment (11010) or a data segment (10010), or all the other types of segments. The “B” bit (busy bit) at offset 9 tells the processor that this task is busy, meaning it’s either running now or was running before switching to another task. It’s set and cleared automatically by the hardware, so you shouldn’t mess with it. The processor will refuse to task-switch to an already-busy task, and this bit in the TSS descriptor is how it knows. 

Since the base address field in the TSS descriptor is 32 bits long (albeit broken up into three awkward parts), you can put your TSS just about anywhere within the 4GB address space. And, since the limit (length) field is 16 bits, your TSS can be a lot bigger than the 104-byte minimum. Last week we saw how that extra space can be put to use tweaking I/O address permissions. You can also extend the TSS with extra user-defined data in case there’s anything you want to store that’s not already included in the TSS. 

You have to put all your TSS descriptors in the Global Descriptor Table (GDT), not in the LDT or the IDT. That’s because task segments must be accessible to the processor at all times and not be task specific. It wouldn’t make sense to put one task’s state information in a place that’s accessible only from a different task. TSS stuff needs to be global. 

Making the JMP

Okay, let’s say we’ve created two task state segments, one for each task we want to run. And we’ve created two TSS descriptors, one for each TSS. Let’s also assume we’re using really simple software task switching, where each task voluntarily jumps to the other task, which then jumps back to the first one, in an endless ping-pong loop. 

How, exactly, does one task jump to another? It’s almost too easy. You just JMP to or CALL the other task as if it were another section of code. Since the beginning of time, x86 processors have had “near” JMP and CALL instructions and “far” JMP and CALL instructions. The near kind means you’re changing the flow of control to code within the same code segment. (In the really early days, that meant code within 64KB of your current position.) A far JMP/CALL means you’re leaping to code in a different code segment. Task switching just extends that concept. 

In any far JMP/CALL, you have to specify both the code segment and the offset that you want to jump to. (That makes far JMP/CALL instructions longer than near JMP/CALL instructions, which need only the offset, in case you’re counting bits.) Well, the same rule applies here, except the “code segment” you specify is really a TSS descriptor. 

There’s no special “switch tasks” instruction in the x86. You use the same old JMP or CALL instruction as always. It just behaves differently when the hardware realizes that the segment descriptor you’ve specified is really a task segment descriptor and not a code segment descriptor. 

The Task Gate

There’s another way to switch tasks that adds a level of security while also reusing the familiar JMP and CALL instructions. It involves something called a “task gate,” which is yet another new type of segment descriptor that you get to create and load into the GDT. 

A task gate looks a lot like the other types of segment descriptors except that it’s mostly empty space. It’s 64 bits long, but only 16 bits are really significant, plus a handful of configuration bits that tell the processor it’s a task gate.

The 16-bit field from offsets 16–31 (decimal) points to a TSS descriptor, like the one we saw above. It’s not an address, it’s a selector, an index pointer into the Global Descriptor Table. As before, you can use a far JMP or a far CALL instruction to force a task switch, but instead of specifying a destination code segment, or even a task segment, you specify the task gate. The task gate points to the task segment descriptor, which points to the task state segment (TSS) itself, which loads all the other registers. How’s that for indirection? 

The net effect is the same either way. You can JMP or CALL to a TSS descriptor or to a call gate. The instructions are even encoded the same way. The only difference is the object they reference, not the instruction itself. The CPU figures this all out on the fly, in hardware. 

Rank Hath Its Privileges

So… what’s the point of a call gate? Privileges. The indirect route gives you another option for managing privileges and controlling which sections of code are allowed to call which other sections of code. All modern x86 processors implement a four-level privilege hierarchy, which takes the form of a two-bit field attached to each and every segment of code. As a rule, lesser-privileged code is not allowed to JMP or CALL to code with a higher privilege level. But there are exceptions. 

Juggling these rules and exceptions is part of your job as programmer, and a lot of real-world x86 programs just don’t. They ignore the built-in privilege hierarchy and substitute their own security system (ahem, Microsoft) or just dispense with privilege checking entirely. That’s fine and dandy, but you can’t make the processor’s privilege-checking hardware go away. It’s always active and, if you set it up properly, pretty darned useful. 

We’ll leave the detailed privilege discussions for later, but for now, a task gate provides a slightly different way to switch between tasks with slightly different privilege rules. Bits 13 and 14 in the task gate above define the DPL, the descriptor privilege level. This matches up very nicely with bits 13–14 of the TSS descriptor, which also parallels the DPL assigned to every code segment. So, we have at least three different sets of privilege bits in play here. It’s the interaction between them that makes secure programming so much fun. 

Task gates also manage access in another way. Recall that TSS descriptors are global; they have to reside in the GDT. But task gates can be local. They can be stored in an LDT (Local Descriptor Table), which means that only a task with the task gate in its LDT can “see” the task gate and, therefore, switch to that task. This allows you to restrict access to the gate (and its associated task) by selectively dropping it into the LDTs of only those task(s) you want to use it. Sneaky. 

Next up: the perils and pitfalls of setting up your first tasks and launching a task switcher. 

 

Leave a Reply

featured blogs
May 18, 2021
Since I was a kid, I’ve always been a fan of technology making life better. When I was 8, I remember programming the VCR to record the morning cartoons so I wouldn’t miss the good ones after the bus picked me up from school. When I was 10, I made mixtapes of my fa...
May 18, 2021
原文出è•: Please Excuse the Mesh: CFD and Pointwise ä½è…: Paul McLellan Cadence於今年四æˆæ”¶è³¼äº†æµé«”動力學公司Pointwiseã‚å¨æˆ‘的前ä¸ç¯‡æ–‡ç« æŽ¢è¨Ž PointwiseãPCIeã...
May 13, 2021
Our new IC design tool, PrimeSim Continuum, enables the next generation of hyper-convergent IC designs. Learn more from eeNews, Electronic Design & EE Times. The post Synopsys Makes Headlines with PrimeSim Continuum, an Innovative Circuit Simulation Solution appeared fi...
May 13, 2021
By Calibre Design Staff Prior to the availability of extreme ultraviolet (EUV) lithography, multi-patterning provided… The post A SAMPle of what you need to know about SAMP technology appeared first on Design with Calibre....

featured video

Introduction to EMI

Sponsored by Texas Instruments

Conducted versus radiated EMI. CISPR-25 and CISPR-32 standards. High-frequency or low-frequency emissions. Designing a system to reduce EMI can be overwhelming, but it doesn’t have to be. Watch this video to get an overview of EMI causes, standards, and mitigation techniques.

Click here for more information

featured paper

Keys to quick success using high-speed data converters

Sponsored by Texas Instruments

Hardware designers using modern high-speed data converters face tough challenges. Issues might include connecting with your field-programmable gate array (FPGAs), being confident that your first design pass will work, or determining how to best model the system before building it. In this article, Texas Instruments takes a closer look at each of these challenges.

Click to read more

featured chalk talk

Minitek Microspace

Sponsored by Mouser Electronics and Amphenol ICC

With the incredible pace of automotive innovation these days, it’s important to choose the right connectors for the job. With everything from high-speed data to lighting, connectors have a huge impact on reliability, cost, and design. In this episode of Chalk Talk, Amelia Dalton chats with Glenn Heath from Amphenol ICC about the Minitek MicroSpace line of automotive- and industrial-grade connectors.

Click here for more information about Amphenol FCI Minitek MicroSpace™ Connector System