C++ Operating System Development
The aim of this tutorial is to show you how to write a developed kernel in C++. At this stage you should be fairly competent in the use of C++ and to have a little knowledge of how protected mode functions would be recommended. I’ll try my best to walk you through the more important parts of the code.
AI
Riepilogo AI: This codebase represents a historical implementation of the logic described in the metadata. Our preservation engine analyzes the structure to provide context for modern developers.
Codice sorgente
<p><br>
The aim of this tutorial is to show you how to write a
developed kernel in C++. At this stage you should be fairly
competent in the use of C++ and to have a little knowledge
of how protected mode functions would be recommended.
I’ll try my best to walk you through the more important
parts of the code.</p>
<p>Part 1, Will look at the IDT
(Interrupt Descriptor Table) and PIC (Programmable Interrupt
Controller) and how to set these up.<br>
<br>
Part 2, Will be programming the Keyboard Interrupt and
how to develop a simple keyboard driver.<br>
<br>
Part 3, Will walk through the development of a simple
‘std::cout’ and ‘std::cin’ implementation.</p>
<p>The end result will be a simple kernel that accepts input
and processes it. <br>
This :-</p>
<p>//--------------------Kernel.cpp--------------------<br>
#include "iostream.h" //(cout, cin, endl)<br>
#include "asmf.h" //(enable)</p>
<p>using std::cout; //so we only have to write cout.<br>
using std::endl;<br>
using std::cin;</p>
<p>int main(void)<br>
{<br>
char buffer[256]; //Max input from cin is 256 chars including
'\0' char,<br>
//This can change once we have ‘new’ and ‘delete’.<br>
enable(); //Interrupts are disabled by my bootstrap.</p>
<p> cout << endl << "\nHello, what is your
name? ";</p>
<p> cin >> buffer;</p>
<p> cout << "\nHi " << buffer <<"!
Nice to meet you." << endl;<br>
}</p>
<p>//--------------------Kernel.cpp--------------------<br>
</p>
<strong>Introduction:</strong><br>
Let me start by saying that there are many ways of doing
this. Some people use assembly, others dot the code with
exorbitant inline assembly and others have assembly stubs
for interrupts. Now I’m not a big believer in assembly
but let’s be serious, assembly just makes things
difficult, especially in C++ with name mangling and such.
There are times where assembly will be our saviour, but
for the most part we can do this in good old pure C++.</p>
<p><strong>Back to Basics:</strong><br>
Ok. Where to start?.. Lets just start at the beginning.
Interrupts. What are they? Well, when communicating to
devices we use I/O ports. These ports enable us to retrieve
information, request device operations and be informed
of any status changes. The question is how do we know
when there is information available? One option would
be to poll the port, but that is very inefficient, the
other would be to have the device interrupt us when there
is information available, jump to some pre-determined
code to handle the device and then return to what we were
doing. Interrupts are also the ONLY way the CPU will communicate
any errors it encounters.</p>
<p>Now the first thing to do when setting up the system
to accept interrupts is to re-program the Programmable
Interrupt Controller (also known as the PIC). This is
because in real mode there are not as many CPU error interrupts
(Intel has reserved the first 31 interrupts for the CPU.
It is possible to use interrupts above 18 at the moment
but this is not recommended as future CPU’s may
use these interrupts) and to move all hardware interrupts
out of the first 31 interrupts requires reprogramming
the PIC: (View source, interrupt.h, for the definitions
of PICM, ICW1 ect.)</p>
<p><span style="font-size:10pt; color:#000000"><tt><span style="color:#0000ff">void</span>
Interrupt::init_pic() <span style="color:#008000"><br>
</span><span style="font-size:10pt; color:#000000"><tt> </tt></span> <span style="color:#008000">//re-programs
the pic</span> <br>
{ <span style="color:#008000">//IRQ interrupts
start at MASTER_VEC</span> <br>
outportb(PICM, ICW1); <br>
outportb(PICS, ICW1); <br>
outportb(PICMI, MASTER_VEC); <br>
outportb(PICSI, SLAVE_VEC); <br>
outportb(PICMI, <span style="color:#600000">4</span>);
<br>
outportb(PICSI, <span style="color:#600000">2</span>);
<br>
outportb(PICMI, ICW4); <br>
outportb(PICSI, ICW4); <br>
outportb(PICMI, <span style="color:#600000">0xff</span>);
<br>
outportb(PICSI, <span style="color:#600000">0xff</span>);
<br>
}</tt></span><br>
<br>
</p>
<p>The next thing to do is to set up our Interrupt Descriptor
Table. The IDT can be located anywhere in memory (unlike
real mode) and it is up to the programmer to inform the
CPU where to look for this table using the ‘LIDT’
instruction (This is where assembly comes into the picture).
The IDT can be any length, but I would not recommend anything
lower than space for at least 48 interrupts (CPU + IRQ)
and the max is 256.</p>
<p><span style="font-size:10pt; color:#000000"><tt> <span style="color:#0000ff">struct</span>
idt_gate <br>
{ <span style="color:#0000ff"><br>
unsigned</span> <span style="color:#0000ff">short</span>
offset1; <span style="color:#0000ff"><br>
unsigned</span> <span style="color:#0000ff">short</span>
selector; <span style="color:#0000ff"><br>
unsigned</span> <span style="color:#0000ff">char</span>
dword_count; <span style="color:#0000ff"><br>
unsigned</span> <span style="color:#0000ff">char</span>
type; <span style="color:#0000ff"><br>
unsigned</span> <span style="color:#0000ff">short</span>
offset2; <br>
} __attribute ((packed)); <br>
<br>
idt_gate idt[<span style="color:#600000">256]</span>;</tt></span></p>
<p>The code above is the actual IDT. Each interrupt in the
table must be set before it is loaded to prevent any errors.
Offset 1 and 2 when placed together create a pointer to
the handler’s code (offset1:offset2). Selector is
the segment code selector that is used to access the code
and the type of interrupt must be set. The type of handler
is not very important in the kernel at the moment but
must be set to either a trap (CPU interrupt) or interrupt
gate, the type of code used in the interrupt (32bit),
whether the interrupt is absent or present and the code
permission level (eg Ring 3, but this doesn’t matter
for embedded kernel drivers as they can access any kernel
code on any level anyway).</p>
<p>Once the IDT has been set we must then create an IDT
descriptor. This descriptor tells the CPU how many interrupts
are available in the table and what its offset in memory
is.</p>
<p><span style="font-size:10pt; color:#000000"><tt> <span style="color:#0000ff">struct</span>
<br>
{ <span style="color:#0000ff"><br>
unsigned</span> <span style="color:#0000ff">short</span>
size __attribute ((packed)); <span style="color:#0000ff"><br>
unsigned</span> <span style="color:#0000ff">long</span>
offset __attribute ((packed)); <br>
} idt_desc;</tt></span></p>
<p><span style="font-size:10pt; color:#000000"><tt> idt_desc.size=(<span style="color:#600000">256</span>*<span style="color:#600000">8</span>)-<span style="color:#600000">1</span>;<br>
</tt></span><span style="font-size:10pt; color:#000000"><tt>idt_desc.offset=(<span style="color:#0000ff">unsigned</span>
<span style="color:#0000ff">long</span>)idt;</tt></span></p>
<p>Now all that is left to do is load the IDT descriptor
for the CPU and we have control of interrupts! </p>
<p><span style="font-size:10pt; color:#000000"><tt><span style="color:#0000ff">asm</span>(<span style="color:#aaaaaa">"lidt
%0"</span> : <span style="color:#aaaaaa">"=m"</span>
(idt_desc)); <span style="color:#008000">//Load IDT.</span></tt></span></p>
<p>That’s all! Pretty basic hey? You will have to
write handlers for the CPU interrupts (at this stage a
simple screen message, disabling of interrupt and a halt
should do fine). For more information on CPU interrupts,
check out:<br>
http://member.netease.com/~laoyang/control/interrup.html</p>
<p>For more information on the PIC have a look at:<br>
http://users.win.be/W0005997/GI/pic.html</p>
<p>The source code for a complete implementation of the
code above is available on this page,
and is in the interrupt.cpp, interrupt.h files.<br>
Note: <br>
<span style="font-size:10pt; color:#000000"><tt> <span style="color:#008000">/*
Engesn (Derived) Operating System</span> <span style="color:#008000">
<br>
* Copyright (c) 2002, 2003 Stephen von Takach</span> <span style="color:#008000">
<br>
* All Rights Reserved.</span> <span style="color:#008000">
<br>
* </span> <span style="color:#008000"> <br>
* Permission to use, copy, modify and distribute this
software</span><span style="color:#008000"><br>
* is hereby granted, provided that both the copyright
notice and</span><span style="color:#008000"><br>
* this permission notice appear in all copies of the software,</span><span style="color:#008000"><br>
* derivative works or modified versions. </span> <span style="color:#008000"><br>
*/</span>
Commenti originali (3)
Recuperato da Wayback Machine