%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