;******************************************************************************************************************************** ;* * ;* File: Boot.asm * ;* * ;* This file contains the bootstrap (including Master Boot Record) for PwnOS. * ;* * ;* Segments: * ;* - contains the space-optimized Master Boot Record code * ;* - contains the global data for the 1st-level bootstrap code * ;* - contains the 1st-level bootstrap code that loads the core * ;* * ;* Includes: * ;* * ;* * ;* See Also: * ;* * ;* * ;* Authors: * ;* - Neil G. Dickson * ;* * ;******************************************************************************************************************************** .686p .xmm OPTION language:stdcall include Boot.inc ;******************************************************************************************************************************** ;* * ;* Section: MBR * ;* * ;* This segment contains the master boot record of PwnOS * ;* * ;<******************************************************************************************************************************* MBR segment use16 ;This segment is optimized for space (not even 512 bytes in which to do as much as possible) ASSUME CS:MBR,DS:MBR,ES:MBR,FS:MBR,GS:MBR,SS:MBR xor ax,ax ;sets some initial values mov ds,ax ; mov ss,ax ; mov sp,7FFEh ;stack goes for 512 bytes after this sector mov es,ax ;code below calling int 10h,4F00h and int 10h,4F01h is dependent on es=ds=0 push dx ;initial value of dl indicates boot drive for int 13h read sectors call ;keep this value in dl so that the Protected-Mode code doesn't need to read this sector again to check partitions ;This next bit is the best way that I've found (as far as space optimization) to: ;-set IOPL to 0 ;-enable interrupts (IF=1) ;-set the direction to forward (DF=0) ;-check whether CPUID is supported by seeing if the Identification Flag can be modified (if not supported, boot error) pushfd mov bx,sp and dword ptr [bx],EFLAGS_IDENTIFICATION_FLAG mov ax,word ptr [bx][2] xor dword ptr [bx],EFLAGS_SET_BIT or EFLAGS_INT_ENABLE_FLAG or EFLAGS_IDENTIFICATION_FLAG popfd pushfd pop cx pop cx and cx,EFLAGS_IDENTIFICATION_FLAG shr 16 cmp ax,cx jne NotCompleteError ;This occurs whenever the boot doesn't work at all. (pre-486, drive error, below VBE 2.0) ;just displays "Boot Error" (& value of ax if in Text Testing Mode) CompleteError: IF TEXT_TESTING_MODE push ax ENDIF xor di,di mov si,offset TextBootError push 0B800h pop es mov ah,0Ch NextMessageLetter: lodsb test al,al jz MessageEnd stosw jmp NextMessageLetter IF TEXT_TESTING_MODE ;displays floppy read error code & num sectors read MessageEnd: pop dx mov cx,4 ;4 hex digits mov ah,09h ;bright blue FailDigitLoop: rol dx,4 ;highest -> lowest order mov al,0Fh and al,dl add al,90h ;get hex char in al daa ; adc al,40h ; daa ; stosw loop FailDigitLoop jmp $ ELSE MessageEnd equ $ ;loop forever (at least until the user realises to turn the computer off) ENDIF ;This is placed here to save one jump. ;Reset the drive and go back for another try of the same track ReadTrackError: dec di jz CompleteError ;give up if 5 fails on same track xor ax,ax int 13h jmp ReadTrack IF FLOPPY_BOOT_MODE ;MBR is on a floppy drive NotCompleteError: ;Load rest of track 0 from the drive, which has code to load all OS stuff from a bootable partition mov bx,PA_TRACK0 ;must be such that the disc read won't go over a segment boundary xor dh,dh mov cx,0002h ;start 1 sector after 1st sector (already have MBR) xor si,si ReadNewTrack: mov di,0005h ReadTrack: mov ah,02h mov al,FloppyReadInfo[si] int 13h ;can't read more sectors than on one head of one cylinder (maybe my BIOS is just ancient) jc ReadTrackError xor dh,1 ;toggle between heads jnz NotNextCyliner inc ch ;next cylinder NotNextCyliner: add bh,FloppyReadSizes[si] ;LSB of sizes is 0 inc si ;next read mov cl,01h ;start reading all other tracks from 1st sector cmp si,lengthof FloppyReadInfo jne ReadNewTrack ELSE ;MBR is on a harddrive NotCompleteError: ;Load rest of track 0 from the drive, which has code to load all OS stuff from a bootable partition mov bx,PA_TRACK0 ;must be such that the disc read won't go over a segment boundary xor dh,dh mov cx,0002h xor si,si mov di,0005h ReadTrack: mov ax,0200h or SZ_TRACK0/512 int 13h ;can't read more sectors than on one head of one cylinder (maybe my BIOS is just ancient) jc ReadTrackError ENDIF ;Enable the A20 addressing bit, which is done through the PS2 controller (it's usually, but not always enabled) WaitToSendWriteCommand: in al,PS2_STATUS_REGR test al,PS2_OUTPUT_BUFFER_FULL_BIT jnz WaitToSendWriteCommand mov al,PS2_C64_WRITE_OUTPUT_PORT out PS2_COMMAND_REGW,al WaitToWriteOutputPort: in al,PS2_STATUS_REGR test al,PS2_OUTPUT_BUFFER_FULL_BIT jnz WaitToWriteOutputPort mov al,PS2_OUTPUT_PORT_NORESET_BIT or PS2_OUTPUT_PORT_A20_BIT ;other bits can be zero out PS2_DATA_REG,al ;Set the video mode. add di,8000h ;will put the data after where we've loaded mov ax,4F00h mov dword ptr [di],32454256h ;"VBE2" indicates that VBE 3.0 info is wanted (who knows why VESA chose that) int 10h ;puts 512 bytes of VBE info at es:di (according to VESA) cmp byte ptr [di][5],2 ;Major Version Number (must be at least VBE 2.0) jb CompleteError ;dependent on es=ds=0 because this int 10h function uses es:di, but MBR uses ds:di lfs si,[di][0Eh] ;Video Mode Table's segment:offset add di,512 ;according to VESA, fs:si could be within the VBEInfoBlock we just got, and as was ;discovered the hard way, that means it can be pointing into this copy it made, ;so need to move es:di to after 512 bytes loaded above NextMode: mov cx,fs:[si] cmp cx,-1 je CompleteError ;end of Mode Table (mode wasn't found, darn) inc si inc si mov ax,4F01h ;gets Mode Info int 10h ;dependent on es=ds=0 because this int 10h function uses es:di, but MBR uses ds:di ;cmp ax,004Fh ;I won't put this in, 'cause the graphics card must be screwed ;jnz CompleteError ;if this function fails while VBE 2.0 is supported. ASSUME DI:PTR VBEMODEINFOBLOCK mov al,byte ptr [di].ModeAttributes ;check bit0 to see if mode supported, bit4 to see if a Graphics Mode, & bit7 to see if Linear Frame Buffer supported and al,91h ;all those bits together make 91h cmp al,91h ; jne NextMode ;if one of them not set, NO SOUP FOR YOU!!!! cmp [di].XResolution,X_RESOLUTION_WANTED jne NextMode cmp [di].YResolution,Y_RESOLUTION_WANTED jne NextMode cmp [di].BitsPerPixel,MIN_BITS_PER_PIXEL jb NextMode FoundMode: ;now copy mode info so can refer back to it mov bx,cx ; push ds ; push es ; pop ds ; push PA_VID_INFO/10h ; pop es ; xor si,si ;it's on a para alignment ; xchg si,di mov si,di mov di,PA_VID_INFO mov cx,SZ_VID_INFO/2 rep movsw ;dependent on es=ds=0 mov [di][-SZ_VID_INFO].Reserved3,bx ;put the mode number in a reseved spot ; pop ds IF TEXT_TESTING_MODE EQ FALSE mov ax,4F02h or bx,4000h ;use Linear Frame Buffer int 10h mov ax,4F05h ;make sure bank0 eventhough using LFB xor bx,bx ;some computers do not have it at bank0 automatically xor dx,dx int 10h ASSUME DI:NOTHING ENDIF ;Turn off interrupts now cli xor di,di mov cx,SZ_STORED_GDT/2 mov si,PA_STORED_GDT ; mov es,di ;in segment 0000h, but es is already 0 IF PA_GDT NE 0 mov di,PA_GDT ENDIF rep movsw pop dx ;restore number indicating boot drive db 066h lidt fword ptr pIDT db 066h lgdt fword ptr pGDT xor eax,eax ;clears the cache disable bit and the not-write-through bit (which makes memory writeback type after 486) mov al,CR0_PROTECTION_BIT or CR0_SET_BIT ;they're in the first byte, so this works mov cr0,eax db 067h db 066h db 0EAh dd offset PA_BOOTCODE32 dw SELECTOR_CORE_CODE ;### SEE - TODO2: ### pIDT dw SZ_IDT-1 dd PA_IDT ;phys addr to start, because no paging yet pGDT dw SZ_GDT-1 dd PA_GDT ; TextBootError db "Boot Error",0 IF FLOPPY_BOOT_MODE ;MBR is on a floppy drive IF SZ_TRACK0 LE 17*512 FloppyReadInfo db SZ_TRACK0/512 FloppyReadSizes db SZ_TRACK0/256 ELSEIF SZ_TRACK0 LE (17+18)*512 FloppyReadInfo db 17,(SZ_TRACK0/512)-17 FloppyReadSizes db 17*512/256,(SZ_TRACK0/256)-17*512/256 ELSEIF SZ_TRACK0 LE (17+18+18)*512 FloppyReadInfo db 17,18,(SZ_TRACK0/512)-17-18 FloppyReadSizes db 17*512/256,18*512/256,(SZ_TRACK0/256)-(17+18)*512/256 ELSEIF SZ_TRACK0 LE (17+18+18+6)*512 FloppyReadInfo db 17,18,18,(SZ_TRACK0/512)-17-18-18 FloppyReadSizes db 17*512/256,18*512/256,18*512/256,(SZ_TRACK0/256)-(17+18+18)*512/256 ELSE .err ENDIF ELSE IF SZ_TRACK0 GT 62*512 .err ELSEIF SZ_TRACK0 GT (17+18+18+6)*512 .err ENDIF ENDIF ;### SEE - TODO1: ### ;org MBR_ENTRY0_OFFSET ;PartitionEntry1 PARTITIONENTRY <0,?,?,?,MBR_PARTTYPE_DOSFAT12,?,?,?,18*(3+7)/2,2880-18*(3+7)> ORG 01FEh ;magic number must be in last 2 bytes of MBR MBRKey word 0AA55h ;magic number telling BIOS that drive is bootable MBR ends ;>******************************************************************************************************************************* ;* * ;* Section: BootData * ;* * ;* This segment contains data for the 1st-level bootstrap code of PwnOS * ;* * ;* IT MUST BE LESS THAN OR EQUAL TO 2KB LARGE * ;* * ;<******************************************************************************************************************************* BootData segment use32 page ;******************************************************************************************************************************** ;* * ;* Array: GDT * ;* INITIAL GLOBAL DESCRIPTOR TABLE * ;* * ;<******************************************************************************************************************************* GDT dq 0 ;NULL descriptor ;System code segment descriptor: 08h dw 0FFFFh dw 0 db 0 db DESC_CODE_BIT or DESC_C_READABLE_BIT or DESC_NOT_SYSTEM_BIT or DESC_PRESENT_BIT or DESC_PRIV_LEVEL0 db 0Fh or DESC_GRANULARITY_BIT or DESC_SIZE_BIT db 0 ;System data segment descriptor: 10h dw 0FFFFh dw 0 db 0 db DESC_D_WRITABLE_BIT or DESC_NOT_SYSTEM_BIT or DESC_PRESENT_BIT or DESC_PRIV_LEVEL0 db 0Fh or DESC_GRANULARITY_BIT or DESC_SIZE_BIT db 0 ;System call gate descriptor: 18h dw lowword (VA_SYSTEM_CALL_GATE) dw SELECTOR_CORE_CODE or DESC_PRIV_LEVEL0 db 0h ;copies no stack entries from caller as parameters db DESC_S_CALL_GATE_32 or DESC_PRESENT_BIT or DESC_PRIV_LEVEL3 dw highword (VA_SYSTEM_CALL_GATE) ;ProcessRouter TSS descriptor: 20h TSS_DESC VA_PROCESS_ROUTER_TSS,DESC_PRIV_LEVEL0 ;User code segment descriptor: 28h dw 0FFFFh dw 0 db 0 db DESC_CODE_BIT or DESC_C_READABLE_BIT or DESC_NOT_SYSTEM_BIT or DESC_PRESENT_BIT or DESC_PRIV_LEVEL3 db 0Fh or DESC_GRANULARITY_BIT or DESC_SIZE_BIT db 0 ;User data segment descriptor: 30h dw 0FFFFh dw 0 db 0 db DESC_D_WRITABLE_BIT or DESC_NOT_SYSTEM_BIT or DESC_PRESENT_BIT or DESC_PRIV_LEVEL3 db 0Fh or DESC_GRANULARITY_BIT or DESC_SIZE_BIT db 0 ;TSS descriptors can be added/removed after common bootup, ;because need at least 1 for each processor ;Change SIZE_STORED_GDT in Core\GDT.inc when adding/removing constant descriptors ;Change *_SELECTOR in Core\GDT.inc when moving descriptors ;>******************************************************************************************************************************* ;* * ;* Array: IDT * ;* INTERRUPT DESCRIPTOR TABLE * ;* * ;<******************************************************************************************************************************* IDT: INT_DESC offset IntDivError ;00 Divide Error INT_DESC offset IntOtherError ;01 Debug Exception (N/A) INT_DESC offset IntOtherError ;02 NonMaskable Interrupt (N/A) INT_DESC offset IntOtherError ;03 Breakpoint Exception (N/A) INT_DESC offset IntOtherError ;04 Overflow Exception (N/A) INT_DESC offset IntOtherError ;05 BOUND Range Exceeded Exception (N/A) INT_DESC offset IntInvalidOpcode ;06 Invalid Opcode (#UD) INT_DESC offset IntDeviceNotAvailable ;07 Device Not Available (#NM; occurs on first FPU/MMX/SSE instruction after a task switch) INT_DESC offset IntDoubleFault ;08 Double Fault INT_DESC offset IntOtherError ;09 Coprocessor Segment Overrun (Obsolete) INT_DESC offset IntInvalidTSS ;0A Invalid TSS Exception INT_DESC offset IntSegmentNotPresent ;0B Segment Not Present INT_DESC offset IntStackFault ;0C Stack Fault Exception INT_DESC offset IntProtectionFault ;0D General Protection Fault INT_DESC offset IntPageFault ;0E Page Fault Exception INT_DESC offset IntOtherError ;0F x87 FPU Floating-Point Error (N/A) INT_DESC offset IntOtherError ;10 Alignment Check Exception (N/A, SSE instructions generate GPF) INT_DESC offset IntMachineCheckEx ;11 Machine-Check Exception INT_DESC offset IntSIMDException ;12 SIMD Floating-Point Exception (N/A) ;dq (20h-13h) dup (NULL) ;13-1F Reserved, but can be used by external devices with the IOAPIC INT_DESC offset IntIRQPITInit ;13 IRQ0 Programmable Interval Timer ;if # changes, change in Core\Core.inc INT_DESC offset IntIRQKeyboard ;14 IRQ1 PS2 Keyboard ; ;INT_DESC offset IntIRQ2 ; IRQ2 Cascade from PIC2, obsolete INT_DESC offset IntIRQCOM24 ;15 IRQ3 COM2/COM4 ; INT_DESC offset IntIRQCOM13 ;16 IRQ4 COM1/COM3 ; INT_DESC offset IntIRQSoundCard ;17 IRQ5 Sound Card ; INT_DESC offset IntIRQFloppyDrive ;18 IRQ6 Floppy Drive ; INT_DESC offset IntIRQParallel ;19 IRQ7 Parallel Comms ; INT_DESC offset IntIRQCMOSClock ;1A IRQ8 CMOS Clock ; ;dq 3 dup (NULL) ; IRQ9-11 undefined INT_DESC offset IntIRQMouse ;1B IRQ12 PS2 Mouse ; ;dq NULL ; IRQ13 undefined INT_DESC offset IntIRQIDE0 ;1C IRQ14 IDE0 Done ; INT_DESC offset IntIRQIDE1 ;1D IRQ15 IDE1 Done ; INT_DESC offset IntAPICError ;1E APIC Error ; INT_DESC offset IntAPICSpurious ;1F APIC Spurious-Interrupt ; INT_DESC offset IntAPICTimerInit ;20 APIC Timer ; INT_DESC offset IntHangInit ;21 Hang Execution ; INT_DESC offset IntIRQUSB ;22 IRQ19 USB Port ; INT_DESC offset IntIRQNetwork ;23 IRQ18 Network Card ; ;Change N_INTERRUPTS in Core\Core.inc when adding/removing descriptors ;>******************************************************************************************************************************* ;* * ;* OTHER BOOT LOADER DATA * ;* * ;<******************************************************************************************************************************* PartitionList PARTITIONINFO_NTFS MAX_BOOT_PARTITIONS dup (<>) NumProcessors dword 0 ;dword instead of byte for fast access only ProcessorWaitCount dword 0 WaitFlag dword 0 BIT_WAITFLAG_SIPI equ 0 ;(bit0) set to indicate that no other processors may handle the SIPI at the same time WAITFLAG_SIPI equ 1 ; ;WAITFLAG_INIT_TIMER equ 2 ;(bit1) set to indicate that one of the initial timers has finished APICTicksPer100ms dword ? ClocksPer10ms dword ? pLocalAPICBoot dword ? IF TEXT_TESTING_MODE OR GFX_TESTING_MODE LineNum dword 0 TextWaitFlag dword 0 ENDIF IRQInts byte INT_PIT, INT_KEYBOARD, -1, INT_COM2_COM4,\ ;for default IRQ details INT_COM1_COM3, INT_SOUND_CARD, INT_FLOPPY, INT_PARALLEL,\ ;-1 indicates unused INT_CMOS_CLOCK, -1, -1, -1,\ ;80h set indicates level-sensitive (not edge-sensitive) INT_MOUSE, -1, INT_IDE0, INT_IDE1,\ ;40h set indicates active-low (not active high) -1, -1, INT_NETWORK or 0C0h, INT_USB or 0C0h,\ -1, -1, -1, -1 IOAPICInts byte INT_PIT, INT_KEYBOARD, -1, INT_COM2_COM4,\ ;for adjusted IRQ Global System Interrupts INT_COM1_COM3, INT_SOUND_CARD, INT_FLOPPY, INT_PARALLEL,\ ;from Interrupt Source Override structures in MADT INT_CMOS_CLOCK, -1, -1, -1,\ ;stuff same as above INT_MOUSE, -1, INT_IDE0, INT_IDE1,\ -1, -1, INT_NETWORK or 0C0h, INT_USB or 0C0h,\ -1, -1, -1, -1 ProcessorIDs byte MAX_NUM_PROCESSORS dup (?) IOAPICID byte ? pIOAPIC dword NULL ATADriveNumTable byte ATA_DEVICE_LBA or ATA_DEVICE_DEV0, ATA_DEVICE_LBA or ATA_DEVICE_DEV1,\ ATA_DEVICE_LBA or ATA_DEVICE_DEV0 or 1, ATA_DEVICE_LBA or ATA_DEVICE_DEV1 or 1 BootDriveSaved byte ? NumPartitions byte ? ALIGN 4 PwnOSUnicode word "P","w","n","O","S",0 IF IMAGE_TEST_MODE CoreBinUnicode word "P","w","n","O","S",".","b","m","p",0 ELSE CoreBinUnicode word "C","o","r","e",".","b","i","n",0;"P","w","n","O","S",".","b","m","p",0 ENDIF BootExeUnicode word "B","o","o","t",".","e","x","e",0 BootProcess PROCESSSTRUCT ALIGN 256 BootTask EXTENDEDTSS <,,<>,,<>> ;> BootData ends ;>******************************************************************************************************************************* ;* * ;* Section: Boot * ;* * ;* This segment contains the 1st-level bootstrap code of PwnOS * ;* * ;<******************************************************************************************************************************* Boot segment use32 ASSUME CS:Boot,DS:BootData,ES:BootData,FS:BootData,GS:BootData,SS:BootData ;******************************************************************************************************************************** ;* * ;* Procedure: 32-bit Entry Point * ;* * ;* This code sets up some basic 32-bit Protected Mode stuff * ;* * ;<******************************************************************************************************************************* xor eax,eax ;set segment registers mov al,SELECTOR_CORE_DATA mov ebx,CR4_OSFXSR_BIT or CR4_OSXMMEXCPT_BIT or CR4_PMC_ENABLE_BIT or CR4_MACHINE_CHK_ENABLE_BIT or CR4_PAGE_GLOBAL_ENABLE_BIT mov ds,eax ;omits useless prefix, even though it's just mov ds,ax mov es,eax ; mov ss,eax ; mov esp,PA_PL0_STACK_TOP ;good practice to set esp right after ss, because interrupts disabled until instruction after mov ss, mov fs,eax ; mov gs,eax ; TestOutputWait "BSPro Loaded Seg Regs" mov BootDriveSaved,dl ;save boot drive # used for int 13h, so that don't have to read MBR again, and could boot to a normal bootable partition with precedence given to this drive mov cr4,ebx TestOutputWait "BSPro Set CR4" IF TEXT_TESTING_MODE mov eax,BOOT_END cmp eax,7C00h jbe BootEndOkay TestOutputVar "Boot segment too big: ends at ",BOOT_END jmp $ BootEndOkay: mov eax,PRE_SIPI_END cmp eax,OFFSET_SIPI jbe PreSIPIOkay TestOutputVar "Pre-SIPI code too big: ends at ",PRE_SIPI_END TestOutputVar " SIPI at ",OFFSET_SIPI jmp $ PreSIPIOkay: ENDIF IF PA_TRACK0+SZ_TRACK0 GT 7C00h echo Error: Track0 loading writes over MBR .err ENDIF IF GFX_TESTING_MODE mov eax,PA_VID_INFO mov edi,[eax].VBEMODEINFOBLOCK.PhysBasePtr mov ecx,786432/4 mov eax,08000FFh ;Purple @@: stosd dec edi dec ecx jnz @B ENDIF ; TestOutputWait "About to check Gate A20" ;WaitToSendReadCommand: ;ensure that A20 address line enabled ; in al,PS2_STATUS_REGR ; test al,PS2_OUTPUT_BUFFER_FULL_BIT ; jnz WaitToSendReadCommand ; mov al,PS2_C64_READ_OUTPUT_PORT ; out PS2_COMMAND_REGW,al ;WaitToReadOutputPort: ; in al,PS2_STATUS_REGR ; test al,PS2_INPUT_BUFFER_FULL_BIT ; jz WaitToReadOutputPort ; in al,PS2_DATA_REG ; test al,PS2_OUTPUT_PORT_A20_BIT ; jz A20Disabled ; TestOutputWait "Gate A20 Enabled" TestOutputWait "Skipped Gate A20 Check" IF FLOPPY_BOOT_MODE mov dx,FDD_DIGITAL_OUTPUT_REG ;turn off floppy drive motor in al,dx ; and al,0Fh ; out dx,al ; ENDIF ;### SEE - TODO14: ### mov al,ATA_DEVCNT_nIEN ;disable harddrive interrupts mov dx,ATA_DEVICE_CONTROL_REGW ;(to be enabled after Boot, or right here once IDE Bus-Mastering implemented) out dx,al ; ;>******************************************************************************************************************************* ;* * ;* Procedure: ACPI Boot * ;* * ;* Searches for Root System Description Pointer (RDSP) * ;* * ;<******************************************************************************************************************************* IF GFX_TESTING_MODE mov eax,PA_VID_INFO mov edi,[eax].VBEMODEINFOBLOCK.PhysBasePtr mov ecx,786432/4 mov eax,0FF00FFh ;Magenta @@: stosd dec edi dec ecx jnz @B ENDIF xor eax,eax ;search for Root System Description Pointer structure in 1st KB of Extended BIOS Data Area movaxoff OFFSET_EBDA_SEG ; xor ecx,ecx ; shl eax,4 ; TestOutputVar "EBDA at ",eax xor ecx,ecx ; ASSUME EAX:PTR ROOTSYSDESCPOINTER,ECX:PTR ROOTSYSDESCPOINTER ; FindRSDP1: ; cmp dword ptr [eax][ecx].Signature," DSR" ; ;actually "RSD ", but MASM will flip it when checking anything more than a byte size jne NextFindRSDP1 ; cmp dword ptr [eax][ecx].Signature[4]," RTP" ; ;actually "PTR " jne NextFindRSDP1 ; lea ebx,[ecx][20 - sizeof ROOTSYSDESCPOINTER.Signature] ; ;end checksum count after 20 bytes (as specification dictates) mov dl,low ("R"+"S"+"D"+" "+"P"+"T"+"R"+" ") ; ;the Signature bytes are already known, so just start with their sum RSDPChecksum1: ; ; add dl,[eax][ecx][sizeof ROOTSYSDESCPOINTER.Signature] ; ;and start after the Signature inc ecx ; cmp ecx,ebx ; jne RSDPChecksum1 ; sub ecx,20 - sizeof ROOTSYSDESCPOINTER.Signature ; test dl,dl ; jz FoundRSDP ; NextFindRSDP1: ; add ecx,16 ; ;must be 16-byte aligned cmp ecx,1024 ; jne FindRSDP1 ; mov eax,0E0000h ;search in 0E0000h-0FFFFFh BIOS ROM area xor ecx,ecx ; ;done so that eax+ecx will point to found structure FindRSDP2: ; cmp dword ptr [eax].Signature," DSR" ; ;actually "RSD ", but MASM will flip it when checking anything more than a byte size jne NextFindRSDP2 ; cmp dword ptr [eax].Signature[4]," RTP" ; ;actually "PTR " jne NextFindRSDP2 ; lea ebx,[eax][20 - sizeof ROOTSYSDESCPOINTER.Signature] ; ;end checksum count after 20 bytes (as specification dictates) mov dl,low ("R"+"S"+"D"+" "+"P"+"T"+"R"+" ") ; ;the Signature bytes are already known, so just start with their sum RSDPChecksum2: ; ; add dl,[eax][sizeof ROOTSYSDESCPOINTER.Signature] ; ;and start after the Signature inc eax ; cmp eax,ebx ; jne RSDPChecksum2 ; sub eax,20 - sizeof ROOTSYSDESCPOINTER.Signature ; test dl,dl ; jz FoundRSDP ; NextFindRSDP2: ; add eax,16 ; cmp eax,100000h ; jne FindRSDP2 ; ASSUME EAX:NOTHING,ECX:NOTHING ;>******************************************************************************************************************************* ;* * ;* Procedure: Not Good Enough * ;* * ;* This is where the bootloader goes if the computer boot doesn't go properly, like if the RSDP isn't found, or if the ACPI * ;* info isn't valid. * ;* * ;<******************************************************************************************************************************* TestOutputWait "Root Sys Description Table not found" NotGoodEnough: ;### SEE - TODO23: ### jmp $ ; jmp CommonBoot ;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ oh well \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ ;>******************************************************************************************************************************* ;* * ;* Procedure: ACPI Boot Continued * ;* * ;* RSDP found, so scan RSDT for Multiple APIC Description Table (MADT) * ;* * ;<******************************************************************************************************************************* FoundRSDP: add eax,ecx ASSUME EAX:PTR ROOTSYSDESCPOINTER IF TEXT_TESTING_MODE TestOutputVar "Root Sys Description Pointer found at ",eax TestOutputVar "Root Sys Description Table at ",[eax].RSDTAddress xor edx,edx mov dl,[eax].Revision TestOutputVar "Root Sys Description Pointer version ",edx test dl,dl jz ShortRSDP TestOutputVar "Root Sys Description Pointer length: ",dword ptr [eax].ThisLength TestOutputVar "Ext Sys Description Table at (low) ",dword ptr [eax].XSDTAddress TestOutputVar " (high) ",dword ptr [eax].XSDTAddress[4] ShortRSDP: ENDIF ;### SEE - TODO16: ### ; mov dl,[eax].Revision ; test dl,dl ; jnz UseXSDT UseRSDT: ;validate RSDT mov esi,[eax].RSDTAddress ; ASSUME ESI:PTR SYSDESCTABLEHEADER ; TestOutputVar "Root Sys Description Table length: ",[esi].ThisLength cmp dword ptr [esi].Signature,"TDSR" ; ;actually "RSDT" jne InvalidRSDT ; cmp [esi].ThisLength,sizeof SYSDESCTABLEHEADER ; ;can't have length that's smaller than SYSDESCTABLEHEADER jb InvalidRSDT ; ; test [esi].ThisLength,3h ; ;can't have length that's not multiple of 4 jnz InvalidRSDT ; ;(sizeof SYSDESCTABLEHEADER is multiple of 4, and 32-bit pointers follow) cmp [esi].Revision,1 ; ;Revision is 1 even in ACPI version 1.0b jb InvalidRSDT ; ;but check anyway mov ecx,esi ; push esi ; xor dl,dl ; add ecx,[esi].ThisLength ; RSDTChecksum: ; add dl,byte ptr [esi] ; inc esi ; cmp esi,ecx ; jne RSDTChecksum ; pop esi ; test dl,dl ; jnz InvalidRSDT ; TestOutputWait "Root Sys Description Table validated" add esi,sizeof SYSDESCTABLEHEADER ;scan RSDT for MADT entries RSDTPointerLoop: ; cmp esi,ecx ; je DoneRSDTScan ; lodsd ; ASSUME EAX:PTR SYSDESCTABLEHEADER ; cmp dword ptr [eax].Signature,"CIPA" ; ;actually "APIC" jne RSDTPointerLoop ; IF TEXT_TESTING_MODE TestOutputVar "Multiple APIC Description Table pointer found at ",esi TestOutputVar "Multiple APIC Description Table found at ",eax TestOutputVar "Multiple APIC Description Table length: ",[eax].ThisLength push ecx xor ecx,ecx mov cl,[eax].Revision TestOutputVar "Multiple APIC Description Table version ",ecx pop ecx ENDIF ;validate MADT cmp [eax].ThisLength,sizeof SYSDESCTABLEHEADER +8 ; ;can't have length that's smaller than SYSDESCTABLEHEADER plus 8 bytes for LocalAPICAddress & Flags jb InvalidMADT ; ; ; cmp [eax].Revision,2 ; ;Revision is 2 in ACPI 3.0 and is 1 in ACPI 1.0b ; jb InvalidMADT ; ;but check anyway mov ebx,eax ; push eax ; xor dl,dl ; add ebx,[eax].ThisLength ; MADTChecksum: ; add dl,byte ptr [eax] ; inc eax ; cmp eax,ebx ; jne MADTChecksum ; pop eax ; test dl,dl ; jnz InvalidMADT ; TestOutputWait "Multiple APIC Description Table validated" mov edx,dword ptr [eax][sizeof SYSDESCTABLEHEADER] ;Local APIC Address for all Local APICs TestOutputVar "Local APIC Base at",edx add eax,sizeof SYSDESCTABLEHEADER +8 ;scan MADT for useful entries mov pLocalAPICBoot,edx ; MADTStructureLoop: ; cmp eax,ebx ; je RSDTPointerLoop ; ja InvalidMADT ; mov dl,byte ptr [eax] ; ;structure type cmp dl,MADT_STRUCT_SOURCE_OVERRIDE ; ja NextMADTStructure ; je IntSourceOverride ; test dl,dl ; jnz IOAPICStructure ; LocalAPICStructure: ;get Local APIC IDs from structures of type 0: "Processor Local APIC" ASSUME EAX:PTR MADTLAPICSTRUCT ; IF TEXT_TESTING_MODE ; xor edx,edx ; ENDIF ; mov edi,NumProcessors ; mov dl,[eax].APICID ; TestOutputVar "Local APIC Structure w\ APIC ID ",edx ; test [eax].Flags,MADT_LAPIC_FLAG_ENABLED ; jz NextMADTStructure ; ;don't use processor unless valid TestOutputWait "Local APIC valid" ; mov ProcessorIDs[edi],dl ; inc NumProcessors ; jmp NextMADTStructure ; IOAPICStructure: ;get I/O APIC ID and check if more than 1 IOAPIC with structures of type 1: "I/O APIC" ASSUME EAX:PTR MADTIOAPICSTRUCT ; IF TEXT_TESTING_MODE ; xor edx,edx ; ENDIF ; mov dl,[eax].IOAPICID ; mov edi,[eax].pIOAPIC ; TestOutputVar "IO APIC Structure w\ APIC ID ",edx ; TestOutputVar "IO APIC Base at ",edi ; mov IOAPICID,dl cmp pIOAPIC,NULL jne NoMultiIOAPICSupport mov pIOAPIC,edi jmp NextMADTStructure IntSourceOverride: ;get IO redirection info from structures of type 2: "Interrupt Source Override", and adjust entries in IOAPICInts ASSUME EAX:PTR MADTSOURCEOVERRIDE ; movzx edi,[eax].Source ; TestOutputVar "Source Override from IRQ ",edi ; cmp [eax].Bus,0 ; ;0 represents ISA jne OnlyISAOverrideSupport ; mov dl,IRQInts[edi] ; ;### SEE - TODO23: ### ; mov IOAPICInts[edi],-1 ; ;set old interrupt as unused mov edi,[eax].GlobalSystemInt ; mov dh,byte ptr [eax].Flags ; TestOutputVar "Source Override to GSI ",edi ; TestOutputVar "Source Override Int w\ Flags (lowword)",edx; test dh,MADT_OVERRIDE_POLARITY_CHANGE ; jz NoPolarityChange ; ;and dl,40h ;put this in if any ISA Ints default to active-low, also put in check for -1 from IRQInts test dh,MADT_OVERRIDE_POLARITY_ACTLOW-MADT_OVERRIDE_POLARITY_CHANGE ; jz NoPolarityChange ; or dl,40h ; NoPolarityChange: ; test dh,MADT_OVERRIDE_TRIGGER_CHANGE ; jz NoTriggerChange ; ;and dl,80h ;put this in if any ISA Ints default to level-triggered, also put in check for -1 from IRQInts test dh,MADT_OVERRIDE_TRIGGER_LEVEL-MADT_OVERRIDE_TRIGGER_CHANGE ; jz NoTriggerChange ; or dl,80h ; NoTriggerChange: ; mov IOAPICInts[edi],dl ; NextMADTStructure: ;skip to next MADT structure xor edx,edx ; mov dl,byte ptr [eax][1] ; ;structure length add eax,edx ; jmp MADTStructureLoop ; DoneRSDTScan: ASSUME EAX:NOTHING ASSUME ESI:NOTHING ;### SEE - TODO16: ### comment ^ UseXSDT: ASSUME EAX:PTR ROOTSYSDESCPOINTER mov edx,dword ptr [eax].XSDTAddress[4] test edx,edx jnz UseRSDT ;no support for memory > 4GB, so use RSDT if XSDT above 4GB mov eax,dword ptr [eax].XSDTAddress ASSUME EAX:PTR SYSDESCTABLEHEADER ASSUME EAX:NOTHING ^ ;>******************************************************************************************************************************* ;* * ;* Procedure: Check Processor Requirements * ;* * ;<******************************************************************************************************************************* REQUIRED_PROCESSOR_FEATURES equ CPUID_EDX_FPU or CPUID_EDX_TSC or CPUID_EDX_MSR or CPUID_EDX_APIC or \ CPUID_EDX_MTRR or CPUID_EDX_CMOV or CPUID_EDX_SSE or CPUID_EDX_SSE2 or \ CPUID_EDX_PAT or CPUID_EDX_FXSAVE xor eax,eax mov al,CPUID_FN_FEATURES cpuid TestOutputVar "BSPro Features: ",edx and edx,REQUIRED_PROCESSOR_FEATURES cmp edx,REQUIRED_PROCESSOR_FEATURES jne Inadequate_Processor TestOutputWait "BSPro Features Suffice" ; shld eax,ebx,8 ;save Local APIC ID ;already saved in MADT processing ; mov ProcessorIDs,al ;but use the Local APIC ID from ebx in I/O APIC Setup section TestOutputVar "BSPro Local APIC ID (highbyte)",ebx fninit TestOutput "BSPro FPU Init'd" ;>******************************************************************************************************************************* ;* * ;* Procedure: I/O APIC Setup * ;* * ;<******************************************************************************************************************************* ;if ebx (Local APIC ID for Bootstrap Processor) changed since Processor Requirements section, have it pushed & popped IF GFX_TESTING_MODE mov eax,PA_VID_INFO mov edi,[eax].VBEMODEINFOBLOCK.PhysBasePtr add edi,100000-1 mov ecx,786432/4 mov eax,0FF0000h ;Red @@: stosd dec edi dec ecx jnz @B ENDIF ; mov al,CMOS_RAM_SHUTDOWN_STATUS ;set Shutdown Code to indicate warm reset (possibly only necessary for 486) ; out CMOS_RAM_ADDRESS_REG,al ; ; mov al,CMOS_RAM_SHUTDOWN_WARM_RESET ; ; out CMOS_RAM_DATA_REG,al ; ; movoffimm OFFSET_WARM_RESET_VECTOR,OFFSET_SIPI;set Warm Reset Vector mov al,0FFh ;mask all IRQs from the PICs ;/\/\/\/\/\/\/\/\/\/\/\/\/\/ MAYBE CHANGE THIS TO UNMASK ALL FROM PICs \/\/\/\/\/\/\/\/\/\ out PIC_INTERRUPT_MASK_REG,al ; out PIC2_INTERRUPT_MASK_REG,al ; mov al,PIC_IMCR_ACCESS_VALUE ;force IRQs through APIC out PIC_IMCR_ACCESS_REGW,al ; mov al,PIC_IMCR_DATA_VALUE ; out PIC_IMCR_DATA_REGW,al ; mov eax,pIOAPIC ;OFFSET_IOAPIC_REGSEL is at first dword, so no change necessary xor esi,esi ; xor edx,edx ; mov dl,IOAPICID mov ebp,IOAPIC_REG_IRQ lea edi,[eax][OFFSET_IOAPIC_DATA-OFFSET_IOAPIC_REGSEL] ; mov dword ptr [eax],IOAPIC_REG_ID ;already set by ACPI BIOS ; mov dword ptr [ecx],IOAPIC_ID ;so IOAPIC_ID (arbitrarily chosen as 15) has been deleted ; mov dword ptr [eax],IOAPIC_REG_ID ;try setting it anyway ; mov dword ptr [ecx],edx ;in case ACPI BIOS just chose the # (it must be set by something before it can be used) ;### SEE - TODO8: ### SetNextIRQVector: xor ecx,ecx mov cl,IOAPICInts[esi] inc esi cmp cl,-1 jne NotMaskedIRQ or ecx,IOAPIC_IRQ_MASK_BIT jmp DoneMaskingIRQ NotMaskedIRQ: test cl,40h jz NotLowActiveIRQ or ecx,IOAPIC_IRQ_LOW_ACTIVE NotLowActiveIRQ: test cl,80h jz NotLevelTriggeredIRQ or ecx,IOAPIC_IRQ_LEVEL_TRIGGERED NotLevelTriggeredIRQ: ;### SEE - TODO15: ### and cl,03Fh DoneMaskingIRQ: mov [eax],ebp TestOutputVar "IOAPIC IRQ REG #",ebp inc ebp mov [edi],ecx ;interrupt vector and a bunch of info TestOutputVar " set to ",ecx mov [eax],ebp inc ebp mov [edi],ebx ;destination processor: pile all ints onto one processor for now cmp esi,IOAPIC_NUM_IRQS jne SetNextIRQVector TestOutputWait "BSPro Enabled I/O APIC" ;>******************************************************************************************************************************* ;* * ;* Procedure: Memory Type Range Registers (MTRRs) and Page Attriubute Table Register (PAT MSR) * ;* * ;<******************************************************************************************************************************* N_REQUIRED_MTRRS equ 2 mov ecx,MSR_MTRRCAP ;Processor must have at least required number of MTRRs rdmsr ; cmp al,N_REQUIRED_MTRRS ; jb Inadequate_Processor ; TestOutputWait "BSPro Has Enough MTRRs" mov ecx,MSR_MTRR_PHYSBASE0 ;Set phys addr 0-7FFFFFFFh to WriteBack memory type xor edx,edx mov eax,0 or MEM_WRITEBACK wrmsr inc ecx ;MSR_MTRR_PHYSMASK0 or edx,0Fh mov eax,80000000h or MTRR_MASK_VALID wrmsr inc ecx ;MSR_MTRR_PHYSBASE1 ;Set phys addr 80000000h-BFFFFFFFh to WriteBack memory type xor edx,edx mov eax,80000000h or MEM_WRITEBACK wrmsr inc ecx ;MSR_MTRR_PHYSMASK1 or edx,0Fh mov eax,0C0000000h or MTRR_MASK_VALID wrmsr ;Don't need to set DMA memory to Uncacheable memory type, because reading and writing will not both occur TestOutputWait "BSPro Set MTRRs" mov ecx,MSR_PAT ;Set PAT MSR to allow Write-Combining type, which is beneficial for frame buffer memory performance mov eax,MEM_WRITEBACK or (MEM_WRITE_THROUGH shl 8) or (MEM_UNCACHED shl 16) or (MEM_UNCACHEABLE shl 24) mov edx,MEM_WRITE_COMBINING or (MEM_WRITE_PROTECTED shl 8) or (MEM_UNCACHED shl 16) or (MEM_UNCACHEABLE shl 24) wrmsr ;now setting the PAGE_TABLE_ATTRIBUTE_INDEX bit in a PTE will set it to Write-Combining type ;in this case, regardless of whether the MTRR memory type is WriteBack or uncacheable TestOutputWait "BSPro Set PAT MSR" ;>******************************************************************************************************************************* ;* * ;* Procedure: Local APIC Setup & Multi-Processor Startup * ;* * ;<******************************************************************************************************************************* N_REQUIRED_LVT_ENTRIES equ 4 ;Timer, Error, LINT0, and LINT1 (last 2 not used) PIT_10MS_DIVISOR equ ((PIT_MAX_RATE+99)/100) IF GFX_TESTING_MODE mov eax,PA_VID_INFO mov edi,[eax].VBEMODEINFOBLOCK.PhysBasePtr add edi,120000 mov ecx,786432/4 mov eax,0FFA000h ;Orange @@: stosd dec edi dec ecx jnz @B ENDIF mov edi,pLocalAPICBoot ASSUME EDI:PTR LOCALAPICMEM mov [edi].SpuriousIntVectorReg,APIC_SVR_ENABLE_BIT or INT_APIC_SPURIOUS ;Enable APIC mov eax,[edi].VersionReg shr eax,16 cmp al,N_REQUIRED_LVT_ENTRIES-1 ;must have minus 1 according to Intel jb Inadequate_Processor TestOutputWait "BSPro Has Enough LVT Entries" ; mov ecx,80000000h ; loop $ mov [edi].LVTErrorReg,INT_APIC_ERROR ;Set APIC Error interrupt vector mov [edi].LVTTimerReg,INT_APIC_TIMER ;Set APIC Timer interrupt vector and one-shot count down mov [edi].TimerDivideConfigReg,APIC_TIMER_DIVIDE_1 ;### SEE - TODO7: ### mov [edi].IntCommandReg,APIC_ICR1_INIT or APIC_ICR1_ALL_BUT_SELF or APIC_ICR1_SET_BIT ;Send INIT TestOutput "INIT Sent" ; mov al,PIT_BINARY_MODE or PIT_ONE_SHOT or PIT_RW_DIVISOR or PIT_COUNTER0 ; out PIT_MODE_CONTROL_REG,al ; mov al,1 ; out PIT_COUNTER0_REG,al ; mov al,0 ; out PIT_COUNTER0_REG,al ;WaitForPITInit: ; in al,PIT_COUNTER0_REG ; test al,al ; jnz WaitForPITInit ;### SEE - TODO27: ### mov al,PIT_BINARY_MODE or PIT_INT_ON_TC or PIT_RW_DIVISOR or PIT_COUNTER2 out PIT_MODE_CONTROL_REG,al mov al,PIT_10MS_DIVISOR and 0FFh ;at least 10ms required according to Intel out PIT_COUNTER2_REG,al ; mov al,PIT_10MS_DIVISOR shr 8 ; out PIT_COUNTER2_REG,al ; ;### SEE - TODO13: ### mov [edi].TimerInitialCountReg,0FFFFFFFFh ;Set APIC Timer for many cycles so PIT interrupt can calibrate it further rdtsc mov ClocksPer10ms,eax ;temporarily used for start TSC TestOutput "PIT & APIC Timer Started" xor ebx,ebx sti INITTimerWait: test ebx,ebx ;ebx is 1 after PIT interrupt returns jz INITTimerWait ;eax = APIC ticks/100ms ;ecx, edx changed after interrupt returns cli TestOutput "PIT & APIC Timer for INIT Complete" ;IF GFX_TESTING_MODE ; pusha ; mov eax,PA_VID_INFO ; mov edi,[eax].VBEMODEINFOBLOCK.PhysBasePtr ; add edi,150000 ; mov ecx,786432/4 ; mov eax,0FFFF00h ;Yellow ;@@: stosd ; dec edi ; dec ecx ; jnz @B ; popa ;ENDIF xor edx,edx ;eax = APIC ticks/100ms mov ecx,500 ;100ms/500 = 0.2ms div ecx ;don't worry about rounding ; mov al,PIT_BINARY_MODE or PIT_INT_ON_TC or PIT_RW_DIVISOR or PIT_COUNTER0 ; out PIT_MODE_CONTROL_REG,al ; mov al,239 ;at least 0.2ms required according to Intel ; out PIT_COUNTER0_REG,al ; ; mov al,0 ; ; out PIT_COUNTER0_REG,al ; mov [edi].IntCommandReg,APIC_ICR1_STARTUP or APIC_ICR1_ALL_BUT_SELF or APIC_ICR1_SET_BIT or (OFFSET_SIPI shr 12) ;Send SIPI xor ebx,ebx mov [edi].TimerInitialCountReg,eax ;Set APIC Timer for 0.2ms TestOutput "SIPI #1 Sent and APIC Timer Started" sti @@: test ebx,ebx ;ebx is 1 after interrupt returns jz @B cli TestOutput "APIC Timer for SIPI #1 Complete" IF GFX_TESTING_MODE pusha mov eax,PA_VID_INFO mov edi,[eax].VBEMODEINFOBLOCK.PhysBasePtr add edi,180000 mov ecx,786432/4 mov eax,00000FFh ;Blue @@: stosd dec edi dec ecx jnz @B popa ENDIF ;### SEE - TODO6: ### mov edx,449 ;eax = APIC ticks/0.2ms (don't worry about slight inaccuracy) mul edx ;0.2ms*449 = (100-10-0.2)ms mov [edi].IntCommandReg,APIC_ICR1_STARTUP or APIC_ICR1_ALL_BUT_SELF or APIC_ICR1_SET_BIT or (OFFSET_SIPI shr 12) ;Send SIPI (again) xor ebx,ebx mov [edi].TimerInitialCountReg,eax ;Set APIC Timer for (100-10-0.2)ms (= 89.8ms) TestOutput "SIPI #2 Sent and APIC Timer Started" sti @@: test ebx,ebx ;ebx is 1 after interrupt returns jz @B cli TestOutput "APIC Timer for SIPI #2 Complete" IF GFX_TESTING_MODE pusha mov eax,PA_VID_INFO mov edi,[eax].VBEMODEINFOBLOCK.PhysBasePtr add edi,210000 mov ecx,786432/4 mov eax,00080FFh ;Sky Blue @@: stosd dec edi dec ecx jnz @B popa ENDIF mov ecx,MSR_MTRR_DEF_TYPE ;Set default memory type and enable MTRRs xor edx,edx ;Reserved mov eax,800h or MEM_UNCACHEABLE ;MTRRs enabled, Fixed-range MTRRs disabled, default memory type is uncacheable TestOutput "BSPro about to Enable MTRRs" ;### SEE - TODO24: ### ; wrmsr TestOutput "BSPro Enabled MTRRs" mov eax,NumProcessors cmp eax,1 je NoOthers mov ProcessorWaitCount,1 mov [edi].IntCommandReg,INT_HANG or APIC_ICR1_ALL_BUT_SELF or APIC_ICR1_SET_BIT ;Send initial Hang Interrupt to all but this processor @@: cmp eax,ProcessorWaitCount ja @B TestOutput "All Non-BSPros Enabled MTRRs" NoOthers: mov word ptr IDT[INT_HANG*8],lowword (offset IntHangInit2) ;set it to the procedure to set up paging mov word ptr IDT[INT_APIC_TIMER*8],lowword (offset IntAPICTimer) ;set it to the normal interrupt handler mov word ptr IDT[INT_PIT*8],lowword (offset IntIRQPIT) ;set it to the normal interrupt handler ASSUME EDI:NOTHING ;>******************************************************************************************************************************* ;* * ;* Procedure: Paging Setup * ;* * ;<******************************************************************************************************************************* ;(not too important) remember that physical address of classic DMA stuff normally must be <16MB, but virtual address can be anywhere ;If Graphics Memory might not be aligned to 64KB, need to change this section ;<** Memory Allocated (Update this in conjunction with its counterpart in Core/Memory/Memory.inc) comment ^ PhysAddr VirtAddr Length Description 00000000 00000000 00030000 Boot Code, ATA Scratch, Boot PD Page 00070000 80000000 00010000 Boot Physical To Virtual Table Page 00100000 80100000 00100000 Core Code, Core Data 00080000 800x0000 00010000 Graphics Physical To Virtual Table Page xxxx0000 90000000 04000000 Graphics Memory 00030000 A0000000 00010000 Boot Page Table 00040000 A0200000 00010000 Common Page Table 00050000 A0240000 00010000 Graphics Page Table 00060000 A0280000 00010000 Page Table Page Table ^ ;> IF GFX_TESTING_MODE mov eax,PA_VID_INFO ASSUME EAX:PTR VBEMODEINFOBLOCK mov edi,[eax].PhysBasePtr add edi,3*786432/4 mov ecx,786432/4 mov eax,000FF00h ;Green @@: stosd dec edi dec ecx jnz @B ASSUME EAX:NOTHING ENDIF ;### SEE - TODO32: ### TestOutput "About to set up page tables" mov eax,PA_INITIAL_ZERO_SPACE pxor xmm0,xmm0 pxor xmm1,xmm1 pxor xmm2,xmm2 pxor xmm3,xmm3 NextInitZero: movdqa [eax][00h],xmm0 movdqa [eax][10h],xmm1 movdqa [eax][20h],xmm2 movdqa [eax][30h],xmm3 add eax,40h cmp eax,PA_INITIAL_ZERO_SPACE+SZ_INITIAL_ZERO_SPACE jne NextInitZero TestOutputVar "End of zeroing: ",eax TestOutputVar "DWORD0: ",[eax][-40h] TestOutputVar "DWORD1: ",[eax][-3Ch] TestOutputVar "DWORD2: ",[eax][-38h] TestOutputVar "DWORD3: ",[eax][-34h] mov eax,0+PAGE_PRESENT_BIT+PAGE_WRITABLE_BIT+PAGE_GLOBAL_BIT mov edi,PA_BOOT_PT NextBootPTE: stosd add eax,1000h cmp eax,PA_BOOT_PD+10000h+PAGE_PRESENT_BIT+PAGE_WRITABLE_BIT+PAGE_GLOBAL_BIT jne NextBootPTE TestOutputVar "End of BootPT: ",edi mov eax,PA_BOOT_PHYSTOVIRTTBL+PAGE_PRESENT_BIT+PAGE_WRITABLE_BIT+PAGE_GLOBAL_BIT mov edi,PA_COMMON_PT+0 NextCommonPTE: stosd add eax,1000h cmp eax,PA_BOOT_PHYSTOVIRTTBL+10000h+PAGE_PRESENT_BIT+PAGE_WRITABLE_BIT+PAGE_GLOBAL_BIT jne NextCommonPTE TestOutputVar "End of CommonPT 1: ",edi mov eax,PA_CORE_CODE+PAGE_PRESENT_BIT+PAGE_WRITABLE_BIT+PAGE_GLOBAL_BIT mov edi,PA_COMMON_PT+((VA_CORE_CODE-VA_SYSTEM_MEMORY) shr (16-6)) NextCommonPTE_2: stosd add eax,1000h cmp eax,PA_CORE_CODE+SZ_CORE_CODE+SZ_CORE_DATA+PAGE_PRESENT_BIT+PAGE_WRITABLE_BIT+PAGE_GLOBAL_BIT jne NextCommonPTE_2 TestOutputVar "End of CommonPT 2: ",edi mov ecx,PA_VID_INFO ASSUME ECX:PTR VBEMODEINFOBLOCK mov eax,PA_GFX_PHYSTOVIRTTBL+PAGE_PRESENT_BIT+PAGE_WRITABLE_BIT+PAGE_GLOBAL_BIT mov edx,[ecx].PhysBasePtr shr edx,28 ;only 16 pages (64KB each) to hold Physical To Virtual Table (1MB) shl edx,6 ;each PTE is 64 bytes (16 smaller PTEs for 4KB pages) lea edi,PA_COMMON_PT[edx] NextCommonPTE_3: stosd add eax,1000h cmp eax,PA_GFX_PHYSTOVIRTTBL+10000h+PAGE_PRESENT_BIT+PAGE_WRITABLE_BIT+PAGE_GLOBAL_BIT jne NextCommonPTE_3 TestOutputVar "End of CommonPT 3: ",edi mov eax,[ecx].PhysBasePtr or eax,PAGE_PRESENT_BIT+PAGE_WRITABLE_BIT+PAGE_GLOBAL_BIT mov edi,PA_GFX_PT NextGfxPTE: stosd add eax,1000h cmp edi,PA_GFX_PT+10000h jne NextGfxPTE TestOutputVar "End of GfxPT: ",edi ASSUME ECX:NOTHING mov eax,PA_BOOT_PT+PAGE_PRESENT_BIT+PAGE_WRITABLE_BIT+PAGE_GLOBAL_BIT mov edi,PA_PT_PT+0 NextPTPTE: stosd add eax,1000h cmp eax,PA_BOOT_PT+10000h+PAGE_PRESENT_BIT+PAGE_WRITABLE_BIT+PAGE_GLOBAL_BIT jne NextPTPTE ; mov eax,PA_COMMON_PT+PAGE_PRESENT_BIT+PAGE_WRITABLE_BIT+PAGE_GLOBAL_BIT mov edi,PA_PT_PT+(PT_COMMON*64) NextPTPTE_2: stosd add eax,1000h cmp eax,PA_COMMON_PT+10000h+PAGE_PRESENT_BIT+PAGE_WRITABLE_BIT+PAGE_GLOBAL_BIT jne NextPTPTE_2 ; mov eax,PA_GFX_PT+PAGE_PRESENT_BIT+PAGE_WRITABLE_BIT+PAGE_GLOBAL_BIT mov edi,PA_PT_PT+(PT_GFX*64) NextPTPTE_3: stosd add eax,1000h cmp eax,PA_GFX_PT+10000h+PAGE_PRESENT_BIT+PAGE_WRITABLE_BIT+PAGE_GLOBAL_BIT jne NextPTPTE_3 ; mov eax,PA_PT_PT+PAGE_PRESENT_BIT+PAGE_WRITABLE_BIT+PAGE_GLOBAL_BIT mov edi,PA_PT_PT+(PT_PAGE_TABLES*64) NextPTPTE_4: stosd add eax,1000h cmp eax,PA_PT_PT+10000h+PAGE_PRESENT_BIT+PAGE_WRITABLE_BIT+PAGE_GLOBAL_BIT jne NextPTPTE_4 TestOutputVar "End of PTPT: ",edi mov esi,PA_PT_PT+0 mov edi,PA_BOOT_PD+0 movdqa xmm0,[esi][00h] movdqa xmm1,[esi][10h] movdqa xmm2,[esi][20h] movdqa xmm3,[esi][30h] mov esi,PA_PT_PT+(PT_COMMON*64) movdqa [edi][00h],xmm0 movdqa [edi][10h],xmm1 movdqa [edi][20h],xmm2 movdqa [edi][30h],xmm3 mov edi,PA_BOOT_PD+(PT_COMMON*64) movdqa xmm0,[esi][00h] movdqa xmm1,[esi][10h] movdqa xmm2,[esi][20h] movdqa xmm3,[esi][30h] mov esi,PA_PT_PT+(PT_GFX*64) movdqa [edi][00h],xmm0 movdqa [edi][10h],xmm1 movdqa [edi][20h],xmm2 movdqa [edi][30h],xmm3 mov edi,PA_BOOT_PD+(PT_GFX*64) movdqa xmm0,[esi][00h] movdqa xmm1,[esi][10h] movdqa xmm2,[esi][20h] movdqa xmm3,[esi][30h] mov esi,PA_PT_PT+(PA_PT_PT*64) movdqa [edi][00h],xmm0 movdqa [edi][10h],xmm1 movdqa [edi][20h],xmm2 movdqa [edi][30h],xmm3 mov edi,PA_BOOT_PD+(PA_PT_PT*64) movdqa xmm0,[esi][00h] movdqa xmm1,[esi][10h] movdqa xmm2,[esi][20h] movdqa xmm3,[esi][30h] movdqa [edi][00h],xmm0 movdqa [edi][10h],xmm1 movdqa [edi][20h],xmm2 movdqa [edi][30h],xmm3 TestOutput "Page Directory set up" TestOutput "About to set up PhysToVirtTbl" mov ecx,PA_VID_INFO mov eax,PA_BOOT_PHYSTOVIRTTBL xor edi,edi mov edx,H_BOOT_PROCESS mov ecx,[ecx].VBEMODEINFOBLOCK.PhysBasePtr dec edi ASSUME EAX:PTR PHYSPAGEINFO ;Note: Age fields cleared to 0 above mov [eax][(sizeof PHYSPAGEINFO)*0].pVirtual,0 ;Boot Code mov [eax][(sizeof PHYSPAGEINFO)*0].hProcess,edx mov esi,ecx mov [eax][(sizeof PHYSPAGEINFO)*1].pVirtual,VA_ATA_SCRATCH ;ATA Scratch mov [eax][(sizeof PHYSPAGEINFO)*1].hProcess,edx shr esi,28 mov [eax][(sizeof PHYSPAGEINFO)*2].pVirtual,VA_BOOT_PD ;Boot PD & Free Space for other PDs mov [eax][(sizeof PHYSPAGEINFO)*2].hProcess,edx mov [eax][(sizeof PHYSPAGEINFO)*3].pVirtual,VA_PAGE_TABLES ;Boot Page Table mov [eax][(sizeof PHYSPAGEINFO)*3].hProcess,edx shl esi,16 mov [eax][(sizeof PHYSPAGEINFO)*4].pVirtual,VA_PAGE_TABLES+(PT_COMMON shl 16) ;Common Page Table mov [eax][(sizeof PHYSPAGEINFO)*4].hProcess,H_UNIVERSAL_PROCESS_ADDR mov [eax][(sizeof PHYSPAGEINFO)*5].pVirtual,VA_PAGE_TABLES+(PT_GFX shl 16) ;Graphics Page Table mov [eax][(sizeof PHYSPAGEINFO)*5].hProcess,H_UNIVERSAL_PROCESS_ADDR add esi,VA_PHYSTOVIRTTBL mov [eax][(sizeof PHYSPAGEINFO)*6].pVirtual,VA_PAGE_TABLES+(PT_PAGE_TABLES shl 16) ;Page Table Page Table mov [eax][(sizeof PHYSPAGEINFO)*6].hProcess,edx mov [eax][(sizeof PHYSPAGEINFO)*7].pVirtual,VA_PHYSTOVIRTTBL ;Boot Physical To Virtual Table Page mov [eax][(sizeof PHYSPAGEINFO)*7].hProcess,H_UNIVERSAL_PROCESS_ADDR mov [eax][(sizeof PHYSPAGEINFO)*8].pVirtual,esi ;Graphics Physical To Virtual Table Page mov [eax][(sizeof PHYSPAGEINFO)*8].hProcess,H_UNIVERSAL_PROCESS_ADDR mov [eax][(sizeof PHYSPAGEINFO)*9].pVirtual,edi ;Empty mov [eax][(sizeof PHYSPAGEINFO)*9].hProcess,edi mov eax,PA_BOOT_PHYSTOVIRTTBL+(sizeof PHYSPAGEINFO)*0Ah dec edi mov [eax][(sizeof PHYSPAGEINFO)*0].pVirtual,edi ;Unusable: Video Memory Bank mov [eax][(sizeof PHYSPAGEINFO)*1].pVirtual,edi ;Unusable: Video Memory Bank mov [eax][(sizeof PHYSPAGEINFO)*2].pVirtual,edi ;Unusable: Video Card ROM mov [eax][(sizeof PHYSPAGEINFO)*3].pVirtual,edi ;Unusable: BIOS ROM mov [eax][(sizeof PHYSPAGEINFO)*4].pVirtual,edi ;Unusable: BIOS ROM mov [eax][(sizeof PHYSPAGEINFO)*5].pVirtual,edi ;Unusable: BIOS ROM mov eax,PA_BOOT_PHYSTOVIRTTBL+(sizeof PHYSPAGEINFO)*10h mov esi,VA_CORE_CODE NextPVTblCoreCode: mov [eax].pVirtual,esi ;Core Code mov [eax].hProcess,H_UNIVERSAL_PROCESS_ADDR add eax,sizeof PHYSPAGEINFO add esi,10000h cmp esi,VA_CORE_CODE+SZ_CORE_CODE+SZ_CORE_DATA jne NextPVTblCoreCode mov eax,ecx shl eax,8 IF sizeof PHYSPAGEINFO NE 16 echo Change line locating graphics Physical To Virtual Table entries (and a whole lot more) now that PHYSPAGEINFO no longer of size 16 .err ENDIF shr eax,24-4 add eax,PA_GFX_PHYSTOVIRTTBL mov esi,VA_GFX NextPVTblGfx: mov [eax].pVirtual,esi mov [eax].hProcess,H_UNIVERSAL_PROCESS_ADDR add eax,sizeof PHYSPAGEINFO add esi,10000h cmp esi,VA_GFX+SZ_GFX jne NextPVTblGfx ASSUME EAX:NOTHING TestOutput "Enable Paging In Non-BSPros first" mov eax,NumProcessors cmp eax,1 je NoOthersForPaging mov ProcessorWaitCount,1 mov edi,pLocalAPICBoot ASSUME EDI:PTR LOCALAPICMEM mov [edi].IntCommandReg,INT_HANG or APIC_ICR1_ALL_BUT_SELF or APIC_ICR1_SET_BIT ;Send 2nd initial Hang Interrupt to all but this processor @@: cmp eax,ProcessorWaitCount ja @B TestOutput "All Non-BSPros Enabled Paging" NoOthersForPaging: mov word ptr IDT[INT_HANG*8],lowword (offset IntHangInit3) ;set it to the next boot interrupt procedure ASSUME EDI:NOTHING TestOutput "About to enable paging" mov ecx,PA_BOOT_PD mov eax,CR0_PROTECTION_BIT or CR0_SET_BIT or CR0_PAGING_BIT mov cr3,ecx mov cr0,eax IF PA_PL0_STACK_TOP NE VA_PL0_STACK_TOP mov esp,VA_PL0_STACK_TOP ;everything should be popped at this point, so just set it to the top ENDIF IF GFX_TESTING_MODE mov edi,VA_GFX mov ecx,X_RESOLUTION_WANTED*Y_RESOLUTION_WANTED mov eax,0FFFF00h ;Yellow @@: stosd dec edi dec ecx jnz @B ENDIF ;>******************************************************************************************************************************* ;* * ;* Procedure: IDE Bus Master Setup (NEED PCI SPECIFICATIONS FOR THIS) * ;* * ;<******************************************************************************************************************************* ;>******************************************************************************************************************************* ;* * ;* Procedure: Read MBRs to Find NTFS Partition * ;* * ;<******************************************************************************************************************************* invoke ATAIdentifyDevice,VA_ATA_SCRATCH+ATA_IDD_STRUCT_SIZE*0,ATA_DEVICE_DEV0 invoke ATAIdentifyDevice,VA_ATA_SCRATCH+ATA_IDD_STRUCT_SIZE*1,ATA_DEVICE_DEV1 invoke ATAIdentifyDevice,VA_ATA_SCRATCH+ATA_IDD_STRUCT_SIZE*2,ATA_DEVICE_DEV0 or 1 invoke ATAIdentifyDevice,VA_ATA_SCRATCH+ATA_IDD_STRUCT_SIZE*3,ATA_DEVICE_DEV1 or 1 xor edi,edi mov esi,VA_ATA_SCRATCH NextCompactATAIdentify: invoke CompactATAIdentify,edi,esi inc edi add esi,ATA_IDD_STRUCT_SIZE cmp edi,4 jne NextCompactATAIdentify xor ebx,ebx CheckDriveMBRLoop: mov esi,VA_ATA_SCRATCH invoke ATAIsValidDevice,ebx test eax,eax jz GoToNextDevice ;### SEE - TODO22: ### invoke ATAReadSectors,esi,ebx,0,0,1 mov esi,VA_ATA_SCRATCH+MBR_ENTRY0_OFFSET ASSUME ESI:PTR PARTITIONENTRY CheckNextPartitionEntry: cmp [esi].IsBootable,80h jne NotBootable IF GFX_TESTING_MODE pusha mov edi,VA_GFX mov ecx,X_RESOLUTION_WANTED*Y_RESOLUTION_WANTED mov eax,0FF0000h ;Red @@: stosd dec edi dec ecx jnz @B popa ENDIF GfxOutput "Found bootable partition! :-)" ;### SEE - TODO21: ### NotBootable: GfxOutputVar "Partition of Type: ",dword ptr [esi].PartitionType cmp [esi].PartitionType,MBR_PARTTYPE_NTFS jne NotNTFS GfxOutput "Found NTFS partition! :-)" mov edi,VA_ATA_SCRATCH+SZ_ATA_SCRATCH-ATA_SECTOR_SIZE invoke ATAReadSectors,edi,ebx,[esi].FirstSector,0,1 ;******************************************************************************************************************************** ;* * ;* FIND MFT, THEN ROOT DIRECTORY "." * ;* * ;<******************************************************************************************************************************* ASSUME EDI:PTR NTFSBOOTSTRUCT invoke MountNTFSPartition,ebx,esi,edi mov edi,eax ASSUME EDI:PTR PARTITIONINFO_NTFS test eax,eax jz GoToNextPartitionEntry GfxOutputVar "MFT @ Cluster #: (Low) ",dword ptr [edi].LCN$MFT GfxOutputVar "MFT @ Cluster #: (High) ",dword ptr [edi].LCN$MFT[4] GfxOutputVar "Sectors Per Cluster: ",dword ptr [edi].SectorsPerClus invoke GetNTFSFileRecord,VA_CORE_CODE,edi,NTFSFILENUM_ROOT,0 IF GFX_TESTING_MODE mov ecx,VA_CORE_CODE ASSUME ECX:PTR NTFSFILEHEADER GfxOutputVar "Root Sig: ",[ecx].Signature GfxOutputVar "Root Attr Offset & Flags: ",dword ptr [ecx].OffAttributes GfxOutputVar "Root Real Size: ",[ecx].RealSize ASSUME ECX:NOTHING ENDIF ;>******************************************************************************************************************************* ;* * ;* FIND DIRECTORY "PwnOS" IN ROOT DIRECTORY ".", THEN FILE "Core.bin" IN "PwnOS" * ;* * ;<******************************************************************************************************************************* invoke SearchNTFSDirectory,edi,VA_CORE_CODE,offset PwnOSUnicode,VA_CORE_CODE+10000h test eax,eax jnz PwnOSDirNotMissing test edx,edx jz GoToNextPartitionEntry PwnOSDirNotMissing: GfxOutput "Found \PwnOS\" and edx,0FFFFh invoke GetNTFSFileRecord,VA_CORE_CODE,edi,eax,edx invoke SearchNTFSDirectory,edi,VA_CORE_CODE,offset CoreBinUnicode,VA_CORE_CODE+10000h test eax,eax jnz CoreBinNotMissing test edx,edx jz GoToNextPartitionEntry CoreBinNotMissing: GfxOutput "Found \PwnOS\Core.bin" and edx,0FFFFh invoke GetNTFSFileRecord,VA_ATA_SCRATCH+ATA_IDD_STRUCT_SIZE*4,edi,eax,edx ;can't be read to VA_CORE_CODE, since that's to where Core.bin will be read ;>******************************************************************************************************************************* ;* * ;* READ FILE "Core.bin" INTO MEMORY * ;* * ;<******************************************************************************************************************************* IF GFX_TESTING_MODE pusha mov edi,VA_GFX mov ecx,X_RESOLUTION_WANTED*Y_RESOLUTION_WANTED mov eax,0FF00C0h ;Purple @@: stosd dec edi dec ecx jnz @B popa ENDIF IF IMAGE_TEST_MODE invoke ReadNTFSFile,VA_GFX+X_RESOLUTION_WANTED*3-54,edi,VA_ATA_SCRATCH+ATA_IDD_STRUCT_SIZE*4 ELSE invoke ReadNTFSFile,VA_CORE_CODE,edi,VA_ATA_SCRATCH+ATA_IDD_STRUCT_SIZE*4;,VA_GFX+X_RESOLUTION_WANTED*3-54,edi,VA_ATA_SCRATCH+ATA_IDD_STRUCT_SIZE*4 GfxOutput "Read Core.bin" invoke SetTSSDescriptor,offset BootTask.GeneralState ltr ax ; push CREATE_PROCESS_FLAG_SYSTEM ; push NULL ; push 0 ; push offset BootExeUnicode ; mov eax,CG_CREATE_PROCESS ; ;call far ptr SELECTOR_CORE_CALL_GATE:00000000h ; byte 9Ah ;call far ptr ; dword 0 ; word SELECTOR_CORE_CALL_GATE ; add esp,4*4 invoke CreateProcess,offset BootExeUnicode,0,NULL,CREATE_PROCESS_FLAG_SYSTEM GfxOutput "Done CreateProcess" jmp $ ;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ STALL POINT \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ ENDIF ASSUME EDI:NOTHING ;> NotNTFS: cmp [esi].PartitionType,MBR_PARTTYPE_EXTENDED_LBA je Extended cmp [esi].PartitionType,MBR_PARTTYPE_EXTENDED je Extended GoToNextPartitionEntry: mov eax,esi add esi,sizeof PARTITIONENTRY and eax,01FFh cmp eax,MBR_ENTRY3_OFFSET jne CheckNextPartitionEntry cmp esi,VA_ATA_SCRATCH+MBR_ENTRY3_OFFSET+sizeof PARTITIONENTRY jne RetFromExtendedPartition GoToNextDevice: inc ebx cmp ebx,4 je CoreNotFound jmp CheckDriveMBRLoop RetFromExtendedPartition: pop esi jmp GoToNextPartitionEntry Extended: GfxOutput "Extended Partition***" push esi add esi,ATA_SECTOR_SIZE and esi,not 1FFh or esi,MBR_ENTRY0_OFFSET cmp esi,VA_ATA_SCRATCH+SZ_ATA_SCRATCH-ATA_SECTOR_SIZE ;leave 1 sector for partition boot sector jae TooManyExtendedPartitions invoke ATAReadSectors,esi,ebx,[esi].FirstSector,0,1 jmp CheckNextPartitionEntry TooManyExtendedPartitions: pop esi jmp GoToNextPartitionEntry ;>******************************************************************************************************************************* ;* * ;* BOOT FROM ANY BOOTABLE PARTITION IF CORE NOT FOUND * ;* * ;<******************************************************************************************************************************* CoreNotFound: jmp $;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ STALL POINT /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ ASSUME ESI:NOTHING ;>******************************************************************************************************************************* ;* * ;* Procedure: Initialize Data in & for Core * ;* * ;<******************************************************************************************************************************* ;******************************************************************************************************************************** ;* * ;* TASK STATE SEGMENT SETUP * ;* * ;******************************************************************************************************************************** ;!!!Remember to set data at VA_PROCESS_ROUTER_TSS, but it doesn't need to contain FXSAVE info, just general state (unless ProcessRouter will use FPU or SSE instructions) ; xor eax,eax ; mov al,SELECTOR_THREAD_SCHEDULER_TSS ; ltr ax ;>******************************************************************************************************************************* ;* * ;* Section: Task Functions * ;* * ;<******************************************************************************************************************************* ;******************************************************************************************************************************** ;* Procedure: SetTSSDescriptor * ;* * ;* Sets the TSS descriptor corresponding with the current processor to select the specified TSS. * ;* * ;* Parameters: * ;* pTSS - virtual address of the TSS * ;* * ;* Returns: * ;* - selector of the descriptor modified * ;******************************************************************************************************************************** SetTSSDescriptor proc pTSS:DWORD push ebx push esi xor eax,eax ;Find Local APIC ID mov al,CPUID_FN_FEATURES ; cpuid ; shld eax,ebx,8 ;Find index of Local APIC ID in ProcessorIDs mov ecx,MAX_NUM_PROCESSORS ; mov esi,offset ProcessorIDs ; repne scasb ; sub esi,offset ProcessorIDs+1 ; lea esi,[VA_GDT+SZ_STORED_GDT][esi*8] ;Find the offset of the descriptor mov eax,pTSS ;Set the descriptor data mov word ptr [esi][0],sizeof(TSS32) ; mov word ptr [esi][2],ax ; shr eax,16 ; mov byte ptr [esi][4],al ; mov byte ptr [esi][5],DESC_S_TSS_AVL_32 or DESC_PRESENT_BIT or DESC_PRIV_LEVEL0 mov byte ptr [esi][6],0 ; mov byte ptr [esi][7],ah ; lea eax,[esi][-VA_GDT] pop esi pop ebx ret SetTSSDescriptor endp ;>******************************************************************************************************************************* ;* * ;* Section: Timing Functions * ;* * ;<******************************************************************************************************************************* ;******************************************************************************************************************************** ;* Procedure: WaitNanoseconds * ;* * ;* Parameters: * ;* Nanoseconds - # of nanoseconds to wait * ;******************************************************************************************************************************** WaitNanoseconds proc Nanoseconds:DWORD push ebx rdtsc mov ebx,eax mov eax,Nanoseconds mov ecx,10*1000*1000 mul ClocksPer10ms div ecx mov ecx,eax WaitLoop: rdtsc sub eax,ebx cmp eax,ecx jb WaitLoop pop ebx ret WaitNanoseconds endp ;>******************************************************************************************************************************* ;* * ;* Section: ATA/ATAPI Functions * ;* * ;<******************************************************************************************************************************* ;******************************************************************************************************************************** ;* Procedure: ATAIdentifyDevice * ;* * ;* Fills in the 512-byte buffer with the information returned by ATA_CC_IDENTIFY_DEVICE. * ;* If the device is a packet device, it calls . * ;* * ;* Parameters: * ;* pDest - pointer to 512-byte buffer * ;* DriveNum - one of: ATA_DEVICE_DEV0, ATA_DEVICE_DEV1, ATA_DEVICE_DEV0 or 1, ATA_DEVICE_DEV1 or 1 * ;* * ;* Returns: * ;* - carry flag set iff error * ;******************************************************************************************************************************** ATAIdentifyDevice proc pDest:DWORD,DriveNum:DWORD push edi mov edi,pDest btr DriveNum,0 mov dx,ATA_DEVICE_REG;ATA_STATUS_REGR jnc PDrives_Port SDrives_Port: and dl,7Fh PDrives_Port: ;HI1: ;; or dl,07h ;ATA_STATUS_REGR ; in al,dx ; test al,ATA_STATUS_BSY ; jnz HI1 ; test al,ATA_STATUS_DRQ ; jnz HI1 ; dec edx ;ATA_DEVICE_REG mov al,byte ptr DriveNum out dx,al inc edx mov al,ATA_CC_IDENTIFY_DEVICE out dx,al push edx invoke WaitNanoseconds,400 pop edx jmp HPIOI1_2 HPIOI0: ;INTRQ_wait ;nothing, because nIEN is set to 1 (no interrupts) HPIOI1: ;Check_Status push edx mov dx,ATA_ALT_STATUS_REGR ;wait by checking the Alternate Status Register (does nothing) in al,dx pop edx HPIOI1_2: or dl,07h ;ATA_STATUS_REGR in al,dx test al,ATA_STATUS_BSY jnz HPIOI1 test al,ATA_STATUS_DRQ jz Error HPIOI2: ;Transfer_Data and dl,0F0h ;ATA_DATA_REG mov ecx,ATA_IDD_STRUCT_SIZE/2 rep insw ; insw ; or dl,07h ;ATA_STATUS_REG ; in al,dx ; test al,ATA_STATUS_DRQ ; jnz HPIOI2 or dl,07h ;ATA_STATUS_REG in al,dx test al,ATA_STATUS_ERR jnz Error sub edi,ATA_IDD_STRUCT_SIZE xor ecx,ecx xor al,al test byte ptr [edi][ATA_IDD_INCOMPLETE_OFFSET],ATA_IDD_INCOMPLETE_BIT jnz Error test byte ptr [edi][ATA_IDD_NOATASUPPORT_OFFSET],ATA_IDD_NOATASUPPORT_BIT jnz Error cmp byte ptr [edi][ATA_IDD_SIGNATURE_OFFSET],ATA_IDD_CORRECT_SIGNATURE jne Error CheckChecksumLoop: add al,[edi][ecx] inc ecx cmp ecx,ATA_IDD_STRUCT_SIZE jne CheckChecksumLoop test al,al jnz Error clc Exit: pop edi ret ;carry if error Error: and dl,0F0h or dl,02h ;ATA_SECTOR_COUNT_REG in al,dx cmp al,ATA_PACKET_SIGNATURE_COUNT jne RealError inc edx ;ATA_LBA_LOW_REG in al,dx cmp al,ATA_PACKET_SIGNATURE_LOW jne RealError inc edx ;ATA_LBA_MID_REG in al,dx cmp al,ATA_PACKET_SIGNATURE_MID jne RealError inc edx ;ATA_LBA_HIGH_REG in al,dx cmp al,ATA_PACKET_SIGNATURE_HIGH jne RealError GfxOutput "Trying IDENTIFY PACKET DEVICE" invoke ATAIdentifyPacketDevice,pDest,DriveNum GfxOutput "back from packet identify" jmp Exit RealError: GfxOutput "ATA Error in ATAIdentifyDevice" GfxOutputVar "IDENTIFY DEVICE dword 0 (or nothing): ",dword ptr [edi] stc jmp Exit ret ATAIdentifyDevice endp ;******************************************************************************************************************************** ;* Procedure: ATAIdentifyPacketDevice * ;* * ;* Fills in the 512-byte buffer with the information returned by ATA_CC_IDENTIFY_PACKET_DEVICE. * ;* Called by * ;* * ;* Parameters: * ;* pDest - pointer to 512-byte buffer * ;* DriveNum - one of: ATA_DEVICE_DEV0, ATA_DEVICE_DEV1, ATA_DEVICE_DEV0 or 1, ATA_DEVICE_DEV1 or 1 * ;* * ;* Returns: * ;* - carry flag set iff error * ;******************************************************************************************************************************** ATAIdentifyPacketDevice proc pDest:DWORD,DriveNum:DWORD push edi mov edi,pDest btr DriveNum,0 mov dx,ATA_DEVICE_REG;ATA_STATUS_REGR jnc PDrives_Port SDrives_Port: and dl,7Fh PDrives_Port: ;HI1: ;; or dl,07h ;ATA_STATUS_REGR ; in al,dx ; test al,ATA_STATUS_BSY ; jnz HI1 ; test al,ATA_STATUS_DRQ ; jnz HI1 ; dec edx ;ATA_DEVICE_REG mov al,byte ptr DriveNum out dx,al inc edx mov al,ATA_CC_IDENTIFY_PACKET_DEVICE out dx,al push edx invoke WaitNanoseconds,400 pop edx jmp HPIOI1_2 HPIOI0: ;INTRQ_wait ;nothing, because nIEN is set to 1 (no interrupts) HPIOI1: ;Check_Status push edx mov dx,ATA_ALT_STATUS_REGR ;wait by checking the Alternate Status Register (does nothing) in al,dx pop edx HPIOI1_2: or dl,07h ;ATA_STATUS_REGR in al,dx test al,ATA_STATUS_BSY jnz HPIOI1 test al,ATA_STATUS_DRQ jz Error HPIOI2: ;Transfer_Data and dl,0F0h ;ATA_DATA_REG mov ecx,ATA_IDPD_STRUCT_SIZE/2 rep insw ; insw ; or dl,07h ;ATA_STATUS_REG ; in al,dx ; test al,ATA_STATUS_DRQ ; jnz HPIOI2 or dl,07h ;ATA_STATUS_REG in al,dx test al,ATA_STATUS_ERR jnz Error sub edi,ATA_IDPD_STRUCT_SIZE xor ecx,ecx xor al,al test byte ptr [edi][ATA_IDPD_INCOMPLETE_OFFSET],ATA_IDPD_INCOMPLETE_BIT jnz Error test byte ptr [edi][ATA_IDPD_NOTATAPI_OFFSET],ATA_IDPD_NOTATAPI_BIT jnz Error cmp byte ptr [edi][ATA_IDPD_SIGNATURE_OFFSET],ATA_IDPD_CORRECT_SIGNATURE jne Error CheckChecksumLoop: add al,[edi][ecx] inc ecx cmp ecx,ATA_IDPD_STRUCT_SIZE jne CheckChecksumLoop test al,al jnz Error clc Exit: pop edi ret ;carry if error Error: GfxOutput "ATA Error in ATAIdentifyPacketDevice" GfxOutputVar "IDENTIFY PACKET DEVICE dword 0 (or nothing): ",dword ptr [edi] stc jmp Exit ret ATAIdentifyPacketDevice endp ;******************************************************************************************************************************** ;* Procedure: CompactATAIdentify * ;* * ;* Fills in the of the specified device with the information returned by . * ;* If the device is invalid (e.g. no device at all), the nSectors field is set to -1. * ;* * ;* Parameters: * ;* Drive0To3 - ATA device index, from 0 to 3 * ;* pSource - pointer to info block returned from ATAIdentifyDevice * ;******************************************************************************************************************************** CompactATAIdentify proc Drive0To3:DWORD,pSource:DWORD push ebx push edi mov edi,Drive0To3 mov eax,pSource IF sizeof ATADEVICEINFO NE 80 .err ENDIF shl edi,4 lea edi,[edi*4+edi] add edi,offset ATADeviceInfo ASSUME EDI:PTR ATADEVICEINFO mov ebx,[eax][ATA_IDD_MAXSECTORS28P1_OFFSET] xor ecx,ecx mov edx,[eax][ATA_IDD_MAXSECTORS48P1_OFFSET] mov dword ptr [edi].nSectors,ebx mov dword ptr [edi].nSectors[4],ecx mov ecx,[eax][ATA_IDD_MAXSECTORS48P1_OFFSET][4] mov ebx,[eax][ATA_IDD_CMNDSETSUPPORT_OFFSET] test ebx,ATA_IDD_48BITSUPPORT_BIT jz No48BitSupport mov dword ptr [edi].nSectors,edx mov dword ptr [edi].nSectors[4],ecx No48BitSupport: xor ecx,ecx test dword ptr [eax][ATA_IDD_REMOVABLE_OFFSET],ATA_IDD_REMOVABLE_BIT jz NotRemovable test ebx,ATA_IDD_REMOVABLESUPPORT_BIT or ATA_IDD_REMOVNOTIFYSUPPORT_BIT ;either one is okay jz Invalid mov dword ptr [edi].Flags,ATADRV_FLAG_REMOVABLE jmp DoneRemovable NotRemovable: mov dword ptr [edi].Flags,ecx ;zero DoneRemovable: test dword ptr [eax][ATA_IDD_DMASUPPORT_OFFSET],ATA_IDD_DMASUPPORT_BIT jz NoDMASupport or dword ptr [edi].Flags,ATADRV_FLAG_DMASUPPORT NoDMASupport: test dword ptr [eax][ATA_IDD_LBASUPPORT_OFFSET],ATA_IDD_LBASUPPORT_BIT jz NoLBASupport or dword ptr [edi].Flags,ATADRV_FLAG_LBASUPPORT NoLBASupport: mov edx,[eax][ATA_IDD_CMNDSETSUPPORT_OFFSET][4] mov dword ptr [edi].Flags[4],ecx ;zero mov ecx,[eax][ATA_IDD_CMNDSETSUPPORT_OFFSET][8] mov [edi].SupportFlags,ebx mov ebx,[eax][ATA_IDD_CMNDSETSUPPORT_OFFSET][12] mov [edi].SupportFlags[4],edx mov [edi].SupportFlags[8],ecx mov [edi].SupportFlags[12],ebx GfxOutputVar "ATA Drive, nSectors: (low) ",dword ptr [edi].nSectors GfxOutputVar " (high) ",dword ptr [edi].nSectors[4] jmp Exit Invalid: mov dword ptr [edi].nSectors,-1 mov dword ptr [edi].nSectors[4],-1 GfxOutput "Invalid ATA Drive" Exit: pop edi pop ebx ret ASSUME EDI:NOTHING CompactATAIdentify endp ;******************************************************************************************************************************** ;* Procedure: ATAIsValidDevice * ;* * ;* Checks the of the specified device to see if it is a valid, supported device. * ;* * ;* Parameters: * ;* Drive0To3 - ATA device index, from 0 to 3 * ;* * ;* Returns: * ;* - eax = 0 in if invalid * ;* - eax = Address of if valid * ;* - ecx = nSectorsLow if valid * ;* - edx = nSectorsHigh if valid * ;******************************************************************************************************************************** ATAIsValidDevice proc Drive0To3:DWORD ;Returns 0 in eax if invalid, otherwise, eax=address of ATADEVICEINFO, ecx=nSectorsLow, edx=nSectorsHigh mov eax,Drive0To3 IF sizeof ATADEVICEINFO NE 80 .err ENDIF shl eax,4 lea eax,[eax*4+eax] add eax,offset ATADeviceInfo ASSUME EAX:PTR ATADEVICEINFO mov ecx,dword ptr [eax].nSectors mov edx,dword ptr [eax].nSectors[4] cmp ecx,-1 jne NotInvalid cmp edx,ecx ;both being -1 indicates invalid je NotValid NotInvalid: test dword ptr [eax].Flags,ATADRV_FLAG_LBASUPPORT ;currently no support for non-LBA jz NotValid test dword ptr [eax].Flags,ATADRV_FLAG_REMOVABLE jz MediaPresent ;### SEE - TODO19: ### MediaPresent: ret ASSUME EAX:NOTHING NotValid: xor eax,eax ret ATAIsValidDevice endp ATAReadSectors proc pDest:DWORD,Drive0To3:DWORD,SectorNumLow:DWORD,SectorNumHigh:DWORD,nSectors:DWORD GfxOutputVar "nSectors:",nSectors invoke ATAIsValidDevice,Drive0To3 test eax,eax jz Error ASSUME EAX:PTR ATADEVICEINFO test dword ptr [eax].SupportFlags,ATA_IDD_PACKETSUPPORT_BIT jnz ReadPacketSectors sub ecx,nSectors ;take into account nSectors sbb edx,0 ; cmp SectorNumHigh,edx ;and check if valid start sector jb ValidStartSector ; ja Error cmp SectorNumLow,ecx ;### SEE - TODO20: ### ja Error ValidStartSector: mov ecx,Drive0To3 xor edx,edx mov dl,ATADriveNumTable[ecx] mov ecx,nSectors mov Drive0To3,edx test dword ptr [eax].SupportFlags,ATA_IDD_48BITSUPPORT_BIT jz No48BitSupport CheckNext48Bit: test ecx,ecx jz Done test ecx,0FFFF0000h jnz NotLast48Bit ASSUME EAX:NOTHING invoke ATAReadSectors48,pDest,Drive0To3,SectorNumLow,SectorNumHigh,ecx ret NotLast48Bit: push ecx invoke ATAReadSectors48,pDest,Drive0To3,SectorNumLow,SectorNumHigh,0FFFFh ;0 should indicate 64K sectors (32MB), but it results in an error pop ecx test eax,eax jnz Error add pDest,0FFFFh*ATA_SECTOR_SIZE add SectorNumLow,0FFFFh adc SectorNumHigh,0 sub ecx,0FFFFh jmp CheckNext48Bit No48BitSupport: CheckNext28Bit: GfxOutputVar "Sect#:",SectorNumLow GfxOutputVar "#left:",ecx test ecx,ecx jz Done test ecx,0FFFFFF00h jnz NotLast28Bit invoke ATAReadSectors28,pDest,Drive0To3,SectorNumLow,ecx ret NotLast28Bit: push ecx invoke ATAReadSectors28,pDest,Drive0To3,SectorNumLow,0FFh ;0 should indicate 256 sectors (128KB), but it results in an error pop ecx test eax,eax jnz Error add pDest,0FFh*ATA_SECTOR_SIZE add SectorNumLow,0FFh sub ecx,0FFh jmp CheckNext28Bit ReadPacketSectors: GfxOutput "PACKET command for read sectors not yet coded" Done: xor eax,eax ret Error: GfxOutputVar "Error in ATAReadSectors:",ecx xor eax,eax inc eax ret ATAReadSectors endp ATAReadSectors28 proc pDest:DWORD,DriveNum:DWORD,SectorNum:DWORD,nSectors:DWORD ;nSectors of 0 results in an error, though it should read 256 sectors push edi push ebx mov edi,pDest btr DriveNum,0 mov dx,ATA_SECTOR_COUNT_REG;ATA_STATUS_REGR jnc PDrives_Port SDrives_Port: and dl,7Fh PDrives_Port: ;HI1: ;; or dl,07h ;ATA_STATUS_REGR ; in al,dx ; test al,ATA_STATUS_BSY ; jnz HI1 ; test al,ATA_STATUS_DRQ ; jnz HI1 ; and dl,0F2h ;ATA_SECTOR_COUNT_REG mov al,byte ptr nSectors out dx,al inc edx ;ATA_LBA_LOW_REG mov al,byte ptr SectorNum[0] out dx,al inc edx ;ATA_LBA_MID_REG mov al,byte ptr SectorNum[1] out dx,al inc edx ;ATA_LBA_HIGH_REG mov al,byte ptr SectorNum[2] out dx,al inc edx ;ATA_DEVICE_REG mov al,byte ptr SectorNum[3] or al,byte ptr DriveNum out dx,al inc edx ;ATA_COMMAND_REGW mov al,ATA_CC_READ_SECTORS out dx,al xor ebx,ebx mov bl,byte ptr nSectors push edx invoke WaitNanoseconds,400 pop edx jmp HPIOI1_2 HPIOI0: ;INTRQ_wait ;nothing, because nIEN is set to 1 (no interrupts) HPIOI1: ;Check_Status push edx mov dx,ATA_ALT_STATUS_REGR ;wait by checking the Alternate Status Register (does nothing) in al,dx pop edx HPIOI1_2: or dl,07h ;ATA_STATUS_REGR in al,dx test al,ATA_STATUS_BSY jnz HPIOI1 test al,ATA_STATUS_DRQ jz Error HPIOI2: ;Transfer_Data and dl,0F0h ;ATA_DATA_REG mov ecx,ATA_SECTOR_SIZE/2 rep insw ; insw ; or dl,07h ;ATA_STATUS_REG dec ebx ; in al,dx ; test al,ATA_STATUS_DRQ ; jnz HPIOI2 ; dec ebx jnz HPIOI1 or dl,07h ;ATA_STATUS_REG in al,dx test al,ATA_STATUS_ERR jnz Error xor eax,eax ;return 0 for no error Exit: pop ebx pop edi ret Error: GfxOutput "ATA Error in ATAReadSectors28" test eax,eax jnz Exit ;status reg value if status shows error not eax ;-1 if protocol error jmp Exit ATAReadSectors28 endp ATAReadSectors48 proc pDest:DWORD,DriveNum:DWORD,SectorNumLow:DWORD,SectorNumHigh:DWORD,nSectors:DWORD ;nSectors of 0 results in an error, though it should read 65536 sectors push edi push ebx mov edi,pDest btr DriveNum,0 mov dx,ATA_SECTOR_COUNT_REG;ATA_STATUS_REGR jnc PDrives_Port SDrives_Port: and dl,7Fh PDrives_Port: ;HI1: ;; or dl,07h ;ATA_STATUS_REGR ; in al,dx ; test al,ATA_STATUS_BSY ; jnz HI1 ; test al,ATA_STATUS_DRQ ; jnz HI1 ; and dl,0F2h ;ATA_SECTOR_COUNT_REG mov al,byte ptr nSectors[1] out dx,al mov al,byte ptr nSectors[0] out dx,al mov ecx,SectorNumLow mov ah,byte ptr SectorNumLow[2] mov ebx,SectorNumHigh inc edx ;ATA_LBA_LOW_REG shld eax,ecx,8 ;SectorNum[3] out dx,al mov al,cl ;SectorNum[0] out dx,al inc edx ;ATA_LBA_MID_REG mov al,bl ;SectorNum[4] out dx,al mov al,ch ;SectorNum[1] out dx,al inc edx ;ATA_LBA_HIGH_REG mov al,bh ;SectorNum[5] out dx,al mov al,ah ;SectorNum[2] out dx,al inc edx ;ATA_DEVICE_REG mov al,byte ptr DriveNum ; or al,40h ;sets bit to indicate using LBA out dx,al inc edx ;ATA_COMMAND_REGW mov al,ATA_CC_READ_SECTORS_EXT out dx,al xor ebx,ebx mov bl,byte ptr nSectors push edx invoke WaitNanoseconds,400 pop edx jmp HPIOI1_2 HPIOI0: ;INTRQ_wait ;nothing, because nIEN is set to 1 (no interrupts) HPIOI1: ;Check_Status push edx mov dx,ATA_ALT_STATUS_REGR ;wait by checking the Alternate Status Register (does nothing) in al,dx pop edx HPIOI1_2: or dl,07h ;ATA_STATUS_REGR in al,dx test al,ATA_STATUS_BSY jnz HPIOI1 test al,ATA_STATUS_DRQ jz Error HPIOI2: ;Transfer_Data and dl,0F0h ;ATA_DATA_REG mov ecx,ATA_SECTOR_SIZE/2 rep insw ; insw ; or dl,07h ;ATA_STATUS_REG dec ebx ; in al,dx ; test al,ATA_STATUS_DRQ ; jnz HPIOI2 ; dec ebx jnz HPIOI1 or dl,07h ;ATA_STATUS_REG in al,dx test al,ATA_STATUS_ERR jnz Error xor eax,eax Exit: pop ebx pop edi ret ;eax non-zero iff error Error: GfxOutput "ATA Error in ATAReadSectors48" or eax,1 jmp Exit ATAReadSectors48 endp ;>******************************************************************************************************************************* ;* * ;* NTFS FUNCTIONS * ;* * ;<******************************************************************************************************************************* MountNTFSPartition proc Drive0To3:DWORD,pPartitionEntry:DWORD,pBootSector:DWORD ;MODIFIES XMM0 and XMM1!!! ;Returns 0 in eax if too many partitions or not NTFS signature, otherwise eax=address of FILESYSTEMNTFSINFO push ebx push esi cmp NumPartitions,MAX_BOOT_PARTITIONS jae Error mov eax,pPartitionEntry ASSUME EAX:PTR PARTITIONENTRY mov esi,pBootSector ASSUME ESI:PTR NTFSBOOTSTRUCT xor ecx,ecx mov cl,NumPartitions mov ebx,Drive0To3 IF sizeof PARTITIONINFO_NTFS NE 64 .err ENDIF shl ecx,6 ASSUME ECX:PTR PARTITIONINFO_NTFS mov edx,[eax].FirstSector add ebx,DEVICENUM_ATA0 cmp dword ptr [esi].SystemID,"SFTN" ;check for signature of "NTFS" ("SFTN" backward because MASM reverses the order for dword-size values) jne Error mov al,[esi].SectorsPerClus movdqu xmm(0),[esi].nSectors ;also copies [esi].LCN$MFT movhlps xmm(1),xmm(0) ;[esi].LCN$MFT is now in low qword of xmm(1) mov PartitionList[ecx].Header.DeviceNum,ebx mov bl,byte ptr [esi].ClusPerFILERec mov bh,byte ptr [esi].ClusPerINDXBuf mov PartitionList[ecx].Header.PartitionType,PARTITIONTYPE_NTFS mov dword ptr PartitionList[ecx].Header.FirstSector,edx mov dword ptr PartitionList[ecx].Header.FirstSector[4],0 movq PartitionList[ecx].Header.nSectors,xmm(0) movq PartitionList[ecx].LCN$MFT,xmm(1) IF offset PARTITIONINFO_NTFS.ClusPerINDXBuf - offset PARTITIONINFO_NTFS.ClusPerFILERec NE 1 .err ENDIF mov word ptr PartitionList[ecx].ClusPerFILERec,bx ;also sets PartitionList[ecx].ClusPerINDXBuf mov PartitionList[ecx].SectorsPerClus,al lea eax,PartitionList[ecx] inc NumPartitions pop esi pop ebx ret Error: GfxOutput "Too many partitions or not valid NTFS" xor eax,eax pop esi pop ebx ret ASSUME ECX:NOTHING ASSUME ESI:NOTHING ASSUME EAX:NOTHING MountNTFSPartition endp LogicalClusNumToSector proc pFileSystemInfo:DWORD,LCNLow:DWORD,LCNHigh:DWORD ;Returns sector number in ECX:EDX and address of FILESYSTEMNTFSINFO in eax mov ecx,pFileSystemInfo ASSUME ECX:PTR PARTITIONINFO_NTFS mov eax,LCNLow push ecx movzx ecx,[ecx].SectorsPerClus ASSUME ECX:NOTHING mul ecx push eax push edx mov eax,LCNHigh mul ecx pop ecx pop edx add ecx,eax pop eax ASSUME EAX:PTR PARTITIONINFO_NTFS add edx,dword ptr [eax].Header.FirstSector adc ecx,dword ptr [eax].Header.FirstSector[4] ret ASSUME EAX:NOTHING LogicalClusNumToSector endp VirtualClusNumToSector proc pFileSystemInfo:DWORD,VCNLow:DWORD,VCNHigh:DWORD,pAttribute:DWORD ;Returns ECX:EDX=sector number, eax=# of subsequent clusters in run ;ECX:EDX=0 if sparse cluster ;ECX:EDX=-1 if past end of runs (or before end of runs) push esi push edi push ebx mov esi,pAttribute ASSUME ESI:PTR NTFSATTRIBHEADER_NRES mov eax,dword ptr [esi].FirstVCN mov edx,dword ptr [esi].FirstVCN[4] GfxOutputVar "1stVCN:",eax GfxOutputVar " ",edx sub VCNLow,eax sbb VCNHigh,edx GfxOutputVar "RelVCN:",VCNLow GfxOutputVar " ",VCNHigh jc PastEndOfRuns movzx eax,[esi].DataRunsOffset GfxOutputVar "DataRunsOffset:",eax add esi,eax ASSUME ESI:NOTHING cmp VCNHigh,0 jne Over4GCluster xor ecx,ecx ;ecx will keep track of the VCN xor ebx,ebx ;ebx will keep track of the LCN NextDataRun: lodsb mov ah,al and al,0Fh ;al has length of cluster run length shr ah,4 ;ah has length of relative cluster offset GfxOutputVar "Lengths of Offset & Length:",eax cmp al,2 je Length2Byte jb LengthBelow2Byte LengthAbove2Byte: cmp al,4 je Length4Byte ja LengthAbove4Byte Length3Byte: mov edx,[esi] shl edx,8 add esi,3 sar edx,8 jmp LengthFound LengthBelow2Byte: test al,al ;end marker is 00h, but only have to check low nibble, because length of 0 bytes is invalid jz PastEndOfRuns Length1Byte: movsx edx,byte ptr [esi] inc esi jmp LengthFound Length2Byte: movsx edx,word ptr [esi] add esi,2 jmp LengthFound Length4Byte: mov edx,[esi] add esi,4 LengthFound: cmp ah,2 je Offset2Byte jb OffsetBelow2Byte OffsetAbove2Byte: cmp ah,4 je Offset4Byte ja OffsetAbove4Byte Offset3Byte: mov edi,[esi] shl edi,8 add esi,3 sar edi,8 jmp OffsetFound OffsetBelow2Byte: test ah,ah jz NoOffset Offset1Byte: movsx edi,byte ptr [esi] inc esi jmp OffsetFound NoOffset: xor edi,edi ;no offset means that the clusters contain only 0s, so have been omitted (a.k.a. sparse clusters) Offset2Byte: movsx edi,word ptr [esi] add esi,2 jmp OffsetFound Offset4Byte: mov edi,[esi] add esi,4 OffsetFound: GfxOutputVar "Offset:",edi GfxOutputVar "Length:",edx GfxOutputVar "Next 4 bytes of data run:",dword ptr [esi] add ebx,edi add ecx,edx cmp ecx,VCNLow jbe NextDataRun FoundCluster: sub VCNLow,ecx add VCNLow,edx ;VCNLow contains number of clusters from beginning of run to desired cluster add ebx,VCNLow ;ebx contains LCN sub edx,VCNLow ;edx contains number of subsequent clusters in run, in case calling function wants to know how much it can read/write at once test edi,edi jz SparseCluster push edx GfxOutputVar "LCN:",ebx invoke LogicalClusNumToSector,pFileSystemInfo,ebx,0 pop eax GfxOutputVar "Number of consecutive clusters: ",eax pop ebx pop edi pop esi ret SparseCluster: mov eax,edx xor ecx,ecx xor edx,edx pop ebx pop edi pop esi ret OffsetAbove4Byte: ;### SEE - TODO30: ### GfxOutput "No support yet for offset >= 2^31" jmp PastEndOfRuns LengthAbove4Byte: ;### SEE - TODO29: ### GfxOutput "No support yet for cluster run length >= 2^31" jmp PastEndOfRuns Over4GCluster: ;### SEE - TODO28: ### GfxOutput "No support yet for VCN >= 2^32" PastEndOfRuns: xor ecx,ecx dec ecx mov edx,ecx pop ebx pop edi pop esi ret VirtualClusNumToSector endp GetMFTFileRecord proc pDest:DWORD,pFileSystemInfo:DWORD pusha mov edi,pFileSystemInfo ASSUME EDI:PTR PARTITIONINFO_NTFS xor eax,eax mov al,[edi].ClusPerFILERec test al,al js BytePowerLength xor edx,edx mov dl,[edi].SectorsPerClus mul edx jmp FoundNumSectors BytePowerLength: neg al IF ATA_SECTOR_SIZE NE 200h .err ENDIF sub al,9 ;ATA_SECTOR_SIZE is 2^9 mov cl,al mov al,1 shl eax,cl FoundNumSectors: push eax invoke LogicalClusNumToSector,pFileSystemInfo,dword ptr [edi].LCN$MFT,dword ptr [edi].LCN$MFT[4] pop eax mov ebx,[edi].Header.DeviceNum sub ebx,DEVICENUM_ATA0 invoke ATAReadSectors,pDest,ebx,edx,ecx,eax popa ret ASSUME EDI:NOTHING GetMFTFileRecord endp GetNTFSFileRecord proc pDest:DWORD,pFileSystemInfo:DWORD,FILERecNumLow:DWORD,FILERecNumHigh:DWORD LOCAL nClusLeft:DWORD pusha mov edi,pFileSystemInfo ASSUME EDI:PTR PARTITIONINFO_NTFS invoke GetMFTFileRecord,pDest,edi mov esi,pDest ASSUME ESI:PTR NTFSFILEHEADER xor ebx,ebx mov bx,[esi].OffAttributes add esi,ebx ASSUME ESI:PTR NTFSATTRIBHEADER NextAttribute: GfxOutputVar "MFT Attrib type: ",[esi].AttributeType cmp [esi].AttributeType,NTFSATTRIBTYPE_END_MARKER je Error cmp [esi].AttributeType,NTFSATTRIBTYPE_DATA je FoundMFTData add esi,[esi].ThisLength jmp NextAttribute FoundMFTData: xor eax,eax mov al,[edi].ClusPerFILERec test al,al js BytePowerLength mov nClusLeft,eax mov ecx,eax mul FILERecNumLow xchg eax,ecx mov ebx,edx mul FILERecNumHigh add ebx,eax NextClusters: GfxOutputVar "MFT VCN: ",ecx GfxOutputVar " ",ebx push ecx ;low dword of cluster num invoke VirtualClusNumToSector,edi,ecx,ebx,esi GfxOutputVar "Sector #: ",edx GfxOutputVar " ",ecx cmp eax,nClusLeft jae EnoughConsecutiveClusters sub nClusLeft,eax add [esp],eax ;low dword of cluster num adc ebx,0 push edx xor edx,edx mov dl,[edi].SectorsPerClus mul edx pop edx push ebx mov ebx,[edi].Header.DeviceNum sub ebx,DEVICENUM_ATA0 invoke ATAReadSectors,pDest,ebx,edx,ecx,eax pop ebx pop ecx jmp NextClusters EnoughConsecutiveClusters: mov eax,nClusLeft push edx xor edx,edx mov dl,[edi].SectorsPerClus mul edx pop edx mov ebx,[edi].Header.DeviceNum sub ebx,DEVICENUM_ATA0 invoke ATAReadSectors,pDest,ebx,edx,ecx,eax popa ret BytePowerLength: neg al IF ATA_SECTOR_SIZE NE 200h .err ENDIF sub al,9 ;ATA_SECTOR_SIZE is 2^9 mov cl,al mov al,1 shl eax,cl push eax mov eax,FILERecNumLow mov edx,FILERecNumHigh shld edx,eax,cl shl eax,cl movzx ecx,[edi].SectorsPerClus push eax ;take into account chance of VCN>=2^32 mov eax,edx ;so need to avoid divide overflow xor edx,edx ; div ecx ; mov ebx,eax ;ebx has upper dword of VCN pop eax ;edx:eax has sector # mod (SecPerClus*2^32) div ecx push edx ;edx has # of sectors to add after finding sector of the cluster GfxOutputVar "MFT VCN: ",ecx GfxOutputVar " ",ebx invoke VirtualClusNumToSector,edi,eax,ebx,esi pop eax add edx,eax adc ecx,0 GfxOutputVar "Sector #: ",edx GfxOutputVar " ",ecx pop eax mov ebx,[edi].Header.DeviceNum sub ebx,DEVICENUM_ATA0 GfxOutputVar "# of Sectors Read in GetNTFSFileRecord:",eax invoke ATAReadSectors,pDest,ebx,edx,ecx,eax Error: popa ret ASSUME EDI:NOTHING,ESI:NOTHING GetNTFSFileRecord endp SearchNTFSDirectory proc pFileSystemInfo:DWORD,pDirFileHeader:DWORD,pFileName:DWORD,pIndexScratch:DWORD ;pFileName points to a Unicode string ;Returns file reference in edx:eax LOCAL pIndexAlloc:DWORD LOCAL pIndexRoot:DWORD push esi push edi push ebx mov esi,pDirFileHeader ASSUME ESI:PTR NTFSFILEHEADER xor eax,eax mov pIndexRoot,eax mov pIndexAlloc,eax mov ax,[esi].OffAttributes ASSUME EAX:PTR NTFSATTRIBHEADER NextAttribute: GfxOutputVar "Attrib type: ",[esi][eax].AttributeType cmp [esi][eax].AttributeType,NTFSATTRIBTYPE_END_MARKER je NotFound cmp [esi][eax].AttributeType,NTFSATTRIBTYPE_INDEXROOT je FoundIndexRoot cmp [esi][eax].AttributeType,NTFSATTRIBTYPE_INDEXALLOC je FoundIndexAlloc MoveToNextAttribute: add eax,[esi][eax].ThisLength jmp NextAttribute FoundIndexAlloc: lea edx,[esi][eax] mov pIndexAlloc,edx cmp pIndexRoot,0 je MoveToNextAttribute jmp SearchTree FoundIndexRoot: ASSUME EAX:PTR NTFSATTRIBHEADER_RES GfxOutputVar "Relative Attrib Addr: ",eax movzx ecx,[esi][eax].AttributeOffset add ecx,eax ASSUME ECX:PTR NTFSINDEXROOTATTRIB GfxOutputVar "Indexing Attrib: ",[esi][ecx].IndexingAttributeType GfxOutputVar "Collation Rule: ",[esi][ecx].CollationRule GfxOutputVar "Bytes/Node in Allocation: ",[esi][ecx].BytesPerIndexNode GfxOutputVar "Clus/Node in Allocation: ",dword ptr [esi][ecx].ClustersPerIndexNode add ecx,sizeof NTFSINDEXROOTATTRIB ASSUME ECX:PTR NTFSINDEXHEADER GfxOutputVar "OffFirstIndexEntry: ",[esi][ecx].OffFirstIndexEntry test [esi][ecx].Flags,NTFSINDEXFLAG_LARGE pushf add ecx,[esi][ecx].OffFirstIndexEntry GfxOutputVar "Index Entry Addr: ",ecx mov pIndexRoot,ecx add pIndexRoot,esi popf jz SearchTree ;no $INDEX_ALLOCATION for this directory cmp pIndexAlloc,0 je MoveToNextAttribute SearchTree: mov ecx,pIndexRoot ASSUME ECX:PTR NTFSINDEXENTRY NextEntry: IF GFX_TESTING_MODE GfxOutputVar "FileRef:",dword ptr [ecx].FILERef GfxOutputVar " ",dword ptr [ecx].FILERef[4] GfxOutputVar "Lengths:",dword ptr [ecx].ThisLength GfxOutputVar "Flags:",dword ptr [ecx].Flags ; GfxOutputVar "Next Dword:",dword ptr [ecx].Flags[4] ; GfxOutputVar "Next Dword:",dword ptr [ecx].Flags[8] ; GfxOutputVar "Next Dword:",dword ptr [ecx].Flags[12] ; GfxOutputVar "Next Dword:",dword ptr [ecx].Flags[16] ; GfxOutputVar "Next Dword:",dword ptr [ecx].Flags[20] ; GfxOutputVar "Next Dword:",dword ptr [ecx].Flags[24] ; GfxOutputVar "Next Dword:",dword ptr [ecx].Flags[28] ; GfxOutputVar "Next Dword:",dword ptr [ecx].Flags[32] ENDIF test [ecx].Flags,NTFSINDEXENTRYFLAG_LAST jnz CheckSubnode GfxOutputVar "FileName:",dword ptr [ecx][sizeof NTFSINDEXENTRY][sizeof NTFSFILENAMEATTRIB] GfxOutputVar " ",dword ptr [ecx][sizeof NTFSINDEXENTRY][sizeof NTFSFILENAMEATTRIB][4] GfxOutputVar " ",dword ptr [ecx][sizeof NTFSINDEXENTRY][sizeof NTFSFILENAMEATTRIB][8] GfxOutputVar " ",dword ptr [ecx][sizeof NTFSINDEXENTRY][sizeof NTFSFILENAMEATTRIB][12] ; push ecx lea edi,[ecx][sizeof NTFSINDEXENTRY][sizeof NTFSFILENAMEATTRIB] ;offset of the filename part of the $FILE_NAME key (and note that the key does not contain the attribute header) ASSUME ECX:PTR NTFSFILENAMEATTRIB movzx ebx,[ecx][sizeof NTFSINDEXENTRY].FilenameLength ;length in characters of the Unicode filename ASSUME ECX:PTR NTFSINDEXENTRY GfxOutputVar "Filename with length: ",ebx mov esi,pFileName test ebx,ebx jz CheckFilenameEnd NextFilenameLetter: ;### SEE - TODO31: ### lodsw cmp ax,"a" jb NotLowercaseSource cmp ax,"z" ja NotLowercaseSource and al,not 20h NotLowercaseSource: mov dx,[edi] add edi,2 cmp dx,"a" jb NotLowercaseDest cmp dx,"z" ja NotLowercaseDest and dl,not 20h NotLowercaseDest: cmp dx,ax ;IF GFX_TESTING_MODE ; pushfd ; pop eax ; pushf ; GfxOutputVar "CPU Flags are: ",eax ; popf ;ENDIF ja CheckSubnode jne NotThisEntry dec ebx jnz NextFilenameLetter ; cmp eax,eax ;make sure zero flag set and carry flag set, in case name length of 0 is allowed at some point ; stc ;forcing check to see if parameter filename starts with terminator ; repe cmpsw ;Unicode, compare by word ; pop ecx ; ja CheckSubnode ;check subnode if key filename greater than parameter filename ; jne NotThisEntry CheckFilenameEnd: cmp word ptr [esi],0 ;check that key and parameter have same length before can say whether equal je Found NotThisEntry: GfxOutput "Search next entry in this node" xor edi,edi ;otherwise move to next entry in this node mov di,[ecx].ThisLength add ecx,edi jmp NextEntry Found: GfxOutput "File found" mov eax,dword ptr [ecx].FILERef mov edx,dword ptr [ecx].FILERef[4] GfxOutputVar "File ref: ",eax GfxOutputVar " ",edx pop ebx pop edi pop esi ret CheckSubnode: test [ecx].Flags,NTFSINDEXENTRYFLAG_SUBNODE jz NotFound GfxOutput "Search subnode" xor edi,edi mov di,[ecx].ThisLength GfxOutputVar "Length of prev Attribute",edi add ecx,edi GfxOutputVar "Offset of next Attribute",ecx mov eax,dword ptr [ecx][-8] mov edx,dword ptr [ecx][-4] and edx,0FFFFh ;Note: the VCN listed here also contains an Update Sequence Number in the top word, so remove it GfxOutputVar "VCN:",eax GfxOutputVar " ",edx invoke VirtualClusNumToSector,pFileSystemInfo,eax,edx,pIndexAlloc GfxOutputVar "Sector:",edx GfxOutputVar " ",ecx mov edi,pFileSystemInfo ASSUME EDI:PTR PARTITIONINFO_NTFS movsx ebx,[edi].ClusPerINDXBuf test ebx,ebx js IndexAllocLessThan1Cluster cmp eax,ebx jb RunBoundaryInIndexNode movzx eax,[edi].SectorsPerClus push edx mul ebx pop edx mov ebx,[edi].Header.DeviceNum sub ebx,DEVICENUM_ATA0 invoke ATAReadSectors,pIndexScratch,ebx,edx,ecx,eax mov ecx,pIndexScratch ASSUME ECX:PTR NTFSINDEXALLOCHEADER add ecx,[ecx].OffFirstIndexEntry add ecx,offset NTFSINDEXALLOCHEADER.OffFirstIndexEntry jmp NextEntry RunBoundaryInIndexNode: GfxOutput "No support yet for run boundaries in $INDEX_ALLOCATION nodes" jmp NotFound IndexAllocLessThan1Cluster: GfxOutput "No support yet for $INDEX_ALLOCATION nodes < 1 cluster" ASSUME EDI:NOTHING ASSUME ECX:NOTHING ASSUME EAX:NOTHING ASSUME ESI:NOTHING NotFound: GfxOutput "File not found" xor eax,eax xor edx,edx pop ebx pop edi pop esi ret SearchNTFSDirectory endp ReadNTFSFile proc pDest:DWORD,pFileSystemInfo:DWORD,pFileHeader:DWORD ;MODIFIES XMM0-3!!! ;Reads entire file (including past official end if not to exact end of cluster) push esi push edi push ebx mov esi,pFileHeader ASSUME ESI:PTR NTFSFILEHEADER IF GFX_TESTING_MODE mov esi,pFileHeader cmp [esi].Signature,"ELIF" je ValidSig GfxOutput "Invalid Signature" jmp $ ValidSig: ENDIF GfxOutputVar "Signature: ",[esi].Signature GfxOutputVar "Off(Len)UpdateSeq: ",dword ptr [esi].OffUpdateSeq GfxOutputVar "LogSeqNum: ",dword ptr [esi].LogSeqNum GfxOutputVar " ",dword ptr [esi].LogSeqNum[4] GfxOutputVar "SeqNum/HardLinkCount: ",dword ptr [esi].SeqNum GfxOutputVar "OffAttributes/Flags: ",dword ptr [esi].OffAttributes GfxOutputVar "RealSize: ",[esi].RealSize GfxOutputVar "AllocSize: ",[esi].AllocSize GfxOutputVar "NextAttributeID: ",dword ptr [esi].NextAttributeID GfxOutputVar "FILERecNum: ",[esi].FILERecNum xor eax,eax mov ax,[esi].OffAttributes add esi,eax ASSUME ESI:PTR NTFSATTRIBHEADER NextAttribute: GfxOutputVar "Attrib type: ",[esi].AttributeType cmp [esi].AttributeType,NTFSATTRIBTYPE_END_MARKER je Error cmp [esi].AttributeType,NTFSATTRIBTYPE_DATA je FoundData add esi,[esi].ThisLength jmp NextAttribute FoundData: test [esi].NonResident?,-1 jz ResidentData mov edi,pFileSystemInfo ASSUME EDI:PTR PARTITIONINFO_NTFS xor ebx,ebx NextClusterRun: invoke VirtualClusNumToSector,edi,ebx,0,esi cmp ecx,-1 jne NotDone cmp edx,-1 je Done NotDone: add ebx,eax test ecx,ecx jnz NotSparse test edx,edx jz Sparse NotSparse: GfxOutputVar "# of Regular Clusters: ",eax push esi movzx esi,[edi].SectorsPerClus push edx mul esi pop edx mov esi,[edi].Header.DeviceNum push eax sub esi,DEVICENUM_ATA0 GfxOutputVar "Drive: ",esi GfxOutputVar "Sector: ",edx GfxOutputVar " ",ecx GfxOutputVar "# of Sectors: ",eax invoke ATAReadSectors,pDest,esi,edx,ecx,eax pop eax IF ATA_SECTOR_SIZE NE 200h echo Change line in ReadNTFSFile now that ATA_SECTOR_SIZE is not 200h .err ENDIF shl eax,9 add pDest,eax pop esi jmp NextClusterRun Sparse: GfxOutputVar "# of Sparse Clusters: ",eax movzx edx,[edi].SectorsPerClus mul edx IF ATA_SECTOR_SIZE NE 200h echo Change line in ReadNTFSFile now that ATA_SECTOR_SIZE is not 200h .err ENDIF shl eax,9 mov edx,pDest add pDest,eax pxor xmm(0),xmm(0) pxor xmm(1),xmm(1) pxor xmm(2),xmm(2) pxor xmm(3),xmm(3) ZeroingLoop: movdqa [edx][00h],xmm(0) movdqa [edx][10h],xmm(1) movdqa [edx][20h],xmm(2) movdqa [edx][30h],xmm(3) add edx,40h cmp edx,pDest jne ZeroingLoop jmp NextClusterRun ResidentData: ASSUME ESI:PTR NTFSATTRIBHEADER_RES mov edi,pDest mov ecx,[esi].AttributeLength movzx edx,[esi].AttributeOffset add esi,edx rep movsb jmp Done Error: GfxOutput "Error reading file" Done: ASSUME EDI:NOTHING,ESI:NOTHING pop ebx pop edi pop esi ret ReadNTFSFile endp ;>******************************************************************************************************************************* ;* * ;* CRITICAL ERRORS * ;* * ;<******************************************************************************************************************************* IF TEXT_TESTING_MODE Inadequate_Processor: TestOutput "Inadequate Processor" jmp $ A20Disabled: TestOutput "Gate A20 Disabled" jmp $ InvalidRSDT: TestOutput "Invalid Root System Description Table" jmp NotGoodEnough ;might as well continue as a single processor InvalidMADT: TestOutput "Invalid Multiple APIC Description Table" jmp NotGoodEnough ;might as well continue as a single processor NoMultiIOAPICSupport: TestOutput "Only support for 1 IOAPIC" jmp NotGoodEnough ;might as well continue as a single processor OnlyISAOverrideSupport: TestOutput "Only support for ISA Int source overrides" jmp NotGoodEnough ;might as well continue as a single processor INITFailed: TestOutput "INIT never dispatched" jmp NotGoodEnough SIPIFailed: TestOutput "SIPI never dispatched" jmp NotGoodEnough ELSE Inadequate_Processor textequ <$> A20Disabled textequ <$> InvalidRSDT textequ InvalidMADT textequ NoMultiIOAPICSupport textequ OnlyISAOverrideSupport textequ INITFailed textequ SIPIFailed textequ ENDIF ;>******************************************************************************************************************************* ;* * ;* INTERRUPT HANDLERS * ;* * ;<******************************************************************************************************************************* ;******************************************************************************************************************************** ;* * ;* > EXCEPTION HANDLERS * ;* * ;<******************************************************************************************************************************* IntDivError proc IF TEXT_TESTING_MODE mov eax,[esp][0] TestOutputVar "Divide Error at ",eax ENDIF IF GFX_TESTING_MODE mov eax,[esp][0] GfxOutputVar "Divide Error at ",eax ENDIF jmp $ ; mov edi,pLocalAPICBoot ; xor eax,eax ; mov [edi].EndOfIntReg,eax ; iretd IntDivError endp IntInvalidOpcode proc IF TEXT_TESTING_MODE mov eax,[esp][0] TestOutputVar "Invalid Opcode Ex at ",eax ENDIF IF GFX_TESTING_MODE mov eax,[esp][0] GfxOutputVar "Invalid Opcode Ex at ",eax ENDIF jmp $ ; mov edi,pLocalAPICBoot ; xor eax,eax ; mov [edi].EndOfIntReg,eax ; iretd IntInvalidOpcode endp IntDeviceNotAvailable proc IF TEXT_TESTING_MODE mov eax,[esp][0] TestOutputVar "Device Not Available Ex at ",eax ENDIF IF GFX_TESTING_MODE mov eax,[esp][0] GfxOutputVar "Device Not Available Ex at ",eax ENDIF jmp $ ; mov edi,pLocalAPICBoot ;this part will be needed in FXSAVE handler for after boot ; xor eax,eax ; ; mov [edi].EndOfIntReg,eax ; ; iretd ; IntDeviceNotAvailable endp IntDoubleFault proc IF TEXT_TESTING_MODE mov eax,[esp][4] ;Error Code is always 0, so ignore it TestOutputVar "Double-Fault Exception at ",eax ENDIF IF GFX_TESTING_MODE mov eax,[esp][4] ;Error Code is always 0, so ignore it GfxOutputVar "Double-Fault Exception at ",eax ENDIF jmp $ ; mov edi,pLocalAPICBoot ; xor eax,eax ; mov [edi].EndOfIntReg,eax ; iretd IntDoubleFault endp IntInvalidTSS proc IF TEXT_TESTING_MODE mov eax,[esp][4] TestOutputVar "Invalid TSS Ex at ",eax mov eax,[esp][0] TestOutputVar " error code: ",eax ENDIF IF GFX_TESTING_MODE mov eax,[esp][4] GfxOutputVar "Invalid TSS Ex at ",eax mov eax,[esp][0] GfxOutputVar " error code: ",eax ENDIF jmp $ ; mov edi,pLocalAPICBoot ; xor eax,eax ; mov [edi].EndOfIntReg,eax ; iretd IntInvalidTSS endp IntSegmentNotPresent proc IF TEXT_TESTING_MODE mov eax,[esp][4] TestOutputVar "Seg Not Present Ex at ",eax mov eax,[esp][0] TestOutputVar " error code: ",eax ENDIF IF GFX_TESTING_MODE mov eax,[esp][4] GfxOutputVar "Seg Not Present Ex at ",eax mov eax,[esp][0] GfxOutputVar " error code: ",eax ENDIF jmp $ ; mov edi,pLocalAPICBoot ; xor eax,eax ; mov [edi].EndOfIntReg,eax ; iretd IntSegmentNotPresent endp IntStackFault proc IF TEXT_TESTING_MODE mov eax,[esp][4] TestOutputVar "Stack Fault at ",eax mov eax,[esp][0] TestOutputVar " error code: ",eax ENDIF IF GFX_TESTING_MODE mov eax,[esp][4] GfxOutputVar "Stack Fault at ",eax mov eax,[esp][0] GfxOutputVar " error code: ",eax ENDIF jmp $ ; mov edi,pLocalAPICBoot ; xor eax,eax ; mov [edi].EndOfIntReg,eax ; iretd IntStackFault endp IntProtectionFault proc IF TEXT_TESTING_MODE mov eax,[esp][4] TestOutputVar "Protection Fault at ",eax mov eax,[esp][0] TestOutputVar " error code: ",eax ENDIF IF GFX_TESTING_MODE mov eax,[esp][4] GfxOutputVar "Protection Fault at ",eax mov eax,[esp][0] GfxOutputVar " error code: ",eax ENDIF jmp $ ; mov edi,pLocalAPICBoot ; xor eax,eax ; mov [edi].EndOfIntReg,eax ; iretd IntProtectionFault endp IntPageFault proc IF TEXT_TESTING_MODE mov eax,[esp][4] TestOutputVar "Page Fault at ",eax mov eax,CR2 TestOutputVar " access address: ",eax mov eax,[esp][0] TestOutputVar " error code: ",eax ENDIF IF GFX_TESTING_MODE mov eax,[esp][4] GfxOutputVar "Page Fault at ",eax mov eax,CR2 GfxOutputVar " access address: ",eax mov eax,[esp][0] GfxOutputVar " error code: ",eax ENDIF jmp $ ; mov edi,pLocalAPICBoot ;this part will be needed in valid page fault handler for after boot ; xor eax,eax ; ; mov [edi].EndOfIntReg,eax ; ; iretd ; IntPageFault endp IntMachineCheckEx proc IF TEXT_TESTING_MODE mov eax,[esp][0] TestOutputVar "Machine Check Ex at ",eax ENDIF IF GFX_TESTING_MODE mov eax,[esp][0] GfxOutputVar "Machine Check Ex at ",eax ENDIF jmp $ ; mov edi,pLocalAPICBoot ; xor eax,eax ; mov [edi].EndOfIntReg,eax ; iretd IntMachineCheckEx endp IntSIMDException proc IF TEXT_TESTING_MODE mov eax,[esp][0] TestOutputVar "SIMD Fl-Pt Ex at ",eax ENDIF IF GFX_TESTING_MODE mov eax,[esp][0] GfxOutputVar "SIMD Fl-Pt Ex at ",eax ENDIF jmp $ ; mov edi,pLocalAPICBoot ; xor eax,eax ; mov [edi].EndOfIntReg,eax ; iretd IntSIMDException endp IntOtherError proc IF TEXT_TESTING_MODE mov eax,[esp][4] TestOutputVar "Unknown Exception: addr / error code:",eax mov eax,[esp][0] TestOutputVar " CS / addr :",eax ENDIF IF GFX_TESTING_MODE mov eax,[esp][4] GfxOutputVar "Unknown Exception: addr / error code:",eax mov eax,[esp][0] GfxOutputVar " CS / addr :",eax ENDIF jmp $ ; mov edi,pLocalAPICBoot ; xor eax,eax ; mov [edi].EndOfIntReg,eax ; iretd IntOtherError endp ;>******************************************************************************************************************************* ;* * ;* > IRQ (ExtInt) HANDLERS * ;* * ;<******************************************************************************************************************************* IntIRQPITInit proc ;allowed to change eax,ecx,edx ;edi contains value of pLocalAPICBoot on entry ASSUME EDI:PTR LOCALAPICMEM rdtsc sub eax,ClocksPer10ms mov ClocksPer10ms,eax mov eax,[edi].TimerCurrentCountReg mov [edi].TimerInitialCountReg,0 ;make it not send the APIC Timer interrupt TestOutput "PIT Tick" ;after reading APIC Timer Current Count to keep accuracy mov edx,PIT_MAX_RATE not eax ;eax = ((Initial Count (0FFFFFFFF)) - (Current Count)) / (Divisor (1)) mul edx mov ecx,PIT_10MS_DIVISOR*10 ;calculating ticks in 1/10 of a second, so *10 add eax,PIT_10MS_DIVISOR*10/2 ;round on division adc edx,0 ; div ecx ;works as long as less than 2^32*10 APIC Timer ticks/second (about 42.95 GHz) mov APICTicksPer100ms,eax ;for the APIC Interrupt to run out first would mean that it's at about 429.5 GHz TestOutputVar "Calculated APIC ticks/100ms: ",eax TestOutputVar "Calculated clock ticks/10ms: ",ClocksPer10ms mov ecx,[edi].IntCommandReg test ecx,APIC_ICR1_SEND_PENDING jnz INITFailed TestOutputWait "INIT confirmed to be sent" IF GFX_TESTING_MODE pusha mov eax,PA_VID_INFO mov edi,[eax].VBEMODEINFOBLOCK.PhysBasePtr mov ecx,X_RESOLUTION_WANTED*Y_RESOLUTION_WANTED mov eax,0000000h ;Black @@: stosd dec edi dec ecx jnz @B popa ENDIF inc ebx iretd ;returns with eax = APIC ticks/100ms ASSUME EDI:NOTHING IntIRQPITInit endp IntIRQPIT proc iretd IntIRQPIT endp IntIRQKeyboard proc IF TEXT_TESTING_MODE TestOutput "Keyboard int" push eax xor eax,eax in al,PS2_STATUS_REGR TestOutputVar " PS2 status value: ",eax in al,PS2_DATA_REG TestOutputVar " PS2 data value: ",eax pop eax ENDIF iretd IntIRQKeyboard endp IntIRQCOM24 proc TestOutput "COM2&4 int" iretd IntIRQCOM24 endp IntIRQCOM13 proc TestOutput "COM1&3 int" iretd IntIRQCOM13 endp IntIRQSoundCard proc TestOutput "Sound card int" iretd IntIRQSoundCard endp IntIRQFloppyDrive proc TestOutput "Floppy int" iretd IntIRQFloppyDrive endp IntIRQParallel proc TestOutput "Parallel int" iretd IntIRQParallel endp IntIRQCMOSClock proc TestOutput "CMOS clock int" iretd IntIRQCMOSClock endp IntIRQMouse proc TestOutput "Mouse int" iretd IntIRQMouse endp IntIRQIDE0 proc TestOutput "IDE0 int" iretd IntIRQIDE0 endp IntIRQIDE1 proc TestOutput "IDE1 int" iretd IntIRQIDE1 endp IntIRQUSB proc TestOutput "USB int" iretd IntIRQUSB endp IntIRQNetwork proc TestOutput "Network int" iretd IntIRQNetwork endp ;>******************************************************************************************************************************* ;* * ;* > APIC HANDLERS * ;* * ;<******************************************************************************************************************************* IntAPICError proc TestOutputWait "APIC Error" push eax push edi mov edi,pLocalAPICBoot ASSUME EDI:PTR LOCALAPICMEM xor eax,eax mov [edi].EndOfIntReg,eax pop edi pop eax iretd ASSUME EDI:NOTHING IntAPICError endp IntAPICTimer proc push eax push edi mov edi,pLocalAPICBoot ASSUME EDI:PTR LOCALAPICMEM xor eax,eax mov [edi].EndOfIntReg,eax pop edi pop eax iretd ASSUME EDI:NOTHING IntAPICTimer endp IntAPICTimerInit proc ;edi contains value of pLocalAPICBoot on entry ASSUME EDI:PTR LOCALAPICMEM ;mustn't modify eax because APIC Setup Code depends on eax staying the same TestOutput "APIC Timer End" mov ecx,[edi].IntCommandReg test ecx,APIC_ICR1_SEND_PENDING jnz SIPIFailed TestOutput "SIPI confirmed to be sent" ; xor ebx,ebx ;ebx already 0 mov [edi].EndOfIntReg,ebx ;mov dword ptr [OFFSET_APIC_EOI],0 inc ebx ;indicates done ;no need for lock (the timers don't overlap) iretd ASSUME EDI:NOTHING IntAPICTimerInit endp IntAPICSpurious proc ;should be "handled", but ignored, according to Intel ;No EOI iretd IntAPICSpurious endp ;>******************************************************************************************************************************* ;* * ;* > SOFTWARE INTERRUPTS * ;* * ;<******************************************************************************************************************************* IntHang proc jmp $ ; mov edi,pLocalAPICBoot ;ASSUME EDI:PTR LOCALAPICMEM ; xor eax,eax ; mov [edi].EndOfIntReg,eax ; iret ;ASSUME EDI:NOTHING IntHang endp IntHangInit proc mov ecx,MSR_MTRR_DEF_TYPE ;Set default memory type and enable MTRRs xor edx,edx ;Reserved mov eax,800h or MEM_UNCACHEABLE ;MTRRs enabled, Fixed-range MTRRs disabled, default memory type is uncacheable ;### SEE - TODO25: ### ; wrmsr TestOutput "Non-BSPro Enabled MTRRs" ;if more than 1 processor receives this at a time, it'll only show once lock inc ProcessorWaitCount mov edi,pLocalAPICBoot ASSUME EDI:PTR LOCALAPICMEM xor eax,eax mov [edi].EndOfIntReg,eax iretd ASSUME EDI:NOTHING IntHangInit endp IntHangInit2 proc mov ecx,PA_BOOT_PD ;set up paging by loading CR3 and setting paging enable bit in CR0 mov eax,CR0_PROTECTION_BIT or CR0_SET_BIT or CR0_PAGING_BIT ;the boot processor has set up the PTs and PD mov cr3,ecx mov cr0,eax IF PA_PL0_STACK_TOP NE VA_PL0_STACK_TOP mov esp,VA_PL0_STACK_TOP ;everything should be popped at this point, so just set it to the top ENDIF lock inc ProcessorWaitCount mov edi,pLocalAPICBoot ASSUME EDI:PTR LOCALAPICMEM xor eax,eax mov [edi].EndOfIntReg,eax iretd ASSUME EDI:NOTHING IntHangInit2 endp IntHangInit3 proc IntHangInit3 endp ;> ;>******************************************************************************************************************************* ;* * ;* TEXT TESTING OUTPUT PROCEDURES * ;* * ;<******************************************************************************************************************************* IF TEXT_TESTING_MODE TestOutputProc proc pText:DWORD,Var:DWORD,Flags:DWORD ;if ebx is modified, change APIC Timer Interrupt to use a different register or WaitFlag pusha pushfd cli @@: lock bts TextWaitFlag,0 ;only works with one call per processor max (so that's why interrupts are disabled: no two calls can come from the same processor together) jc @B mov edi,LineNum mov esi,pText mov ah,09h lea edi,[edi*4+edi] ;edi = text base + line * (80 characters/line) * (2 bytes per character) shl edi,5 ; add edi,0B8000h ; push edi NextChar: lodsb test al,al jz TextCopied stosw jmp NextChar TextCopied: test Flags,2 jz NoVar mov edx,Var mov ecx,8 ;8 hex digits mov ah,0Fh ;bright white DigitLoop: rol edx,4 ;highest -> lowest order mov al,0Fh and al,dl add al,90h ;get hex char in al daa ; adc al,40h ; daa ; stosw dec ecx jnz DigitLoop NoVar: pop ecx add ecx,80*2 ;put in space to line end sub ecx,edi mov al," " shr ecx,1 rep stosw inc LineNum ;update line # cmp LineNum,25 jne @F mov LineNum,0 mov edi,0B8000h @@: mov ax,"-"+0A00h ;put in dashed line mov ecx,80 rep stosw and TextWaitFlag,not 1 popfd ;mov [esp][14h],ebx ;this function doesn't alter ebx, but APIC Timer Interrupt might have, so it has to be preserved popa ;not perfect mutual exclusion on ebx, but this won't be in the final product anyway test Flags,1 jnz NoWait push ecx mov ecx,20000000h ;!!!!!!!!!!!IDLE FOR A BIT!!!!!!!!!!!! loop $ ; pop ecx ;@@: in al,PS2_STATUS_REGR ; test al,PS2_INPUT_BUFFER_FULL_BIT ; jz @B ; in al,PS2_DATA_REG ; cmp al,0F0h ; jnz @B ;wait for key down ;@@: in al,PS2_STATUS_REGR ; test al,PS2_INPUT_BUFFER_FULL_BIT ; jz @B ; in al,PS2_DATA_REG ; test al,80h ; jz @B ;wait for key up NoWait: ret TestOutputProc endp ENDIF IF GFX_TESTING_MODE TestOutputProc proc pText:DWORD,Var:DWORD,Flags:DWORD ;if ebx is modified, change APIC Timer Interrupt to use a different register or WaitFlag pusha pushfd cli @@: lock bts TextWaitFlag,0 ;only works with one call per processor max (so that's why interrupts are disabled: no two calls can come from the same processor together) jc @B mov ecx,VA_VID_INFO ASSUME ECX:PTR VBEMODEINFOBLOCK mov eax,LineNum xor edi,edi mov di,[ecx].BytesPerScanLine mul edi lea edi,[eax*2+eax] ;12 scanlines per text line shl edi,2 ; add edi,VA_GFX mov esi,pText push ebp NextChar: xor eax,eax lodsb test al,al jz TextCopied sub al,20h jc ControlChar push edi lea eax,[eax*2+eax] ;12 bytes per character shl eax,2 ; lea ebp,[eax+12] NextScanLine: push edi mov dl,1 NextPixel: test byte ptr FontBits[eax],dl jnz Background mov dword ptr [edi],FOREGROUND_COLOUR jmp Foreground Background: mov dword ptr [edi],BACKGROUND_COLOUR Foreground: cmp [ecx].BitsPerPixel,32 jne BitsPerPixel24 inc edi BitsPerPixel24: add edi,3 add dl,dl jnz NextPixel pop edi xor ebx,ebx mov bx,[ecx].BytesPerScanLine add edi,ebx inc eax cmp eax,ebp jb NextScanLine pop edi ControlChar: xor ebx,ebx mov bl,[ecx].BitsPerPixel add edi,ebx jmp NextChar TextCopied: pop ebp test Flags,2 jz NoVar mov esi,Var mov ebx,8 ;8 hex digits push ebp DigitLoop: push ebx rol esi,4 ;highest -> lowest order mov eax,0Fh and eax,esi add al,90h ;get hex char in al daa ; adc al,40h ; daa ; sub al,20h lea eax,[eax*2+eax] ;12 bytes per character shl eax,2 ; push edi lea ebp,[eax+12] NextScanLineVar: push edi mov dl,1 NextPixelVar: test byte ptr FontBits[eax],dl jnz BackgroundVar mov dword ptr [edi],NUMBER_FOREGROUND_COLOUR jmp ForegroundVar BackgroundVar: mov dword ptr [edi],BACKGROUND_COLOUR ForegroundVar: cmp [ecx].BitsPerPixel,32 jne BitsPerPixel24Var inc edi BitsPerPixel24Var: add edi,3 add dl,dl jnz NextPixelVar pop edi xor ebx,ebx mov bx,[ecx].BytesPerScanLine add edi,ebx inc eax cmp eax,ebp jb NextScanLineVar pop edi xor ebx,ebx mov bl,[ecx].BitsPerPixel add edi,ebx pop ebx dec ebx jnz DigitLoop pop ebp NoVar: comment ^ pop ecx add ecx,80*2 ;put in space to line end sub ecx,edi mov al," " shr ecx,1 rep stosw ^ inc LineNum ;update line # cmp LineNum,Y_RESOLUTION_WANTED/12 jne NotScreenTop mov LineNum,0 mov edi,VA_GFX jmp DoneScreenTop NotScreenTop: mov eax,LineNum xor edi,edi mov di,[ecx].BytesPerScanLine mul edi lea edi,[eax*2+eax] ;12 scanlines per text line shl edi,2 ; add edi,VA_GFX DoneScreenTop: mov ebx,X_RESOLUTION_WANTED/8 push ebp LineLoop: push ebx mov eax,("-"-20h)*12 ;12 bytes per character push edi lea ebp,[eax+12] NextScanLineLine: push edi mov dl,1 NextPixelLine: test byte ptr FontBits[eax],dl jnz BackgroundLine mov dword ptr [edi],LINE_COLOUR jmp ForegroundLine BackgroundLine: mov dword ptr [edi],BACKGROUND_COLOUR ForegroundLine: cmp [ecx].BitsPerPixel,32 jne BitsPerPixel24Line inc edi BitsPerPixel24Line: add edi,3 add dl,dl jnz NextPixelLine pop edi xor ebx,ebx mov bx,[ecx].BytesPerScanLine add edi,ebx inc eax cmp eax,ebp jb NextScanLineLine pop edi xor ebx,ebx mov bl,[ecx].BitsPerPixel add edi,ebx pop ebx dec ebx jnz LineLoop pop ebp and TextWaitFlag,not 1 popfd ;mov [esp][14h],ebx ;this function doesn't alter ebx, but APIC Timer Interrupt might have, so it has to be preserved popa ;not perfect mutual exclusion on ebx, but this won't be in the final product anyway test Flags,1 jnz NoWait push ecx mov ecx,20000000h ;!!!!!!!!!!!IDLE FOR A BIT!!!!!!!!!!!! loop $ ; pop ecx ;@@: in al,PS2_STATUS_REGR ; test al,PS2_INPUT_BUFFER_FULL_BIT ; jz @B ; in al,PS2_DATA_REG ; cmp al,0F0h ; jnz @B ;wait for key down ;@@: in al,PS2_STATUS_REGR ; test al,PS2_INPUT_BUFFER_FULL_BIT ; jz @B ; in al,PS2_DATA_REG ; test al,80h ; jz @B ;wait for key up NoWait: ret ASSUME ECX:NOTHING TestOutputProc endp ;### SEE - TODO26: ### FontBits: comment ^ font.bmp: 2-colour bitmap (background is set bit, white; flipped upside-down and leftside-right) To convert to font.bin: -Open in RadASM as Hex -Delete first 03Eh bytes -Find a byte value that's not used (01h worked this time) -Replace all instances of 00 00 00 00 with 00 00 00 xx, where xx is the unused value found above -Replace all instances of 00 00 00 with empty -Replace all instances of xx with 00 -Save as font.bin font.bin converted to byte lists with block mode in RadASM Space character added because fewer bytes than making a special case in code ^ ;<** Font data bits db 0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh db 0FFh,0F3h,0E1h,0E1h,0E1h,0F3h,0F3h,0FFh,0F3h,0F3h,0FFh,0FFh,0FFh,099h,099h,099h db 0DBh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0C9h,0C9h,080h,0C9h,0C9h,0C9h,080h db 0C9h,0C9h,0FFh,0FFh,0F3h,0F3h,0C1h,0FCh,0FCh,0E1h,0CFh,0CFh,0E0h,0F3h,0F3h,0FFh db 0FFh,0FFh,0FFh,0DCh,0CCh,0E7h,0F3h,0F9h,0CCh,0CEh,0FFh,0FFh,0FFh,0F1h,0E4h,0E4h db 0F1h,0A0h,084h,0CCh,0C4h,091h,0FFh,0FFh,0FFh,0F3h,0F3h,0F3h,0F9h,0FFh,0FFh,0FFh db 0FFh,0FFh,0FFh,0FFh,0FFh,0CFh,0E7h,0F3h,0F9h,0F9h,0F9h,0F3h,0E7h,0CFh,0FFh,0FFh db 0FFh,0F9h,0F3h,0E7h,0CFh,0CFh,0CFh,0E7h,0F3h,0F9h,0FFh,0FFh,0FFh,0FFh,0FFh,099h db 0C3h,001h,0C3h,099h,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0E7h,0E7h,081h,0E7h,0E7h db 0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0E3h,0E3h,0F9h,0FFh db 0FFh,0FFh,0FFh,0FFh,0FFh,080h,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh db 0FFh,0FFh,0FFh,0FFh,0E3h,0E3h,0FFh,0FFh,0FFh,0FFh,0BFh,09Fh,0CFh,0E7h,0F3h,0F9h db 0FCh,0FEh,0FFh,0FFh,0FFh,0C1h,09Ch,08Ch,084h,094h,090h,098h,09Ch,0C1h,0FFh,0FFh db 0FFh,0F7h,0F3h,0F0h,0F3h,0F3h,0F3h,0F3h,0F3h,0C0h,0FFh,0FFh,0FFh,0E1h,0CCh,0CCh db 0CFh,0E7h,0F3h,0F9h,0CCh,0C0h,0FFh,0FFh,0FFh,0E1h,0CCh,0CFh,0CFh,0E3h,0CFh,0CFh db 0CCh,0E1h,0FFh,0FFh,0FFh,0CFh,0C7h,0C3h,0C9h,0CCh,080h,0CFh,0CFh,087h,0FFh,0FFh db 0FFh,0C0h,0FCh,0FCh,0FCh,0E0h,0CFh,0CFh,0CCh,0E1h,0FFh,0FFh,0FFh,0E3h,0F9h,0FCh db 0FCh,0E0h,0CCh,0CCh,0CCh,0E1h,0FFh,0FFh,0FFh,080h,09Ch,09Ch,09Fh,0CFh,0E7h,0F3h db 0F3h,0F3h,0FFh,0FFh,0FFh,0E1h,0CCh,0CCh,0C8h,0E1h,0C4h,0CCh,0CCh,0E1h,0FFh,0FFh db 0FFh,0E1h,0CCh,0CCh,0CCh,0C1h,0E7h,0E7h,0F3h,0F1h,0FFh,0FFh,0FFh,0FFh,0FFh,0E3h db 0E3h,0FFh,0FFh,0E3h,0E3h,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0E3h,0E3h,0FFh,0FFh,0E3h db 0E3h,0E7h,0F3h,0FFh,0FFh,0CFh,0E7h,0F3h,0F9h,0FCh,0F9h,0F3h,0E7h,0CFh,0FFh,0FFh db 0FFh,0FFh,0FFh,0FFh,081h,0FFh,081h,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0F9h,0F3h,0E7h db 0CFh,09Fh,0CFh,0E7h,0F3h,0F9h,0FFh,0FFh,0FFh,0E1h,0CCh,0CFh,0E7h,0F3h,0F3h,0FFh db 0F3h,0F3h,0FFh,0FFh,0FFh,0C1h,09Ch,09Ch,084h,084h,084h,0FCh,0FCh,0C1h,0FFh,0FFh db 0FFh,0F3h,0E1h,0CCh,0CCh,0CCh,0C0h,0CCh,0CCh,0CCh,0FFh,0FFh,0FFh,0C0h,099h,099h db 099h,0C1h,099h,099h,099h,0C0h,0FFh,0FFh,0FFh,0C3h,099h,09Ch,0FCh,0FCh,0FCh,09Ch db 099h,0C3h,0FFh,0FFh,0FFh,0E0h,0C9h,099h,099h,099h,099h,099h,0C9h,0E0h,0FFh,0FFh db 0FFh,080h,0B9h,0F9h,0D9h,0C1h,0D9h,0F9h,0B9h,080h,0FFh,0FFh,0FFh,080h,099h,0B9h db 0D9h,0C1h,0D9h,0F9h,0F9h,0F0h,0FFh,0FFh,0FFh,0C3h,099h,09Ch,0FCh,0FCh,08Ch,09Ch db 099h,083h,0FFh,0FFh,0FFh,0CCh,0CCh,0CCh,0CCh,0C0h,0CCh,0CCh,0CCh,0CCh,0FFh,0FFh db 0FFh,0E1h,0F3h,0F3h,0F3h,0F3h,0F3h,0F3h,0F3h,0E1h,0FFh,0FFh,0FFh,087h,0CFh,0CFh db 0CFh,0CFh,0CCh,0CCh,0CCh,0E1h,0FFh,0FFh,0FFh,098h,099h,0C9h,0C9h,0E1h,0C9h,0C9h db 099h,098h,0FFh,0FFh,0FFh,0F0h,0F9h,0F9h,0F9h,0F9h,0B9h,099h,099h,080h,0FFh,0FFh db 0FFh,09Ch,088h,080h,080h,094h,09Ch,09Ch,09Ch,09Ch,0FFh,0FFh,0FFh,09Ch,09Ch,098h db 090h,080h,084h,08Ch,09Ch,09Ch,0FFh,0FFh,0FFh,0E3h,0C9h,09Ch,09Ch,09Ch,09Ch,09Ch db 0C9h,0E3h,0FFh,0FFh,0FFh,0C0h,099h,099h,099h,0C1h,0F9h,0F9h,0F9h,0F0h,0FFh,0FFh db 0FFh,0E3h,0C9h,09Ch,09Ch,09Ch,08Ch,084h,0C1h,0CFh,087h,0FFh,0FFh,0C0h,099h,099h db 099h,0C1h,0C9h,099h,099h,098h,0FFh,0FFh,0FFh,0E1h,0CCh,0CCh,0FCh,0F1h,0E7h,0CCh db 0CCh,0E1h,0FFh,0FFh,0FFh,0C0h,0D2h,0F3h,0F3h,0F3h,0F3h,0F3h,0F3h,0E1h,0FFh,0FFh db 0FFh,0CCh,0CCh,0CCh,0CCh,0CCh,0CCh,0CCh,0CCh,0E1h,0FFh,0FFh,0FFh,0CCh,0CCh,0CCh db 0CCh,0CCh,0CCh,0CCh,0E1h,0F3h,0FFh,0FFh,0FFh,09Ch,09Ch,09Ch,09Ch,094h,094h,0C9h db 0C9h,0C9h,0FFh,0FFh,0FFh,0CCh,0CCh,0CCh,0E1h,0F3h,0E1h,0CCh,0CCh,0CCh,0FFh,0FFh db 0FFh,0CCh,0CCh,0CCh,0CCh,0E1h,0F3h,0F3h,0F3h,0E1h,0FFh,0FFh,0FFh,080h,08Ch,0E6h db 0E7h,0F3h,0F9h,0B9h,09Ch,080h,0FFh,0FFh,0FFh,0C3h,0F3h,0F3h,0F3h,0F3h,0F3h,0F3h db 0F3h,0C3h,0FFh,0FFh,0FFh,0FFh,0FEh,0FCh,0F9h,0F3h,0E7h,0CFh,09Fh,0BFh,0FFh,0FFh db 0FFh,0C3h,0CFh,0CFh,0CFh,0CFh,0CFh,0CFh,0CFh,0C3h,0FFh,0FFh,0F7h,0E3h,0C9h,09Ch db 0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh db 0FFh,0FFh,001h,0FFh,0F3h,0F3h,0E7h,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh db 0FFh,0FFh,0FFh,0FFh,0E1h,0CFh,0C1h,0CCh,0CCh,091h,0FFh,0FFh,0FFh,0F8h,0F9h,0F9h db 0C1h,099h,099h,099h,099h,0C4h,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0E1h,0CCh,0FCh,0FCh db 0CCh,0E1h,0FFh,0FFh,0FFh,0C7h,0CFh,0CFh,0C1h,0CCh,0CCh,0CCh,0CCh,091h,0FFh,0FFh db 0FFh,0FFh,0FFh,0FFh,0E1h,0CCh,0C0h,0FCh,0CCh,0E1h,0FFh,0FFh,0FFh,0E3h,0C9h,0F9h db 0F9h,0E0h,0F9h,0F9h,0F9h,0F0h,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,091h,0CCh,0CCh,0CCh db 0C1h,0CFh,0CCh,0E1h,0FFh,0F8h,0F9h,0F9h,0C9h,091h,099h,099h,099h,098h,0FFh,0FFh db 0FFh,0E7h,0E7h,0FFh,0E1h,0E7h,0E7h,0E7h,0E7h,081h,0FFh,0FFh,0FFh,0CFh,0CFh,0FFh db 0C3h,0CFh,0CFh,0CFh,0CFh,0CCh,0CCh,0E1h,0FFh,0F8h,0F9h,0F9h,099h,0C9h,0E1h,0C9h db 099h,098h,0FFh,0FFh,0FFh,0E1h,0E7h,0E7h,0E7h,0E7h,0E7h,0E7h,0E7h,081h,0FFh,0FFh db 0FFh,0FFh,0FFh,0FFh,0C0h,094h,094h,094h,094h,09Ch,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh db 0E0h,0CCh,0CCh,0CCh,0CCh,0CCh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0E1h,0CCh,0CCh,0CCh db 0CCh,0E1h,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0C4h,099h,099h,099h,099h,0C1h,0F9h,0F0h db 0FFh,0FFh,0FFh,0FFh,091h,0CCh,0CCh,0CCh,0CCh,0C1h,0CFh,087h,0FFh,0FFh,0FFh,0FFh db 0C8h,089h,091h,0F9h,0F9h,0F0h,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0E1h,0CCh,0F9h,0E7h db 0CCh,0E1h,0FFh,0FFh,0FFh,0FFh,0FBh,0F9h,0C0h,0F9h,0F9h,0F9h,0C9h,0E3h,0FFh,0FFh db 0FFh,0FFh,0FFh,0FFh,0CCh,0CCh,0CCh,0CCh,0CCh,091h,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh db 0CCh,0CCh,0CCh,0CCh,0E1h,0F3h,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,09Ch,09Ch,094h,094h db 0C9h,0C9h,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,09Ch,0C9h,0E3h,0E3h,0C9h,09Ch,0FFh,0FFh db 0FFh,0FFh,0FFh,0FFh,099h,099h,099h,099h,0C3h,0CFh,0E7h,0F0h,0FFh,0FFh,0FFh,0FFh db 0C0h,0CEh,0E7h,0F9h,0DCh,0C0h,0FFh,0FFh,0FFh,0C7h,0F3h,0F3h,0F9h,0FCh,0F9h,0F3h db 0F3h,0C7h,0FFh,0FFh,0FFh,0E7h,0E7h,0E7h,0E7h,0FFh,0E7h,0E7h,0E7h,0E7h,0FFh,0FFh db 0FFh,0F8h,0F3h,0F3h,0E7h,0CFh,0E7h,0F3h,0F3h,0F8h,0FFh,0FFh,0FFh,031h,0A4h,08Ch db 0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh ;> ENDIF ;>******************************************************************************************************************************* ;* * PRE_SIPI_END EQU $ ;* STARTUP IPI * ;* WARNING: THIS MUST BE 16-BIT CODE IN THIS 32-BIT SEGMENT * ;* * ;<******************************************************************************************************************************* ;******************************************************************************************************************************** ;* * ;* SWITCH TO PROTECTED MODE * ;* * ;<******************************************************************************************************************************* IF TEXT_TESTING_MODE OFFSET_SIPI equ (PA_TRACK0+SZ_TRACK0-600h)/1000h*1000h ELSE OFFSET_SIPI equ (PA_TRACK0+SZ_TRACK0-600h)/1000h*1000h ENDIF org OFFSET_SIPI-PA_BOOTCODE32 ;must be aligned to 1000h in physical space ;and must give a bit of space (600h bytes) for the code ;(600h bytes if testing mode) ;with current configuration, it'll end up at 7000h ;must be 16-bit code @@: lock bts WaitFlag,BIT_WAITFLAG_SIPI ;only 1 processor at a time ;same encoding as 16-bit jc @B ;same encoding as 16-bit (as long as short) xor eax,eax ;set segment registers ;actually xor ax,ax 16-bit mov ds,eax ; ;looks dumb, but actually mov ds,ax 16-bit cli ;same encoding as 16-bit db 66h,0Fh,01h,1Eh ;same as: db 66h dw lowword (offset pIDT) ; lidt fword ptr pIDT db 66h,0Fh,01h,16h ;same as: db 66h dw lowword (offset pGDT) ; lgdt fword ptr pIDT xor ax,ax ;actually xor eax,eax 16-bit mov al,CR0_PROTECTION_BIT or CR0_SET_BIT ;same encoding as 16-bit mov cr0,eax ;same encoding as 16-bit db 067h ;far jump to 32-bit SIPI code db 066h ; db 0EAh ; dd offset SIPI_Code_32 ; dw SELECTOR_CORE_CODE ; SIPI_Code_32: inc ProcessorWaitCount xor eax,eax ;set segment registers mov al,SELECTOR_CORE_DATA mov ebx,CR4_OSFXSR_BIT or CR4_OSXMMEXCPT_BIT or CR4_PMC_ENABLE_BIT or CR4_MACHINE_CHK_ENABLE_BIT or CR4_PAGE_GLOBAL_ENABLE_BIT mov ds,eax ;omits useless prefix, even though it's just mov ds,ax mov es,eax ; mov ss,eax ; mov esp,PA_PL0_STACK_TOP ;good practice to set esp right after ss, because interrupts disabled until instruction after mov ss, mov ecx,ProcessorWaitCount ;but a bit more calculation is involved here, to give each processor 1KB of stack shl ecx,10 ; add esp,ecx ; mov fs,eax ; mov gs,eax ; TestOutput "Non-BSPro Loaded Seg Regs" mov cr4,ebx TestOutput "Non-BSPro Set CR4" ;>******************************************************************************************************************************* ;* * ;* PROCESSOR REQUIREMENTS * ;* * ;<******************************************************************************************************************************* xor eax,eax mov al,CPUID_FN_FEATURES cpuid TestOutputVar "Non-BSPro Features: ",edx and edx,REQUIRED_PROCESSOR_FEATURES cmp edx,REQUIRED_PROCESSOR_FEATURES jne Inadequate_Processor TestOutput "Non-BSPro Features Suffice" ; shld eax,ebx,8 ;save Local APIC ID ;already saved in MADT processing ; mov ProcessorIDs,al ;but use the Local APIC ID from ebx in I/O APIC Setup section TestOutputVar "Non-BSPro Local APIC ID (highbyte)",ebx fninit TestOutput "Non-BSPro FPU Init'd" ;>******************************************************************************************************************************* ;* * ;* MEMORY TYPE RANGE REGISTERS (MTRRs) and PAGE ATTRIUBUTE TABLE REGISTER (PAT MSR) * ;* * ;<******************************************************************************************************************************* mov ecx,MSR_MTRRCAP ;Processor must have at least required number of MTRRs rdmsr ; cmp al,N_REQUIRED_MTRRS ; jb Inadequate_Processor ; TestOutput "Non-BSPro Has Enough MTRRs" mov ecx,MSR_MTRR_PHYSBASE0 ;Set phys addr 0-7FFFFFFFh to WriteBack memory type xor edx,edx mov eax,0 or MEM_WRITEBACK wrmsr inc ecx ;MSR_MTRR_PHYSMASK0 or edx,0Fh mov eax,80000000h or MTRR_MASK_VALID wrmsr inc ecx ;MSR_MTRR_PHYSBASE1 ;Set phys addr 80000000h-BFFFFFFFh to WriteBack memory type xor edx,edx mov eax,80000000h or MEM_WRITEBACK wrmsr inc ecx ;MSR_MTRR_PHYSMASK1 or edx,0Fh mov eax,0C0000000h or MTRR_MASK_VALID wrmsr ; inc ecx ;MSR_MTRR_PHYSBASE2 ;Set phys addr 0-FFFFFh to Uncacheable memory type (for DMA memory; overrides Writeback above) ; xor edx,edx ;However, apparently, this is not necessary, because reading and writing will not both occur with DMA ; mov eax,0h or MTRR_UNCACHEABLE ; wrmsr ; inc ecx ;MSR_MTRR_PHYSMASK2 ; or edx,0Fh ; mov eax,0FFF00000h or MTRR_MASK_VALID ; wrmsr TestOutput "Non-BSPro Set MTRRs" mov ecx,MSR_PAT ;Set PAT MSR to allow Write-Combining type, which is beneficial for frame buffer memory performance mov eax,MEM_WRITEBACK or (MEM_WRITE_THROUGH shl 8) or (MEM_UNCACHED shl 16) or (MEM_UNCACHEABLE shl 24) mov edx,MEM_WRITE_COMBINING or (MEM_WRITE_PROTECTED shl 8) or (MEM_UNCACHED shl 16) or (MEM_UNCACHEABLE shl 24) wrmsr ;now setting the PAGE_TABLE_ATTRIBUTE_INDEX bit in a PTE will set it to Write-Combining type ;in this case, regardless of whether the MTRR memory type is WriteBack or uncacheable TestOutput "Non-BSPro Set PAT MSR" ;>******************************************************************************************************************************* ;* * ;* APIC SETUP * ;* * ;<******************************************************************************************************************************* mov edi,pLocalAPICBoot ASSUME EDI:PTR LOCALAPICMEM mov [edi].SpuriousIntVectorReg,APIC_SVR_ENABLE_BIT or INT_APIC_SPURIOUS ;Enable APIC mov eax,[edi].VersionReg shr eax,16 cmp al,N_REQUIRED_LVT_ENTRIES-1 ;must be minus 1 according to Intel jb Inadequate_Processor mov [edi].LVTErrorReg,INT_APIC_ERROR ;Set APIC Error interrupt vector ASSUME EDI:NOTHING TestOutput "Non-BSPro Has Enough LVT" ;### SEE - TODO4: ### and WaitFlag,not WAITFLAG_SIPI ;release flag sti ;enable interrupts so can be called from Bootstrap Processor jmp $ BOOT_END EQU $ Boot ends ;> ;> end