www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1996/09/24/09:13:26

Date: Tue, 24 Sep 1996 14:36:24 +0200 (MET DST)
From: Mark Habersack <grendel AT ananke DOT amu DOT edu DOT pl>
Reply-To: grendel AT ananke DOT amu DOT edu DOT pl
To: "Turpen, Josh -- Josh Turpen" <snarfy AT goodnet DOT com>
cc: djgpp AT delorie DOT com
Subject: PMode rings - small intro
Message-ID: <Pine.NEB.3.95.960924143451.17398A-100000@ananke.amu.edu.pl>
MIME-Version: 1.0

This is more detailed info on protected mode rings. Enjoy reading ;-)))

        Anyone is granted to distribute this article without any
restrictions. The only thing forbidden is making fun of it ;-))

        I am not responsible for any damage or loss of information
resulting from use or misuse of any information contained here. I AM
responsible for any typos, errors and mistakes.

        Text is saved in Unix format.

Protection Mechanisms by Mark Habersack
=======================================

	There are two basic protection schemes built into the i386+
microprocessors. First of them is *task separation*. In i386+ CPUs it
is achieved by giving each task its own *virtual address space*. This
is done by means of translation tables: on each task switch the LDTR
(Local Descriptor Table Register) and CR3 (Control Register 3) are
being loaded with some, task-specific, value. This way each and every
task has exclusive access to the local descriptor table (LDT), as well
as to *page directory*. Task switch does not change the value stored
in GDTR (Global Descriptor Table Register). Table pointed to by GDTR
is shared accross all tasks in the system. It maps global resources,
mainly OS' code and data areas.

	Different tasks, although using the same virtual address, are
referring to different *physical* areas of the host memory. The exact
area referenced by task depends on the value stored in their LDTs and
in paging mechanism translation tables. Every task uses logical
addresses to reference memory and each segment selector may point to a
descriptor stored in either LDT or GDT.  This approach makes it easy
to create a *local address space* for every process (task) in the
system, OTOH there is a possibility to share memory between tasks
These two techniques are rarely used in concert, though. The most
common way of sharing memory between tasks is mapping their memory to
the same physical adresse or by copying appropriate descriptors to
LDTs of task that are to share memory.

        Second protection scheme used in i386+ CPUs are so called
*rings*. Each memory segment is assigned some *protection
level*. Every task, then, has in given moment some Current Privilege
Level (CPL) which is equal to the protection level of current code
segment. CPL allows to verify tasks rights to access some other area
(segment) of memory. There are two kinds of memory accesses: (1) to
data, (2) to code (i.e. making far calls to procedures living in
different code segment). Protection schemes employed here are as
follows:

  (ad 1) only access to data on protection level *lower* or *equal* to
         CPL is allowed.

  (ad 2) it is possible to call procedures from *equal* or *higher* to
         CPL level of protection.

        The rules are result of reasoning that it is not acceptable to
allow some program (task) to access data which is more protected and
that the code on the less protected level might be unreliable and, as
such, should not be called by more privileged parts of system
software.

        There are certain simplifications in ring-based protection
scheme presented above:

  (1) CPL is not always equal to protection level of current code
      segment

  (2) Ways to call a procedure at different protection level are far
      more complicated than presented here.

  (3) It is possible to lower CPL at execution time.

        In Intel(tm) microprocessors there are 4 protection levels
(rings) - 0..3.  From these, level 0 is the most privileged. Usual
"assignment" of rings is as follows:

  0 - operating system kernel
  1 - operating system drivers, high-level services, etc.
  2 - if used, it may contain intermediate software like database
      drivers, network front-ends, etc.
  3 - application software

        Gathering together what was said before, task can access data
only on its own level of protection or on that which is numerically
higher (i.e. on outer one as related to current). This results in ring
0 being the most protected in terms of data access. From the point of
view of code segments, ring 0 is the most privileged as one having
access to data areas in entire system. Reverse situation exists when
looking at the code access: ring 0 can invoke code that lives on its
own level only, while ring 3 can call all (unless restricted
otherwise) code in entire OS.

        Protection level of specific segment is stored in its
corresponding descriptor in either LDT or GDT. Descriptor contains
two-bit field with its associated DPL (Descriptor Privilege Level).
CPU fetches the descriptor from memory and stores its contents in a
hidden set of registers associated with every segment register in
CPU. This cache is then being used instead of reloading descriptors
from memory every time segment associated with the given register is
being accessed. Data in cache is validated only when code loads some
new value into the segment register.

        When you look at the content of any segment register (of
course if it contains a valid selector) you will notice that all of
them (I am assuming the task is being executed with CPL == 3) have
bits 0-1 set. These bits are called RPL (Requestor's Privilege Level)
and provide information on in which ring associated data/code
exists. As it can be deduced from this discussion, CPU checks validity
of memory access by comparing CPL with DPL of a segment which is to be
accessed. This segment (or more precisely descriptor of segment ) is
selected by a selector contained in register. Selector's RPL field is
used to "weaken" the callee CPL. Checks performed by CPU to authorize
access to, let's say, data are:

   if( (DPL >= CPL) && (DPL >= RPL) )
     grant_access;
   else
     signal_protection_violation;

        Consider the following example. Application requests access to
some data stored in ring 0. To do that the program has to call some OS
procedure and pass it a selector to the segment it wants to visit. In
this situation, then, the validity checks should refer not to CPL but
to requestor's protection level. CPL will be 0 as the code being
executed will pertain to OS kernel living in ring 0 and DPL will be
also 0. If CPU checked ONLY whether DPL >= CPL then the application
would gain access to any data managed and owned by OS, which is
obviously not acceptable. It is very easy for the application to set
selector's RPL to 0. To preserve the protection scheme, OS procedure
called by the application has to set the passed selector's RPL field
to the value of the user program (i.e. 3) and only then use the
selector to access data. After these actions are performed CPU sees
that DPL < RPL and rejects the access request. Net result of setting
selector RPL to 3 is "weakening" of OS kernel's protection level to
that of application. The DPL here is compared to EPL (Effective
Privilege Level) which is computed by comparing CPL to RPL (EPL =
MAX(CPL,RPL)).

        The protection rings discussed are tightly related to
segmentation scheme used in Intel i386+ CPUs. Other techniques involve
page attributes and protection levels (there are two: User and
Supervisor. The latter one allows access to page only from levels 0,
1, 2; while the former allows access from all rings).

Hope this will help a little,

Mark


---------------------------------------------------------------------------
You can't brush me under the carpet, you can't hide me under the stairs,
The custodian of your private fears, your leading actor of yesteryear,
Who as you crawled out of the alleys of obscurity, sentenced to rejection
 in the morass of anonymity. You who I directed with a lover's will, you
 who I let hypnotise the lens. You who I let bathe in the spotlights glare.
You who wiped me from your memory like a greasepaint mask, just like a
 greasepaint mask...
-------------------- http://ananke.amu.edu.pl/~grendel -------------------

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019