Skip to content

Commit

Permalink
Updated the README and added the code from the John Burger tutorial o…
Browse files Browse the repository at this point in the history
…n wiki.osdev.org
  • Loading branch information
andy committed Dec 1, 2014
1 parent 69c79a2 commit d0aed68
Show file tree
Hide file tree
Showing 96 changed files with 5,139 additions and 5 deletions.
9 changes: 9 additions & 0 deletions OSDev-Demo-Wiki/BIOS/A20.inc
@@ -0,0 +1,9 @@
;
; BIOS/A20.inc
;

; These are the definitions for the BIOS A20 controller
BIOS.A20.Int EQU 15h
BIOS.A20.Fn EQU 24h
BIOS.A20.Enable EQU 01h
BIOS.A20.Disable EQU 00h
26 changes: 26 additions & 0 deletions OSDev-Demo-Wiki/BIOS/BIOS.inc
@@ -0,0 +1,26 @@
;
; BIOS/BIOS.inc
;

; The original IBM PC BIOS, and various successors, have all embodied relatively
; arbitrary design decisions that have become industry standards. Of course, not
; every BIOS uses the same definitions, and others had bugs which were fixed in
; later versions, but those arbitrary decisions need to be either utilised or
; accommodated by any system wanting to work on the PC.

BIOS.RAMTop.Int EQU 12h

;-------------------------------------------------------------------------------
%include "BIOS/A20.inc" ; Definitions for A20 Gate controller
;-------------------------------------------------------------------------------
%include "BIOS/RAMMap.inc" ; Definitions for RAMMap information
;-------------------------------------------------------------------------------
%include "BIOS/Key.inc" ; Definitions for Keyboard
;-------------------------------------------------------------------------------
%include "BIOS/VGA.inc" ; Definitions for VGA video
;-------------------------------------------------------------------------------
%include "BIOS/Disk.inc" ; Definitions for Disk controller
;-------------------------------------------------------------------------------
%include "BIOS/MBR.inc" ; Definitions for Master Boot Record
;-------------------------------------------------------------------------------
%include "BIOS/MemMap.inc" ; Definitions for boot-time memory map
11 changes: 11 additions & 0 deletions OSDev-Demo-Wiki/BIOS/Disk.inc
@@ -0,0 +1,11 @@
;
; BIOS/Disk.inc
;

; These are the definitions for the BIOS Disk controller

BIOS.Disk.Sector.Size EQU 512

BIOS.Disk.Int EQU 13h
BIOS.Disk.Fn.Reset EQU 00h
BIOS.Disk.Fn.Read EQU 02h
54 changes: 54 additions & 0 deletions OSDev-Demo-Wiki/BIOS/Key.inc
@@ -0,0 +1,54 @@
;
; BIOS/Key.inc
;

; These are the definitions for the BIOS keyboard controller

BIOS.Key.Int EQU 16h

BIOS.Key.SetRate.Fn EQU 03h
BIOS.Key.SetRate.Default EQU 00h ; Set back to default
BIOS.Key.SetRate.Increase EQU 01h
BIOS.Key.SetRate.Decrease EQU 02h ; Slow down by half
BIOS.Key.SetRate.Off EQU 04h ; Turn off
BIOS.Key.SetRate.Set EQU 05h ; Set to below values (BH:BL)

; Delay before typematic starts, in milliseconds (in BH)
BIOS.Key.SetRate.Delay.250 EQU 00h
BIOS.Key.SetRate.Delay.500 EQU 01h
BIOS.Key.SetRate.Delay.750 EQU 02h
BIOS.Key.SetRate.Delay.1000 EQU 03h

