Title : Linenoise
Author : Phrack Staff
==Phrack Inc.==
Volume 0x0b, Issue 0x3b, Phile #0x03 of 0x12
|=---------------------=[ L I N E N O I S E ]=---------------------------=|
|=-----------------------------------------------------------------------=|
|=------------------------=[ phrackstaff ]=------------------------------=|
--[ Contents
1 - PHRACK Linenoise Introduction
1.1 PHRACK Oops
1.2 PHRACK Fakes
2 - PHRACK OS Construction
3 - PHRACK ninja lockpicking
4 - PHRACK sportz: fingerboarding
--[ 1 - PHRACK Linenoise Introduction
I think you know what linenoise is about. We had the same
cut & paste Linenoise Introduction in the last 10 issues :)
----[ 1.1 - PHRACK Oops
Oops, For the last 17 years we forgot the .txt extension to the
articles.
Some reader complained about a little mistake in p59-0x01:
phrack:~# head -20 /usr/include/std-disclaimer.h
22 lines of the header are actually printed :P
The message of the disclaimer remains:
1) No guarantee on anything.
2) Nobody is responsible.
3) Dont blame us if your kids turn into hackerz.
----[ 1.2 - PHRACK Fakes
http://www.cafepress.com/cp/store/store.aspx?storeid=phrack
That's not us.
Check out our homepage at http://www.phrack.org for some tshirts.
|=[ 0x02 ]=-------=[ Methodology For OS Construction ]=------------------=|
|=-----------------------------------------------------------------------=|
|=--------------=[ Bill Blunden <[email protected]> ]=---------------=|
--[ Contents
0 - Introduction
1 - The Critical Path
1.1 Choose a Host Platform
1.2 Build a Simulator
1.3 Build a Cross-Compiler
1.4 Build and Port The OS
1.5 Bootstrap the Cross-Compiler
2 - OS Components
2.1 Task Model
2.2 Memory Management
2.3 I/O interface
2.4 File System
2.5 Notes On Security
3 - Simple Case Study
3.1 Host Platform
3.3 Compiler Issues
3.4 Booting Up
3.5 Initializing The OS
3.6 Building and Deploying
4 - References and Credits
--[ 0 - Introduction
Of the countless number of books on operating system design, there are
perhaps only three or four, that I know of, which actually discuss how to
build a fully-functional operating system. Even these books focus so
narrowly on specific hardware that the essential steps become buried
under a pile of agonizing minutiae. This is not necessarily a bad thing,
rather it is an unintended consequence. Operating systems are incredibly
complicated pieces of software, and dissecting one will yield countless
details.
Nevertheless, my motivation for submitting this article is to provide a
generic series of steps which can be used to build an OS, from scratch,
without bias towards a particular hardware vendor.
"Geese Uncle Don, how do you build an OS ..."
My own understanding of OS construction was rather sketchy until I had the
privilege of meeting some old fogeys from Control Data. These were people
who had worked on the CDC 6600 with Seymour Cray. The methodology which I
am passing on to you was used to build Control Data's SCOPE76 operating
system. Although some of the engineers that I spoke with are now in their
70s, I can assure you that the approach they described to me is still very
useful and relevant.
During the many hours that I pestered these CDC veterans for details, I
heard more than a few interesting war stories. For example, when Control
Data came out with the 6600, it was much faster than anything IBM was
selling. The execs at Big Blue were so peeved at being upstaged by Cray
that they created a paper tiger and told everyone to wait a few months.
Unfortunately, it worked. Everyone waited for IBM to deliver ( IBM never
did, those bastards ) and this forced CDC to drop the price of the 6600
in half in order to attract customers.
If you are familiar with IBM's business practices, this type of behavior
comes as no surprise. Did you know that IBM sold Hollerith tabulators to
the Nazis during WWII?
This article is broken into three parts.
Part 1 presents a general approach that may be used to build an operating
system. I am intentionally going to be ambiguous. I want the approach to
be useful regardless of which hardware platform you are targeting.
For the sake of focusing on the process itself, I delay the finer details
of construction until Part 2. In Part 2, I present a rough map that can be
used to determine the order in which the components of the OS should be
implemented.
For the sake of illuminating a few of the issues that a system engineer
will face during OS implementation, I have included a brief discussion
of an extended example in part 3. My goal in part 3 is to illustrate some
of the points that I make in part 1. I have no intention of offering a
production quality OS, there are already a number of excellent examples
available. Interested readers can pick up any of the references provided
at the end of this article.
--[ 1 - The Critical Path
In the stock market, you typically need money in order to make money.
Building an OS is the same way: you need an OS in order to build one.
Let's call the initial OS, and the hardware that it runs on, the 'host'
platform. I will refer to the OS to be constructed, and the hardware that
it will run on, as the 'target' platform.
--[ 1.1 - Choose a Host Platform
I remember asking a Marine Corp Recon guy once what he thought was the
most effective small sidearm. His answer: "whichever one you are the most
familiar with."
The same holds true for choosing a host platform. The best host platform
to use is the one which you are the most familiar with. You are going to
have to perform some fancy software acrobatics and you will need to be
intimately familiar with both your host OS and its development tools. In
some more pathological cases, it may even help to be familiar with the
machine instruction encoding of your hardware. This will allow you to
double check what your development tools are spitting out.
You may also discover that there are bugs in your initial set of tools,
and be forced to switch vendors. This is a good reason for picking a host
platform which is popular enough that their are several tool vendors to
choose from. For example, during some system work, on Windows, I
discovered a bug in Microsoft's assembler (MASM). As it happened, MASM
would refuse to assemble a source file which exceeded a certain number of
lines. Fortunately, I was able to buy Borland's nifty Turbo Assembler
(TASM) and forge onward.
--[ 1.2 - Build a Simulator
Once you've picked a host platform and decided on an appropriate set of
development tools, you will need to build a simulator that replicates the
behavior of the target platform's hardware.
This can be a lot more work than it sounds. Not only will you have to
reproduce the bare hardware, but you will also have to mimic the BIOS which
is burned into the machine's ROM. There are also peripheral devices and
micro controllers that you will need to replicate.
Note: The best way to see if you have implemented a simulator correctly is
to create an image file of a live partition and see if the simulator will
run the system loaded on it. For example, if you built an x86 simulator,
then you could test out an image file of a Linux boot partition.
The primary benefit of the simulator is that it will save you from having
to work in the dark. There is nothing worse than having your machine
crash and not being able to determine why. Watching your Intel box triple
fault can be extremely frustrating, primarily because it is almost
impossible to diagnose the problem once it has occurred. This is
particularly true during the boot phase, where you haven't built enough
infrastructure to stream messages to the console.
A simulator allows you to see what is happening in a safe, and controlled,
environment. If your code crashes the simulator, you can insert diagnostic
procedures to help perform forensic work. You can also run the simulator
from within the context of a debugger so that you can single-step through
tricky areas.
The alternative is to run your OS code on raw metal, which will basically
preclude your ability to record the machine's state when it crashes. The
diagnostic and forensic techniques which you used with the simulator will
be replaced by purely speculative tactics. This is no fun, trust me.
For an excellent example of a simulator, you should take a look at the
bochs x86 simulator. It is available at:
http://sourceforge.net/projects/bochs
Once thing that I should mention is that it is best to use bochs in
conjunction with Linux. This is because bochs works with disk images and
the Linux 'dd' command is a readily available and easy way to produce
a disk image. For example, the following command takes a floppy disk and
produces an image file named floppy.img.
dd if=/dev/fd0 of=floppy.img bs=1k
Windows does not ship with an equivalent tool. Big surprise.
"Back in my day ..."
In the old days, creating a simulator was often a necessity because
sometimes the target hardware had not yet gone into production. In those
days, a smoke test was truly a smoke test ... they turned on the machines
and looked for smoke!
--[ 1.3 - Build a Cross-Compiler
Once you have a simulator built, you should build a cross-compiler.
Specifically, you will need to construct a compiler which runs on the host
platform, but generates a binary which is run by the target platform.
Initially you will use the simulator to run everything that the cross-
compiler generates. When you feel confident enough with your environment,
you can start running code directly on the target platform.
"Speaking words of wisdom, write in C..."
Given that C is the de facto language for doing system work, I would
highly recommend getting the source code for compiler like gcc and
modifying the backend. The gcc compiler even comes with documentation
dedicated to this task, which is why I recommend gcc. There are other
public C compilers, like small-C, that obey a subset of the ANSI spec
and may be easier to port.
gcc: http://gcc.gnu.org
small-C: http://www.ddjembedded.com/languages/smallc
If you want to be different, I suppose you could find a Pascal or Fortran
compiler to muck around with. It wouldn't be the first time that someone
took the less traveled route. During the early years, the Control Data
engineers invented their own variation of Pascal to construct the
NOSVE (aka NOSEBLEED) OS. NOSVE was one of those Tower of Babel projects
that never made it to production. At Control Data, you weren't considered
a real manager until you had at least one big failure under your belt. I
bet NOS/VE pushed the manager up to VP status!
--[ 1.4 - Build and Port The OS
OK, you've done all the prep work. It's time to code the OS proper. The
finer details of this process are discussed in Part 2. Once you have
a prototype OS built than runs well on the simulator you will be faced
with the -BIG- hurdle ... running your code on the actual target hardware.
I found that this is a hurdle which you should jump early on. Do a test
run on the target platform as soon as you have the minimal number of
working components. Discovering that your code will not boot after 50,000
lines of effort can be demoralizing.
If you were disciplined about designing and testing your simulator, most
of your problems will probably be with the OS code itself and perhaps
undocumented features in peripheral hardware controllers. This is where
investing the time in building a bullet-proof simulator truly pays off.
Knowing that the simulator does its job will allow you to more accurately
diagnose problems ... and also save you plenty of sleep.
Finally, I would recommend using a boot disk so that you don't put the
hard drive(s) of your target machine at risk. Even the Linux kernel can
be made to fit on a single floppy, so for the time being try not to worry
about binary size constraints.
--[ 1.5 - Bootstrap the Cross-Compiler
Congratulations. You have gone where only a select few have gone before.
You've built an operating system. However, wouldn't it be nice to have
a set of development tools that can be run by your new OS? This can be
achieved by bootstrapping the existing cross-compiler.
Here's how bootstrapping works: You take the source code for your cross-
compiler and feed it to the cross-compiler on the host platform. The
cross-compiler digests this source code and produce a new binary that can
be executed by the target OS. You now have a compiler that runs on the
target OS and which creates executables that also run on the target OS.
Naturally, I am making a few assumptions. Specifically, I am assuming that
the libraries which the cross-compiler uses are also available on the
target OS. Compilers spend a lot of time performing string manipulation and
file I/O. If these supporting routines are not present and supported on the
target platform, then the newly built compiler is of little utility.
--[ 2 - OS Components
An OS is a strange sort of program in that it must launch and manage
itself in addition to launching and managing other programs. Hence, the
first thing that an operating system needs to do is bootstrap itself and
then set up its various components so that it can do its job.
I would recommend getting your hands on the vendor documentation for
your hardware. If you are targeting Intel, then you are in luck because
I explain the x86 boot process in Part 3 of this article.
In terms of overall architecture, I would recommend a modular, object-
oriented, design. This doesn't mean that you have to use C++. Rather, I
am encouraging you to delineate the various portions of the OS into
related sets of data and code. Whether or not you use a compiler to
enforce this separation is up to you. This approach has its advantages
in that it allows you to create sharply delineated boundaries between
components. This is good because it allows you to hide/modify each
subsystem's implementation.
Tanenbaum takes this idea to an extreme by making core components, like
the file system and memory manager, pluggable at runtime. With other
operating systems, you would have to re-compile the kernel to swap
core subsystems like the memory manager. With Minix, these components
can be switched at runtime. Linux has tried to implement something
similar via loadable kernel modules.
As a final aside, you will want to learn the assembly language for the
target platform's hardware. There are some OS features that are tied
directly to hardware and cannot be provided without executing a few dozen
lines of hardware-specific assembler. The Intel instruction set is
probably one of the most complicated. This is primarily due to historical
forces that drove Intel to constantly strive for backwards compatibility.
The binary encoding of Intel instructions is particularly perplexing.
Which OS component should you tackle first?
In what order should the components be implemented?
I would recommend that you implement the different areas of functionality
in the manner described by the following four sections.
--[ 2.1 - Task Model
In his book on OS design, Richard Burgess states that you should try to
start with the task control code, and I would tend to agree with him.
The task model you choose will impact everything else that you do.
First, and foremost, an operating system manages tasks. What is a task? The
Intel Pentium docs define a process as a "unit of work" (V3 p.6-1).
What was that person smoking? It's like saying that a hat is defined as a
piece of clothing. It doesn't give any insight into the true nature of a
task. I prefer to think of a task a set of instructions being executed by
the CPU in conjunction with the machine state which that execution
produces.
Inevitably, the exact definition of a task is spelled out by the operating
system's source code.
The Linux kernel (2.4.18) represents each task by a task_struct
structure defined in /usr/src/linux/include/linux/sched.h. The kernel's
collection of processes are aggregated in two ways. First, they are
indexed in a hash table of pointers:
extern struct task_struct *pidhash[PIDHASH_SZ];
The task structures are also joined by next_task and prev_task pointers
to form a doubly-linked list.
struct task_struct
{
:
struct task_struct *next_task, *prev_task;
:
};
You will need to decide if your OS will multi-task, and if so then what
policy will it apply in order to decide when to switch between tasks
( switching tasks is also known as a context switch ). Establishing a
mechanism-policy separation is important because you may decide to change
the policy later on and you don't want to have to re-write all the
mechanism code.
Context Switch Mechanism:
-------------------------
On the Intel platform, task switching is facilitated by a set of system
data structures and a series of special instructions. Specifically,
Intel Pentium class processors have a task register (TR) that is intended
to be loaded (via the LTR instruction) with a 16-bit segment selector.
This segment selector indexes a descriptor in the global descriptor table
(GDT). The information in the descriptor includes the base address and
size of the task state segment (TSS). The TSS is a state-information
repository for a task. It includes register state data (EAX, EBX, etc. )
and keeps track of the memory segments used by a given task. In other
words, it stores the 'context' of a task.
The TR register always holds the segment selector for the currently
executing task. A task switch is performed by saving the state of
the existing process in its TSS and then loading the TR with a new
selector. How this actually occurs, in terms of what facilitates the
re-loading of TR, is usually related to hardware timers.
The majority of multi-tasking systems assign each process a quantum
of time. The amount of time that a task receives is a policy decision.
An on-board timer, like the 82C54, can be set up to generate interrupts
at evenly spaced intervals. Every time these interrupts occur, the kernel
has an opportunity to check and see if it should perform a task switch.
If so, an Intel-based OS can then initiate a task switch by executing
a JMP or CALL instruction to the descriptor, in the GDT, of the task to
be dispatched. This causes the contents of TR to be changed.
Using the timer facilitates what is known as preemptive multitasking.
In the case of preemptive multitasking, the OS decides which task
gets to execute in conjunction with a scheduling policy. At the other
end of the spectrum is cooperative multitasking, where each task decides
when to yield the CPU to another task.
For an exhaustive treatment of task management on Intel, see Intel's
Pentium manual (Volume 3, Chapter 6).
Context Switch Policy:
----------------------
Deciding which process gets the CPU's attention, and for how long, is a
matter of policy. This policy is implemented by the scheduler. The Linux
kernel has a scheduler which is implemented by the schedule() function
located in /usr/src/linux/kernel/sched.c.
There are a lot of little details in the schedule() function related to
handling the scenario where there are multiple processors, and there are
also a couple of special cases. However, the core actions taken by the
scheduler are relatively straightforward. The scheduler looks through the
set of tasks that are eligible to execute. These eligible tasks are
tracked by the runqueue data structure.
The scheduler looks for the task on the runqueue with the highest
'goodness' value and schedules that task for execution. Goodness is a
value calculated by the goodness() function. It basically returns a
value which reflects the need for the task to run.
Goodness Spectrum
-----------------
-1000: never select this
0: re-examine entire list of tasks, not just runqueue
+ve: the larger, the better
+1000: realtime process, select this.
If the highest goodness values of all the tasks in the runqueue is zero,
then the scheduler takes a step back and looks at all of the tasks, not
just the ones in runqueue.
To give you an idea of how this is implemented, I've included a snippet
of the schedule() function and some of its more memorable lines:
asmlinkage void schedule(void)
{
struct schedule_data * sched_data;
struct task_struct *prev, *next, *p;
struct list_head *tmp;
int this_cpu, c;
:
:
/*
* this is the scheduler proper:
*/
repeat_schedule:
/*
* Default process to select..
*/
next = idle_task(this_cpu);
c = -1000;
list_for_each(tmp, &runqueue_head)
{
p = list_entry(tmp, struct task_struct, run_list);
if (can_schedule(p, this_cpu))
{
int weight = goodness(p, this_cpu, prev->active_mm);
if (weight > c){ c = weight, next = p; }
}
}
/* Do we need to re-calculate counters? */
if (unlikely(!c))
{
struct task_struct *p;
spin_unlock_irq(&runqueue_lock);
read_lock(&tasklist_lock);
for_each_task(p)
{
p->counter = (p->counter >> 1) + NICE_TO_TICKS(p->nice);
}
read_unlock(&tasklist_lock);
spin_lock_irq(&runqueue_lock);
goto repeat_schedule;
}
:
:
--[ 2.2 - Memory Management
A process both occupies and allocates memory. Once you have a task model
sketched out, you will need to give it access to a memory management
subsystem. Make sure to keep the interface to the memory subsystem clean,
so that you can yank it out and replace it later, if you need to.
On an OS level, memory protection is provided by two mechanisms:
i- segmentation
ii- paging
You will have to decide whether or not you want to support these two
features. Paging, in particular, is a hardware intensive task. This means
that if you do decide to provide paging facilities, porting the OS will
be difficult at best. According to Tanenbaum, this is the primary reason
why Minix does not support paging.
Segmentation can be enforced by hardware, or can be done manually via a
sand boxing technique at the kernel level. Almost everyone relies on
hardware based segmentation because it is faster. Like paging, hardware
based segmentation will necessarily involve a lot of hardware specific
code and a healthy dose of assembly language.
The MMURTL operating system breaks its virtual address space into three
segments. There's one code segment for the OS, one code segment for
applications, and a single data segment. This doesn't exactly protect
the applications from each other, but it does protect the OS.
MMURTL Segment Selector Value
-------------- --------------
OS code 0x08
Apps code 0x18
Apps data 0x10
MMURTL's memory subsystem is actually set up by the boot sector! That's
correct, I said the boot sector. If you look at the source code in
bootblok.asm, which Burgess compiles with TASM, you notice that the book
code does the book keeping necessary to make the transition to protected
mode. Here are a few relevant snippets from the file.
IDTptr DW 7FFh ;LIMIT 256 IDT Slots
DD 0000h ;BASE (Linear)
GDTptr DW 17FFh ;LIMIT 768 slots
DD 0800h ;BASE (Linear)
:
:
LIDT FWORD PTR IDTptr ;Load Processor ITD Pointer
LGDT FWORD PTR GDTptr ;Load Processor GDT Pointer
:
:
MOV EAX,CR0 ;Control Register
OR AL,1 ;Set protected mode bit
MOV CR0,EAX
JMP $+2 ;Clear prefetch queue with JMP
NOP
NOP
MOV BX, 10h ;Set up segment registers
MOV DS,BX
MOV ES,BX
MOV FS,BX
MOV GS,BX
MOV SS,BX
;We define a far jump
DB 66h
DB 67h
DB 0EAh
DD 10000h
DW 8h
; now in protect mode
Before he loaded GDTR and IDTR, Burgess loaded the OS into memory so that
the base address values in the selectors actually point to valid
global and interrupt descriptor tables. It also saves him from having
to put these data structures in the boot code, which helps because of
the 512 byte size limit.
Most production operating systems use paging as a way to augment the
address space which the OS manages. Paging is complicated, and involves
a lot of dedicated code, and this code frequently executes ... which
adds up to a tremendous loss in performance. Disk I/O is probably the
most costly operation an isolated computer can perform. Even with
the bookkeeping being pushed down to the hardware, paging eats up time.
Barry Brey, who is an expert on the Intel chip set, told me that paging on
Windows eats up about 10% of the execution time. In fact, paging is so
costly, in terms of execution time, and RAM is so cheap that it is
often a better idea to buy more memory and turn off paging anyways.
In light of this, you shouldn't feel like paging is a necessity. If you
are designing an embedded OS, you won't need paging anyways.
Back when primary memory cores were 16KB, and those little magnets were
big ticket items, paging probably made a whole lot more sense. Today,
however, buying a couple GB of SDRAM is not uncommon and this causes me
to speculate that maybe paging is a relic of the past.
--[ 2.3 - I/O interface
This is the scary part.
You now have processes, and they live in memory. But they cannot interact
with the outside world without connections to I/O devices. Connecting to
I/O devices is traditionally performed by sections of code called drivers,
which are traditionally buried in the bowels of the OS. As with other
components of the OS, you will have to use your assembly language skills.
In Intel protected mode, using the BIOS to get data to the screen is not
an option because the old real-mode way of handling interrupts and
addressing memory is no longer valid. One way to send messages to the
screen is to write directly to video memory. Most monitors, even flat
panels, start up in either VGA 80x25 monochrome text mode or VGA 80x25
color text mode.
memory region real-mode address linear address of buffer
------------- ----------------- ----------------------
monochrome text B000[0]:0000 B0000H
color text B800[0]:0000 B8000H
In either case, the screen can display 80 rows and 25 columns worth of
character data. Each character takes up two bytes in the video RAM memory
region ( which isn't so bad ... 80x25=2000x2=4000 bytes ). You can place
a character on the screen by merely altering the contents of video RAM.
The lower byte holds the ASCII character, and the high byte holds an
attribute.
The attribute bit is organized as follows:
bit 7 blink
---------------
bit 6
bit 5 background color ( 0H=black )
bit 4
---------------
bit 3
bit 2 foreground color ( 0EH=white )
bit 1
bit 0
To handle multiple screens, you merely create screen buffers and then
commit the virtual screen to video RAM when you want to see it.
For example, in protected mode the following code ( written with DJGPP )
will place a 'J' on the screen.
#include <sys/farptr.h>
#include <go32.h>
_farpokeb(_dos_ds, 0xB8000, 'J');
_farpokeb(_dos_ds, 0xB8000+1, 0x0F);
When I saw the following snippet of code in Minix's console.c file,
I knew that Minix used this technique to write to the screen.
#define MONO_BASE 0xB0000L /* base of mono video memory */
#define COLOR_BASE 0xB8000L /* base of color video memory */
:
:
PUBLIC void scr_init(tp)
tty_t *tp;
{
:
:
if (color)
{
vid_base = COLOR_BASE;
vid_size = COLOR_SIZE;
}
else
{
vid_base = MONO_BASE;
vid_size = MONO_SIZE;
}
:
:
Handling I/O to other devices on the Intel platform is no where nearly
as simple. This is where our old friend the 8259 Programmable Interrupt
Controller (PIC) comes into play. Recently I have read a lot in Intel
docs about an advanced PIC (i.e. APIC), but everyone still seems to be
sticking to the old interrupt controller.
The 8259 PIC is the hardware liaison between the hardware and the processor.
The most common setup involves two 8259 PICs configured in a master-slave
arrangement. Each PIC has eight interrupt request lines (IRQ lines) that
receive data from external devices ( i.e. the keyboard, hard drive, etc. ).
The master 8259 will use its third pin to latch on to the slave 8259
so that, all told, they provide 15 IRQ lines for external hardware. The
master 8259 then communicates to the CPU through the CPUs INTR interrupt
PIN. The slave 8259 uses it's INTR slot to speak to the master on its
third IRQ line.
Normally the BIOS will program the 8259 when then computer boots, but
to talk to hardware devices in protected mode, the 8259 must be
re-programmed. This is because the 8259 couples the IRQ lines to
interrupt signals. Programming the 8259 will make use of the IN and OUT
instructions. You basically have to send 8-bit values to the 8259's
interrupt command register (ICR) and interrupt mask register (IMR)
in a certain order. One wrong move and you triple-fault.
My favorite example of programming the 8259 PIC comes from MMURTL. The
following code is located in INITCODE.INC and is invoked during the
initialization sequence in MOS.ASM.
;=========================================================================
; This sets IRQ00-0F vectors in the 8259s
; to be Int20 thru 2F.
;
; When the PICUs are initialized, all the hardware interrupts are MASKED.
; Each driver that uses a hardware interrupt(s) is responsible
; for unmasking that particular IRQ.
;
PICU1 EQU 0020h
PICU2 EQU 00A0h
Set8259 PROC NEAR
MOV AL,00010001b
OUT PICU1+0,AL ;ICW1 - MASTER
jmp $+2
jmp $+2
OUT PICU2+0,AL ;ICW1 - SLAVE
jmp $+2
jmp $+2
MOV AL,20h
OUT PICU1+1,AL ;ICW2 - MASTER
jmp $+2
jmp $+2
MOV AL,28h
OUT PICU2+1,AL ;ICW2 - SLAVE
jmp $+2
jmp $+2
MOV AL,00000100b
OUT PICU1+1,AL ;ICW3 - MASTER
jmp $+2
jmp $+2
MOV AL,00000010b
OUT PICU2+1,AL ;ICW3 - SLAVE
jmp $+2
jmp $+2
MOV AL,00000001b
OUT PICU1+1,AL ;ICW4 - MASTER
jmp $+2
jmp $+2
OUT PICU2+1,AL ;ICW4 - SLAVE
jmp $+2
jmp $+2
MOV AL,11111010b ;Masked all but cascade/timer
; MOV AL,01000000b ;Floppy masked
OUT PICU1+1,AL ;MASK - MASTER (0= Ints ON)
jmp $+2
jmp $+2
MOV AL,11111111b
; MOV AL,00000000b
OUT PICU2+1,AL ;MASK - SLAVE
jmp $+2
jmp $+2
RETN
SET8259 ENDP
;=========================================================================
Note how Burgess performs two NEAR jumps after each OUT instruction. This
is to give the PIC time to process the command.
Writing a driver can be a harrowing experience. This is because drivers
are nothing less than official members of the kernel memory image. When
you build a driver, you are building a part of the OS. This means that
if you incorrectly implement a driver, you could be dooming your system
to a crash of the worst kind ... death by friendly fire.
Building drivers is also fraught with all sorts of vendor-specific byte
encoding and bit wise acrobatics. The best advise that I can give you is
to stick to widely-used, commodity, hardware. Once you have a working
console, you can attempt to communicate with a disk drive and then maybe
a network card.
You might want to consider designing your OS so that drivers can be
loaded and unloaded at runtime. Having to recompile the kernel to
accommodate a single driver is a pain. This will confront you with
creating an indirect calling mechanism so that the OS can invoke the
driver, even though it does not know in advance where that driver is.
The Linux kernel allows code to be added to the kernel at runtime
via loadable kernel modules (LKMs). These dynamically loadable modules
are nothing more than ELF object files ( they've been compiled, but
not officially linked ). There are a number of utilities that can
be used to manage LKMs. Two of the most common are insmod and rmmod,
which are used to insert and remove LKMs at runtime.
The insmod utility acts as a linker/loader and assimilates the LKM into
the kernel's memory image. Insmod does this by invoking the init_module
system call. This is located in /usr/src/linux/kernel/module.c.
asmlinkage long
sys_init_module(const char *name_user, struct module *mod_user){ ...
This function, in turn, invokes another function belonging to the LKM
which also just happens to be named init_module(). Here is a the
relevant snippet from sys_init_module():
/* Initialize the module. */
atomic_set(&mod->uc.usecount,1);
mod->flags |= MOD_INITIALIZING;
if (mod->init && (error = mod->init()) != 0)
{
atomic_set(&mod->uc.usecount,0);
mod->flags &= ~MOD_INITIALIZING;
if (error > 0) /* Buggy module */
error = -EBUSY;
goto err0;
}
atomic_dec(&mod->uc.usecount);
The LKM's init_module() function, which is pointed to by the kernel code
above, then invokes a kernel routine to register the LKMs subroutines.
Here is a simple example:
/* Initialize the module - Register the character device */
int init_module()
{
/* Register the character device (atleast try) */
Major = module_register_chrdev( 0,
DEVICE_NAME,
&Fops);
/* Negative values signify an error */
if (Major < 0)
{
printk ("%s device failed with %d\n",
"Sorry, registering the character",
Major);
return Major;
}
printk ("%s The major device number is %d.\n",
"Registeration is a success.",
Major);
printk ("If you want to talk to the device driver,\n");
printk ("you'll have to create a device file. \n");
printk ("We suggest you use:\n");
printk ("mknod <name> c %d <minor>\n", Major);
printk ("You can try different minor numbers %s",
"and see what happens.\n");
return 0;
}
The Unix OS, in an attempt to simply things, treats every device like a
file. This is done in order to keep the number of system calls down and
to offer a uniform interface from one hardware subsystem to the next.
This is an approach worth considering. However, on the other hand, the
Unix approach have not always gotten a good grade in terms of ease of use.
Specifically, I have heard complaints about mounting and un-mounting from
Windows users who migrate to Unix.
Note, If you do take the LKM route, you should be careful not to make
the loadable driver feature into a security flaw.
With regard to nuts-and-bolts details, for the Intel platform, I would
recommend Frank Van Gilluwe's book. If you are not targeting Intel, then
you have some real digging to do. Get on the phone and the internet and
contact your hardware vendors.
--[ 2.4 - File System
You now have processes, in memory, that can talk to the outside world.
The final step is to give them a way of persisting and organizing data.
In general, you will build the file system manager on top of the disk
drivers that you implemented earlier in the last step. If your OS is
managing an embedded system, you may not need to implement a file system
because no disk hardware exists. Even with embedded systems, though, I've
seen file systems implemented as RAM disks. Even embedded systems
sometimes need to produce and store log files ....
There are several documented files system specifications available to the
public, like the ext2 file system made famous by Linux. Here is the main
link for the ext2 implementation:
http://e2fsprogs.sourceforge.net/ext2.html
The documentation at this site should be sufficient to get you started.
In particular, there is a document named "Design and Implementation of
the Second Extended File System" which I found to be a well-rounded
introduction to ext2.
If you have the Linux kernel source and you want to take a look at the
basic data structures of the ext2fs, then look in:
/usr/src/linux/include/linux/ext2_fs.h
/usr/src/linux/include/linux/ext2_fs_i.h
To take a look at the functions that manipulate these data structures,
take a look in the following directory:
/usr/src/linux/fs/ext2
In this directory you will see code like:
#include <linux/module.h>
MODULE_AUTHOR("Remy Card and others");
MODULE_DESCRIPTION("Second Extended Filesystem");
MODULE_LICENSE("GPL");
in inode.c, and in super.c you will see:
EXPORT_NO_SYMBOLS;
module_init(init_ext2_fs)
module_exit(exit_ext2_fs)
Obviously, from the previous discussion, you should realize that support
for ext2fs can be provided by an LKM!
Some OS creators, like Burgess, go the way of the MS-DOS FAT file system,
for the sake of simplicity, and so they didn't have to reformat their
hard drives. I wouldn't recommend the FAT system. In general, you might
want to keep in mind that it is a good idea to implement a file system
which facilitates file ownership and access controls. More on this in the
next section ...
--[ 2.5 - Notes On Security
Complexity is the enemy of security. Simple procedures are easy to check
and police, complicated ones are not. Any certified accountant will tell
you that our Byzantine tax laws leave all sorts of room for abuse.
Software is the same way. Complicated source code has the potential to
provide all sorts of insidious places for bugs to hide. As operating
systems have evolved they have become more complicated. According to
testimony given by a Microsoft executive on Feb. 2, 1999, Windows 98
consists of over 18 million lines of code. Do you think there is a bug
in there somewhere? Oh, ... no ... Microsoft wouldn't sell buggy code ...
<picture Dr. Evil, a la Austin Powers, saying the previous sentence>
Security is not something that you want to add on to your OS when you are
almost done with it. Security should be an innate part of your system's
normal operation. Keep this in mind during every phase of construction,
from task management to the file system manager.
In addition, you might consider having a creditable third party perform
an independent audit of your security mechanisms before you proclaim
your OS as being 'secure.' For example, the NSA evaluates 'trusted'
operating systems on a scale from C2 to A1.
A 'trusted' OS is just an OS which has security policies in place. The
salient characteristic of a trusted system is the ranking which the
NSA gives it. A C2 trusted system has only limited access and
authentication controls. An A1 trusted system, at the other end of the
spectrum, has rigorous and mandatory security mechanisms.
People who have imaginary enemies are called 'paranoid.' People who have
enemies that they think are imaginary are called 'victims.' It's often
hard to tell the two apart until its too late. If I had to trust my
business to an OS, I would prefer to invest in one that errs on the side
of paranoia.
--[ 3 - Simple Case Study
In this section, I present you with some home-brewed system code in an
effort to highlight some of the issues that I talked about in Part 1.
--[ 3.1 - Host Platform
For a number of reasons, I decided to take a shortcut and create an OS
that runs on Intel 8x86 hardware. Cost was one salient issue, and so was
the fact that there are several potential host operating systems to choose
from ( Linux, OpenBSD, MMURTL, Windows, etc. ).
The primary benefit, however, is that I can avoid ( to an extent ) having
to build a cross-compiler and simulator from scratch. By having the host
and target systems run on the same hardware, I was able to take advantage
of existing tools that generated x86 binaries and emulated x86 hardware.
For the sake of appealing to the least common denominator, I decided to
use Windows as a host OS. Windows, regardless of its failings, happens
to be have the largest base of users. Almost anyone should be able to
follow the issues and ideas I discuss in Part 3.
One side benefit of choosing Windows is that it ships with its own
simulator. The DOS Virtual Machine subsystem is basically a crudely
implemented 8086 simulator. I say 'crude' because it doesn't have the
number or range of features that bochs provides. I actually tested a lot
of code within the confines of the DOS VM.
--[ 3.2 - Compiler Issues
There are dozens of C compilers that run on Windows. I ended up having
three requirements for choosing one:
i- generates raw binary ( i.e. MS .COM file )
ii- allow for special in-line instructions (i.e. INT, LGDT )
iii- is free
Intel PCs boot into real-mode, which means that I will need to start the
party with a 16-bit compiler. In addition, system code must be raw binary
so that runtime address fix ups do not have to be manually implemented.
This is not mandatory, but it would make life much easier.
The only commercial compilers that generated 16-bit, raw binary, files
passed out of fashion years ago ... so I had to do some searching.
After trolling the net for compilers, I ended up with the following matrix:
compiler decision reason
-------- -------- ------
TurboC NO in-line assembly requires TASM ($$$)
Micro-C YES generates MASM friendly output
PacificC NO does not support tiny MM (i.e. .COM)
Borland 4.5C++ NO costs $$$
VisualC++ 1.52 NO costs $$$
Watcom NO does not support tiny MM (i.e. .COM)
DJGPP NO AT&T assembler syntax ( yuck )
I Ended up working with Micro-C, even though it does not support the entire
ANSI standard. The output of Micro-C is assembler and can be fed to MASM
without to much trouble. Micro-C was created by Dave Dunfield and can be
found at:
ftp://ftp.dunfield.com/mc321pc.zip
Don't worry about the MASM dependency. You can now get MASM 6.1 for free
as a part of the Windows DDK. See the following URL for details:
http://www.microsoft.com/ddk/download/98/BINS_DDK.EXE
http://download.microsoft.com/download/vc15/Update/1/WIN98/EN-US/Lnk563.exe
The only downside to obtaining this 'free' version of MASM ( i.e. the
ML.EXE,ML.err, and LINK.EXE files ) is that they come with zero documents.
Ha ha, the internet to the rescue ....
http://webster.cs.ucr.edu/Page_TechDocs/MASMDoc
By using Micro-C, I am following the advice I gave in Part 1 and sticking
to the tools that I am skilled with. I grew up using MASM and TASM. I am
comfortable using them at the command line and reading their listing
files. Because MASM is the free tool I picked it over TASM, even if it is
a little buggy.
One problem with using most C compilers to create OS code is that they all
add formatting information to the executable files they generate. For
example, the current version of Visual C++ creates console binaries that
obey the Portable Executable (PE) file format. This extra formatting is
used by the OS program loader at runtime.
Compilers also tack on library code to their executables, even when they
don't need it.
Consider a text file named file.c consisting of the code:
void main(){}
I am going to compile this code as a .COM file using TurboC. Take a look at
the size of the object file and final binary.
C:\DOCS\OS\lab\testTCC>tcc -mt -lt -ln file.c
C:\DOCS\OS\lab\testTCC>dir
. <DIR> 03-29-02 9:26p .
.. <DIR> 03-29-02 9:26p ..
FILE C 19 03-30-02 12:07a file.c
FILE OBJ 184 03-30-02 12:09a FILE.OBJ
FILE COM 1,742 03-30-02 12:09a file.com
Holy smokes... there's a mother load of ballast that the compiler adds on.
This is strictly the doing of the compiler and linker. Those bastards!
To see how excessive this actually is, let's look at a .COM file which
is coded in assembler. For example, let's create a file.asm that looks
like:
CSEG SEGMENT
start:
ADD ax,ax
ADD ax,cx
CSEG ENDS
end start
We can assemble this with MASM
C:\DOCS\OS\lab\testTCC>ml /AT file.asm
C:\DOCS\OS\lab\testTCC>dir
. <DIR> 03-29-02 9:26p .
.. <DIR> 03-29-02 9:26p ..
FILE OBJ 53 03-30-02 12:27a file.obj
FILE ASM 67 03-30-02 12:27a file.asm
FILE COM 4 03-30-02 12:27a file.com
5 file(s) 187 bytes
2 dir(s) 7,463.23 MB free
As you can see, the executable is only 4 bytes in size! The assembler
didn't add anything, unlike the C compiler, which threw in everything but
the kitchen sink. In all likelihood, the extra space is probably taken
up by libraries which the linker appends on.
The painful truth is, unless you want to build your own backend to a
C compiler, you will be faced with extra code and data on your OS binary.
One solution is simply to ignore the additional bytes. Which is to say
that the OS boot loader will simply skip the formatting stuff and go right
for the code which you wrote. If you decide to take this route, you might
want to look at a hex dump of your binary to determine the file offset at
which your code begins.
I escaped dealing with this problem because Micro-C's C compiler (MCC)
spits out an assembly file instead of object code. This provided me with
the opportunity to tweak and remove any extra junk before it gets a
chance to find its way into the executable.
However, I still had problems...
For example, the MCC compiler would always add extra segments and
place program elements in them. Variables translated to assembler would
always be prefixed with these unwanted segments (i.e. OFFSET DGRP:_var ).
Take the program:
char arr[]={'d','e','v','m','a','n','\0'};
void main(){}
MCC will process this file and spit out:
DGRP GROUP DSEG,BSEG
DSEG SEGMENT BYTE PUBLIC 'IDATA'
DSEG ENDS
BSEG SEGMENT BYTE PUBLIC 'UDATA'
BSEG ENDS
CSEG SEGMENT BYTE PUBLIC 'CODE'
ASSUME CS:CSEG, DS:DGRP, SS:DGRP
EXTRN ?eq:NEAR,?ne:NEAR,?lt:NEAR,?le:NEAR,?gt:NEAR
EXTRN ?ge:NEAR,?ult:NEAR,?ule:NEAR,?ugt:NEAR,?uge:NEAR
EXTRN ?not:NEAR,?switch:NEAR,?temp:WORD
CSEG ENDS
DSEG SEGMENT
PUBLIC _arr
_arr DB 100,101,118,109,97,110,0
DSEG ENDS
CSEG SEGMENT
PUBLIC _main
_main: PUSH BP
MOV BP,SP
POP BP
RET
CSEG ENDS
END
Rather than re-work the backend of the compiler, I implemented a more
immediate solution by creating a hasty post-processor. The alternative
would have been to manually adjust each assembly file that MCC produced,
and that was just too much work.
The following program ( convert.c ) creates a skeleton .COM program of the
form:
.486
CSEG SEGMENT BYTE USE16 PUBLIC 'CODE'
ORG 100H ; for DOS PSP only, strip and start OS on 0x0000 offset
here:
JMP _main
; --> add stuff here <----
EXTRN ?eq:NEAR,?ne:NEAR,?lt:NEAR,?le:NEAR,?gt:NEAR
EXTRN ?ge:NEAR,?ult:NEAR,?ule:NEAR,?ugt:NEAR,?uge:NEAR
EXTRN ?not:NEAR,?switch:NEAR,?temp:WORD
CSEG ENDS
END here
It then picks out the procedures and data elements in the original
assembly program and places them in the body of the skeleton. Here is the
somewhat awkward, but effective program that performed this task:
/* convert.c------------------------------------------------------------*/
#include<stdio.h>
#include<string.h>
/* read a line from fptr, place in buff */
int getNextLine(FILE *fptr,char *buff)
{
int i=0;
int ch;
ch = fgetc(fptr);
if(ch==EOF){ buff[0]='\0'; return(0); }
while((ch=='\n')||(ch=='\r')||(ch=='\t')||(ch==' '))
{
ch = fgetc(fptr);
if(ch==EOF){ buff[0]='\0'; return(0); }
}
while((ch!='\n')&&(ch!='\r'))
{
if(ch!=EOF){ buff[i]=(char)ch; i++; }
else
{
buff[i]='\0';
return(0);
}
ch = fgetc(fptr);
}
buff[i]='\r';i++;
buff[i]='\n';i++;
buff[i]='\0';
return(1);
}/*end getNextLine*/
/* changes DGRP:_variable to CSEG:_variable */
void swipeDGRP(char *buff)
{
int i;
i=0;
while(buff[i]!='\0')
{
if((buff[i]=='D')&&
(buff[i+1]=='G')&&
(buff[i+2]=='R')&&
(buff[i+3]=='P'))
{
buff[i]='C';buff[i+1]='S';buff[i+2]='E';buff[i+3]='G';
}
if((buff[i]=='B')&&
(buff[i+1]=='G')&&
(buff[i+2]=='R')&&
(buff[i+3]=='P'))
{
buff[i]='C';buff[i+1]='S';buff[i+2]='E';buff[i+3]='G';
}
i++;
}
return;
}/*end swipeDGRP*/
void main(int argc, char *argv[])
{
FILE *fin;
FILE *fout;
/*MASM allows lines to be 512 chars long, so have upper bound*/
char buffer[512];
char write=0;
fin = fopen(argv[1],"rb");
printf("Opening %s\n",argv[1]);
fout = fopen("os.asm","wb");
fprintf(fout,".486P ; enable 80486 instructions\r\n");
fprintf(fout,"CSEG SEGMENT BYTE USE16 PUBLIC \'CODE\'\r\n");
fprintf(fout,";\'USE16\' forces 16-bit offset addresses\r\n");
fprintf(fout,"ASSUME CS:CSEG, DS:CSEG, SS:CSEG\r\n");
fprintf(fout,"ORG 100H\r\n");
fprintf(fout,"here:\r\n");
fprintf(fout,"JMP _main\r\n\r\n");
fprintf(fout,"EXTRN ?eq:NEAR,?ne:NEAR,?lt:NEAR,?le:NEAR,?gt:NEAR\r\n");
fprintf(fout,"EXTRN ?ge:NEAR,?ult:NEAR,?ule:NEAR,?ugt:NEAR,?uge:NEAR\r\n");
fprintf(fout,"EXTRN ?not:NEAR,?switch:NEAR,?temp:WORD\r\n\r\n");
while(getNextLine(fin,buffer))
{
if((buffer[0]=='P')&&
(buffer[1]=='U')&&
(buffer[2]=='B')&&
(buffer[3]=='L')&&
(buffer[4]=='I')&&
(buffer[5]=='C')){ fprintf(fout,"\r\n"); write=1;}
if((buffer[0]=='D')&&
(buffer[1]=='S')&&
(buffer[2]=='E')&&
(buffer[3]=='G')){ write=0;}
if((buffer[0]=='B')&&
(buffer[1]=='S')&&
(buffer[2]=='E')&&
(buffer[3]=='G')){ write=0;}
if((buffer[0]=='R')&&
(buffer[1]=='E')&&
(buffer[2]=='T')){ fprintf(fout,"%s",buffer); write=0;}
if(write)
{
swipeDGRP(buffer);
fprintf(fout,"%s",buffer);
}
buffer[0]='\0';
}
fprintf(fout,"CSEG ENDS\r\n");
fprintf(fout,"END here\r\n");
fclose(fin);
fclose(fout);
return;
}/*end main-------------------------------------------------------------*/
--[ 3.3 - Booting Up
In the following discussion, I'm going to discuss booting from a floppy
disk. Booting from a hard drive, CD-ROM, or other storage device is
typically a lot more complicated due to partitioning and device formatting.
OK, the first thing I'm going to do is build a boot program. This program
has to be small. In fact, it has to be less than 512 bytes in size because
it has to fit on the very first logical sector of the floppy disk. Most
1.44 floppy disks have 80 tracks per side and 18 sectors per track. The
BIOS labels the two sides ( 0,1 ), tracks 0-79, and sectors 1-18.
When an Intel machine boots, the BIOS firmware (which resides
in a ROM chip on the motherboard) will look for a bootable storage
device. The order in which it does so can be configured on most machines
via a BIOS startup menu system. If the BIOS finds a boot diskette, it will
read the diskettes boot sector (Track 0, Side 0 and Sector 1) into memory
and execute the boot sector code. Some times this code will do nothing
more than print a message to the screen:
Not a boot disk, you are hosed.
All 8x86 machines start in real-mode, and the boot sector is loaded into
memory at the address 0000[0]:7C00 ( or 0x07C00 ) using hexadecimal. Once
this occurs, the BIOS washes its hands of the booting procedure and we
are left to our own devices.
Many operating systems will have the boot sector load a larger boot
program, which then loads the OS proper. This is known as a multi-stage
boot. Large operating systems that have a lot of things to set up,
a complicated file structure, and flexible configuration, will utilize
a multi-stage boot loader. A classic example of this is GNU's GRand
Unified Bootloader ( GRUB ).
http://www.gnu.org/software/grub
As usual, I am going to take the path of least resistance. I am going to
have the boot sector directly load my system code. The boot sector assumes
that the system code will be located directly after the boot sector
(track 0, side, 0, sector 2 ). This will save me from including special
data and instructions to read a file system. Finally, because of size
constraints, all the code in this section will be written in assembler.
The boot code follows:
;-boot.asm----------------------------------------------------------------
.8086
CSEG SEGMENT
start:
; step 1) load the OS on floppy
; to location above the
; existing interrupt table (0-3FF)
; and BIOS data region (400-7FF)
MOV AH,02H ; read command
MOV AL,10H ; 16 sectors = 8KB of storage to load
MOV CH,0H ; low 8 bits of track number
MOV CL,2H ; sector start ( right after boot sector )
MOV DH,0H ; side
MOV DL,0H ; drive
MOV BX,CS
MOV ES,BX ; segment to load code
MOV BX,0H
MOV BX,800H ; offset to load code ( after IVT )
INT 13H
; signal that code was loaded and we are going to jump
MOV AH,0EH
MOV AL,'-'
INT 10H
MOV AH,0EH
MOV AL,'J'
INT 10H
MOV AH,0EH
MOV AL,'M'
INT 10H
MOV AH,0EH
MOV AL,'P'
INT 10H
MOV AH,0EH
MOV AL,'-'
INT 10H
; step 2) jump to the OS
; bonzai!!!
JMP BX
CSEG ENDS
END start
;-end file----------------------------------------------------------------
This boot loader also assumes that the system code to be loaded lies
in sectors 2-17 on the first track. As the OS gets bigger ( beyond 8K ),
extra instructions will be needed to load the additional code. But for now
lets assume that the code will be less than 8K in size.
OK, you should build the above code as a .COM file and burn it on to the
boot sector. The boot.asm file is assembled via:
C:\> ML /AT boot.asm
How do you do burn it on to the floppy disk's boot sector?
Ah ha! Debug to the rescue. Note, for big jobs I would recommend rawrite.
This is such a small job that debug will suffice. Not to mention, I have
nostalgic feeling about debug. I assembled my first program with it; back
in the 1980s when parachute pants were in.
Assuming the boot code has been assembled to a file named boot.COM, here
is how you would write it to the boot sector of a floppy disk.
C:\DOCS\OS\lab\bsector>debug showmsg.com
-l
-w cs:0100 0 0 1
-q
C:\DOCS\OS\lab\bsector>
The 'l' command loads the file to memory starting at CS:0100 hex.
The 'w' command writes this memory to disk A ( 0 ) starting at sector 0
and writing a single sector. The 'w' command has the general form:
w address drive start-sector #-sectors
Note, DOS sees logical sectors ( which start with 0 ), whereas
physical (BIOS manipulated) sectors always start with 1.
If you want to test this whole procedure, assemble the following program
as a .COM file and burn it on to the boot sector of a diskette with debug.
.486
CSEG SEGMENT
start:
MOV AH,0EH
MOV AL,'-'
INT 10H
MOV AH,0EH
MOV AL,'h'
INT 10H
MOV AH,0EH
MOV AL,'i'
INT 10H
MOV AH,0EH
MOV AL,'-'
INT 10H
lp LABEL NEAR
JMP lp
CSEG ENDS
END start
This will print '-hi-' to the console and then loop. It's a nice way to
break the ice and build your confidence. Especially if you've never
manually meddled with disk sectors.
--[ 3.4 - Initializing The OS
The boot sector loads the system code binary into memory and then sets
CS and IP to the first ( lowest ) byte of the code's instructions. My
system code doesn't do anything more than print a few messages and then
jump to protected mode. Execution ends in an infinite loop.
I wrote the program using real-mode instructions. Intel machines all
start up in real-mode. It is the responsibility of this initial code to
push the computer into protected memory mode. Once in protected mode,
the OS will adjust its segment registers, set up a stack, and establish
an execution environment for applications ( process table, drivers, etc.).
This made life difficult because if I could only go so far using
real-mode instructions and registers. Eventually, I would need to
use the extended registers (i.e. EAX ) to access memory higher up.
Some compilers won't accept a mixture of 16-bit and 32-bit
instructions, or they get persnickety and encode instructions incorrectly.
If you look at the FAR JMP that I make at the end of setUpMemory(), you'll
notice that I had to code it manually.
My situation was even more tenuous because I was fitting everything into a
single segment. Once I had made the translation to protected mode, there
wasn't that much that I could do that was very interesting.
One solution would be to convert my 16-bit system code into the second
phase of a multi-stage boot process. In other words, have the system code,
which was loaded by the boat sector, load a 32-bit binary into memory
before it makes the transition to protected mode. When the FAR JMP is
executed, it could send execution to the 32-bit code ... which could then
take matters from there. If you look at MMURTL, you will see that this
is exactly what Burgess does. Doh! I just wish I had known sooner.
I was excited initially by the thought of being able to leverage the Micro-
C compiler. However, as you will see, most of the set up work was done
via in-line assembly. Only small portions were pure C. This is the nature
of initializing an OS. Key memory and task management functions are
anchored directly to the hardware, and the best that you can hope for is
to bury the assembly code deep in the bowels of the OS and wrap everything
in C.
Here is the system code (os.c), in all its glory:
/* os.c ----------------------------------------------------------------*/
void printBiosCh(ch)
char ch;
{
/*
ch = BP + savedBP + retaddress = BP + 4 bytes
*/
asm "MOV AH,0EH";
asm "MOV AL,+4[BP]";
asm "INT 10H";
return;
}/*end printBiosCh---------------------------------------*/
void printBiosStr(cptr,n)
char* cptr;
int n;
{
int i;
for(i=0;i<n;i++){ printBiosCh(cptr[i]); }
return;
}/*end printBiosStr--------------------------------------*/
void setUpMemory()
{
/*going to protected mode is an 6-step dance*/
/* step 1) build GDT ( see GDT table in function below )*/
printBiosCh('1');
/*
step 2) disable interrupts so we can work undisturbed
( note, once we issue CLI, we cannot use BIOS interrupts
to print data to the screen )
*/
printBiosCh('2');
asm "CLI";
/*
step 3) enable A20 address line via keyboard controller
60H = status port, 64H = control port on 8042
*/
asm "MOV AL,0D1H";
asm "OUT 64H,AL";
asm "MOV AL,0DFH";
asm "OUT 60H,AL";
/*
step 4) execute LGDT instruction to load GDTR with GDT info
recall GDTR = 48-bits
= [32-bit base address][16-bit limit]
HI-bit LO-bit
*/
asm "JMP overRdata";
asm "gdtr_stuff:";
asm "gdt_limit DW 0C0H";
asm "gdt_base DD 0H";
asm "overRdata:";
/*
copy GDT to 0000[0]:0000 ( linear address is 00000000H )
makes life easier, so don't have to modify gdt_base
REP MOVSB moves DS:[SI] to ES:[DI] until CX=0
*/
asm "MOV AX,OFFSET CS:nullDescriptor";
asm "MOV SI,AX";
asm "MOV AX,0";
asm "MOV ES,AX";
asm "MOV DI,0H";
asm "MOV CX,0C0H";
asm "REP MOVSB";
asm "LGDT FWORD PTR gdtr_stuff";
/* step 5) set first bit in CR0, protected mode bit*/
asm "smsw ax";
asm "or al,1";
asm "lmsw ax";
/*
step 6) perform a manually coded FAR JUMP
( MASM would encode it incorrectly in 'USE16' mode )
*/
asm "DB 66H";
asm "DB 67H";
asm "DB 0EAH";
asm "DW OFFSET _loadshell";
asm "DW 8H";
/* end of the line, infinite loop */
asm "_loadshell:";
asm "NOP";
asm "JMP _loadShell";
return;
}/*end setUpMemory---------------------------------------*/
/* our GDT has 3 descriptor (null,code,data)*/
void GDT()
{
/*
end up treating the function body as data
( can treat code as data as long as we don't execute it ;-))
*/
asm "nullDescriptor:";
asm "NDlimit0_15 dw 0 ; seg. limit";
asm "NDbaseAddr0_15 dw 0 ; base address";
asm "NDbaseAddr16_23 db 0 ; base address";
asm "NDflags db 0 ; segment type and flags";
asm "NDlimit_flags db 0 ; segment limit and flags";
asm "NDbaseAddr24_31 db 0 ; final 8 bits of base address";
asm "codeDescriptor:";
asm "CDlimit0_15 dw 0FFFFH";
asm "CDbaseAddr0_15 dw 0";
asm "CDbaseAddr16_23 db 0";
asm "CDflags db 9AH";
asm "CDlimit_flags db 0CFH";
asm "CDbaseAddr24_31 db 0";
asm "dataDescriptor:";
asm "DDlimit0_15 dw 0FFFFH";
asm "DDbaseAddr0_15 dw 0";
asm "DDbaseAddr16_23 db 0";
asm "DDflags db 92H";
asm "DDlimit_flags db 0CFH";
asm "DDbaseAddr24_31 db 0";
return;
}/*end GDT-----------------------------------------------*/
char startStr[7] = {'S','t','a','r','t','\n','\r'};
char startMemStr[10] = {'I','n','i','t',' ','m','e','m','\n','\r'};
char tstack[128];
void main()
{
/*set up temp real-mode stack*/
asm "MOV AX,CS";
asm "MOV SS,AX";
asm "MOV AX, OFFSET CSEG:_tstack";
asm "ADD AX,80H";
asm "MOV SP,AX";
/*successfully made JMP to OS from boot loader*/
printBiosStr(startStr,7);
/*set up Basic Protected Mode*/
printBiosStr(startMemStr,10);
setUpMemory();
return;
}/*end main-------------------------------------------------------------*/
--[ 3.5 - Building and Deploying
Because the OS was written in C and in-line assembler, the build
process involved three distinct steps. First, I compiled my system code to
assembly with:
mcp os.c | mcc > osPre.asm
Note, mcp is Micro-C's pre-processor.
Chuck it all in one 16-bit segment:
convert osPre.asm
Once I had an .ASM file in my hands, I assembled it:
ML /Fllist.txt /AT /Zm -c osPre.asm
Note how I've had to use the /Zm option so that I can assemble code that
obeys conventions intended for earlier versions of MASM. This step is
typically where the problems occurred. Needless to say, I became tired of
fixing up segment prefixes rather quickly and that is what led me to
write convert.c.
Finally, after a few tears, I linked the OS object file to one of Micro-C's
object files.
LINK os.obj PC86RL_T.OBJ /TINY
If you look back at convert.c, you'll see a whole load of EXTRN directives.
All of these imported symbols are math libraries that are located in the
PC86RL_T.OBJ file.
If you have a copy of NASM on your machine, you can verify your work with
the following command:
ndisasmw -b 16 os.com
This will dump a disassembled version of the code to the screen. If you
want a more permanent artifact, then use the listing file option when you
invoke ML.EXE:
ML /AT /Zm /Fl -c os.asm
Once you have the OS and boot sector code built. You should burn them on
to the boot floppy. You can do so with the DOS debug utility.
C:\DOCS\OS\lab\final>debug boot.com
-l
-w cs:0100 0 0 1
-q
C:\DOCS\OS\lab\final>debug os.com
-l
-w cs:0100 0 1 2
-q
After that, you just boot with the floppy disk and hang on!
I hope this article gave you some ideas to experiment with. Good luck
and have fun.
"Contrasting this modest effort [of Seymour Cray in his laboratory to
build the CDC 6600] with 34 people including the janitor with our vast
development activities, I fail to understand why we have lost our
industry leadership position by letting someone else offer the world's
most powerful computer."
-Thomas J. Watson, IBM President, 1965
"It seems Mr. Watson has answered his own question."
-Seymour Cray
--[ 4 - References and Credits
[1] Operating Systems: Design And Implementation,
Andrew S. Tanenbaum, Prentice Hall, ISBN: 0136386776
This book explains how the Minix operating system functions.
Linux was originally Linus's attempt at creating a production
quality version of Minix. Minix is an Intel OS.
[2] MMURTL V1.0, Richard A. Burgess, Sensory Publishing, ISBN: 1588530000
MMURTL is another Intel OS. Unlike Tanenbaum, Burgess dives
into more sophisticated topics, like memory paging. Another
thing I admire about Burgess is that he'll answer your e-mail
without getting snooty like Tanenbaum. If Minix gave birth to
Linux, then MMURTL may also be reincarnated as the next big thing.
[3] Dissecting DOS, Michael Podanoffsky, Addison-Wesley Pub,
ISBN: 020162687X
In this book, Podanoffsky describes a DOS clone named RxDOS.
RxDOS is presented as a real-mode OS and is written entirely
in assembly code.
[4] FreeDOS Kernel, Pat Villani, CMP Books, ISBN: 0879304367
Another DOS clone ... but this one is written in C, whew!
[5] Virtual Machine Design and Implementation In C/C++, Bill Blunden,
Wordware Publishing, ISBN: 1556229038
Yes, it's time for the self-plug. Writing a VM is really only a
hop, skip, and a jump, from writing a simulator. My book presents
all the information in this article and a whole lot more. This
includes a complete virtual machine, assembler, and debugger.
[6] Linux Core Kernel Commentary, 2nd Edition, Scott Andrew Maxwell,
The Coriolis Group; ISBN: 1588801497
This is an annotated stroll through the task and memory management
source code of Linux.
[7] The Design and Implementation of the 4.4BSD Operating System,
Marshall Kirk McKusick (Editor), Keith Bostic, Michael J. Karels (Editor)
Addison-Wesley Pub Co; ISBN: 0201549794
These guys are all deep geeks. If you don't believe me, look
at the group photo on the inside cover. This book is a
comprehensive overview of the FreeBSD OS.
[8] The Undocumented PC : A Programmer's Guide, Frank Van Gilluwe,
Addison-Wesley Pub, ISBN: 0201479508
If you're doing I/O on Intel, it truly helps to have this book.
[9] Control Data Corporation
There are a numerous old fogeys from Control Data that I
would like to thank for offering their help and advice.
Control Data was killed by its management, but there
were a handful of gifted engineers, like Cray, who made sure
that some of the good ideas found a home.
[10] IBM and the Holocaust: The Strategic Alliance Between Nazi Germany
and America's Most Powerful Corporation, Edwin Black,
Three Rivers Press; ISBN: 0609808990
I originally heard about this through one of Dave Emory's
radio broadcasts. Mae Brussell would agree ... profit at
any cost is not a good thing.
I would like to thank George Matkovitz, who wrote the first message-based
kernel in the world, and Mike Adler, a compiler wizard who was there
when Cray whipped IBM for sharing their thoughts and experiences with me.
<EOF>
|=[ 0x03 ]=--------------------------------------------------------------=|
L O C K P I C K I N G
BY
/< n i g h t m a r e
As per usual, I accept no responsibility for your actions using this
file; It is only here to show how locksmiths gain access when keys are
missing or broken.
CONTENTS
INTRODUCTION
1 The warded Lock
2 Pin-tumbler lock and wafer locks
3 Wafer locks
4 The tension wrench turning tool
5 Raking pin-tumbler locks and wafer cylinder locks
6 Picking locks without a Turning tool
7 The lock gun
9 Pure picking
10 Opening locks without picking
11 Rapping open locks
12 TOOLS AND APPARATUS
INTRODUCTION
The main purpose of writing this work is to provide the modern student with
an up-to-date, accurate book to enable him to explore the fascinating
subject of lock picking. In by gone years, people who were drawn to magic of
the lock, were tempted to 'pick locks', and were confronted by obstacles to
protect the lock, such as devices which would shoot steel barbs into the
picker's hands. vicious toothed jaws were employed to cut off the thiefs
fingers. perhaps the most fearsome lock pick deterrent was a devilish device
which would fire a bullet if the locking mechanism was tampered with.
Books and manuscripts over the years change hands.
Unfortunately, in the case of this type of work, it could fall into the
wrong hands. However unlike such works as '1001 ways to have fun with a
Frankfurter', the person who is merely curious will find this work tiresome
and unpalatable, leaving the true enthusiasts to explore the teasing allure
of the lock. This unique animal who has ingenuity and patience to follow
through the fascinating study, will be rewarded in the knowledge that he is
in the elite company that I salute in this work. for the people who argue
books on this subject should not be written, I would like to point out that
a villain who wishes to gain entry into a property in happier with a brick
than a pick.
Have fun and enjoy your new hobby or trade !
CHAPTER 1: THE WARDED LOCK
Probably the best place to begin this book is at the point at which mass
lock manufacture began, with the WARDED LOCK. These locks are generally of
simple construction, These are of simple construction and generally, and
therefore recommended for the beginner. The dictionary defines 'ward' as 'to
guard, keep away, or to fend off', which in reality is exactly what the lock
does.
(See FIG. 1.) The small circular section is the ward with the wrong type of
key attempting to open the lock. Ti is quite obvious that if this key were
to be turned, its turning path would be halted by the protruding ward.
___________ ____ __________ ____
________ ) / \ \ ______ ) / \ \
| _| | | | <-Wards | [ | | |
|[ \____/ Bit -> |__[ \____/
FIG. 1 FIG. 2
FIG. 2 shows the correct key which will open the warded lock.
It has just the right cuts on the bit to miss the wards. warded locks are
found in many forms. FIG. 3 is a normal key, with an intricate patterned bit
which would open an old and beautifully designed, elaborate ward lock. At
this point, I would like to say that key collecting had become a hobby for
many people. Since keys are quite easy to come by, a nice display can soon
be obtained.
__
/ \__.,-,________
\__/--.,-,--------'
[]
[[
Normal Key
FIG. 3
the security of the warded lock was further enhanced by the shape of the key
hole, preventing entry to everything apart from the correct key. the
extravagant shapes, in both the wards and the key holes, are the only
problems which we must overcome in picking open the warded lock. we do this
by inserting a pick, which is much thinner than the lock's keyhole, or by
using a skeleton key. FIG. 5 shows this best in the case of the skeleton
key, which would open the same lock which is in our FIG. 3. This skeleton
key has been cut from a blank. The area which would fool the locks ward's
has been removed, forming the new key. For the complete newcomer the world
of locks, I should explain that the word 'blank' is the name given to the
key before it is cut to the desired shape.
______ __.__________
| /\ | __ __ __ __|
| || | ' _|| ||_
| \\ | |.-' '-.|
| // | || ||
| C| | skeleton|'-. .-'|
| || | key '--' '--'
|______|
FIG. 4 FIG. 5
FIG. 6 looks inside a typical warded padlock. It is clear that, because of
the wards which obstruct the turning, only the correct key (as shown) will
open this lock. it is guarded by six, close-fitting wards, and also by the
small, thin keyhole.
_____
/ ___ \
__/ / \ \__
| \___/ |
\ /
\____ ____/
/ \
______| |______
| __ ( ) __ |
.---> | (__| | | |__) |
| | < > |
Wards ---|---> | ====| |==== |
| | ( ) |
'---> | =====|_ _|===== |
| [[[[(_____)]]]] |
| (_) |
|_________________|
Y Y
| |
Opening spring
FIG. 7 shows how we overcome this lock with a key that has been skeletoned,
and which will now open this and many others.
This has been achieved by removing all the projections other than the end
which comes into contact with the spring-opening point.
Take a look and make sure you read and understand this before moving on.
__
_ __nn_n/ \_
(_| |______ o_:
_ __ _\__/
U UU U
FIG. 7
FIG. 8 is a warded pick in it's most simple form - a coil spring with it's
end bend and flattened. If the coil is of suitable diameter, it will fit
onto the end of your index finger. This forms, as it were, an extension of
your finger, and you will find that it is a highly sensitive tool to fell
the layout of the interior and so find and trigger the mechanism. This
sensitive manipulation can be achieved only with practice. If the spring
pick becomes weak or bent simply pull out a new length from the coil and you
have a brand new tool.
Before we move on, I would suggest that you build up a large set of picks
of different sizes.
________________________________________
| ____ |
| /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ | |
|________________________________________|
Coil Spring
FIG. 8
Look inside as many locks as possible -- it's the finest way of becoming a
lock expert. picking locks is a true art form and even more difficult than
learning to play a musical instrument proficiently.
Here is a useful lock picking set to make:
____
/ \_____________|
\____/ |
____
/ \_____________.
\____/ '
____
/ \___________._.
\____/ ' '
____
/ \_____________
\____/ |
____
/ \___________|_|
\____/ | |
____
/ \____________.-
\____/ '-
FIG. 9
In summing up the subject of warded locks, I would say that once you have
clearly understood that the wards simply guard the opening, and also that
the actual shape of the keyhole prevents the wrong key entering, you are
well on the right path to becoming a total master at this type of lock.
start looking for warded locks: they are usually older locks or at the cheap
end of the market.
The most difficult task before the novice must be to identify the particular
type of lock he is trying to pick. Is the lock a WAFER or PIN-TUMBLER? Or,
in the case of the raw beginner, is the lock a LEVER or PIN-TUMBLER? There
is no simple answer. The ability to identify the particular types comes only
with practice and study.
Open up as many old locks as you can and study the principles, LOOKING ALL
THE TIME FOR WEAK POINTS which are built into the design. Believe me, ALL
locks have weak points.
CHAPTER 2: PIN TUMBLER and WAFER LOCKS
As in all lock picking, it is an advantage that the student is fully
conversant with the basic operation of the lock. In the case of the
PIN-TUMBLER and WAFER it is absolutely vital. The number of times I have
read leading works on the subject, and then asked myself if I would fully
understand how the lock worked from their description ! each book I read
failed to explain accurately and precisely how these locks work and can be
picked. what follows is my own humble effort to right this wrong. You
yourself must judge if I have obtained this objective.
When we first look at this type of lock, it would appear that all
necessary to insert a small implement into the keyway and give it a turn for
the device to open. plainly this is not the case, as we can see when we take
a closer look at FIG. 10 This is a typical PIN-TUMBLER lock, and generally
consists of pairs of bottom pins made from brass and with the top drivers
formed in steel. Commonly, five pairs of pins are found. in the smaller,
cheaper models, four are more common.
______________________________
\ K
| | | | | | / E
| | | | \ Y [|] Upper tumbler pin
^ ^ / H [^] Lower tumbler pin
^ ^ ^ ^ ^ ^ \ O [-] Cylinder wall
/ L This is a greatly simplified
\ E drawing
______________________________/
FIG. 10
_______
Shear Line / ___ \
- - - - -| |///| | <-- Springs
/ |[ ]|<-\----- Top Drivers
Plug\ \ @ /<-/----- Bottom Pins
\___|___/
Key
FIG. 11
_______
Shear Line / ___ \
- - - - -| |///| |
/ |[ ]| /\
\ / / / <-- Plug Turning
\___///_/
FIG. 11a
________
/ \
Shearing Line --> __ _ ___ _ ___ _ ___ / \ A
/ _ _ _ _ _ \/ /\ \
/ |_||_||_||_||_| ___/\ \/ / K
\ / \/\/\/\/\/\/\____\/ / E
\____________________/\__________/ Y
FIG. 12
FIG. 11 is the end-view of the arrangement. Each of the locks shown in FIGS.
10, 11 and 12 are ready to open, since in each case they have been given the
right key ready to turn the plug.
FIG. 12 shows each of the five bottom brass pins settled into it's own notch
along the key. This ha the effect of bringing the point between the drivers
and the pins EXACTLY to the same height. ONLY THE PROPER KEY WILL ALIGN ALL
FIVE PINS AT THIS HEIGHT, WHICH WE CALL THE SHEAR OR SHEARING LINE, AT THE
SAME TIME. All five pins must be in line together, and, when we have this
state of affairs, the plug will turn opening the lock. FIG. 11a shows the
plug starting to turn. FIG. 11 is an end-view, and shows the shaded plug
ready to turn. Make sure you fully understand this before you go on. Most
students fail to understand that the bottom brass pins TURN WITH THE PLUG.
FIG. 13 shows this. the top holding drivers stay put in the chambers in the
outer case. Remember that the bottom pins must turn with the plug because
they are contained within unit. It is important to know that if only one
notch on the key is even SLIGHTLY wrong, too high or too low, the plug would
be prevented from turning, just one pin, sitting into this plug from the
outer case, has such an amazing strength that it would be impossible to snap
-- such is the power of each little pin.
:::::
___ ##### <-- Top Drivers
/ \ooooo Plug Turning |
\___/===== <'
OOOOO <-- Bottom pins
FIG. 13
I have cut away the plug in FIG. 13 and the pins can clearly be seen in the
turning motion. With all the required points within the lock aligned, the
plug must and will turn. However, let us take a look at what would happen if
the wrong key were inserted. FIG. 14 shows this, with the top drivers, still
inside the plugs, preventing it from turning. The wrong key is just as bad
as no key, and the lock stays locked.
Chambers
______/___|___\______
| / | \ |
| \/ V \/ |
| __ __ __ |
--------| __ | | | | | | |-------- <-- Shear line
Plug --> _|_| |_| |_| |_| |_|_
[ | | | | | | | | | | ]
[ | '--' '--' '--' '--' | ]
[ | .--. .--. .--. .--. | ]
[ | '--' '--' '--' '--' | ]
[_|_____________________|_]
'---------------------'
FIG. 14
FIG. 15 is the end-view, showing the top driver inside the plug, preventing
the turning, and the driver just below the shearing line. I have already
said that these little drivers are manufactured from steel and are very
strong indeed, overcoming any force that a normal wrong key or instrument
could present. even if there were only one little driver inside the plug, it
would still be unable to rotate, or be snapped at the shear line. Now
multiply that strength by five, and I am sure that you will understand it's
almost superhuman strength. Before I move on I must explain that there a no
skeleton keys which will magically open this lock, or it's brother the
WAFER.
Note top drivers are inside plug
______ preventing any turning
/______\
// == \\
|| == ||
|| () ||
Shearing line --> -----||-[||]-||-----
|| [==] ||
\\__##__// ## - Bottom pins
\______/ [==] Plug
FIG. 15
The turning tool replaces the bottom part of the key, and the pick replaces
the notches on the key. Just think of the turning tool as part of the key,
and the pick as the notches. Once you have all the points inside the line,
only a small amount of light pressure is needed to turn the plug. Most books
on the subject stress that too much pressure is wrong. FIG. 20 shows the top
driver inside the chamber binding on three points, because the tension is
too great. Trial and error seems to be the only true way, with only light
turning applied.
Chapter 3: WAFER LOCKS
FIG. 16 shows a single-sided wafer lock. This type of lock contains WAFERS
instead of pins and drivers, and is known as a DISC-TUMBLER instead of a pin
tumbler. the wafers, five as in a pin-tumbler, are held in place by a small,
light spring, as shown (left hand side) of FIGS. 16 and 17. FIG. 16 shows
the lock closed, and FIG. 17 open. The wafer lock is best opened by RAKING,
which is explained later in this work.
________ ________
/ __ \ / __ \
=| / \ | =| / \ |
=| | | | =| | | |
/_ \__/ | /_ \__/ |
\__ __/ \__ __/
--.\__/.-- __ \__/ __
'----' '____'
Locked Unlocked
FIG. 16 FIG. 17
Chapter 4: THE TENSION WRENCH TURNING TOOL
Probably the single most important factor in lock manipulation is the use of
the TENSION WRENCH which I prefer to call the TURNING TOOL. perhaps if it
had been given this name in the first place, hundreds of aspiring locksmiths
would have had greater instant success. I maintain that the word 'tension'
implies that great pressure has to be exerted by this tool. Add to this the
word 'wrench' and totally the wrong impression is given. in order that you
will fully understand the use of this turning tool, I will explain it's
simple function. FIG. 18 shows an normal pin-tumbler or wafer key; FIG. 19
shows the key cut away. This bottom section is now a turning tool. the
reality is that the notches along the key would lift the bottom pins level
with the shearing line, and the part beneath would turn the plug.
____ ____ ,_^^,^,-.-^.
/ \,_^^,^,-.-^. / \/'_____________
\____/-----------' \____/---------------' <-- Turning tool
FIG. 18 FIG. 19
The turning tool replaces the bottom part of the key, and the pick replaces
the notches on the key. Just think of the turning tool as part of the key,
and the picks as the notches. Once you have all of the points inside the
line, only a small amount of light pressure is needed to turn the plug. Most
books on the subject stress that too much pressure is wrong. The student
must first know why too much tension is wrong. FIG. 20 shows the top driver
inside the chamber binding on the tree points, because the tension is too
great. Trial and error seems to be the only true way, with only light
turning applied
___________
| ------. <|----Spring
| .-----' | Top chamber
| '-----. |
| .-----' |
| _'--_____ | Binding
|| || |
|| || V
______|| ||______
------.|_________|.------ Shear line
| | <-- Binding
FIG. 20
If you are raking open a lock, no real pressure need be applied because the
pins and wafers MUST be free to bounce into line with the shearing line. if
too much pressure is used, it prevents this as shown in FIG. 20. Multiply
the one shown by, and you can imagine the lock is well and truly bound
tight. I have used a lot of words in trying to say what has not been put in
print before.
|
--------------'
|
.--------------'
| TURNING TOOLS
FIG. 21
The turning tools are shown in FIG. 21. Once again, I get onto my high
horse, and say that it is not necessary to have lots of different turning
tools in your kit. it is complete nonsense to have light, medium and heavy
tools. Further confusing the is the term used to rigidity of the different
types. This is termed the 'weight', but most of my students mistakenly
assume the actual weight is important to the turning potential. the best is
to choose a medium weight tension wrench and from then on call it a turning
tool. If I am not careful I will change the whole lock picking vocabulary.
The best and easiest wafer or pin-tumbler locks to open are the ones which
contain the smaller pin or wafer sizes together in the same lock, i.e. small
pins in each chamber and ideally all about the same length. When this state
exists, the method to open the lock is by RAKING.
Chapter 5: RAKING PIN-TUMBLER AND WAFER CYLINDER LOCKS
The first plan of attack on any lock of this type, whether it is a padlock
protected with this locking arrangement, a door on a car or a house, is to
try raking. the turning tool fits into the bottom section of the keyway, as
shown in FIG. 22, with just the weight of your finger. No visible bend
should be seen on the tool, otherwise it will be found impossible to pick
open the lock with this method.
________________________
/ \ the tools got to
/ \ be at 45 DEG.
/ ______ \ parallel like
\ / n \ / so: //
\ ********@____/ /
\ / / *** the pick
\ / / / turning tool
\____/_______________/
FIG. 22
Using the picks shown in FIG. 23, we rake the lock, as we shall explain
later, starting with pick number one and working up through until you open
the lock. Perhaps, before we get down to the actual method of raking, we had
better take a close look at the make-up of this tool, known as a RAKE. Look
again at FIG. 23. Notice that 1B is just the same as 1A except that it has
been cut in half, giving the half double ball. 1C is a silhouette of them
both.
If we look closely at 2A, 2B and 2C, we find they are arranged just the
same as the first group. 3A, 3B and 3C are know as DIAMONDS because of their
shape. There seems to be no reason for A, B and C in each of the groups 1, 2
and 3 other than, in the case of the diamonds, for use in smaller locks.
Don't let the different sizes bother you, but just use whatever you have in
your set.
RAKING TOOLS
FIG. 23
1A 1B 1C
|
- | /
| /| \
/ \ / \ / \
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
|_| |_| |_|
Double Half Silhouette
Ball Double Double
Rake Ball Rake Ball Rake
2A 2B 2C
o
| o /
/\ \ |
/ \ / \ / \
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
|__| |_| |_|
Full single Half Single Silhouette
Ball Rake Ball Rake Single Ball Rake
3A 3B 3C
< <| _ |>
| <| | /_| || Handy
| /| | || || Double
/| / | /| 4 || || Ended
| | | | | | || || Rake
| | | | | | || ||
| | | | | | || ||
| | | | | | / \ ||
| | | | | | | | \\
|_| |_| |_| /____\ //
3 Diamond Rakes
In FIG. 23 I have included a number 4, which is sometimes mistaken by
students for a raking tool, but which is, in fact, a broken key extractor,
and has nothing to do with raking. I have shown it's end in close up in the
illustration so that there can be no mistake. The number 5 is a double-ended
rake, which combines on one end a diamond and on the other a silhouette
double ball.
HOW RAKING WORKS
While we are taking a close look at things, it is a good time to do the
same thing with the action of raking, in order that you will fully
understand how it works. Select any of the number 1 raking tools (FIG. 23),
and insert it into the lock so that it touches the back of the lock and is
in contact with the back bottom pin of the lock. The pick is then drawn from
the back of the lock very quickly (see FIG. 24).
Rake is pulled out
causing top driver
and bottom pin to
===== ===== ===== ===== ===== vibrate about the
===== ===== ===== ===== ===== shear line.
.---.
.---. .---. .---. .---. | ^ |
| | | | | | | | | | |
Shearing | | | | | | | | | V | Shearing
Line ______ '---' '---' '---' '---' '---' _____ Line
.---. .---. .---. .---. .---.
Front of | | | | | | | | | ^ | Back
Lock '---' '---' '---' '---' '-v-'_ of the
/-\_________________________________________/ \
(______________________________________________/
Rake being pulled out
<---------------
This action has the effect of causing all the pins, which have been in
contact momentarily with the rake's passage out of the cylinder to vibrate,
each pin lifts the top driver out of the plug with this vibrating momentum
given> The whole thing is really a bit hit and miss, because some of the top
drivers will be out will others are still holding the plug. We must repeat
with the same rake about twenty times, and only if unsuccessful then move on
to another, following the pattern outlined in FIG. 23.
When we rake a lock, we are raising the pins inside the lock to the shear
line. moving through the different shaped picks varies the pattern of the
lift as the tool is repeatedly drawn out. The pins and drivers are bouncing
about the shear line, just waiting to please you and be at the right height
to open as you turn with your turning tool, which has been in place
throughout. I MUST STRESS THAT THE TURNING TOOL HAS NOT BEEN EXERTING A
CONSTANT TURNING PRESSURE, OTHERWISE THE PINS WOULD BIND, AS SHOWN IN FIG.
20. The pressure exerted is best described as a pulsating one. Gentle
pressure must only be on as the rake is leaving the lock on the way out. No
pressure is on as the pins are vibrating. The pins vibrate and the pulsating
turning tool turns the plug, so opening the lock. If too much pressure is
applied at the opening wrong moment, binding takes place and picking is
impossible.
Normally, I first test a lock by inserting my Turing tool into the lock,
turning it in both directions. Any slight movement tells me a few things
about the locks without actually seeing inside it. If has a lot of movement
in each direction, then it is going to be an easy lock to open. Its general
condition tells me if it is an old, worn or cheap lock. if you find little
movement an the lock is known to be a good one, then it is going to take a
little longer or require another technique.
Chapter 6: PICKING LOCKS WITHOUT A TURNING TOOL
A useful tip, for those long practice sessions or demonstrations, is to bend
the connecting cam downwards as shown in FIG. 25. If the lock is held as
shown in FIG. 26 you will find that it eliminates the use of the turning
tool. My advice to the beginner is to try raking with the index finger,
pulsating on the lock's cam.
_
( )----------.
| |__________|____
| | )_
| | )
| | )____
| | LOCK )---.|
| | _) ^||
| | ___) / ||
| | | / '' <-- Cam
(_)-----------' BEND
FIG. 25
_
/ \____ Finger provides
/ \ \_) <----- turning
/___/-\ \
/ / (__)
_||_
(____)
||
||
||
||
||
||
FIG. 26 '' Pick held in other hand
Another practice tip is to remove two sets of pins and drivers, leaving
three sets within the lock, thereby reducing the strength and making it a
little easier to manipulate.
Chapter 7: THE LOCK GUN
This useful tool is really a super raking device. pulling the trigger causes
the needle probes to flick upwards, and this has the effect of bouncing the
pins about the shearing line. this tool is capable of producing a continuous
vibration of the pins, making picking easy. It is a useful tool, and a nice
addition to your toolkit. The gun is shown in FIG. 27.
_______/\
<.|- \__
\ \_______
\ |_/
/ . _____| =[]
/ | \\ \
/ / \\ \__
/ . / (|
|_____/ .------
Lock Gun |
FIG. 27
Chapter 8: THE LOCK MASTER
Before we leave raking, perhaps we had better look at my own invention, the
LOCK MASTER, which has certain advantages over the lock gun, and even more
disadvantages. That said, its main advantage is a big one -- it completely
eliminates the need for a turning tool. Its bottom section has its own
turning tool built in. FIG. 28 shows the tool. the top is flicked with the
index finger nail, and the probe is returned to the horizontal by means of
two small springs. the finger snaps away while the master is twisted, again
in the pulsating fashion. The main disadvantage is that you have to have
different LOCK MASTERS for different size lock.
________________
/----------#-(.)-\-
___________#_(.)_
(______________ )____ Lock Master
/\__) \
| |
\________/
FIG. 28
Chapter 9: PURE PICKING
I like to think of my next section as 'pure picking', because that is
precisely what we do. Each pin is lifted in turn, lifting the driver clear
of the plug. Remember that earlier I advised the beginner to remove a couple
of set of pins and drivers. This is perhaps when you will find this most
useful. Turning is applied by the turning tool, or my own bent cam motion.
The HOOK PICKS shown in FIG. 29 are used.
Pure picking
-------------------
--. \ Top __ __ __
| | Chambers |==||==||==|
/ \ / \ '-------> |==||==||--|
| | | | ____|--||--|'--|___ <--- Shear Line
| | | | '--''--'.__.
| | | | .--..--.| |
| | | | '--''--''--'
| | | | ( )_______________
| | | | \_______________/
| | | | ___________________
| | | | Hook lifting Pin to
'-' '-' Shearing Line
Hook Picks
FIG. 30
FIG. 30
It requires a fair measure of practice, and even more patience, but the
rewards once you are a master of this technique are more than words can
convey. Using whatever method you choose to turn the plug, FIG. 30 shows the
pick lifting the pins one at a time until they are pushed out of the plug
into the top chambers. All the time, a very gentle turning motion has been
applied by means of the turning tool. FIG. 31 shows the lock set to open.
Set to open
___ ___ ___
| = || = || = |
|.-.||.-.||.-.| Notice how the
Shear line ___|'-'||'-'||'-'|___ bottom pins line
_ _ _ <--------- up precisely on
| | | | | | the shear line
'-' '-' '-'
FIG. 31
____________
U----(____________) Small
____________
\----(____________) Medium
____________
|____(____________) Large
Three sizes of Hook Picks
FIG. 32
Use the correct size of hook pick, by first trying the smallest. see FIG.
32. Practice this, and you will have a gem.
Chapter 10: OPENING LOCKS WITHOUT ACTUAL PICKING
FIG. 33 some points of attack which you will find convenient, and which have
been unknowingly built into the lock's construction by the manufacturer. The
method is known as shimming. FIG. 34 shows a collection of springs and
probes. go along to your local watchmaker and obtain as many as you can. Add
to this blades from junior hacksaws, coping and fretsaws and you will soon
have a fine collection.
FIG. 33
________ X
X / ______ \ /
\ / / \ \
\__/ /________\ \__
|\ |_|_------ | | |
| |_,-.----.#| | |
X----|--| ||_.--._||=| |
| '-' .-''-. |=| |
| | | |=| |
| | | |=| |
| '----' '=' |
|__________________|
Old Clock springs
_____________ ________________ _________________
|_____________| [________________]'-----------------' Small,Med,Large
Saw Blades
____________\_
______________) -----------------, __________________
\ VVVVVVVVVVVVVVVVV vvvvvvvvvvvvvvvvvv'
FIG. 34
Taking advantage of the lock's weak points, we insert our clock spring or
saw blade between the point where the two halves of the lock case meet, or
down the side of the shackle, following the line of the bow, and so pushing
back the spring-loaded bolt.
CHAPTER 11: RAPPING OPEN LOCKS
Look at my FIG. 35, which shows a pin-tumbler lock about to be opened by
rapping. the blow must be sharp but not heavy.
___ Sharp
| | Blow
FIG. 35 _| |_
\ / Pins
\ / __ line up
\ / | | on the
________V_____| | Shear Line
Blow causes | __ _ _ _ _ |
the pins and | |==||=|=|=|=| |
drivers to |-|V ||V|V|V|V|___| Shearing
vibrate -----| |^ ||^|^|^|^| |-------
| |V ||V|V|V|V| | Line
| |--||-|-|-|-| |
| '--''-'-'-'-' |
'______________ |
| |
|__|
How Rapping works
The blow should be only to the point shown. It has the effect of causing
the pins to vibrate and to split at the shearing line, as in raking and the
lock gun methods. Just as in the other methods, we use the turning tool
together with the pulsating movement. Try rapping open a spring-loaded bow
(shackle) padlock before you try a pin-tumbler or wafer lock. (See FIG. 36)
______
/,^--. \
__ __/ /
/ \___/ / /
/ ---. __ \
/ _/ ( \
/ C. / \
\ \\ (o) / <--- Sharp blow at this
\ \, | / point opens the lock
\___________/
Vibration causes lock to open like magic
TOOLS AND APPARATUS
FOR USE IN LOCK PICKING
1 Small vice, from watchmaker's suppliers, with 2" jaws.
2 A selection of small files, from watchmaker's suppliers.
3 A junior hacksaw from hardware stores.
4 A selection of saw blades, from hardware stores.
5 Leaf gauges, from a garage.
6 Piano wire, from music shop.
7 Lock picks, from locksmiths.
8 Old clock springs, from local watchmaker.
9 Wire cutters, from hardware stores.
10 Collection of blank keys, from locksmiths.
11 Lock gun from locksmiths.
12 Oil, from hardware stores.
13 Lots of old locks, from friends.
14 Pencil torch.
15 Strong magnifying glass.
16 Patience, and a bottomless coffee pot.
Get together as many locks of all types as possible. ask your friends if
they can find you any old locks for which they have lost the keys. After
experimenting with the locks, open them up to find out how they work. This
is the finest way to becoming a true lock expert.
If you are beaten by a particular lock, dont despair. I know the feeling
all to well. it's back to the drawing board, or, more correctly, the
workshop. Open it up, study it's workings, then re-assemble. always LOOK FOR
ITS WEAK POINTS. believe me, it will have some; you just have to look long
enough and hard enough. Locks are like a chain, as strong as the weakest
link.
|=[ 0x04 ]=--------------------------------------------------------------=|
Spyke's Beginner Guide 2
FFF III N N GGG EEE RRR BBB OOO AAA RRR DD III N N GGG
F I NN N G E R R B B O O A A R R D D I NN N G
FFF I N NN G EEE RRR BBB O O AAA RRR D D I N NN G
F I N N G G E RR B B O O A A RR D D I N N G G
F III N N GGG EEE R R BBB OOO A A R R DD III N N GGG
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
(Like anyone wants to know..
Just somin' to do in your
Spare time!)
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
Sections
--------
1. How to perform ollies
2. How to perform Backflips
3. How to perform shuv-its (in air)
4. How to perform Grinds
4.1 Boardslide
4.2 Darkslide
5. How to get a fingerboard
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
Section : 1. How to perform ollies
==================================
The ollie is possibly the first fingerboarding trick in
which you should learn. It allows you to pop your finger-
board into the air with your fingers allowing you to jump
Onto OR over (small) objects.
the first part of the ollie is to put you fingers in the
correct possition (as you can see in {Fig. A}) with one
finger flat on the tail and another right behind were the
trucks are on the top.
{Fig. A}
Key
-------
F=Finger \=Left Tail 0=Wheel
/=Right Tail ^=Trucks _=Part of deck
\____F__________F/
^0^ ^0^
Next you hit the tail (with the finger that is placed on
on the tail) lift hand and push forwards.
After practice you //should// be able to get the board
into the air a few inchs ({Fig. B}).
{Fig. B}
|
0\F
\
\
\
\
0\_F
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
Section : 2. How to perform Backflips
=====================================
The back flip on a finger board if diffurent to a backflip
on a skateboard in the way that your fingers do not flip
360 degrees verticly (That would break your wrist) but they
hover above the board while it flips.
Firstly put your fingers into the ollie postition (Shown
above in {Fig. A}), and hit the tail hard. Quickly lift
your fingers up into the air and the board //should// flip
in the air verticaly. Now for the hard bit : wait until
the board flips 360 degrees then drop your fingers so it
lands the correct way up,this movemnt has to be farely
fast to work.
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
Section : 3. How to perform shuv-its (in Air)
=============================================
The shuv-it (in Air) is were you ollie your board so
it spins 180 degrees horizontaly.
To do this trick you must place your fingers in the ollie
postition but with the tail-finger on the side on the board,
not the middle (Shown in {Fig. C}), next you ollie but when
you hit the tail you also turn you hand a little bit.
{Fig. C}
______________________F
/ . . . . \
| . .F . . |
\_______________________/
When the board is (hopefully) spinning in the air hit it
down after it has made a full 180 degree turn.
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
Section : 4. How to perform Grinds
==================================
To grind, ollie the board onto the edge of somthing OR
onto a pencil of bar.
Section : 4.1 Boardslide
------------------------
Ollie the board and turn it 90 degrees in the air
onto a thin object/edge of somthing then, push smoothly
across (Refer to {Fig. D}), to land push the board off
the object and turn 90 degrees back to the orginal
position.
{Fig. D}
_
/F\
|. .|
|. .|
| |
-------| |-------
-------| |--------Grinding Object
| F |
|. .|
|. .|
\_/
Section : 4.2 Darkslide
-----------------------
The darkslide is a grinding trick were you flip the board
upside down, grind it upside down, then flip it the
correct way up. It is technically an upside-down
Boardslide.
Firstly put your fingers into an ollie postition and move
the board towards the grinding objects, when you are close
annouf to ollie onto it, flip your board 180 degrees so
it is upside down, and push it onto the grinding object.
Push it forwards assuming pressure to the front, when you
get to the end of the grinding object attemp to flip the
board the correct way up.
Section : 5 How to get a fingerboard
====================================
Search in some local shops near you or buy them online from:
http://www.skateboard.com/techdeckshop/
|=[ EOF ]=---------------------------------------------------------------=|