compile-time rather than at run-time, and will as such not impact performance
adversely.
As it is a monolithic kernel, there are no external entities and fixed protocols that
have to be taken into account, so the compiler is free to optimize away operations
that are not needed on specific architectures. More specifically, because nothing
else depends on the internal data structures those data structures can be tailored at
a source level to match the user or hardware requirements as closely as necessary.
The way the Linux kernel virtual machine is implemented is through the creation
of architecture-specific header files and a common API between the generic kernel
code and the architecture-specific files. These header files create the image of the
virtual machine that the common code is running on.
The virtual machine header files define the machine by using the C language pre-
processor (#define directives) and by using various type defines and inline functions
to implement the virtual machine on top of the physical hardware. While inline
functions are not part of standard C, they are implemented by most C compilers,
and the support for them by the normal Linux C compiler (GNU C compiler, also
known as “gcc”) is extensive. As the GNU C compiler is itself very portable, the
use of C extensions is not a problem.
The use of gcc also allows the architecture header files to use inline assembly
routines to implement code that cannot be expressed efficiently with portable C.
This, together with inline functions, allows the compiler to efficiently map the virtual
machine semantics on top of any specific hardware, and means that the virtual
machine abstraction results in little or no performance loss.
In addition to the architecture-specific header files, each architecture has its own
subdirectory in the arch directory in the system sources. This directory contains the
set of rules to build the kernel sources for each architecture; what files to use, what
special options the compiler needs for this architecture and so on. This approach
allows a maximum of flexibility with regard to architecture-specific code, and does
not impose any restrictions on what the code does.
Even in the architecture-specific parts of the kernel, common concerns have re-
sulted in a basic layout of the architecture-specific kernel sources. Most architectures
tend to have the subdirectories kernel, mm and lib available. These subdirecto-
ries contain code for generic kernel functionality (e.g., system call interface, trap
handling), low-level memory management code (e.g., page table initialization and
page fault handling) and optimized architecture-specific library code (e.g., memory
copying, network checksum calculations) respectively.
12
Additionally, many architectures have software floating point math emulation
for hardware that does not have floating point available, or for hardware which
needs software support for special cases like underflow and overflow situations.
13
3
Software Interface Portability Issues
One area of concern with regard to operating system portability that is often over-
looked is the software interface side. The issue has traditionally been ignored,
because the operating system designer was also in charge of designing the interface
to the system and application software, and as such the operating system kernel
could freely implement any interface it wanted.
P1
P2
P3
Server 1
Server 2
Personality
Personality
Common Microkernel
Figure 4: Multiple personalities
However, the computer industry
has matured, and most modern op-
erating systems have to live with
the fact that interface standards al-
ready exist, and cannot be ignored.
Sometimes the standards are on a
source level, allowing much freedom
in actually implementing the stan-
dard. In the UNIX world, the most
well-known example of this is the
POSIX (Portable Operating System
Interface) standard [Ins96].
More often, the standard is a bi-
nary compatibility standard that is
required in order to run legacy appli-
cations designed for a previous oper-
ating system. In this case, the de-
signer must very closely follow the
exact interface details of the binary
standard so that no legacy applications break when the system is upgraded to a
new operating system kernel.
If no previous binary standard exists, the operating system designer is generally
free to create any binary interface to the kernel, and in that sense a lack of a standard
can be very liberating. However, even then the designer is generally limited by the
hardware protection mechanisms in selecting the exact interface for the kernel, and
as such the architecture to some degree always limits the interaction between user
mode and the kernel.
14
Another issue that is sometimes faced is the existence of multiple standards on
the same platform, with subtly different
4
and possibly even contradictory require-
ments. While this is fortunately rare, it may be one of the primary concerns for the
system designers.
The issue of multiple interfaces to the operating system is usually handled by
having so-called OS personalities. One personality handles the interfacing issues of
one interface standard, and all personalities share the same common core operating
system routines.
In one sense, the concept of OS personality is very similar to the issue of porta-
bility to the hardware, and the same virtual machine abstraction can be used to
handle the case of multiple interfaces. The idealized kernel does not directly im-
plement any of the interfaces, and the software portability issue is then a matter of
mapping the wanted user interface on top of the idealized kernel image.
One large difference between OS personalities and hardware platforms is gener-
ally that the kernel only runs on one physical platform at a time, yet it potentially
has to handle multiple personalities concurrently. Microkernel operating systems
generally handle this by the addition of a personality server for each personality
(see Figure 4).
In this kind of personality server approach, the overhead of such personality
handling is quite high, though, and is one of the primary reasons for work on
migrating threads (see for example [FL94]) and moving system services into the
kernel address space (see [LHFL93]). More importantly, while the concept of a
personality server allows a personality-independent view of the system, most real
system usage tends to favor one primary personality. The other personalities are
then mainly used for backwards compatibility or emulation of non-native systems.
3.1
The implementation of the software interface
Because the primary goal of Linux was never to act as a platform for emulating
other systems, the Linux approach to the software interface personality problems is
straightforward.
Rather than supporting the notion of multiple personalities of equal importance,
the Linux kernel interfaces tend to have just one primary personality for which the
system is optimized. Having a primary personality allows the use of compile-time
optimizations for the common case, and means that the internal structures can be
4
Sometimes the differences are not so very subtle.
15
Dostları ilə paylaş: |