; Rate at which typematic occurs, in chars per 10 seconds (in BL)
BIOS.Key.SetRate.Rate.300 EQU 00h
BIOS.Key.SetRate.Rate.267 EQU 01h
BIOS.Key.SetRate.Rate.240 EQU 02h
BIOS.Key.SetRate.Rate.218 EQU 03h
BIOS.Key.SetRate.Rate.200 EQU 04h
BIOS.Key.SetRate.Rate.185 EQU 05h
BIOS.Key.SetRate.Rate.171 EQU 06h
BIOS.Key.SetRate.Rate.160 EQU 07h
BIOS.Key.SetRate.Rate.150 EQU 08h
BIOS.Key.SetRate.Rate.133 EQU 09h
BIOS.Key.SetRate.Rate.120 EQU 0Ah
BIOS.Key.SetRate.Rate.109 EQU 0Bh
BIOS.Key.SetRate.Rate.100 EQU 0Ch
BIOS.Key.SetRate.Rate.92 EQU 0Dh
BIOS.Key.SetRate.Rate.86 EQU 0Eh
BIOS.Key.SetRate.Rate.80 EQU 0Fh
BIOS.Key.SetRate.Rate.75 EQU 10h
BIOS.Key.SetRate.Rate.67 EQU 11h
BIOS.Key.SetRate.Rate.60 EQU 12h
BIOS.Key.SetRate.Rate.55 EQU 13h
BIOS.Key.SetRate.Rate.50 EQU 14h
BIOS.Key.SetRate.Rate.46 EQU 15h
BIOS.Key.SetRate.Rate.43 EQU 16h
BIOS.Key.SetRate.Rate.40 EQU 17h
BIOS.Key.SetRate.Rate.37 EQU 18h
BIOS.Key.SetRate.Rate.33 EQU 19h
BIOS.Key.SetRate.Rate.30 EQU 1Ah
BIOS.Key.SetRate.Rate.27 EQU 1Bh
BIOS.Key.SetRate.Rate.25 EQU 1Ch
BIOS.Key.SetRate.Rate.23 EQU 1Dh
BIOS.Key.SetRate.Rate.21 EQU 1Eh
BIOS.Key.SetRate.Rate.20 EQU 1Fh
22 changes: 22 additions & 0 deletions OSDev-Demo-Wiki/BIOS/MBR.inc
@@ -0,0 +1,22 @@
;
; BIOS/MBR.inc
;

; These are the definitions for the standard BIOS Master Boot Record

; If we booted from a hard disk, ES:SI will be pointing to the relevant Partition
STRUC BIOS.MBR.Entry
.Active RESB 1
.StartHead RESB 1
.StartCylSect RESW 1
.Type RESB 1
.EndHead RESB 1
.EndCylSect RESW 1
.Start RESD 1
.Size RESD 1
ENDSTRUC

; The two CylSect entries above have the following format. But don't be fooled!
; The HIGH bits of the Cylinder are in the LOW byte - it's weirdly reversed!
BIOS.MBR.Entry.Cyl EQU 1111_1111_1100_0000b
BIOS.MBR.Entry.Sect EQU 0000_0000_0011_1111b
20 changes: 20 additions & 0 deletions OSDev-Demo-Wiki/BIOS/MemMap.inc
@@ -0,0 +1,20 @@
;
; BIOS/MemMap.inc
;

; This is the Memory Map of when the BIOS first boots.

; You'll notice that the Stack is on top of the Interrupt Vector Table!
BIOS.Stack.Base EQU 0000h ; BIOS Boot stack
BIOS.Stack.Size EQU 0400h

BIOS.BDA.Base EQU 0400h ; BIOS Data Area
BIOS.BDA.Size EQU 0100h

BIOS.MBR.Base EQU 0600h ; BIOS Master Boot Record load area
BIOS.MBR.Size EQU 0200h

BIOS.Entry EQU 7C00h ; BIOS Boot Entry point

BIOS.Sig.Value EQU 0AA55h ; BIOS Signature flag
BIOS.Sig.Pos EQU BIOS.Disk.Sector.Size - 2
19 changes: 19 additions & 0 deletions OSDev-Demo-Wiki/BIOS/RAMMap.inc
@@ -0,0 +1,19 @@
;
; BIOS/RAMMap.inc
;

; These are the definitions for the BIOS RAM Map information handler

BIOS.RAMMap.Int EQU 15h
BIOS.RAMMap.Fn EQU 0000_E820h
BIOS.RAMMap.Magic EQU "PAMS" ; NASM reverses "SMAP"

; This is the BIOS RAMMap structure
STRUC BIOS.RAMMap
.Base RESQ 1
.Length RESQ 1
.Type RESD 1
.Flags RESD 1 ; Added in later BIOSes
ENDSTRUC

BIOS.RAMMap.Flags.DontIgnore EQU 0000_0000_0000_0001b
18 changes: 18 additions & 0 deletions OSDev-Demo-Wiki/BIOS/VGA.inc
@@ -0,0 +1,18 @@
;
; BIOS/VGA.inc
;

; These are the definitions for the BIOS video controller

BIOS.VGA.Int EQU 10h

BIOS.VGA.SetMode.Fn EQU 00h
BIOS.VGA.SetMode.80x25 EQU 03h

BIOS.VGA.ExtMode.Fn EQU 11h
BIOS.VGA.ExtMode.80x50 EQU 12h

BIOS.VGA.Cursor.Fn EQU 01h
BIOS.VGA.Cursor.None EQU 0010_0000_0000_0000b
BIOS.VGA.Cursor.Under EQU 06_07h
BIOS.VGA.Cursor.Block EQU 00_07h
118 changes: 118 additions & 0 deletions OSDev-Demo-Wiki/Boot/A20.inc
@@ -0,0 +1,118 @@
;
; Boot/A20.inc
;

; The 8086 has a 20-bit address bus. If you loaded a segment register with
; 0FFFFh and accessed 0FFFFh:0FFFFh, the Segment:Offset addition would wrap
; and you'd actually be accessing 0000_FFEFh. The BIOS would "take advantage"
; of this quirk and use it to access both top-of-Address BIOS and botttom-of-
; Address RAM with the same segment register.
;
; Of course, then the '286 PC/AT came out with a 24-bit bus - and the wrap no
; longer occurred. You could use it to access the (nearly) 64K of High Memory!
; But what about all the legacy code? That was now broken.
;
; To "fix" this, the designers of the PC/AT added a Gate to the A20 line, to
; hold A20 on the memory bus at zero regardless of what the CPU wanted. This
; emulated the wrap-around "feature", but made the high memory inaccessible.
;
; So to fix that, they found a spare output that they could program at run-time
; to turn the Gate on or off. Where was this spare pin? The keyboard controller,
; of course...
;
; As PCs became more sophisticated, the A20 Gate stayed, but the programming
; mechanism to turn it on or off changed - and it wasn't really standardised.
; Since this program wants to access high memory, it has to turn off the Gate -
; and it uses a number of techniques to attempt this.
;
; Of course, this means finding out whether A20 is off, both up front and after
; each technique. How? Go to a known memory location, get its value, and compare
; it with its high-memory "alias". If they're different, then the Gate is off.
; If they're the same, then maybe it was a coincidence? Change the original
; location, and check the alias again. If they're now different (they were the
; same, but now they're different), the Gate must be off.

A20.Enable EQU (BIOS.A20.Fn << 8) | BIOS.A20.Enable

; [0000h:BIOS.Entry + BIOS.Sig.Pos] holds the value BIOS.Sig.Value
; [FFFFh:BIOS.Entry + BIOS.Sig.Pos + 10h] is its alias, if the A20 Gate is on.
Sig.Alias EQU BIOS.Entry + BIOS.Sig.Pos + 10h

Boot.A20:
; CS:BIOS.Sig.Pos has a known, safely-modifable value.
; Prepare for testing, by comparing CS:BIOS.Sig.Pos with 0FFFFh:Sig.Alias
MOV SI,BIOS.Sig.Pos

MOV AX,0FFFFh ; End of 1 MB
MOV ES,AX ; In ES
MOV DI,Sig.Alias

; First things first: has it already been done for us?
CALL .Test ; Test if A20 already on
JE .End ; Yep! Nothing to do

; No. OK, maybe the BIOS can help.
MOV AX,A20.Enable
INT BIOS.A20.Int ; Using BIOS

CALL .Test ; Did it work?
JE .End ; Yep! Nothing more to do

; No. OK: the traditional ways are always the best?
CALL Boot.A20.Switch ; Switch A20 myself
; JNZ $ ; Uh oh! ***STOP!***

CALL .Test ; Did it work?
JE .End ; Yep! Nothing more to do

; No. Maybe it's a PS/2?
IN AL,Dev.A20.Fast.Port ; Try Fast A20
TEST AL,Dev.A20.Fast.A20 ; Enabled?
JNZ $ ; Uh oh! Isn't working! ***STOP!***
OR AL,Dev.A20.Fast.A20 ; Enable it
AND AL,~Dev.A20.Fast.Reset ; But NOT Fast Reset!
OUT Dev.A20.Fast.Port,AL

CALL .Test ; Did it work?
JE .End ; Yep! Finally!

JMP $ ; No reaction! ***STOP!***
Boot.A20.Test:
MOV DX,[CS:SI] ; Get current value
CMP DX,[ES:DI] ; Same at end of RAM?
JNE .Good ; No, so no problem!

