;This code was written in NASM because I needed an Assembler that supports ;almost all 32-bit instructions and now it has become my FAVORITE assembler. [bits 16] %include "equates.asm" original_offset equ 8400h stack_size equ 200h start_code: ;%include "VGATest.asm" cli lgdt [gdtr] lidt [idtr] mov ax, sys_data_sel mov ds, ax mov es, ax mov fs, ax mov ax, linear_data_sel mov gs, ax mov ax, stack_sel mov ss, ax in al, 92h ;these 3 lines enable the a20 gate for > 20 bit access or al, 2 out 92h, al mov eax, cr0 or al, 1 mov cr0, eax jmp sys_code_sel:0 [bits 32] code32: mov ax, sys_data_sel mov ds, ax mov gs, ax mov ax, shared_data_sel mov fs, ax mov ax, linear_data_sel mov es, ax mov ax, stack_sel mov ss, ax mov ebp, stack_end - the_stack mov esp, ebp mov edi, 0b8000h ;Screen buffer, text 80x25 mov esi, message1 - code32 cld mov ecx, 174 mov al, blue charloop1: movsb stosb loop charloop1 ; push esi ; mov ecx, 32 ; mov ebx, "fart" ; mov eax, 0100000h ; mov esi, 0ffffah ;checkmem: ; mov dword [es:esi], ebx ; cmp dword [es:esi], ebx ; jz overit ; mov al, 0feh ; out 64h, al ;overit: ; add esi, eax ; loop checkmem ; pop esi mov al, 0aeh out 64h, al ;enable keyboard xor al, al sti theloop: cmp word [fs:keyptr], 0 jz theloop mov si, shared_data - code32 + keybuffer add si, word [fs:keyptr] movsb dec word [fs:keyptr] mov al, blue stosb jmp theloop jmp real_code_sel:0 [bits 16] code16: mov al, 0feh out 64h, al [bits 32] ;************** I N T E R R U P T H A N D L E R S **************** handlers: unhand equ $ - handlers pushad mov ecx, 14 mov esi, exc6 - code32 mov al, blue theloop_unhand: movsb stosb loop theloop_unhand mov al, 20h out 20h, al popad iret exception6 equ $ - handlers pushad mov ecx, 14 mov esi, exc6 - code32 mov al, 1 theloop_exc6: movsb stosb loop theloop_exc6 mov al, 20h out 20h, al popad iret exception8 equ $ - handlers theloop_exc8: push ax mov al, 20h out 20h, al pop ax iret ;*************** INTERRUPT 9 key equ $ - handlers ;mov al, 0aeh program must do this to enable keyboard to call ;out 64h, al interrupt 9. It must also make a loop to catch the ; key(s) it is waiting for. The int stores the ascii ; byte at es:di if dx = 1 and increments di. It also ; returns the ascii value in al and the scan code in ; ah. Value of bx is unreliable. ;mov al, 0adh and this to disable it from being called ;out 64h, al jmp over_int9_data ;*************** KEYBOARD DATA ****************** ctrldown db 0 altdown db 0 capslock db 0 lshift equ 42 rshift equ 54 ctrl equ 29 alt equ 56 caps equ 58 ;*************** END KEYBOARD DATA ***************** over_int9_data: pushad cmp word [fs:keyptr], 25 jnz go_on_int9 jmp do_nothing go_on_int9: in al, 60h ;get the key scan value cmp al, 129 jb regular_key jmp do_nothing regular_key: mov si, word [fs:keyptr] mov [fs:si + keyscanbuffer], al inc word [fs:keyptr] mov ah, al ;store it in ah so the program can access the scan cmp byte [capslock - code32], 1 jz caps_change_case mov ebx, scan_to_ascii - 1 - code32 ;set address of xlat table xlatb cmp al, 0 jz special_key jmp finish_up ;************* Special Key Handler *************** special_key: cmp ah, lshift jz shift_handler cmp ah, rshift jz shift_handler cmp ah, ctrl jz ctrl_handler cmp ah, alt jz alt_handler cmp ah, caps jz caps_handler jmp other_special ;****************** SHIFT ******************** shift_handler: mov al, 0 jmp finish_up ;****************** CTRL ********************* ctrl_handler: mov al, 0feh out 64h, al ;****************** ALT ********************* alt_handler: mov al, 0 jmp finish_up ;****************** CAPS LOCK ****************** caps_handler: mov byte [capslock - code32], 1 or byte [es:0417h], 64 ;01000000xb xor al, al dec word [fs:keyptr] jmp do_nothing caps_change_case: cmp ah, caps jz caps_head_back mov ebx, shift_scan_to_ascii - 1 - code32 ;set address of xlat table xlatb jmp finish_up caps_head_back: mov byte [capslock - code32], 0 and byte [es:0417h], 191 ;10111111xb xor al, al dec word [fs:keyptr] jmp do_nothing ;******************** OTHER **************** other_special: xor al, al jmp finish_up ;****************** END SPECIAL KEY HANDLERS ************* finish_up: mov si, word [fs:keyptr] mov byte [fs:si + keybuffer], al do_nothing: mov al, 20h ;Because it is a hardware int, this has to tell out 20h, al ;computer it is end of interrupt. popad iret ;**** REGULAR **** scan_to_ascii: ;scans: 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 db 27,49,50,51,52,53,54,55,56,57,48,45,61, 8, 9,113,119,101,114,116,121,117,105,111,112 ;scans: 26,27,28,29,30, 31, 32, 33, 34, 35, 36, 37, 38,39,40,41,42,43, 44, 45,46, 47,48, 49, 50 db 91,93,13, 0,97,115,100,102,103,104,106,107,108,59,39,96, 0,92,122,120,99,118,98,110,109 ;^ctrl left shift^ ;scans: 51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68 db 44,46,47, 0, 0, 0,32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; right shift^ ^ ^alt ^ ^-these are F1 through F10-^ ; ?print screen or *?^ ^caps lock db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;these 15 0's are the following: Numlock, Scroll Lock, Home or 7, Up or 8, ;Page Up or 9, Gray -, Left or 4, Center or 5, Right or 6, Gray +, End or 1, ;Down or 2, Page Down or 3, Ins or 0, Del or . TIMES 49 db 0;reserve 49 bytes between 83 and 133 for unused scan codes db 133,134 ;F11 and F12 db 0, 0 TIMES 121 db 0 ; cover to end = 255 ;**** SHIFTED SCAN TO ASCII **** shift_scan_to_ascii: ;scans: 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25 db 27,33,64,35,36,37,94,38,42,40,41,95,43, 8, 9,81,87,69,82,84,89,85,73,79,80 ;scans: 26, 27,28,29,30,31,32,33,34,35,36,37,38,39,40, 41,42, 43,44,45,46,47,48,49,50 db 123,125,13, 0,65,83,68,70,71,72,74,75,76,58,34,126, 0,124,90,88,67,86,66,78,77 ;^ctrl left shift^ ;scans: 51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68 db 60,62,63, 0, 0, 0,32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; right shift^ ^ ^alt ^ ^-these are F1 through F10-^ ; ?print screen or *?^ ^caps lock db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;these 15 0's are the following: Numlock, Scroll Lock, Home or 7, Up or 8, ;Page Up or 9, Gray -, Left or 4, Center or 5, Right or 6, Gray +, End or 1, ;Down or 2, Page Down or 3, Ins or 0, Del or . TIMES 49 db 0 ;reserve 49 bytes between 83 and 133 for unused scan codes db 133,134 ;F11 and F12 db 0, 0 TIMES 121 db 0 ; cover to end = 255 ;!!! For a more detailed scan to ascii chart, view c:\assembly\progs\cool\source\keyboard.asm ;******************** END OF INTERRUPT 9 HANDLER ***************** exceptionA equ $ - handlers pushad mov ecx, 14 mov esi, excA - code32 mov al, 1 theloop_excA: movsb stosb loop theloop_excA mov al, 20h out 20h, al popad iret exceptionD equ $ - handlers pushad mov ecx, 14 mov esi, excD - code32 mov al, 1 theloop_excD: movsb stosb loop theloop_excD pop esi pop ax mov ds, ax mov ecx, 5 rep movsb mov al, 20h out 20h, al popad iret ;*************** INTERRUPT SERVICE ROUTINE 20H isr20 equ $ - handlers iret end_handlers: ;******************* D A T A ******************** message1 db "PROTECTED MODE!" TIMES 150 db 0 db "Welcome!",0 exc6 db "Invalid opcode" excA db "invalid TSS " excD db "Gen protection" unknown db "Unknown Error " ;******* GDT ******** gdtr: dw gdt_end - gdt_start - 1 ;gdt limit dd gdt_start + original_offset gdt_start: dw 0 ;**** #1 dw 0 TIMES 4 db 0 ;**** #2 gdt_image equ $ - gdt_start dw 0ffffh dw gdt_start + original_offset db 0 db 0f2h db 0cfh db 0 ;**** #3 linear_data_sel equ $ - gdt_start dw 0ffffh ;limit dw 0 ;low word base db 0 ;low byte of high word base db 92h ;seg type and access flags db 0cfh ;flags, high nibble limit db 0 ;base 31:24 ;**** #4 interrupt_sel equ $ - gdt_start dw end_handlers - handlers - 1 dw original_offset + handlers db 0 db 09ah db 040h db 0 ;**** #5 stack_sel equ $ - gdt_start dw stack_end - the_stack - 1 dw original_offset + the_stack db 0 db 92h db 0c0h db 0 ;**** #6 bios_data_sel equ $ - gdt_start dw 05ffh dw original_offset + bios_emulation_data db 0 db 092h db 0 db 0 ;**** #7 vga_a0000h_sel equ $ - gdt_start dw 65535 dw 0 db 0ah ;low byte of high word: 0ah && 0000 = 0a0000h db 092h db 0 db 0 ;**** #8 vga_b0000h_sel equ $ - gdt_start dw 65535 dw 0 db 0bh db 092h db 0 db 0 ;**** #9 vga_b8000h_sel equ $ - gdt_start dw 32767 ; = 7fffh? dw 08000h db 0bh db 92h db 0 db 0 ;**** #10 vga_code_as_data equ $ - gdt_start dw 0ffffh dw original_offset + bios_image db 0 db 092h db 0 db 0 ;**** #11 vga_code equ $ - gdt_start dw 0ffffh dw original_offset + bios_image db 0 db 09eh db 040h db 0 ;**** #12 vga_stack_sel equ $ - gdt_start dw 03ffh dw original_offset + vga_stack db 0 db 92h db 0 db 0 ;**** #13 sys_code_sel equ $ - gdt_start dw 0ffffh dw original_offset + code32 db 0 db 09ah db 0cfh db 0 ;**** #14 sys_data_sel equ $ - gdt_start dw 0ffffh dw original_offset + code32 db 0 db 092h db 0cfh db 0 ;**** #15 real_code_sel equ $ - gdt_start dw 0ffffh dw original_offset + code16 db 0 db 09ah db 0 db 0 ;**** #16 real_data_sel equ $ - gdt_start dw 0ffffh dw original_offset + code16 db 0 db 082h db 0 db 0 ;**** #17 shared_data_sel equ $ - gdt_start dw 0ffffh dw original_offset + shared_data db 0 db 0f2h db 0cfh db 0 gdt_end: ;******** I D T ******** idtr: dw idt_end - idt_start - 1 dd idt_start + original_offset idt_start: dw unhand ; entry point 15:0 dw interrupt_sel ; selector db 0 ; word count db 0x8E ; type (32-bit Ring 0 interrupt gate) dw 0 ; entry point 31:16 (XXX - unhand >> 16) dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw exception6 dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw exception8 dw interrupt_sel db 0 db 0x8E dw 0 ; user interrupt handler dw key dw interrupt_sel db 0 db 0x8e dw 0 ;dw unhand ;dw interrupt_sel ;db 0 ;db 0x8e ;dw 0 dw exceptionA dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw exceptionD dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw unhand dw interrupt_sel db 0 db 0x8E dw 0 dw isr20 dw interrupt_sel db 0 db 0x8E dw 0 dw key dw interrupt_sel db 0 db 0x8e dw0 ;dw unhand ;dw interrupt_sel ;db 0 ;db 0x8E ;dw 0 idt_end: ;******** S T A C K ******* the_stack: TIMES stack_size db 0 stack_end: shared_data: keyptr equ 0 dw 0 keybuffer equ $ - shared_data TIMES 25 db 0 keyscanbuffer equ $ - shared_data TIMES 25 db 0 curdir equ $ - shared_data TIMES 80 db 0 xcoord equ $ - shared_data dw 0 ycoord equ $ - shared_data dw 0 vgabiosptr equ $ - shared_data dd 0 ;start dd 0 ;PM VGA BIOS entry point dd 0 ;offset to initialization code right_before_end: resb 512 - right_before_end + shared_data ;****************** E N D O F C O D E *************** bios_emulation_data: TIMES 0600h db 0 vga_stack: TIMES 1024 db 0 bios_image: