You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

492 lines
11 KiB

%define GDT_Paragraph 0x1000
%define GDT (GDT_Paragraph*16)
%define GDT_CodeSegIndex 1
%define GDT_DataSegIndex 2
%define GDT_CodeSeg16Index 3
%define GDT_DataSeg16Index 4
%define GDT_Selector(DescriptorIndex, TableIndicator, RequestorPrivLevel) ((DescriptorIndex << 3) | ((TableIndicator & 1) << 2) | (RequestorPrivLevel & 0x3))
%define GDT_CodeSegSelector GDT_Selector(GDT_CodeSegIndex, 0, 0)
%define GDT_DataSegSelector GDT_Selector(GDT_DataSegIndex, 0, 0)
%define GDT_CodeSeg16Selector GDT_Selector(GDT_CodeSeg16Index, 0, 0)
%define GDT_DataSeg16Selector GDT_Selector(GDT_DataSeg16Index, 0, 0)
%define VIDEO 0xB8000
%define VIDEO_X_RES 80
%define VIDEO_Y_RES 25
%define ScreenCoord(x, y) (2*(VIDEO_X_RES*(y)+(x)))
; GDT Stuff
%define Data 0000b
%define DataMutable 0010b
%define DataShrink 0100b
%define DataShrinkMutable 0110b
%define Code 1000b
%define CodeRead 1010b
%define CodeOwnRing 1100b
%define CodeOwnRingRead 1110b
%macro GDT_NULL_ENTRY 1 ; address
%assign address %1
lea di, [address]
xor ax, ax
mov cx, 4
rep stosw
%assign GDT_COUNT (GDT_COUNT+1)
%endmacro
%macro GDT_ENTRY 6 ; address base limit type privilege bits32
%assign address %1
%assign base %2
%assign limit %3
%assign type (%4 & 0xf)
%assign reserved (1<<4)
%assign privilege ((%5 & 0x3) << 5)
%assign present (1<<7)
%assign access (present | privilege | reserved | type)
%assign bits32 ((%6 & 1) << 2)
%assign granularity (1<<3)
%assign flags (granularity | bits32)
%assign limit_0_15 (limit & 0xffff)
%assign limit_16_19 ((limit >> 16) & 0xf)
%assign base_0_15 (base & 0xffff)
%assign base_16_23 ((base >> 16) & 0xff)
%assign base_24_31 ((base >> 24) & 0xff)
mov WORD [es:(address + 0)], limit_0_15
mov WORD [es:(address + 2)], base_0_15
mov WORD [es:(address + 4)], base_16_23 | (access << 8)
mov WORD [es:(address + 6)], limit_16_19 | (flags << 4) | (base_24_31 << 8)
%assign GDT_COUNT (GDT_COUNT+1)
%endmacro
%define IOKeyData 0x60
%define InKeyStatus 0x64
%define OutKeyCommand 0x64
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Enable_A20:
; Enables A20 gate using:the BIOS, keyboard controller, or Fast A20
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pushad ;Preserve registers
pushfd ;Preserve EFLAGS because we might disable interrupts
mov ax,0x2402 ;INT 15h AX=2402h: Query A20 status
int 0x15 ;Check to see if A20 gate is enabled
jc A20_No_BIOS ;Error? Don't use BIOS to enable gate
test al,1 ;Test Bit 0 of AL
je A20_Enabled ;A20 gate already enabled
mov ax,0x2401 ;INT 15h AX=2401h: Enable A20 gate
int 0x15 ;Use BIOS to enable A20 gate
jc A20_No_BIOS ;Error? Don't use BIOS to enable gate
or ah,ah ;Test AH
jnz A20_No_BIOS ;Non-zero? A20 gate may not be enabled
A20_Enabled:
popfd ;Restore EFLAGS
popad ;Restore registers
ret ;Return
A20_No_BIOS:
mov ax,0x2403 ;INT 15h AX=2403h: Query A20 support
int 0x15 ;Call BIOS to find out how the A20 gate can be enabled
jc A20_KBD ;Error? Assume that keyboard controller is the only option
test bx,1 ;Bit 0:Keyboard controller supported
je A20_KBD ;BIOS indicates that keyboard controller is supported
test bx,2 ;Bit 1:Fast A20 supported
je FAST_A20 ;BIOS indicated that Fast A20 is supported
call Check_A20 ;Test A20 gate manually
jc A20_Enabled ;A20 gate already enabled
A20_Fail:
call A20_OUT_Wait ;"Unable to enable A20 gate!"
cli ;Disable interrupts
hlt ;Halt machine
FAST_A20:
in al,0x92 ;Read System Control Port A
test al,2 ;Test Fast A20 bit
jnz A20_Fail ;Bit already set, failed to enable A20 gate
or al,2 ;Set Bit 1:Enable Fast A20
and al,0xFE ;Always clear Bit 0 so that machine does not reboot
out 0x92,al ;Write to port 92h
call Check_A20 ;Check A20 gate
jc A20_Enabled ;Success?
cli ;No? something must have gone wrong
hlt ;Clear interrupts and halt machine
A20_KBD:
cli ;Disable interrupts
mov cx,50 ;Number of attempts to enable gate
Use_KBD:
call A20_OUT_Wait ;Wait for keyboard
mov al,0xAD ;Disable Keyboard
out 0x64,al ;Wait for Keyboard
mov al,0xD0 ;Read Controller Output Port
out 0x64,al
call A20_IN_Wait ;Wait for Keyboard
in al,0x60 ;Read Data Port
push ax ;Save
call A20_OUT_Wait ;Wait for Keyboard
mov al,0xD1 ;Write Controller Output Port
out 0x64,al
call A20_OUT_Wait ;Wait for Keyboard
pop ax ;Get port data back
or al,10b ;Bit 1: Enable A20 gate
out 0x60,al ;Write to data port
call A20_OUT_Wait ;Wait for Keyboard
mov al,0xAE ;Enable Keyboard
out 0x64,al
call A20_OUT_Wait ;Wait for Keyboard
call Check_A20 ;Verify that gate is enabled
jc A20_Enabled ;Yes? Return
loop Use_KBD ;No? Keep trying
jmp A20_Fail ;Could not enable gate after 50 tries
A20_OUT_Wait:
in al,0x64 ;Read status register
test al,10b ;Is port ready?
jnz A20_OUT_Wait ;Nope, wait
ret ;Yep, continue
A20_IN_Wait:
in al,0x64 ;Read status register
test al,1b ;Is port ready?
jz A20_IN_Wait ;Nope, wait
ret ;Yep, continue
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Check_A20:
; Test if A20 gate is enabled by comaparing the value in FFFF:7E0E
; with the VBR boot signature at 0000:7DFE
; Out: Carry flag set if A20 gate is enabled
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pushad ;Preserve registers
push es
mov ax, 0xFFFF
mov es, ax ;Extra segment:FFFF
cmp WORD [es:0x7DFE + 16], 0xAAFF ;See if boot signature is wrapped at FFFF:7E0E (Meaning FFFF:7E0E = 0:7DFE)
stc ; Assume we didn't wrap, yes A20
jne .End
clc ; We did wrap, no A20
.End:
pop es
popad
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Go32Bit:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
call Enable_A20
; Set screen mode
mov ax, 0x0003 ; AH=0 (Change video mode), AL=13h (Mode) = 320x200 - 256 colors
mov bx, 0x0000
int 0x10 ; Video BIOS interrupt
;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Global Descriptor Table ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov ax, GDT_Paragraph
mov es, ax
mov cx, 4096
lea si, [GO32_COPY_BEGIN]
xor di, di
rep movsb
%assign GDT_COUNT 0
GDT_NULL_ENTRY 0
GDT_ENTRY (GDT_CodeSegIndex*8), 0x00000000, 0xffffffff, CodeRead, 0, 1
GDT_ENTRY (GDT_DataSegIndex*8), 0x00000000, 0xffffffff, DataMutable, 0, 1
GDT_ENTRY (GDT_CodeSeg16Index*8), 0x00000000, 0xffffffff, CodeRead, 0, 0
GDT_ENTRY (GDT_DataSeg16Index*8), 0x00000000, 0xffffffff, DataMutable, 0, 0
cli
lgdt [GDT_Record]
mov eax, cr0
or al, 1 ; set PE (Protection Enable) bit in CR0 (Control Register 0)
mov cr0, eax
jmp ClearPrefetchQueue
nop
nop
ClearPrefetchQueue:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Manually assembled long jump ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
db 0x66 ; 32bit override
db 0xea ; Long jump
dd ProtectedModeBaby ; Absolute address
dw GDT_CodeSegSelector ; Descriptor Selector
GDT_Record:
dw (GDT_COUNT*8) - 1 ; Size of GDT in bytes minus 1
dd 0x1000*16 ; Linear address of GDT
align 512
BITS 32
GO32_COPY_BEGIN:
segment Go32Bit vstart=GDT
GDT_SPACE: times (GDT_COUNT*8) db 0
ProtectedModeBaby:
; Update Other Segments
mov ax, GDT_DataSegSelector
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
; Setup stack
mov esp, (100 << 20) - 1 ; 100M Addressable
mov ebp, esp
; Space for dynamic variables
sub esp, 200*4 ; 200 32-bit integers
push ebp
DrawStuff:
xor ecx, ecx
xor edx, edx
lea edi, [VIDEO]
mov ebp, dword [Zoom]
sar ebp, 9
jnz .DrawLoop
mov ebp, 0x7fffffff
.DrawLoop:
mov eax, [Px]
shr eax, 4
add eax, ecx
imul eax, eax
mov ebx, eax
mov eax, [Py]
shr eax, 4
add eax, edx
add eax, edx
imul eax, eax
add ebx, eax
mov eax, [ColorOffset]
push edx
xor edx, edx
idiv ebp
pop edx
xchg eax, ebx
add ax, bx
mov al, ah
stosw
inc ecx
cmp ecx, VIDEO_X_RES
jne .DrawLoop
xor ecx, ecx
inc edx
cmp edx, VIDEO_Y_RES-2
jne .DrawLoop
pop ebp
cld
xor eax, eax
in al, IOKeyData ; Get the scan code from the keyboard
test al, 0x80
jnz .ThereWasNothing
cmp al, 75; left
je .KeyLeft
cmp al, 72; up
je .KeyUp
cmp al, 80; right
je .KeyDown
cmp al, 77; down
je .KeyRight
cmp al, 51; <
je .KeyLess
cmp al, 52; >
je .KeyGreater
cmp al, 1 ; Escape
je .KeyEscape
.ThereWasNothing:
mov [Key], byte ' '
jmp .PrintKeyLegend
; lea esi, [ProtectedWelcomeStr]
.KeyEscape:
call Reboot
jmp .PrintKeyLegend
.KeyLeft:
mov [Key], byte 'L'
add [Px], dword -1
jmp .PrintKeyLegend
.KeyUp:
mov [Key], byte 'U'
add [Py], dword -1
jmp .PrintKeyLegend
.KeyRight:
mov [Key], byte 'R'
add [Px], dword 1
jmp .PrintKeyLegend
.KeyDown:
mov [Key], byte 'D'
add [Py], dword 1
jmp .PrintKeyLegend
.KeyLess:
mov [Key], byte '<'
add [Zoom], dword -1
jmp .PrintKeyLegend
.KeyGreater:
mov [Key], byte '>'
add [Zoom], dword 1
.PrintKeyLegend:
lea esi, [ThereWasSomethingStr]
lea edi, [VIDEO + ScreenCoord((80-11), 24)]
mov ah, 0x2f
.print_loop:
mov al, BYTE [esi]
test al, al
jz .break_print_loop
stosw
inc esi
jmp .print_loop
.break_print_loop:
lea esi, [VarLabels]
lea edi, [ConversionBuffer]
mov ecx, VarLabelsLength
call CopyData
lea esi, [ConversionBuffer]
lea edi, [VIDEO + ScreenCoord(0, 24)]
mov ah, 0x0f
call PrintString
; lea esi, [ConversionBuffer]
mov eax, dword [Px]
sar eax, 4
call IntToString
; lea esi, [ConversionBuffer]
; ecx set by IntToString
mov edx, 7
mov al, ' '
call RightJustifyString
; esi still ConversionBuffer
mov ecx, edx
lea edi, [VIDEO + ScreenCoord(StrXStart, 24)]
mov ah, 0x70
call PrintString
; lea esi, [ConversionBuffer]
mov eax, dword [Py]
sar eax, 4
call IntToString
; lea esi, [ConversionBuffer]
; ecx set by IntToString
mov edx, 7
mov al, ' '
call RightJustifyString
; esi still ConversionBuffer
mov ecx, edx
lea edi, [VIDEO + ScreenCoord(StrYStart, 24)]
mov ah, 0x70
call PrintString
add [ColorOffset], dword 1
jmp DrawStuff
%include "Strings32.nasm"
Halt:
cli
hlt
jmp Halt
; ------------------------------------------------------------------------------
Reboot:
in al, 0x64
test al, 0x2 ; Wait for an empty Input Buffer
jne Reboot
mov al, 0xFE
out 0x64, al ; Send the reboot call to the keyboard controller
jmp Reboot
;;;;;;;;;;;;;;;;;;;;;;;;
;; Strings
;;;;;;;;;;;;;;;;;;;;;;;;
VarLabels: db "X:"
StrXStart equ $-VarLabels
db " "
db "Y:"
StrYStart equ $-VarLabels
db " "
VarLabelsLength equ $-VarLabels
ProtectedWelcomeStr: db " Placeholder for SingOS - 32 bit edition! ", 0
ProtectedWelcomeStrLength equ $-ProtectedWelcomeStr
TestStr: db "hello, world"
TestStrLength equ $-TestStr
ThereWasSomethingStr: db " KEY = '"
Key: db " ' ", 0
Px: dd 0
Py: dd 0
ColorOffset: dd 0
Zoom: dd (4<<9)
ConversionBuffer: times 40 db 0
align 512