NOT WORD [CS:SI] ; Change current value
CMP DX,[ES:DI] ; Still same as old?
JMP .Bad ; No, so problem!
.Good:
XOR AX,AX ; Set Z flag
.Bad:
RET

;-------------------------------------------------------------------------------

Boot.A20.Switch:
CALL .Wait ; Wait for 8042 to be ready
JNZ .Dead ; Uh oh...

MOV AL,Dev.A20.Ctrl.Write
OUT Dev.A20.Ctrl.Port,AL ; Tell 8042 we're writing to it
CALL .Wait ; Wait for acknowledge
JNZ .Dead ; Uh oh...

MOV AL,Dev.A20.Data.Enable
OUT Dev.A20.Data.Port,AL ; Tell 8042 to Enable A20
;...............................................................................
.Wait:
XOR CX,CX ; Try a LARGE number of times!
.Loop:
IN AL,Dev.A20.Stat.Port ; Wait to write
TEST AL,Dev.A20.Stat.InFull ; YES, In! It's backwards
LOOPNZ .Loop ; Nope. Still full
.Dead:
RET

;-------------------------------------------------------------------------------

Boot.A20.End:
69 changes: 69 additions & 0 deletions OSDev-Demo-Wiki/Boot/Boot.inc
@@ -0,0 +1,69 @@
;
; Boot/Boot.inc
;

; This is the BIOS Boot entry point. It runs in Real Mode, and assumes the
; standard BIOS Boot Specification 1.01.
;
; It performs the following actions:
; 1) Loads the rest of the code into RAM;
; 2) Gets some information from the soon-to-be-unusable BIOS;
; 3) Sets up the PC for Protected Mode;
; 4) JMPs to the freshly-loaded Protected Mode code
; After that, the memory used to hold this code is avaiable to the system.
;
; Note that one of the goals of the Boot sector is to jettison itself:
; 7C00h is such an awkward location, so ideally after doing all the Real Mode
; initialisation, we can JMP to Protected Mode and simply leave this code behind.

; To save space, I take advantage of some HORRIBLE things you can do with
; assembly language: PUSHing values to fake CALLs, or worse, SELF-MODIFYING CODE!
; In Protected Mode, this last is very difficult to organise - and unreliable
; with later processors that have on-board caches - so not worth it.
; In Real Mode, this can be very useful as a register- and code-saving device!

; To save space, I've done away with byte-wasting CALLs and RETs for "modular"
; programming. Not that modules aren't in and of themselves useful - indeed,
; they're still modularised within their own little files - but the result is
; simply a stream of bytes to execute. Where I have defined subroutines to be
; CALLed, the stream of code has to either JMP over the subroutine's RET, or
; a CALL is faked by PUSHing the desired continuation address onto the stack.

;-------------------------------------------------------------------------------
SEGMENT Real VSTART=0 ALIGN=1

USE16 ; Real Mode? 16 bits!

; At this point, DL is probably the drive number of the Boot Drive.
; ES:SI is possibly a pointer to the MBR Partition table entry (See Load.inc).
; In any case: don't clobber DL, ES or SI before Load.inc!

%include "Boot/Entry.inc" ; Entry code to initialise important registers
;-------------------------------------------------------------------------------
%include "Boot/CPU.inc" ; Check CPU is (at least) a '386
;-------------------------------------------------------------------------------
%include "Boot/Load.inc" ; Load Protected Mode code
;-------------------------------------------------------------------------------
%include "Boot/IDT.inc" ; Move IDT to final location
;-------------------------------------------------------------------------------
%include "Boot/RAM.inc" ; Get RAM size
;-------------------------------------------------------------------------------
%include "Boot/A20.inc" ; Enable A20 gate
;-------------------------------------------------------------------------------
%include "Boot/Key.inc" ; Speed up keyboard
;-------------------------------------------------------------------------------
%include "Boot/VGA.inc" ; Switch Video mode
;-------------------------------------------------------------------------------
%include "Boot/PM.inc" ; Switch to Protected Mode
;-------------------------------------------------------------------------------

; At this point, we still must be inside the first 512-byte Boot sector.
; We need to confirm to the BIOS that this sector is a valid Boot sector by
; having BIOS.Sig.Value at the correct place.
; Note that if the previous code was too large, the following Pad calculation
; will underflow and generate an error.

Real.Padding EQU BIOS.Sig.Pos - ($ - $$)
TIMES Real.Padding DB 00h

DW BIOS.Sig.Value

0 comments on commit d0aed68

Please sign in to comment.