From c69dd9dfad3eb97d5e21f520f3ba35d102ec4cfa Mon Sep 17 00:00:00 2001 From: klu2 Date: Thu, 17 Apr 2008 05:48:13 +0000 Subject: [PATCH] Porting Duet module from EDKI to EDKII git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@5076 6f19259b-4bc3-4df7-8a09-765794883524 --- DuetPkg/BootSector/BootSector.inf | 30 + DuetPkg/BootSector/FILE.LST | 26 + DuetPkg/BootSector/Gpt.asm | 294 +++ DuetPkg/BootSector/Makefile | 276 +++ DuetPkg/BootSector/Mbr.asm | 261 +++ DuetPkg/BootSector/bootsect.asm | 288 +++ DuetPkg/BootSector/bs16.asm | 288 +++ DuetPkg/BootSector/bs32.asm | 310 +++ DuetPkg/BootSector/efi32.asm | 581 ++++++ DuetPkg/BootSector/efi64.asm | 787 ++++++++ DuetPkg/BootSector/st16_64.asm | 1140 +++++++++++ DuetPkg/BootSector/st32_64.asm | 1156 +++++++++++ DuetPkg/BootSector/start.asm | 921 +++++++++ DuetPkg/BootSector/start16.asm | 914 +++++++++ DuetPkg/BootSector/start32.asm | 929 +++++++++ DuetPkg/BootSector/start64.asm | 1147 +++++++++++ DuetPkg/CpuDxe/Cpu.c | 1151 +++++++++++ DuetPkg/CpuDxe/Cpu.dxs | 25 + DuetPkg/CpuDxe/Cpu.inf | 53 + DuetPkg/CpuDxe/CpuDxe.h | 148 ++ DuetPkg/CpuDxe/Ia32/CpuInterrupt.asm | 835 ++++++++ DuetPkg/CpuDxe/x64/CpuInterrupt.asm | 949 +++++++++ DuetPkg/CpuIoDxe/CpuIo.c | 533 +++++ DuetPkg/CpuIoDxe/CpuIo.h | 245 +++ DuetPkg/CpuIoDxe/CpuIo.inf | 56 + DuetPkg/CpuIoDxe/CpuIoAccess.h | 216 +++ DuetPkg/CpuIoDxe/Ia32/CpuIoAccess.asm | 120 ++ DuetPkg/CpuIoDxe/Ia32CpuIo.dxs | 26 + DuetPkg/CpuIoDxe/x64/CpuIoAccess.asm | 111 ++ DuetPkg/DuetPkg.dec | 6 +- DuetPkg/DuetPkg.dsc | 101 +- DuetPkg/DuetPkg.fdf | 189 ++ DuetPkg/DxeIpl/DxeIpl.inf | 13 +- DuetPkg/Include/EfiFlashMap.h | 28 +- DuetPkg/IsaAcpiDxe/ComponentName.c | 170 ++ DuetPkg/IsaAcpiDxe/IsaAcpi.c | 306 +++ DuetPkg/IsaAcpiDxe/IsaAcpi.inf | 50 + DuetPkg/IsaAcpiDxe/PcatIsaAcpi.c | 329 ++++ DuetPkg/IsaAcpiDxe/PcatIsaAcpi.h | 159 ++ DuetPkg/KbcResetDxe/Ia32/Ia32Reset.c | 79 + DuetPkg/KbcResetDxe/Ia32Reset.dxs | 27 + DuetPkg/KbcResetDxe/Ipf/IpfReset.c | 117 ++ DuetPkg/KbcResetDxe/IpfReset.dxs | 27 + DuetPkg/KbcResetDxe/Reset.c | 70 + DuetPkg/KbcResetDxe/Reset.h | 85 + DuetPkg/KbcResetDxe/Reset.inf | 59 + DuetPkg/KbcResetDxe/x64/x64Reset.c | 79 + DuetPkg/KbcResetDxe/x64Reset.dxs | 27 + DuetPkg/LegacyMetronome/Metronome.c | 201 ++ DuetPkg/LegacyMetronome/Metronome.dxs | 28 + DuetPkg/LegacyMetronome/Metronome.h | 75 + DuetPkg/LegacyMetronome/Metronome.inf | 48 + DuetPkg/Library/DuetBdsLib/BdsPlatform.c | 1720 +++++++++++++++++ DuetPkg/Library/DuetBdsLib/BdsPlatform.h | 312 +++ DuetPkg/Library/DuetBdsLib/PlatformBds.inf | 64 + DuetPkg/Library/DuetBdsLib/PlatformData.c | 157 ++ DuetPkg/PcRtc/Ia32/RealTimeClock.c | 170 ++ DuetPkg/PcRtc/Ia32RealTimeClock.dxs | 29 + DuetPkg/PcRtc/Ipf/IpfPcRtc.c | 185 ++ DuetPkg/PcRtc/IpfRealTimeClock.dxs | 28 + DuetPkg/PcRtc/RealTimeClock.c | 1065 ++++++++++ DuetPkg/PcRtc/RealTimeClock.h | 491 +++++ DuetPkg/PcRtc/RealTimeClock.inf | 63 + DuetPkg/PcRtc/x64/RealTimeClock.c | 170 ++ DuetPkg/PcRtc/x64RealTimeClock.dxs | 29 + .../PciRootBridgeNoEnumerationDxe/DeviceIo.c | 845 ++++++++ .../PciRootBridgeNoEnumerationDxe/DeviceIo.h | 449 +++++ .../Ia32/PcatIo.c | 734 +++++++ .../Ipf/PcatIo.c | 459 +++++ .../PcatPciRootBridge.c | 1018 ++++++++++ .../PcatPciRootBridge.h | 215 +++ .../PcatPciRootBridgeDevicePath.c | 87 + .../PcatPciRootBridgeIo.c | 1054 ++++++++++ .../PciRootBridgeNoEnumeration.inf | 70 + .../x64/PcatIo.c | 732 +++++++ .../RtPlatformStatusCode.c | 146 ++ .../RtPlatformStatusCode.inf | 47 + 77 files changed, 26415 insertions(+), 13 deletions(-) create mode 100644 DuetPkg/BootSector/BootSector.inf create mode 100644 DuetPkg/BootSector/FILE.LST create mode 100644 DuetPkg/BootSector/Gpt.asm create mode 100644 DuetPkg/BootSector/Makefile create mode 100644 DuetPkg/BootSector/Mbr.asm create mode 100644 DuetPkg/BootSector/bootsect.asm create mode 100644 DuetPkg/BootSector/bs16.asm create mode 100644 DuetPkg/BootSector/bs32.asm create mode 100644 DuetPkg/BootSector/efi32.asm create mode 100644 DuetPkg/BootSector/efi64.asm create mode 100644 DuetPkg/BootSector/st16_64.asm create mode 100644 DuetPkg/BootSector/st32_64.asm create mode 100644 DuetPkg/BootSector/start.asm create mode 100644 DuetPkg/BootSector/start16.asm create mode 100644 DuetPkg/BootSector/start32.asm create mode 100644 DuetPkg/BootSector/start64.asm create mode 100644 DuetPkg/CpuDxe/Cpu.c create mode 100644 DuetPkg/CpuDxe/Cpu.dxs create mode 100644 DuetPkg/CpuDxe/Cpu.inf create mode 100644 DuetPkg/CpuDxe/CpuDxe.h create mode 100644 DuetPkg/CpuDxe/Ia32/CpuInterrupt.asm create mode 100644 DuetPkg/CpuDxe/x64/CpuInterrupt.asm create mode 100644 DuetPkg/CpuIoDxe/CpuIo.c create mode 100644 DuetPkg/CpuIoDxe/CpuIo.h create mode 100644 DuetPkg/CpuIoDxe/CpuIo.inf create mode 100644 DuetPkg/CpuIoDxe/CpuIoAccess.h create mode 100644 DuetPkg/CpuIoDxe/Ia32/CpuIoAccess.asm create mode 100644 DuetPkg/CpuIoDxe/Ia32CpuIo.dxs create mode 100644 DuetPkg/CpuIoDxe/x64/CpuIoAccess.asm create mode 100644 DuetPkg/DuetPkg.fdf create mode 100644 DuetPkg/IsaAcpiDxe/ComponentName.c create mode 100644 DuetPkg/IsaAcpiDxe/IsaAcpi.c create mode 100644 DuetPkg/IsaAcpiDxe/IsaAcpi.inf create mode 100644 DuetPkg/IsaAcpiDxe/PcatIsaAcpi.c create mode 100644 DuetPkg/IsaAcpiDxe/PcatIsaAcpi.h create mode 100644 DuetPkg/KbcResetDxe/Ia32/Ia32Reset.c create mode 100644 DuetPkg/KbcResetDxe/Ia32Reset.dxs create mode 100644 DuetPkg/KbcResetDxe/Ipf/IpfReset.c create mode 100644 DuetPkg/KbcResetDxe/IpfReset.dxs create mode 100644 DuetPkg/KbcResetDxe/Reset.c create mode 100644 DuetPkg/KbcResetDxe/Reset.h create mode 100644 DuetPkg/KbcResetDxe/Reset.inf create mode 100644 DuetPkg/KbcResetDxe/x64/x64Reset.c create mode 100644 DuetPkg/KbcResetDxe/x64Reset.dxs create mode 100644 DuetPkg/LegacyMetronome/Metronome.c create mode 100644 DuetPkg/LegacyMetronome/Metronome.dxs create mode 100644 DuetPkg/LegacyMetronome/Metronome.h create mode 100644 DuetPkg/LegacyMetronome/Metronome.inf create mode 100644 DuetPkg/Library/DuetBdsLib/BdsPlatform.c create mode 100644 DuetPkg/Library/DuetBdsLib/BdsPlatform.h create mode 100644 DuetPkg/Library/DuetBdsLib/PlatformBds.inf create mode 100644 DuetPkg/Library/DuetBdsLib/PlatformData.c create mode 100644 DuetPkg/PcRtc/Ia32/RealTimeClock.c create mode 100644 DuetPkg/PcRtc/Ia32RealTimeClock.dxs create mode 100644 DuetPkg/PcRtc/Ipf/IpfPcRtc.c create mode 100644 DuetPkg/PcRtc/IpfRealTimeClock.dxs create mode 100644 DuetPkg/PcRtc/RealTimeClock.c create mode 100644 DuetPkg/PcRtc/RealTimeClock.h create mode 100644 DuetPkg/PcRtc/RealTimeClock.inf create mode 100644 DuetPkg/PcRtc/x64/RealTimeClock.c create mode 100644 DuetPkg/PcRtc/x64RealTimeClock.dxs create mode 100644 DuetPkg/PciRootBridgeNoEnumerationDxe/DeviceIo.c create mode 100644 DuetPkg/PciRootBridgeNoEnumerationDxe/DeviceIo.h create mode 100644 DuetPkg/PciRootBridgeNoEnumerationDxe/Ia32/PcatIo.c create mode 100644 DuetPkg/PciRootBridgeNoEnumerationDxe/Ipf/PcatIo.c create mode 100644 DuetPkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridge.c create mode 100644 DuetPkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridge.h create mode 100644 DuetPkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridgeDevicePath.c create mode 100644 DuetPkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridgeIo.c create mode 100644 DuetPkg/PciRootBridgeNoEnumerationDxe/PciRootBridgeNoEnumeration.inf create mode 100644 DuetPkg/PciRootBridgeNoEnumerationDxe/x64/PcatIo.c create mode 100644 DuetPkg/RtPlatformStatusCode/RtPlatformStatusCode.c create mode 100644 DuetPkg/RtPlatformStatusCode/RtPlatformStatusCode.inf diff --git a/DuetPkg/BootSector/BootSector.inf b/DuetPkg/BootSector/BootSector.inf new file mode 100644 index 0000000000..149d4e49f6 --- /dev/null +++ b/DuetPkg/BootSector/BootSector.inf @@ -0,0 +1,30 @@ +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BootSector + FILE_GUID = A36495C1-C205-414e-B71F-4BE3476D699C + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x00020000 + +[Packages] + MdePkg/MdePkg.dec + DuetPkg/DuetPkg.dec + +[Sources] + bootsect.asm + bs16.asm + bs32.asm + Gpt.asm + Mbr.asm + Start.asm + Start16.asm + Start32.asm + Efi32.asm + +[BuildOptions.common] + #MSFT:*_*_IA32_DLINK_FLAGS = /out:"$(BIN_DIR)\SecMain.exe" /base:0x10000000 /pdb:"$(BIN_DIR)\SecMain.pdb" /LIBPATH:"$(VCINSTALLDIR)\Lib" /LIBPATH:"$(VCINSTALLDIR)\PlatformSdk\Lib" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /MAP /OPT:REF /DEBUG /MACHINE:I386 /LTCG Kernel32.lib MSVCRTD.lib Gdi32.lib User32.lib Winmm.lib + MSFT:*_*_IA32_CC_FLAGS = /nologo /W4 /WX /Gy /c /D UNICODE /Od /FI$(DEST_DIR_DEBUG)/AutoGen.h /EHs-c- /GF /Gs8192 /Zi /Gm /D _CRT_SECURE_NO_WARNINGS /D _CRT_SECURE_NO_DEPRECATE + MSFT:*_*_IA32_PP_FLAGS = /nologo /E /TC /FI$(DEST_DIR_DEBUG)/AutoGen.h + MSFT:*_*_IA32_ASM_FLAGS = /nologo /W3 /WX /c /coff /Cx /Zd /W0 /Zi + MSFT:*_*_IA32_ASMLINK_FLAGS = /link /nologo /tiny diff --git a/DuetPkg/BootSector/FILE.LST b/DuetPkg/BootSector/FILE.LST new file mode 100644 index 0000000000..f0f47a42a9 --- /dev/null +++ b/DuetPkg/BootSector/FILE.LST @@ -0,0 +1,26 @@ +IA32 +==== +FAT12 FAT16 FAT32 +bootsect.asm bs16.asm bs32.asm +start.asm start16.asm start32.asm + \ | / + \ | / + efi32.asm + +X64 +=== +FAT12 FAT16 FAT32 +bootsect.asm bs16.asm bs32.asm +start64.asm st16_64.asm st32_64.asm + \ | / + \ | / + efi64.asm + +MBR +=== +Mbr.asm + + +GPT +=== +Gpt.asm \ No newline at end of file diff --git a/DuetPkg/BootSector/Gpt.asm b/DuetPkg/BootSector/Gpt.asm new file mode 100644 index 0000000000..15f91f5f49 --- /dev/null +++ b/DuetPkg/BootSector/Gpt.asm @@ -0,0 +1,294 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright 2006 - 2007, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* gpt.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + + .model small +; .dosseg + .stack + .486p + .code + +BLOCK_SIZE EQU 0200h +BLOCK_MASK EQU 01ffh +BLOCK_SHIFT EQU 9 + +; **************************************************************************** +; Code loaded by BIOS at 0x0000:0x7C00 +; **************************************************************************** + + org 0h +Start: + +; **************************************************************************** +; Start Print +; **************************************************************************** + + mov ax,0b800h + mov es,ax + mov ax, 07c0h + mov ds, ax + lea si, cs:[StartString] + mov cx, 10 + mov di, 160 + rep movsw + +; **************************************************************************** +; Print over +; **************************************************************************** + +; **************************************************************************** +; Initialize segment registers and copy code at 0x0000:0x7c00 to 0x0000:0x0600 +; **************************************************************************** + xor ax, ax ; AX = 0x0000 + mov bx, 07c00h ; BX = 0x7C00 + mov bp, 0600h ; BP = 0x0600 + mov si, OFFSET RelocatedStart ; SI = Offset(RelocatedStart) + mov cx, 0200h ; CX = 0x0200 + sub cx, si ; CS = 0x0200 - Offset(RelocatedStart) + lea di, [bp+si] ; DI = 0x0600 + Offset(RelocatedStart) + lea si, [bx+si] ; BX = 0x7C00 + Offset(RelocatedStart) + mov ss, ax ; SS = 0x0000 + mov sp, bx ; SP = 0x7C00 + mov es,ax ; ES = 0x0000 + mov ds,ax ; DS = 0x0000 + push ax ; PUSH 0x0000 + push di ; PUSH 0x0600 + Offset(RelocatedStart) + cld ; Clear the direction flag + rep movsb ; Copy 0x0200 bytes from 0x7C00 to 0x0600 + retf ; JMP 0x0000:0x0600 + Offset(RelocatedStart) + +; **************************************************************************** +; Code relocated to 0x0000:0x0600 +; **************************************************************************** + +RelocatedStart: +; **************************************************************************** +; Get Driver Parameters to 0x0000:0x7BFC +; **************************************************************************** + xor ax,ax ; ax = 0 + mov ss,ax ; ss = 0 + add ax,1000h + mov ds,ax + + mov sp,07c00h ; sp = 0x7c00 + mov bp,sp ; bp = 0x7c00 + + mov ah,8 ; ah = 8 - Get Drive Parameters Function + mov byte ptr [bp+PhysicalDrive],dl ; BBS defines that BIOS would pass the booting driver number to the loader through DL + int 13h ; Get Drive Parameters + xor ax,ax ; ax = 0 + mov al,dh ; al = dh + inc al ; MaxHead = al + 1 + push ax ; 0000:7bfe = MaxHead + mov al,cl ; al = cl + and al,03fh ; MaxSector = al & 0x3f + push ax ; 0000:7bfc = MaxSector + +; **************************************************************************** +; Read GPT Header from hard disk to 0x0000:0x0800 +; **************************************************************************** + xor ax, ax + mov es, ax ; Read to 0x0000:0x0800 + mov di, 0800h ; Read to 0x0000:0x0800 + mov eax, 1 ; Read LBA #1 + mov edx, 0 ; Read LBA #1 + mov bx, 1 ; Read 1 Block + push es + call ReadBlocks + pop es + +; **************************************************************************** +; Read Target GPT Entry from hard disk to 0x0000:0x0A00 +; **************************************************************************** + cmp dword ptr es:[di], 020494645h ; Check for "EFI " + jne BadGpt + cmp dword ptr es:[di + 4], 054524150h ; Check for "PART" + jne BadGpt + cmp dword ptr es:[di + 8], 000010000h ; Check Revision - 0x10000 + jne BadGpt + + mov eax, dword ptr es:[di + 84] ; EAX = SizeOfPartitionEntry + mul byte ptr [bp+GptPartitionIndicator] ; EAX = SizeOfPartitionEntry * GptPartitionIndicator + mov edx, eax ; EDX = SizeOfPartitionEntry * GptPartitionIndicator + shr eax, BLOCK_SHIFT ; EAX = (SizeOfPartitionEntry * GptPartitionIndicator) / BLOCK_SIZE + and edx, BLOCK_MASK ; EDX = Targer PartitionEntryLBA Offset + ; = (SizeOfPartitionEntry * GptPartitionIndicator) % BLOCK_SIZE + push edx + mov ecx, dword ptr es:[di + 72] ; ECX = PartitionEntryLBA (Low) + mov ebx, dword ptr es:[di + 76] ; EBX = PartitionEntryLBA (High) + add eax, ecx ; EAX = Target PartitionEntryLBA (Low) + ; = (PartitionEntryLBA + + ; (SizeOfPartitionEntry * GptPartitionIndicator) / BLOCK_SIZE) + adc edx, ebx ; EDX = Target PartitionEntryLBA (High) + + mov di, 0A00h ; Read to 0x0000:0x0A00 + mov bx, 1 ; Read 1 Block + push es + call ReadBlocks + pop es + +; **************************************************************************** +; Read Target DBR from hard disk to 0x0000:0x7C00 +; **************************************************************************** + pop edx ; EDX = (SizeOfPartitionEntry * GptPartitionIndicator) % BLOCK_SIZE + add di, dx ; DI = Targer PartitionEntryLBA Offset + cmp dword ptr es:[di], 0C12A7328h ; Check for EFI System Partition "C12A7328-F81F-11d2-BA4B-00A0C93EC93B" + jne BadGpt + cmp dword ptr es:[di + 4], 011d2F81Fh ; + jne BadGpt + cmp dword ptr es:[di + 8], 0A0004BBAh ; + jne BadGpt + cmp dword ptr es:[di + 0ch], 03BC93EC9h ; + jne BadGpt + + mov eax, dword ptr es:[di + 32] ; EAX = StartingLBA (Low) + mov edx, dword ptr es:[di + 36] ; EDX = StartingLBA (High) + mov di, 07C00h ; Read to 0x0000:0x7C00 + mov bx, 1 ; Read 1 Block + call ReadBlocks + +; **************************************************************************** +; Transfer control to BootSector - Jump to 0x0000:0x7C00 +; **************************************************************************** + xor ax, ax + push ax ; PUSH 0x0000 + mov di, 07c00h + push di ; PUSH 0x7C00 + retf ; JMP 0x0000:0x7C00 + +; **************************************************************************** +; ReadBlocks - Reads a set of blocks from a block device +; +; EDX:EAX = Start LBA +; BX = Number of Blocks to Read (must < 127) +; ES:DI = Buffer to store sectors read from disk +; **************************************************************************** + +; si = DiskAddressPacket + +ReadBlocks: + pushad + push ds + xor cx, cx + mov ds, cx + mov bp, 0600h ; bp = 0x600 + lea si, [bp + OFFSET AddressPacket] ; DS:SI = Disk Address Packet + mov BYTE PTR ds:[si+2],bl ; 02 = Number Of Block transfered + mov WORD PTR ds:[si+4],di ; 04 = Transfer Buffer Offset + mov WORD PTR ds:[si+6],es ; 06 = Transfer Buffer Segment + mov DWORD PTR ds:[si+8],eax ; 08 = Starting LBA (Low) + mov DWORD PTR ds:[si+0ch],edx ; 0C = Starting LBA (High) + mov ah, 42h ; ah = Function 42 + mov dl,byte ptr [bp+PhysicalDrive] ; dl = Drive Number + int 13h + jc BadGpt + pop ds + popad + ret + +; **************************************************************************** +; Address Packet used by ReadBlocks +; **************************************************************************** +AddressPacket: + db 10h ; Size of address packet + db 00h ; Reserved. Must be 0 + db 01h ; Read blocks at a time (To be fixed each times) + db 00h ; Reserved. Must be 0 + dw 0000h ; Destination Address offset (To be fixed each times) + dw 0000h ; Destination Address segment (To be fixed each times) +AddressPacketLba: + dd 0h, 0h ; Start LBA (To be fixed each times) +AddressPacketEnd: + +; **************************************************************************** +; ERROR Condition: +; **************************************************************************** + +BadGpt: + mov ax,0b800h + mov es,ax + mov ax, 060h + mov ds, ax + lea si, cs:[ErrorString] + mov cx, 10 + mov di, 320 + rep movsw +Halt: + jmp Halt + +StartString: + db 'G', 0ch, 'P', 0ch, 'T', 0ch, ' ', 0ch, 'S', 0ch, 't', 0ch, 'a', 0ch, 'r', 0ch, 't', 0ch, '!', 0ch +ErrorString: + db 'G', 0ch, 'P', 0ch, 'T', 0ch, ' ', 0ch, 'E', 0ch, 'r', 0ch, 'r', 0ch, 'o', 0ch, 'r', 0ch, '!', 0ch + +; **************************************************************************** +; PhysicalDrive - Used to indicate which disk to be boot +; Can be patched by tool +; **************************************************************************** + org 01B6h +PhysicalDrive db 80h + +; **************************************************************************** +; GptPartitionIndicator - Used to indicate which GPT partition to be boot +; Can be patched by tool +; **************************************************************************** + org 01B7h +GptPartitionIndicator db 0 + +; **************************************************************************** +; Unique MBR signature +; **************************************************************************** + org 01B8h + db 'DUET' + +; **************************************************************************** +; Unknown +; **************************************************************************** + org 01BCh + dw 0 + +; **************************************************************************** +; PMBR Entry - Can be patched by tool +; **************************************************************************** + org 01BEh + db 0 ; Boot Indicator + db 0ffh ; Start Header + db 0ffh ; Start Sector + db 0ffh ; Start Track + db 0eeh ; OS Type + db 0ffh ; End Header + db 0ffh ; End Sector + db 0ffh ; End Track + dd 1 ; Starting LBA + dd 0FFFFFFFFh ; End LBA + + org 01CEh + dd 0, 0, 0, 0 + org 01DEh + dd 0, 0, 0, 0 + org 01EEh + dd 0, 0, 0, 0 + +; **************************************************************************** +; Sector Signature +; **************************************************************************** + + org 01FEh +SectorSignature: + dw 0aa55h ; Boot Sector Signature + + end + diff --git a/DuetPkg/BootSector/Makefile b/DuetPkg/BootSector/Makefile new file mode 100644 index 0000000000..fc24f37677 --- /dev/null +++ b/DuetPkg/BootSector/Makefile @@ -0,0 +1,276 @@ + +# +# Platform Macro Definition +# +PLATFORM_NAME = DuetPkg +PLATFORM_GUID = 199E24E0-0989-42aa-87F2-611A8C397E72 +PLATFORM_VERSION = 0.3 +PLATFORM_RELATIVE_DIR = DuetPkg +PLATFORM_DIR = $(WORKSPACE)\DuetPkg +PLATFORM_OUTPUT_DIR = Build\DuetPkg + +# +# Module Macro Definition +# +MODULE_NAME = BootSector +MODULE_GUID = 2410F0DF-D915-4137-BD04-AAB6BA4C50E0 +MODULE_VERSION = 1.0 +MODULE_TYPE = USER_DEFINED +MODULE_FILE_BASE_NAME = BootSector +BASE_NAME = $(MODULE_NAME) +MODULE_RELATIVE_DIR = DuetPkg\BootSector +MODULE_DIR = $(WORKSPACE)\DuetPkg\BootSector + +# +# Build Configuration Macro Definition +# +ARCH = IA32 +TOOLCHAIN_TAG = MYTOOLS +TARGET = DEBUG +BASETOOLS_DIR=m:\tree\working\BaseTools\Bin\Win32 + +# +# Build Directory Macro Definition +# +# PLATFORM_BUILD_DIR = m:\tree\working\Build\DuetPkg\DEBUG_MYTOOLS +BUILD_DIR = $(WORKSPACE)\Build\DuetPkg\DEBUG_MYTOOLS +BIN_DIR = $(BUILD_DIR)\IA32 +LIB_DIR = $(BIN_DIR) +MODULE_BUILD_DIR = $(BUILD_DIR)\IA32\DuetPkg\BootSector\BootSector +OUTPUT_DIR = $(MODULE_BUILD_DIR)\OUTPUT +DEBUG_DIR = $(MODULE_BUILD_DIR)\DEBUG +DEST_DIR_OUTPUT = $(OUTPUT_DIR) +DEST_DIR_DEBUG = $(DEBUG_DIR) + +# +# Default Tools Flags Macro Definition (from tools_def.txt by default) +# +DEFAULT_PP_FLAGS = /nologo /E /TC /FIAutoGen.h +DEFAULT_SLINK_FLAGS = /nologo /LTCG +DEFAULT_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs8192 /Gy /D UNICODE /O1ib2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Zi /Gm +DEFAULT_APP_FLAGS = /nologo /E /TC +DEFAULT_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FIAutoGen.h +DEFAULT_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4086 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /MACHINE:I386 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:CONSOLE /SAFESEH:NO /BASE:0 /DRIVER /DEBUG /PDB:$(DEBUG_DIR)/$(BASE_NAME).pdb +DEFAULT_ASM_FLAGS = /nologo /c /WX /W3 /coff /Cx /Zd /Zi +DEFAULT_TIANO_FLAGS = +DEFAULT_MAKE_FLAGS = /nologo +DEFAULT_ASMLINK_FLAGS = /nologo /tiny +DEFAULT_ASL_FLAGS = + + +# +# Platform Tools Flags Macro Definition (from platform description file) +# +PLATFORM_PP_FLAGS = +PLATFORM_SLINK_FLAGS = +PLATFORM_CC_FLAGS = +PLATFORM_APP_FLAGS = +PLATFORM_VFRPP_FLAGS = +PLATFORM_DLINK_FLAGS = +PLATFORM_ASM_FLAGS = +PLATFORM_TIANO_FLAGS = +PLATFORM_MAKE_FLAGS = +PLATFORM_ASMLINK_FLAGS = +PLATFORM_ASL_FLAGS = + + +# +# Module Tools Flags Macro Definition (from platform/module description file) +# +MODULE_PP_FLAGS = +MODULE_SLINK_FLAGS = +MODULE_CC_FLAGS = +MODULE_APP_FLAGS = +MODULE_VFRPP_FLAGS = +MODULE_DLINK_FLAGS = +MODULE_ASM_FLAGS = +MODULE_TIANO_FLAGS = +MODULE_MAKE_FLAGS = +MODULE_ASMLINK_FLAGS = +MODULE_ASL_FLAGS = + + +# +# Tools Flag Macro +# +PP_FLAGS = $(DEFAULT_PP_FLAGS) $(PLATFORM_PP_FLAGS) $(MODULE_PP_FLAGS) +SLINK_FLAGS = $(DEFAULT_SLINK_FLAGS) $(PLATFORM_SLINK_FLAGS) $(MODULE_SLINK_FLAGS) +CC_FLAGS = $(DEFAULT_CC_FLAGS) $(PLATFORM_CC_FLAGS) $(MODULE_CC_FLAGS) +APP_FLAGS = $(DEFAULT_APP_FLAGS) $(PLATFORM_APP_FLAGS) $(MODULE_APP_FLAGS) +VFRPP_FLAGS = $(DEFAULT_VFRPP_FLAGS) $(PLATFORM_VFRPP_FLAGS) $(MODULE_VFRPP_FLAGS) +DLINK_FLAGS = $(DEFAULT_DLINK_FLAGS) $(PLATFORM_DLINK_FLAGS) $(MODULE_DLINK_FLAGS) +ASM_FLAGS = $(DEFAULT_ASM_FLAGS) $(PLATFORM_ASM_FLAGS) $(MODULE_ASM_FLAGS) +TIANO_FLAGS = $(DEFAULT_TIANO_FLAGS) $(PLATFORM_TIANO_FLAGS) $(MODULE_TIANO_FLAGS) +MAKE_FLAGS = $(DEFAULT_MAKE_FLAGS) $(PLATFORM_MAKE_FLAGS) $(MODULE_MAKE_FLAGS) +ASMLINK_FLAGS = $(DEFAULT_ASMLINK_FLAGS) $(PLATFORM_ASMLINK_FLAGS) $(MODULE_ASMLINK_FLAGS) +ASL_FLAGS = $(DEFAULT_ASL_FLAGS) $(PLATFORM_ASL_FLAGS) $(MODULE_ASL_FLAGS) + + +# +# Tools Path Macro +# +PP = C:\Program Files\Microsoft Visual Studio 8\Vc\bin\cl.exe +SLINK = C:\Program Files\Microsoft Visual Studio 8\Vc\bin\lib.exe +CC = C:\Program Files\Microsoft Visual Studio 8\Vc\bin\cl.exe +APP = C:\Program Files\Microsoft Visual Studio 8\Vc\bin\cl.exe +VFRPP = C:\Program Files\Microsoft Visual Studio 8\Vc\bin\cl.exe +DLINK = C:\Program Files\Microsoft Visual Studio 8\Vc\bin\link.exe +ASM = C:\WINDDK\3790.1830\bin\x86\ml.exe +TIANO = TianoCompress.exe +MAKE = C:\Program Files\Microsoft Visual Studio 8\Vc\bin\nmake.exe +#ASMLINK = C:\WINDDK\3790.1830\bin\bin16\link.exe +ASMLINK = C:\WINDDK\3790.1830\bin\bin16\link16.exe +ASL = C:\ASL\iasl.exe + + +MAKE_FILE = $(MODULE_BUILD_DIR)\Makefile + +# +# Shell Command Macro +# +RD = rmdir /s /q +RM = del /f /q +MD = mkdir +CP = copy /y +MV = move /y + + +# +# Build Macro +# +ASSEMBLY_CODE_FILE_LIST = $(MODULE_DIR)\bootsect.asm \ + $(MODULE_DIR)\bs16.asm \ + $(MODULE_DIR)\bs32.asm \ + $(MODULE_DIR)\efi32.asm \ + $(MODULE_DIR)\Gpt.asm \ + $(MODULE_DIR)\Mbr.asm \ + $(MODULE_DIR)\start.asm \ + $(MODULE_DIR)\start16.asm \ + $(MODULE_DIR)\start32.asm + +TARGET_FILES = $(OUTPUT_DIR)\bootsect.com \ + $(OUTPUT_DIR)\bs16.com \ + $(OUTPUT_DIR)\bs32.com \ + $(OUTPUT_DIR)\Gpt.com \ + $(OUTPUT_DIR)\Mbr.com \ + $(OUTPUT_DIR)\Start.com \ + $(OUTPUT_DIR)\Start16.com \ + $(OUTPUT_DIR)\Start32.com \ + $(OUTPUT_DIR)\efi32.com2 + +INC = + + +#OBJECTS = + +LIBS = + +COMMON_DEPS = + +all: init $(TARGET_FILES) loader + +init: + if not exist $(OUTPUT_DIR) mkdir $(OUTPUT_DIR) + if not exist $(DEBUG_DIR) mkdir $(DEBUG_DIR) + +#============= +$(OUTPUT_DIR)\bootsect.obj:$(MODULE_DIR)\bootsect.asm + $(ASM) /c /omf /Fo"$(OUTPUT_DIR)\bootsect.obj" /FR"$(OUTPUT_DIR)\bootsect.txt" "$(MODULE_DIR)\bootsect.asm" + +$(OUTPUT_DIR)\bootsect.com:$(OUTPUT_DIR)\bootsect.obj + "$(ASMLINK)" /tiny $(OUTPUT_DIR)\bootsect.obj,$(OUTPUT_DIR)\bootsect.com,$(OUTPUT_DIR)\bootsect.map,,, + +#============= + +$(OUTPUT_DIR)\bs16.obj:$(MODULE_DIR)\bs16.asm + $(ASM) /c /omf /Fo"$(OUTPUT_DIR)\bs16.obj" "$(MODULE_DIR)\bs16.asm" + +$(OUTPUT_DIR)\bs16.com:$(OUTPUT_DIR)\bs16.obj + "$(ASMLINK)" /tiny $(OUTPUT_DIR)\bs16.obj,$(OUTPUT_DIR)\bs16.com,$(OUTPUT_DIR)\bs16.map,,, + +#============= + +$(OUTPUT_DIR)\bs32.obj:$(MODULE_DIR)\bs32.asm + $(ASM) /c /omf /Fo"$(OUTPUT_DIR)\bs32.obj" "$(MODULE_DIR)\bs32.asm" + +$(OUTPUT_DIR)\bs32.com:$(OUTPUT_DIR)\bs32.obj + "$(ASMLINK)" /tiny $(OUTPUT_DIR)\bs32.obj,$(OUTPUT_DIR)\bs32.com,$(OUTPUT_DIR)\bs32.map,,, + +#============= + +$(OUTPUT_DIR)\Gpt.obj:$(MODULE_DIR)\Gpt.asm + $(ASM) /c /omf /Fo"$(OUTPUT_DIR)\Gpt.obj" "$(MODULE_DIR)\Gpt.asm" + +$(OUTPUT_DIR)\Gpt.com:$(OUTPUT_DIR)\Gpt.obj + "$(ASMLINK)" /tiny $(OUTPUT_DIR)\Gpt.obj,$(OUTPUT_DIR)\Gpt.com,$(OUTPUT_DIR)\Gpt.map,,, + +#============= + +$(OUTPUT_DIR)\Mbr.obj:$(MODULE_DIR)\Mbr.asm + $(ASM) /c /omf /Fo"$(OUTPUT_DIR)\Mbr.obj" "$(MODULE_DIR)\Mbr.asm" + +$(OUTPUT_DIR)\Mbr.com:$(OUTPUT_DIR)\Mbr.obj + "$(ASMLINK)" /tiny $(OUTPUT_DIR)\Mbr.obj,$(OUTPUT_DIR)\Mbr.com,$(OUTPUT_DIR)\Mbr.map,,, + +#============ + +$(OUTPUT_DIR)\Start.obj:$(MODULE_DIR)\Start.asm + $(ASM) /c /omf /Fo"$(OUTPUT_DIR)\Start.obj" "$(MODULE_DIR)\Start.asm" + +$(OUTPUT_DIR)\Start.com:$(OUTPUT_DIR)\Start.obj + "$(ASMLINK)" /tiny $(OUTPUT_DIR)\Start.obj,$(OUTPUT_DIR)\Start.com,$(OUTPUT_DIR)\Start.map,,, + +#============= + +$(OUTPUT_DIR)\Start16.obj:$(MODULE_DIR)\Start16.asm + $(ASM) /c /omf /Fo"$(OUTPUT_DIR)\Start16.obj" "$(MODULE_DIR)\Start16.asm" + +$(OUTPUT_DIR)\Start16.com:$(OUTPUT_DIR)\Start16.obj + "$(ASMLINK)" /tiny $(OUTPUT_DIR)\Start16.obj,$(OUTPUT_DIR)\Start16.com,$(OUTPUT_DIR)\Start16.map,,, + +#============= + +$(OUTPUT_DIR)\Start32.obj:$(MODULE_DIR)\Start32.asm + $(ASM) /c /omf /Fo"$(OUTPUT_DIR)\Start32.obj" "$(MODULE_DIR)\Start32.asm" + +$(OUTPUT_DIR)\Start32.com:$(OUTPUT_DIR)\Start32.obj + "$(ASMLINK)" /tiny $(OUTPUT_DIR)\Start32.obj,$(OUTPUT_DIR)\Start32.com,$(OUTPUT_DIR)\Start32.map,,, + +#============= + +$(OUTPUT_DIR)\efi32.obj:$(MODULE_DIR)\efi32.asm + $(ASM) /c /omf /Fo"$(OUTPUT_DIR)\efi32.obj" "$(MODULE_DIR)\efi32.asm" + +$(OUTPUT_DIR)\efi32.com:$(OUTPUT_DIR)\efi32.obj + "$(ASMLINK)" /tiny $(OUTPUT_DIR)\efi32.obj,$(OUTPUT_DIR)\efi32.com,$(OUTPUT_DIR)\efi32.map,,, + +#============= + +$(OUTPUT_DIR)\efi32.com2:$(OUTPUT_DIR)\efi32.com + $(BASETOOLS_DIR)\Split.exe -f $(OUTPUT_DIR)\efi32.com -t $(OUTPUT_DIR)\efi32.com2 -s 135168 +# +# clean all generated files +# + +loader:$(BUILD_DIR)\FV\Efildr + +$(BUILD_DIR)\FV\DUETEFIMAINFV.z:$(BUILD_DIR)\FV\DUETEFIMAINFV.Fv + $(BASETOOLS_DIR)\TianoCompress -e -o $(BUILD_DIR)\FV\DUETEFIMAINFV.z $(BUILD_DIR)\FV\DUETEFIMAINFV.Fv + +$(BUILD_DIR)\FV\DxeMain.z:$(BUILD_DIR)\IA32\DxeMain.efi + $(BASETOOLS_DIR)\TianoCompress -e -o $(BUILD_DIR)\FV\DxeMain.z $(BUILD_DIR)\IA32\DxeMain.efi + +$(BUILD_DIR)\FV\DxeIpl.z:$(BUILD_DIR)\IA32\DxeIpl.efi + $(BASETOOLS_DIR)\TianoCompress -e -o $(BUILD_DIR)\FV\DxeIpl.z $(BUILD_DIR)\IA32\DxeIpl.efi + +$(BUILD_DIR)\FV\Efildr32:$(BUILD_DIR)\IA32\EfiLoader.efi $(BUILD_DIR)\FV\DxeIpl.z $(BUILD_DIR)\FV\DUETEFIMAINFV.z + $(BASETOOLS_DIR)\EfiLdrImage.exe -o $(BUILD_DIR)\FV\Efildr32 $(BUILD_DIR)\IA32\EfiLoader.efi $(BUILD_DIR)\FV\DxeIpl.z $(BUILD_DIR)\FV\DUETEFIMAINFV.z + +$(BUILD_DIR)\FV\Efildr:$(OUTPUT_DIR)\Start.com $(OUTPUT_DIR)\Efi32.com2 $(BUILD_DIR)\FV\Efildr32 + copy /b $(OUTPUT_DIR)\BootSect.com+$(OUTPUT_DIR)\Efi32.com2+$(BUILD_DIR)\FV\Efildr32 $(BUILD_DIR)\FV\Efildr + +clean: + if exist $(DEBUG_DIR) rmdir /s /q $(DEBUG_DIR) + if exist $(OUTPUT_DIR) rmdir /s /q $(OUTPUT_DIR) + + diff --git a/DuetPkg/BootSector/Mbr.asm b/DuetPkg/BootSector/Mbr.asm new file mode 100644 index 0000000000..03182a649a --- /dev/null +++ b/DuetPkg/BootSector/Mbr.asm @@ -0,0 +1,261 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright 2006 - 2007, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* Mbr.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + + .model small +; .dosseg + .stack + .486p + .code + +BLOCK_SIZE EQU 0200h +BLOCK_MASK EQU 01ffh +BLOCK_SHIFT EQU 9 + +; **************************************************************************** +; Code loaded by BIOS at 0x0000:0x7C00 +; **************************************************************************** + + org 0h +Start: + +; **************************************************************************** +; Start Print +; **************************************************************************** + + mov ax,0b800h + mov es,ax + mov ax, 07c0h + mov ds, ax + lea si, cs:[StartString] + mov cx, 10 + mov di, 160 + rep movsw + +; **************************************************************************** +; Print over +; **************************************************************************** + +; **************************************************************************** +; Initialize segment registers and copy code at 0x0000:0x7c00 to 0x0000:0x0600 +; **************************************************************************** + xor ax, ax ; AX = 0x0000 + mov bx, 07c00h ; BX = 0x7C00 + mov bp, 0600h ; BP = 0x0600 + mov si, OFFSET RelocatedStart ; SI = Offset(RelocatedStart) + mov cx, 0200h ; CX = 0x0200 + sub cx, si ; CS = 0x0200 - Offset(RelocatedStart) + lea di, [bp+si] ; DI = 0x0600 + Offset(RelocatedStart) + lea si, [bx+si] ; BX = 0x7C00 + Offset(RelocatedStart) + mov ss, ax ; SS = 0x0000 + mov sp, bx ; SP = 0x7C00 + mov es,ax ; ES = 0x0000 + mov ds,ax ; DS = 0x0000 + push ax ; PUSH 0x0000 + push di ; PUSH 0x0600 + Offset(RelocatedStart) + cld ; Clear the direction flag + rep movsb ; Copy 0x0200 bytes from 0x7C00 to 0x0600 + retf ; JMP 0x0000:0x0600 + Offset(RelocatedStart) + +; **************************************************************************** +; Code relocated to 0x0000:0x0600 +; **************************************************************************** + +RelocatedStart: +; **************************************************************************** +; Get Driver Parameters to 0x0000:0x7BFC +; **************************************************************************** + + xor ax,ax ; AX = 0 + mov ss,ax ; SS = 0 + add ax,1000h + mov ds,ax + + mov sp,07c00h ; SP = 0x7c00 + mov bp,sp ; BP = 0x7c00 + + mov ah,8 ; AH = 8 - Get Drive Parameters Function + mov byte ptr [bp+PhysicalDrive],dl ; BBS defines that BIOS would pass the booting driver number to the loader through DL + int 13h ; Get Drive Parameters + xor ax,ax ; AX = 0 + mov al,dh ; AL = DH + inc al ; MaxHead = AL + 1 + push ax ; 0000:7bfe = MaxHead + mov al,cl ; AL = CL + and al,03fh ; MaxSector = AL & 0x3f + push ax ; 0000:7bfc = MaxSector + +; **************************************************************************** +; Read Target DBR from hard disk to 0x0000:0x7C00 +; **************************************************************************** + + xor ax, ax + mov al, byte ptr [bp+MbrPartitionIndicator] ; AX = MbrPartitionIndex + cmp al, 0ffh ; 0xFF means do legacy MBR boot + jnz EfiDbr +LegacyMbr: + mov eax, 00000600h ; Assume LegacyMBR is backuped in Sector 6 + jmp StartReadTo7C00 ; EAX = Header/Sector/Tracker/Zero + +EfiDbr: + cmp al, 4 ; MbrPartitionIndex should < 4 + jae BadDbr + shl ax, 4 ; AX = MBREntrySize * Index + add ax, 1beh ; AX = MBREntryOffset + mov di, ax ; DI = MBREntryOffset + + ; Here we don't use the C/H/S information provided by Partition table + ; but calculate C/H/S from LBA ourselves + ; Ci: Cylinder number + ; Hi: Header number + ; Si: Sector number + mov eax, dword ptr es:[bp + di + 8] ; Start LBA + mov edx, eax + shr edx, 16 ; DX:AX = Start LBA + ; = Ci * (H * S) + Hi * S + (Si - 1) + + ; Calculate C/H/S according to LBA + mov bp, 7bfah + div word ptr [bp+2] ; AX = Hi + H*Ci + ; DX = Si - 1 + inc dx ; DX = Si + push dx ; 0000:7bfa = Si <---- + xor dx, dx ; DX:AX = Hi + H*Ci + div word ptr [bp+4] ; AX = Ci <---- + ; DX = Hi <---- + +StartReadTo7C00: + + mov cl, byte ptr [bp] ; Si + mov ch, al ; Ci[0-7] + or cl, ah ; Ci[8,9] + mov bx, 7c00h ; ES:BX = 0000:7C00h + mov ah, 2h ; Function 02h + mov al, 1 ; 1 Sector + mov dh, dl ; Hi + mov bp, 0600h + mov dl, byte ptr [bp + PhysicalDrive] ; Drive number + int 13h + jc BadDbr + + + +; **************************************************************************** +; Transfer control to BootSector - Jump to 0x0000:0x7C00 +; **************************************************************************** + xor ax, ax + push ax ; PUSH 0x0000 - Segment + mov di, 07c00h + push di ; PUSH 0x7C00 - Offset + retf ; JMP 0x0000:0x7C00 + +; **************************************************************************** +; ERROR Condition: +; **************************************************************************** + +BadDbr: + push ax + mov ax, 0b800h + mov es, ax + mov ax, 060h + mov ds, ax + lea si, cs:[ErrorString] + mov di, 320 + pop ax + call A2C + mov [si+16], ah + mov [si+18], al + mov cx, 10 + rep movsw +Halt: + jmp Halt + +StartString: + db 'M', 0ch, 'B', 0ch, 'R', 0ch, ' ', 0ch, 'S', 0ch, 't', 0ch, 'a', 0ch, 'r', 0ch, 't', 0ch, '!', 0ch +ErrorString: + db 'M', 0ch, 'B', 0ch, 'R', 0ch, ' ', 0ch, 'E', 0ch, 'r', 0ch, 'r', 0ch, ':', 0ch, '?', 0ch, '?', 0ch + +; **************************************************************************** +; A2C - convert Ascii code stored in AH to character stored in AX +; **************************************************************************** +A2C: + mov al, ah + shr ah, 4 + and al, 0Fh + add ah, '0' + add al, '0' + + cmp ah, '9' + jle @f + add ah, 7 +@@: + + cmp al, '9' + jle @f + add al, 7 +@@: + ret + + +; **************************************************************************** +; PhysicalDrive - Used to indicate which disk to be boot +; Can be patched by tool +; **************************************************************************** + org 01B6h +PhysicalDrive db 80h + +; **************************************************************************** +; MbrPartitionIndicator - Used to indicate which MBR partition to be boot +; Can be patched by tool +; OxFF means boot to legacy MBR. (LBA OFFSET 6) +; **************************************************************************** + org 01B7h +MbrPartitionIndicator db 0 + +; **************************************************************************** +; Unique MBR signature +; **************************************************************************** + org 01B8h + db 'DUET' + +; **************************************************************************** +; Unknown +; **************************************************************************** + org 01BCh + dw 0 + +; **************************************************************************** +; MBR Entry - To be patched +; **************************************************************************** + org 01BEh + dd 0, 0, 0, 0 + org 01CEh + dd 0, 0, 0, 0 + org 01DEh + dd 0, 0, 0, 0 + org 01EEh + dd 0, 0, 0, 0 + +; **************************************************************************** +; Sector Signature +; **************************************************************************** + + org 01FEh +SectorSignature: + dw 0aa55h ; Boot Sector Signature + + end + diff --git a/DuetPkg/BootSector/bootsect.asm b/DuetPkg/BootSector/bootsect.asm new file mode 100644 index 0000000000..972e36e8a1 --- /dev/null +++ b/DuetPkg/BootSector/bootsect.asm @@ -0,0 +1,288 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright 2006 - 2007, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* bootsect.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + + .model small + .stack + .486p + .code + +FAT_DIRECTORY_ENTRY_SIZE EQU 020h +FAT_DIRECTORY_ENTRY_SHIFT EQU 5 +BLOCK_SIZE EQU 0200h +BLOCK_MASK EQU 01ffh +BLOCK_SHIFT EQU 9 + ; "EFILDR_____" +LOADER_FILENAME_PART1 EQU 04c494645h ; "EFIL" +LOADER_FILENAME_PART2 EQU 020205244h ; "DR__" +LOADER_FILENAME_PART3 EQU 020202020h ; "____" + + org 0h +Ia32Jump: + jmp BootSectorEntryPoint ; JMP inst - 3 bytes + nop + +OemId db "INTEL " ; OemId - 8 bytes +; BPB data below will be fixed by tool +SectorSize dw 0 ; Sector Size - 16 bits +SectorsPerCluster db 0 ; Sector Per Cluster - 8 bits +ReservedSectors dw 0 ; Reserved Sectors - 16 bits +NoFats db 0 ; Number of FATs - 8 bits +RootEntries dw 0 ; Root Entries - 16 bits +Sectors dw 0 ; Number of Sectors - 16 bits +Media db 0 ; Media - 8 bits - ignored +SectorsPerFat dw 0 ; Sectors Per FAT - 16 bits +SectorsPerTrack dw 0 ; Sectors Per Track - 16 bits - ignored +Heads dw 0 ; Heads - 16 bits - ignored +HiddenSectors dd 0 ; Hidden Sectors - 32 bits - ignored +LargeSectors dd 0 ; Large Sectors - 32 bits +PhysicalDrive db 0 ; PhysicalDriveNumber - 8 bits - ignored +CurrentHead db 0 ; Current Head - 8 bits +Signature db 0 ; Signature - 8 bits - ignored +Id db " " ; Id - 4 bytes +FatLabel db " " ; Label - 11 bytes +SystemId db "FAT12 " ; SystemId - 8 bytes + +BootSectorEntryPoint: + ASSUME ds:@code + ASSUME ss:@code + +; **************************************************************************** +; Start Print +; **************************************************************************** + lea si, cs:[StartString] + call PrintString + +; **************************************************************************** +; Print over +; **************************************************************************** + + mov ax,cs ; ax = 0 + mov ss,ax ; ss = 0 + add ax,1000h + mov ds,ax + + mov sp,07c00h ; sp = 0x7c00 + mov bp,sp ; bp = 0x7c00 + + mov ah,8 ; ah = 8 - Get Drive Parameters Function + mov byte ptr [bp+PhysicalDrive],dl ; BBS defines that BIOS would pass the booting driver number to the loader through DL + int 13h ; Get Drive Parameters + xor ax,ax ; ax = 0 + mov al,dh ; al = dh + inc al ; MaxHead = al + 1 + push ax ; 0000:7bfe = MaxHead + mov al,cl ; al = cl + and al,03fh ; MaxSector = al & 0x3f + push ax ; 0000:7bfc = MaxSector + + cmp word ptr [bp+SectorSignature],0aa55h ; Verify Boot Sector Signature + jne BadBootSector + mov cx,word ptr [bp+RootEntries] ; cx = RootEntries + shl cx,FAT_DIRECTORY_ENTRY_SHIFT ; cx = cx * 32 = cx * sizeof(FAT_DIRECTORY_ENTRY) = Size of Root Directory in bytes + mov bx,cx ; bx = size of the Root Directory in bytes + and bx,BLOCK_MASK ; See if it is an even number of sectors long + jne BadBootSector ; If is isn't, then the boot sector is bad. + mov bx,cx ; bx = size of the Root Directory in bytes + shr bx,BLOCK_SHIFT ; bx = size of Root Directory in sectors + mov al,byte ptr [bp+NoFats] ; al = NoFats + xor ah,ah ; ah = 0 ==> ax = NoFats + mul word ptr [bp+SectorsPerFat] ; ax = NoFats * SectorsPerFat + add ax,word ptr [bp+ReservedSectors] ; ax = NoFats * SectorsPerFat + ReservedSectors = RootLBA + push ds + pop es + xor di,di ; Store directory in es:di = 1000:0000 + call ReadBlocks ; Read entire Root Directory + add ax,bx ; ax = NoFats * SectorsPerFat + ReservedSectors + RootDirSectors = FirstClusterLBA (FirstDataSector) + mov word ptr [bp],ax ; Save FirstClusterLBA (FirstDataSector) for later use + + ; dx - variable storage (initial value is 0) + ; bx - loader (initial value is 0) + xor dx, dx + xor bx, bx + +FindEFILDR: + cmp dword ptr [di],LOADER_FILENAME_PART1 ; Compare to "EFIL" + jne FindVARSTORE + cmp dword ptr [di+4],LOADER_FILENAME_PART2 + jne FindVARSTORE + cmp dword ptr [di+7],LOADER_FILENAME_PART3 + jne FindVARSTORE + mov bx, word ptr [di+26] ; bx = Start Cluster for EFILDR <---------------------------------- + test dx, dx + je FindNext ; Efivar.bin is not loaded + jmp FoundAll + +FindVARSTORE: + ; if the file is not loader file, see if it's "EFIVAR BIN" + cmp dword ptr [di], 056494645h ; Compare to "EFIV" + jne FindNext + cmp dword ptr [di+4], 020205241h ; Compare to "AR " + jne FindNext + cmp dword ptr [di+7], 04e494220h ; Compare to " BIN" + jne FindNext + mov dx, di ; dx = Offset of Start Cluster for Efivar.bin <--------------------- + add dx, 26 + test bx, bx + je FindNext ; Efildr is not loaded + jmp FoundAll + +FindNext: + ; go to next find + add di,FAT_DIRECTORY_ENTRY_SIZE ; Increment di + sub cx,FAT_DIRECTORY_ENTRY_SIZE ; Decrement cx + ; TODO: jump to FindVarStore if ... + jne FindEFILDR + jmp NotFoundAll + +FoundAll: +FoundEFILDR: + mov cx,bx ; cx = Start Cluster for EFILDR <---------------------------------- + mov ax,cs ; Destination = 2000:0000 + add ax,2000h + mov es,ax + xor di,di +ReadFirstClusterOfEFILDR: + mov ax,cx ; ax = StartCluster + sub ax,2 ; ax = StartCluster - 2 + xor bh,bh + mov bl,byte ptr [bp+SectorsPerCluster] ; bx = SectorsPerCluster + push dx + mul bx + pop dx ; ax = (StartCluster - 2) * SectorsPerCluster + add ax, word ptr [bp] ; ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster + xor bh,bh + mov bl,byte ptr [bp+SectorsPerCluster] ; bx = Number of Sectors in a cluster + push es + call ReadBlocks + pop ax +JumpIntoFirstSectorOfEFILDR: + mov word ptr [bp+JumpSegment],ax +JumpFarInstruction: + db 0eah +JumpOffset: + dw 0000h +JumpSegment: + dw 2000h + + +PrintString: + mov ax,0b800h + mov es,ax + mov ax, 07c0h + mov ds, ax + mov cx, 7 + mov di, 160 + rep movsw + ret +; **************************************************************************** +; ReadBlocks - Reads a set of blocks from a block device +; +; AX = Start LBA +; BX = Number of Blocks to Read +; ES:DI = Buffer to store sectors read from disk +; **************************************************************************** + +; cx = Blocks +; bx = NumberOfBlocks +; si = StartLBA + +ReadBlocks: + pusha + add eax,dword ptr [bp+LBAOffsetForBootSector] ; Add LBAOffsetForBootSector to Start LBA + add eax,dword ptr [bp+HiddenSectors] ; Add HiddenSectors to Start LBA + mov esi,eax ; esi = Start LBA + mov cx,bx ; cx = Number of blocks to read +ReadCylinderLoop: + mov bp,07bfch ; bp = 0x7bfc + mov eax,esi ; eax = Start LBA + xor edx,edx ; edx = 0 + movzx ebx,word ptr [bp] ; bx = MaxSector + div ebx ; ax = StartLBA / MaxSector + inc dx ; dx = (StartLBA % MaxSector) + 1 + sub bx,dx ; bx = MaxSector - Sector + inc bx ; bx = MaxSector - Sector + 1 + cmp cx,bx ; Compare (Blocks) to (MaxSector - Sector + 1) + jg LimitTransfer + mov bx,cx ; bx = Blocks +LimitTransfer: + push cx + mov cl,dl ; cl = (StartLBA % MaxSector) + 1 = Sector + xor dx,dx ; dx = 0 + div word ptr [bp+2] ; ax = ax / (MaxHead + 1) = Cylinder + ; dx = ax % (MaxHead + 1) = Head + + push bx ; Save number of blocks to transfer + mov dh,dl ; dh = Head + mov bp,07c00h ; bp = 0x7c00 + mov dl,byte ptr [bp+PhysicalDrive] ; dl = Drive Number + mov ch,al ; ch = Cylinder + mov al,bl ; al = Blocks + mov ah,2 ; ah = Function 2 + mov bx,di ; es:bx = Buffer address + int 013h + jc DiskError + pop bx + pop cx + movzx ebx,bx + add esi,ebx ; StartLBA = StartLBA + NumberOfBlocks + sub cx,bx ; Blocks = Blocks - NumberOfBlocks + mov ax,es + shl bx,(BLOCK_SHIFT-4) + add ax,bx + mov es,ax ; es:di = es:di + NumberOfBlocks*BLOCK_SIZE + cmp cx,0 + jne ReadCylinderLoop + popa + ret + +; **************************************************************************** +; ERROR Condition: +; **************************************************************************** +NotFoundAll: + ; if we found EFILDR, continue + test bx,bx + jne FoundEFILDR +BadBootSector: +DiskError: + lea si, cs:[ErrorString] + call PrintString +Halt: + jmp Halt + +StartString: + db 'B', 0ch, 'S', 0ch, 't', 0ch, 'a', 0ch, 'r', 0ch, 't', 0ch, '!', 0ch +ErrorString: + db 'B', 0ch, 'E', 0ch, 'r', 0ch, 'r', 0ch, 'o', 0ch, 'r', 0ch, '!', 0ch + +; **************************************************************************** +; LBA Offset for BootSector, need patched by tool for HD boot. +; **************************************************************************** + + org 01fah +LBAOffsetForBootSector: + dd 0h + +; **************************************************************************** +; Sector Signature +; **************************************************************************** + + org 01feh +SectorSignature: + dw 0aa55h ; Boot Sector Signature + + end + diff --git a/DuetPkg/BootSector/bs16.asm b/DuetPkg/BootSector/bs16.asm new file mode 100644 index 0000000000..41040269cd --- /dev/null +++ b/DuetPkg/BootSector/bs16.asm @@ -0,0 +1,288 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright 2006 - 2007, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* bs16.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + + .model small + .stack + .486p + .code + +FAT_DIRECTORY_ENTRY_SIZE EQU 020h +FAT_DIRECTORY_ENTRY_SHIFT EQU 5 +BLOCK_SIZE EQU 0200h +BLOCK_MASK EQU 01ffh +BLOCK_SHIFT EQU 9 + ; "EFILDR_____" +LOADER_FILENAME_PART1 EQU 04c494645h ; "EFIL" +LOADER_FILENAME_PART2 EQU 036315244h ; "DR16" +LOADER_FILENAME_PART3 EQU 020202036h ; "6___" + + org 0h +Ia32Jump: + jmp BootSectorEntryPoint ; JMP inst - 3 bytes + nop + +OemId db "INTEL " ; OemId - 8 bytes +; BPB data below will be fixed by tool +SectorSize dw 0 ; Sector Size - 16 bits +SectorsPerCluster db 0 ; Sector Per Cluster - 8 bits +ReservedSectors dw 0 ; Reserved Sectors - 16 bits +NoFats db 0 ; Number of FATs - 8 bits +RootEntries dw 0 ; Root Entries - 16 bits +Sectors dw 0 ; Number of Sectors - 16 bits +Media db 0 ; Media - 8 bits - ignored +SectorsPerFat dw 0 ; Sectors Per FAT - 16 bits +SectorsPerTrack dw 0 ; Sectors Per Track - 16 bits - ignored +Heads dw 0 ; Heads - 16 bits - ignored +HiddenSectors dd 0 ; Hidden Sectors - 32 bits - ignored +LargeSectors dd 0 ; Large Sectors - 32 bits +PhysicalDrive db 0 ; PhysicalDriveNumber - 8 bits - ignored +CurrentHead db 0 ; Current Head - 8 bits +Signature db 0 ; Signature - 8 bits - ignored +Id db " " ; Id - 4 bytes +FatLabel db " " ; Label - 11 bytes +SystemId db "FAT16 " ; SystemId - 8 bytes + +BootSectorEntryPoint: + ASSUME ds:@code + ASSUME ss:@code + +; **************************************************************************** +; Start Print +; **************************************************************************** + lea si, cs:[StartString] + call PrintString + +; **************************************************************************** +; Print over +; **************************************************************************** + + mov ax,cs ; ax = 0 + mov ss,ax ; ss = 0 + add ax,1000h + mov ds,ax + + mov sp,07c00h ; sp = 0x7c00 + mov bp,sp ; bp = 0x7c00 + + mov ah,8 ; ah = 8 - Get Drive Parameters Function + mov byte ptr [bp+PhysicalDrive],dl ; BBS defines that BIOS would pass the booting driver number to the loader through DL + int 13h ; Get Drive Parameters + xor ax,ax ; ax = 0 + mov al,dh ; al = dh + inc al ; MaxHead = al + 1 + push ax ; 0000:7bfe = MaxHead + mov al,cl ; al = cl + and al,03fh ; MaxSector = al & 0x3f + push ax ; 0000:7bfc = MaxSector + + cmp word ptr [bp+SectorSignature],0aa55h ; Verify Boot Sector Signature + jne BadBootSector + mov cx,word ptr [bp+RootEntries] ; cx = RootEntries + shl cx,FAT_DIRECTORY_ENTRY_SHIFT ; cx = cx * 32 = cx * sizeof(FAT_DIRECTORY_ENTRY) = Size of Root Directory in bytes + mov bx,cx ; bx = size of the Root Directory in bytes + and bx,BLOCK_MASK ; See if it is an even number of sectors long + jne BadBootSector ; If is isn't, then the boot sector is bad. + mov bx,cx ; bx = size of the Root Directory in bytes + shr bx,BLOCK_SHIFT ; bx = size of Root Directory in sectors + mov al,byte ptr [bp+NoFats] ; al = NoFats + xor ah,ah ; ah = 0 ==> ax = NoFats + mul word ptr [bp+SectorsPerFat] ; ax = NoFats * SectorsPerFat + add ax,word ptr [bp+ReservedSectors] ; ax = NoFats * SectorsPerFat + ReservedSectors = RootLBA + push ds + pop es + xor di,di ; Store directory in es:di = 1000:0000 + call ReadBlocks ; Read entire Root Directory + add ax,bx ; ax = NoFats * SectorsPerFat + ReservedSectors + RootDirSectors = FirstClusterLBA (FirstDataSector) + mov word ptr [bp],ax ; Save FirstClusterLBA (FirstDataSector) for later use + + ; dx - variable storage (initial value is 0) + ; bx - loader (initial value is 0) + xor dx, dx + xor bx, bx + +FindEFILDR: + cmp dword ptr [di],LOADER_FILENAME_PART1 ; Compare to "EFIL" + jne FindVARSTORE + cmp dword ptr [di+4],LOADER_FILENAME_PART2 + jne FindVARSTORE + cmp dword ptr [di+7],LOADER_FILENAME_PART3 + jne FindVARSTORE + mov bx, word ptr [di+26] ; bx = Start Cluster for EFILDR <---------------------------------- + test dx, dx + je FindNext ; Efivar.bin is not loaded + jmp FoundAll + +FindVARSTORE: + ; if the file is not loader file, see if it's "EFIVAR BIN" + cmp dword ptr [di], 056494645h ; Compare to "EFIV" + jne FindNext + cmp dword ptr [di+4], 020205241h ; Compare to "AR " + jne FindNext + cmp dword ptr [di+7], 04e494220h ; Compare to " BIN" + jne FindNext + mov dx, di ; dx = Offset of Start Cluster for Efivar.bin <--------------------- + add dx, 26 + test bx, bx + je FindNext ; Efildr is not loaded + jmp FoundAll + +FindNext: + ; go to next find + add di,FAT_DIRECTORY_ENTRY_SIZE ; Increment di + sub cx,FAT_DIRECTORY_ENTRY_SIZE ; Decrement cx + ; TODO: jump to FindVarStore if ... + jne FindEFILDR + jmp NotFoundAll + +FoundAll: +FoundEFILDR: + mov cx,bx ; cx = Start Cluster for EFILDR <---------------------------------- + mov ax,cs ; Destination = 2000:0000 + add ax,2000h + mov es,ax + xor di,di +ReadFirstClusterOfEFILDR: + mov ax,cx ; ax = StartCluster + sub ax,2 ; ax = StartCluster - 2 + xor bh,bh + mov bl,byte ptr [bp+SectorsPerCluster] ; bx = SectorsPerCluster + push dx + mul bx + pop dx ; ax = (StartCluster - 2) * SectorsPerCluster + add ax, word ptr [bp] ; ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster + xor bh,bh + mov bl,byte ptr [bp+SectorsPerCluster] ; bx = Number of Sectors in a cluster + push es + call ReadBlocks + pop ax +JumpIntoFirstSectorOfEFILDR: + mov word ptr [bp+JumpSegment],ax +JumpFarInstruction: + db 0eah +JumpOffset: + dw 0000h +JumpSegment: + dw 2000h + + +PrintString: + mov ax,0b800h + mov es,ax + mov ax, 07c0h + mov ds, ax + mov cx, 7 + mov di, 160 + rep movsw + ret +; **************************************************************************** +; ReadBlocks - Reads a set of blocks from a block device +; +; AX = Start LBA +; BX = Number of Blocks to Read +; ES:DI = Buffer to store sectors read from disk +; **************************************************************************** + +; cx = Blocks +; bx = NumberOfBlocks +; si = StartLBA + +ReadBlocks: + pusha + add eax,dword ptr [bp+LBAOffsetForBootSector] ; Add LBAOffsetForBootSector to Start LBA + add eax,dword ptr [bp+HiddenSectors] ; Add HiddenSectors to Start LBA + mov esi,eax ; esi = Start LBA + mov cx,bx ; cx = Number of blocks to read +ReadCylinderLoop: + mov bp,07bfch ; bp = 0x7bfc + mov eax,esi ; eax = Start LBA + xor edx,edx ; edx = 0 + movzx ebx,word ptr [bp] ; bx = MaxSector + div ebx ; ax = StartLBA / MaxSector + inc dx ; dx = (StartLBA % MaxSector) + 1 + sub bx,dx ; bx = MaxSector - Sector + inc bx ; bx = MaxSector - Sector + 1 + cmp cx,bx ; Compare (Blocks) to (MaxSector - Sector + 1) + jg LimitTransfer + mov bx,cx ; bx = Blocks +LimitTransfer: + push cx + mov cl,dl ; cl = (StartLBA % MaxSector) + 1 = Sector + xor dx,dx ; dx = 0 + div word ptr [bp+2] ; ax = ax / (MaxHead + 1) = Cylinder + ; dx = ax % (MaxHead + 1) = Head + + push bx ; Save number of blocks to transfer + mov dh,dl ; dh = Head + mov bp,07c00h ; bp = 0x7c00 + mov dl,byte ptr [bp+PhysicalDrive] ; dl = Drive Number + mov ch,al ; ch = Cylinder + mov al,bl ; al = Blocks + mov ah,2 ; ah = Function 2 + mov bx,di ; es:bx = Buffer address + int 013h + jc DiskError + pop bx + pop cx + movzx ebx,bx + add esi,ebx ; StartLBA = StartLBA + NumberOfBlocks + sub cx,bx ; Blocks = Blocks - NumberOfBlocks + mov ax,es + shl bx,(BLOCK_SHIFT-4) + add ax,bx + mov es,ax ; es:di = es:di + NumberOfBlocks*BLOCK_SIZE + cmp cx,0 + jne ReadCylinderLoop + popa + ret + +; **************************************************************************** +; ERROR Condition: +; **************************************************************************** +NotFoundAll: + ; if we found EFILDR, continue + test bx,bx + jne FoundEFILDR +BadBootSector: +DiskError: + lea si, cs:[ErrorString] + call PrintString +Halt: + jmp Halt + +StartString: + db 'B', 0ch, 'S', 0ch, 't', 0ch, 'a', 0ch, 'r', 0ch, 't', 0ch, '!', 0ch +ErrorString: + db 'B', 0ch, 'E', 0ch, 'r', 0ch, 'r', 0ch, 'o', 0ch, 'r', 0ch, '!', 0ch + +; **************************************************************************** +; LBA Offset for BootSector, need patched by tool for HD boot. +; **************************************************************************** + + org 01fah +LBAOffsetForBootSector: + dd 0h + +; **************************************************************************** +; Sector Signature +; **************************************************************************** + + org 01feh +SectorSignature: + dw 0aa55h ; Boot Sector Signature + + end + diff --git a/DuetPkg/BootSector/bs32.asm b/DuetPkg/BootSector/bs32.asm new file mode 100644 index 0000000000..bc84f83732 --- /dev/null +++ b/DuetPkg/BootSector/bs32.asm @@ -0,0 +1,310 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright 2006 - 2007, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* bs32.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + + .model small + .stack + .486p + .code + +FAT_DIRECTORY_ENTRY_SIZE EQU 020h +FAT_DIRECTORY_ENTRY_SHIFT EQU 5 +BLOCK_SIZE EQU 0200h +BLOCK_MASK EQU 01ffh +BLOCK_SHIFT EQU 9 + ; "EFILDR_____" +LOADER_FILENAME_PART1 EQU 04c494645h ; "EFIL" +LOADER_FILENAME_PART2 EQU 030325244h ; "DR20" +LOADER_FILENAME_PART3 EQU 020202030h ; "0___" + + org 0h +Ia32Jump: + jmp BootSectorEntryPoint ; JMP inst - 3 bytes + nop + +OemId db "INTEL " ; OemId - 8 bytes +; BPB data below will be fixed by tool +SectorSize dw 0 ; Sector Size - 16 bits +SectorsPerCluster db 0 ; Sector Per Cluster - 8 bits +ReservedSectors dw 0 ; Reserved Sectors - 16 bits +NoFats db 0 ; Number of FATs - 8 bits +RootEntries dw 0 ; Root Entries - 16 bits +Sectors dw 0 ; Number of Sectors - 16 bits +Media db 0 ; Media - 8 bits - ignored +SectorsPerFat dw 0 ; Sectors Per FAT - 16 bits +SectorsPerTrack dw 0 ; Sectors Per Track - 16 bits - ignored +Heads dw 0 ; Heads - 16 bits - ignored +HiddenSectors dd 0 ; Hidden Sectors - 32 bits - ignored +LargeSectors dd 0 ; Large Sectors - 32 bits + +;****************************************************************************** +; +;The structure for FAT32 starting at offset 36 of the boot sector. (At this point, +;the BPB/boot sector for FAT12 and FAT16 differs from the BPB/boot sector for FAT32.) +; +;****************************************************************************** + +SectorsPerFat32 dd 0 ; Sectors Per FAT for FAT32 - 4 bytes +ExtFlags dw 0 ; Mirror Flag - 2 bytes +FSVersion dw 0 ; File System Version - 2 bytes +RootCluster dd 0 ; 1st Cluster Number of Root Dir - 4 bytes +FSInfo dw 0 ; Sector Number of FSINFO - 2 bytes +BkBootSector dw 0 ; Sector Number of Bk BootSector - 2 bytes +Reserved db 12 dup(0) ; Reserved Field - 12 bytes +PhysicalDrive db 0 ; Physical Drive Number - 1 byte +Reserved1 db 0 ; Reserved Field - 1 byte +Signature db 0 ; Extended Boot Signature - 1 byte +VolId db " " ; Volume Serial Number - 4 bytes +FatLabel db " " ; Volume Label - 11 bytes +FileSystemType db "FAT32 " ; File System Type - 8 bytes + +BootSectorEntryPoint: + ASSUME ds:@code + ASSUME ss:@code + +; **************************************************************************** +; Start Print +; **************************************************************************** + lea si, cs:[StartString] + call PrintString + +; **************************************************************************** +; Print over +; **************************************************************************** + + mov ax,cs ; ax = 0 + mov ss,ax ; ss = 0 + add ax,1000h + mov ds,ax + + mov sp,07c00h ; sp = 0x7c00 + mov bp,sp ; bp = 0x7c00 + + mov ah,8 ; ah = 8 - Get Drive Parameters Function + mov byte ptr [bp+PhysicalDrive],dl ; BBS defines that BIOS would pass the booting driver number to the loader through DL + int 13h ; Get Drive Parameters + xor ax,ax ; ax = 0 + mov al,dh ; al = dh + inc al ; MaxHead = al + 1 + push ax ; 0000:7bfe = MaxHead + mov al,cl ; al = cl + and al,03fh ; MaxSector = al & 0x3f + push ax ; 0000:7bfc = MaxSector + + cmp word ptr [bp+SectorSignature],0aa55h ; Verify Boot Sector Signature + jne BadBootSector + mov cx,word ptr [bp+RootEntries] ; cx = RootEntries + shl cx,FAT_DIRECTORY_ENTRY_SHIFT ; cx = cx * 32 = cx * sizeof(FAT_DIRECTORY_ENTRY) = Size of Root Directory in bytes + mov bx,cx ; bx = size of the Root Directory in bytes + and bx,BLOCK_MASK ; See if it is an even number of sectors long + jne BadBootSector ; If is isn't, then the boot sector is bad. + mov bx,cx ; bx = size of the Root Directory in bytes + shr bx,BLOCK_SHIFT ; bx = size of Root Directory in sectors + mov al,byte ptr [bp+NoFats] ; al = NoFats + xor ah,ah ; ah = 0 ==> ax = NoFats + mul word ptr [bp+SectorsPerFat32] ; ax = NoFats * SectorsPerFat + add ax,word ptr [bp+ReservedSectors] ; ax = NoFats * SectorsPerFat + ReservedSectors = RootLBA + add ax,bx ; ax = NoFats * SectorsPerFat + ReservedSectors + RootDirSectors = FirstClusterLBA + mov word ptr [bp],ax ; Save FirstClusterLBA for later use + + mov ax,word ptr [bp+RootCluster] ; ax = StartCluster of Root Directory + sub ax,2 ; ax = StartCluster - 2 + xor bh,bh + mov bl,byte ptr [bp+SectorsPerCluster]; bx = SectorsPerCluster + mul bx ; ax = (StartCluster - 2) * SectorsPerCluster + add ax, word ptr [bp] ; ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster + push ds + pop es + xor di,di ; Store directory in es:di = 1000:0000 + call ReadBlocks ; Read StartCluster of Root Directory + + ; dx - variable storage (initial value is 0) + ; bx - loader (initial value is 0) + xor dx, dx + xor bx, bx + +FindEFILDR: + cmp dword ptr [di],LOADER_FILENAME_PART1 ; Compare to "EFIL" + jne FindVARSTORE + cmp dword ptr [di+4],LOADER_FILENAME_PART2 + jne FindVARSTORE + cmp dword ptr [di+7],LOADER_FILENAME_PART3 + jne FindVARSTORE + mov bx, word ptr [di+26] ; bx = Start Cluster for EFILDR <---------------------------------- + test dx, dx + je FindNext ; Efivar.bin is not loaded + jmp FoundAll + +FindVARSTORE: + ; if the file is not loader file, see if it's "EFIVAR BIN" + cmp dword ptr [di], 056494645h ; Compare to "EFIV" + jne FindNext + cmp dword ptr [di+4], 020205241h ; Compare to "AR " + jne FindNext + cmp dword ptr [di+7], 04e494220h ; Compare to " BIN" + jne FindNext + mov dx, di ; dx = Offset of Start Cluster for Efivar.bin <--------------------- + add dx, 26 + test bx, bx + je FindNext ; Efildr is not loaded + jmp FoundAll + +FindNext: + ; go to next find + add di,FAT_DIRECTORY_ENTRY_SIZE ; Increment di + sub cx,FAT_DIRECTORY_ENTRY_SIZE ; Decrement cx + ; TODO: jump to FindVarStore if ... + jne FindEFILDR + jmp NotFoundAll + +FoundAll: +FoundEFILDR: + mov cx,bx ; cx = Start Cluster for EFILDR <---------------------------------- + mov ax,cs ; Destination = 2000:0000 + add ax,2000h + mov es,ax + xor di,di +ReadFirstClusterOfEFILDR: + mov ax,cx ; ax = StartCluster + sub ax,2 ; ax = StartCluster - 2 + xor bh,bh + mov bl,byte ptr [bp+SectorsPerCluster] ; bx = SectorsPerCluster + push dx + mul bx + pop dx ; ax = (StartCluster - 2) * SectorsPerCluster + add ax, word ptr [bp] ; ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster + xor bh,bh + mov bl,byte ptr [bp+SectorsPerCluster] ; bx = Number of Sectors in a cluster + push es + call ReadBlocks + pop ax +JumpIntoFirstSectorOfEFILDR: + mov word ptr [bp+JumpSegment],ax +JumpFarInstruction: + db 0eah +JumpOffset: + dw 0000h +JumpSegment: + dw 2000h + + +PrintString: + mov ax,0b800h + mov es,ax + mov ax, 07c0h + mov ds, ax + mov cx, 7 + mov di, 160 + rep movsw + ret +; **************************************************************************** +; ReadBlocks - Reads a set of blocks from a block device +; +; AX = Start LBA +; BX = Number of Blocks to Read +; ES:DI = Buffer to store sectors read from disk +; **************************************************************************** + +; cx = Blocks +; bx = NumberOfBlocks +; si = StartLBA + +ReadBlocks: + pusha + add eax,dword ptr [bp+LBAOffsetForBootSector] ; Add LBAOffsetForBootSector to Start LBA + add eax,dword ptr [bp+HiddenSectors] ; Add HiddenSectors to Start LBA + mov esi,eax ; esi = Start LBA + mov cx,bx ; cx = Number of blocks to read +ReadCylinderLoop: + mov bp,07bfch ; bp = 0x7bfc + mov eax,esi ; eax = Start LBA + xor edx,edx ; edx = 0 + movzx ebx,word ptr [bp] ; bx = MaxSector + div ebx ; ax = StartLBA / MaxSector + inc dx ; dx = (StartLBA % MaxSector) + 1 + sub bx,dx ; bx = MaxSector - Sector + inc bx ; bx = MaxSector - Sector + 1 + cmp cx,bx ; Compare (Blocks) to (MaxSector - Sector + 1) + jg LimitTransfer + mov bx,cx ; bx = Blocks +LimitTransfer: + push cx + mov cl,dl ; cl = (StartLBA % MaxSector) + 1 = Sector + xor dx,dx ; dx = 0 + div word ptr [bp+2] ; ax = ax / (MaxHead + 1) = Cylinder + ; dx = ax % (MaxHead + 1) = Head + + push bx ; Save number of blocks to transfer + mov dh,dl ; dh = Head + mov bp,07c00h ; bp = 0x7c00 + mov dl,byte ptr [bp+PhysicalDrive] ; dl = Drive Number + mov ch,al ; ch = Cylinder + mov al,bl ; al = Blocks + mov ah,2 ; ah = Function 2 + mov bx,di ; es:bx = Buffer address + int 013h + jc DiskError + pop bx + pop cx + movzx ebx,bx + add esi,ebx ; StartLBA = StartLBA + NumberOfBlocks + sub cx,bx ; Blocks = Blocks - NumberOfBlocks + mov ax,es + shl bx,(BLOCK_SHIFT-4) + add ax,bx + mov es,ax ; es:di = es:di + NumberOfBlocks*BLOCK_SIZE + cmp cx,0 + jne ReadCylinderLoop + popa + ret + +; **************************************************************************** +; ERROR Condition: +; **************************************************************************** +NotFoundAll: + ; if we found EFILDR, continue + test bx,bx + jne FoundEFILDR +BadBootSector: +DiskError: + lea si, cs:[ErrorString] + call PrintString +Halt: + jmp Halt + +StartString: + db 'B', 0ch, 'S', 0ch, 't', 0ch, 'a', 0ch, 'r', 0ch, 't', 0ch, '!', 0ch +ErrorString: + db 'B', 0ch, 'E', 0ch, 'r', 0ch, 'r', 0ch, 'o', 0ch, 'r', 0ch, '!', 0ch + +; **************************************************************************** +; LBA Offset for BootSector, need patched by tool for HD boot. +; **************************************************************************** + + org 01fah +LBAOffsetForBootSector: + dd 0h + +; **************************************************************************** +; Sector Signature +; **************************************************************************** + + org 01feh +SectorSignature: + dw 0aa55h ; Boot Sector Signature + + end + diff --git a/DuetPkg/BootSector/efi32.asm b/DuetPkg/BootSector/efi32.asm new file mode 100644 index 0000000000..d9560221d6 --- /dev/null +++ b/DuetPkg/BootSector/efi32.asm @@ -0,0 +1,581 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright 2006, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* efi32.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Now in 32-bit protected mode. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + .486 + .model flat + .stack + .code + org 21000h + +DEFAULT_HANDLER_SIZE EQU INT1 - INT0 + +JmpCommonIdtEntry macro + ; jmp commonIdtEntry - this must be hand coded to keep the assembler from + ; using a 8 bit reletive jump when the entries are + ; within 255 bytes of the common entry. This must + ; be done to maintain the consistency of the size + ; of entry points... + db 0e9h ; jmp 16 bit relative + dd commonIdtEntry - $ - 4 ; offset to jump to +endm + + +Start: + mov ds,ax + mov es,ax + mov fs,ax + mov gs,ax + mov ss,ax + mov esp,0001ffff0h + + call ClearScreen + + ; Populate IDT with meaningful offsets for exception handlers... + sidt fword ptr [Idtr] ; get fword address of IDT + + mov eax, offset Halt + mov ebx, eax ; use bx to copy 15..0 to descriptors + shr eax, 16 ; use ax to copy 31..16 to descriptors + mov ecx, 78h ; 78h IDT entries to initialize with unique entry points (exceptions) + mov esi, [offset Idtr + 2] + mov edi, [esi] + +@@: ; loop through all IDT entries exception handlers and initialize to default handler + mov word ptr [edi], bx ; write bits 15..0 of offset + mov word ptr [edi+2], 20h ; SYS_CODE_SEL from GDT + mov word ptr [edi+4], 0e00h OR 8000h ; type = 386 interrupt gate, present + mov word ptr [edi+6], ax ; write bits 31..16 of offset + add edi, 8 ; move up to next descriptor + add bx, DEFAULT_HANDLER_SIZE ; move to next entry point + loop @b ; loop back through again until all descriptors are initialized + + ;; at this point edi contains the offset of the descriptor for INT 20 + ;; and bx contains the low 16 bits of the offset of the default handler + ;; so initialize all the rest of the descriptors with these two values... +; mov ecx, 101 ; there are 100 descriptors left (INT 20 (14h) - INT 119 (77h) +;@@: ; loop through all IDT entries exception handlers and initialize to default handler +; mov word ptr [edi], bx ; write bits 15..0 of offset +; mov word ptr [edi+2], 20h ; SYS_CODE_SEL from GDT +; mov word ptr [edi+4], 0e00h OR 8000h ; type = 386 interrupt gate, present +; mov word ptr [edi+6], ax ; write bits 31..16 of offset +; add edi, 8 ; move up to next descriptor +; loop @b ; loop back through again until all descriptors are initialized + + +;; DUMP location of IDT and several of the descriptors +; mov ecx, 8 +; mov eax, [offset Idtr + 2] +; mov eax, [eax] +; mov edi, 0b8000h +; call PrintDword +; mov esi, eax +; mov edi, 0b80a0h +; jmp OuterLoop + +;; +;; just for fun, let's do a software interrupt to see if we correctly land in the exception handler... +; mov eax, 011111111h +; mov ebx, 022222222h +; mov ecx, 033333333h +; mov edx, 044444444h +; mov ebp, 055555555h +; mov esi, 066666666h +; mov edi, 077777777h +; push 011111111h +; push 022222222h +; push 033333333h +; int 119 + + + mov esi,022000h ; esi = 22000 + mov eax,[esi+014h] ; eax = [22014] + add esi,eax ; esi = 22000 + [22014] = Base of EFILDR.C + mov ebp,[esi+03ch] ; ebp = [22000 + [22014] + 3c] = NT Image Header for EFILDR.C + add ebp,esi + mov edi,[ebp+034h] ; edi = [[22000 + [22014] + 3c] + 30] = ImageBase + mov eax,[ebp+028h] ; eax = [[22000 + [22014] + 3c] + 24] = EntryPoint + add eax,edi ; eax = ImageBase + EntryPoint + mov dword ptr [EfiLdrOffset],eax ; Modify far jump instruction for correct entry point + + mov bx,word ptr[ebp+6] ; bx = Number of sections + xor eax,eax + mov ax,word ptr[ebp+014h] ; ax = Optional Header Size + add ebp,eax + add ebp,018h ; ebp = Start of 1st Section + +SectionLoop: + push esi ; Save Base of EFILDR.C + push edi ; Save ImageBase + add esi,[ebp+014h] ; esi = Base of EFILDR.C + PointerToRawData + add edi,[ebp+00ch] ; edi = ImageBase + VirtualAddress + mov ecx,[ebp+010h] ; ecs = SizeOfRawData + + cld + shr ecx,2 + rep movsd + + pop edi ; Restore ImageBase + pop esi ; Restore Base of EFILDR.C + + add bp,028h ; ebp = ebp + 028h = Pointer to next section record + dec bx + cmp bx,0 + jne SectionLoop + + movzx eax, word ptr [Idtr] ; get size of IDT + inc eax + add eax, dword ptr [Idtr + 2] ; add to base of IDT to get location of memory map... + push eax ; push memory map location on stack for call to EFILDR... + + push eax ; push return address (useless, just for stack balance) + db 0b8h +EfiLdrOffset: + dd 000401000h ; Offset of EFILDR +; mov eax, 401000h + push eax + ret + +; db "**** DEFAULT IDT ENTRY ***",0 + align 02h +Halt: +INT0: + push 0h ; push error code place holder on the stack + push 0h + JmpCommonIdtEntry +; db 0e9h ; jmp 16 bit reletive +; dd commonIdtEntry - $ - 4 ; offset to jump to + +INT1: + push 0h ; push error code place holder on the stack + push 1h + JmpCommonIdtEntry + +INT2: + push 0h ; push error code place holder on the stack + push 2h + JmpCommonIdtEntry + +INT3: + push 0h ; push error code place holder on the stack + push 3h + JmpCommonIdtEntry + +INT4: + push 0h ; push error code place holder on the stack + push 4h + JmpCommonIdtEntry + +INT5: + push 0h ; push error code place holder on the stack + push 5h + JmpCommonIdtEntry + +INT6: + push 0h ; push error code place holder on the stack + push 6h + JmpCommonIdtEntry + +INT7: + push 0h ; push error code place holder on the stack + push 7h + JmpCommonIdtEntry + +INT8: +; Double fault causes an error code to be pushed so no phony push necessary + nop + nop + push 8h + JmpCommonIdtEntry + +INT9: + push 0h ; push error code place holder on the stack + push 9h + JmpCommonIdtEntry + +INT10: +; Invalid TSS causes an error code to be pushed so no phony push necessary + nop + nop + push 10 + JmpCommonIdtEntry + +INT11: +; Segment Not Present causes an error code to be pushed so no phony push necessary + nop + nop + push 11 + JmpCommonIdtEntry + +INT12: +; Stack fault causes an error code to be pushed so no phony push necessary + nop + nop + push 12 + JmpCommonIdtEntry + +INT13: +; GP fault causes an error code to be pushed so no phony push necessary + nop + nop + push 13 + JmpCommonIdtEntry + +INT14: +; Page fault causes an error code to be pushed so no phony push necessary + nop + nop + push 14 + JmpCommonIdtEntry + +INT15: + push 0h ; push error code place holder on the stack + push 15 + JmpCommonIdtEntry + +INT16: + push 0h ; push error code place holder on the stack + push 16 + JmpCommonIdtEntry + +INT17: +; Alignment check causes an error code to be pushed so no phony push necessary + nop + nop + push 17 + JmpCommonIdtEntry + +INT18: + push 0h ; push error code place holder on the stack + push 18 + JmpCommonIdtEntry + +INT19: + push 0h ; push error code place holder on the stack + push 19 + JmpCommonIdtEntry + +INTUnknown: +REPEAT (78h - 20) + push 0h ; push error code place holder on the stack +; push xxh ; push vector number + db 06ah + db ( $ - INTUnknown - 3 ) / 9 + 20 ; vector number + JmpCommonIdtEntry +ENDM + +commonIdtEntry: + pushad + mov ebp, esp +;; +;; At this point the stack looks like this: +;; +;; eflags +;; Calling CS +;; Calling EIP +;; Error code or 0 +;; Int num or 0ffh for unknown int num +;; eax +;; ecx +;; edx +;; ebx +;; esp +;; ebp +;; esi +;; edi <------- ESP, EBP +;; + + call ClearScreen + mov esi, offset String1 + call PrintString + mov eax, [ebp + 32] ;; move Int number into EAX + cmp eax, 19 + ja PrintDefaultString +PrintExceptionString: + shl eax, 2 ;; multiply by 4 to get offset from StringTable to actual string address + add eax, offset StringTable + mov esi, [eax] + jmp PrintTheString +PrintDefaultString: + mov esi, offset IntUnknownString + ; patch Int number + mov edx, eax + call A2C + mov [esi + 1], al + mov eax, edx + shr eax, 4 + call A2C + mov [esi], al +PrintTheString: + call PrintString + mov esi, offset String2 + call PrintString + mov eax, [ebp+44] ; CS + call PrintDword + mov al, ':' + mov byte ptr [edi], al + add edi, 2 + mov eax, [ebp+40] ; EIP + call PrintDword + mov esi, offset String3 + call PrintString + + mov edi, 0b8140h + + mov esi, offset StringEax ; eax + call PrintString + mov eax, [ebp+28] + call PrintDword + + mov esi, offset StringEbx ; ebx + call PrintString + mov eax, [ebp+16] + call PrintDword + + mov esi, offset StringEcx ; ecx + call PrintString + mov eax, [ebp+24] + call PrintDword + + mov esi, offset StringEdx ; edx + call PrintString + mov eax, [ebp+20] + call PrintDword + + mov esi, offset StringEcode ; error code + call PrintString + mov eax, [ebp+36] + call PrintDword + + mov edi, 0b81e0h + + mov esi, offset StringEsp ; esp + call PrintString + mov eax, [ebp+12] + call PrintDword + + mov esi, offset StringEbp ; ebp + call PrintString + mov eax, [ebp+8] + call PrintDword + + mov esi, offset StringEsi ; esi + call PrintString + mov eax, [ebp+4] + call PrintDword + + mov esi, offset StringEdi ; edi + call PrintString + mov eax, [ebp] + call PrintDword + + mov esi, offset StringEflags ; eflags + call PrintString + mov eax, [ebp+48] + call PrintDword + + mov edi, 0b8320h + + mov esi, ebp + add esi, 52 + mov ecx, 8 + + +OuterLoop: + push ecx + mov ecx, 8 + mov edx, edi + +InnerLoop: + mov eax, [esi] + call PrintDword + add esi, 4 + mov al, ' ' + mov [edi], al + add edi, 2 + loop InnerLoop + + pop ecx + add edx, 0a0h + mov edi, edx + loop OuterLoop + + + mov edi, 0b8960h + + mov eax, [ebp+40] ; EIP + sub eax, 32 * 4 + mov esi, eax ; esi = eip - 32 DWORD linear (total 64 DWORD) + + mov ecx, 8 + +OuterLoop1: + push ecx + mov ecx, 8 + mov edx, edi + +InnerLoop1: + mov eax, [esi] + call PrintDword + add esi, 4 + mov al, ' ' + mov [edi], al + add edi, 2 + loop InnerLoop1 + + pop ecx + add edx, 0a0h + mov edi, edx + loop OuterLoop1 + + + +; wbinvd ; Ken: this intruction does not support in early than 486 arch +@@: + jmp @b +; +; return +; + mov esp, ebp + popad + add esp, 8 ; error code and INT number + + iretd + + +PrintString: + push eax +@@: + mov al, byte ptr [esi] + cmp al, 0 + je @f + mov byte ptr [edi], al + inc esi + add edi, 2 + jmp @b +@@: + pop eax + ret + +;; EAX contains dword to print +;; EDI contains memory location (screen location) to print it to +PrintDword: + push ecx + push ebx + push eax + + mov ecx, 8 +looptop: + rol eax, 4 + mov bl, al + and bl, 0fh + add bl, '0' + cmp bl, '9' + jle @f + add bl, 7 +@@: + mov byte ptr [edi], bl + add edi, 2 + loop looptop + wbinvd + + pop eax + pop ebx + pop ecx + ret + +ClearScreen: + push eax + push ecx + + mov al, ' ' + mov ah, 0ch + mov edi, 0b8000h + mov ecx, 80 * 24 +@@: + mov word ptr [edi], ax + add edi, 2 + loop @b + mov edi, 0b8000h + + pop ecx + pop eax + + ret + +A2C: + and al, 0fh + add al, '0' + cmp al, '9' + jle @f + add al, 7 +@@: + ret + +String1 db "*** INT ",0 + +Int0String db "00h Divide by 0 -",0 +Int1String db "01h Debug exception -",0 +Int2String db "02h NMI -",0 +Int3String db "03h Breakpoint -",0 +Int4String db "04h Overflow -",0 +Int5String db "05h Bound -",0 +Int6String db "06h Invalid opcode -",0 +Int7String db "07h Device not available -",0 +Int8String db "08h Double fault -",0 +Int9String db "09h Coprocessor seg overrun (reserved) -",0 +Int10String db "0Ah Invalid TSS -",0 +Int11String db "0Bh Segment not present -",0 +Int12String db "0Ch Stack fault -",0 +Int13String db "0Dh General protection fault -",0 +Int14String db "0Eh Page fault -",0 +Int15String db "0Fh (Intel reserved) -",0 +Int16String db "10h Floating point error -",0 +Int17String db "11h Alignment check -",0 +Int18String db "12h Machine check -",0 +Int19String db "13h SIMD Floating-Point Exception -",0 +IntUnknownString db "??h Unknown interrupt -",0 + +StringTable dd offset Int0String, offset Int1String, offset Int2String, offset Int3String, + offset Int4String, offset Int5String, offset Int6String, offset Int7String, + offset Int8String, offset Int9String, offset Int10String, offset Int11String, + offset Int12String, offset Int13String, offset Int14String, offset Int15String, + offset Int16String, offset Int17String, offset Int18String, offset Int19String + +String2 db " HALT!! *** (",0 +String3 db ")",0 +StringEax db "EAX=",0 +StringEbx db " EBX=",0 +StringEcx db " ECX=",0 +StringEdx db " EDX=",0 +StringEcode db " ECODE=",0 +StringEsp db "ESP=",0 +StringEbp db " EBP=",0 +StringEsi db " ESI=",0 +StringEdi db " EDI=",0 +StringEflags db " EFLAGS=",0 + +Idtr df 0 + + org 21ffeh +BlockSignature: + dw 0aa55h + + end diff --git a/DuetPkg/BootSector/efi64.asm b/DuetPkg/BootSector/efi64.asm new file mode 100644 index 0000000000..bbf8fee35a --- /dev/null +++ b/DuetPkg/BootSector/efi64.asm @@ -0,0 +1,787 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright 2006, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* efi64.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Now in 64-bit long mode. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + .486 + .model flat + .stack + .code + org 21000h + +DEFAULT_HANDLER_SIZE EQU INT1 - INT0 + +JmpCommonIdtEntry macro + ; jmp commonIdtEntry - this must be hand coded to keep the assembler from + ; using a 8 bit reletive jump when the entries are + ; within 255 bytes of the common entry. This must + ; be done to maintain the consistency of the size + ; of entry points... + db 0e9h ; jmp 16 bit reletive + dd commonIdtEntry - $ - 4 ; offset to jump to +endm + + +Start: + + mov esp,0001fffe8h ; make final stack aligned + + ; set OSFXSR and OSXMMEXCPT because some code will use XMM register + db 0fh + db 20h + db 0e0h +; mov rax, cr4 + bts eax, 9 + bts eax, 0ah + db 0fh + db 22h + db 0e0h +; mov cr4, rax + + call ClearScreen + + ; Populate IDT with meaningful offsets for exception handlers... + mov eax, offset Idtr + sidt fword ptr [eax] ; get fword address of IDT + + mov eax, offset Halt + mov ebx, eax ; use bx to copy 15..0 to descriptors + shr eax, 16 ; use ax to copy 31..16 to descriptors + ; 63..32 of descriptors is 0 + mov ecx, 78h ; 78h IDT entries to initialize with unique entry points (exceptions) + mov esi, [offset Idtr + 2] + mov edi, [esi] + +@@: ; loop through all IDT entries exception handlers and initialize to default handler + mov word ptr [edi], bx ; write bits 15..0 of offset + mov word ptr [edi+2], 38h ; SYS_CODE64_SEL from GDT + mov word ptr [edi+4], 0e00h OR 8000h ; type = 386 interrupt gate, present + mov word ptr [edi+6], ax ; write bits 31..16 of offset + mov dword ptr [edi+8], 0 ; write bits 63..32 of offset + add edi, 16 ; move up to next descriptor + add bx, DEFAULT_HANDLER_SIZE ; move to next entry point + loop @b ; loop back through again until all descriptors are initialized + + ;; at this point edi contains the offset of the descriptor for INT 20 + ;; and bx contains the low 16 bits of the offset of the default handler + ;; so initialize all the rest of the descriptors with these two values... +; mov ecx, 101 ; there are 100 descriptors left (INT 20 (14h) - INT 119 (77h) +;@@: ; loop through all IDT entries exception handlers and initialize to default handler +; mov word ptr [edi], bx ; write bits 15..0 of offset +; mov word ptr [edi+2], 38h ; SYS_CODE64_SEL from GDT +; mov word ptr [edi+4], 0e00h OR 8000h ; type = 386 interrupt gate, present +; mov word ptr [edi+6], ax ; write bits 31..16 of offset +; mov dword ptr [edi+8], 0 ; write bits 63..32 of offset +; add edi, 16 ; move up to next descriptor +; loop @b ; loop back through again until all descriptors are initialized + + +;; DUMP location of IDT and several of the descriptors +; mov ecx, 8 +; mov eax, [offset Idtr + 2] +; mov eax, [eax] +; mov edi, 0b8000h +; call PrintQword +; mov esi, eax +; mov edi, 0b80a0h +; jmp OuterLoop + +;; +;; just for fun, let's do a software interrupt to see if we correctly land in the exception handler... +; mov eax, 011111111h +; mov ebx, 022222222h +; mov ecx, 033333333h +; mov edx, 044444444h +; mov ebp, 055555555h +; mov esi, 066666666h +; mov edi, 077777777h +; push 011111111h +; push 022222222h +; push 033333333h +; int 119 + + mov esi,022000h ; esi = 22000 + mov eax,[esi+014h] ; eax = [22014] + add esi,eax ; esi = 22000 + [22014] = Base of EFILDR.C + mov ebp,[esi+03ch] ; ebp = [22000 + [22014] + 3c] = NT Image Header for EFILDR.C + add ebp,esi + mov edi,[ebp+030h] ; edi = [[22000 + [22014] + 3c] + 2c] = ImageBase (63..32 is zero, ignore) + mov eax,[ebp+028h] ; eax = [[22000 + [22014] + 3c] + 24] = EntryPoint + add eax,edi ; eax = ImageBase + EntryPoint + mov ebx, offset EfiLdrOffset + mov dword ptr [ebx],eax ; Modify far jump instruction for correct entry point + + mov bx,word ptr[ebp+6] ; bx = Number of sections + xor eax,eax + mov ax,word ptr[ebp+014h] ; ax = Optional Header Size + add ebp,eax + add ebp,018h ; ebp = Start of 1st Section + +SectionLoop: + push esi ; Save Base of EFILDR.C + push edi ; Save ImageBase + add esi,[ebp+014h] ; esi = Base of EFILDR.C + PointerToRawData + add edi,[ebp+00ch] ; edi = ImageBase + VirtualAddress + mov ecx,[ebp+010h] ; ecs = SizeOfRawData + + cld + shr ecx,2 + rep movsd + + pop edi ; Restore ImageBase + pop esi ; Restore Base of EFILDR.C + + add bp,028h ; ebp = ebp + 028h = Pointer to next section record + db 66h + db 0ffh + db 0cbh +; dec bx + cmp bx,0 + jne SectionLoop + + mov edx, offset Idtr + movzx eax, word ptr [edx] ; get size of IDT + db 0ffh + db 0c0h +; inc eax + add eax, dword ptr [edx + 2] ; add to base of IDT to get location of memory map... + xor ecx, ecx + mov ecx, eax ; put argument to RCX + + db 48h + db 0c7h + db 0c0h +EfiLdrOffset: + dd 000401000h ; Offset of EFILDR +; mov rax, 401000h + db 50h +; push rax + +; ret + db 0c3h + +; db "**** DEFAULT IDT ENTRY ***",0 + align 02h +Halt: +INT0: + push 0h ; push error code place holder on the stack + push 0h + JmpCommonIdtEntry +; db 0e9h ; jmp 16 bit reletive +; dd commonIdtEntry - $ - 4 ; offset to jump to + +INT1: + push 0h ; push error code place holder on the stack + push 1h + JmpCommonIdtEntry + +INT2: + push 0h ; push error code place holder on the stack + push 2h + JmpCommonIdtEntry + +INT3: + push 0h ; push error code place holder on the stack + push 3h + JmpCommonIdtEntry + +INT4: + push 0h ; push error code place holder on the stack + push 4h + JmpCommonIdtEntry + +INT5: + push 0h ; push error code place holder on the stack + push 5h + JmpCommonIdtEntry + +INT6: + push 0h ; push error code place holder on the stack + push 6h + JmpCommonIdtEntry + +INT7: + push 0h ; push error code place holder on the stack + push 7h + JmpCommonIdtEntry + +INT8: +; Double fault causes an error code to be pushed so no phony push necessary + nop + nop + push 8h + JmpCommonIdtEntry + +INT9: + push 0h ; push error code place holder on the stack + push 9h + JmpCommonIdtEntry + +INT10: +; Invalid TSS causes an error code to be pushed so no phony push necessary + nop + nop + push 10 + JmpCommonIdtEntry + +INT11: +; Segment Not Present causes an error code to be pushed so no phony push necessary + nop + nop + push 11 + JmpCommonIdtEntry + +INT12: +; Stack fault causes an error code to be pushed so no phony push necessary + nop + nop + push 12 + JmpCommonIdtEntry + +INT13: +; GP fault causes an error code to be pushed so no phony push necessary + nop + nop + push 13 + JmpCommonIdtEntry + +INT14: +; Page fault causes an error code to be pushed so no phony push necessary + nop + nop + push 14 + JmpCommonIdtEntry + +INT15: + push 0h ; push error code place holder on the stack + push 15 + JmpCommonIdtEntry + +INT16: + push 0h ; push error code place holder on the stack + push 16 + JmpCommonIdtEntry + +INT17: +; Alignment check causes an error code to be pushed so no phony push necessary + nop + nop + push 17 + JmpCommonIdtEntry + +INT18: + push 0h ; push error code place holder on the stack + push 18 + JmpCommonIdtEntry + +INT19: + push 0h ; push error code place holder on the stack + push 19 + JmpCommonIdtEntry + +INTUnknown: +REPEAT (78h - 20) + push 0h ; push error code place holder on the stack +; push xxh ; push vector number + db 06ah + db ( $ - INTUnknown - 3 ) / 9 + 20 ; vector number + JmpCommonIdtEntry +ENDM + +commonIdtEntry: + push eax + push ecx + push edx + push ebx + push esp + push ebp + push esi + push edi + db 41h + db 50h +; push r8 + db 41h + db 51h +; push r9 + db 41h + db 52h +; push r10 + db 41h + db 53h +; push r11 + db 41h + db 54h +; push r12 + db 41h + db 55h +; push r13 + db 41h + db 56h +; push r14 + db 41h + db 57h +; push r15 + db 48h + mov ebp, esp +; mov rbp, rsp + +;; +;; At this point the stack looks like this: +;; +;; Calling SS +;; Calling RSP +;; rflags +;; Calling CS +;; Calling RIP +;; Error code or 0 +;; Int num or 0ffh for unknown int num +;; rax +;; rcx +;; rdx +;; rbx +;; rsp +;; rbp +;; rsi +;; rdi +;; r8 +;; r9 +;; r10 +;; r11 +;; r12 +;; r13 +;; r14 +;; r15 <------- RSP, RBP +;; + + call ClearScreen + mov esi, offset String1 + call PrintString + db 48h + mov eax, [ebp + 16*8] ;; move Int number into RAX + db 48h + cmp eax, 18 + ja PrintDefaultString +PrintExceptionString: + shl eax, 3 ;; multiply by 8 to get offset from StringTable to actual string address + add eax, offset StringTable + mov esi, [eax] + jmp PrintTheString +PrintDefaultString: + mov esi, offset IntUnknownString + ; patch Int number + mov edx, eax + call A2C + mov [esi + 1], al + mov eax, edx + shr eax, 4 + call A2C + mov [esi], al +PrintTheString: + call PrintString + mov esi, offset String2 + call PrintString + db 48h + mov eax, [ebp+19*8] ; CS + call PrintQword + mov al, ':' + mov byte ptr [edi], al + add edi, 2 + db 48h + mov eax, [ebp+18*8] ; RIP + call PrintQword + mov esi, offset String3 + call PrintString + + mov edi, 0b8140h + + mov esi, offset StringRax ; rax + call PrintString + db 48h + mov eax, [ebp+15*8] + call PrintQword + + mov esi, offset StringRcx ; rcx + call PrintString + db 48h + mov eax, [ebp+14*8] + call PrintQword + + mov esi, offset StringRdx ; rdx + call PrintString + db 48h + mov eax, [ebp+13*8] + call PrintQword + + mov edi, 0b81e0h + + mov esi, offset StringRbx ; rbx + call PrintString + db 48h + mov eax, [ebp+12*8] + call PrintQword + + mov esi, offset StringRsp ; rsp + call PrintString + db 48h + mov eax, [ebp+21*8] + call PrintQword + + mov esi, offset StringRbp ; rbp + call PrintString + db 48h + mov eax, [ebp+10*8] + call PrintQword + + mov edi, 0b8280h + + mov esi, offset StringRsi ; rsi + call PrintString + db 48h + mov eax, [ebp+9*8] + call PrintQword + + mov esi, offset StringRdi ; rdi + call PrintString + db 48h + mov eax, [ebp+8*8] + call PrintQword + + mov esi, offset StringEcode ; error code + call PrintString + db 48h + mov eax, [ebp+17*8] + call PrintQword + + mov edi, 0b8320h + + mov esi, offset StringR8 ; r8 + call PrintString + db 48h + mov eax, [ebp+7*8] + call PrintQword + + mov esi, offset StringR9 ; r9 + call PrintString + db 48h + mov eax, [ebp+6*8] + call PrintQword + + mov esi, offset StringR10 ; r10 + call PrintString + db 48h + mov eax, [ebp+5*8] + call PrintQword + + mov edi, 0b83c0h + + mov esi, offset StringR11 ; r11 + call PrintString + db 48h + mov eax, [ebp+4*8] + call PrintQword + + mov esi, offset StringR12 ; r12 + call PrintString + db 48h + mov eax, [ebp+3*8] + call PrintQword + + mov esi, offset StringR13 ; r13 + call PrintString + db 48h + mov eax, [ebp+2*8] + call PrintQword + + mov edi, 0b8460h + + mov esi, offset StringR14 ; r14 + call PrintString + db 48h + mov eax, [ebp+1*8] + call PrintQword + + mov esi, offset StringR15 ; r15 + call PrintString + db 48h + mov eax, [ebp+0*8] + call PrintQword + + mov esi, offset StringSs ; ss + call PrintString + db 48h + mov eax, [ebp+22*8] + call PrintQword + + mov edi, 0b8500h + + mov esi, offset StringRflags ; rflags + call PrintString + db 48h + mov eax, [ebp+20*8] + call PrintQword + + mov edi, 0b8640h + + mov esi, ebp + add esi, 23*8 + mov ecx, 4 + + +OuterLoop: + push ecx + mov ecx, 4 + db 48h + mov edx, edi + +InnerLoop: + db 48h + mov eax, [esi] + call PrintQword + add esi, 8 + mov al, ' ' + mov [edi], al + add edi, 2 + loop InnerLoop + + pop ecx + add edx, 0a0h + mov edi, edx + loop OuterLoop + + + mov edi, 0b8960h + + db 48h + mov eax, [ebp+18*8] ; RIP + sub eax, 8 * 8 + db 48h + mov esi, eax ; esi = rip - 8 QWORD linear (total 16 QWORD) + + mov ecx, 4 + +OuterLoop1: + push ecx + mov ecx, 4 + mov edx, edi + +InnerLoop1: + db 48h + mov eax, [esi] + call PrintQword + add esi, 8 + mov al, ' ' + mov [edi], al + add edi, 2 + loop InnerLoop1 + + pop ecx + add edx, 0a0h + mov edi, edx + loop OuterLoop1 + + + + wbinvd +@@: + jmp @b + +; +; return +; + mov esp, ebp +; mov rsp, rbp + db 41h + db 5fh +; pop r15 + db 41h + db 5eh +; pop r14 + db 41h + db 5dh +; pop r13 + db 41h + db 5ch +; pop r12 + db 41h + db 5bh +; pop r11 + db 41h + db 5ah +; pop r10 + db 41h + db 59h +; pop r9 + db 41h + db 58h +; pop r8 + pop edi + pop esi + pop ebp + pop eax ; esp + pop ebx + pop edx + pop ecx + pop eax + + db 48h + db 83h + db 0c4h + db 10h +; add esp, 16 ; error code and INT number + + db 48h + db 0cfh +; iretq + +PrintString: + push eax +@@: + mov al, byte ptr [esi] + cmp al, 0 + je @f + mov byte ptr [edi], al + db 0ffh + db 0c6h +; inc esi + add edi, 2 + jmp @b +@@: + pop eax + ret + +;; RAX contains qword to print +;; RDI contains memory location (screen location) to print it to +PrintQword: + push ecx + push ebx + push eax + + db 48h + db 0c7h + db 0c1h + dd 16 +; mov rcx, 16 +looptop: + db 48h + rol eax, 4 + mov bl, al + and bl, 0fh + add bl, '0' + cmp bl, '9' + jle @f + add bl, 7 +@@: + mov byte ptr [edi], bl + add edi, 2 + loop looptop + wbinvd + + pop eax + pop ebx + pop ecx + ret + +ClearScreen: + push eax + push ecx + + mov al, ' ' + mov ah, 0ch + mov edi, 0b8000h + mov ecx, 80 * 24 +@@: + mov word ptr [edi], ax + add edi, 2 + loop @b + mov edi, 0b8000h + + pop ecx + pop eax + + ret + +A2C: + and al, 0fh + add al, '0' + cmp al, '9' + jle @f + add al, 7 +@@: + ret + +String1 db "*** INT ",0 + +Int0String db "00h Divide by 0 -",0 +Int1String db "01h Debug exception -",0 +Int2String db "02h NMI -",0 +Int3String db "03h Breakpoint -",0 +Int4String db "04h Overflow -",0 +Int5String db "05h Bound -",0 +Int6String db "06h Invalid opcode -",0 +Int7String db "07h Device not available -",0 +Int8String db "08h Double fault -",0 +Int9String db "09h Coprocessor seg overrun (reserved) -",0 +Int10String db "0Ah Invalid TSS -",0 +Int11String db "0Bh Segment not present -",0 +Int12String db "0Ch Stack fault -",0 +Int13String db "0Dh General protection fault -",0 +Int14String db "0Eh Page fault -",0 +Int15String db "0Fh (Intel reserved) -",0 +Int16String db "10h Floating point error -",0 +Int17String db "11h Alignment check -",0 +Int18String db "12h Machine check -",0 +Int19String db "13h SIMD Floating-Point Exception -",0 +IntUnknownString db "??h Unknown interrupt -",0 + +StringTable dq offset Int0String, offset Int1String, offset Int2String, offset Int3String, + offset Int4String, offset Int5String, offset Int6String, offset Int7String, + offset Int8String, offset Int9String, offset Int10String, offset Int11String, + offset Int12String, offset Int13String, offset Int14String, offset Int15String, + offset Int16String, offset Int17String, offset Int18String, offset Int19String + +String2 db " HALT!! *** (",0 +String3 db ")",0 +StringRax db "RAX=",0 +StringRcx db " RCX=",0 +StringRdx db " RDX=",0 +StringRbx db "RBX=",0 +StringRsp db " RSP=",0 +StringRbp db " RBP=",0 +StringRsi db "RSI=",0 +StringRdi db " RDI=",0 +StringEcode db " ECODE=",0 +StringR8 db "R8 =",0 +StringR9 db " R9 =",0 +StringR10 db " R10=",0 +StringR11 db "R11=",0 +StringR12 db " R12=",0 +StringR13 db " R13=",0 +StringR14 db "R14=",0 +StringR15 db " R15=",0 +StringSs db " SS =",0 +StringRflags db "RFLAGS=",0 + +Idtr df 0 + df 0 + + org 21ffeh +BlockSignature: + dw 0aa55h + + end diff --git a/DuetPkg/BootSector/st16_64.asm b/DuetPkg/BootSector/st16_64.asm new file mode 100644 index 0000000000..b2df0eb042 --- /dev/null +++ b/DuetPkg/BootSector/st16_64.asm @@ -0,0 +1,1140 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright 2006 - 2007, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* st16_64.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + + .model small + .stack + .486p + .code + +FAT_DIRECTORY_ENTRY_SIZE EQU 020h +FAT_DIRECTORY_ENTRY_SHIFT EQU 5 +BLOCK_SIZE EQU 0200h +BLOCK_MASK EQU 01ffh +BLOCK_SHIFT EQU 9 + + org 0h +Ia32Jump: + jmp BootSectorEntryPoint ; JMP inst - 3 bytes + nop + +OemId db "INTEL " ; OemId - 8 bytes + +SectorSize dw 0 ; Sector Size - 16 bits +SectorsPerCluster db 0 ; Sector Per Cluster - 8 bits +ReservedSectors dw 0 ; Reserved Sectors - 16 bits +NoFats db 0 ; Number of FATs - 8 bits +RootEntries dw 0 ; Root Entries - 16 bits +Sectors dw 0 ; Number of Sectors - 16 bits +Media db 0 ; Media - 8 bits - ignored +SectorsPerFat dw 0 ; Sectors Per FAT - 16 bits +SectorsPerTrack dw 0 ; Sectors Per Track - 16 bits - ignored +Heads dw 0 ; Heads - 16 bits - ignored +HiddenSectors dd 0 ; Hidden Sectors - 32 bits - ignored +LargeSectors dd 0 ; Large Sectors - 32 bits +PhysicalDrive db 0 ; PhysicalDriveNumber - 8 bits - ignored +CurrentHead db 0 ; Current Head - 8 bits +Signature db 0 ; Signature - 8 bits - ignored +VolId db " " ; Volume Serial Number- 4 bytes +FatLabel db " " ; Label - 11 bytes +SystemId db "FAT16 " ; SystemId - 8 bytes + +BootSectorEntryPoint: + ASSUME ds:@code + ASSUME ss:@code + ; ds = 1000, es = 2000 + x (size of first cluster >> 4) + ; cx = Start Cluster of EfiLdr + ; dx = Start Cluster of Efivar.bin + +; Re use the BPB data stored in Boot Sector + mov bp,07c00h + + push cx +; Read Efivar.bin +; 1000:dx = DirectoryEntry of Efivar.bin -> BS.com has filled already + mov ax,01900h + mov es,ax + test dx,dx + jnz CheckVarStoreSize + + mov al,1 +NoVarStore: + push es +; Set the 5th byte start @ 0:19000 to non-zero indicating we should init var store header in DxeIpl + mov byte ptr es:[4],al + jmp SaveVolumeId + +CheckVarStoreSize: + mov di,dx + cmp dword ptr ds:[di+2], 04000h + mov al,2 + jne NoVarStore + +LoadVarStore: + mov al,0 + mov byte ptr es:[4],al + mov cx,word ptr[di] +; ES:DI = 1500:0 + xor di,di + push es + mov ax,01500h + mov es,ax + call ReadFile +SaveVolumeId: + pop es + mov ax,word ptr [bp+VolId] + mov word ptr es:[0],ax ; Save Volume Id to 0:19000. we will find the correct volume according to this VolumeId + mov ax,word ptr [bp+VolId+2] + mov word ptr es:[2],ax + +; Read Efildr + pop cx +; cx = Start Cluster of Efildr -> BS.com has filled already +; ES:DI = 2000:0, first cluster will be read again + xor di,di ; di = 0 + mov ax,02000h + mov es,ax + call ReadFile + mov ax,cs + mov word ptr cs:[JumpSegment],ax + +CheckEm64T: + mov eax, 080000001h +; cpuid + dw 0A20Fh + bt edx, 29 + jc CheckEm64TPass + push cs + pop ds + lea si, [Em64String] + mov cx, 18 + jmp PrintStringAndHalt +CheckEm64TPass: +JumpFarInstruction: + db 0eah +JumpOffset: + dw 0200h +JumpSegment: + dw 2000h + + + +; **************************************************************************** +; ReadFile +; +; Arguments: +; CX = Start Cluster of File +; ES:DI = Buffer to store file content read from disk +; +; Return: +; (ES << 4 + DI) = end of file content Buffer +; +; **************************************************************************** +ReadFile: +; si = NumberOfClusters +; cx = ClusterNumber +; dx = CachedFatSectorNumber +; ds:0000 = CacheFatSectorBuffer +; es:di = Buffer to load file +; bx = NextClusterNumber + pusha + mov si,1 ; NumberOfClusters = 1 + push cx ; Push Start Cluster onto stack + mov dx,0fffh ; CachedFatSectorNumber = 0xfff +FatChainLoop: + mov ax,cx ; ax = ClusterNumber + and ax,0fff8h ; ax = ax & 0xfff8 + cmp ax,0fff8h ; See if this is the last cluster + je FoundLastCluster ; Jump if last cluster found + mov ax,cx ; ax = ClusterNumber + shl ax,1 ; FatOffset = ClusterNumber * 2 + push si ; Save si + mov si,ax ; si = FatOffset + shr ax,BLOCK_SHIFT ; ax = FatOffset >> BLOCK_SHIFT + add ax,word ptr [bp+ReservedSectors] ; ax = FatSectorNumber = ReservedSectors + (FatOffset >> BLOCK_OFFSET) + and si,BLOCK_MASK ; si = FatOffset & BLOCK_MASK + cmp ax,dx ; Compare FatSectorNumber to CachedFatSectorNumber + je SkipFatRead + mov bx,2 + push es + push ds + pop es + call ReadBlocks ; Read 2 blocks starting at AX storing at ES:DI + pop es + mov dx,ax ; CachedFatSectorNumber = FatSectorNumber +SkipFatRead: + mov bx,word ptr [si] ; bx = NextClusterNumber + mov ax,cx ; ax = ClusterNumber + pop si ; Restore si + dec bx ; bx = NextClusterNumber - 1 + cmp bx,cx ; See if (NextClusterNumber-1)==ClusterNumber + jne ReadClusters + inc bx ; bx = NextClusterNumber + inc si ; NumberOfClusters++ + mov cx,bx ; ClusterNumber = NextClusterNumber + jmp FatChainLoop +ReadClusters: + inc bx + pop ax ; ax = StartCluster + push bx ; StartCluster = NextClusterNumber + mov cx,bx ; ClusterNumber = NextClusterNumber + sub ax,2 ; ax = StartCluster - 2 + xor bh,bh + mov bl,byte ptr [bp+SectorsPerCluster] ; bx = SectorsPerCluster + mul bx ; ax = (StartCluster - 2) * SectorsPerCluster + add ax, word ptr [bp] ; ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster + push ax ; save start sector + mov ax,si ; ax = NumberOfClusters + mul bx ; ax = NumberOfClusters * SectorsPerCluster + mov bx,ax ; bx = Number of Sectors + pop ax ; ax = Start Sector + call ReadBlocks + mov si,1 ; NumberOfClusters = 1 + jmp FatChainLoop +FoundLastCluster: + pop cx + popa + ret + + +; **************************************************************************** +; ReadBlocks - Reads a set of blocks from a block device +; +; AX = Start LBA +; BX = Number of Blocks to Read +; ES:DI = Buffer to store sectors read from disk +; **************************************************************************** + +; cx = Blocks +; bx = NumberOfBlocks +; si = StartLBA + +ReadBlocks: + pusha + add eax,dword ptr [bp+LBAOffsetForBootSector] ; Add LBAOffsetForBootSector to Start LBA + add eax,dword ptr [bp+HiddenSectors] ; Add HiddenSectors to Start LBA + mov esi,eax ; esi = Start LBA + mov cx,bx ; cx = Number of blocks to read +ReadCylinderLoop: + mov bp,07bfch ; bp = 0x7bfc + mov eax,esi ; eax = Start LBA + xor edx,edx ; edx = 0 + movzx ebx,word ptr [bp] ; bx = MaxSector + div ebx ; ax = StartLBA / MaxSector + inc dx ; dx = (StartLBA % MaxSector) + 1 + + mov bx,word ptr [bp] ; bx = MaxSector + sub bx,dx ; bx = MaxSector - Sector + inc bx ; bx = MaxSector - Sector + 1 + cmp cx,bx ; Compare (Blocks) to (MaxSector - Sector + 1) + jg LimitTransfer + mov bx,cx ; bx = Blocks +LimitTransfer: + push ax ; save ax + mov ax,es ; ax = es + shr ax,(BLOCK_SHIFT-4) ; ax = Number of blocks into mem system + and ax,07fh ; ax = Number of blocks into current seg + add ax,bx ; ax = End Block number of transfer + cmp ax,080h ; See if it crosses a 64K boundry + jle NotCrossing64KBoundry ; Branch if not crossing 64K boundry + sub ax,080h ; ax = Number of blocks past 64K boundry + sub bx,ax ; Decrease transfer size by block overage +NotCrossing64KBoundry: + pop ax ; restore ax + + push cx + mov cl,dl ; cl = (StartLBA % MaxSector) + 1 = Sector + xor dx,dx ; dx = 0 + div word ptr [bp+2] ; ax = ax / (MaxHead + 1) = Cylinder + ; dx = ax % (MaxHead + 1) = Head + + push bx ; Save number of blocks to transfer + mov dh,dl ; dh = Head + mov bp,07c00h ; bp = 0x7c00 + mov dl,byte ptr [bp+PhysicalDrive] ; dl = Drive Number + mov ch,al ; ch = Cylinder + mov al,bl ; al = Blocks + mov ah,2 ; ah = Function 2 + mov bx,di ; es:bx = Buffer address + int 013h + jc DiskError + pop bx + pop cx + movzx ebx,bx + add esi,ebx ; StartLBA = StartLBA + NumberOfBlocks + sub cx,bx ; Blocks = Blocks - NumberOfBlocks + mov ax,es + shl bx,(BLOCK_SHIFT-4) + add ax,bx + mov es,ax ; es:di = es:di + NumberOfBlocks*BLOCK_SIZE + cmp cx,0 + jne ReadCylinderLoop + popa + ret + +DiskError: + push cs + pop ds + lea si, [ErrorString] + mov cx, 7 + jmp PrintStringAndHalt + +PrintStringAndHalt: + mov ax,0b800h + mov es,ax + mov di,160 + rep movsw +Halt: + jmp Halt + +ErrorString: + db 'S', 0ch, 'E', 0ch, 'r', 0ch, 'r', 0ch, 'o', 0ch, 'r', 0ch, '!', 0ch + + org 01fah +LBAOffsetForBootSector: + dd 0h + + org 01feh + dw 0aa55h + +;****************************************************************************** +;****************************************************************************** +;****************************************************************************** + +DELAY_PORT equ 0edh ; Port to use for 1uS delay +KBD_CONTROL_PORT equ 060h ; 8042 control port +KBD_STATUS_PORT equ 064h ; 8042 status port +WRITE_DATA_PORT_CMD equ 0d1h ; 8042 command to write the data port +ENABLE_A20_CMD equ 0dfh ; 8042 command to enable A20 + + org 200h + jmp start +Em64String: + db 'E', 0ch, 'm', 0ch, '6', 0ch, '4', 0ch, 'T', 0ch, ' ', 0ch, 'U', 0ch, 'n', 0ch, 's', 0ch, 'u', 0ch, 'p', 0ch, 'p', 0ch, 'o', 0ch, 'r', 0ch, 't', 0ch, 'e', 0ch, 'd', 0ch, '!', 0ch + +start: + mov ax,cs + mov ds,ax + mov es,ax + mov ss,ax + mov sp,MyStack + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[160],'a' +; mov ax,cs +; mov es,ax + + mov ebx,0 + lea edi,MemoryMap +MemMapLoop: + mov eax,0e820h + mov ecx,20 + mov edx,'SMAP' + int 15h + jc MemMapDone + add edi,20 + cmp ebx,0 + je MemMapDone + jmp MemMapLoop +MemMapDone: + lea eax,MemoryMap + sub edi,eax ; Get the address of the memory map + mov dword ptr [MemoryMapSize],edi ; Save the size of the memory map + + xor ebx,ebx + mov bx,cs ; BX=segment + shl ebx,4 ; BX="linear" address of segment base + lea eax,[GDT_BASE + ebx] ; EAX=PHYSICAL address of gdt + mov dword ptr [gdtr + 2],eax ; Put address of gdt into the gdtr + lea eax,[IDT_BASE + ebx] ; EAX=PHYSICAL address of idt + mov dword ptr [idtr + 2],eax ; Put address of idt into the idtr + lea edx,[MemoryMapSize + ebx] ; Physical base address of the memory map + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[162],'b' +; mov ax,cs +; mov es,ax + +; +; Enable A20 Gate +; + + mov ax,2401h ; Enable A20 Gate + int 15h + jnc A20GateEnabled ; Jump if it suceeded + +; +; If INT 15 Function 2401 is not supported, then attempt to Enable A20 manually. +; + + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + jnz Timeout8042 ; Jump if the 8042 timed out + out DELAY_PORT,ax ; Delay 1 uS + mov al,WRITE_DATA_PORT_CMD ; 8042 cmd to write output port + out KBD_STATUS_PORT,al ; Send command to the 8042 + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + jnz Timeout8042 ; Jump if the 8042 timed out + mov al,ENABLE_A20_CMD ; gate address bit 20 on + out KBD_CONTROL_PORT,al ; Send command to thre 8042 + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + mov cx,25 ; Delay 25 uS for the command to complete on the 8042 +Delay25uS: + out DELAY_PORT,ax ; Delay 1 uS + loop Delay25uS +Timeout8042: + + +A20GateEnabled: + +; +; DISABLE INTERRUPTS - Entering Protected Mode +; + + cli + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[164],'c' +; mov ax,cs +; mov es,ax + + lea eax, OffsetIn32BitProtectedMode + add eax, 20000h + 6h + mov dword ptr[OffsetIn32BitProtectedMode], eax + + lea eax, OffsetInLongMode + add eax, 20000h + 6h + mov dword ptr[OffsetInLongMode], eax + + ; + ; load GDT + ; + db 66h + lgdt fword ptr [gdtr] + + ; + ; Enable Protect Mode (set CR0.PE=1) + ; + mov eax, cr0 ; Read CR0. + or eax, 1h ; Set PE=1 + mov cr0, eax ; Write CR0. + db 066h + db 0eah ; jmp far 16:32 +OffsetIn32BitProtectedMode: + dd 00000000h ; offset $+8 (In32BitProtectedMode) + dw 10h ; selector (flat CS) +In32BitProtectedMode: + +; +; Entering Long Mode +; + db 66h + mov ax, 8 + mov ds, ax + mov es, ax + mov ss, ax + + ; + ; Enable the 64-bit page-translation-table entries by + ; setting CR4.PAE=1 (this is _required_ before activating + ; long mode). Paging is not enabled until after long mode + ; is enabled. + ; + db 0fh + db 20h + db 0e0h +; mov eax, cr4 + bts eax, 5 + db 0fh + db 22h + db 0e0h +; mov cr4, eax + + ; + ; This is the Trapolean Page Tables that are guarenteed + ; under 4GB. + ; + ; Address Map: + ; 10000 ~ 12000 - efildr (loaded) + ; 20000 ~ 21000 - start64.com + ; 21000 ~ 22000 - efi64.com + ; 22000 ~ 90000 - efildr + ; 90000 ~ 96000 - 4G pagetable (will be reload later) + ; + db 0b8h + dd 90000h +; mov eax, 90000h + mov cr3, eax + + ; + ; Enable long mode (set EFER.LME=1). + ; + db 0b9h + dd 0c0000080h +; mov ecx, 0c0000080h ; EFER MSR number. + db 0fh + db 32h +; rdmsr ; Read EFER. + db 0fh + db 0bah + db 0e8h + db 08h +; bts eax, 8 ; Set LME=1. + db 0fh + db 30h +; wrmsr ; Write EFER. + + ; + ; Enable paging to activate long mode (set CR0.PG=1) + ; + mov eax, cr0 ; Read CR0. + db 0fh + db 0bah + db 0e8h + db 01fh +; bts eax, 31 ; Set PG=1. + mov cr0, eax ; Write CR0. + jmp GoToLongMode +GoToLongMode: + + db 067h + db 0eah ; Far Jump $+9:Selector to reload CS +OffsetInLongMode: + dd 00000000 ; $+9 Offset is ensuing instruction boundary + dw 038h ; Selector is our code selector, 38h + +InLongMode: + db 66h + mov ax, 30h + mov ds, ax + + db 66h + mov ax, 18h + mov es, ax + mov ss, ax + mov ds, ax + + db 0bdh + dd 400000h +; mov ebp,000400000h ; Destination of EFILDR32 + db 0bbh + dd 70000h +; mov ebx,000070000h ; Length of copy + + ; + ; load idt later + ; + db 48h + db 33h + db 0c0h +; xor rax, rax + db 66h + mov ax, offset idtr + db 48h + db 05h + dd 20000h +; add rax, 20000h + + db 0fh + db 01h + db 18h +; lidt fword ptr [rax] + + db 48h + db 0c7h + db 0c0h + dd 21000h +; mov rax, 21000h + db 50h +; push rax + +; ret + db 0c3h + +Empty8042InputBuffer: + mov cx,0 +Empty8042Loop: + out DELAY_PORT,ax ; Delay 1us + in al,KBD_STATUS_PORT ; Read the 8042 Status Port + and al,02h ; Check the Input Buffer Full Flag + loopnz Empty8042Loop ; Loop until the input buffer is empty or a timout of 65536 uS + ret + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; data +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + align 02h + +gdtr dw GDT_END - GDT_BASE - 1 ; GDT limit + dd 0 ; (GDT base gets set above) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; global descriptor table (GDT) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + align 02h + +public GDT_BASE +GDT_BASE: +; null descriptor +NULL_SEL equ $-GDT_BASE ; Selector [0x0] + dw 0 ; limit 15:0 + dw 0 ; base 15:0 + db 0 ; base 23:16 + db 0 ; type + db 0 ; limit 19:16, flags + db 0 ; base 31:24 + +; linear data segment descriptor +LINEAR_SEL equ $-GDT_BASE ; Selector [0x8] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; linear code segment descriptor +LINEAR_CODE_SEL equ $-GDT_BASE ; Selector [0x10] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system data segment descriptor +SYS_DATA_SEL equ $-GDT_BASE ; Selector [0x18] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system code segment descriptor +SYS_CODE_SEL equ $-GDT_BASE ; Selector [0x20] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; spare segment descriptor +SPARE3_SEL equ $-GDT_BASE ; Selector [0x28] + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +; +; system data segment descriptor +; +SYS_DATA64_SEL equ $-GDT_BASE ; Selector [0x30] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; P | DPL [1..2] | 1 | 1 | C | R | A + db 0CFh ; G | D | L | AVL | Segment [19..16] + db 0 + +; +; system code segment descriptor +; +SYS_CODE64_SEL equ $-GDT_BASE ; Selector [0x38] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; P | DPL [1..2] | 1 | 1 | C | R | A + db 0AFh ; G | D | L | AVL | Segment [19..16] + db 0 + +; spare segment descriptor +SPARE4_SEL equ $-GDT_BASE ; Selector [0x40] + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +GDT_END: + + align 02h + + + +idtr dw IDT_END - IDT_BASE - 1 ; IDT limit + dq 0 ; (IDT base gets set above) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; interrupt descriptor table (IDT) +; +; Note: The hardware IRQ's specified in this table are the normal PC/AT IRQ +; mappings. This implementation only uses the system timer and all other +; IRQs will remain masked. The descriptors for vectors 33+ are provided +; for convenience. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;idt_tag db "IDT",0 + align 02h + +public IDT_BASE +IDT_BASE: +; divide by zero (INT 0) +DIV_ZERO_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; debug exception (INT 1) +DEBUG_EXCEPT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; NMI (INT 2) +NMI_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; soft breakpoint (INT 3) +BREAKPOINT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; overflow (INT 4) +OVERFLOW_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; bounds check (INT 5) +BOUNDS_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; invalid opcode (INT 6) +INVALID_OPCODE_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; device not available (INT 7) +DEV_NOT_AVAIL_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; double fault (INT 8) +DOUBLE_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; Coprocessor segment overrun - reserved (INT 9) +RSVD_INTR_SEL1 equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; invalid TSS (INT 0ah) +INVALID_TSS_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; segment not present (INT 0bh) +SEG_NOT_PRESENT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; stack fault (INT 0ch) +STACK_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; general protection (INT 0dh) +GP_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; page fault (INT 0eh) +PAGE_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; Intel reserved - do not use (INT 0fh) +RSVD_INTR_SEL2 equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; floating point error (INT 10h) +FLT_POINT_ERR_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; alignment check (INT 11h) +ALIGNMENT_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; machine check (INT 12h) +MACHINE_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; SIMD floating-point exception (INT 13h) +SIMD_EXCEPTION_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; 85 unspecified descriptors, First 12 of them are reserved, the rest are avail + db (85 * 16) dup(0) + +; IRQ 0 (System timer) - (INT 68h) +IRQ0_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 1 (8042 Keyboard controller) - (INT 69h) +IRQ1_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; Reserved - IRQ 2 redirect (IRQ 2) - DO NOT USE!!! - (INT 6ah) +IRQ2_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 3 (COM 2) - (INT 6bh) +IRQ3_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 4 (COM 1) - (INT 6ch) +IRQ4_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 5 (LPT 2) - (INT 6dh) +IRQ5_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 6 (Floppy controller) - (INT 6eh) +IRQ6_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 7 (LPT 1) - (INT 6fh) +IRQ7_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 8 (RTC Alarm) - (INT 70h) +IRQ8_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 9 - (INT 71h) +IRQ9_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 10 - (INT 72h) +IRQ10_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 11 - (INT 73h) +IRQ11_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 12 (PS/2 mouse) - (INT 74h) +IRQ12_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 13 (Floating point error) - (INT 75h) +IRQ13_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 14 (Secondary IDE) - (INT 76h) +IRQ14_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 15 (Primary IDE) - (INT 77h) +IRQ15_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +IDT_END: + + align 02h + +MemoryMapSize dd 0 +MemoryMap dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + + dd 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + org 0fe0h +MyStack: + ; below is the pieces of the IVT that is used to redirect INT 68h - 6fh + ; back to INT 08h - 0fh when in real mode... It is 'org'ed to a + ; known low address (20f00) so it can be set up by PlMapIrqToVect in + ; 8259.c + + int 8 + iret + + int 9 + iret + + int 10 + iret + + int 11 + iret + + int 12 + iret + + int 13 + iret + + int 14 + iret + + int 15 + iret + + + org 0ffeh +BlockSignature: + dw 0aa55h + + end diff --git a/DuetPkg/BootSector/st32_64.asm b/DuetPkg/BootSector/st32_64.asm new file mode 100644 index 0000000000..970cdc8f0d --- /dev/null +++ b/DuetPkg/BootSector/st32_64.asm @@ -0,0 +1,1156 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright 2006 - 2007, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* st32_64.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + + .model small + .stack + .486p + .code + +FAT_DIRECTORY_ENTRY_SIZE EQU 020h +FAT_DIRECTORY_ENTRY_SHIFT EQU 5 +BLOCK_SIZE EQU 0200h +BLOCK_MASK EQU 01ffh +BLOCK_SHIFT EQU 9 + + org 0h +Ia32Jump: + jmp BootSectorEntryPoint ; JMP inst - 3 bytes + nop + +OemId db "INTEL " ; OemId - 8 bytes +SectorSize dw 0 ; Sector Size - 2 bytes +SectorsPerCluster db 0 ; Sector Per Cluster - 1 byte +ReservedSectors dw 0 ; Reserved Sectors - 2 bytes +NoFats db 0 ; Number of FATs - 1 byte +RootEntries dw 0 ; Root Entries - 2 bytes +Sectors dw 0 ; Number of Sectors - 2 bytes +Media db 0 ; Media - 1 byte +SectorsPerFat16 dw 0 ; Sectors Per FAT for FAT12/FAT16 - 2 byte +SectorsPerTrack dw 0 ; Sectors Per Track - 2 bytes +Heads dw 0 ; Heads - 2 bytes +HiddenSectors dd 0 ; Hidden Sectors - 4 bytes +LargeSectors dd 0 ; Large Sectors - 4 bytes + +;****************************************************************************** +; +;The structure for FAT32 starting at offset 36 of the boot sector. (At this point, +;the BPB/boot sector for FAT12 and FAT16 differs from the BPB/boot sector for FAT32.) +; +;****************************************************************************** + +SectorsPerFat32 dd 0 ; Sectors Per FAT for FAT32 - 4 bytes +ExtFlags dw 0 ; Mirror Flag - 2 bytes +FSVersion dw 0 ; File System Version - 2 bytes +RootCluster dd 0 ; 1st Cluster Number of Root Dir - 4 bytes +FSInfo dw 0 ; Sector Number of FSINFO - 2 bytes +BkBootSector dw 0 ; Sector Number of Bk BootSector - 2 bytes +Reserved db 12 dup(0) ; Reserved Field - 12 bytes +PhysicalDrive db 0 ; Physical Drive Number - 1 byte +Reserved1 db 0 ; Reserved Field - 1 byte +Signature db 0 ; Extended Boot Signature - 1 byte +VolId db " " ; Volume Serial Number - 4 bytes +FatLabel db " " ; Volume Label - 11 bytes +FileSystemType db "FAT32 " ; File System Type - 8 bytes + +BootSectorEntryPoint: + ASSUME ds:@code + ASSUME ss:@code + ; ds = 1000, es = 2000 + x (size of first cluster >> 4) + ; cx = Start Cluster of EfiLdr + ; dx = Start Cluster of Efivar.bin + +; Re use the BPB data stored in Boot Sector + mov bp,07c00h + + + push cx +; Read Efivar.bin +; 1000:dx = DirectoryEntry of Efivar.bin -> BS.com has filled already + mov ax,01900h + mov es,ax + test dx,dx + jnz CheckVarStoreSize + + mov al,1 +NoVarStore: + push es +; Set the 5th byte start @ 0:19000 to non-zero indicating we should init var store header in DxeIpl + mov byte ptr es:[4],al + jmp SaveVolumeId + +CheckVarStoreSize: + mov di,dx + cmp dword ptr ds:[di+2], 04000h + mov al,2 + jne NoVarStore + +LoadVarStore: + mov al,0 + mov byte ptr es:[4],al + mov cx,word ptr[di] +; ES:DI = 1500:0 + xor di,di + push es + mov ax,01500h + mov es,ax + call ReadFile +SaveVolumeId: + pop es + mov ax,word ptr [bp+VolId] + mov word ptr es:[0],ax ; Save Volume Id to 0:19000. we will find the correct volume according to this VolumeId + mov ax,word ptr [bp+VolId+2] + mov word ptr es:[2],ax + +; Read Efildr + pop cx +; cx = Start Cluster of Efildr -> BS.com has filled already +; ES:DI = 2000:0, first cluster will be read again + xor di,di ; di = 0 + mov ax,02000h + mov es,ax + call ReadFile + mov ax,cs + mov word ptr cs:[JumpSegment],ax + +CheckEm64T: + mov eax, 080000001h +; cpuid + dw 0A20Fh + bt edx, 29 + jc CheckEm64TPass + push cs + pop ds + lea si, [Em64String] + mov cx, 18 + jmp PrintStringAndHalt +CheckEm64TPass: +JumpFarInstruction: + db 0eah +JumpOffset: + dw 0200h +JumpSegment: + dw 2000h + + + + +; **************************************************************************** +; ReadFile +; +; Arguments: +; CX = Start Cluster of File +; ES:DI = Buffer to store file content read from disk +; +; Return: +; (ES << 4 + DI) = end of file content Buffer +; +; **************************************************************************** +ReadFile: +; si = NumberOfClusters +; cx = ClusterNumber +; dx = CachedFatSectorNumber +; ds:0000 = CacheFatSectorBuffer +; es:di = Buffer to load file +; bx = NextClusterNumber + pusha + mov si,1 ; NumberOfClusters = 1 + push cx ; Push Start Cluster onto stack + mov dx,0fffh ; CachedFatSectorNumber = 0xfff +FatChainLoop: + mov ax,cx ; ax = ClusterNumber + and ax,0fff8h ; ax = ax & 0xfff8 + cmp ax,0fff8h ; See if this is the last cluster + je FoundLastCluster ; Jump if last cluster found + mov ax,cx ; ax = ClusterNumber + shl ax,2 ; FatOffset = ClusterNumber * 4 + push si ; Save si + mov si,ax ; si = FatOffset + shr ax,BLOCK_SHIFT ; ax = FatOffset >> BLOCK_SHIFT + add ax,word ptr [bp+ReservedSectors] ; ax = FatSectorNumber = ReservedSectors + (FatOffset >> BLOCK_OFFSET) + and si,BLOCK_MASK ; si = FatOffset & BLOCK_MASK + cmp ax,dx ; Compare FatSectorNumber to CachedFatSectorNumber + je SkipFatRead + mov bx,2 + push es + push ds + pop es + call ReadBlocks ; Read 2 blocks starting at AX storing at ES:DI + pop es + mov dx,ax ; CachedFatSectorNumber = FatSectorNumber +SkipFatRead: + mov bx,word ptr [si] ; bx = NextClusterNumber + mov ax,cx ; ax = ClusterNumber + pop si ; Restore si + dec bx ; bx = NextClusterNumber - 1 + cmp bx,cx ; See if (NextClusterNumber-1)==ClusterNumber + jne ReadClusters + inc bx ; bx = NextClusterNumber + inc si ; NumberOfClusters++ + mov cx,bx ; ClusterNumber = NextClusterNumber + jmp FatChainLoop +ReadClusters: + inc bx + pop ax ; ax = StartCluster + push bx ; StartCluster = NextClusterNumber + mov cx,bx ; ClusterNumber = NextClusterNumber + sub ax,2 ; ax = StartCluster - 2 + xor bh,bh + mov bl,byte ptr [bp+SectorsPerCluster] ; bx = SectorsPerCluster + mul bx ; ax = (StartCluster - 2) * SectorsPerCluster + add ax, word ptr [bp] ; ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster + push ax ; save start sector + mov ax,si ; ax = NumberOfClusters + mul bx ; ax = NumberOfClusters * SectorsPerCluster + mov bx,ax ; bx = Number of Sectors + pop ax ; ax = Start Sector + call ReadBlocks + mov si,1 ; NumberOfClusters = 1 + jmp FatChainLoop +FoundLastCluster: + pop cx + popa + ret + + +; **************************************************************************** +; ReadBlocks - Reads a set of blocks from a block device +; +; AX = Start LBA +; BX = Number of Blocks to Read +; ES:DI = Buffer to store sectors read from disk +; **************************************************************************** + +; cx = Blocks +; bx = NumberOfBlocks +; si = StartLBA + +ReadBlocks: + pusha + add eax,dword ptr [bp+LBAOffsetForBootSector] ; Add LBAOffsetForBootSector to Start LBA + add eax,dword ptr [bp+HiddenSectors] ; Add HiddenSectors to Start LBA + mov esi,eax ; esi = Start LBA + mov cx,bx ; cx = Number of blocks to read +ReadCylinderLoop: + mov bp,07bfch ; bp = 0x7bfc + mov eax,esi ; eax = Start LBA + xor edx,edx ; edx = 0 + movzx ebx,word ptr [bp] ; bx = MaxSector + div ebx ; ax = StartLBA / MaxSector + inc dx ; dx = (StartLBA % MaxSector) + 1 + + mov bx,word ptr [bp] ; bx = MaxSector + sub bx,dx ; bx = MaxSector - Sector + inc bx ; bx = MaxSector - Sector + 1 + cmp cx,bx ; Compare (Blocks) to (MaxSector - Sector + 1) + jg LimitTransfer + mov bx,cx ; bx = Blocks +LimitTransfer: + push ax ; save ax + mov ax,es ; ax = es + shr ax,(BLOCK_SHIFT-4) ; ax = Number of blocks into mem system + and ax,07fh ; ax = Number of blocks into current seg + add ax,bx ; ax = End Block number of transfer + cmp ax,080h ; See if it crosses a 64K boundry + jle NotCrossing64KBoundry ; Branch if not crossing 64K boundry + sub ax,080h ; ax = Number of blocks past 64K boundry + sub bx,ax ; Decrease transfer size by block overage +NotCrossing64KBoundry: + pop ax ; restore ax + + push cx + mov cl,dl ; cl = (StartLBA % MaxSector) + 1 = Sector + xor dx,dx ; dx = 0 + div word ptr [bp+2] ; ax = ax / (MaxHead + 1) = Cylinder + ; dx = ax % (MaxHead + 1) = Head + + push bx ; Save number of blocks to transfer + mov dh,dl ; dh = Head + mov bp,07c00h ; bp = 0x7c00 + mov dl,byte ptr [bp+PhysicalDrive] ; dl = Drive Number + mov ch,al ; ch = Cylinder + mov al,bl ; al = Blocks + mov ah,2 ; ah = Function 2 + mov bx,di ; es:bx = Buffer address + int 013h + jc DiskError + pop bx + pop cx + movzx ebx,bx + add esi,ebx ; StartLBA = StartLBA + NumberOfBlocks + sub cx,bx ; Blocks = Blocks - NumberOfBlocks + mov ax,es + shl bx,(BLOCK_SHIFT-4) + add ax,bx + mov es,ax ; es:di = es:di + NumberOfBlocks*BLOCK_SIZE + cmp cx,0 + jne ReadCylinderLoop + popa + ret + +DiskError: + push cs + pop ds + lea si, [ErrorString] + mov cx, 7 + jmp PrintStringAndHalt + +PrintStringAndHalt: + mov ax,0b800h + mov es,ax + mov di,160 + rep movsw +Halt: + jmp Halt + +ErrorString: + db 'S', 0ch, 'E', 0ch, 'r', 0ch, 'r', 0ch, 'o', 0ch, 'r', 0ch, '!', 0ch + + org 01fah +LBAOffsetForBootSector: + dd 0h + + org 01feh + dw 0aa55h + +;****************************************************************************** +;****************************************************************************** +;****************************************************************************** + +DELAY_PORT equ 0edh ; Port to use for 1uS delay +KBD_CONTROL_PORT equ 060h ; 8042 control port +KBD_STATUS_PORT equ 064h ; 8042 status port +WRITE_DATA_PORT_CMD equ 0d1h ; 8042 command to write the data port +ENABLE_A20_CMD equ 0dfh ; 8042 command to enable A20 + + org 200h + jmp start +Em64String: + db 'E', 0ch, 'm', 0ch, '6', 0ch, '4', 0ch, 'T', 0ch, ' ', 0ch, 'U', 0ch, 'n', 0ch, 's', 0ch, 'u', 0ch, 'p', 0ch, 'p', 0ch, 'o', 0ch, 'r', 0ch, 't', 0ch, 'e', 0ch, 'd', 0ch, '!', 0ch + +start: + mov ax,cs + mov ds,ax + mov es,ax + mov ss,ax + mov sp,MyStack + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[160],'a' +; mov ax,cs +; mov es,ax + + mov ebx,0 + lea edi,MemoryMap +MemMapLoop: + mov eax,0e820h + mov ecx,20 + mov edx,'SMAP' + int 15h + jc MemMapDone + add edi,20 + cmp ebx,0 + je MemMapDone + jmp MemMapLoop +MemMapDone: + lea eax,MemoryMap + sub edi,eax ; Get the address of the memory map + mov dword ptr [MemoryMapSize],edi ; Save the size of the memory map + + xor ebx,ebx + mov bx,cs ; BX=segment + shl ebx,4 ; BX="linear" address of segment base + lea eax,[GDT_BASE + ebx] ; EAX=PHYSICAL address of gdt + mov dword ptr [gdtr + 2],eax ; Put address of gdt into the gdtr + lea eax,[IDT_BASE + ebx] ; EAX=PHYSICAL address of idt + mov dword ptr [idtr + 2],eax ; Put address of idt into the idtr + lea edx,[MemoryMapSize + ebx] ; Physical base address of the memory map + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[162],'b' +; mov ax,cs +; mov es,ax + +; +; Enable A20 Gate +; + + mov ax,2401h ; Enable A20 Gate + int 15h + jnc A20GateEnabled ; Jump if it suceeded + +; +; If INT 15 Function 2401 is not supported, then attempt to Enable A20 manually. +; + + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + jnz Timeout8042 ; Jump if the 8042 timed out + out DELAY_PORT,ax ; Delay 1 uS + mov al,WRITE_DATA_PORT_CMD ; 8042 cmd to write output port + out KBD_STATUS_PORT,al ; Send command to the 8042 + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + jnz Timeout8042 ; Jump if the 8042 timed out + mov al,ENABLE_A20_CMD ; gate address bit 20 on + out KBD_CONTROL_PORT,al ; Send command to thre 8042 + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + mov cx,25 ; Delay 25 uS for the command to complete on the 8042 +Delay25uS: + out DELAY_PORT,ax ; Delay 1 uS + loop Delay25uS +Timeout8042: + + +A20GateEnabled: + +; +; DISABLE INTERRUPTS - Entering Protected Mode +; + + cli + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[164],'c' +; mov ax,cs +; mov es,ax + + lea eax, OffsetIn32BitProtectedMode + add eax, 20000h + 6h + mov dword ptr[OffsetIn32BitProtectedMode], eax + + lea eax, OffsetInLongMode + add eax, 20000h + 6h + mov dword ptr[OffsetInLongMode], eax + + ; + ; load GDT + ; + db 66h + lgdt fword ptr [gdtr] + + ; + ; Enable Protect Mode (set CR0.PE=1) + ; + mov eax, cr0 ; Read CR0. + or eax, 1h ; Set PE=1 + mov cr0, eax ; Write CR0. + db 066h + db 0eah ; jmp far 16:32 +OffsetIn32BitProtectedMode: + dd 00000000h ; offset $+8 (In32BitProtectedMode) + dw 10h ; selector (flat CS) +In32BitProtectedMode: + +; +; Entering Long Mode +; + db 66h + mov ax, 8 + mov ds, ax + mov es, ax + mov ss, ax + + ; + ; Enable the 64-bit page-translation-table entries by + ; setting CR4.PAE=1 (this is _required_ before activating + ; long mode). Paging is not enabled until after long mode + ; is enabled. + ; + db 0fh + db 20h + db 0e0h +; mov eax, cr4 + bts eax, 5 + db 0fh + db 22h + db 0e0h +; mov cr4, eax + + ; + ; This is the Trapolean Page Tables that are guarenteed + ; under 4GB. + ; + ; Address Map: + ; 10000 ~ 12000 - efildr (loaded) + ; 20000 ~ 21000 - start64.com + ; 21000 ~ 22000 - efi64.com + ; 22000 ~ 90000 - efildr + ; 90000 ~ 96000 - 4G pagetable (will be reload later) + ; + db 0b8h + dd 90000h +; mov eax, 90000h + mov cr3, eax + + ; + ; Enable long mode (set EFER.LME=1). + ; + db 0b9h + dd 0c0000080h +; mov ecx, 0c0000080h ; EFER MSR number. + db 0fh + db 32h +; rdmsr ; Read EFER. + db 0fh + db 0bah + db 0e8h + db 08h +; bts eax, 8 ; Set LME=1. + db 0fh + db 30h +; wrmsr ; Write EFER. + + ; + ; Enable paging to activate long mode (set CR0.PG=1) + ; + mov eax, cr0 ; Read CR0. + db 0fh + db 0bah + db 0e8h + db 01fh +; bts eax, 31 ; Set PG=1. + mov cr0, eax ; Write CR0. + jmp GoToLongMode +GoToLongMode: + + db 067h + db 0eah ; Far Jump $+9:Selector to reload CS +OffsetInLongMode: + dd 00000000 ; $+9 Offset is ensuing instruction boundary + dw 038h ; Selector is our code selector, 38h + +InLongMode: + db 66h + mov ax, 30h + mov ds, ax + + db 66h + mov ax, 18h + mov es, ax + mov ss, ax + mov ds, ax + + db 0bdh + dd 400000h +; mov ebp,000400000h ; Destination of EFILDR32 + db 0bbh + dd 70000h +; mov ebx,000070000h ; Length of copy + + ; + ; load idt later + ; + db 48h + db 33h + db 0c0h +; xor rax, rax + db 66h + mov ax, offset idtr + db 48h + db 05h + dd 20000h +; add rax, 20000h + + db 0fh + db 01h + db 18h +; lidt fword ptr [rax] + + db 48h + db 0c7h + db 0c0h + dd 21000h +; mov rax, 21000h + db 50h +; push rax + +; ret + db 0c3h + +Empty8042InputBuffer: + mov cx,0 +Empty8042Loop: + out DELAY_PORT,ax ; Delay 1us + in al,KBD_STATUS_PORT ; Read the 8042 Status Port + and al,02h ; Check the Input Buffer Full Flag + loopnz Empty8042Loop ; Loop until the input buffer is empty or a timout of 65536 uS + ret + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; data +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + align 02h + +gdtr dw GDT_END - GDT_BASE - 1 ; GDT limit + dd 0 ; (GDT base gets set above) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; global descriptor table (GDT) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + align 02h + +public GDT_BASE +GDT_BASE: +; null descriptor +NULL_SEL equ $-GDT_BASE ; Selector [0x0] + dw 0 ; limit 15:0 + dw 0 ; base 15:0 + db 0 ; base 23:16 + db 0 ; type + db 0 ; limit 19:16, flags + db 0 ; base 31:24 + +; linear data segment descriptor +LINEAR_SEL equ $-GDT_BASE ; Selector [0x8] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; linear code segment descriptor +LINEAR_CODE_SEL equ $-GDT_BASE ; Selector [0x10] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system data segment descriptor +SYS_DATA_SEL equ $-GDT_BASE ; Selector [0x18] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system code segment descriptor +SYS_CODE_SEL equ $-GDT_BASE ; Selector [0x20] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; spare segment descriptor +SPARE3_SEL equ $-GDT_BASE ; Selector [0x28] + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +; +; system data segment descriptor +; +SYS_DATA64_SEL equ $-GDT_BASE ; Selector [0x30] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; P | DPL [1..2] | 1 | 1 | C | R | A + db 0CFh ; G | D | L | AVL | Segment [19..16] + db 0 + +; +; system code segment descriptor +; +SYS_CODE64_SEL equ $-GDT_BASE ; Selector [0x38] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; P | DPL [1..2] | 1 | 1 | C | R | A + db 0AFh ; G | D | L | AVL | Segment [19..16] + db 0 + +; spare segment descriptor +SPARE4_SEL equ $-GDT_BASE ; Selector [0x40] + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +GDT_END: + + align 02h + + + +idtr dw IDT_END - IDT_BASE - 1 ; IDT limit + dq 0 ; (IDT base gets set above) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; interrupt descriptor table (IDT) +; +; Note: The hardware IRQ's specified in this table are the normal PC/AT IRQ +; mappings. This implementation only uses the system timer and all other +; IRQs will remain masked. The descriptors for vectors 33+ are provided +; for convenience. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;idt_tag db "IDT",0 + align 02h + +public IDT_BASE +IDT_BASE: +; divide by zero (INT 0) +DIV_ZERO_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; debug exception (INT 1) +DEBUG_EXCEPT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; NMI (INT 2) +NMI_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; soft breakpoint (INT 3) +BREAKPOINT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; overflow (INT 4) +OVERFLOW_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; bounds check (INT 5) +BOUNDS_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; invalid opcode (INT 6) +INVALID_OPCODE_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; device not available (INT 7) +DEV_NOT_AVAIL_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; double fault (INT 8) +DOUBLE_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; Coprocessor segment overrun - reserved (INT 9) +RSVD_INTR_SEL1 equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; invalid TSS (INT 0ah) +INVALID_TSS_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; segment not present (INT 0bh) +SEG_NOT_PRESENT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; stack fault (INT 0ch) +STACK_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; general protection (INT 0dh) +GP_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; page fault (INT 0eh) +PAGE_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; Intel reserved - do not use (INT 0fh) +RSVD_INTR_SEL2 equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; floating point error (INT 10h) +FLT_POINT_ERR_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; alignment check (INT 11h) +ALIGNMENT_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; machine check (INT 12h) +MACHINE_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; SIMD floating-point exception (INT 13h) +SIMD_EXCEPTION_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; 85 unspecified descriptors, First 12 of them are reserved, the rest are avail + db (85 * 16) dup(0) + +; IRQ 0 (System timer) - (INT 68h) +IRQ0_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 1 (8042 Keyboard controller) - (INT 69h) +IRQ1_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; Reserved - IRQ 2 redirect (IRQ 2) - DO NOT USE!!! - (INT 6ah) +IRQ2_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 3 (COM 2) - (INT 6bh) +IRQ3_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 4 (COM 1) - (INT 6ch) +IRQ4_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 5 (LPT 2) - (INT 6dh) +IRQ5_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 6 (Floppy controller) - (INT 6eh) +IRQ6_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 7 (LPT 1) - (INT 6fh) +IRQ7_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 8 (RTC Alarm) - (INT 70h) +IRQ8_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 9 - (INT 71h) +IRQ9_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 10 - (INT 72h) +IRQ10_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 11 - (INT 73h) +IRQ11_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 12 (PS/2 mouse) - (INT 74h) +IRQ12_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 13 (Floating point error) - (INT 75h) +IRQ13_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 14 (Secondary IDE) - (INT 76h) +IRQ14_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 15 (Primary IDE) - (INT 77h) +IRQ15_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +IDT_END: + + align 02h + +MemoryMapSize dd 0 +MemoryMap dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + + dd 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + org 0fe0h +MyStack: + ; below is the pieces of the IVT that is used to redirect INT 68h - 6fh + ; back to INT 08h - 0fh when in real mode... It is 'org'ed to a + ; known low address (20f00) so it can be set up by PlMapIrqToVect in + ; 8259.c + + int 8 + iret + + int 9 + iret + + int 10 + iret + + int 11 + iret + + int 12 + iret + + int 13 + iret + + int 14 + iret + + int 15 + iret + + + org 0ffeh +BlockSignature: + dw 0aa55h + + end diff --git a/DuetPkg/BootSector/start.asm b/DuetPkg/BootSector/start.asm new file mode 100644 index 0000000000..e8eb22982d --- /dev/null +++ b/DuetPkg/BootSector/start.asm @@ -0,0 +1,921 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright 2006 - 2007, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* start.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + + .model small + .stack + .486p + .code + +FAT_DIRECTORY_ENTRY_SIZE EQU 020h +FAT_DIRECTORY_ENTRY_SHIFT EQU 5 +BLOCK_SIZE EQU 0200h +BLOCK_MASK EQU 01ffh +BLOCK_SHIFT EQU 9 + + org 0h +Ia32Jump: + jmp BootSectorEntryPoint ; JMP inst - 3 bytes + nop + +OemId db "INTEL " ; OemId - 8 bytes + +SectorSize dw 0 ; Sector Size - 16 bits +SectorsPerCluster db 0 ; Sector Per Cluster - 8 bits +ReservedSectors dw 0 ; Reserved Sectors - 16 bits +NoFats db 0 ; Number of FATs - 8 bits +RootEntries dw 0 ; Root Entries - 16 bits +Sectors dw 0 ; Number of Sectors - 16 bits +Media db 0 ; Media - 8 bits - ignored +SectorsPerFat dw 0 ; Sectors Per FAT - 16 bits +SectorsPerTrack dw 0 ; Sectors Per Track - 16 bits - ignored +Heads dw 0 ; Heads - 16 bits - ignored +HiddenSectors dd 0 ; Hidden Sectors - 32 bits - ignored +LargeSectors dd 0 ; Large Sectors - 32 bits +PhysicalDrive db 0 ; PhysicalDriveNumber - 8 bits - ignored +CurrentHead db 0 ; Current Head - 8 bits +Signature db 0 ; Signature - 8 bits - ignored +VolId db " " ; Volume Serial Number- 4 bytes +FatLabel db " " ; Label - 11 bytes +SystemId db "FAT12 " ; SystemId - 8 bytes + +BootSectorEntryPoint: + ASSUME ds:@code + ASSUME ss:@code + ; ds = 1000, es = 2000 + x (size of first cluster >> 4) + ; cx = Start Cluster of EfiLdr + ; dx = Start Cluster of Efivar.bin + +; Re use the BPB data stored in Boot Sector + mov bp,07c00h + + push cx +; Read Efivar.bin +; 1000:dx = DirectoryEntry of Efivar.bin -> BS.com has filled already + mov ax,01900h + mov es,ax + test dx,dx + jnz CheckVarStoreSize + + mov al,1 +NoVarStore: + push es +; Set the 5th byte start @ 0:19000 to non-zero indicating we should init var store header in DxeIpl + mov byte ptr es:[4],al + jmp SaveVolumeId + +CheckVarStoreSize: + mov di,dx + cmp dword ptr ds:[di+2], 04000h + mov al,2 + jne NoVarStore + +LoadVarStore: + mov al,0 + mov byte ptr es:[4],al + mov cx,word ptr[di] +; ES:DI = 1500:0 + xor di,di + push es + mov ax,01500h + mov es,ax + call ReadFile +SaveVolumeId: + pop es + mov ax,word ptr [bp+VolId] + mov word ptr es:[0],ax ; Save Volume Id to 0:19000. we will find the correct volume according to this VolumeId + mov ax,word ptr [bp+VolId+2] + mov word ptr es:[2],ax + +; Read Efildr + pop cx +; cx = Start Cluster of Efildr -> BS.com has filled already +; ES:DI = 2000:0, first cluster will be read again + xor di,di ; di = 0 + mov ax,02000h + mov es,ax + call ReadFile + mov ax,cs + mov word ptr cs:[JumpSegment],ax + +JumpFarInstruction: + db 0eah +JumpOffset: + dw 0200h +JumpSegment: + dw 2000h + + + +; **************************************************************************** +; ReadFile +; +; Arguments: +; CX = Start Cluster of File +; ES:DI = Buffer to store file content read from disk +; +; Return: +; (ES << 4 + DI) = end of file content Buffer +; +; **************************************************************************** +ReadFile: +; si = NumberOfClusters +; cx = ClusterNumber +; dx = CachedFatSectorNumber +; ds:0000 = CacheFatSectorBuffer +; es:di = Buffer to load file +; bx = NextClusterNumber + pusha + mov si,1 ; NumberOfClusters = 1 + push cx ; Push Start Cluster onto stack + mov dx,0fffh ; CachedFatSectorNumber = 0xfff +FatChainLoop: + mov ax,cx ; ax = ClusterNumber + and ax,0ff8h ; ax = ax & 0xff8 + cmp ax,0ff8h ; See if this is the last cluster + je FoundLastCluster ; Jump if last cluster found + mov ax,cx ; ax = ClusterNumber + shl ax,1 ; ax = ClusterNumber * 2 + add ax,cx ; ax = ClusterNumber * 2 + ClusterNumber = ClusterNumber * 3 + shr ax,1 ; FatOffset = ClusterNumber*3 / 2 + push si ; Save si + mov si,ax ; si = FatOffset + shr ax,BLOCK_SHIFT ; ax = FatOffset >> BLOCK_SHIFT + add ax,word ptr [bp+ReservedSectors] ; ax = FatSectorNumber = ReservedSectors + (FatOffset >> BLOCK_OFFSET) + and si,BLOCK_MASK ; si = FatOffset & BLOCK_MASK + cmp ax,dx ; Compare FatSectorNumber to CachedFatSectorNumber + je SkipFatRead + mov bx,2 + push es + push ds + pop es + call ReadBlocks ; Read 2 blocks starting at AX storing at ES:DI + pop es + mov dx,ax ; CachedFatSectorNumber = FatSectorNumber +SkipFatRead: + mov bx,word ptr [si] ; bx = NextClusterNumber + mov ax,cx ; ax = ClusterNumber + and ax,1 ; See if this is an odd cluster number + je EvenFatEntry + shr bx,4 ; NextClusterNumber = NextClusterNumber >> 4 +EvenFatEntry: + and bx,0fffh ; Strip upper 4 bits of NextClusterNumber + pop si ; Restore si + dec bx ; bx = NextClusterNumber - 1 + cmp bx,cx ; See if (NextClusterNumber-1)==ClusterNumber + jne ReadClusters + inc bx ; bx = NextClusterNumber + inc si ; NumberOfClusters++ + mov cx,bx ; ClusterNumber = NextClusterNumber + jmp FatChainLoop +ReadClusters: + inc bx + pop ax ; ax = StartCluster + push bx ; StartCluster = NextClusterNumber + mov cx,bx ; ClusterNumber = NextClusterNumber + sub ax,2 ; ax = StartCluster - 2 + xor bh,bh + mov bl,byte ptr [bp+SectorsPerCluster] ; bx = SectorsPerCluster + mul bx ; ax = (StartCluster - 2) * SectorsPerCluster + add ax, word ptr [bp] ; ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster + push ax ; save start sector + mov ax,si ; ax = NumberOfClusters + mul bx ; ax = NumberOfClusters * SectorsPerCluster + mov bx,ax ; bx = Number of Sectors + pop ax ; ax = Start Sector + call ReadBlocks + mov si,1 ; NumberOfClusters = 1 + jmp FatChainLoop +FoundLastCluster: + pop cx + popa + ret + + +; **************************************************************************** +; ReadBlocks - Reads a set of blocks from a block device +; +; AX = Start LBA +; BX = Number of Blocks to Read +; ES:DI = Buffer to store sectors read from disk +; **************************************************************************** + +; cx = Blocks +; bx = NumberOfBlocks +; si = StartLBA + +ReadBlocks: + pusha + add eax,dword ptr [bp+LBAOffsetForBootSector] ; Add LBAOffsetForBootSector to Start LBA + add eax,dword ptr [bp+HiddenSectors] ; Add HiddenSectors to Start LBA + mov esi,eax ; esi = Start LBA + mov cx,bx ; cx = Number of blocks to read +ReadCylinderLoop: + mov bp,07bfch ; bp = 0x7bfc + mov eax,esi ; eax = Start LBA + xor edx,edx ; edx = 0 + movzx ebx,word ptr [bp] ; bx = MaxSector + div ebx ; ax = StartLBA / MaxSector + inc dx ; dx = (StartLBA % MaxSector) + 1 + + mov bx,word ptr [bp] ; bx = MaxSector + sub bx,dx ; bx = MaxSector - Sector + inc bx ; bx = MaxSector - Sector + 1 + cmp cx,bx ; Compare (Blocks) to (MaxSector - Sector + 1) + jg LimitTransfer + mov bx,cx ; bx = Blocks +LimitTransfer: + push ax ; save ax + mov ax,es ; ax = es + shr ax,(BLOCK_SHIFT-4) ; ax = Number of blocks into mem system + and ax,07fh ; ax = Number of blocks into current seg + add ax,bx ; ax = End Block number of transfer + cmp ax,080h ; See if it crosses a 64K boundry + jle NotCrossing64KBoundry ; Branch if not crossing 64K boundry + sub ax,080h ; ax = Number of blocks past 64K boundry + sub bx,ax ; Decrease transfer size by block overage +NotCrossing64KBoundry: + pop ax ; restore ax + + push cx + mov cl,dl ; cl = (StartLBA % MaxSector) + 1 = Sector + xor dx,dx ; dx = 0 + div word ptr [bp+2] ; ax = ax / (MaxHead + 1) = Cylinder + ; dx = ax % (MaxHead + 1) = Head + + push bx ; Save number of blocks to transfer + mov dh,dl ; dh = Head + mov bp,07c00h ; bp = 0x7c00 + mov dl,byte ptr [bp+PhysicalDrive] ; dl = Drive Number + mov ch,al ; ch = Cylinder + mov al,bl ; al = Blocks + mov ah,2 ; ah = Function 2 + mov bx,di ; es:bx = Buffer address + int 013h + jc DiskError + pop bx + pop cx + movzx ebx,bx + add esi,ebx ; StartLBA = StartLBA + NumberOfBlocks + sub cx,bx ; Blocks = Blocks - NumberOfBlocks + mov ax,es + shl bx,(BLOCK_SHIFT-4) + add ax,bx + mov es,ax ; es:di = es:di + NumberOfBlocks*BLOCK_SIZE + cmp cx,0 + jne ReadCylinderLoop + popa + ret + +DiskError: + push cs + pop ds + lea si, [ErrorString] + mov cx, 7 + jmp PrintStringAndHalt + +PrintStringAndHalt: + mov ax,0b800h + mov es,ax + mov di,160 + rep movsw +Halt: + jmp Halt + +ErrorString: + db 'S', 0ch, 'E', 0ch, 'r', 0ch, 'r', 0ch, 'o', 0ch, 'r', 0ch, '!', 0ch + + org 01fah +LBAOffsetForBootSector: + dd 0h + + org 01feh + dw 0aa55h + +;****************************************************************************** +;****************************************************************************** +;****************************************************************************** + +DELAY_PORT equ 0edh ; Port to use for 1uS delay +KBD_CONTROL_PORT equ 060h ; 8042 control port +KBD_STATUS_PORT equ 064h ; 8042 status port +WRITE_DATA_PORT_CMD equ 0d1h ; 8042 command to write the data port +ENABLE_A20_CMD equ 0dfh ; 8042 command to enable A20 + + org 200h + jmp start +Em64String: + db 'E', 0ch, 'm', 0ch, '6', 0ch, '4', 0ch, 'T', 0ch, ' ', 0ch, 'U', 0ch, 'n', 0ch, 's', 0ch, 'u', 0ch, 'p', 0ch, 'p', 0ch, 'o', 0ch, 'r', 0ch, 't', 0ch, 'e', 0ch, 'd', 0ch, '!', 0ch + +start: + mov ax,cs + mov ds,ax + mov es,ax + mov ss,ax + mov sp,MyStack + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[160],'a' +; mov ax,cs +; mov es,ax + + mov ebx,0 + lea edi,MemoryMap +MemMapLoop: + mov eax,0e820h + mov ecx,20 + mov edx,'SMAP' + int 15h + jc MemMapDone + add edi,20 + cmp ebx,0 + je MemMapDone + jmp MemMapLoop +MemMapDone: + lea eax,MemoryMap + sub edi,eax ; Get the address of the memory map + mov dword ptr [MemoryMapSize],edi ; Save the size of the memory map + + xor ebx,ebx + mov bx,cs ; BX=segment + shl ebx,4 ; BX="linear" address of segment base + lea eax,[GDT_BASE + ebx] ; EAX=PHYSICAL address of gdt + mov dword ptr [gdtr + 2],eax ; Put address of gdt into the gdtr + lea eax,[IDT_BASE + ebx] ; EAX=PHYSICAL address of idt + mov dword ptr [idtr + 2],eax ; Put address of idt into the idtr + lea edx,[MemoryMapSize + ebx] ; Physical base address of the memory map + + add ebx,01000h ; Source of EFI32 + mov dword ptr [JUMP+2],ebx + add ebx,01000h + mov esi,ebx ; Source of EFILDR32 + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[162],'b' +; mov ax,cs +; mov es,ax + +; +; Enable A20 Gate +; + + mov ax,2401h ; Enable A20 Gate + int 15h + jnc A20GateEnabled ; Jump if it suceeded + +; +; If INT 15 Function 2401 is not supported, then attempt to Enable A20 manually. +; + + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + jnz Timeout8042 ; Jump if the 8042 timed out + out DELAY_PORT,ax ; Delay 1 uS + mov al,WRITE_DATA_PORT_CMD ; 8042 cmd to write output port + out KBD_STATUS_PORT,al ; Send command to the 8042 + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + jnz Timeout8042 ; Jump if the 8042 timed out + mov al,ENABLE_A20_CMD ; gate address bit 20 on + out KBD_CONTROL_PORT,al ; Send command to thre 8042 + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + mov cx,25 ; Delay 25 uS for the command to complete on the 8042 +Delay25uS: + out DELAY_PORT,ax ; Delay 1 uS + loop Delay25uS +Timeout8042: + + +A20GateEnabled: + +; +; DISABLE INTERRUPTS - Entering Protected Mode +; + + cli + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[164],'c' +; mov ax,cs +; mov es,ax + + db 66h + lgdt fword ptr [gdtr] + db 66h + lidt fword ptr [idtr] + + mov eax,cr0 + or al,1 + mov cr0,eax + + mov eax,0008h ; Flat data descriptor + mov ebp,000400000h ; Destination of EFILDR32 + mov ebx,000070000h ; Length of copy + +JUMP: +; jmp far 0010:00020000 + db 066h + db 0eah + dd 000020000h + dw 00010h + +Empty8042InputBuffer: + mov cx,0 +Empty8042Loop: + out DELAY_PORT,ax ; Delay 1us + in al,KBD_STATUS_PORT ; Read the 8042 Status Port + and al,02h ; Check the Input Buffer Full Flag + loopnz Empty8042Loop ; Loop until the input buffer is empty or a timout of 65536 uS + ret + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; data +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + align 02h + +gdtr dw GDT_END - GDT_BASE - 1 ; GDT limit + dd 0 ; (GDT base gets set above) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; global descriptor table (GDT) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + align 02h + +public GDT_BASE +GDT_BASE: +; null descriptor +NULL_SEL equ $-GDT_BASE + dw 0 ; limit 15:0 + dw 0 ; base 15:0 + db 0 ; base 23:16 + db 0 ; type + db 0 ; limit 19:16, flags + db 0 ; base 31:24 + +; linear data segment descriptor +LINEAR_SEL equ $-GDT_BASE + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; linear code segment descriptor +LINEAR_CODE_SEL equ $-GDT_BASE + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system data segment descriptor +SYS_DATA_SEL equ $-GDT_BASE + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system code segment descriptor +SYS_CODE_SEL equ $-GDT_BASE + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; spare segment descriptor +SPARE3_SEL equ $-GDT_BASE + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +; spare segment descriptor +SPARE4_SEL equ $-GDT_BASE + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +; spare segment descriptor +SPARE5_SEL equ $-GDT_BASE + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +GDT_END: + + align 02h + + + +idtr dw IDT_END - IDT_BASE - 1 ; IDT limit + dd 0 ; (IDT base gets set above) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; interrupt descriptor table (IDT) +; +; Note: The hardware IRQ's specified in this table are the normal PC/AT IRQ +; mappings. This implementation only uses the system timer and all other +; IRQs will remain masked. The descriptors for vectors 33+ are provided +; for convenience. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;idt_tag db "IDT",0 + align 02h + +public IDT_BASE +IDT_BASE: +; divide by zero (INT 0) +DIV_ZERO_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; debug exception (INT 1) +DEBUG_EXCEPT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; NMI (INT 2) +NMI_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; soft breakpoint (INT 3) +BREAKPOINT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; overflow (INT 4) +OVERFLOW_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; bounds check (INT 5) +BOUNDS_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; invalid opcode (INT 6) +INVALID_OPCODE_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; device not available (INT 7) +DEV_NOT_AVAIL_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; double fault (INT 8) +DOUBLE_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; Coprocessor segment overrun - reserved (INT 9) +RSVD_INTR_SEL1 equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; invalid TSS (INT 0ah) +INVALID_TSS_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; segment not present (INT 0bh) +SEG_NOT_PRESENT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; stack fault (INT 0ch) +STACK_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; general protection (INT 0dh) +GP_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; page fault (INT 0eh) +PAGE_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; Intel reserved - do not use (INT 0fh) +RSVD_INTR_SEL2 equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; floating point error (INT 10h) +FLT_POINT_ERR_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; alignment check (INT 11h) +ALIGNMENT_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; machine check (INT 12h) +MACHINE_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; SIMD floating-point exception (INT 13h) +SIMD_EXCEPTION_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; 85 unspecified descriptors, First 12 of them are reserved, the rest are avail + db (85 * 8) dup(0) + +; IRQ 0 (System timer) - (INT 68h) +IRQ0_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 1 (8042 Keyboard controller) - (INT 69h) +IRQ1_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; Reserved - IRQ 2 redirect (IRQ 2) - DO NOT USE!!! - (INT 6ah) +IRQ2_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 3 (COM 2) - (INT 6bh) +IRQ3_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 4 (COM 1) - (INT 6ch) +IRQ4_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 5 (LPT 2) - (INT 6dh) +IRQ5_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 6 (Floppy controller) - (INT 6eh) +IRQ6_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 7 (LPT 1) - (INT 6fh) +IRQ7_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 8 (RTC Alarm) - (INT 70h) +IRQ8_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 9 - (INT 71h) +IRQ9_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 10 - (INT 72h) +IRQ10_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 11 - (INT 73h) +IRQ11_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 12 (PS/2 mouse) - (INT 74h) +IRQ12_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 13 (Floating point error) - (INT 75h) +IRQ13_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 14 (Secondary IDE) - (INT 76h) +IRQ14_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 15 (Primary IDE) - (INT 77h) +IRQ15_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +IDT_END: + + align 02h + +MemoryMapSize dd 0 +MemoryMap dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + + dd 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + org 0fe0h +MyStack: + ; below is the pieces of the IVT that is used to redirect INT 68h - 6fh + ; back to INT 08h - 0fh when in real mode... It is 'org'ed to a + ; known low address (20f00) so it can be set up by PlMapIrqToVect in + ; 8259.c + + int 8 + iret + + int 9 + iret + + int 10 + iret + + int 11 + iret + + int 12 + iret + + int 13 + iret + + int 14 + iret + + int 15 + iret + + + org 0ffeh +BlockSignature: + dw 0aa55h + + end diff --git a/DuetPkg/BootSector/start16.asm b/DuetPkg/BootSector/start16.asm new file mode 100644 index 0000000000..4775c4e8a3 --- /dev/null +++ b/DuetPkg/BootSector/start16.asm @@ -0,0 +1,914 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright 2006 - 2007, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* start16.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + + .model small + .stack + .486p + .code + +FAT_DIRECTORY_ENTRY_SIZE EQU 020h +FAT_DIRECTORY_ENTRY_SHIFT EQU 5 +BLOCK_SIZE EQU 0200h +BLOCK_MASK EQU 01ffh +BLOCK_SHIFT EQU 9 + + org 0h +Ia32Jump: + jmp BootSectorEntryPoint ; JMP inst - 3 bytes + nop + +OemId db "INTEL " ; OemId - 8 bytes + +SectorSize dw 0 ; Sector Size - 16 bits +SectorsPerCluster db 0 ; Sector Per Cluster - 8 bits +ReservedSectors dw 0 ; Reserved Sectors - 16 bits +NoFats db 0 ; Number of FATs - 8 bits +RootEntries dw 0 ; Root Entries - 16 bits +Sectors dw 0 ; Number of Sectors - 16 bits +Media db 0 ; Media - 8 bits - ignored +SectorsPerFat dw 0 ; Sectors Per FAT - 16 bits +SectorsPerTrack dw 0 ; Sectors Per Track - 16 bits - ignored +Heads dw 0 ; Heads - 16 bits - ignored +HiddenSectors dd 0 ; Hidden Sectors - 32 bits - ignored +LargeSectors dd 0 ; Large Sectors - 32 bits +PhysicalDrive db 0 ; PhysicalDriveNumber - 8 bits - ignored +CurrentHead db 0 ; Current Head - 8 bits +Signature db 0 ; Signature - 8 bits - ignored +VolId db " " ; Volume Serial Number- 4 bytes +FatLabel db " " ; Label - 11 bytes +SystemId db "FAT16 " ; SystemId - 8 bytes + +BootSectorEntryPoint: + ASSUME ds:@code + ASSUME ss:@code + ; ds = 1000, es = 2000 + x (size of first cluster >> 4) + ; cx = Start Cluster of EfiLdr + ; dx = Start Cluster of Efivar.bin + +; Re use the BPB data stored in Boot Sector + mov bp,07c00h + + push cx +; Read Efivar.bin +; 1000:dx = DirectoryEntry of Efivar.bin -> BS.com has filled already + mov ax,01900h + mov es,ax + test dx,dx + jnz CheckVarStoreSize + + mov al,1 +NoVarStore: + push es +; Set the 5th byte start @ 0:19000 to non-zero indicating we should init var store header in DxeIpl + mov byte ptr es:[4],al + jmp SaveVolumeId + +CheckVarStoreSize: + mov di,dx + cmp dword ptr ds:[di+2], 04000h + mov al,2 + jne NoVarStore + +LoadVarStore: + mov al,0 + mov byte ptr es:[4],al + mov cx,word ptr[di] +; ES:DI = 1500:0 + xor di,di + push es + mov ax,01500h + mov es,ax + call ReadFile +SaveVolumeId: + pop es + mov ax,word ptr [bp+VolId] + mov word ptr es:[0],ax ; Save Volume Id to 0:19000. we will find the correct volume according to this VolumeId + mov ax,word ptr [bp+VolId+2] + mov word ptr es:[2],ax + +; Read Efildr + pop cx +; cx = Start Cluster of Efildr -> BS.com has filled already +; ES:DI = 2000:0, first cluster will be read again + xor di,di ; di = 0 + mov ax,02000h + mov es,ax + call ReadFile + mov ax,cs + mov word ptr cs:[JumpSegment],ax + +JumpFarInstruction: + db 0eah +JumpOffset: + dw 0200h +JumpSegment: + dw 2000h + + + +; **************************************************************************** +; ReadFile +; +; Arguments: +; CX = Start Cluster of File +; ES:DI = Buffer to store file content read from disk +; +; Return: +; (ES << 4 + DI) = end of file content Buffer +; +; **************************************************************************** +ReadFile: +; si = NumberOfClusters +; cx = ClusterNumber +; dx = CachedFatSectorNumber +; ds:0000 = CacheFatSectorBuffer +; es:di = Buffer to load file +; bx = NextClusterNumber + pusha + mov si,1 ; NumberOfClusters = 1 + push cx ; Push Start Cluster onto stack + mov dx,0fffh ; CachedFatSectorNumber = 0xfff +FatChainLoop: + mov ax,cx ; ax = ClusterNumber + and ax,0fff8h ; ax = ax & 0xfff8 + cmp ax,0fff8h ; See if this is the last cluster + je FoundLastCluster ; Jump if last cluster found + mov ax,cx ; ax = ClusterNumber + shl ax,1 ; FatOffset = ClusterNumber * 2 + push si ; Save si + mov si,ax ; si = FatOffset + shr ax,BLOCK_SHIFT ; ax = FatOffset >> BLOCK_SHIFT + add ax,word ptr [bp+ReservedSectors] ; ax = FatSectorNumber = ReservedSectors + (FatOffset >> BLOCK_OFFSET) + and si,BLOCK_MASK ; si = FatOffset & BLOCK_MASK + cmp ax,dx ; Compare FatSectorNumber to CachedFatSectorNumber + je SkipFatRead + mov bx,2 + push es + push ds + pop es + call ReadBlocks ; Read 2 blocks starting at AX storing at ES:DI + pop es + mov dx,ax ; CachedFatSectorNumber = FatSectorNumber +SkipFatRead: + mov bx,word ptr [si] ; bx = NextClusterNumber + mov ax,cx ; ax = ClusterNumber + pop si ; Restore si + dec bx ; bx = NextClusterNumber - 1 + cmp bx,cx ; See if (NextClusterNumber-1)==ClusterNumber + jne ReadClusters + inc bx ; bx = NextClusterNumber + inc si ; NumberOfClusters++ + mov cx,bx ; ClusterNumber = NextClusterNumber + jmp FatChainLoop +ReadClusters: + inc bx + pop ax ; ax = StartCluster + push bx ; StartCluster = NextClusterNumber + mov cx,bx ; ClusterNumber = NextClusterNumber + sub ax,2 ; ax = StartCluster - 2 + xor bh,bh + mov bl,byte ptr [bp+SectorsPerCluster] ; bx = SectorsPerCluster + mul bx ; ax = (StartCluster - 2) * SectorsPerCluster + add ax, word ptr [bp] ; ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster + push ax ; save start sector + mov ax,si ; ax = NumberOfClusters + mul bx ; ax = NumberOfClusters * SectorsPerCluster + mov bx,ax ; bx = Number of Sectors + pop ax ; ax = Start Sector + call ReadBlocks + mov si,1 ; NumberOfClusters = 1 + jmp FatChainLoop +FoundLastCluster: + pop cx + popa + ret + + +; **************************************************************************** +; ReadBlocks - Reads a set of blocks from a block device +; +; AX = Start LBA +; BX = Number of Blocks to Read +; ES:DI = Buffer to store sectors read from disk +; **************************************************************************** + +; cx = Blocks +; bx = NumberOfBlocks +; si = StartLBA + +ReadBlocks: + pusha + add eax,dword ptr [bp+LBAOffsetForBootSector] ; Add LBAOffsetForBootSector to Start LBA + add eax,dword ptr [bp+HiddenSectors] ; Add HiddenSectors to Start LBA + mov esi,eax ; esi = Start LBA + mov cx,bx ; cx = Number of blocks to read +ReadCylinderLoop: + mov bp,07bfch ; bp = 0x7bfc + mov eax,esi ; eax = Start LBA + xor edx,edx ; edx = 0 + movzx ebx,word ptr [bp] ; bx = MaxSector + div ebx ; ax = StartLBA / MaxSector + inc dx ; dx = (StartLBA % MaxSector) + 1 + + mov bx,word ptr [bp] ; bx = MaxSector + sub bx,dx ; bx = MaxSector - Sector + inc bx ; bx = MaxSector - Sector + 1 + cmp cx,bx ; Compare (Blocks) to (MaxSector - Sector + 1) + jg LimitTransfer + mov bx,cx ; bx = Blocks +LimitTransfer: + push ax ; save ax + mov ax,es ; ax = es + shr ax,(BLOCK_SHIFT-4) ; ax = Number of blocks into mem system + and ax,07fh ; ax = Number of blocks into current seg + add ax,bx ; ax = End Block number of transfer + cmp ax,080h ; See if it crosses a 64K boundry + jle NotCrossing64KBoundry ; Branch if not crossing 64K boundry + sub ax,080h ; ax = Number of blocks past 64K boundry + sub bx,ax ; Decrease transfer size by block overage +NotCrossing64KBoundry: + pop ax ; restore ax + + push cx + mov cl,dl ; cl = (StartLBA % MaxSector) + 1 = Sector + xor dx,dx ; dx = 0 + div word ptr [bp+2] ; ax = ax / (MaxHead + 1) = Cylinder + ; dx = ax % (MaxHead + 1) = Head + + push bx ; Save number of blocks to transfer + mov dh,dl ; dh = Head + mov bp,07c00h ; bp = 0x7c00 + mov dl,byte ptr [bp+PhysicalDrive] ; dl = Drive Number + mov ch,al ; ch = Cylinder + mov al,bl ; al = Blocks + mov ah,2 ; ah = Function 2 + mov bx,di ; es:bx = Buffer address + int 013h + jc DiskError + pop bx + pop cx + movzx ebx,bx + add esi,ebx ; StartLBA = StartLBA + NumberOfBlocks + sub cx,bx ; Blocks = Blocks - NumberOfBlocks + mov ax,es + shl bx,(BLOCK_SHIFT-4) + add ax,bx + mov es,ax ; es:di = es:di + NumberOfBlocks*BLOCK_SIZE + cmp cx,0 + jne ReadCylinderLoop + popa + ret + +DiskError: + push cs + pop ds + lea si, [ErrorString] + mov cx, 7 + jmp PrintStringAndHalt + +PrintStringAndHalt: + mov ax,0b800h + mov es,ax + mov di,160 + rep movsw +Halt: + jmp Halt + +ErrorString: + db 'S', 0ch, 'E', 0ch, 'r', 0ch, 'r', 0ch, 'o', 0ch, 'r', 0ch, '!', 0ch + + org 01fah +LBAOffsetForBootSector: + dd 0h + + org 01feh + dw 0aa55h + +;****************************************************************************** +;****************************************************************************** +;****************************************************************************** + +DELAY_PORT equ 0edh ; Port to use for 1uS delay +KBD_CONTROL_PORT equ 060h ; 8042 control port +KBD_STATUS_PORT equ 064h ; 8042 status port +WRITE_DATA_PORT_CMD equ 0d1h ; 8042 command to write the data port +ENABLE_A20_CMD equ 0dfh ; 8042 command to enable A20 + + org 200h + jmp start +Em64String: + db 'E', 0ch, 'm', 0ch, '6', 0ch, '4', 0ch, 'T', 0ch, ' ', 0ch, 'U', 0ch, 'n', 0ch, 's', 0ch, 'u', 0ch, 'p', 0ch, 'p', 0ch, 'o', 0ch, 'r', 0ch, 't', 0ch, 'e', 0ch, 'd', 0ch, '!', 0ch + +start: + mov ax,cs + mov ds,ax + mov es,ax + mov ss,ax + mov sp,MyStack + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[160],'a' +; mov ax,cs +; mov es,ax + + mov ebx,0 + lea edi,MemoryMap +MemMapLoop: + mov eax,0e820h + mov ecx,20 + mov edx,'SMAP' + int 15h + jc MemMapDone + add edi,20 + cmp ebx,0 + je MemMapDone + jmp MemMapLoop +MemMapDone: + lea eax,MemoryMap + sub edi,eax ; Get the address of the memory map + mov dword ptr [MemoryMapSize],edi ; Save the size of the memory map + + xor ebx,ebx + mov bx,cs ; BX=segment + shl ebx,4 ; BX="linear" address of segment base + lea eax,[GDT_BASE + ebx] ; EAX=PHYSICAL address of gdt + mov dword ptr [gdtr + 2],eax ; Put address of gdt into the gdtr + lea eax,[IDT_BASE + ebx] ; EAX=PHYSICAL address of idt + mov dword ptr [idtr + 2],eax ; Put address of idt into the idtr + lea edx,[MemoryMapSize + ebx] ; Physical base address of the memory map + + add ebx,01000h ; Source of EFI32 + mov dword ptr [JUMP+2],ebx + add ebx,01000h + mov esi,ebx ; Source of EFILDR32 + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[162],'b' +; mov ax,cs +; mov es,ax + +; +; Enable A20 Gate +; + + mov ax,2401h ; Enable A20 Gate + int 15h + jnc A20GateEnabled ; Jump if it suceeded + +; +; If INT 15 Function 2401 is not supported, then attempt to Enable A20 manually. +; + + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + jnz Timeout8042 ; Jump if the 8042 timed out + out DELAY_PORT,ax ; Delay 1 uS + mov al,WRITE_DATA_PORT_CMD ; 8042 cmd to write output port + out KBD_STATUS_PORT,al ; Send command to the 8042 + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + jnz Timeout8042 ; Jump if the 8042 timed out + mov al,ENABLE_A20_CMD ; gate address bit 20 on + out KBD_CONTROL_PORT,al ; Send command to thre 8042 + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + mov cx,25 ; Delay 25 uS for the command to complete on the 8042 +Delay25uS: + out DELAY_PORT,ax ; Delay 1 uS + loop Delay25uS +Timeout8042: + + +A20GateEnabled: + +; +; DISABLE INTERRUPTS - Entering Protected Mode +; + + cli + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[164],'c' +; mov ax,cs +; mov es,ax + + db 66h + lgdt fword ptr [gdtr] + db 66h + lidt fword ptr [idtr] + + mov eax,cr0 + or al,1 + mov cr0,eax + + mov eax,0008h ; Flat data descriptor + mov ebp,000400000h ; Destination of EFILDR32 + mov ebx,000070000h ; Length of copy + +JUMP: +; jmp far 0010:00020000 + db 066h + db 0eah + dd 000020000h + dw 00010h + +Empty8042InputBuffer: + mov cx,0 +Empty8042Loop: + out DELAY_PORT,ax ; Delay 1us + in al,KBD_STATUS_PORT ; Read the 8042 Status Port + and al,02h ; Check the Input Buffer Full Flag + loopnz Empty8042Loop ; Loop until the input buffer is empty or a timout of 65536 uS + ret + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; data +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + align 02h + +gdtr dw GDT_END - GDT_BASE - 1 ; GDT limit + dd 0 ; (GDT base gets set above) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; global descriptor table (GDT) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + align 02h + +public GDT_BASE +GDT_BASE: +; null descriptor +NULL_SEL equ $-GDT_BASE + dw 0 ; limit 15:0 + dw 0 ; base 15:0 + db 0 ; base 23:16 + db 0 ; type + db 0 ; limit 19:16, flags + db 0 ; base 31:24 + +; linear data segment descriptor +LINEAR_SEL equ $-GDT_BASE + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; linear code segment descriptor +LINEAR_CODE_SEL equ $-GDT_BASE + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system data segment descriptor +SYS_DATA_SEL equ $-GDT_BASE + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system code segment descriptor +SYS_CODE_SEL equ $-GDT_BASE + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; spare segment descriptor +SPARE3_SEL equ $-GDT_BASE + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +; spare segment descriptor +SPARE4_SEL equ $-GDT_BASE + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +; spare segment descriptor +SPARE5_SEL equ $-GDT_BASE + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +GDT_END: + + align 02h + + + +idtr dw IDT_END - IDT_BASE - 1 ; IDT limit + dd 0 ; (IDT base gets set above) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; interrupt descriptor table (IDT) +; +; Note: The hardware IRQ's specified in this table are the normal PC/AT IRQ +; mappings. This implementation only uses the system timer and all other +; IRQs will remain masked. The descriptors for vectors 33+ are provided +; for convenience. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;idt_tag db "IDT",0 + align 02h + +public IDT_BASE +IDT_BASE: +; divide by zero (INT 0) +DIV_ZERO_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; debug exception (INT 1) +DEBUG_EXCEPT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; NMI (INT 2) +NMI_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; soft breakpoint (INT 3) +BREAKPOINT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; overflow (INT 4) +OVERFLOW_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; bounds check (INT 5) +BOUNDS_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; invalid opcode (INT 6) +INVALID_OPCODE_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; device not available (INT 7) +DEV_NOT_AVAIL_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; double fault (INT 8) +DOUBLE_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; Coprocessor segment overrun - reserved (INT 9) +RSVD_INTR_SEL1 equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; invalid TSS (INT 0ah) +INVALID_TSS_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; segment not present (INT 0bh) +SEG_NOT_PRESENT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; stack fault (INT 0ch) +STACK_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; general protection (INT 0dh) +GP_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; page fault (INT 0eh) +PAGE_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; Intel reserved - do not use (INT 0fh) +RSVD_INTR_SEL2 equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; floating point error (INT 10h) +FLT_POINT_ERR_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; alignment check (INT 11h) +ALIGNMENT_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; machine check (INT 12h) +MACHINE_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; SIMD floating-point exception (INT 13h) +SIMD_EXCEPTION_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; 85 unspecified descriptors, First 12 of them are reserved, the rest are avail + db (85 * 8) dup(0) + +; IRQ 0 (System timer) - (INT 68h) +IRQ0_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 1 (8042 Keyboard controller) - (INT 69h) +IRQ1_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; Reserved - IRQ 2 redirect (IRQ 2) - DO NOT USE!!! - (INT 6ah) +IRQ2_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 3 (COM 2) - (INT 6bh) +IRQ3_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 4 (COM 1) - (INT 6ch) +IRQ4_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 5 (LPT 2) - (INT 6dh) +IRQ5_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 6 (Floppy controller) - (INT 6eh) +IRQ6_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 7 (LPT 1) - (INT 6fh) +IRQ7_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 8 (RTC Alarm) - (INT 70h) +IRQ8_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 9 - (INT 71h) +IRQ9_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 10 - (INT 72h) +IRQ10_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 11 - (INT 73h) +IRQ11_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 12 (PS/2 mouse) - (INT 74h) +IRQ12_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 13 (Floating point error) - (INT 75h) +IRQ13_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 14 (Secondary IDE) - (INT 76h) +IRQ14_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 15 (Primary IDE) - (INT 77h) +IRQ15_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +IDT_END: + + align 02h + +MemoryMapSize dd 0 +MemoryMap dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + + dd 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + org 0fe0h +MyStack: + ; below is the pieces of the IVT that is used to redirect INT 68h - 6fh + ; back to INT 08h - 0fh when in real mode... It is 'org'ed to a + ; known low address (20f00) so it can be set up by PlMapIrqToVect in + ; 8259.c + + int 8 + iret + + int 9 + iret + + int 10 + iret + + int 11 + iret + + int 12 + iret + + int 13 + iret + + int 14 + iret + + int 15 + iret + + + org 0ffeh +BlockSignature: + dw 0aa55h + + end diff --git a/DuetPkg/BootSector/start32.asm b/DuetPkg/BootSector/start32.asm new file mode 100644 index 0000000000..6cc6fcaa6c --- /dev/null +++ b/DuetPkg/BootSector/start32.asm @@ -0,0 +1,929 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright 2006 - 2007, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* start32.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + + .model small + .stack + .486p + .code + +FAT_DIRECTORY_ENTRY_SIZE EQU 020h +FAT_DIRECTORY_ENTRY_SHIFT EQU 5 +BLOCK_SIZE EQU 0200h +BLOCK_MASK EQU 01ffh +BLOCK_SHIFT EQU 9 + + org 0h +Ia32Jump: + jmp BootSectorEntryPoint ; JMP inst - 3 bytes + nop + +OemId db "INTEL " ; OemId - 8 bytes +SectorSize dw 0 ; Sector Size - 2 bytes +SectorsPerCluster db 0 ; Sector Per Cluster - 1 byte +ReservedSectors dw 0 ; Reserved Sectors - 2 bytes +NoFats db 0 ; Number of FATs - 1 byte +RootEntries dw 0 ; Root Entries - 2 bytes +Sectors dw 0 ; Number of Sectors - 2 bytes +Media db 0 ; Media - 1 byte +SectorsPerFat16 dw 0 ; Sectors Per FAT for FAT12/FAT16 - 2 byte +SectorsPerTrack dw 0 ; Sectors Per Track - 2 bytes +Heads dw 0 ; Heads - 2 bytes +HiddenSectors dd 0 ; Hidden Sectors - 4 bytes +LargeSectors dd 0 ; Large Sectors - 4 bytes + +;****************************************************************************** +; +;The structure for FAT32 starting at offset 36 of the boot sector. (At this point, +;the BPB/boot sector for FAT12 and FAT16 differs from the BPB/boot sector for FAT32.) +; +;****************************************************************************** + +SectorsPerFat32 dd 0 ; Sectors Per FAT for FAT32 - 4 bytes +ExtFlags dw 0 ; Mirror Flag - 2 bytes +FSVersion dw 0 ; File System Version - 2 bytes +RootCluster dd 0 ; 1st Cluster Number of Root Dir - 4 bytes +FSInfo dw 0 ; Sector Number of FSINFO - 2 bytes +BkBootSector dw 0 ; Sector Number of Bk BootSector - 2 bytes +Reserved db 12 dup(0) ; Reserved Field - 12 bytes +PhysicalDrive db 0 ; Physical Drive Number - 1 byte +Reserved1 db 0 ; Reserved Field - 1 byte +Signature db 0 ; Extended Boot Signature - 1 byte +VolId db " " ; Volume Serial Number - 4 bytes +FatLabel db " " ; Volume Label - 11 bytes +FileSystemType db "FAT32 " ; File System Type - 8 bytes + +BootSectorEntryPoint: + ASSUME ds:@code + ASSUME ss:@code + ; ds = 1000, es = 2000 + x (size of first cluster >> 4) + ; cx = Start Cluster of EfiLdr + ; dx = Start Cluster of Efivar.bin + +; Re use the BPB data stored in Boot Sector + mov bp,07c00h + + + push cx +; Read Efivar.bin +; 1000:dx = DirectoryEntry of Efivar.bin -> BS.com has filled already + mov ax,01900h + mov es,ax + test dx,dx + jnz CheckVarStoreSize + + mov al,1 +NoVarStore: + push es +; Set the 5th byte start @ 0:19000 to non-zero indicating we should init var store header in DxeIpl + mov byte ptr es:[4],al + jmp SaveVolumeId + +CheckVarStoreSize: + mov di,dx + cmp dword ptr ds:[di+2], 04000h + mov al,2 + jne NoVarStore + +LoadVarStore: + mov al,0 + mov byte ptr es:[4],al + mov cx,word ptr[di] +; ES:DI = 1500:0 + xor di,di + push es + mov ax,01500h + mov es,ax + call ReadFile +SaveVolumeId: + pop es + mov ax,word ptr [bp+VolId] + mov word ptr es:[0],ax ; Save Volume Id to 0:19000. we will find the correct volume according to this VolumeId + mov ax,word ptr [bp+VolId+2] + mov word ptr es:[2],ax + +; Read Efildr + pop cx +; cx = Start Cluster of Efildr -> BS.com has filled already +; ES:DI = 2000:0, first cluster will be read again + xor di,di ; di = 0 + mov ax,02000h + mov es,ax + call ReadFile + mov ax,cs + mov word ptr cs:[JumpSegment],ax +JumpFarInstruction: + db 0eah +JumpOffset: + dw 0200h +JumpSegment: + dw 2000h + + + + +; **************************************************************************** +; ReadFile +; +; Arguments: +; CX = Start Cluster of File +; ES:DI = Buffer to store file content read from disk +; +; Return: +; (ES << 4 + DI) = end of file content Buffer +; +; **************************************************************************** +ReadFile: +; si = NumberOfClusters +; cx = ClusterNumber +; dx = CachedFatSectorNumber +; ds:0000 = CacheFatSectorBuffer +; es:di = Buffer to load file +; bx = NextClusterNumber + pusha + mov si,1 ; NumberOfClusters = 1 + push cx ; Push Start Cluster onto stack + mov dx,0fffh ; CachedFatSectorNumber = 0xfff +FatChainLoop: + mov ax,cx ; ax = ClusterNumber + and ax,0fff8h ; ax = ax & 0xfff8 + cmp ax,0fff8h ; See if this is the last cluster + je FoundLastCluster ; Jump if last cluster found + mov ax,cx ; ax = ClusterNumber + shl ax,2 ; FatOffset = ClusterNumber * 4 + push si ; Save si + mov si,ax ; si = FatOffset + shr ax,BLOCK_SHIFT ; ax = FatOffset >> BLOCK_SHIFT + add ax,word ptr [bp+ReservedSectors] ; ax = FatSectorNumber = ReservedSectors + (FatOffset >> BLOCK_OFFSET) + and si,BLOCK_MASK ; si = FatOffset & BLOCK_MASK + cmp ax,dx ; Compare FatSectorNumber to CachedFatSectorNumber + je SkipFatRead + mov bx,2 + push es + push ds + pop es + call ReadBlocks ; Read 2 blocks starting at AX storing at ES:DI + pop es + mov dx,ax ; CachedFatSectorNumber = FatSectorNumber +SkipFatRead: + mov bx,word ptr [si] ; bx = NextClusterNumber + mov ax,cx ; ax = ClusterNumber + pop si ; Restore si + dec bx ; bx = NextClusterNumber - 1 + cmp bx,cx ; See if (NextClusterNumber-1)==ClusterNumber + jne ReadClusters + inc bx ; bx = NextClusterNumber + inc si ; NumberOfClusters++ + mov cx,bx ; ClusterNumber = NextClusterNumber + jmp FatChainLoop +ReadClusters: + inc bx + pop ax ; ax = StartCluster + push bx ; StartCluster = NextClusterNumber + mov cx,bx ; ClusterNumber = NextClusterNumber + sub ax,2 ; ax = StartCluster - 2 + xor bh,bh + mov bl,byte ptr [bp+SectorsPerCluster] ; bx = SectorsPerCluster + mul bx ; ax = (StartCluster - 2) * SectorsPerCluster + add ax, word ptr [bp] ; ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster + push ax ; save start sector + mov ax,si ; ax = NumberOfClusters + mul bx ; ax = NumberOfClusters * SectorsPerCluster + mov bx,ax ; bx = Number of Sectors + pop ax ; ax = Start Sector + call ReadBlocks + mov si,1 ; NumberOfClusters = 1 + jmp FatChainLoop +FoundLastCluster: + pop cx + popa + ret + + +; **************************************************************************** +; ReadBlocks - Reads a set of blocks from a block device +; +; AX = Start LBA +; BX = Number of Blocks to Read +; ES:DI = Buffer to store sectors read from disk +; **************************************************************************** + +; cx = Blocks +; bx = NumberOfBlocks +; si = StartLBA + +ReadBlocks: + pusha + add eax,dword ptr [bp+LBAOffsetForBootSector] ; Add LBAOffsetForBootSector to Start LBA + add eax,dword ptr [bp+HiddenSectors] ; Add HiddenSectors to Start LBA + mov esi,eax ; esi = Start LBA + mov cx,bx ; cx = Number of blocks to read +ReadCylinderLoop: + mov bp,07bfch ; bp = 0x7bfc + mov eax,esi ; eax = Start LBA + xor edx,edx ; edx = 0 + movzx ebx,word ptr [bp] ; bx = MaxSector + div ebx ; ax = StartLBA / MaxSector + inc dx ; dx = (StartLBA % MaxSector) + 1 + + mov bx,word ptr [bp] ; bx = MaxSector + sub bx,dx ; bx = MaxSector - Sector + inc bx ; bx = MaxSector - Sector + 1 + cmp cx,bx ; Compare (Blocks) to (MaxSector - Sector + 1) + jg LimitTransfer + mov bx,cx ; bx = Blocks +LimitTransfer: + push ax ; save ax + mov ax,es ; ax = es + shr ax,(BLOCK_SHIFT-4) ; ax = Number of blocks into mem system + and ax,07fh ; ax = Number of blocks into current seg + add ax,bx ; ax = End Block number of transfer + cmp ax,080h ; See if it crosses a 64K boundry + jle NotCrossing64KBoundry ; Branch if not crossing 64K boundry + sub ax,080h ; ax = Number of blocks past 64K boundry + sub bx,ax ; Decrease transfer size by block overage +NotCrossing64KBoundry: + pop ax ; restore ax + + push cx + mov cl,dl ; cl = (StartLBA % MaxSector) + 1 = Sector + xor dx,dx ; dx = 0 + div word ptr [bp+2] ; ax = ax / (MaxHead + 1) = Cylinder + ; dx = ax % (MaxHead + 1) = Head + + push bx ; Save number of blocks to transfer + mov dh,dl ; dh = Head + mov bp,07c00h ; bp = 0x7c00 + mov dl,byte ptr [bp+PhysicalDrive] ; dl = Drive Number + mov ch,al ; ch = Cylinder + mov al,bl ; al = Blocks + mov ah,2 ; ah = Function 2 + mov bx,di ; es:bx = Buffer address + int 013h + jc DiskError + pop bx + pop cx + movzx ebx,bx + add esi,ebx ; StartLBA = StartLBA + NumberOfBlocks + sub cx,bx ; Blocks = Blocks - NumberOfBlocks + mov ax,es + shl bx,(BLOCK_SHIFT-4) + add ax,bx + mov es,ax ; es:di = es:di + NumberOfBlocks*BLOCK_SIZE + cmp cx,0 + jne ReadCylinderLoop + popa + ret + +DiskError: + push cs + pop ds + lea si, [ErrorString] + mov cx, 7 + jmp PrintStringAndHalt + +PrintStringAndHalt: + mov ax,0b800h + mov es,ax + mov di,160 + rep movsw +Halt: + jmp Halt + +ErrorString: + db 'S', 0ch, 'E', 0ch, 'r', 0ch, 'r', 0ch, 'o', 0ch, 'r', 0ch, '!', 0ch + + org 01fah +LBAOffsetForBootSector: + dd 0h + + org 01feh + dw 0aa55h + +;****************************************************************************** +;****************************************************************************** +;****************************************************************************** + +DELAY_PORT equ 0edh ; Port to use for 1uS delay +KBD_CONTROL_PORT equ 060h ; 8042 control port +KBD_STATUS_PORT equ 064h ; 8042 status port +WRITE_DATA_PORT_CMD equ 0d1h ; 8042 command to write the data port +ENABLE_A20_CMD equ 0dfh ; 8042 command to enable A20 + + org 200h + jmp start +Em64String: + db 'E', 0ch, 'm', 0ch, '6', 0ch, '4', 0ch, 'T', 0ch, ' ', 0ch, 'U', 0ch, 'n', 0ch, 's', 0ch, 'u', 0ch, 'p', 0ch, 'p', 0ch, 'o', 0ch, 'r', 0ch, 't', 0ch, 'e', 0ch, 'd', 0ch, '!', 0ch + +start: + mov ax,cs + mov ds,ax + mov es,ax + mov ss,ax + mov sp,MyStack + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[160],'a' +; mov ax,cs +; mov es,ax + + mov ebx,0 + lea edi,MemoryMap +MemMapLoop: + mov eax,0e820h + mov ecx,20 + mov edx,'SMAP' + int 15h + jc MemMapDone + add edi,20 + cmp ebx,0 + je MemMapDone + jmp MemMapLoop +MemMapDone: + lea eax,MemoryMap + sub edi,eax ; Get the address of the memory map + mov dword ptr [MemoryMapSize],edi ; Save the size of the memory map + + xor ebx,ebx + mov bx,cs ; BX=segment + shl ebx,4 ; BX="linear" address of segment base + lea eax,[GDT_BASE + ebx] ; EAX=PHYSICAL address of gdt + mov dword ptr [gdtr + 2],eax ; Put address of gdt into the gdtr + lea eax,[IDT_BASE + ebx] ; EAX=PHYSICAL address of idt + mov dword ptr [idtr + 2],eax ; Put address of idt into the idtr + lea edx,[MemoryMapSize + ebx] ; Physical base address of the memory map + + add ebx,01000h ; Source of EFI32 + mov dword ptr [JUMP+2],ebx + add ebx,01000h + mov esi,ebx ; Source of EFILDR32 + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[162],'b' +; mov ax,cs +; mov es,ax + +; +; Enable A20 Gate +; + + mov ax,2401h ; Enable A20 Gate + int 15h + jnc A20GateEnabled ; Jump if it suceeded + +; +; If INT 15 Function 2401 is not supported, then attempt to Enable A20 manually. +; + + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + jnz Timeout8042 ; Jump if the 8042 timed out + out DELAY_PORT,ax ; Delay 1 uS + mov al,WRITE_DATA_PORT_CMD ; 8042 cmd to write output port + out KBD_STATUS_PORT,al ; Send command to the 8042 + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + jnz Timeout8042 ; Jump if the 8042 timed out + mov al,ENABLE_A20_CMD ; gate address bit 20 on + out KBD_CONTROL_PORT,al ; Send command to thre 8042 + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + mov cx,25 ; Delay 25 uS for the command to complete on the 8042 +Delay25uS: + out DELAY_PORT,ax ; Delay 1 uS + loop Delay25uS +Timeout8042: + + +A20GateEnabled: + +; +; DISABLE INTERRUPTS - Entering Protected Mode +; + + cli + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[164],'c' +; mov ax,cs +; mov es,ax + + db 66h + lgdt fword ptr [gdtr] + db 66h + lidt fword ptr [idtr] + + mov eax,cr0 + or al,1 + mov cr0,eax + + mov eax,0008h ; Flat data descriptor + mov ebp,000400000h ; Destination of EFILDR32 + mov ebx,000070000h ; Length of copy + +JUMP: +; jmp far 0010:00020000 + db 066h + db 0eah + dd 000020000h + dw 00010h + +Empty8042InputBuffer: + mov cx,0 +Empty8042Loop: + out DELAY_PORT,ax ; Delay 1us + in al,KBD_STATUS_PORT ; Read the 8042 Status Port + and al,02h ; Check the Input Buffer Full Flag + loopnz Empty8042Loop ; Loop until the input buffer is empty or a timout of 65536 uS + ret + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; data +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + align 02h + +gdtr dw GDT_END - GDT_BASE - 1 ; GDT limit + dd 0 ; (GDT base gets set above) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; global descriptor table (GDT) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + align 02h + +public GDT_BASE +GDT_BASE: +; null descriptor +NULL_SEL equ $-GDT_BASE + dw 0 ; limit 15:0 + dw 0 ; base 15:0 + db 0 ; base 23:16 + db 0 ; type + db 0 ; limit 19:16, flags + db 0 ; base 31:24 + +; linear data segment descriptor +LINEAR_SEL equ $-GDT_BASE + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; linear code segment descriptor +LINEAR_CODE_SEL equ $-GDT_BASE + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system data segment descriptor +SYS_DATA_SEL equ $-GDT_BASE + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system code segment descriptor +SYS_CODE_SEL equ $-GDT_BASE + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; spare segment descriptor +SPARE3_SEL equ $-GDT_BASE + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +; spare segment descriptor +SPARE4_SEL equ $-GDT_BASE + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +; spare segment descriptor +SPARE5_SEL equ $-GDT_BASE + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +GDT_END: + + align 02h + + + +idtr dw IDT_END - IDT_BASE - 1 ; IDT limit + dd 0 ; (IDT base gets set above) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; interrupt descriptor table (IDT) +; +; Note: The hardware IRQ's specified in this table are the normal PC/AT IRQ +; mappings. This implementation only uses the system timer and all other +; IRQs will remain masked. The descriptors for vectors 33+ are provided +; for convenience. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;idt_tag db "IDT",0 + align 02h + +public IDT_BASE +IDT_BASE: +; divide by zero (INT 0) +DIV_ZERO_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; debug exception (INT 1) +DEBUG_EXCEPT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; NMI (INT 2) +NMI_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; soft breakpoint (INT 3) +BREAKPOINT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; overflow (INT 4) +OVERFLOW_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; bounds check (INT 5) +BOUNDS_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; invalid opcode (INT 6) +INVALID_OPCODE_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; device not available (INT 7) +DEV_NOT_AVAIL_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; double fault (INT 8) +DOUBLE_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; Coprocessor segment overrun - reserved (INT 9) +RSVD_INTR_SEL1 equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; invalid TSS (INT 0ah) +INVALID_TSS_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; segment not present (INT 0bh) +SEG_NOT_PRESENT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; stack fault (INT 0ch) +STACK_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; general protection (INT 0dh) +GP_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; page fault (INT 0eh) +PAGE_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; Intel reserved - do not use (INT 0fh) +RSVD_INTR_SEL2 equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; floating point error (INT 10h) +FLT_POINT_ERR_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; alignment check (INT 11h) +ALIGNMENT_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; machine check (INT 12h) +MACHINE_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; SIMD floating-point exception (INT 13h) +SIMD_EXCEPTION_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; 85 unspecified descriptors, First 12 of them are reserved, the rest are avail + db (85 * 8) dup(0) + +; IRQ 0 (System timer) - (INT 68h) +IRQ0_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 1 (8042 Keyboard controller) - (INT 69h) +IRQ1_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; Reserved - IRQ 2 redirect (IRQ 2) - DO NOT USE!!! - (INT 6ah) +IRQ2_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 3 (COM 2) - (INT 6bh) +IRQ3_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 4 (COM 1) - (INT 6ch) +IRQ4_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 5 (LPT 2) - (INT 6dh) +IRQ5_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 6 (Floppy controller) - (INT 6eh) +IRQ6_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 7 (LPT 1) - (INT 6fh) +IRQ7_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 8 (RTC Alarm) - (INT 70h) +IRQ8_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 9 - (INT 71h) +IRQ9_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 10 - (INT 72h) +IRQ10_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 11 - (INT 73h) +IRQ11_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 12 (PS/2 mouse) - (INT 74h) +IRQ12_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 13 (Floating point error) - (INT 75h) +IRQ13_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 14 (Secondary IDE) - (INT 76h) +IRQ14_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 15 (Primary IDE) - (INT 77h) +IRQ15_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +IDT_END: + + align 02h + +MemoryMapSize dd 0 +MemoryMap dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + + dd 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + org 0fe0h +MyStack: + ; below is the pieces of the IVT that is used to redirect INT 68h - 6fh + ; back to INT 08h - 0fh when in real mode... It is 'org'ed to a + ; known low address (20f00) so it can be set up by PlMapIrqToVect in + ; 8259.c + + int 8 + iret + + int 9 + iret + + int 10 + iret + + int 11 + iret + + int 12 + iret + + int 13 + iret + + int 14 + iret + + int 15 + iret + + + org 0ffeh +BlockSignature: + dw 0aa55h + + end diff --git a/DuetPkg/BootSector/start64.asm b/DuetPkg/BootSector/start64.asm new file mode 100644 index 0000000000..5491722e58 --- /dev/null +++ b/DuetPkg/BootSector/start64.asm @@ -0,0 +1,1147 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright 2006 - 2007, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* start64.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + + .model small + .stack + .486p + .code + +FAT_DIRECTORY_ENTRY_SIZE EQU 020h +FAT_DIRECTORY_ENTRY_SHIFT EQU 5 +BLOCK_SIZE EQU 0200h +BLOCK_MASK EQU 01ffh +BLOCK_SHIFT EQU 9 + + org 0h +Ia32Jump: + jmp BootSectorEntryPoint ; JMP inst - 3 bytes + nop + +OemId db "INTEL " ; OemId - 8 bytes + +SectorSize dw 0 ; Sector Size - 16 bits +SectorsPerCluster db 0 ; Sector Per Cluster - 8 bits +ReservedSectors dw 0 ; Reserved Sectors - 16 bits +NoFats db 0 ; Number of FATs - 8 bits +RootEntries dw 0 ; Root Entries - 16 bits +Sectors dw 0 ; Number of Sectors - 16 bits +Media db 0 ; Media - 8 bits - ignored +SectorsPerFat dw 0 ; Sectors Per FAT - 16 bits +SectorsPerTrack dw 0 ; Sectors Per Track - 16 bits - ignored +Heads dw 0 ; Heads - 16 bits - ignored +HiddenSectors dd 0 ; Hidden Sectors - 32 bits - ignored +LargeSectors dd 0 ; Large Sectors - 32 bits +PhysicalDrive db 0 ; PhysicalDriveNumber - 8 bits - ignored +CurrentHead db 0 ; Current Head - 8 bits +Signature db 0 ; Signature - 8 bits - ignored +VolId db " " ; Volume Serial Number- 4 bytes +FatLabel db " " ; Label - 11 bytes +SystemId db "FAT12 " ; SystemId - 8 bytes + +BootSectorEntryPoint: + ASSUME ds:@code + ASSUME ss:@code + ; ds = 1000, es = 2000 + x (size of first cluster >> 4) + ; cx = Start Cluster of EfiLdr + ; dx = Start Cluster of Efivar.bin + +; Re use the BPB data stored in Boot Sector + mov bp,07c00h + + push cx +; Read Efivar.bin +; 1000:dx = DirectoryEntry of Efivar.bin -> BS.com has filled already + mov ax,01900h + mov es,ax + test dx,dx + jnz CheckVarStoreSize + + mov al,1 +NoVarStore: + push es +; Set the 5th byte start @ 0:19000 to non-zero indicating we should init var store header in DxeIpl + mov byte ptr es:[4],al + jmp SaveVolumeId + +CheckVarStoreSize: + mov di,dx + cmp dword ptr ds:[di+2], 04000h + mov al,2 + jne NoVarStore + +LoadVarStore: + mov al,0 + mov byte ptr es:[4],al + mov cx,word ptr[di] +; ES:DI = 1500:0 + xor di,di + push es + mov ax,01500h + mov es,ax + call ReadFile +SaveVolumeId: + pop es + mov ax,word ptr [bp+VolId] + mov word ptr es:[0],ax ; Save Volume Id to 0:19000. we will find the correct volume according to this VolumeId + mov ax,word ptr [bp+VolId+2] + mov word ptr es:[2],ax + +; Read Efildr + pop cx +; cx = Start Cluster of Efildr -> BS.com has filled already +; ES:DI = 2000:0, first cluster will be read again + xor di,di ; di = 0 + mov ax,02000h + mov es,ax + call ReadFile + mov ax,cs + mov word ptr cs:[JumpSegment],ax + +CheckEm64T: + mov eax, 080000001h +; cpuid + dw 0A20Fh + bt edx, 29 + jc CheckEm64TPass + push cs + pop ds + lea si, [Em64String] + mov cx, 18 + jmp PrintStringAndHalt +CheckEm64TPass: +JumpFarInstruction: + db 0eah +JumpOffset: + dw 0200h +JumpSegment: + dw 2000h + + + +; **************************************************************************** +; ReadFile +; +; Arguments: +; CX = Start Cluster of File +; ES:DI = Buffer to store file content read from disk +; +; Return: +; (ES << 4 + DI) = end of file content Buffer +; +; **************************************************************************** +ReadFile: +; si = NumberOfClusters +; cx = ClusterNumber +; dx = CachedFatSectorNumber +; ds:0000 = CacheFatSectorBuffer +; es:di = Buffer to load file +; bx = NextClusterNumber + pusha + mov si,1 ; NumberOfClusters = 1 + push cx ; Push Start Cluster onto stack + mov dx,0fffh ; CachedFatSectorNumber = 0xfff +FatChainLoop: + mov ax,cx ; ax = ClusterNumber + and ax,0ff8h ; ax = ax & 0xff8 + cmp ax,0ff8h ; See if this is the last cluster + je FoundLastCluster ; Jump if last cluster found + mov ax,cx ; ax = ClusterNumber + shl ax,1 ; ax = ClusterNumber * 2 + add ax,cx ; ax = ClusterNumber * 2 + ClusterNumber = ClusterNumber * 3 + shr ax,1 ; FatOffset = ClusterNumber*3 / 2 + push si ; Save si + mov si,ax ; si = FatOffset + shr ax,BLOCK_SHIFT ; ax = FatOffset >> BLOCK_SHIFT + add ax,word ptr [bp+ReservedSectors] ; ax = FatSectorNumber = ReservedSectors + (FatOffset >> BLOCK_OFFSET) + and si,BLOCK_MASK ; si = FatOffset & BLOCK_MASK + cmp ax,dx ; Compare FatSectorNumber to CachedFatSectorNumber + je SkipFatRead + mov bx,2 + push es + push ds + pop es + call ReadBlocks ; Read 2 blocks starting at AX storing at ES:DI + pop es + mov dx,ax ; CachedFatSectorNumber = FatSectorNumber +SkipFatRead: + mov bx,word ptr [si] ; bx = NextClusterNumber + mov ax,cx ; ax = ClusterNumber + and ax,1 ; See if this is an odd cluster number + je EvenFatEntry + shr bx,4 ; NextClusterNumber = NextClusterNumber >> 4 +EvenFatEntry: + and bx,0fffh ; Strip upper 4 bits of NextClusterNumber + pop si ; Restore si + dec bx ; bx = NextClusterNumber - 1 + cmp bx,cx ; See if (NextClusterNumber-1)==ClusterNumber + jne ReadClusters + inc bx ; bx = NextClusterNumber + inc si ; NumberOfClusters++ + mov cx,bx ; ClusterNumber = NextClusterNumber + jmp FatChainLoop +ReadClusters: + inc bx + pop ax ; ax = StartCluster + push bx ; StartCluster = NextClusterNumber + mov cx,bx ; ClusterNumber = NextClusterNumber + sub ax,2 ; ax = StartCluster - 2 + xor bh,bh + mov bl,byte ptr [bp+SectorsPerCluster] ; bx = SectorsPerCluster + mul bx ; ax = (StartCluster - 2) * SectorsPerCluster + add ax, word ptr [bp] ; ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster + push ax ; save start sector + mov ax,si ; ax = NumberOfClusters + mul bx ; ax = NumberOfClusters * SectorsPerCluster + mov bx,ax ; bx = Number of Sectors + pop ax ; ax = Start Sector + call ReadBlocks + mov si,1 ; NumberOfClusters = 1 + jmp FatChainLoop +FoundLastCluster: + pop cx + popa + ret + + +; **************************************************************************** +; ReadBlocks - Reads a set of blocks from a block device +; +; AX = Start LBA +; BX = Number of Blocks to Read +; ES:DI = Buffer to store sectors read from disk +; **************************************************************************** + +; cx = Blocks +; bx = NumberOfBlocks +; si = StartLBA + +ReadBlocks: + pusha + add eax,dword ptr [bp+LBAOffsetForBootSector] ; Add LBAOffsetForBootSector to Start LBA + add eax,dword ptr [bp+HiddenSectors] ; Add HiddenSectors to Start LBA + mov esi,eax ; esi = Start LBA + mov cx,bx ; cx = Number of blocks to read +ReadCylinderLoop: + mov bp,07bfch ; bp = 0x7bfc + mov eax,esi ; eax = Start LBA + xor edx,edx ; edx = 0 + movzx ebx,word ptr [bp] ; bx = MaxSector + div ebx ; ax = StartLBA / MaxSector + inc dx ; dx = (StartLBA % MaxSector) + 1 + + mov bx,word ptr [bp] ; bx = MaxSector + sub bx,dx ; bx = MaxSector - Sector + inc bx ; bx = MaxSector - Sector + 1 + cmp cx,bx ; Compare (Blocks) to (MaxSector - Sector + 1) + jg LimitTransfer + mov bx,cx ; bx = Blocks +LimitTransfer: + push ax ; save ax + mov ax,es ; ax = es + shr ax,(BLOCK_SHIFT-4) ; ax = Number of blocks into mem system + and ax,07fh ; ax = Number of blocks into current seg + add ax,bx ; ax = End Block number of transfer + cmp ax,080h ; See if it crosses a 64K boundry + jle NotCrossing64KBoundry ; Branch if not crossing 64K boundry + sub ax,080h ; ax = Number of blocks past 64K boundry + sub bx,ax ; Decrease transfer size by block overage +NotCrossing64KBoundry: + pop ax ; restore ax + + push cx + mov cl,dl ; cl = (StartLBA % MaxSector) + 1 = Sector + xor dx,dx ; dx = 0 + div word ptr [bp+2] ; ax = ax / (MaxHead + 1) = Cylinder + ; dx = ax % (MaxHead + 1) = Head + + push bx ; Save number of blocks to transfer + mov dh,dl ; dh = Head + mov bp,07c00h ; bp = 0x7c00 + mov dl,byte ptr [bp+PhysicalDrive] ; dl = Drive Number + mov ch,al ; ch = Cylinder + mov al,bl ; al = Blocks + mov ah,2 ; ah = Function 2 + mov bx,di ; es:bx = Buffer address + int 013h + jc DiskError + pop bx + pop cx + movzx ebx,bx + add esi,ebx ; StartLBA = StartLBA + NumberOfBlocks + sub cx,bx ; Blocks = Blocks - NumberOfBlocks + mov ax,es + shl bx,(BLOCK_SHIFT-4) + add ax,bx + mov es,ax ; es:di = es:di + NumberOfBlocks*BLOCK_SIZE + cmp cx,0 + jne ReadCylinderLoop + popa + ret + +DiskError: + push cs + pop ds + lea si, [ErrorString] + mov cx, 7 + jmp PrintStringAndHalt + +PrintStringAndHalt: + mov ax,0b800h + mov es,ax + mov di,160 + rep movsw +Halt: + jmp Halt + +ErrorString: + db 'S', 0ch, 'E', 0ch, 'r', 0ch, 'r', 0ch, 'o', 0ch, 'r', 0ch, '!', 0ch + + org 01fah +LBAOffsetForBootSector: + dd 0h + + org 01feh + dw 0aa55h + +;****************************************************************************** +;****************************************************************************** +;****************************************************************************** + +DELAY_PORT equ 0edh ; Port to use for 1uS delay +KBD_CONTROL_PORT equ 060h ; 8042 control port +KBD_STATUS_PORT equ 064h ; 8042 status port +WRITE_DATA_PORT_CMD equ 0d1h ; 8042 command to write the data port +ENABLE_A20_CMD equ 0dfh ; 8042 command to enable A20 + + org 200h + jmp start +Em64String: + db 'E', 0ch, 'm', 0ch, '6', 0ch, '4', 0ch, 'T', 0ch, ' ', 0ch, 'U', 0ch, 'n', 0ch, 's', 0ch, 'u', 0ch, 'p', 0ch, 'p', 0ch, 'o', 0ch, 'r', 0ch, 't', 0ch, 'e', 0ch, 'd', 0ch, '!', 0ch + +start: + mov ax,cs + mov ds,ax + mov es,ax + mov ss,ax + mov sp,MyStack + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[160],'a' +; mov ax,cs +; mov es,ax + + mov ebx,0 + lea edi,MemoryMap +MemMapLoop: + mov eax,0e820h + mov ecx,20 + mov edx,'SMAP' + int 15h + jc MemMapDone + add edi,20 + cmp ebx,0 + je MemMapDone + jmp MemMapLoop +MemMapDone: + lea eax,MemoryMap + sub edi,eax ; Get the address of the memory map + mov dword ptr [MemoryMapSize],edi ; Save the size of the memory map + + xor ebx,ebx + mov bx,cs ; BX=segment + shl ebx,4 ; BX="linear" address of segment base + lea eax,[GDT_BASE + ebx] ; EAX=PHYSICAL address of gdt + mov dword ptr [gdtr + 2],eax ; Put address of gdt into the gdtr + lea eax,[IDT_BASE + ebx] ; EAX=PHYSICAL address of idt + mov dword ptr [idtr + 2],eax ; Put address of idt into the idtr + lea edx,[MemoryMapSize + ebx] ; Physical base address of the memory map + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[162],'b' +; mov ax,cs +; mov es,ax + +; +; Enable A20 Gate +; + + mov ax,2401h ; Enable A20 Gate + int 15h + jnc A20GateEnabled ; Jump if it suceeded + +; +; If INT 15 Function 2401 is not supported, then attempt to Enable A20 manually. +; + + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + jnz Timeout8042 ; Jump if the 8042 timed out + out DELAY_PORT,ax ; Delay 1 uS + mov al,WRITE_DATA_PORT_CMD ; 8042 cmd to write output port + out KBD_STATUS_PORT,al ; Send command to the 8042 + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + jnz Timeout8042 ; Jump if the 8042 timed out + mov al,ENABLE_A20_CMD ; gate address bit 20 on + out KBD_CONTROL_PORT,al ; Send command to thre 8042 + call Empty8042InputBuffer ; Empty the Input Buffer on the 8042 controller + mov cx,25 ; Delay 25 uS for the command to complete on the 8042 +Delay25uS: + out DELAY_PORT,ax ; Delay 1 uS + loop Delay25uS +Timeout8042: + + +A20GateEnabled: + +; +; DISABLE INTERRUPTS - Entering Protected Mode +; + + cli + +; mov ax,0b800h +; mov es,ax +; mov byte ptr es:[164],'c' +; mov ax,cs +; mov es,ax + + lea eax, OffsetIn32BitProtectedMode + add eax, 20000h + 6h + mov dword ptr[OffsetIn32BitProtectedMode], eax + + lea eax, OffsetInLongMode + add eax, 20000h + 6h + mov dword ptr[OffsetInLongMode], eax + + ; + ; load GDT + ; + db 66h + lgdt fword ptr [gdtr] + + ; + ; Enable Protect Mode (set CR0.PE=1) + ; + mov eax, cr0 ; Read CR0. + or eax, 1h ; Set PE=1 + mov cr0, eax ; Write CR0. + db 066h + db 0eah ; jmp far 16:32 +OffsetIn32BitProtectedMode: + dd 00000000h ; offset $+8 (In32BitProtectedMode) + dw 10h ; selector (flat CS) +In32BitProtectedMode: + +; +; Entering Long Mode +; + db 66h + mov ax, 8 + mov ds, ax + mov es, ax + mov ss, ax + + ; + ; Enable the 64-bit page-translation-table entries by + ; setting CR4.PAE=1 (this is _required_ before activating + ; long mode). Paging is not enabled until after long mode + ; is enabled. + ; + db 0fh + db 20h + db 0e0h +; mov eax, cr4 + bts eax, 5 + db 0fh + db 22h + db 0e0h +; mov cr4, eax + + ; + ; This is the Trapolean Page Tables that are guarenteed + ; under 4GB. + ; + ; Address Map: + ; 10000 ~ 12000 - efildr (loaded) + ; 20000 ~ 21000 - start64.com + ; 21000 ~ 22000 - efi64.com + ; 22000 ~ 90000 - efildr + ; 90000 ~ 96000 - 4G pagetable (will be reload later) + ; + db 0b8h + dd 90000h +; mov eax, 90000h + mov cr3, eax + + ; + ; Enable long mode (set EFER.LME=1). + ; + db 0b9h + dd 0c0000080h +; mov ecx, 0c0000080h ; EFER MSR number. + db 0fh + db 32h +; rdmsr ; Read EFER. + db 0fh + db 0bah + db 0e8h + db 08h +; bts eax, 8 ; Set LME=1. + db 0fh + db 30h +; wrmsr ; Write EFER. + + ; + ; Enable paging to activate long mode (set CR0.PG=1) + ; + mov eax, cr0 ; Read CR0. + db 0fh + db 0bah + db 0e8h + db 01fh +; bts eax, 31 ; Set PG=1. + mov cr0, eax ; Write CR0. + jmp GoToLongMode +GoToLongMode: + + db 067h + db 0eah ; Far Jump $+9:Selector to reload CS +OffsetInLongMode: + dd 00000000 ; $+9 Offset is ensuing instruction boundary + dw 038h ; Selector is our code selector, 38h + +InLongMode: + db 66h + mov ax, 30h + mov ds, ax + + db 66h + mov ax, 18h + mov es, ax + mov ss, ax + mov ds, ax + + db 0bdh + dd 400000h +; mov ebp,000400000h ; Destination of EFILDR32 + db 0bbh + dd 70000h +; mov ebx,000070000h ; Length of copy + + ; + ; load idt later + ; + db 48h + db 33h + db 0c0h +; xor rax, rax + db 66h + mov ax, offset idtr + db 48h + db 05h + dd 20000h +; add rax, 20000h + + db 0fh + db 01h + db 18h +; lidt fword ptr [rax] + + db 48h + db 0c7h + db 0c0h + dd 21000h +; mov rax, 21000h + db 50h +; push rax + +; ret + db 0c3h + +Empty8042InputBuffer: + mov cx,0 +Empty8042Loop: + out DELAY_PORT,ax ; Delay 1us + in al,KBD_STATUS_PORT ; Read the 8042 Status Port + and al,02h ; Check the Input Buffer Full Flag + loopnz Empty8042Loop ; Loop until the input buffer is empty or a timout of 65536 uS + ret + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; data +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + align 02h + +gdtr dw GDT_END - GDT_BASE - 1 ; GDT limit + dd 0 ; (GDT base gets set above) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; global descriptor table (GDT) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + align 02h + +public GDT_BASE +GDT_BASE: +; null descriptor +NULL_SEL equ $-GDT_BASE ; Selector [0x0] + dw 0 ; limit 15:0 + dw 0 ; base 15:0 + db 0 ; base 23:16 + db 0 ; type + db 0 ; limit 19:16, flags + db 0 ; base 31:24 + +; linear data segment descriptor +LINEAR_SEL equ $-GDT_BASE ; Selector [0x8] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; linear code segment descriptor +LINEAR_CODE_SEL equ $-GDT_BASE ; Selector [0x10] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system data segment descriptor +SYS_DATA_SEL equ $-GDT_BASE ; Selector [0x18] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system code segment descriptor +SYS_CODE_SEL equ $-GDT_BASE ; Selector [0x20] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; spare segment descriptor +SPARE3_SEL equ $-GDT_BASE ; Selector [0x28] + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +; +; system data segment descriptor +; +SYS_DATA64_SEL equ $-GDT_BASE ; Selector [0x30] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; P | DPL [1..2] | 1 | 1 | C | R | A + db 0CFh ; G | D | L | AVL | Segment [19..16] + db 0 + +; +; system code segment descriptor +; +SYS_CODE64_SEL equ $-GDT_BASE ; Selector [0x38] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; P | DPL [1..2] | 1 | 1 | C | R | A + db 0AFh ; G | D | L | AVL | Segment [19..16] + db 0 + +; spare segment descriptor +SPARE4_SEL equ $-GDT_BASE ; Selector [0x40] + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +GDT_END: + + align 02h + + + +idtr dw IDT_END - IDT_BASE - 1 ; IDT limit + dq 0 ; (IDT base gets set above) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; interrupt descriptor table (IDT) +; +; Note: The hardware IRQ's specified in this table are the normal PC/AT IRQ +; mappings. This implementation only uses the system timer and all other +; IRQs will remain masked. The descriptors for vectors 33+ are provided +; for convenience. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;idt_tag db "IDT",0 + align 02h + +public IDT_BASE +IDT_BASE: +; divide by zero (INT 0) +DIV_ZERO_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; debug exception (INT 1) +DEBUG_EXCEPT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; NMI (INT 2) +NMI_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; soft breakpoint (INT 3) +BREAKPOINT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; overflow (INT 4) +OVERFLOW_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; bounds check (INT 5) +BOUNDS_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; invalid opcode (INT 6) +INVALID_OPCODE_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; device not available (INT 7) +DEV_NOT_AVAIL_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; double fault (INT 8) +DOUBLE_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; Coprocessor segment overrun - reserved (INT 9) +RSVD_INTR_SEL1 equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; invalid TSS (INT 0ah) +INVALID_TSS_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; segment not present (INT 0bh) +SEG_NOT_PRESENT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; stack fault (INT 0ch) +STACK_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; general protection (INT 0dh) +GP_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; page fault (INT 0eh) +PAGE_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; Intel reserved - do not use (INT 0fh) +RSVD_INTR_SEL2 equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; floating point error (INT 10h) +FLT_POINT_ERR_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; alignment check (INT 11h) +ALIGNMENT_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; machine check (INT 12h) +MACHINE_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; SIMD floating-point exception (INT 13h) +SIMD_EXCEPTION_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; 85 unspecified descriptors, First 12 of them are reserved, the rest are avail + db (85 * 16) dup(0) + +; IRQ 0 (System timer) - (INT 68h) +IRQ0_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 1 (8042 Keyboard controller) - (INT 69h) +IRQ1_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; Reserved - IRQ 2 redirect (IRQ 2) - DO NOT USE!!! - (INT 6ah) +IRQ2_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 3 (COM 2) - (INT 6bh) +IRQ3_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 4 (COM 1) - (INT 6ch) +IRQ4_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 5 (LPT 2) - (INT 6dh) +IRQ5_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 6 (Floppy controller) - (INT 6eh) +IRQ6_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 7 (LPT 1) - (INT 6fh) +IRQ7_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 8 (RTC Alarm) - (INT 70h) +IRQ8_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 9 - (INT 71h) +IRQ9_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 10 - (INT 72h) +IRQ10_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 11 - (INT 73h) +IRQ11_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 12 (PS/2 mouse) - (INT 74h) +IRQ12_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 13 (Floating point error) - (INT 75h) +IRQ13_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 14 (Secondary IDE) - (INT 76h) +IRQ14_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 15 (Primary IDE) - (INT 77h) +IRQ15_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +IDT_END: + + align 02h + +MemoryMapSize dd 0 +MemoryMap dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0 + + dd 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dd 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + org 0fe0h +MyStack: + ; below is the pieces of the IVT that is used to redirect INT 68h - 6fh + ; back to INT 08h - 0fh when in real mode... It is 'org'ed to a + ; known low address (20f00) so it can be set up by PlMapIrqToVect in + ; 8259.c + + int 8 + iret + + int 9 + iret + + int 10 + iret + + int 11 + iret + + int 12 + iret + + int 13 + iret + + int 14 + iret + + int 15 + iret + + + org 0ffeh +BlockSignature: + dw 0aa55h + + end diff --git a/DuetPkg/CpuDxe/Cpu.c b/DuetPkg/CpuDxe/Cpu.c new file mode 100644 index 0000000000..1390a89d57 --- /dev/null +++ b/DuetPkg/CpuDxe/Cpu.c @@ -0,0 +1,1151 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + Cpu.c + +Abstract: + +--*/ + +#include "CpuDxe.h" + +// +// Global Variables +// + +BOOLEAN mInterruptState = FALSE; +extern UINT32 mExceptionCodeSize; +UINTN mTimerVector = 0; +volatile EFI_CPU_INTERRUPT_HANDLER mTimerHandler = NULL; +EFI_LEGACY_8259_PROTOCOL *gLegacy8259 = NULL; + +// +// The Cpu Architectural Protocol that this Driver produces +// +EFI_HANDLE mHandle = NULL; +EFI_CPU_ARCH_PROTOCOL mCpu = { + CpuFlushCpuDataCache, + CpuEnableInterrupt, + CpuDisableInterrupt, + CpuGetInterruptState, + CpuInit, + CpuRegisterInterruptHandler, + CpuGetTimerValue, + CpuSetMemoryAttributes, + 1, // NumberOfTimers + 4, // DmaBufferAlignment +}; + +EFI_STATUS +EFIAPI +CpuFlushCpuDataCache ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length, + IN EFI_CPU_FLUSH_TYPE FlushType + ) +/*++ + +Routine Description: + Flush CPU data cache. If the instruction cache is fully coherent + with all DMA operations then function can just return EFI_SUCCESS. + +Arguments: + This - Protocol instance structure + Start - Physical address to start flushing from. + Length - Number of bytes to flush. Round up to chipset + granularity. + FlushType - Specifies the type of flush operation to perform. + +Returns: + + EFI_SUCCESS - If cache was flushed + EFI_UNSUPPORTED - If flush type is not supported. + EFI_DEVICE_ERROR - If requested range could not be flushed. + +--*/ +{ + if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) { + AsmWbinvd (); + return EFI_SUCCESS; + } else if (FlushType == EfiCpuFlushTypeInvalidate) { + AsmInvd (); + return EFI_SUCCESS; + } else { + return EFI_UNSUPPORTED; + } +} + + +EFI_STATUS +EFIAPI +CpuEnableInterrupt ( + IN EFI_CPU_ARCH_PROTOCOL *This + ) +/*++ + +Routine Description: + Enables CPU interrupts. + +Arguments: + This - Protocol instance structure + +Returns: + EFI_SUCCESS - If interrupts were enabled in the CPU + EFI_DEVICE_ERROR - If interrupts could not be enabled on the CPU. + +--*/ +{ + EnableInterrupts (); + + mInterruptState = TRUE; + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +CpuDisableInterrupt ( + IN EFI_CPU_ARCH_PROTOCOL *This + ) +/*++ + +Routine Description: + Disables CPU interrupts. + +Arguments: + This - Protocol instance structure + +Returns: + EFI_SUCCESS - If interrupts were disabled in the CPU. + EFI_DEVICE_ERROR - If interrupts could not be disabled on the CPU. + +--*/ +{ + DisableInterrupts (); + + mInterruptState = FALSE; + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +CpuGetInterruptState ( + IN EFI_CPU_ARCH_PROTOCOL *This, + OUT BOOLEAN *State + ) +/*++ + +Routine Description: + Return the state of interrupts. + +Arguments: + This - Protocol instance structure + State - Pointer to the CPU's current interrupt state + +Returns: + EFI_SUCCESS - If interrupts were disabled in the CPU. + EFI_INVALID_PARAMETER - State is NULL. + +--*/ +{ + if (State == NULL) { + return EFI_INVALID_PARAMETER; + } + + *State = mInterruptState; + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +CpuInit ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_CPU_INIT_TYPE InitType + ) + +/*++ + +Routine Description: + Generates an INIT to the CPU + +Arguments: + This - Protocol instance structure + InitType - Type of CPU INIT to perform + +Returns: + EFI_SUCCESS - If CPU INIT occurred. This value should never be + seen. + EFI_DEVICE_ERROR - If CPU INIT failed. + EFI_NOT_SUPPORTED - Requested type of CPU INIT not supported. + +--*/ +{ + return EFI_UNSUPPORTED; +} + + +EFI_STATUS +EFIAPI +CpuRegisterInterruptHandler ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +/*++ + +Routine Description: + Registers a function to be called from the CPU interrupt handler. + +Arguments: + This - Protocol instance structure + InterruptType - Defines which interrupt to hook. IA-32 valid range + is 0x00 through 0xFF + InterruptHandler - A pointer to a function of type + EFI_CPU_INTERRUPT_HANDLER that is called when a + processor interrupt occurs. A null pointer + is an error condition. + +Returns: + EFI_SUCCESS - If handler installed or uninstalled. + EFI_ALREADY_STARTED - InterruptHandler is not NULL, and a handler for + InterruptType was previously installed + EFI_INVALID_PARAMETER - InterruptHandler is NULL, and a handler for + InterruptType was not previously installed. + EFI_UNSUPPORTED - The interrupt specified by InterruptType is not + supported. + +--*/ +{ + if ((InterruptType < 0) || (InterruptType >= INTERRUPT_VECTOR_NUMBER)) { + return EFI_UNSUPPORTED; + } + if ((UINTN)(UINT32)InterruptType != mTimerVector) { + return EFI_UNSUPPORTED; + } + if ((mTimerHandler == NULL) && (InterruptHandler == NULL)) { + return EFI_INVALID_PARAMETER; + } else if ((mTimerHandler != NULL) && (InterruptHandler != NULL)) { + return EFI_ALREADY_STARTED; + } + mTimerHandler = InterruptHandler; + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +CpuGetTimerValue ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN UINT32 TimerIndex, + OUT UINT64 *TimerValue, + OUT UINT64 *TimerPeriod OPTIONAL + ) +/*++ + +Routine Description: + Returns a timer value from one of the CPU's internal timers. There is no + inherent time interval between ticks but is a function of the CPU + frequency. + +Arguments: + This - Protocol instance structure + TimerIndex - Specifies which CPU timer ie requested + TimerValue - Pointer to the returned timer value + TimerPeriod - + +Returns: + EFI_SUCCESS - If the CPU timer count was returned. + EFI_UNSUPPORTED - If the CPU does not have any readable timers + EFI_DEVICE_ERROR - If an error occurred reading the timer. + EFI_INVALID_PARAMETER - TimerIndex is not valid + +--*/ +{ + if (TimerValue == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (TimerIndex == 0) { + *TimerValue = AsmReadTsc (); + if (TimerPeriod != NULL) { + // + // BugBug: Hard coded. Don't know how to do this generically + // + *TimerPeriod = 1000000000; + } + return EFI_SUCCESS; + } + return EFI_INVALID_PARAMETER; +} + +EFI_STATUS +EFIAPI +CpuSetMemoryAttributes ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ) +/*++ + +Routine Description: + Set memory cacheability attributes for given range of memeory + +Arguments: + This - Protocol instance structure + BaseAddress - Specifies the start address of the memory range + Length - Specifies the length of the memory range + Attributes - The memory cacheability for the memory range + +Returns: + EFI_SUCCESS - If the cacheability of that memory range is set successfully + EFI_UNSUPPORTED - If the desired operation cannot be done + EFI_INVALID_PARAMETER - The input parameter is not correct, such as Length = 0 + +--*/ +{ + return EFI_UNSUPPORTED; +} + +#if CPU_EXCEPTION_DEBUG_OUTPUT +STATIC +VOID +DumpExceptionDataDebugOut ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINT32 ErrorCodeFlag; + + ErrorCodeFlag = 0x00027d00; + +#ifdef EFI32 + DEBUG (( + EFI_D_ERROR, + "!!!! IA32 Exception Type - %08x !!!!\n", + InterruptType + )); + DEBUG (( + EFI_D_ERROR, + "EIP - %08x, CS - %08x, EFLAGS - %08x\n", + SystemContext.SystemContextIa32->Eip, + SystemContext.SystemContextIa32->Cs, + SystemContext.SystemContextIa32->Eflags + )); + if (ErrorCodeFlag & (1 << InterruptType)) { + DEBUG (( + EFI_D_ERROR, + "ExceptionData - %08x\n", + SystemContext.SystemContextIa32->ExceptionData + )); + } + DEBUG (( + EFI_D_ERROR, + "EAX - %08x, ECX - %08x, EDX - %08x, EBX - %08x\n", + SystemContext.SystemContextIa32->Eax, + SystemContext.SystemContextIa32->Ecx, + SystemContext.SystemContextIa32->Edx, + SystemContext.SystemContextIa32->Ebx + )); + DEBUG (( + EFI_D_ERROR, + "ESP - %08x, EBP - %08x, ESI - %08x, EDI - %08x\n", + SystemContext.SystemContextIa32->Esp, + SystemContext.SystemContextIa32->Ebp, + SystemContext.SystemContextIa32->Esi, + SystemContext.SystemContextIa32->Edi + )); + DEBUG (( + EFI_D_ERROR, + "DS - %08x, ES - %08x, FS - %08x, GS - %08x, SS - %08x\n", + SystemContext.SystemContextIa32->Ds, + SystemContext.SystemContextIa32->Es, + SystemContext.SystemContextIa32->Fs, + SystemContext.SystemContextIa32->Gs, + SystemContext.SystemContextIa32->Ss + )); + DEBUG (( + EFI_D_ERROR, + "GDTR - %08x %08x, IDTR - %08x %08x\n", + SystemContext.SystemContextIa32->Gdtr[0], + SystemContext.SystemContextIa32->Gdtr[1], + SystemContext.SystemContextIa32->Idtr[0], + SystemContext.SystemContextIa32->Idtr[1] + )); + DEBUG (( + EFI_D_ERROR, + "LDTR - %08x, TR - %08x\n", + SystemContext.SystemContextIa32->Ldtr, + SystemContext.SystemContextIa32->Tr + )); + DEBUG (( + EFI_D_ERROR, + "CR0 - %08x, CR2 - %08x, CR3 - %08x, CR4 - %08x\n", + SystemContext.SystemContextIa32->Cr0, + SystemContext.SystemContextIa32->Cr2, + SystemContext.SystemContextIa32->Cr3, + SystemContext.SystemContextIa32->Cr4 + )); + DEBUG (( + EFI_D_ERROR, + "DR0 - %08x, DR1 - %08x, DR2 - %08x, DR3 - %08x\n", + SystemContext.SystemContextIa32->Dr0, + SystemContext.SystemContextIa32->Dr1, + SystemContext.SystemContextIa32->Dr2, + SystemContext.SystemContextIa32->Dr3 + )); + DEBUG (( + EFI_D_ERROR, + "DR6 - %08x, DR7 - %08x\n", + SystemContext.SystemContextIa32->Dr6, + SystemContext.SystemContextIa32->Dr7 + )); +#else + DEBUG (( + EFI_D_ERROR, + "!!!! X64 Exception Type - %016lx !!!!\n", + (UINT64)InterruptType + )); + DEBUG (( + EFI_D_ERROR, + "RIP - %016lx, CS - %016lx, RFLAGS - %016lx\n", + SystemContext.SystemContextX64->Rip, + SystemContext.SystemContextX64->Cs, + SystemContext.SystemContextX64->Rflags + )); + if (ErrorCodeFlag & (1 << InterruptType)) { + DEBUG (( + EFI_D_ERROR, + "ExceptionData - %016lx\n", + SystemContext.SystemContextX64->ExceptionData + )); + } + DEBUG (( + EFI_D_ERROR, + "RAX - %016lx, RCX - %016lx, RDX - %016lx\n", + SystemContext.SystemContextX64->Rax, + SystemContext.SystemContextX64->Rcx, + SystemContext.SystemContextX64->Rdx + )); + DEBUG (( + EFI_D_ERROR, + "RBX - %016lx, RSP - %016lx, RBP - %016lx\n", + SystemContext.SystemContextX64->Rbx, + SystemContext.SystemContextX64->Rsp, + SystemContext.SystemContextX64->Rbp + )); + DEBUG (( + EFI_D_ERROR, + "RSI - %016lx, RDI - %016lx\n", + SystemContext.SystemContextX64->Rsi, + SystemContext.SystemContextX64->Rdi + )); + DEBUG (( + EFI_D_ERROR, + "R8 - %016lx, R9 - %016lx, R10 - %016lx\n", + SystemContext.SystemContextX64->R8, + SystemContext.SystemContextX64->R9, + SystemContext.SystemContextX64->R10 + )); + DEBUG (( + EFI_D_ERROR, + "R11 - %016lx, R12 - %016lx, R13 - %016lx\n", + SystemContext.SystemContextX64->R11, + SystemContext.SystemContextX64->R12, + SystemContext.SystemContextX64->R13 + )); + DEBUG (( + EFI_D_ERROR, + "R14 - %016lx, R15 - %016lx\n", + SystemContext.SystemContextX64->R14, + SystemContext.SystemContextX64->R15 + )); + DEBUG (( + EFI_D_ERROR, + "DS - %016lx, ES - %016lx, FS - %016lx\n", + SystemContext.SystemContextX64->Ds, + SystemContext.SystemContextX64->Es, + SystemContext.SystemContextX64->Fs + )); + DEBUG (( + EFI_D_ERROR, + "GS - %016lx, SS - %016lx\n", + SystemContext.SystemContextX64->Gs, + SystemContext.SystemContextX64->Ss + )); + DEBUG (( + EFI_D_ERROR, + "GDTR - %016lx %016lx, LDTR - %016lx\n", + SystemContext.SystemContextX64->Gdtr[0], + SystemContext.SystemContextX64->Gdtr[1], + SystemContext.SystemContextX64->Ldtr + )); + DEBUG (( + EFI_D_ERROR, + "IDTR - %016lx %016lx, TR - %016lx\n", + SystemContext.SystemContextX64->Idtr[0], + SystemContext.SystemContextX64->Idtr[1], + SystemContext.SystemContextX64->Tr + )); + DEBUG (( + EFI_D_ERROR, + "CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n", + SystemContext.SystemContextX64->Cr0, + SystemContext.SystemContextX64->Cr2, + SystemContext.SystemContextX64->Cr3 + )); + DEBUG (( + EFI_D_ERROR, + "CR4 - %016lx, CR8 - %016lx\n", + SystemContext.SystemContextX64->Cr4, + SystemContext.SystemContextX64->Cr8 + )); + DEBUG (( + EFI_D_ERROR, + "DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n", + SystemContext.SystemContextX64->Dr0, + SystemContext.SystemContextX64->Dr1, + SystemContext.SystemContextX64->Dr2 + )); + DEBUG (( + EFI_D_ERROR, + "DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n", + SystemContext.SystemContextX64->Dr3, + SystemContext.SystemContextX64->Dr6, + SystemContext.SystemContextX64->Dr7 + )); +#endif + return ; +} +#endif + +STATIC +UINTN +SPrint ( + IN OUT CHAR16 *Buffer, + IN CONST CHAR16 *Format, + ... + ) +{ + VA_LIST Marker; + UINTN Index; + UINTN Flags; + UINTN Width; + UINT64 Value; + + VA_START (Marker, Format); + + // + // Process the format string. Stop if Buffer is over run. + // + + for (Index = 0; *Format != 0; Format++) { + if (*Format != L'%') { + Buffer[Index++] = *Format; + } else { + + // + // Now it's time to parse what follows after % + // Support: % [ 0 width ] [ l ] x + // width - fill 0, to ensure the width of x will be "width" + // l - UINT64 instead of UINT32 + // + Width = 0; + Flags = 0; + Format ++; + + if (*Format == L'0') { + Flags |= PREFIX_ZERO; + do { + Width += Width * 10 + (*Format - L'0'); + Format ++; + } while (*Format >= L'1' && *Format <= L'9'); + } + + if (*Format == L'l') { + Flags |= LONG_TYPE; + Format ++; + } + + + switch (*Format) { + case 'X': + Flags |= PREFIX_ZERO; + Width = sizeof (UINT64) * 2; + // + // break skiped on purpose + // + case 'x': + if ((Flags & LONG_TYPE) == LONG_TYPE) { + Value = VA_ARG (Marker, UINT64); + } else { + Value = VA_ARG (Marker, UINTN); + } + + UnicodeValueToString (Buffer+Index, Flags, Value, Width); + + for ( ; Buffer[Index] != L'\0'; Index ++) { + } + + break; + + default: + // + // if the type is unknown print it to the screen + // + Buffer[Index++] = *Format; + } + } + } + Buffer[Index++] = '\0'; + + VA_END (Marker); + return Index; +} + +STATIC +VOID +DumpExceptionDataVgaOut ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINTN COLUMN_MAX; + UINTN ROW_MAX; + UINT32 ErrorCodeFlag; + CHAR16 *VideoBufferBase; + CHAR16 *VideoBuffer; + UINTN Index; + + COLUMN_MAX = 80; + ROW_MAX = 25; + ErrorCodeFlag = 0x00027d00; + VideoBufferBase = (CHAR16 *) (UINTN) 0xb8000; + VideoBuffer = (CHAR16 *) (UINTN) 0xb8000; + +#ifdef EFI32 + SPrint ( + VideoBuffer, + L"!!!! IA32 Exception Type - %08x !!!!", + InterruptType + ); + VideoBuffer += COLUMN_MAX; + SPrint ( + VideoBuffer, + L"EIP - %08x, CS - %08x, EFLAGS - %08x", + SystemContext.SystemContextIa32->Eip, + SystemContext.SystemContextIa32->Cs, + SystemContext.SystemContextIa32->Eflags + ); + VideoBuffer += COLUMN_MAX; + if (ErrorCodeFlag & (1 << InterruptType)) { + SPrint ( + VideoBuffer, + L"ExceptionData - %08x", + SystemContext.SystemContextIa32->ExceptionData + ); + VideoBuffer += COLUMN_MAX; + } + SPrint ( + VideoBuffer, + L"EAX - %08x, ECX - %08x, EDX - %08x, EBX - %08x", + SystemContext.SystemContextIa32->Eax, + SystemContext.SystemContextIa32->Ecx, + SystemContext.SystemContextIa32->Edx, + SystemContext.SystemContextIa32->Ebx + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"ESP - %08x, EBP - %08x, ESI - %08x, EDI - %08x", + SystemContext.SystemContextIa32->Esp, + SystemContext.SystemContextIa32->Ebp, + SystemContext.SystemContextIa32->Esi, + SystemContext.SystemContextIa32->Edi + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"DS - %08x, ES - %08x, FS - %08x, GS - %08x, SS - %08x", + SystemContext.SystemContextIa32->Ds, + SystemContext.SystemContextIa32->Es, + SystemContext.SystemContextIa32->Fs, + SystemContext.SystemContextIa32->Gs, + SystemContext.SystemContextIa32->Ss + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"GDTR - %08x %08x, IDTR - %08x %08x", + SystemContext.SystemContextIa32->Gdtr[0], + SystemContext.SystemContextIa32->Gdtr[1], + SystemContext.SystemContextIa32->Idtr[0], + SystemContext.SystemContextIa32->Idtr[1] + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"LDTR - %08x, TR - %08x", + SystemContext.SystemContextIa32->Ldtr, + SystemContext.SystemContextIa32->Tr + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"CR0 - %08x, CR2 - %08x, CR3 - %08x, CR4 - %08x", + SystemContext.SystemContextIa32->Cr0, + SystemContext.SystemContextIa32->Cr2, + SystemContext.SystemContextIa32->Cr3, + SystemContext.SystemContextIa32->Cr4 + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"DR0 - %08x, DR1 - %08x, DR2 - %08x, DR3 - %08x", + SystemContext.SystemContextIa32->Dr0, + SystemContext.SystemContextIa32->Dr1, + SystemContext.SystemContextIa32->Dr2, + SystemContext.SystemContextIa32->Dr3 + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"DR6 - %08x, DR7 - %08x", + SystemContext.SystemContextIa32->Dr6, + SystemContext.SystemContextIa32->Dr7 + ); + VideoBuffer += COLUMN_MAX; +#else + SPrint ( + VideoBuffer, + L"!!!! X64 Exception Type - %016lx !!!!", + (UINT64)InterruptType + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"RIP - %016lx, CS - %016lx, RFLAGS - %016lx", + SystemContext.SystemContextX64->Rip, + SystemContext.SystemContextX64->Cs, + SystemContext.SystemContextX64->Rflags + ); + VideoBuffer += COLUMN_MAX; + + if (ErrorCodeFlag & (1 << InterruptType)) { + SPrint ( + VideoBuffer, + L"ExceptionData - %016lx", + SystemContext.SystemContextX64->ExceptionData + ); + VideoBuffer += COLUMN_MAX; + } + + SPrint ( + VideoBuffer, + L"RAX - %016lx, RCX - %016lx, RDX - %016lx", + SystemContext.SystemContextX64->Rax, + SystemContext.SystemContextX64->Rcx, + SystemContext.SystemContextX64->Rdx + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"RBX - %016lx, RSP - %016lx, RBP - %016lx", + SystemContext.SystemContextX64->Rbx, + SystemContext.SystemContextX64->Rsp, + SystemContext.SystemContextX64->Rbp + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"RSI - %016lx, RDI - %016lx", + SystemContext.SystemContextX64->Rsi, + SystemContext.SystemContextX64->Rdi + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"R8 - %016lx, R9 - %016lx, R10 - %016lx", + SystemContext.SystemContextX64->R8, + SystemContext.SystemContextX64->R9, + SystemContext.SystemContextX64->R10 + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"R11 - %016lx, R12 - %016lx, R13 - %016lx", + SystemContext.SystemContextX64->R11, + SystemContext.SystemContextX64->R12, + SystemContext.SystemContextX64->R13 + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"R14 - %016lx, R15 - %016lx", + SystemContext.SystemContextX64->R14, + SystemContext.SystemContextX64->R15 + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"DS - %016lx, ES - %016lx, FS - %016lx", + SystemContext.SystemContextX64->Ds, + SystemContext.SystemContextX64->Es, + SystemContext.SystemContextX64->Fs + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"GS - %016lx, SS - %016lx", + SystemContext.SystemContextX64->Gs, + SystemContext.SystemContextX64->Ss + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"GDTR - %016lx %016lx, LDTR - %016lx", + SystemContext.SystemContextX64->Gdtr[0], + SystemContext.SystemContextX64->Gdtr[1], + SystemContext.SystemContextX64->Ldtr + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"IDTR - %016lx %016lx, TR - %016lx", + SystemContext.SystemContextX64->Idtr[0], + SystemContext.SystemContextX64->Idtr[1], + SystemContext.SystemContextX64->Tr + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"CR0 - %016lx, CR2 - %016lx, CR3 - %016lx", + SystemContext.SystemContextX64->Cr0, + SystemContext.SystemContextX64->Cr2, + SystemContext.SystemContextX64->Cr3 + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"CR4 - %016lx, CR8 - %016lx", + SystemContext.SystemContextX64->Cr4, + SystemContext.SystemContextX64->Cr8 + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"DR0 - %016lx, DR1 - %016lx, DR2 - %016lx", + SystemContext.SystemContextX64->Dr0, + SystemContext.SystemContextX64->Dr1, + SystemContext.SystemContextX64->Dr2 + ); + VideoBuffer += COLUMN_MAX; + + SPrint ( + VideoBuffer, + L"DR3 - %016lx, DR6 - %016lx, DR7 - %016lx", + SystemContext.SystemContextX64->Dr3, + SystemContext.SystemContextX64->Dr6, + SystemContext.SystemContextX64->Dr7 + ); + VideoBuffer += COLUMN_MAX; +#endif + + for (Index = 0; Index < COLUMN_MAX * ROW_MAX; Index ++) { + if (Index > (UINTN)(VideoBuffer - VideoBufferBase)) { + VideoBufferBase[Index] = 0x0c20; + } else { + VideoBufferBase[Index] |= 0x0c00; + } + } + + return ; +} + +#if CPU_EXCEPTION_VGA_SWITCH +STATIC +UINT16 +SwitchVideoMode ( + UINT16 NewVideoMode + ) +/*++ +Description + Switch Video Mode from current mode to new mode, and return the old mode. + Use Thuink + +Arguments + NewVideoMode - new video mode want to set + +Return + UINT16 - (UINT16) -1 indicates failure + Other value indicates the old mode, which can be used for restore later + +--*/ +{ + EFI_STATUS Status; + EFI_LEGACY_BIOS_THUNK_PROTOCOL *LegacyBios; + EFI_IA32_REGISTER_SET Regs; + UINT16 OriginalVideoMode = (UINT16) -1; + + // + // See if the Legacy BIOS Protocol is available + // + Status = gBS->LocateProtocol (&gEfiLegacyBiosThunkProtocolGuid, NULL, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) { + return OriginalVideoMode; + } + + // + // VESA SuperVGA BIOS - GET CURRENT VIDEO MODE + // AX = 4F03h + // Return:AL = 4Fh if function supported + // AH = status 00h successful + // BX = video mode (see #0082,#0083) + // + gBS->SetMem (&Regs, sizeof (Regs), 0); + Regs.X.AX = 0x4F03; + LegacyBios->Int86 (LegacyBios, 0x10, &Regs); + if (Regs.X.AX == 0x004F) { + OriginalVideoMode = Regs.X.BX; + } else { + // + // VIDEO - GET CURRENT VIDEO MODE + // AH = 0Fh + // Return:AH = number of character columns + // AL = display mode (see #0009 at AH=00h) + // BH = active page (see AH=05h) + // + gBS->SetMem (&Regs, sizeof (Regs), 0); + Regs.H.AH = 0x0F; + LegacyBios->Int86 (LegacyBios, 0x10, &Regs); + OriginalVideoMode = Regs.H.AL; + } + + // + // Set new video mode + // + if (NewVideoMode < 0x100) { + // + // Set the 80x25 Text VGA Mode: Assume successful always + // + // VIDEO - SET VIDEO MODE + // AH = 00h + // AL = desired video mode (see #0009) + // Return:AL = video mode flag (Phoenix, AMI BIOS) + // 20h mode > 7 + // 30h modes 0-5 and 7 + // 3Fh mode 6 + // AL = CRT controller mode byte (Phoenix 386 BIOS v1.10) + // + gBS->SetMem (&Regs, sizeof (Regs), 0); + Regs.H.AH = 0x00; + Regs.H.AL = (UINT8) NewVideoMode; + LegacyBios->Int86 (LegacyBios, 0x10, &Regs); + + // + // VIDEO - TEXT-MODE CHARGEN - LOAD ROM 8x16 CHARACTER SET (VGA) + // AX = 1114h + // BL = block to load + // Return:Nothing + // + gBS->SetMem (&Regs, sizeof (Regs), 0); + Regs.H.AH = 0x11; + Regs.H.AL = 0x14; + Regs.H.BL = 0; + LegacyBios->Int86 (LegacyBios, 0x10, &Regs); + } else { + // + // VESA SuperVGA BIOS - SET SuperVGA VIDEO MODE + // AX = 4F02h + // BX = mode (see #0082,#0083) + // bit 15 set means don't clear video memory + // bit 14 set means enable linear framebuffer mode (VBE v2.0+) + // Return:AL = 4Fh if function supported + // AH = status + // 00h successful + // 01h failed + // + gBS->SetMem (&Regs, sizeof (Regs), 0); + Regs.X.AX = 0x4F02; + Regs.X.BX = NewVideoMode; + LegacyBios->Int86 (LegacyBios, 0x10, &Regs); + if (Regs.X.AX != 0x004F) { + DEBUG ((EFI_D_ERROR, "SORRY: Cannot set to video mode: 0x%04X!\n", NewVideoMode)); + return (UINT16) -1; + } + } + + return OriginalVideoMode; +} +#endif + +VOID +ExceptionHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ +#if CPU_EXCEPTION_VGA_SWITCH + UINT16 VideoMode; +#endif + +#if CPU_EXCEPTION_DEBUG_OUTPUT + DumpExceptionDataDebugOut (InterruptType, SystemContext); +#endif + +#if CPU_EXCEPTION_VGA_SWITCH + // + // Switch to text mode for RED-SCREEN output + // + VideoMode = SwitchVideoMode (0x83); + if (VideoMode == (UINT16) -1) { + DEBUG ((EFI_D_ERROR, "Video Mode Unknown!\n")); + } +#endif + + DumpExceptionDataVgaOut (InterruptType, SystemContext); + + // + // Use this macro to hang so that the compiler does not optimize out + // the following RET instructions. This allows us to return if we + // have a debugger attached. + // + CpuDeadLoop (); + +#if CPU_EXCEPTION_VGA_SWITCH + // + // Switch back to the old video mode + // + if (VideoMode != (UINT16)-1) { + SwitchVideoMode (VideoMode); + } +#endif + + return ; +} + +VOID +TimerHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + if (mTimerHandler != NULL) { + mTimerHandler (InterruptType, SystemContext); + } +} + +EFI_STATUS +EFIAPI +InitializeCpu ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Initialize the state information for the CPU Architectural Protocol + +Arguments: + ImageHandle of the loaded driver + Pointer to the System Table + +Returns: + EFI_SUCCESS - thread can be successfully created + EFI_OUT_OF_RESOURCES - cannot allocate protocol data structure + EFI_DEVICE_ERROR - cannot create the thread + +--*/ +{ + EFI_STATUS Status; + EFI_8259_IRQ Irq; + UINT32 InterruptVector; + + // + // Find the Legacy8259 protocol. + // + Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &gLegacy8259); + ASSERT_EFI_ERROR (Status); + + // + // Get the interrupt vector number corresponding to IRQ0 from the 8259 driver + // + Status = gLegacy8259->GetVector (gLegacy8259, Efi8259Irq0, (UINT8 *) &mTimerVector); + ASSERT_EFI_ERROR (Status); + + // + // Reload GDT, IDT + // + InitDescriptor (); + + // + // Install Exception Handler (0x00 ~ 0x1F) + // + for (InterruptVector = 0; InterruptVector < 0x20; InterruptVector++) { + InstallInterruptHandler ( + InterruptVector, + (VOID (*)(VOID))(UINTN)((UINTN)SystemExceptionHandler + mExceptionCodeSize * InterruptVector) + ); + } + + // + // Install Timer Handler + // + InstallInterruptHandler (mTimerVector, SystemTimerHandler); + + // + // BUGBUG: We add all other interrupt vector + // + for (Irq = Efi8259Irq1; Irq <= Efi8259Irq15; Irq++) { + InterruptVector = 0; + Status = gLegacy8259->GetVector (gLegacy8259, Irq, (UINT8 *) &InterruptVector); + ASSERT_EFI_ERROR (Status); + InstallInterruptHandler (InterruptVector, SystemTimerHandler); + } + + // + // Install CPU Architectural Protocol and the thunk protocol + // + mHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &mHandle, + &gEfiCpuArchProtocolGuid, + &mCpu, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + diff --git a/DuetPkg/CpuDxe/Cpu.dxs b/DuetPkg/CpuDxe/Cpu.dxs new file mode 100644 index 0000000000..b07f51b159 --- /dev/null +++ b/DuetPkg/CpuDxe/Cpu.dxs @@ -0,0 +1,25 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + Cpu.dxs + +Abstract: + Dependency expression source file. + +--*/ + +#include "EfiDepex.h" +#include EFI_PROTOCOL_DEFINITION (Legacy8259) + +DEPENDENCY_START + EFI_LEGACY_8259_PROTOCOL_GUID +DEPENDENCY_END diff --git a/DuetPkg/CpuDxe/Cpu.inf b/DuetPkg/CpuDxe/Cpu.inf new file mode 100644 index 0000000000..8483aca65a --- /dev/null +++ b/DuetPkg/CpuDxe/Cpu.inf @@ -0,0 +1,53 @@ +#/*++ +# +# Copyright (c) 2006, Intel Corporation +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# Cpu.inf +# +# Abstract: +# +#--*/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Cpu + FILE_GUID = 10527025-78B2-4d3e-A9DF-41E75C220F5A + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x00020000 + + ENTRY_POINT = InitializeCpu + +[Packages] + DuetPkg/DuetPkg.dec + MdePkg/MdePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + PrintLib + UefiBootServicesTableLib + +[Sources.IA32] + IA32/CpuInterrupt.asm + +[Sources.X64] + X64/CpuInterrupt.asm + +[Sources.common] + Cpu.c + CpuDxe.h + +[Protocols] + gEfiCpuArchProtocolGuid + gEfiLegacyBiosThunkProtocolGuid + gEfiLegacy8259ProtocolGuid diff --git a/DuetPkg/CpuDxe/CpuDxe.h b/DuetPkg/CpuDxe/CpuDxe.h new file mode 100644 index 0000000000..5bca0ca10c --- /dev/null +++ b/DuetPkg/CpuDxe/CpuDxe.h @@ -0,0 +1,148 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + CpuDxe.h + +Abstract: + +--*/ +#ifndef _CPU_DXE_H +#define _CPU_DXE_H + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#define CPU_EXCEPTION_DEBUG_OUTPUT 1 +#define CPU_EXCEPTION_VGA_SWITCH 1 + +#define INTERRUPT_VECTOR_NUMBER 0x100 + +// +// Print primitives +// +//#define LEFT_JUSTIFY 0x01 +#define PREFIX_SIGN 0x02 +#define PREFIX_BLANK 0x04 +//#define COMMA_TYPE 0x08 +#define LONG_TYPE 0x10 +//#define PREFIX_ZERO 0x20 +#define OUTPUT_UNICODE 0x40 +//#define RADIX_HEX 0x80 +#define FORMAT_UNICODE 0x100 +#define PAD_TO_WIDTH 0x200 +#define ARGUMENT_UNICODE 0x400 +#define PRECISION 0x800 +#define ARGUMENT_REVERSED 0x1000 + +// +// Function declarations +// +EFI_STATUS +EFIAPI +InitializeCpu ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +CpuFlushCpuDataCache ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length, + IN EFI_CPU_FLUSH_TYPE FlushType + ); + +EFI_STATUS +EFIAPI +CpuEnableInterrupt ( + IN EFI_CPU_ARCH_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +CpuDisableInterrupt ( + IN EFI_CPU_ARCH_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +CpuGetInterruptState ( + IN EFI_CPU_ARCH_PROTOCOL *This, + OUT BOOLEAN *State + ); + +EFI_STATUS +EFIAPI +CpuInit ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_CPU_INIT_TYPE InitType + ); + +EFI_STATUS +EFIAPI +CpuRegisterInterruptHandler ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ); + +EFI_STATUS +EFIAPI +CpuGetTimerValue ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN UINT32 TimerIndex, + OUT UINT64 *TimerValue, + OUT UINT64 *TimerPeriod OPTIONAL + ); + +EFI_STATUS +EFIAPI +CpuSetMemoryAttributes( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ); + +VOID +InstallInterruptHandler ( + UINTN Vector, + VOID (*Handler)(VOID) + ); + +VOID +SystemExceptionHandler ( + VOID + ); + +VOID +SystemTimerHandler ( + VOID + ); + +VOID +InitDescriptor ( + VOID + ); + +#endif diff --git a/DuetPkg/CpuDxe/Ia32/CpuInterrupt.asm b/DuetPkg/CpuDxe/Ia32/CpuInterrupt.asm new file mode 100644 index 0000000000..cc1402cd9b --- /dev/null +++ b/DuetPkg/CpuDxe/Ia32/CpuInterrupt.asm @@ -0,0 +1,835 @@ + TITLE CpuInterrupt.asm: +;------------------------------------------------------------------------------ +;* +;* Copyright 2006, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* CpuInterrupt.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + +.686p +.model flat, C + +PUBLIC SystemTimerHandler +PUBLIC SystemExceptionHandler +EXTERNDEF mExceptionCodeSize:DWORD + +.code +.stack +.MMX +.XMM + +EXTERN TimerHandler: NEAR +EXTERN ExceptionHandler: NEAR +EXTERN mTimerVector: DWORD + +mExceptionCodeSize DD 9 + +InitDescriptor PROC C + lea eax, [GDT_BASE] ; EAX=PHYSICAL address of gdt + mov dword ptr [gdtr + 2],eax ; Put address of gdt into the gdtr + lgdt fword ptr [gdtr] + lea eax, [IDT_BASE] ; EAX=PHYSICAL address of idt + mov dword ptr [idtr + 2],eax ; Put address of idt into the idtr + lidt fword ptr [idtr] + ret +InitDescriptor ENDP + +; VOID +; InstallInterruptHandler ( +; UINTN Vector, +; VOID (*Handler)(VOID) +; ) +InstallInterruptHandler PROC C \ + Vector:DWORD, \ + Handler:DWORD + + push edi + pushfd ; save eflags + cli ; turn off interrupts + sub esp, 6 ; open some space on the stack + mov edi, esp + sidt es:[edi] ; get fword address of IDT + mov edi, es:[edi+2] ; move offset of IDT into EDI + add esp, 6 ; correct stack + mov eax, Vector ; Get vector number + shl eax, 3 ; multiply by 8 to get offset + add edi, eax ; add to IDT base to get entry + mov eax, Handler ; load new address into IDT entry + mov word ptr es:[edi], ax ; write bits 15..0 of offset + shr eax, 16 ; use ax to copy 31..16 to descriptors + mov word ptr es:[edi+6], ax ; write bits 31..16 of offset + popfd ; restore flags (possible enabling interrupts) + pop edi + ret + +InstallInterruptHandler ENDP + +JmpCommonIdtEntry macro + ; jmp commonIdtEntry - this must be hand coded to keep the assembler from + ; using a 8 bit reletive jump when the entries are + ; within 255 bytes of the common entry. This must + ; be done to maintain the consistency of the size + ; of entry points... + db 0e9h ; jmp 16 bit reletive + dd commonIdtEntry - $ - 4 ; offset to jump to +endm + + align 02h +SystemExceptionHandler PROC +INT0: + push 0h ; push error code place holder on the stack + push 0h + JmpCommonIdtEntry +; db 0e9h ; jmp 16 bit reletive +; dd commonIdtEntry - $ - 4 ; offset to jump to + +INT1: + push 0h ; push error code place holder on the stack + push 1h + JmpCommonIdtEntry + +INT2: + push 0h ; push error code place holder on the stack + push 2h + JmpCommonIdtEntry + +INT3: + push 0h ; push error code place holder on the stack + push 3h + JmpCommonIdtEntry + +INT4: + push 0h ; push error code place holder on the stack + push 4h + JmpCommonIdtEntry + +INT5: + push 0h ; push error code place holder on the stack + push 5h + JmpCommonIdtEntry + +INT6: + push 0h ; push error code place holder on the stack + push 6h + JmpCommonIdtEntry + +INT7: + push 0h ; push error code place holder on the stack + push 7h + JmpCommonIdtEntry + +INT8: +; Double fault causes an error code to be pushed so no phony push necessary + nop + nop + push 8h + JmpCommonIdtEntry + +INT9: + push 0h ; push error code place holder on the stack + push 9h + JmpCommonIdtEntry + +INT10: +; Invalid TSS causes an error code to be pushed so no phony push necessary + nop + nop + push 10 + JmpCommonIdtEntry + +INT11: +; Segment Not Present causes an error code to be pushed so no phony push necessary + nop + nop + push 11 + JmpCommonIdtEntry + +INT12: +; Stack fault causes an error code to be pushed so no phony push necessary + nop + nop + push 12 + JmpCommonIdtEntry + +INT13: +; GP fault causes an error code to be pushed so no phony push necessary + nop + nop + push 13 + JmpCommonIdtEntry + +INT14: +; Page fault causes an error code to be pushed so no phony push necessary + nop + nop + push 14 + JmpCommonIdtEntry + +INT15: + push 0h ; push error code place holder on the stack + push 15 + JmpCommonIdtEntry + +INT16: + push 0h ; push error code place holder on the stack + push 16 + JmpCommonIdtEntry + +INT17: +; Alignment check causes an error code to be pushed so no phony push necessary + nop + nop + push 17 + JmpCommonIdtEntry + +INT18: + push 0h ; push error code place holder on the stack + push 18 + JmpCommonIdtEntry + +INT19: + push 0h ; push error code place holder on the stack + push 19 + JmpCommonIdtEntry + +INTUnknown: +REPEAT (32 - 20) + push 0h ; push error code place holder on the stack +; push xxh ; push vector number + db 06ah + db ( $ - INTUnknown - 3 ) / 9 + 20 ; vector number + JmpCommonIdtEntry +ENDM +SystemExceptionHandler ENDP + +SystemTimerHandler PROC + push 0 + push mTimerVector + JmpCommonIdtEntry +SystemTimerHandler ENDP + +commonIdtEntry: +; +---------------------+ +; + EFlags + +; +---------------------+ +; + CS + +; +---------------------+ +; + EIP + +; +---------------------+ +; + Error Code + +; +---------------------+ +; + Vector Number + +; +---------------------+ +; + EBP + +; +---------------------+ <-- EBP + + cli + push ebp + mov ebp, esp + + ; + ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 + ; is 16-byte aligned + ; + and esp, 0fffffff0h + sub esp, 12 + +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + push eax + push ecx + push edx + push ebx + lea ecx, [ebp + 6 * 4] + push ecx ; ESP + push dword ptr [ebp] ; EBP + push esi + push edi + +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; + mov eax, ss + push eax + movzx eax, word ptr [ebp + 4 * 4] + push eax + mov eax, ds + push eax + mov eax, es + push eax + mov eax, fs + push eax + mov eax, gs + push eax + +;; UINT32 Eip; + push dword ptr [ebp + 3 * 4] + +;; UINT32 Gdtr[2], Idtr[2]; + sub esp, 8 + sidt fword ptr [esp] + sub esp, 8 + sgdt fword ptr [esp] + +;; UINT32 Ldtr, Tr; + xor eax, eax + str ax + push eax + sldt ax + push eax + +;; UINT32 EFlags; + push dword ptr [ebp + 5 * 4] + +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + mov eax, cr4 + or eax, 208h + mov cr4, eax + push eax + mov eax, cr3 + push eax + mov eax, cr2 + push eax + xor eax, eax + push eax + mov eax, cr0 + push eax + +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + mov eax, dr7 + push eax +;; clear Dr7 while executing debugger itself + xor eax, eax + mov dr7, eax + + mov eax, dr6 + push eax +;; insure all status bits in dr6 are clear... + xor eax, eax + mov dr6, eax + + mov eax, dr3 + push eax + mov eax, dr2 + push eax + mov eax, dr1 + push eax + mov eax, dr0 + push eax + +;; FX_SAVE_STATE_IA32 FxSaveState; + sub esp, 512 + mov edi, esp + db 0fh, 0aeh, 00000111y ;fxsave [edi] + +;; UINT32 ExceptionData; + push dword ptr [ebp + 2 * 4] + +;; Prepare parameter and call + mov edx, esp + push edx + mov eax, dword ptr [ebp + 1 * 4] + push eax + cmp eax, 32 + jb CallException + call TimerHandler + jmp ExceptionDone +CallException: + call ExceptionHandler +ExceptionDone: + add esp, 8 + + cli +;; UINT32 ExceptionData; + add esp, 4 + +;; FX_SAVE_STATE_IA32 FxSaveState; + mov esi, esp + db 0fh, 0aeh, 00001110y ; fxrstor [esi] + add esp, 512 + +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + pop eax + mov dr0, eax + pop eax + mov dr1, eax + pop eax + mov dr2, eax + pop eax + mov dr3, eax +;; skip restore of dr6. We cleared dr6 during the context save. + add esp, 4 + pop eax + mov dr7, eax + +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + pop eax + mov cr0, eax + add esp, 4 ; not for Cr1 + pop eax + mov cr2, eax + pop eax + mov cr3, eax + pop eax + mov cr4, eax + +;; UINT32 EFlags; + pop dword ptr [ebp + 5 * 4] + +;; UINT32 Ldtr, Tr; +;; UINT32 Gdtr[2], Idtr[2]; +;; Best not let anyone mess with these particular registers... + add esp, 24 + +;; UINT32 Eip; + pop dword ptr [ebp + 3 * 4] + +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; +;; NOTE - modified segment registers could hang the debugger... We +;; could attempt to insulate ourselves against this possibility, +;; but that poses risks as well. +;; + pop gs + pop fs + pop es + pop ds + pop dword ptr [ebp + 4 * 4] + pop ss + +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + pop edi + pop esi + add esp, 4 ; not for ebp + add esp, 4 ; not for esp + pop ebx + pop edx + pop ecx + pop eax + + mov esp, ebp + pop ebp + add esp, 8 + iretd + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; data +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + align 02h + +gdtr dw GDT_END - GDT_BASE - 1 ; GDT limit + dd 0 ; (GDT base gets set above) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; global descriptor table (GDT) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + align 02h + +public GDT_BASE +GDT_BASE: +; null descriptor +NULL_SEL equ $-GDT_BASE + dw 0 ; limit 15:0 + dw 0 ; base 15:0 + db 0 ; base 23:16 + db 0 ; type + db 0 ; limit 19:16, flags + db 0 ; base 31:24 + +; linear data segment descriptor +LINEAR_SEL equ $-GDT_BASE + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; linear code segment descriptor +LINEAR_CODE_SEL equ $-GDT_BASE + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system data segment descriptor +SYS_DATA_SEL equ $-GDT_BASE + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system code segment descriptor +SYS_CODE_SEL equ $-GDT_BASE + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; spare segment descriptor +SPARE3_SEL equ $-GDT_BASE + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +; spare segment descriptor +SPARE4_SEL equ $-GDT_BASE + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +; spare segment descriptor +SPARE5_SEL equ $-GDT_BASE + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +GDT_END: + + align 02h + + + +idtr dw IDT_END - IDT_BASE - 1 ; IDT limit + dd 0 ; (IDT base gets set above) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; interrupt descriptor table (IDT) +; +; Note: The hardware IRQ's specified in this table are the normal PC/AT IRQ +; mappings. This implementation only uses the system timer and all other +; IRQs will remain masked. The descriptors for vectors 33+ are provided +; for convenience. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;idt_tag db "IDT",0 + align 02h + +public IDT_BASE +IDT_BASE: +; divide by zero (INT 0) +DIV_ZERO_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; debug exception (INT 1) +DEBUG_EXCEPT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; NMI (INT 2) +NMI_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; soft breakpoint (INT 3) +BREAKPOINT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; overflow (INT 4) +OVERFLOW_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; bounds check (INT 5) +BOUNDS_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; invalid opcode (INT 6) +INVALID_OPCODE_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; device not available (INT 7) +DEV_NOT_AVAIL_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; double fault (INT 8) +DOUBLE_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; Coprocessor segment overrun - reserved (INT 9) +RSVD_INTR_SEL1 equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; invalid TSS (INT 0ah) +INVALID_TSS_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; segment not present (INT 0bh) +SEG_NOT_PRESENT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; stack fault (INT 0ch) +STACK_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; general protection (INT 0dh) +GP_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; page fault (INT 0eh) +PAGE_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; Intel reserved - do not use (INT 0fh) +RSVD_INTR_SEL2 equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; floating point error (INT 10h) +FLT_POINT_ERR_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; alignment check (INT 11h) +ALIGNMENT_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; machine check (INT 12h) +MACHINE_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; SIMD floating-point exception (INT 13h) +SIMD_EXCEPTION_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +REPEAT (32 - 20) + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 +ENDM + +; 72 unspecified descriptors + db (72 * 8) dup(0) + +; IRQ 0 (System timer) - (INT 68h) +IRQ0_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 1 (8042 Keyboard controller) - (INT 69h) +IRQ1_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; Reserved - IRQ 2 redirect (IRQ 2) - DO NOT USE!!! - (INT 6ah) +IRQ2_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 3 (COM 2) - (INT 6bh) +IRQ3_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 4 (COM 1) - (INT 6ch) +IRQ4_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 5 (LPT 2) - (INT 6dh) +IRQ5_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 6 (Floppy controller) - (INT 6eh) +IRQ6_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 7 (LPT 1) - (INT 6fh) +IRQ7_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 8 (RTC Alarm) - (INT 70h) +IRQ8_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 9 - (INT 71h) +IRQ9_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 10 - (INT 72h) +IRQ10_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 11 - (INT 73h) +IRQ11_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 12 (PS/2 mouse) - (INT 74h) +IRQ12_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 13 (Floating point error) - (INT 75h) +IRQ13_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 14 (Secondary IDE) - (INT 76h) +IRQ14_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + +; IRQ 15 (Primary IDE) - (INT 77h) +IRQ15_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + + db (1 * 8) dup(0) + +IDT_END: + +END diff --git a/DuetPkg/CpuDxe/x64/CpuInterrupt.asm b/DuetPkg/CpuDxe/x64/CpuInterrupt.asm new file mode 100644 index 0000000000..acf86059c4 --- /dev/null +++ b/DuetPkg/CpuDxe/x64/CpuInterrupt.asm @@ -0,0 +1,949 @@ + TITLE CpuInterrupt.asm: +;------------------------------------------------------------------------------ +;* +;* Copyright 2006, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* CpuInterrupt.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + +EXTERNDEF mExceptionCodeSize:DWORD + +.code + +EXTERN TimerHandler: FAR +EXTERN ExceptionHandler: NEAR +EXTERN mTimerVector: QWORD + +mExceptionCodeSize DD 9 + +InitDescriptor PROC + lea rax, [GDT_BASE] ; RAX=PHYSICAL address of gdt + mov qword ptr [gdtr + 2], rax ; Put address of gdt into the gdtr + lgdt fword ptr [gdtr] + mov rax, 18h + mov gs, rax + mov fs, rax + lea rax, [IDT_BASE] ; RAX=PHYSICAL address of idt + mov qword ptr [idtr + 2], rax ; Put address of idt into the idtr + lidt fword ptr [idtr] + ret +InitDescriptor ENDP + +; VOID +; InstallInterruptHandler ( +; UINTN Vector, // rcx +; void (*Handler)(void) // rdx +; ) +InstallInterruptHandler PROC + push rbx + pushfq ; save eflags + cli ; turn off interrupts + sub rsp, 10h ; open some space on the stack + mov rbx, rsp + sidt [rbx] ; get fword address of IDT + mov rbx, [rbx+2] ; move offset of IDT into RBX + add rsp, 10h ; correct stack + mov rax, rcx ; Get vector number + shl rax, 4 ; multiply by 16 to get offset + add rbx, rax ; add to IDT base to get entry + mov rax, rdx ; load new address into IDT entry + mov word ptr [rbx], ax ; write bits 15..0 of offset + shr rax, 16 ; use ax to copy 31..16 to descriptors + mov word ptr [rbx+6], ax ; write bits 31..16 of offset + shr rax, 16 ; use eax to copy 63..32 to descriptors + mov dword ptr [rbx+8], eax ; write bits 63..32 of offset + popfq ; restore flags (possible enabling interrupts) + pop rbx + ret + +InstallInterruptHandler ENDP + +JmpCommonIdtEntry macro + ; jmp commonIdtEntry - this must be hand coded to keep the assembler from + ; using a 8 bit reletive jump when the entries are + ; within 255 bytes of the common entry. This must + ; be done to maintain the consistency of the size + ; of entry points... + db 0e9h ; jmp 16 bit reletive + dd commonIdtEntry - $ - 4 ; offset to jump to +endm + + align 02h +SystemExceptionHandler PROC +INT0: + push 0h ; push error code place holder on the stack + push 0h + JmpCommonIdtEntry +; db 0e9h ; jmp 16 bit reletive +; dd commonIdtEntry - $ - 4 ; offset to jump to + +INT1: + push 0h ; push error code place holder on the stack + push 1h + JmpCommonIdtEntry + +INT2: + push 0h ; push error code place holder on the stack + push 2h + JmpCommonIdtEntry + +INT3: + push 0h ; push error code place holder on the stack + push 3h + JmpCommonIdtEntry + +INT4: + push 0h ; push error code place holder on the stack + push 4h + JmpCommonIdtEntry + +INT5: + push 0h ; push error code place holder on the stack + push 5h + JmpCommonIdtEntry + +INT6: + push 0h ; push error code place holder on the stack + push 6h + JmpCommonIdtEntry + +INT7: + push 0h ; push error code place holder on the stack + push 7h + JmpCommonIdtEntry + +INT8: +; Double fault causes an error code to be pushed so no phony push necessary + nop + nop + push 8h + JmpCommonIdtEntry + +INT9: + push 0h ; push error code place holder on the stack + push 9h + JmpCommonIdtEntry + +INT10: +; Invalid TSS causes an error code to be pushed so no phony push necessary + nop + nop + push 10 + JmpCommonIdtEntry + +INT11: +; Segment Not Present causes an error code to be pushed so no phony push necessary + nop + nop + push 11 + JmpCommonIdtEntry + +INT12: +; Stack fault causes an error code to be pushed so no phony push necessary + nop + nop + push 12 + JmpCommonIdtEntry + +INT13: +; GP fault causes an error code to be pushed so no phony push necessary + nop + nop + push 13 + JmpCommonIdtEntry + +INT14: +; Page fault causes an error code to be pushed so no phony push necessary + nop + nop + push 14 + JmpCommonIdtEntry + +INT15: + push 0h ; push error code place holder on the stack + push 15 + JmpCommonIdtEntry + +INT16: + push 0h ; push error code place holder on the stack + push 16 + JmpCommonIdtEntry + +INT17: +; Alignment check causes an error code to be pushed so no phony push necessary + nop + nop + push 17 + JmpCommonIdtEntry + +INT18: + push 0h ; push error code place holder on the stack + push 18 + JmpCommonIdtEntry + +INT19: + push 0h ; push error code place holder on the stack + push 19 + JmpCommonIdtEntry + +INTUnknown: +REPEAT (32 - 20) + push 0h ; push error code place holder on the stack +; push xxh ; push vector number + db 06ah + db ( $ - INTUnknown - 3 ) / 9 + 20 ; vector number + JmpCommonIdtEntry +ENDM +SystemExceptionHandler ENDP + +SystemTimerHandler PROC + push 0 + push mTimerVector + JmpCommonIdtEntry +SystemTimerHandler ENDP + +commonIdtEntry: +; +---------------------+ <-- 16-byte aligned ensured by processor +; + Old SS + +; +---------------------+ +; + Old RSP + +; +---------------------+ +; + RFlags + +; +---------------------+ +; + CS + +; +---------------------+ +; + RIP + +; +---------------------+ +; + Error Code + +; +---------------------+ +; + Vector Number + +; +---------------------+ +; + RBP + +; +---------------------+ <-- RBP, 16-byte aligned + + cli + push rbp + mov rbp, rsp + + ; + ; Since here the stack pointer is 16-byte aligned, so + ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64 + ; is 16-byte aligned + ; + +;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; +;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push rax + push rcx + push rdx + push rbx + push qword ptr [rbp + 6 * 8] ; RSP + push qword ptr [rbp] ; RBP + push rsi + push rdi + +;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero + movzx rax, word ptr [rbp + 7 * 8] + push rax ; for ss + movzx rax, word ptr [rbp + 4 * 8] + push rax ; for cs + mov rax, ds + push rax + mov rax, es + push rax + mov rax, fs + push rax + mov rax, gs + push rax + +;; UINT64 Rip; + push qword ptr [rbp + 3 * 8] + +;; UINT64 Gdtr[2], Idtr[2]; + sub rsp, 16 + sidt fword ptr [rsp] + sub rsp, 16 + sgdt fword ptr [rsp] + +;; UINT64 Ldtr, Tr; + xor rax, rax + str ax + push rax + sldt ax + push rax + +;; UINT64 RFlags; + push qword ptr [rbp + 5 * 8] + +;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + mov rax, cr8 + push rax + mov rax, cr4 + or rax, 208h + mov cr4, rax + push rax + mov rax, cr3 + push rax + mov rax, cr2 + push rax + xor rax, rax + push rax + mov rax, cr0 + push rax + +;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + mov rax, dr7 + push rax +;; clear Dr7 while executing debugger itself + xor rax, rax + mov dr7, rax + + mov rax, dr6 + push rax +;; insure all status bits in dr6 are clear... + xor rax, rax + mov dr6, rax + + mov rax, dr3 + push rax + mov rax, dr2 + push rax + mov rax, dr1 + push rax + mov rax, dr0 + push rax + +;; FX_SAVE_STATE_X64 FxSaveState; + + sub rsp, 512 + mov rdi, rsp + db 0fh, 0aeh, 00000111y ;fxsave [rdi] + +;; UINT32 ExceptionData; + push qword ptr [rbp + 2 * 8] + +;; call into exception handler +;; Prepare parameter and call + mov rcx, qword ptr [rbp + 1 * 8] + mov rdx, rsp + ; + ; Per X64 calling convention, allocate maximum parameter stack space + ; and make sure RSP is 16-byte aligned + ; + sub rsp, 4 * 8 + 8 + cmp rcx, 32 + jb CallException + call TimerHandler + jmp ExceptionDone +CallException: + call ExceptionHandler +ExceptionDone: + add rsp, 4 * 8 + 8 + + cli +;; UINT64 ExceptionData; + add rsp, 8 + +;; FX_SAVE_STATE_X64 FxSaveState; + + mov rsi, rsp + db 0fh, 0aeh, 00001110y ; fxrstor [rsi] + add rsp, 512 + +;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + pop rax + mov dr0, rax + pop rax + mov dr1, rax + pop rax + mov dr2, rax + pop rax + mov dr3, rax +;; skip restore of dr6. We cleared dr6 during the context save. + add rsp, 8 + pop rax + mov dr7, rax + +;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; + pop rax + mov cr0, rax + add rsp, 8 ; not for Cr1 + pop rax + mov cr2, rax + pop rax + mov cr3, rax + pop rax + mov cr4, rax + pop rax + mov cr8, rax + +;; UINT64 RFlags; + pop qword ptr [rbp + 5 * 8] + +;; UINT64 Ldtr, Tr; +;; UINT64 Gdtr[2], Idtr[2]; +;; Best not let anyone mess with these particular registers... + add rsp, 48 + +;; UINT64 Rip; + pop qword ptr [rbp + 3 * 8] + +;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; + pop rax + ; mov gs, rax ; not for gs + pop rax + ; mov fs, rax ; not for fs + ; (X64 will not use fs and gs, so we do not restore it) + pop rax + mov es, rax + pop rax + mov ds, rax + pop qword ptr [rbp + 4 * 8] ; for cs + pop qword ptr [rbp + 7 * 8] ; for ss + +;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; +;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; + pop rdi + pop rsi + add rsp, 8 ; not for rbp + pop qword ptr [rbp + 6 * 8] ; for rsp + pop rbx + pop rdx + pop rcx + pop rax + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + + mov rsp, rbp + pop rbp + add rsp, 16 + iretq + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; data +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + align 010h + +gdtr dw GDT_END - GDT_BASE - 1 ; GDT limit + dq 0 ; (GDT base gets set above) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; global descriptor table (GDT) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + align 010h + +public GDT_BASE +GDT_BASE: +; null descriptor +NULL_SEL equ $-GDT_BASE ; Selector [0x0] + dw 0 ; limit 15:0 + dw 0 ; base 15:0 + db 0 ; base 23:16 + db 0 ; type + db 0 ; limit 19:16, flags + db 0 ; base 31:24 + +; linear data segment descriptor +LINEAR_SEL equ $-GDT_BASE ; Selector [0x8] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; linear code segment descriptor +LINEAR_CODE_SEL equ $-GDT_BASE ; Selector [0x10] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system data segment descriptor +SYS_DATA_SEL equ $-GDT_BASE ; Selector [0x18] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; system code segment descriptor +SYS_CODE_SEL equ $-GDT_BASE ; Selector [0x20] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular, 32-bit + db 0 + +; spare segment descriptor +SPARE3_SEL equ $-GDT_BASE ; Selector [0x28] + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +; +; system data segment descriptor +; +SYS_DATA64_SEL equ $-GDT_BASE ; Selector [0x30] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 092h ; P | DPL [1..2] | 1 | 1 | C | R | A + db 0CFh ; G | D | L | AVL | Segment [19..16] + db 0 + +; +; system code segment descriptor +; +SYS_CODE64_SEL equ $-GDT_BASE ; Selector [0x38] + dw 0FFFFh ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 09Ah ; P | DPL [1..2] | 1 | 1 | C | R | A + db 0AFh ; G | D | L | AVL | Segment [19..16] + db 0 + +; spare segment descriptor +SPARE4_SEL equ $-GDT_BASE ; Selector [0x40] + dw 0 ; limit 0xFFFFF + dw 0 ; base 0 + db 0 + db 0 ; present, ring 0, data, expand-up, writable + db 0 ; page-granular, 32-bit + db 0 + +GDT_END: + + align 02h + + + +idtr dw IDT_END - IDT_BASE - 1 ; IDT limit + dq 0 ; (IDT base gets set above) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; interrupt descriptor table (IDT) +; +; Note: The hardware IRQ's specified in this table are the normal PC/AT IRQ +; mappings. This implementation only uses the system timer and all other +; IRQs will remain masked. The descriptors for vectors 33+ are provided +; for convenience. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;idt_tag db "IDT",0 + align 02h + +public IDT_BASE +IDT_BASE: +; divide by zero (INT 0) +DIV_ZERO_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; debug exception (INT 1) +DEBUG_EXCEPT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; NMI (INT 2) +NMI_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; soft breakpoint (INT 3) +BREAKPOINT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; overflow (INT 4) +OVERFLOW_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; bounds check (INT 5) +BOUNDS_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; invalid opcode (INT 6) +INVALID_OPCODE_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; device not available (INT 7) +DEV_NOT_AVAIL_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; double fault (INT 8) +DOUBLE_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; Coprocessor segment overrun - reserved (INT 9) +RSVD_INTR_SEL1 equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; invalid TSS (INT 0ah) +INVALID_TSS_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; segment not present (INT 0bh) +SEG_NOT_PRESENT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; stack fault (INT 0ch) +STACK_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; general protection (INT 0dh) +GP_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; page fault (INT 0eh) +PAGE_FAULT_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; Intel reserved - do not use (INT 0fh) +RSVD_INTR_SEL2 equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; floating point error (INT 10h) +FLT_POINT_ERR_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; alignment check (INT 11h) +ALIGNMENT_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; machine check (INT 12h) +MACHINE_CHECK_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; SIMD floating-point exception (INT 13h) +SIMD_EXCEPTION_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +REPEAT (32 - 20) + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved +ENDM + +; 72 unspecified descriptors + db (72 * 16) dup(0) + +; IRQ 0 (System timer) - (INT 68h) +IRQ0_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 1 (8042 Keyboard controller) - (INT 69h) +IRQ1_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; Reserved - IRQ 2 redirect (IRQ 2) - DO NOT USE!!! - (INT 6ah) +IRQ2_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 3 (COM 2) - (INT 6bh) +IRQ3_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 4 (COM 1) - (INT 6ch) +IRQ4_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 5 (LPT 2) - (INT 6dh) +IRQ5_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 6 (Floppy controller) - (INT 6eh) +IRQ6_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 7 (LPT 1) - (INT 6fh) +IRQ7_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 8 (RTC Alarm) - (INT 70h) +IRQ8_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 9 - (INT 71h) +IRQ9_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 10 - (INT 72h) +IRQ10_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 11 - (INT 73h) +IRQ11_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 12 (PS/2 mouse) - (INT 74h) +IRQ12_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 13 (Floating point error) - (INT 75h) +IRQ13_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 14 (Secondary IDE) - (INT 76h) +IRQ14_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + +; IRQ 15 (Primary IDE) - (INT 77h) +IRQ15_SEL equ $-IDT_BASE + dw 0 ; offset 15:0 + dw SYS_CODE64_SEL ; selector 15:0 + db 0 ; 0 for interrupt gate + db 0eh OR 80h ; (10001110)type = 386 interrupt gate, present + dw 0 ; offset 31:16 + dd 0 ; offset 63:32 + dd 0 ; 0 for reserved + + db (1 * 16) dup(0) + +IDT_END: + + align 02h + +END diff --git a/DuetPkg/CpuIoDxe/CpuIo.c b/DuetPkg/CpuIoDxe/CpuIo.c new file mode 100644 index 0000000000..f95697130c --- /dev/null +++ b/DuetPkg/CpuIoDxe/CpuIo.c @@ -0,0 +1,533 @@ +/*++ + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + CpuIo.c + +Abstract: + + This is the code that publishes the CPU I/O Protocol. + The intent herein is to have a single I/O service that can load + as early as possible, extend into runtime, and be layered upon by + the implementations of architectural protocols and the PCI Root + Bridge I/O Protocol. + +--*/ + +#include "CpuIo.h" +#include "CpuIoAccess.h" + +#define IA32_MAX_IO_ADDRESS 0xFFFF + +EFI_CPU_IO_PROTOCOL mCpuIo = { + { + CpuMemoryServiceRead, + CpuMemoryServiceWrite + }, + { + CpuIoServiceRead, + CpuIoServiceWrite + } +}; + +STATIC +EFI_STATUS +CpuIoMemRW ( + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + IN BOOLEAN DestinationStrideFlag, + OUT PTR Destination, + IN BOOLEAN SourceStrideFlag, + IN PTR Source + ) +/*++ + +Routine Description: + + Private service to perform memory mapped I/O read/write + +Arguments: + + Width - Width of the memory mapped I/O operation + Count - Count of the number of accesses to perform + DestinationStrideFlag - Boolean flag indicates if the destination is to be incremented + Destination - Destination of the memory mapped I/O operation + SourceStrideFlag - Boolean flag indicates if the source is to be incremented + Source - Source of the memory mapped I/O operation + +Returns: + + EFI_SUCCESS - Successful operation + EFI_INVALID_PARAMETER - Width is invalid + +--*/ +{ + UINTN Stride; + UINTN DestinationStride; + UINTN SourceStride; + + Width = Width & 0x03; + Stride = (UINTN)1 << Width; + DestinationStride = DestinationStrideFlag ? Stride : 0; + SourceStride = SourceStrideFlag ? Stride : 0; + + // + // Loop for each iteration and move the data + // + switch (Width) { + case EfiCpuIoWidthUint8: + for (; Count > 0; Count--, Destination.buf += DestinationStride, Source.buf += SourceStride) { + MemoryFence(); + *Destination.ui8 = *Source.ui8; + MemoryFence(); + } + break; + + case EfiCpuIoWidthUint16: + for (; Count > 0; Count--, Destination.buf += DestinationStride, Source.buf += SourceStride) { + MemoryFence (); + *Destination.ui16 = *Source.ui16; + MemoryFence (); + } + break; + + case EfiCpuIoWidthUint32: + for (; Count > 0; Count--, Destination.buf += DestinationStride, Source.buf += SourceStride) { + MemoryFence (); + *Destination.ui32 = *Source.ui32; + MemoryFence (); + } + break; + + case EfiCpuIoWidthUint64: + for (; Count > 0; Count--, Destination.buf += DestinationStride, Source.buf += SourceStride) { + MemoryFence (); + *Destination.ui64 = *Source.ui64; + MemoryFence (); + } + break; + + default: + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +CpuMemoryServiceRead ( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform the memory mapped I/O read service + +Arguments: + + This - Pointer to an instance of the CPU I/O Protocol + Width - Width of the memory mapped I/O operation + Address - Base address of the memory mapped I/O operation + Count - Count of the number of accesses to perform + Buffer - Pointer to the destination buffer to store the results + +Returns: + + EFI_SUCCESS - The data was read. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_INVALID_PARAMETER - Buffer is NULL. + EFI_UNSUPPORTED - The Buffer is not aligned for the given Width. + EFI_UNSUPPORTED - The address range specified by Address, Width, + and Count is not valid. + +--*/ +{ + PTR Source; + PTR Destination; + EFI_STATUS Status; + + Status = CpuIoCheckParameter (Width, Address, Count, Buffer, EFI_MAX_ADDRESS); + if (EFI_ERROR (Status)) { + return Status; + } + + Destination.buf = Buffer; + Source.buf = (VOID *) (UINTN) Address; + + if (Width >= EfiCpuIoWidthUint8 && Width <= EfiCpuIoWidthUint64) { + return CpuIoMemRW (Width, Count, TRUE, Destination, TRUE, Source); + } + + if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) { + return CpuIoMemRW (Width, Count, TRUE, Destination, FALSE, Source); + } + + if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) { + return CpuIoMemRW (Width, Count, FALSE, Destination, TRUE, Source); + } + + return EFI_INVALID_PARAMETER; +} + +EFI_STATUS +EFIAPI +CpuMemoryServiceWrite ( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Perform the memory mapped I/O write service + +Arguments: + + This - Pointer to an instance of the CPU I/O Protocol + Width - Width of the memory mapped I/O operation + Address - Base address of the memory mapped I/O operation + Count - Count of the number of accesses to perform + Buffer - Pointer to the source buffer from which to write data + +Returns: + + EFI_SUCCESS - The data was written. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_INVALID_PARAMETER - Buffer is NULL. + EFI_UNSUPPORTED - The Buffer is not aligned for the given Width. + EFI_UNSUPPORTED - The address range specified by Address, Width, + and Count is not valid. + +--*/ +{ + PTR Source; + PTR Destination; + EFI_STATUS Status; + + Status = CpuIoCheckParameter (Width, Address, Count, Buffer, EFI_MAX_ADDRESS); + if (EFI_ERROR (Status)) { + return Status; + } + + Destination.buf = (VOID *) (UINTN) Address; + Source.buf = Buffer; + + if (Width >= EfiCpuIoWidthUint8 && Width <= EfiCpuIoWidthUint64) { + return CpuIoMemRW (Width, Count, TRUE, Destination, TRUE, Source); + } + + if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) { + return CpuIoMemRW (Width, Count, FALSE, Destination, TRUE, Source); + } + + if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) { + return CpuIoMemRW (Width, Count, TRUE, Destination, FALSE, Source); + } + + return EFI_INVALID_PARAMETER; +} + +EFI_STATUS +EFIAPI +CpuIoServiceRead ( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + OUT VOID *UserBuffer + ) +/*++ + +Routine Description: + + Perform the port I/O read service + +Arguments: + + This - Pointer to an instance of the CPU I/O Protocol + Width - Width of the port I/O operation + Address - Base address of the port I/O operation + Count - Count of the number of accesses to perform + Buffer - Pointer to the destination buffer to store the results + +Returns: + + EFI_SUCCESS - The data was read. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_INVALID_PARAMETER - Buffer is NULL. + EFI_UNSUPPORTED - The Buffer is not aligned for the given Width. + EFI_UNSUPPORTED - The address range specified by Address, Width, + and Count is not valid. + +--*/ +{ + UINTN InStride; + UINTN OutStride; + UINTN Address; + PTR Buffer; + EFI_STATUS Status; + + Buffer.buf = (UINT8 *) UserBuffer; + + if (Width >= EfiCpuIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + Status = CpuIoCheckParameter (Width, UserAddress, Count, UserBuffer, IA32_MAX_IO_ADDRESS); + if (EFI_ERROR (Status)) { + return Status; + } + + Address = (UINTN) UserAddress; + InStride = (UINTN)1 << (Width & 0x03); + OutStride = InStride; + if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) { + InStride = 0; + } + + if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) { + OutStride = 0; + } + + Width = Width & 0x03; + + // + // Loop for each iteration and move the data + // + switch (Width) { + case EfiCpuIoWidthUint8: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + *Buffer.ui8 = CpuIoRead8 ((UINT16) Address); + } + break; + + case EfiCpuIoWidthUint16: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + *Buffer.ui16 = CpuIoRead16 ((UINT16) Address); + } + break; + + case EfiCpuIoWidthUint32: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + *Buffer.ui32 = CpuIoRead32 ((UINT16) Address); + } + break; + + default: + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +CpuIoServiceWrite ( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN VOID *UserBuffer + ) +/*++ + +Routine Description: + + Perform the port I/O write service + +Arguments: + + This - Pointer to an instance of the CPU I/O Protocol + Width - Width of the port I/O operation + Address - Base address of the port I/O operation + Count - Count of the number of accesses to perform + Buffer - Pointer to the source buffer from which to write data + +Returns: + + EFI_SUCCESS - The data was written. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_INVALID_PARAMETER - Buffer is NULL. + EFI_UNSUPPORTED - The Buffer is not aligned for the given Width. + EFI_UNSUPPORTED - The address range specified by Address, Width, + and Count is not valid. + +--*/ +{ + UINTN InStride; + UINTN OutStride; + UINTN Address; + PTR Buffer; + EFI_STATUS Status; + + Buffer.buf = (UINT8 *) UserBuffer; + + if (Width >= EfiCpuIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + Status = CpuIoCheckParameter (Width, UserAddress, Count, UserBuffer, IA32_MAX_IO_ADDRESS); + if (EFI_ERROR (Status)) { + return Status; + } + + Address = (UINTN) UserAddress; + InStride = (UINTN)1 << (Width & 0x03); + OutStride = InStride; + if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) { + InStride = 0; + } + + if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) { + OutStride = 0; + } + + Width = Width & 0x03; + + // + // Loop for each iteration and move the data + // + switch (Width) { + case EfiCpuIoWidthUint8: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + CpuIoWrite8 ((UINT16) Address, *Buffer.ui8); + } + break; + + case EfiCpuIoWidthUint16: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + CpuIoWrite16 ((UINT16) Address, *Buffer.ui16); + } + break; + + case EfiCpuIoWidthUint32: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + CpuIoWrite32 ((UINT16) Address, *Buffer.ui32); + } + break; + + default: + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +CpuIoInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + CpuIo driver entry point. + +Arguments: + + ImageHandle - The firmware allocated handle for the EFI image. + SystemTable - A pointer to the EFI System Table. + +Returns: + + EFI_SUCCESS - The driver was initialized. + EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources. + +--*/ +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + Handle = NULL; + Status = SystemTable->BootServices->InstallProtocolInterface ( + &Handle, + &gEfiCpuIoProtocolGuid, + EFI_NATIVE_INTERFACE, + &mCpuIo + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +EFI_STATUS +CpuIoCheckParameter ( + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer, + IN UINT64 Limit + ) +/*++ + +Routine Description: + + Check the validation of parameters for CPU I/O interface functions. + +Arguments: + + Width - Width of the Memory Access + Address - Address of the Memory access + Count - Count of the number of accesses to perform + Buffer - Pointer to the buffer to read from memory + Buffer - Memory buffer for the I/O operation + Limit - Maximum address supported + +Returns: + + EFI_INVALID_PARAMETER - Buffer is NULL + EFI_UNSUPPORTED - The address range specified by Width, Address and Count is invalid + EFI_UNSUPPORTED - The memory buffer is not aligned + EFI_SUCCESS - Parameters are OK + +--*/ +{ + UINTN AlignMask; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Address > Limit) { + return EFI_UNSUPPORTED; + } + + // + // For FiFo type, the target address won't increase during the access, + // so treat count as 1 + // + if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) { + Count = 1; + } + + Width = Width & 0x03; + if (Address - 1 + ((UINTN)1 << Width) * Count > Limit) { + return EFI_UNSUPPORTED; + } + + AlignMask = ((UINTN)1 << Width) - 1; + if ((UINTN) Buffer & AlignMask) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} diff --git a/DuetPkg/CpuIoDxe/CpuIo.h b/DuetPkg/CpuIoDxe/CpuIo.h new file mode 100644 index 0000000000..622cc1560f --- /dev/null +++ b/DuetPkg/CpuIoDxe/CpuIo.h @@ -0,0 +1,245 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + CpuIo.h + +Abstract: + *.h file for the driver + + Note: the EFIAPI on the CpuIo functions is used to glue MASM (assembler) code + into C code. By making the MASM functions EFIAPI it ensures that a standard + C calling convention is assumed by the compiler, reguardless of the compiler + flags. + + +--*/ + +#ifndef _CPU_IO_H +#define _CPU_IO_H + +#include + +#include + +#include +#include + +#define VOLATILE volatile + +typedef union { + UINT8 VOLATILE *buf; + UINT8 VOLATILE *ui8; + UINT16 VOLATILE *ui16; + UINT32 VOLATILE *ui32; + UINT64 VOLATILE *ui64; + UINTN VOLATILE ui; +} PTR; + +EFI_STATUS +EFIAPI +CpuIoInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + CpuIo driver entry point. + +Arguments: + + ImageHandle - The firmware allocated handle for the EFI image. + SystemTable - A pointer to the EFI System Table. + +Returns: + + EFI_SUCCESS - The driver was initialized. + EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources. + +--*/ +; + +EFI_STATUS +EFIAPI +CpuMemoryServiceRead ( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform the memory mapped I/O read service + +Arguments: + + This - Pointer to an instance of the CPU I/O Protocol + Width - Width of the memory mapped I/O operation + Address - Base address of the memory mapped I/O operation + Count - Count of the number of accesses to perform + Buffer - Pointer to the destination buffer to store the results + +Returns: + + EFI_SUCCESS - The data was read. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_INVALID_PARAMETER - Buffer is NULL. + EFI_UNSUPPORTED - The Buffer is not aligned for the given Width. + EFI_UNSUPPORTED - The address range specified by Address, Width, + and Count is not valid. + +--*/ +; + +EFI_STATUS +EFIAPI +CpuMemoryServiceWrite ( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Perform the memory mapped I/O write service + +Arguments: + + This - Pointer to an instance of the CPU I/O Protocol + Width - Width of the memory mapped I/O operation + Address - Base address of the memory mapped I/O operation + Count - Count of the number of accesses to perform + Buffer - Pointer to the source buffer from which to write data + +Returns: + + EFI_SUCCESS - The data was written. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_INVALID_PARAMETER - Buffer is NULL. + EFI_UNSUPPORTED - The Buffer is not aligned for the given Width. + EFI_UNSUPPORTED - The address range specified by Address, Width, + and Count is not valid. + +--*/ +; + +EFI_STATUS +EFIAPI +CpuIoServiceRead ( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + OUT VOID *UserBuffer + ) +/*++ + +Routine Description: + + Perform the port I/O read service + +Arguments: + + This - Pointer to an instance of the CPU I/O Protocol + Width - Width of the port I/O operation + Address - Base address of the port I/O operation + Count - Count of the number of accesses to perform + Buffer - Pointer to the destination buffer to store the results + +Returns: + + EFI_SUCCESS - The data was read. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_INVALID_PARAMETER - Buffer is NULL. + EFI_UNSUPPORTED - The Buffer is not aligned for the given Width. + EFI_UNSUPPORTED - The address range specified by Address, Width, + and Count is not valid. + +--*/ +; + +EFI_STATUS +EFIAPI +CpuIoServiceWrite ( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN VOID *UserBuffer + ) +/*++ + +Routine Description: + + Perform the port I/O write service + +Arguments: + + This - Pointer to an instance of the CPU I/O Protocol + Width - Width of the port I/O operation + Address - Base address of the port I/O operation + Count - Count of the number of accesses to perform + Buffer - Pointer to the source buffer from which to write data + +Returns: + + EFI_SUCCESS - The data was written. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_INVALID_PARAMETER - Buffer is NULL. + EFI_UNSUPPORTED - The Buffer is not aligned for the given Width. + EFI_UNSUPPORTED - The address range specified by Address, Width, + and Count is not valid. + +--*/ +; + +EFI_STATUS +CpuIoCheckParameter ( + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer, + IN UINT64 Limit + ) +/*++ + +Routine Description: + + Check the validation of parameters for CPU I/O interface functions. + +Arguments: + + Width - Width of the Memory Access + Address - Address of the Memory access + Count - Count of the number of accesses to perform + Buffer - Pointer to the buffer to read from memory + Buffer - Memory buffer for the I/O operation + Limit - Maximum address supported + +Returns: + + EFI_INVALID_PARAMETER - Buffer is NULL + EFI_UNSUPPORTED - The address range specified by Width, Address and Count is invalid + EFI_UNSUPPORTED - The memory buffer is not aligned + EFI_SUCCESS - Parameters are OK + +--*/ +; + +#endif diff --git a/DuetPkg/CpuIoDxe/CpuIo.inf b/DuetPkg/CpuIoDxe/CpuIo.inf new file mode 100644 index 0000000000..9deda69ce0 --- /dev/null +++ b/DuetPkg/CpuIoDxe/CpuIo.inf @@ -0,0 +1,56 @@ +#/*++ +# +# Copyright (c) 2004, Intel Corporation +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# CpuIo.inf +# +# Abstract: +# +# Component description file for CpuIo module +# +#--*/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = CpuIo + FILE_GUID = BAE7599F-3C6B-43b7-BDF0-9CE07AA91AA6 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x00020000 + + ENTRY_POINT = CpuIoInitialize + +[Packages] + DuetPkg/DuetPkg.dec + MdePkg/MdePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + UefiDriverEntryPoint + IoLib + +[Sources.common] + CpuIo.c + CpuIo.h + CpuIoAccess.h + +[Sources.IA32] + IA32\CpuIoAccess.asm + +[Sources.X64] + X64\CpuIoAccess.asm + +[Protocols] + gEfiCpuIoProtocolGuid \ No newline at end of file diff --git a/DuetPkg/CpuIoDxe/CpuIoAccess.h b/DuetPkg/CpuIoDxe/CpuIoAccess.h new file mode 100644 index 0000000000..3983ec8f73 --- /dev/null +++ b/DuetPkg/CpuIoDxe/CpuIoAccess.h @@ -0,0 +1,216 @@ +/*++ +# +# Copyright (c) 2004, Intel Corporation +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: + + CpuIoAccess.h + +Abstract: + +--*/ + +#ifndef _CPU_IO_ACCESS_H +#define _CPU_IO_ACCESS_H + + +#define IA32API __cdecl + +UINT8 +IA32API +CpuIoRead8 ( + IN UINT16 Port + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Port - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +/*++ +Routine Description: + Cpu I/O read port +Arguments: + Port: - Port number to read +Returns: + Return read 8 bit value +--*/ +UINT16 +IA32API +CpuIoRead16 ( + IN UINT16 Port + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Port - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +/*++ +Routine Description: + Cpu I/O read port +Arguments: + Port: - Port number to read +Returns: + Return read 16 bit value +--*/ +UINT32 +IA32API +CpuIoRead32 ( + IN UINT16 Port + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Port - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +/*++ +Routine Description: + Cpu I/O read port +Arguments: + Port: - Port number to read +Returns: + Return read 32 bit value +--*/ +VOID +IA32API +CpuIoWrite8 ( + IN UINT16 Port, + IN UINT32 Data + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Port - GC_TODO: add argument description + Data - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +/*++ +Routine Description: + Cpu I/O write 8 bit data to port +Arguments: + Port: - Port number to read + Data: - Data to write to the Port +Returns: + None +--*/ +VOID +IA32API +CpuIoWrite16 ( + IN UINT16 Port, + IN UINT32 Data + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Port - GC_TODO: add argument description + Data - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +/*++ +Routine Description: + Cpu I/O write 16 bit data to port +Arguments: + Port: - Port number to read + Data: - Data to write to the Port +Returns: + None +--*/ +VOID +IA32API +CpuIoWrite32 ( + IN UINT16 Port, + IN UINT32 Data + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Port - GC_TODO: add argument description + Data - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +/*++ +Routine Description: + Cpu I/O write 32 bit data to port +Arguments: + Port: - Port number to read + Data: - Data to write to the Port +Returns: + None +--*/ +#endif diff --git a/DuetPkg/CpuIoDxe/Ia32/CpuIoAccess.asm b/DuetPkg/CpuIoDxe/Ia32/CpuIoAccess.asm new file mode 100644 index 0000000000..07b14ea554 --- /dev/null +++ b/DuetPkg/CpuIoDxe/Ia32/CpuIoAccess.asm @@ -0,0 +1,120 @@ + title CpuIoAccess.asm +;------------------------------------------------------------------------------ +;* +;* Copyright (c) 2005, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* Module Name: +;* CpuIoAccess.asm +;* +;* Abstract: +;* Supports IA32 CPU IO operation +;* +;------------------------------------------------------------------------------ +; +; +;------------------------------------------------------------------------------ + + .686 + .MODEL FLAT,C + .CODE + + +UINT8 TYPEDEF BYTE +UINT16 TYPEDEF WORD +UINT32 TYPEDEF DWORD +UINT64 TYPEDEF QWORD +UINTN TYPEDEF UINT32 + + + +;------------------------------------------------------------------------------ +; UINT8 +; CpuIoRead8 ( +; IN UINT16 Port +; ) +;------------------------------------------------------------------------------ +CpuIoRead8 PROC PUBLIC Port:UINT16 + mov dx, Port + in al, dx + ret +CpuIoRead8 ENDP + +;------------------------------------------------------------------------------ +; UINT16 +; CpuIoRead16 ( +; IN UINT16 Port +; ) +;------------------------------------------------------------------------------ +CpuIoRead16 PROC PUBLIC Port:UINT16 + mov dx, Port + in ax, dx + ret +CpuIoRead16 ENDP + +;------------------------------------------------------------------------------ +; UINT32 +; CpuIoRead32 ( +; IN UINT16 Port +; ) +;------------------------------------------------------------------------------ +CpuIoRead32 PROC PUBLIC Port:UINT16 + mov dx, Port + in eax, dx + ret +CpuIoRead32 ENDP + + + +;------------------------------------------------------------------------------ +; VOID +; CpuIoWrite8 ( +; IN UINT16 Port, +; IN UINT32 Data +; ) +;------------------------------------------------------------------------------ +CpuIoWrite8 PROC PUBLIC Port:UINT16, Data:UINT32 + mov eax, Data + mov dx, Port + out dx, al + ret +CpuIoWrite8 ENDP + + +;------------------------------------------------------------------------------ +; VOID +; CpuIoWrite16 ( +; IN UINT16 Port, +; IN UINT32 Data +; ) +;------------------------------------------------------------------------------ +CpuIoWrite16 PROC PUBLIC Port:UINT16, Data:UINT32 + mov eax, Data + mov dx, Port + out dx, ax + ret +CpuIoWrite16 ENDP + + +;------------------------------------------------------------------------------ +; VOID +; CpuIoWrite32 ( +; IN UINT16 Port, +; IN UINT32 Data +; ) +;------------------------------------------------------------------------------ +CpuIoWrite32 PROC PUBLIC Port:UINT16, Data:UINT32 + mov eax, Data + mov dx, Port + out dx, eax + ret +CpuIoWrite32 ENDP + + +END \ No newline at end of file diff --git a/DuetPkg/CpuIoDxe/Ia32CpuIo.dxs b/DuetPkg/CpuIoDxe/Ia32CpuIo.dxs new file mode 100644 index 0000000000..874f333985 --- /dev/null +++ b/DuetPkg/CpuIoDxe/Ia32CpuIo.dxs @@ -0,0 +1,26 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + Ia32CpuIo.dxs + +Abstract: + + Dependency expression source file. + +--*/ + +#include "EfiDepex.h" + + +DEPENDENCY_START + TRUE +DEPENDENCY_END diff --git a/DuetPkg/CpuIoDxe/x64/CpuIoAccess.asm b/DuetPkg/CpuIoDxe/x64/CpuIoAccess.asm new file mode 100644 index 0000000000..fa71762877 --- /dev/null +++ b/DuetPkg/CpuIoDxe/x64/CpuIoAccess.asm @@ -0,0 +1,111 @@ + title CpuIoAccess.asm + +;------------------------------------------------------------------------------ +;* +;* Copyright (c) 2005 - 2007, Intel Corporation +;* All rights reserved. This program and the accompanying materials +;* are licensed and made available under the terms and conditions of the BSD License +;* which accompanies this distribution. The full text of the license may be found at +;* http://opensource.org/licenses/bsd-license.php +;* +;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +;* +;* Module Name: +;* CpuIoAccess.asm +;* +;* Abstract: +;* Supports x64 CPU IO operation +;* +;------------------------------------------------------------------------------ +; +; +; +; Abstract: +; +; +;------------------------------------------------------------------------------ + +.CODE + +;------------------------------------------------------------------------------ +; UINT8 +; CpuIoRead8 ( +; UINT16 Port // rcx +; ) +;------------------------------------------------------------------------------ +CpuIoRead8 PROC PUBLIC + xor eax, eax + mov dx, cx + in al, dx + ret +CpuIoRead8 ENDP + +;------------------------------------------------------------------------------ +; VOID +; CpuIoWrite8 ( +; UINT16 Port, // rcx +; UINT32 Data // rdx +; ) +;------------------------------------------------------------------------------ +CpuIoWrite8 PROC PUBLIC + mov eax, edx + mov dx, cx + out dx, al + ret +CpuIoWrite8 ENDP + +;------------------------------------------------------------------------------ +; UINT16 +; CpuIoRead16 ( +; UINT16 Port // rcx +; ) +;------------------------------------------------------------------------------ +CpuIoRead16 PROC PUBLIC + xor eax, eax + mov dx, cx + in ax, dx + ret +CpuIoRead16 ENDP + +;------------------------------------------------------------------------------ +; VOID +; CpuIoWrite16 ( +; UINT16 Port, // rcx +; UINT32 Data // rdx +; ) +;------------------------------------------------------------------------------ +CpuIoWrite16 PROC PUBLIC + mov eax, edx + mov dx, cx + out dx, ax + ret +CpuIoWrite16 ENDP + +;------------------------------------------------------------------------------ +; UINT32 +; CpuIoRead32 ( +; UINT16 Port // rcx +; ) +;------------------------------------------------------------------------------ +CpuIoRead32 PROC PUBLIC + mov dx, cx + in eax, dx + ret +CpuIoRead32 ENDP + +;------------------------------------------------------------------------------ +; VOID +; CpuIoWrite32 ( +; UINT16 Port, // rcx +; UINT32 Data // rdx +; ) +;------------------------------------------------------------------------------ +CpuIoWrite32 PROC PUBLIC + mov eax, edx + mov dx, cx + out dx, eax + ret +CpuIoWrite32 ENDP + +END diff --git a/DuetPkg/DuetPkg.dec b/DuetPkg/DuetPkg.dec index 77a368c69e..7bea09ebb1 100644 --- a/DuetPkg/DuetPkg.dec +++ b/DuetPkg/DuetPkg.dec @@ -9,4 +9,8 @@ [Guids.common] gEfiPciExpressBaseAddressGuid = {0x3677d529, 0x326f, 0x4603, {0xa9, 0x26, 0xea, 0xac, 0xe0, 0x1d, 0xcb, 0xb0 }} - gEfiAcpiDescriptionGuid = {0x3c699197, 0x093c, 0x4c69, {0xb0, 0x6b, 0x12, 0x8a, 0xe3, 0x48, 0x1d, 0xc9 }} \ No newline at end of file + gEfiAcpiDescriptionGuid = {0x3c699197, 0x093c, 0x4c69, {0xb0, 0x6b, 0x12, 0x8a, 0xe3, 0x48, 0x1d, 0xc9 }} + gEfiFlashMapHobGuid = { 0xb091e7d2, 0x5a0, 0x4198, {0x94, 0xf0, 0x74, 0xb7, 0xb8, 0xc5, 0x54, 0x59 }} + +[Protocols.common] + gEfiLegacyBiosThunkProtocolGuid = {0x4c51a7ba, 0x7195, 0x442d, {0x87, 0x92, 0xbe, 0xea, 0x6e, 0x2f, 0xf6, 0xec}} \ No newline at end of file diff --git a/DuetPkg/DuetPkg.dsc b/DuetPkg/DuetPkg.dsc index 3cd902fc83..d47bad9382 100644 --- a/DuetPkg/DuetPkg.dsc +++ b/DuetPkg/DuetPkg.dsc @@ -9,7 +9,7 @@ SUPPORTED_ARCHITECTURES = IA32|X64 BUILD_TARGETS = DEBUG SKUID_IDENTIFIER = DEFAULT - #FLASH_DEFINITION = DuetPkg/DuetPkg.fdf + FLASH_DEFINITION = DuetPkg/DuetPkg.fdf [LibraryClasses.common] BaseLib|MdePkg/Library/BaseLib/BaseLib.inf @@ -26,15 +26,106 @@ HiiLib|MdePkg/Library/HiiLib/HiiLib.inf UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf + UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf + UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf + BaseUefiTianoDecompressLib|IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLib.inf + ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf + PlatformBdsLib|DuetPkg/Library/DuetBdsLib/PlatformBds.inf + IfrSupportLib|MdePkg/Library/IfrSupportLib/IfrSupportLib.inf + ExtendedIfrSupportLib|MdeModulePkg/Library/ExtendedIfrSupportLib/ExtendedIfrSupportLib.inf + GenericBdsLib|MdeModulePkg/Library/GenericBdsLib/GenericBdsLib.inf + PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf + GraphicsLib|MdeModulePkg/Library/GraphicsLib/GraphicsLib.inf + ExtendedHiiLib|MdeModulePkg/Library/ExtendedHiiLib/ExtendedHiiLib.inf + CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf + DxePiLib|MdePkg/Library/DxePiLib/DxePiLib.inf + PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf + PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + OemHookStatusCodeLib|IntelFrameworkModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf [LibraryClasses.common.DXE_DRIVER] MemoryAllocationLib|MdePkg/Library/DxeMemoryAllocationLib/DxeMemoryAllocationLib.inf HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + ReportStatusCodeLib|IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.inf + SerialPortLib|MdePkg/Library/SerialPortLibNull/SerialPortLibNull.inf + MemoryAllocationLib|MdePkg/Library/DxeMemoryAllocationLib/DxeMemoryAllocationLib.inf + IoLib|IntelFrameworkPkg/Library/DxeIoLibCpuIo/DxeIoLibCpuIo.inf + UsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf + +[LibraryClasses.common.DXE_CORE] + HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf + PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + DxeCoreEntryPoint|MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.inf + MemoryAllocationLib|MdePkg/Library/DxeMemoryAllocationLib/DxeMemoryAllocationLib.inf + UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf + +[LibraryClasses.common.DXE_RUNTIME_DRIVER] + MemoryAllocationLib|MdePkg/Library/DxeMemoryAllocationLib/DxeMemoryAllocationLib.inf + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + ReportStatusCodeLib|IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.inf + SerialPortLib|MdePkg/Library/SerialPortLibNull/SerialPortLibNull.inf + IoLib|IntelFrameworkPkg/Library/DxeIoLibCpuIo/DxeIoLibCpuIo.inf + TimerLib|MdePkg/Library/SecPeiDxeTimerLibCpu/SecPeiDxeTimerLibCpu.inf -[Components.IA32] +[LibraryClasses.common.UEFI_DRIVER] + MemoryAllocationLib|MdePkg/Library/DxeMemoryAllocationLib/DxeMemoryAllocationLib.inf + +[LibraryClasses.common.UEFI_APPLICATION] + MemoryAllocationLib|MdePkg/Library/DxeMemoryAllocationLib/DxeMemoryAllocationLib.inf + +[Components.common] DuetPkg/DxeIpl/DxeIpl.inf + + MdeModulePkg/Core/Dxe/DxeMain.inf + MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf + MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf + MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf + + DuetPkg/FSVariable/FSVariable.inf + + MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf + MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf + IntelFrameworkModulePkg/Universal/StatusCode/Dxe/DxeStatusCode.inf + MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf + MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf + MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf + MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf + + IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.inf + MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf + MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf + MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf + DuetPkg/DataHubGenDxe/DataHubGen.inf + DuetPkg/FvbRuntimeService/DUETFwh.inf + DuetPkg/EfiLdr/EfiLdr.inf + MdeModulePkg/Universal/BdsDxe/BdsDxe.inf + DuetPkg/CpuIoDxe/CpuIo.inf + DuetPkg/CpuDxe/Cpu.inf + + IntelFrameworkModulePkg/Universal/Legacy8259Dxe/8259.inf + DuetPkg/KbcResetDxe/Reset.inf + DuetPkg/LegacyMetronome/Metronome.inf -[Components.X64] - DuetPkg/DxeIpl/DxeIpl.inf - DuetPkg/DataHubGenDxe/DataHubGen.inf \ No newline at end of file + DuetPkg/PcRtc/RealTimeClock.inf + DuetPkg/PciRootBridgeNoEnumerationDxe/PciRootBridgeNoEnumeration.inf + IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClassDxe.inf + + # IDE Support + #IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxe.inf + + # Usb Support + MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf + MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf + MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf + MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf + MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.inf + + # ISA Support + DuetPkg/IsaAcpiDxe/IsaAcpi.inf + DuetPkg/BootSector/BootSector.inf diff --git a/DuetPkg/DuetPkg.fdf b/DuetPkg/DuetPkg.fdf new file mode 100644 index 0000000000..faa2ca0388 --- /dev/null +++ b/DuetPkg/DuetPkg.fdf @@ -0,0 +1,189 @@ +# This is NT32 FDF file with UEFI HII features enabled +# +# Copyright (c) 2007, Intel Corporation +# +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# + +################################################################################ +# +# FD Section +# The [FD] Section is made up of the definition statements and a +# description of what goes into the Flash Device Image. Each FD section +# defines one flash "device" image. A flash device image may be one of +# the following: Removable media bootable image (like a boot floppy +# image,) an Option ROM image (that would be "flashed" into an add-in +# card,) a System "Flash" image (that would be burned into a system's +# flash) or an Update ("Capsule") image that will be used to update and +# existing system flash. +# +################################################################################ +[FD.DuetMainFd] +BaseAddress = 0x0 #The base address of the FLASH Device. +Size = 0x002a0000 #The size in bytes of the FLASH Device +ErasePolarity = 1 +BlockSize = 0x10000 +NumBlocks = 0x2a + +0x00000000|0x002a0000 + +################################################################################ +# +# FV Section +# +# [FV] section is used to define what components or modules are placed within a flash +# device file. This section also defines order the components and modules are positioned +# within the image. The [FV] section consists of define statements, set statements and +# module statements. +# +################################################################################ +[FV.DuetEfiMainFv] +FvAlignment = 16 #FV alignment and FV attributes setting. +ERASE_POLARITY = 1 +MEMORY_MAPPED = TRUE +STICKY_WRITE = TRUE +LOCK_CAP = TRUE +LOCK_STATUS = TRUE +WRITE_DISABLED_CAP = TRUE +WRITE_ENABLED_CAP = TRUE +WRITE_STATUS = TRUE +WRITE_LOCK_CAP = TRUE +WRITE_LOCK_STATUS = TRUE +READ_DISABLED_CAP = TRUE +READ_ENABLED_CAP = TRUE +READ_STATUS = TRUE +READ_LOCK_CAP = TRUE +READ_LOCK_STATUS = TRUE + +INF MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf +INF MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf +INF MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf + +INF DuetPkg/FSVariable/FSVariable.inf + +INF MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf +INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf +INF IntelFrameworkModulePkg/Universal/StatusCode/Dxe/DxeStatusCode.inf +INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf +INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf +INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf +INF MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf + +INF IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.inf +INF MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf +INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf +INF MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf + +INF DuetPkg/DataHubGenDxe/DataHubGen.inf +INF DuetPkg/FvbRuntimeService/DUETFwh.inf +INF MdeModulePkg/Universal/BdsDxe/BdsDxe.inf +INF DuetPkg/CpuIoDxe/CpuIo.inf +INF DuetPkg/CpuDxe/Cpu.inf + +INF IntelFrameworkModulePkg/Universal/Legacy8259Dxe/8259.inf +INF DuetPkg/KbcResetDxe/Reset.inf +INF DuetPkg/LegacyMetronome/Metronome.inf + +INF DuetPkg/PcRtc/RealTimeClock.inf +INF DuetPkg/PciRootBridgeNoEnumerationDxe/PciRootBridgeNoEnumeration.inf +INF IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClassDxe.inf + + # IDE Support + #IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxe.inf + + # Usb Support +INF MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf +INF MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf +INF MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf +INF MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf +INF MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.inf + + # ISA Support +INF DuetPkg/IsaAcpiDxe/IsaAcpi.inf + +[Rule.Common.PEI_CORE] + FILE PEI_CORE = $(NAMED_GUID) { + PE32 PE32 |.efi + UI STRING ="$(MODULE_NAME)" Optional + VERSION STRING ="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) + } + +[Rule.Common.PEIM] + FILE PEIM = $(NAMED_GUID) { + PEI_DEPEX PEI_DEPEX Optional |.depex + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) + } + +[Rule.Common.PEIM.TIANOCOMPRESSED] + FILE PEIM = $(NAMED_GUID) DEBUG_MYTOOLS_IA32 { + PEI_DEPEX PEI_DEPEX Optional |.depex + GUIDED A31280AD-481E-41B6-95E8-127F4C984779 PROCESSING_REQUIRED = TRUE { + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) + } + } + +[Rule.Common.DXE_CORE] + FILE DXE_CORE = $(NAMED_GUID) { + COMPRESS PI_STD { + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) + } + } + +[Rule.Common.UEFI_DRIVER] + FILE DRIVER = $(NAMED_GUID) { + DXE_DEPEX DXE_DEPEX Optional |.depex + COMPRESS PI_STD { + GUIDED { + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) + } + } + } + +[Rule.Common.DXE_DRIVER] + FILE DRIVER = $(NAMED_GUID) { + DXE_DEPEX DXE_DEPEX Optional |.depex + COMPRESS PI_STD { + GUIDED { + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) + } + } + } + +[Rule.Common.DXE_RUNTIME_DRIVER] + FILE DRIVER = $(NAMED_GUID) { + DXE_DEPEX DXE_DEPEX Optional |.depex + COMPRESS PI_STD { + GUIDED { + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) + } + } + } + +[Rule.Common.UEFI_APPLICATION] + FILE APPLICATION = $(NAMED_GUID) { + COMPRESS PI_STD { + GUIDED { + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) + } + } + } diff --git a/DuetPkg/DxeIpl/DxeIpl.inf b/DuetPkg/DxeIpl/DxeIpl.inf index 0e6d1fb585..bea8730a2e 100644 --- a/DuetPkg/DxeIpl/DxeIpl.inf +++ b/DuetPkg/DxeIpl/DxeIpl.inf @@ -20,7 +20,7 @@ INF_VERSION = 0x00010005 BASE_NAME = DxeIpl FILE_GUID = 2119BBD7-9432-4f47-B5E2-5C4EA31B6BDC - MODULE_TYPE = USER_DEFINED + MODULE_TYPE = DXE_DRIVER VERSION_STRING = 1.0 EDK_RELEASE_VERSION = 0x00020000 EFI_SPECIFICATION_VERSION = 0x00020000 @@ -38,6 +38,7 @@ BaseMemoryLib PrintLib ReportStatusCodeLib + UefiDriverEntryPoint [Sources.common] DxeIpl.h @@ -65,9 +66,9 @@ Ia32\Paging.c Ia32\VirtualMemory.h -[BuildOptions.common] +#[BuildOptions.common] #MSFT:*_*_IA32_DLINK_FLAGS = /out:"$(BIN_DIR)\SecMain.exe" /base:0x10000000 /pdb:"$(BIN_DIR)\SecMain.pdb" /LIBPATH:"$(VCINSTALLDIR)\Lib" /LIBPATH:"$(VCINSTALLDIR)\PlatformSdk\Lib" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /MAP /OPT:REF /DEBUG /MACHINE:I386 /LTCG Kernel32.lib MSVCRTD.lib Gdi32.lib User32.lib Winmm.lib - MSFT:*_*_IA32_CC_FLAGS = /nologo /W4 /WX /Gy /c /D UNICODE /Od /FI$(DEST_DIR_DEBUG)/AutoGen.h /EHs-c- /GF /Gs8192 /Zi /Gm /D _CRT_SECURE_NO_WARNINGS /D _CRT_SECURE_NO_DEPRECATE - MSFT:*_*_IA32_PP_FLAGS = /nologo /E /TC /FI$(DEST_DIR_DEBUG)/AutoGen.h - MSFT:*_*_IA32_ASM_FLAGS = /nologo /W3 /WX /c /coff /Cx /Zd /W0 /Zi - MSFT:*_*_IA32_ASMLINK_FLAGS = /link /nologo /tiny + #MSFT:*_*_IA32_CC_FLAGS = /nologo /W4 /WX /Gy /c /D UNICODE /Od /FI$(DEST_DIR_DEBUG)/AutoGen.h /EHs-c- /GF /Gs8192 /Zi /Gm /D _CRT_SECURE_NO_WARNINGS /D _CRT_SECURE_NO_DEPRECATE + #MSFT:*_*_IA32_PP_FLAGS = /nologo /E /TC /FI$(DEST_DIR_DEBUG)/AutoGen.h + #MSFT:*_*_IA32_ASM_FLAGS = /nologo /W3 /WX /c /coff /Cx /Zd /W0 /Zi + #MSFT:*_*_IA32_ASMLINK_FLAGS = /link /nologo /tiny diff --git a/DuetPkg/Include/EfiFlashMap.h b/DuetPkg/Include/EfiFlashMap.h index 5dfad52205..240789c4c6 100644 --- a/DuetPkg/Include/EfiFlashMap.h +++ b/DuetPkg/Include/EfiFlashMap.h @@ -22,7 +22,6 @@ Abstract: #ifndef _EFI_FLASHMAP_H_ #define _EFI_FLASHMAP_H_ - // // Definition for flash map GUIDed HOBs // @@ -59,6 +58,7 @@ typedef UINT8 EFI_FLASH_AREA_TYPE; // An individual sub-area Entry. // A single flash area may consist of more than one sub-area. // +/** typedef struct { EFI_FLASH_AREA_ATTRIBUTES Attributes; UINT32 Reserved; @@ -121,6 +121,32 @@ typedef struct { UINT8 Reserved[3]; EFI_GUID AreaTypeGuid; } EFI_FLASH_AREA_DATA; +**/ + +typedef struct { + EFI_FLASH_AREA_ATTRIBUTES Attributes; + UINT32 Reserved; + EFI_PHYSICAL_ADDRESS Base; + EFI_PHYSICAL_ADDRESS Length; + EFI_GUID FileSystem; +} EFI_FLASH_SUBAREA_ENTRY; + +typedef struct { + UINT8 Reserved[3]; + EFI_FLASH_AREA_TYPE AreaType; + EFI_GUID AreaTypeGuid; + UINT32 NumberOfEntries; + EFI_FLASH_SUBAREA_ENTRY Entries[1]; + // + // Extended Hob data. + // + // VolumeId and FilePath indicating a unique file. + // + UINT32 VolumeId; + CHAR16 FilePath[256]; + UINT32 ActuralSize; + UINT32 Offset; +} EFI_FLASH_MAP_FS_ENTRY_DATA; #pragma pack() diff --git a/DuetPkg/IsaAcpiDxe/ComponentName.c b/DuetPkg/IsaAcpiDxe/ComponentName.c new file mode 100644 index 0000000000..01084223d0 --- /dev/null +++ b/DuetPkg/IsaAcpiDxe/ComponentName.c @@ -0,0 +1,170 @@ +/*++ + +Copyright (c) 2006 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "PcatIsaAcpi.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +PcatIsaAcpiComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +PcatIsaAcpiComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +// +// EFI Component Name Protocol +// + +EFI_COMPONENT_NAME2_PROTOCOL gPcatIsaAcpiComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) PcatIsaAcpiComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) PcatIsaAcpiComponentNameGetControllerName, + "en" +}; + +EFI_COMPONENT_NAME_PROTOCOL gPcatIsaAcpiComponentName = { + PcatIsaAcpiComponentNameGetDriverName, + PcatIsaAcpiComponentNameGetControllerName, + "eng" +}; + + +static EFI_UNICODE_STRING_TABLE mPcatIsaAcpiDriverNameTable[] = { + { + "eng;en", + L"PC-AT ISA Device Enumeration Driver" + }, + { + NULL, + NULL + } +}; + +EFI_STATUS +EFIAPI +PcatIsaAcpiComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + Language - A pointer to a three character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + DriverName - A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + Returns: + EFI_SUCCES - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mPcatIsaAcpiDriverNameTable, + DriverName, + (BOOLEAN)(This == &gPcatIsaAcpiComponentName) + ); +} + +EFI_STATUS +EFIAPI +PcatIsaAcpiComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + ControllerHandle - The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + ChildHandle - The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + ControllerName - A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language specified + by Language from the point of view of the driver specified + by This. + + Returns: + EFI_SUCCESS - The Unicode string for the user readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return EFI_UNSUPPORTED; +} diff --git a/DuetPkg/IsaAcpiDxe/IsaAcpi.c b/DuetPkg/IsaAcpiDxe/IsaAcpi.c new file mode 100644 index 0000000000..e3792a7818 --- /dev/null +++ b/DuetPkg/IsaAcpiDxe/IsaAcpi.c @@ -0,0 +1,306 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: + + IsaAcpi.c + +Abstract: + + ISA ACPI Protocol Implementation + +Revision History + +--*/ + +#include "PcatIsaAcpi.h" + +// +// Platform specific data for the ISA devices that are present.in the platform +// + +// +// COM 1 UART Controller +// +static EFI_ISA_ACPI_RESOURCE mPcatIsaAcpiCom1DeviceResources[] = { + {EfiIsaAcpiResourceIo, 0, 0x3f8, 0x3ff}, + {EfiIsaAcpiResourceInterrupt, 0, 4, 0}, + {EfiIsaAcpiResourceEndOfList, 0, 0, 0} +}; + +// +// COM 2 UART Controller +// +static EFI_ISA_ACPI_RESOURCE mPcatIsaAcpiCom2DeviceResources[] = { + {EfiIsaAcpiResourceIo, 0, 0x2f8, 0x2ff}, + {EfiIsaAcpiResourceInterrupt, 0, 3, 0}, + {EfiIsaAcpiResourceEndOfList, 0, 0, 0} +}; + +// +// PS/2 Keyboard Controller +// +static EFI_ISA_ACPI_RESOURCE mPcatIsaAcpiPs2KeyboardDeviceResources[] = { + {EfiIsaAcpiResourceIo, 0, 0x60, 0x64}, + {EfiIsaAcpiResourceInterrupt, 0, 1, 0}, + {EfiIsaAcpiResourceEndOfList, 0, 0, 0} +}; + +// +// PS/2 Mouse Controller +// +static EFI_ISA_ACPI_RESOURCE mPcatIsaAcpiPs2MouseDeviceResources[] = { + {EfiIsaAcpiResourceIo, 0, 0x60, 0x64}, + {EfiIsaAcpiResourceInterrupt, 0, 12, 0}, + {EfiIsaAcpiResourceEndOfList, 0, 0, 0} +}; + +// +// Floppy Disk Controller +// +static EFI_ISA_ACPI_RESOURCE mPcatIsaAcpiFloppyResources[] = { + {EfiIsaAcpiResourceIo, 0, 0x3f0, 0x3f7}, + {EfiIsaAcpiResourceInterrupt, 0, 6, 0}, + {EfiIsaAcpiResourceDma, EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE | EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8 | EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE, 2, 0}, + {EfiIsaAcpiResourceEndOfList, 0, 0, 0} +}; + +// +// Table of ISA Controllers +// +EFI_ISA_ACPI_RESOURCE_LIST gPcatIsaAcpiDeviceList[] = { + {{EISA_PNP_ID(0x501), 0}, mPcatIsaAcpiCom1DeviceResources }, // COM 1 UART Controller + {{EISA_PNP_ID(0x501), 1}, mPcatIsaAcpiCom2DeviceResources }, // COM 2 UART Controller + {{EISA_PNP_ID(0x303), 0}, mPcatIsaAcpiPs2KeyboardDeviceResources }, // PS/2 Keyboard Controller + {{EISA_PNP_ID(0x303), 1}, mPcatIsaAcpiPs2MouseDeviceResources }, // PS/2 Mouse Controller + {{EISA_PNP_ID(0x604), 0}, mPcatIsaAcpiFloppyResources }, // Floppy Disk Controller A: + {{EISA_PNP_ID(0x604), 1}, mPcatIsaAcpiFloppyResources }, // Floppy Disk Controller B: + {{0, 0}, NULL } // End if ISA Controllers +}; + +// +// ISA ACPI Protocol Functions +// +VOID +IsaDeviceLookup ( + IN EFI_ISA_ACPI_DEVICE_ID *Device, + OUT EFI_ISA_ACPI_RESOURCE_LIST **IsaAcpiDevice, + OUT EFI_ISA_ACPI_RESOURCE_LIST **NextIsaAcpiDevice + ) +/*++ + +Routine Description: + Enumerate the ISA devices on the ISA bus + +Arguments: + +Returns: + +--*/ +{ + UINTN Index; + + *IsaAcpiDevice = NULL; + if (NextIsaAcpiDevice != NULL) { + *NextIsaAcpiDevice = NULL; + } + if (Device == NULL) { + Index = 0; + } else { + for(Index = 0; gPcatIsaAcpiDeviceList[Index].ResourceItem != NULL; Index++) { + if (Device->HID == gPcatIsaAcpiDeviceList[Index].Device.HID && + Device->UID == gPcatIsaAcpiDeviceList[Index].Device.UID ) { + break; + } + } + if (gPcatIsaAcpiDeviceList[Index].ResourceItem == NULL) { + return; + } + *IsaAcpiDevice = &(gPcatIsaAcpiDeviceList[Index]); + Index++; + } + if (gPcatIsaAcpiDeviceList[Index].ResourceItem != NULL && NextIsaAcpiDevice != NULL) { + *NextIsaAcpiDevice = &(gPcatIsaAcpiDeviceList[Index]); + } +} + +EFI_STATUS +EFIAPI +IsaDeviceEnumerate ( + IN EFI_ISA_ACPI_PROTOCOL *This, + OUT EFI_ISA_ACPI_DEVICE_ID **Device + ) +/*++ + +Routine Description: + Enumerate the ISA devices on the ISA bus + +Arguments: + +Returns: + +--*/ +{ + EFI_ISA_ACPI_RESOURCE_LIST *IsaAcpiDevice; + EFI_ISA_ACPI_RESOURCE_LIST *NextIsaAcpiDevice; + + IsaDeviceLookup (*Device, &IsaAcpiDevice, &NextIsaAcpiDevice); + if (NextIsaAcpiDevice == NULL) { + return EFI_NOT_FOUND; + } + *Device = &(NextIsaAcpiDevice->Device); + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +IsaDeviceSetPower ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + IN BOOLEAN OnOff + ) +/*++ + +Routine Description: + Set ISA device power + +Arguments: + +Returns: + +--*/ +{ + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +IsaGetCurrentResource ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + OUT EFI_ISA_ACPI_RESOURCE_LIST **ResourceList + ) +/*++ + +Routine Description: + Get current Resource of the specific ISA device + +Arguments: + +Returns: + +--*/ +{ + IsaDeviceLookup (Device, ResourceList, NULL); + if (*ResourceList == NULL) { + return EFI_NOT_FOUND; + } + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +IsaGetPossibleResource ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + OUT EFI_ISA_ACPI_RESOURCE_LIST **ResourceList + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +IsaSetResource ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + IN EFI_ISA_ACPI_RESOURCE_LIST *ResourceList + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +IsaEnableDevice ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + IN BOOLEAN Enable + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +IsaInitDevice ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +IsaInterfaceInit ( + IN EFI_ISA_ACPI_PROTOCOL *This +) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + return EFI_SUCCESS; +} diff --git a/DuetPkg/IsaAcpiDxe/IsaAcpi.inf b/DuetPkg/IsaAcpiDxe/IsaAcpi.inf new file mode 100644 index 0000000000..ec01a28346 --- /dev/null +++ b/DuetPkg/IsaAcpiDxe/IsaAcpi.inf @@ -0,0 +1,50 @@ +#/*++ +# +# Copyright (c) 2005, Intel Corporation +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# IsaAcpi.inf +# +# Abstract: +# Component description file for PCAT ISA ACPI driver +# +#--*/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = IsaAcpi + FILE_GUID = 38A0EC22-FBE7-4911-8BC1-176E0D6C1DBD + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x0002000A + + ENTRY_POINT = PcatIsaAcpiDriverEntryPoint + +[Packages] + MdePkg/MdePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec + DuetPkg/DuetPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiLib + +[Sources] + PcatIsaAcpi.h + PcatIsaAcpi.c + IsaAcpi.c + ComponentName.c + +[Protocols] + gEfiPciIoProtocolGuid + gEfiIsaAcpiProtocolGuid diff --git a/DuetPkg/IsaAcpiDxe/PcatIsaAcpi.c b/DuetPkg/IsaAcpiDxe/PcatIsaAcpi.c new file mode 100644 index 0000000000..a618728791 --- /dev/null +++ b/DuetPkg/IsaAcpiDxe/PcatIsaAcpi.c @@ -0,0 +1,329 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: + + PcatIsaAcpi.c + +Abstract: + + EFI PCAT ISA ACPI Driver for a Generic PC Platform + +Revision History + +--*/ + +#include "PcatIsaAcpi.h" + +// +// PcatIsaAcpi Driver Binding Protocol +// +EFI_DRIVER_BINDING_PROTOCOL gPcatIsaAcpiDriverBinding = { + PcatIsaAcpiDriverBindingSupported, + PcatIsaAcpiDriverBindingStart, + PcatIsaAcpiDriverBindingStop, + 0xa, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +PcatIsaAcpiDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + + Routine Description: + the entry point of the PcatIsaAcpi driver + + Arguments: + + Returns: + +--*/ +{ + return EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gPcatIsaAcpiDriverBinding, + ImageHandle, + &gPcatIsaAcpiComponentName, + &gPcatIsaAcpiComponentName2 + ); +} + +EFI_STATUS +EFIAPI +PcatIsaAcpiDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + ControllerDriver Protocol Method + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 Pci; + + // + // Get PciIo protocol instance + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof(Pci) / sizeof(UINT32), + &Pci); + + if (!EFI_ERROR (Status)) { + Status = EFI_UNSUPPORTED; + if ((Pci.Hdr.Command & 0x03) == 0x03) { + if (Pci.Hdr.ClassCode[2] == PCI_CLASS_BRIDGE) { + // + // See if this is a standard PCI to ISA Bridge from the Base Code and Class Code + // + if (Pci.Hdr.ClassCode[1] == PCI_CLASS_ISA) { + Status = EFI_SUCCESS; + } + + // + // See if this is an Intel PCI to ISA bridge in Positive Decode Mode + // + if (Pci.Hdr.ClassCode[1] == PCI_CLASS_ISA_POSITIVE_DECODE && + Pci.Hdr.VendorId == 0x8086 && + Pci.Hdr.DeviceId == 0x7110) { + Status = EFI_SUCCESS; + } + } + } + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +EFI_STATUS +EFIAPI +PcatIsaAcpiDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Install EFI_ISA_ACPI_PROTOCOL + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + PCAT_ISA_ACPI_DEV *PcatIsaAcpiDev; + + PcatIsaAcpiDev = NULL; + // + // Open the PCI I/O Protocol Interface + // + PciIo = NULL; + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_ISA_IO | EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO, + NULL + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Allocate memory for the PCAT ISA ACPI Device structure + // + PcatIsaAcpiDev = NULL; + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof(PCAT_ISA_ACPI_DEV), + &PcatIsaAcpiDev + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Initialize the PCAT ISA ACPI Device structure + // + PcatIsaAcpiDev->Signature = PCAT_ISA_ACPI_DEV_SIGNATURE; + PcatIsaAcpiDev->Handle = Controller; + PcatIsaAcpiDev->PciIo = PciIo; + + // + // IsaAcpi interface + // + (PcatIsaAcpiDev->IsaAcpi).DeviceEnumerate = IsaDeviceEnumerate; + (PcatIsaAcpiDev->IsaAcpi).SetPower = IsaDeviceSetPower; + (PcatIsaAcpiDev->IsaAcpi).GetCurResource = IsaGetCurrentResource; + (PcatIsaAcpiDev->IsaAcpi).GetPosResource = IsaGetPossibleResource; + (PcatIsaAcpiDev->IsaAcpi).SetResource = IsaSetResource; + (PcatIsaAcpiDev->IsaAcpi).EnableDevice = IsaEnableDevice; + (PcatIsaAcpiDev->IsaAcpi).InitDevice = IsaInitDevice; + (PcatIsaAcpiDev->IsaAcpi).InterfaceInit = IsaInterfaceInit; + + // + // Install the ISA ACPI Protocol interface + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiIsaAcpiProtocolGuid, &PcatIsaAcpiDev->IsaAcpi, + NULL + ); + +Done: + if (EFI_ERROR (Status)) { + if (PciIo) { + PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationDisable, + EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_ISA_IO | EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO, + NULL + ); + } + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + if (PcatIsaAcpiDev != NULL) { + gBS->FreePool (PcatIsaAcpiDev); + } + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcatIsaAcpiDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + + Arguments: + + Returns: + +--*/ +{ + EFI_STATUS Status; + EFI_ISA_ACPI_PROTOCOL *IsaAcpi; + PCAT_ISA_ACPI_DEV *PcatIsaAcpiDev; + + // + // Get the ISA ACPI Protocol Interface + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiIsaAcpiProtocolGuid, + &IsaAcpi, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the PCAT ISA ACPI Device structure from the ISA ACPI Protocol + // + PcatIsaAcpiDev = PCAT_ISA_ACPI_DEV_FROM_THIS (IsaAcpi); + + PcatIsaAcpiDev->PciIo->Attributes ( + PcatIsaAcpiDev->PciIo, + EfiPciIoAttributeOperationDisable, + EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_ISA_IO | EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO, + NULL + ); + + // + // Uninstall protocol interface: EFI_ISA_ACPI_PROTOCOL + // + Status = gBS->UninstallProtocolInterface ( + Controller, + &gEfiIsaAcpiProtocolGuid, &PcatIsaAcpiDev->IsaAcpi + ); + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->FreePool (PcatIsaAcpiDev); + + return EFI_SUCCESS; +} diff --git a/DuetPkg/IsaAcpiDxe/PcatIsaAcpi.h b/DuetPkg/IsaAcpiDxe/PcatIsaAcpi.h new file mode 100644 index 0000000000..57e4112923 --- /dev/null +++ b/DuetPkg/IsaAcpiDxe/PcatIsaAcpi.h @@ -0,0 +1,159 @@ +/*++ + +Copyright (c) 2006 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +Module Name: + + PcatIsaAcpi.h + +Abstract: + + EFI PCAT ISA ACPI Driver for a Generic PC Platform + +Revision History + +--*/ + +#ifndef _PCAT_ISA_ACPI_H_ +#define _PCAT_ISA_ACPI_H_ + +#include + +#include + +#include +#include +#include +#include +#include +#include + + +#include +#include + +#include +// +// PCAT ISA ACPI device private data structure +// +#define PCAT_ISA_ACPI_DEV_SIGNATURE EFI_SIGNATURE_32('L','P','C','D') + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + EFI_ISA_ACPI_PROTOCOL IsaAcpi; + EFI_PCI_IO_PROTOCOL *PciIo; +} PCAT_ISA_ACPI_DEV; + +#define PCAT_ISA_ACPI_DEV_FROM_THIS(a) _CR(a, PCAT_ISA_ACPI_DEV, IsaAcpi) + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gPcatIsaAcpiDriverBinding; + +extern EFI_COMPONENT_NAME2_PROTOCOL gPcatIsaAcpiComponentName2; + +extern EFI_COMPONENT_NAME_PROTOCOL gPcatIsaAcpiComponentName; + + +// +// Prototypes for Driver model protocol interface +// +EFI_STATUS +EFIAPI +PcatIsaAcpiDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +PcatIsaAcpiDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +PcatIsaAcpiDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// Prototypes for the ISA ACPI protocol interface +// +EFI_STATUS +EFIAPI +IsaDeviceEnumerate ( + IN EFI_ISA_ACPI_PROTOCOL *This, + OUT EFI_ISA_ACPI_DEVICE_ID **Device + ); + +EFI_STATUS +EFIAPI +IsaDeviceSetPower ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + IN BOOLEAN OnOff + ); + +EFI_STATUS +EFIAPI +IsaGetCurrentResource ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + OUT EFI_ISA_ACPI_RESOURCE_LIST **ResourceList + ); + +EFI_STATUS +EFIAPI +IsaGetPossibleResource ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + OUT EFI_ISA_ACPI_RESOURCE_LIST **ResourceList + ); + +EFI_STATUS +EFIAPI +IsaSetResource ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + IN EFI_ISA_ACPI_RESOURCE_LIST *ResourceList + ); + +EFI_STATUS +EFIAPI +IsaEnableDevice ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + IN BOOLEAN Enable + ); + +EFI_STATUS +EFIAPI +IsaInitDevice ( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device + ); + +EFI_STATUS +EFIAPI +IsaInterfaceInit ( + IN EFI_ISA_ACPI_PROTOCOL *This + ); + +#endif diff --git a/DuetPkg/KbcResetDxe/Ia32/Ia32Reset.c b/DuetPkg/KbcResetDxe/Ia32/Ia32Reset.c new file mode 100644 index 0000000000..00c5223a14 --- /dev/null +++ b/DuetPkg/KbcResetDxe/Ia32/Ia32Reset.c @@ -0,0 +1,79 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + Ia32Reset.c + +Abstract: + +--*/ + +#include "Reset.h" + +// +// The handle onto which the Reset Architectural Protocol is installed +// +EFI_HANDLE mResetHandle = NULL; + + +EFI_STATUS +EFIAPI +InitializeReset ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Initialize the state information for the Reset Architectural Protocol + +Arguments: + + ImageHandle of the loaded driver + Pointer to the System Table + +Returns: + + Status + + EFI_SUCCESS - thread can be successfully created + EFI_OUT_OF_RESOURCES - cannot allocate protocol data structure + EFI_DEVICE_ERROR - cannot create the timer service + +--*/ +// TODO: SystemTable - add argument and description to function comment +{ + EFI_STATUS Status; + + // + // Make sure the Reset Architectural Protocol is not already installed in the system + // + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiResetArchProtocolGuid); + + // + // Hook the runtime service table + // + SystemTable->RuntimeServices->ResetSystem = KbcResetSystem; + + // + // Now install the Reset RT AP on a new handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mResetHandle, + &gEfiResetArchProtocolGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/DuetPkg/KbcResetDxe/Ia32Reset.dxs b/DuetPkg/KbcResetDxe/Ia32Reset.dxs new file mode 100644 index 0000000000..ae2b86de40 --- /dev/null +++ b/DuetPkg/KbcResetDxe/Ia32Reset.dxs @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + Ia32Reset.dxs + +Abstract: + Dependency expression source file. + +--*/ + + +#include "EfiDepex.h" + +#include EFI_PROTOCOL_DEFINITION (CpuIO) + +DEPENDENCY_START + EFI_CPU_IO_PROTOCOL_GUID +DEPENDENCY_END diff --git a/DuetPkg/KbcResetDxe/Ipf/IpfReset.c b/DuetPkg/KbcResetDxe/Ipf/IpfReset.c new file mode 100644 index 0000000000..028fd13876 --- /dev/null +++ b/DuetPkg/KbcResetDxe/Ipf/IpfReset.c @@ -0,0 +1,117 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + IpfReset.c + +Abstract: + +--*/ + +#include "Cf9Reset.h" + +SAL_RETURN_REGS +ResetEsalServicesClassCommonEntry ( + IN UINT64 FunctionId, + IN UINT64 Arg2, + IN UINT64 Arg3, + IN UINT64 Arg4, + IN UINT64 Arg5, + IN UINT64 Arg6, + IN UINT64 Arg7, + IN UINT64 Arg8, + IN SAL_EXTENDED_SAL_PROC ExtendedSalProc, + IN BOOLEAN VirtualMode, + IN VOID *Global + ) +/*++ + +Routine Description: + + Main entry for Extended SAL Reset Services + +Arguments: + + FunctionId Function Id which needed to be called. + Arg2 EFI_RESET_TYPE, whether WARM of COLD reset + Arg3 Last EFI_STATUS + Arg4 Data Size of UNICODE STRING passed in ARG5 + Arg5 Unicode String which CHAR16* + +Returns: + + SAL_RETURN_REGS + +--*/ +// TODO: Arg6 - add argument and description to function comment +// TODO: Arg7 - add argument and description to function comment +// TODO: Arg8 - add argument and description to function comment +// TODO: ExtendedSalProc - add argument and description to function comment +// TODO: VirtualMode - add argument and description to function comment +// TODO: Global - add argument and description to function comment +{ + SAL_RETURN_REGS ReturnVal; + + switch (FunctionId) { + case ResetSystem: + KbcResetSystem (Arg2, Arg3, (UINTN) Arg4, (VOID *) Arg5); + ReturnVal.Status = EFI_SUCCESS; + break; + + default: + ReturnVal.Status = EFI_SAL_INVALID_ARGUMENT; + break; + } + + return ReturnVal; +} + +EFI_STATUS +EFIAPI +InitializeReset ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Initialize the state information for the Reset Architectural Protocol + +Arguments: + + ImageHandle of the loaded driver + Pointer to the System Table + +Returns: + + Status + + EFI_SUCCESS - thread can be successfully created + EFI_OUT_OF_RESOURCES - cannot allocate protocol data structure + EFI_DEVICE_ERROR - cannot create the timer service + +--*/ +// TODO: SystemTable - add argument and description to function comment +{ + EfiInitializeRuntimeDriverLib (ImageHandle, SystemTable, NULL); + + RegisterEsalClass ( + &gEfiExtendedSalResetServicesProtocolGuid, + NULL, + ResetEsalServicesClassCommonEntry, + ResetSystem, + NULL + ); + + return EFI_SUCCESS; +} + diff --git a/DuetPkg/KbcResetDxe/IpfReset.dxs b/DuetPkg/KbcResetDxe/IpfReset.dxs new file mode 100644 index 0000000000..6bb389199d --- /dev/null +++ b/DuetPkg/KbcResetDxe/IpfReset.dxs @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + IpfReset.dxs + +Abstract: + Dependency expression source file. + +--*/ + + +#include "EfiDepex.h" + +#include EFI_PROTOCOL_DEFINITION (ExtendedSalGuid) + +DEPENDENCY_START + EFI_EXTENDED_SAL_BASE_IO_SERVICES_PROTOCOL_GUID +DEPENDENCY_END diff --git a/DuetPkg/KbcResetDxe/Reset.c b/DuetPkg/KbcResetDxe/Reset.c new file mode 100644 index 0000000000..b06c999842 --- /dev/null +++ b/DuetPkg/KbcResetDxe/Reset.c @@ -0,0 +1,70 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + Reset.c + +Abstract: + + Reset Architectural Protocol implementation + +--*/ + +#include "Reset.h" + +VOID +EFIAPI +KbcResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData OPTIONAL + ) +/*++ + +Routine Description: + + Reset the system. + +Arguments: + + ResetType - warm or cold + ResetStatus - possible cause of reset + DataSize - Size of ResetData in bytes + ResetData - Optional Unicode string + For details, see efiapi.h + +Returns: + Does not return if the reset takes place. + EFI_INVALID_PARAMETER If ResetType is invalid. + +--*/ +{ + UINT8 Data; + + switch (ResetType) { + case EfiResetWarm: + case EfiResetCold: + case EfiResetShutdown: + Data = 0xfe; + IoWrite8 (0x64, Data); + break; + + default: + return ; + } + + // + // Given we should have reset getting here would be bad + // + ASSERT (FALSE); +} + diff --git a/DuetPkg/KbcResetDxe/Reset.h b/DuetPkg/KbcResetDxe/Reset.h new file mode 100644 index 0000000000..3777c331fb --- /dev/null +++ b/DuetPkg/KbcResetDxe/Reset.h @@ -0,0 +1,85 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + Reset.h + +Abstract: + + some definitions for reset + +--*/ + +#ifndef _KBC_RESET_H +#define _KBC_RESET_H + +#include + +#include +#include +#include +#include + +#include + +EFI_STATUS +EFIAPI +InitializeReset ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageHandle - TODO: add argument description + SystemTable - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +EFIAPI +KbcResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData OPTIONAL + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ResetType - TODO: add argument description + ResetStatus - TODO: add argument description + DataSize - TODO: add argument description + ResetData - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/DuetPkg/KbcResetDxe/Reset.inf b/DuetPkg/KbcResetDxe/Reset.inf new file mode 100644 index 0000000000..b491691962 --- /dev/null +++ b/DuetPkg/KbcResetDxe/Reset.inf @@ -0,0 +1,59 @@ +#/*++ +# +# Copyright (c) 2006, Intel Corporation +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# Reset.inf +# +# Abstract: +# +#--*/ +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = KbcReset + FILE_GUID = 6F0198AA-1F1D-426D-AE3E-39AB633FCC28 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x00020000 + + ENTRY_POINT = InitializeReset + +[Packages] + DuetPkg/DuetPkg.dec + MdePkg/MdePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + +[LibraryClasses] + DebugLib + UefiBootServicesTableLib + UefiDriverEntryPoint + IoLib + +[Sources.common] + Reset.c + Reset.h + +[Sources.ipf] + Ipf\IpfReset.c + +[Sources.ia32] + Ia32\Ia32Reset.c + +[Sources.x64] + x64\x64Reset.c + +[Protocols] + gEfiResetArchProtocolGuid + +[Depex] + gEfiCpuIoProtocolGuid + + diff --git a/DuetPkg/KbcResetDxe/x64/x64Reset.c b/DuetPkg/KbcResetDxe/x64/x64Reset.c new file mode 100644 index 0000000000..1fd79bf0fe --- /dev/null +++ b/DuetPkg/KbcResetDxe/x64/x64Reset.c @@ -0,0 +1,79 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + x64Reset.c + +Abstract: + +--*/ + +#include "Reset.h" + +// +// The handle onto which the Reset Architectural Protocol is installed +// +EFI_HANDLE mResetHandle = NULL; + + +EFI_STATUS +EFIAPI +InitializeReset ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Initialize the state information for the Reset Architectural Protocol + +Arguments: + + ImageHandle of the loaded driver + Pointer to the System Table + +Returns: + + Status + + EFI_SUCCESS - thread can be successfully created + EFI_OUT_OF_RESOURCES - cannot allocate protocol data structure + EFI_DEVICE_ERROR - cannot create the timer service + +--*/ +// TODO: SystemTable - add argument and description to function comment +{ + EFI_STATUS Status; + + // + // Make sure the Reset Architectural Protocol is not already installed in the system + // + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiResetArchProtocolGuid); + + // + // Hook the runtime service table + // + SystemTable->RuntimeServices->ResetSystem = KbcResetSystem; + + // + // Now install the Reset RT AP on a new handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mResetHandle, + &gEfiResetArchProtocolGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/DuetPkg/KbcResetDxe/x64Reset.dxs b/DuetPkg/KbcResetDxe/x64Reset.dxs new file mode 100644 index 0000000000..a2b1498f6c --- /dev/null +++ b/DuetPkg/KbcResetDxe/x64Reset.dxs @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + x64Reset.dxs + +Abstract: + Dependency expression source file. + +--*/ + + +#include "EfiDepex.h" + +#include EFI_PROTOCOL_DEFINITION (CpuIO) + +DEPENDENCY_START + EFI_CPU_IO_PROTOCOL_GUID +DEPENDENCY_END diff --git a/DuetPkg/LegacyMetronome/Metronome.c b/DuetPkg/LegacyMetronome/Metronome.c new file mode 100644 index 0000000000..acc0dad45c --- /dev/null +++ b/DuetPkg/LegacyMetronome/Metronome.c @@ -0,0 +1,201 @@ +/*++ + +Copyright (c) 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + LegacyMetronome.c + +Abstract: + + This contains the installation function for the driver. + +--*/ + +#include "Metronome.h" + +// +// Handle for the Metronome Architectural Protocol instance produced by this driver +// +EFI_HANDLE mMetronomeHandle = NULL; + +// +// The Metronome Architectural Protocol instance produced by this driver +// +EFI_METRONOME_ARCH_PROTOCOL mMetronome = { + WaitForTick, + TICK_PERIOD +}; + +// +// The CPU I/O Protocol used to access system hardware +// +EFI_CPU_IO_PROTOCOL *mCpuIo = NULL; + +// +// Worker Functions +// +VOID +IoWrite8 ( + UINT16 Port, + UINT8 Data + ) +/*++ + +Routine Description: + + Write an 8 bit value to an I/O port and save it to the S3 script + +Arguments: + +Returns: + + None. + +--*/ +// TODO: Port - add argument and description to function comment +// TODO: Data - add argument and description to function comment +{ + mCpuIo->Io.Write ( + mCpuIo, + EfiCpuIoWidthUint8, + Port, + 1, + &Data + ); + +} + +UINT8 +ReadRefresh ( + VOID + ) +/*++ + +Routine Description: + + Read the refresh bit from the REFRESH_PORT + +Arguments: + +Returns: + + None. + +--*/ +{ + UINT8 Data; + + mCpuIo->Io.Read ( + mCpuIo, + EfiCpuIoWidthUint8, + REFRESH_PORT, + 1, + &Data + ); + return (UINT8) (Data & REFRESH_ON); +} + +EFI_STATUS +EFIAPI +WaitForTick ( + IN EFI_METRONOME_ARCH_PROTOCOL *This, + IN UINT32 TickNumber + ) +/*++ + +Routine Description: + + Waits for the TickNumber of ticks from a known platform time source. + +Arguments: + + This Pointer to the protocol instance. + +Returns: + + EFI_SUCCESS If number of ticks occurred. + EFI_NOT_FOUND Could not locate CPU IO protocol + +--*/ +// TODO: TickNumber - add argument and description to function comment +{ + // + // Wait for TickNumber toggles of the Refresh bit + // + for (; TickNumber != 0x00; TickNumber--) { + while (ReadRefresh () == REFRESH_ON) + ; + while (ReadRefresh () == REFRESH_OFF) + ; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +InstallMetronome ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Install the LegacyMetronome driver. Loads a Metronome Arch Protocol based + on the Port 61 timer. + +Arguments: + + (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) + +Returns: + + EFI_SUCCESS - Metronome Architectural Protocol Installed + +--*/ +// TODO: ImageHandle - add argument and description to function comment +// TODO: SystemTable - add argument and description to function comment +{ + EFI_STATUS Status; + + // + // Make sure the Metronome Architectural Protocol is not already installed in the system + // + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiMetronomeArchProtocolGuid); + + // + // Get the CPU I/O Protocol that this driver requires + // If the CPU I/O Protocol is not found, then ASSERT because the dependency expression + // should guarantee that it is present in the handle database. + // + Status = gBS->LocateProtocol (&gEfiCpuIoProtocolGuid, NULL, &mCpuIo); + ASSERT_EFI_ERROR (Status); + + // + // Program port 61 timer 1 as refresh timer. We could use ACPI timer in the + // future. + // + IoWrite8 (TIMER1_CONTROL_PORT, LOAD_COUNTER1_LSB); + IoWrite8 (TIMER1_COUNT_PORT, COUNTER1_COUNT); + + // + // Install on a new handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mMetronomeHandle, + &gEfiMetronomeArchProtocolGuid, + &mMetronome, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/DuetPkg/LegacyMetronome/Metronome.dxs b/DuetPkg/LegacyMetronome/Metronome.dxs new file mode 100644 index 0000000000..6e224957fc --- /dev/null +++ b/DuetPkg/LegacyMetronome/Metronome.dxs @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + LegacyMetronome.dxs + +Abstract: + Dependency expression source file. + +--*/ + + +#include "EfiDepex.h" + +#include EFI_PROTOCOL_DEFINITION (CpuIo) + +DEPENDENCY_START + EFI_CPU_IO_PROTOCOL_GUID +DEPENDENCY_END + diff --git a/DuetPkg/LegacyMetronome/Metronome.h b/DuetPkg/LegacyMetronome/Metronome.h new file mode 100644 index 0000000000..87a12cbc34 --- /dev/null +++ b/DuetPkg/LegacyMetronome/Metronome.h @@ -0,0 +1,75 @@ +/*++ + +Copyright (c) 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + LegacyMetronome.h + +Abstract: + + Driver implementing the EFI 2.0 metronome protocol using the legacy PORT 61 + timer. + +--*/ + +#ifndef _LEGACY_METRONOME_H +#define _LEGACY_METRONOME_H + +// +// Statements that include other files +// +#include + +#include +#include + +#include +#include + +// +// Private definitions +// +#define TICK_PERIOD 300 +#define REFRESH_PORT 0x61 +#define REFRESH_ON 0x10 +#define REFRESH_OFF 0x00 +#define TIMER1_CONTROL_PORT 0x43 +#define TIMER1_COUNT_PORT 0x41 +#define LOAD_COUNTER1_LSB 0x54 +#define COUNTER1_COUNT 0x12 + +// +// Function Prototypes +// +EFI_STATUS +EFIAPI +WaitForTick ( + IN EFI_METRONOME_ARCH_PROTOCOL *This, + IN UINT32 TickNumber + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + TickNumber - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/DuetPkg/LegacyMetronome/Metronome.inf b/DuetPkg/LegacyMetronome/Metronome.inf new file mode 100644 index 0000000000..d97b67f334 --- /dev/null +++ b/DuetPkg/LegacyMetronome/Metronome.inf @@ -0,0 +1,48 @@ +#/*++ +# +# Copyright (c) 2005, Intel Corporation +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# Abstract: +# +#--*/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Metronome + FILE_GUID = 07A9330A-F347-11d4-9A49-0090273FC14D + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x00020000 + + ENTRY_POINT = InstallMetronome + +[Packages] + MdePkg/MdePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + DuetPkg/DuetPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + DebugLib + UefiBootServicesTableLib + +[Sources.common] + Metronome.c + Metronome.h + +[Protocols] + gEfiMetronomeArchProtocolGuid + gEfiCpuIoProtocolGuid + +[Depex] + gEfiCpuIoProtocolGuid diff --git a/DuetPkg/Library/DuetBdsLib/BdsPlatform.c b/DuetPkg/Library/DuetBdsLib/BdsPlatform.c new file mode 100644 index 0000000000..e8404e5524 --- /dev/null +++ b/DuetPkg/Library/DuetBdsLib/BdsPlatform.c @@ -0,0 +1,1720 @@ +/*++ + +Copyright (c) 2006 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BdsPlatform.c + +Abstract: + + This file include all platform action which can be customized + by IBV/OEM. + +--*/ + +#include "BdsPlatform.h" + +#define IS_PCI_ISA_PDECODE(_p) IS_CLASS3 (_p, PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_ISA_PDECODE, 0) + +CHAR16 mFirmwareVendor[] = L"TianoCore.org"; +extern BOOLEAN gConnectAllHappened; +extern USB_CLASS_FORMAT_DEVICE_PATH gUsbClassKeyboardDevicePath; +// +// BDS Platform Functions +// + +VOID +GetSystemTablesFromHob ( + VOID + ) +/*++ + +Routine Description: + Find GUID'ed HOBs that contain EFI_PHYSICAL_ADDRESS of ACPI, SMBIOS, MPs tables + +Arguments: + None + +Returns: + None. + +--*/ +{ + EFI_STATUS Status; + EFI_HOB_HANDOFF_INFO_TABLE *HobList; + EFI_HOB_HANDOFF_INFO_TABLE *HobStart; + EFI_PHYSICAL_ADDRESS *Table; + UINTN Index; + EFI_GUID *TableGuidArray[] = { + &gEfiAcpi20TableGuid, &gEfiAcpiTableGuid, &gEfiSmbiosTableGuid, &gEfiMpsTableGuid + }; + + // + // Get Hob List + // + Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, (VOID *) &HobList); + if (EFI_ERROR (Status)) { + return; + } + + // + // Iteratively add ACPI Table, SMBIOS Table, MPS Table to EFI System Table + // + for (Index = 0; Index < sizeof (TableGuidArray) / sizeof (*TableGuidArray); ++Index) { + HobStart = HobList; + Table = NULL; + Table = GetNextGuidHob (TableGuidArray[Index], &HobStart); + if (!EFI_ERROR (Status)) { + if (Table != NULL) { + // + // Check if Mps Table/Smbios Table/Acpi Table exists in E/F seg, + // According to UEFI Spec, we should make sure Smbios table, + // ACPI table and Mps tables kept in memory of specified type + // + ConvertSystemTable(TableGuidArray[Index], &Table); + gBS->InstallConfigurationTable (TableGuidArray[Index], (VOID *)Table); + } + } + } + + return ; +} + +#define EFI_LDR_MEMORY_DESCRIPTOR_GUID \ + { 0x7701d7e5, 0x7d1d, 0x4432, 0xa4, 0x68, 0x67, 0x3d, 0xab, 0x8a, 0xde, 0x60 } + +EFI_GUID gEfiLdrMemoryDescriptorGuid = EFI_LDR_MEMORY_DESCRIPTOR_GUID; + +#pragma pack(1) + +typedef struct { + EFI_HOB_GUID_TYPE Hob; + UINTN MemDescCount; + EFI_MEMORY_DESCRIPTOR *MemDesc; +} MEMORY_DESC_HOB; + +#pragma pack() + +#if 0 +VOID +PrintMemoryMap ( + VOID + ) +{ + EFI_MEMORY_DESCRIPTOR *MemMap; + EFI_MEMORY_DESCRIPTOR *MemMapPtr; + UINTN MemMapSize; + UINTN MapKey, DescriptorSize; + UINTN Index; + UINT32 DescriptorVersion; + UINT64 Bytes; + EFI_STATUS Status; + + MemMapSize = 0; + MemMap = NULL; + Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + MemMapSize += EFI_PAGE_SIZE; + Status = gBS->AllocatePool (EfiBootServicesData, MemMapSize, &MemMap); + ASSERT (Status == EFI_SUCCESS); + Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion); + ASSERT (Status == EFI_SUCCESS); + MemMapPtr = MemMap; + + ASSERT (DescriptorVersion == EFI_MEMORY_DESCRIPTOR_VERSION); + + for (Index = 0; Index < MemMapSize / DescriptorSize; Index ++) { + Bytes = LShiftU64 (MemMap->NumberOfPages, 12); + DEBUG ((EFI_D_ERROR, "%lX-%lX %lX %lX %X\n", + MemMap->PhysicalStart, + MemMap->PhysicalStart + Bytes - 1, + MemMap->NumberOfPages, + MemMap->Attribute, + (UINTN)MemMap->Type)); + MemMap = (EFI_MEMORY_DESCRIPTOR *)((UINTN)MemMap + DescriptorSize); + } + + gBS->FreePool (MemMapPtr); +} +#endif + +VOID +UpdateMemoryMap ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HOB_HANDOFF_INFO_TABLE *HobList; + VOID *Table; + MEMORY_DESC_HOB MemoryDescHob; + UINTN Index; + EFI_PHYSICAL_ADDRESS Memory; + + // + // Get Hob List + // + Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, (VOID *) &HobList); + if (EFI_ERROR (Status)) { + return; + } + + Table = GetNextGuidHob (&gEfiLdrMemoryDescriptorGuid, &HobList); + MemoryDescHob.MemDescCount = *(UINTN *)Table; + MemoryDescHob.MemDesc = *(EFI_MEMORY_DESCRIPTOR **)((UINTN)Table + sizeof(UINTN)); + + // + // Add ACPINVS, ACPIReclaim, and Reserved memory to MemoryMap + // + for (Index = 0; Index < MemoryDescHob.MemDescCount; Index++) { + if (MemoryDescHob.MemDesc[Index].PhysicalStart < 0x100000) { + continue; + } + if (MemoryDescHob.MemDesc[Index].PhysicalStart >= 0x100000000) { + continue; + } + if ((MemoryDescHob.MemDesc[Index].Type == EfiReservedMemoryType) || + (MemoryDescHob.MemDesc[Index].Type == EfiRuntimeServicesData) || + (MemoryDescHob.MemDesc[Index].Type == EfiRuntimeServicesCode) || + (MemoryDescHob.MemDesc[Index].Type == EfiACPIReclaimMemory) || + (MemoryDescHob.MemDesc[Index].Type == EfiACPIMemoryNVS)) { + DEBUG ((EFI_D_ERROR, "PhysicalStart - 0x%x, ", MemoryDescHob.MemDesc[Index].PhysicalStart)); + DEBUG ((EFI_D_ERROR, "PageNumber - 0x%x, ", MemoryDescHob.MemDesc[Index].NumberOfPages)); + DEBUG ((EFI_D_ERROR, "Type - 0x%x\n", MemoryDescHob.MemDesc[Index].Type)); + if ((MemoryDescHob.MemDesc[Index].Type == EfiRuntimeServicesData) || + (MemoryDescHob.MemDesc[Index].Type == EfiRuntimeServicesCode)) { + // + // Skip RuntimeSevicesData and RuntimeServicesCode, they are BFV + // + continue; + } + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeSystemMemory, + MemoryDescHob.MemDesc[Index].PhysicalStart, + LShiftU64 (MemoryDescHob.MemDesc[Index].NumberOfPages, EFI_PAGE_SHIFT), + MemoryDescHob.MemDesc[Index].Attribute + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "AddMemorySpace fail!\n")); + if ((MemoryDescHob.MemDesc[Index].Type == EfiACPIReclaimMemory) || + (MemoryDescHob.MemDesc[Index].Type == EfiACPIMemoryNVS)) { + // + // For EfiACPIReclaimMemory and EfiACPIMemoryNVS, it must success. + // For EfiReservedMemoryType, there maybe overlap. So skip check here. + // +// ASSERT_EFI_ERROR (Status); + } + continue; + } + + Memory = MemoryDescHob.MemDesc[Index].PhysicalStart; + Status = gBS->AllocatePages ( + AllocateAddress, + MemoryDescHob.MemDesc[Index].Type, + (UINTN)MemoryDescHob.MemDesc[Index].NumberOfPages, + &Memory + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "AllocatePages fail!\n")); + // + // For the page added, it must be allocated. + // +// ASSERT_EFI_ERROR (Status); + continue; + } + } + } + +} + +EFI_STATUS +DisableUsbLegacySupport( + void + ) +/*++ + +Routine Description: + Disabble the USB legacy Support in all Ehci and Uhci. + This function assume all PciIo handles have been created in system. + +Arguments: + None + +Returns: + EFI_SUCCESS + EFI_NOT_FOUND +--*/ +{ + EFI_STATUS Status; + EFI_HANDLE *HandleArray; + UINTN HandleArrayCount; + UINTN Index; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT8 Class[3]; + UINT16 Command; + UINT32 HcCapParams; + UINT32 ExtendCap; + UINT32 Value; + UINT32 TimeOut; + + // + // Find the usb host controller + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &HandleArrayCount, + &HandleArray + ); + if (!EFI_ERROR (Status)) { + for (Index = 0; Index < HandleArrayCount; Index++) { + Status = gBS->HandleProtocol ( + HandleArray[Index], + &gEfiPciIoProtocolGuid, + (VOID **)&PciIo + ); + if (!EFI_ERROR (Status)) { + // + // Find the USB host controller controller + // + Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class); + if (!EFI_ERROR (Status)) { + if ((PCI_CLASS_SERIAL == Class[2]) && + (PCI_CLASS_SERIAL_USB == Class[1])) { + if (PCI_CLASSC_PI_UHCI == Class[0]) { + // + // Found the UHCI, then disable the legacy support + // + Command = 0; + Status = PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0xC0, 1, &Command); + } else if (PCI_CLASSC_PI_EHCI == Class[0]) { + // + // Found the EHCI, then disable the legacy support + // + Status = PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, //EHC_BAR_INDEX + (UINT64) 0x08, //EHC_HCCPARAMS_OFFSET + 1, + &HcCapParams + ); + + ExtendCap = (HcCapParams >> 8) & 0xFF; + // + // Disable the SMI in USBLEGCTLSTS firstly + // + PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap + 0x4, 1, &Value); + Value &= 0xFFFF0000; + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, ExtendCap + 0x4, 1, &Value); + + // + // Get EHCI Ownership from legacy bios + // + PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value); + Value |= (0x1 << 24); + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value); + + TimeOut = 40; + while (TimeOut--) { + gBS->Stall (500); + + PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value); + + if ((Value & 0x01010000) == 0x01000000) { + break; + } + } + } + } + } + } + } + } else { + return Status; + } + gBS->FreePool (HandleArray); + return EFI_SUCCESS; +} + + +VOID +PlatformBdsInit ( + IN EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData + ) +/*++ + +Routine Description: + + Platform Bds init. Incude the platform firmware vendor, revision + and so crc check. + +Arguments: + + PrivateData - The EFI_BDS_ARCH_PROTOCOL_INSTANCE instance + +Returns: + + None. + +--*/ +{ + // + // set firmwarevendor, here can be IBV/OEM customize + // + gST->FirmwareVendor = AllocateRuntimeCopyPool ( + sizeof (mFirmwareVendor), + &mFirmwareVendor + ); + ASSERT (gST->FirmwareVendor != NULL); + + gST->FirmwareRevision = 0; + + // + // Fixup Tasble CRC after we updated Firmware Vendor and Revision + // + gBS->CalculateCrc32 ((VOID *) gST, sizeof (EFI_SYSTEM_TABLE), &gST->Hdr.CRC32); +} + +UINT64 +GetPciExpressBaseAddressForRootBridge ( + IN UINTN HostBridgeNumber, + IN UINTN RootBridgeNumber + ) +/*++ + +Routine Description: + This routine is to get PciExpress Base Address for this RootBridge + +Arguments: + HostBridgeNumber - The number of HostBridge + RootBridgeNumber - The number of RootBridge + +Returns: + UINT64 - PciExpressBaseAddress for this HostBridge and RootBridge + +--*/ +{ + EFI_PCI_EXPRESS_BASE_ADDRESS_INFORMATION *PciExpressBaseAddressInfo; + UINTN BufferSize; + UINT32 Index; + UINT32 Number; + VOID *HobList; + EFI_STATUS Status; + + BufferSize = 0; + // + // Get Hob List from configuration table + // + Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList); + if (EFI_ERROR (Status)) { + return 0; + } + + // + // Get PciExpressAddressInfo Hob + // + PciExpressBaseAddressInfo = NULL; + PciExpressBaseAddressInfo = GetNextGuidHob (&gEfiPciExpressBaseAddressGuid, &HobList); + + // + // Search the PciExpress Base Address in the Hob for current RootBridge + // + Number = (UINT32)(BufferSize / sizeof(EFI_PCI_EXPRESS_BASE_ADDRESS_INFORMATION)); + for (Index = 0; Index < Number; Index++) { + if ((PciExpressBaseAddressInfo[Index].HostBridgeNumber == HostBridgeNumber) && + (PciExpressBaseAddressInfo[Index].RootBridgeNumber == RootBridgeNumber)) { + return PciExpressBaseAddressInfo[Index].PciExpressBaseAddress; + } + } + + // + // Do not find the PciExpress Base Address in the Hob + // + return 0; +} + +VOID +PatchPciRootBridgeDevicePath ( + IN UINTN HostBridgeNumber, + IN UINTN RootBridgeNumber, + IN PLATFORM_ROOT_BRIDGE_DEVICE_PATH *RootBridge + ) +{ + UINT64 PciExpressBase; + + PciExpressBase = GetPciExpressBaseAddressForRootBridge (HostBridgeNumber, RootBridgeNumber); + + if (PciExpressBase != 0) { + RootBridge->PciRootBridge.HID = EISA_PNP_ID(0x0A08); + } +} + +EFI_STATUS +ConnectRootBridge ( + VOID + ) +/*++ + +Routine Description: + + Connect RootBridge + +Arguments: + + None. + +Returns: + + EFI_SUCCESS - Connect RootBridge successfully. + EFI_STATUS - Connect RootBridge fail. + +--*/ +{ + EFI_STATUS Status; + EFI_HANDLE RootHandle; + + // + // Patch Pci Root Bridge Device Path + // + PatchPciRootBridgeDevicePath (0, 0, &gPlatformRootBridge0); + + // + // Make all the PCI_IO protocols on PCI Seg 0 show up + // + BdsLibConnectDevicePath (gPlatformRootBridges[0]); + + Status = gBS->LocateDevicePath ( + &gEfiDevicePathProtocolGuid, + &gPlatformRootBridges[0], + &RootHandle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->ConnectController (RootHandle, NULL, NULL, FALSE); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PrepareLpcBridgeDevicePath ( + IN EFI_HANDLE DeviceHandle + ) +/*++ + +Routine Description: + + Add IsaKeyboard to ConIn, + add IsaSerial to ConOut, ConIn, ErrOut. + LPC Bridge: 06 01 00 + +Arguments: + + DeviceHandle - Handle of PCIIO protocol. + +Returns: + + EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut. + EFI_STATUS - No LPC bridge is added. + +--*/ +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + + DevicePath = NULL; + Status = gBS->HandleProtocol ( + DeviceHandle, + &gEfiDevicePathProtocolGuid, + &DevicePath + ); + if (EFI_ERROR (Status)) { + return Status; + } + TempDevicePath = DevicePath; + + // + // Register Keyboard + // + DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode); + + BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL); + + // + // Register COM1 + // + DevicePath = TempDevicePath; + gPnp16550ComPortDeviceNode.UID = 0; + + DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode); + DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode); + DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode); + + BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL); + BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL); + BdsLibUpdateConsoleVariable (VarErrorOut, DevicePath, NULL); + + // + // Register COM2 + // + DevicePath = TempDevicePath; + gPnp16550ComPortDeviceNode.UID = 1; + + DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode); + DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode); + DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode); + + BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL); + BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL); + BdsLibUpdateConsoleVariable (VarErrorOut, DevicePath, NULL); + + return EFI_SUCCESS; +} + +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) +EFI_STATUS +GetGopDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath, + OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath + ) +{ + UINTN Index; + EFI_STATUS Status; + EFI_HANDLE PciDeviceHandle; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath; + UINTN GopHandleCount; + EFI_HANDLE *GopHandleBuffer; + + if (PciDevicePath == NULL || GopDevicePath == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Initialize the GopDevicePath to be PciDevicePath + // + *GopDevicePath = PciDevicePath; + TempPciDevicePath = PciDevicePath; + + Status = gBS->LocateDevicePath ( + &gEfiDevicePathProtocolGuid, + &TempPciDevicePath, + &PciDeviceHandle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Try to connect this handle, so that GOP dirver could start on this + // device and create child handles with GraphicsOutput Protocol installed + // on them, then we get device paths of these child handles and select + // them as possible console device. + // + gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE); + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiGraphicsOutputProtocolGuid, + NULL, + &GopHandleCount, + &GopHandleBuffer + ); + if (!EFI_ERROR (Status)) { + // + // Add all the child handles as possible Console Device + // + for (Index = 0; Index < GopHandleCount; Index++) { + Status = gBS->HandleProtocol (GopHandleBuffer[Index], &gEfiDevicePathProtocolGuid, &TempDevicePath); + if (EFI_ERROR (Status)) { + continue; + } + if (CompareMem ( + PciDevicePath, + TempDevicePath, + GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH + ) == 0) { + // + // In current implementation, we only enable one of the child handles + // as console device, i.e. sotre one of the child handle's device + // path to variable "ConOut" + // In futhure, we could select all child handles to be console device + // + + *GopDevicePath = TempDevicePath; + + // + // Delete the PCI device's path that added by GetPlugInPciVgaDevicePath() + // Add the integrity GOP device path. + // + BdsLibUpdateConsoleVariable (VarConsoleOutDev, NULL, PciDevicePath); + BdsLibUpdateConsoleVariable (VarConsoleOutDev, TempDevicePath, NULL); + } + } + gBS->FreePool (GopHandleBuffer); + } + + return EFI_SUCCESS; +} +#endif + +EFI_STATUS +PreparePciVgaDevicePath ( + IN EFI_HANDLE DeviceHandle + ) +/*++ + +Routine Description: + + Add PCI VGA to ConOut. + PCI VGA: 03 00 00 + +Arguments: + + DeviceHandle - Handle of PCIIO protocol. + +Returns: + + EFI_SUCCESS - PCI VGA is added to ConOut. + EFI_STATUS - No PCI VGA device is added. + +--*/ +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) + EFI_DEVICE_PATH_PROTOCOL *GopDevicePath; +#endif + + DevicePath = NULL; + Status = gBS->HandleProtocol ( + DeviceHandle, + &gEfiDevicePathProtocolGuid, + &DevicePath + ); + if (EFI_ERROR (Status)) { + return Status; + } + +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) + GetGopDevicePath (DevicePath, &GopDevicePath); + DevicePath = GopDevicePath; +#endif + + BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL); + + return EFI_SUCCESS; +} + +EFI_STATUS +PreparePciSerialDevicePath ( + IN EFI_HANDLE DeviceHandle + ) +/*++ + +Routine Description: + + Add PCI Serial to ConOut, ConIn, ErrOut. + PCI Serial: 07 00 02 + +Arguments: + + DeviceHandle - Handle of PCIIO protocol. + +Returns: + + EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut. + EFI_STATUS - No PCI Serial device is added. + +--*/ +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + DevicePath = NULL; + Status = gBS->HandleProtocol ( + DeviceHandle, + &gEfiDevicePathProtocolGuid, + &DevicePath + ); + if (EFI_ERROR (Status)) { + return Status; + } + + DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode); + DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode); + + BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL); + BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL); + BdsLibUpdateConsoleVariable (VarErrorOut, DevicePath, NULL); + + return EFI_SUCCESS; +} + +EFI_STATUS +DetectAndPreparePlatformPciDevicePath ( + BOOLEAN DetectVgaOnly + ) +/*++ + +Routine Description: + + Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut + +Arguments: + + DetectVgaOnly - Only detect VGA device if it's TRUE. + +Returns: + + EFI_SUCCESS - PCI Device check and Console variable update successfully. + EFI_STATUS - PCI Device check or Console variable update fail. + +--*/ +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Index; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 Pci; + + // + // Start to check all the PciIo to find all possible device + // + HandleCount = 0; + HandleBuffer = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, &PciIo); + if (EFI_ERROR (Status)) { + continue; + } + + // + // Check for all PCI device + // + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (Pci) / sizeof (UINT32), + &Pci + ); + if (EFI_ERROR (Status)) { + continue; + } + + if (!DetectVgaOnly) { + // + // Here we decide whether it is LPC Bridge + // + if ((IS_PCI_LPC (&Pci)) || + ((IS_PCI_ISA_PDECODE (&Pci)) && (Pci.Hdr.VendorId == 0x8086) && (Pci.Hdr.DeviceId == 0x7110))) { + // + // Add IsaKeyboard to ConIn, + // add IsaSerial to ConOut, ConIn, ErrOut + // + PrepareLpcBridgeDevicePath (HandleBuffer[Index]); + continue; + } + // + // Here we decide which Serial device to enable in PCI bus + // + if (IS_PCI_16550SERIAL (&Pci)) { + // + // Add them to ConOut, ConIn, ErrOut. + // + PreparePciSerialDevicePath (HandleBuffer[Index]); + continue; + } + } + + // + // Here we decide which VGA device to enable in PCI bus + // + if (IS_PCI_VGA (&Pci)) { + // + // Add them to ConOut. + // + PreparePciVgaDevicePath (HandleBuffer[Index]); + continue; + } + } + + gBS->FreePool (HandleBuffer); + + return EFI_SUCCESS; +} + +EFI_STATUS +PlatformBdsConnectConsole ( + IN BDS_CONSOLE_CONNECT_ENTRY *PlatformConsole + ) +/*++ + +Routine Description: + + Connect the predefined platform default console device. Always try to find + and enable the vga device if have. + +Arguments: + + PlatformConsole - Predfined platform default console device array. + +Returns: + + EFI_SUCCESS - Success connect at least one ConIn and ConOut + device, there must have one ConOut device is + active vga device. + + EFI_STATUS - Return the status of + BdsLibConnectAllDefaultConsoles () + +--*/ +{ + EFI_STATUS Status; + UINTN Index; + EFI_DEVICE_PATH_PROTOCOL *VarConout; + EFI_DEVICE_PATH_PROTOCOL *VarConin; + UINTN DevicePathSize; + + // + // Connect RootBridge + // + ConnectRootBridge (); + + VarConout = BdsLibGetVariableAndSize ( + VarConsoleOut, + &gEfiGlobalVariableGuid, + &DevicePathSize + ); + VarConin = BdsLibGetVariableAndSize ( + VarConsoleInp, + &gEfiGlobalVariableGuid, + &DevicePathSize + ); + if (VarConout == NULL || VarConin == NULL) { + // + // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut + // + DetectAndPreparePlatformPciDevicePath (FALSE); + + // + // Have chance to connect the platform default console, + // the platform default console is the minimue device group + // the platform should support + // + for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) { + // + // Update the console variable with the connect type + // + if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) { + BdsLibUpdateConsoleVariable (VarConsoleInp, PlatformConsole[Index].DevicePath, NULL); + } + if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) { + BdsLibUpdateConsoleVariable (VarConsoleOut, PlatformConsole[Index].DevicePath, NULL); + } + if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) { + BdsLibUpdateConsoleVariable (VarErrorOut, PlatformConsole[Index].DevicePath, NULL); + } + } + } else { + // + // Only detect VGA device and add them to ConOut + // + DetectAndPreparePlatformPciDevicePath (TRUE); + } + + // + // The ConIn devices connection will start the USB bus, should disable all + // Usb legacy support firstly. + // Caution: Must ensure the PCI bus driver has been started. Since the + // ConnectRootBridge() will create all the PciIo protocol, it's safe here now + // + Status = DisableUsbLegacySupport(); + + // + // Connect the all the default console with current cosole variable + // + Status = BdsLibConnectAllDefaultConsoles (); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +VOID +PlatformBdsConnectSequence ( + VOID + ) +/*++ + +Routine Description: + + Connect with predeined platform connect sequence, + the OEM/IBV can customize with their own connect sequence. + +Arguments: + + None. + +Returns: + + None. + +--*/ +{ + UINTN Index; + + Index = 0; + + // + // Here we can get the customized platform connect sequence + // Notes: we can connect with new variable which record the + // last time boots connect device path sequence + // + while (gPlatformConnectSequence[Index] != NULL) { + // + // Build the platform boot option + // + BdsLibConnectDevicePath (gPlatformConnectSequence[Index]); + Index++; + } + +} + +VOID +PlatformBdsGetDriverOption ( + IN OUT LIST_ENTRY *BdsDriverLists + ) +/*++ + +Routine Description: + + Load the predefined driver option, OEM/IBV can customize this + to load their own drivers + +Arguments: + + BdsDriverLists - The header of the driver option link list. + +Returns: + + None. + +--*/ +{ + UINTN Index; + + Index = 0; + + // + // Here we can get the customized platform driver option + // + while (gPlatformDriverOption[Index] != NULL) { + // + // Build the platform boot option + // + BdsLibRegisterNewOption (BdsDriverLists, gPlatformDriverOption[Index], NULL, L"DriverOrder"); + Index++; + } + +} + +VOID +PlatformBdsDiagnostics ( + IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel, + IN BOOLEAN QuietBoot + ) +/*++ + +Routine Description: + + Perform the platform diagnostic, such like test memory. OEM/IBV also + can customize this fuction to support specific platform diagnostic. + +Arguments: + + MemoryTestLevel - The memory test intensive level + + QuietBoot - Indicate if need to enable the quiet boot + +Returns: + + None. + +--*/ +{ + EFI_STATUS Status; + + // + // Here we can decide if we need to show + // the diagnostics screen + // Notes: this quiet boot code should be remove + // from the graphic lib + // + if (QuietBoot) { + EnableQuietBootEx (&gEfiDefaultBmpLogoGuid, mBdsImageHandle); + // + // Perform system diagnostic + // + Status = BdsMemoryTest (MemoryTestLevel); + if (EFI_ERROR (Status)) { + DisableQuietBoot (); + } + + return ; + } + // + // Perform system diagnostic + // + Status = BdsMemoryTest (MemoryTestLevel); +} + +VOID +PlatformBdsPolicyBehavior ( + IN EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData, + IN OUT LIST_ENTRY *DriverOptionList, + IN OUT LIST_ENTRY *BootOptionList + ) +/*++ + +Routine Description: + + The function will excute with as the platform policy, current policy + is driven by boot mode. IBV/OEM can customize this code for their specific + policy action. + +Arguments: + + PrivateData - The EFI_BDS_ARCH_PROTOCOL_INSTANCE instance + + DriverOptionList - The header of the driver option link list + + BootOptionList - The header of the boot option link list + +Returns: + + None. + +--*/ +{ + EFI_STATUS Status; + UINT16 Timeout; + EFI_EVENT UserInputDurationTime; + LIST_ENTRY *Link; + BDS_COMMON_OPTION *BootOption; + UINTN Index; + EFI_INPUT_KEY Key; + EFI_TPL OldTpl; + + // + // Init the time out value + // + Timeout = BdsLibGetTimeout (); + + // + // Load the driver option as the driver option list + // + PlatformBdsGetDriverOption (DriverOptionList); + + // + // Get current Boot Mode + // + Status = BdsLibGetBootMode (&PrivateData->BootMode); + DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", PrivateData->BootMode)); + + // + // Go the different platform policy with different boot mode + // Notes: this part code can be change with the table policy + // + ASSERT (PrivateData->BootMode == BOOT_WITH_FULL_CONFIGURATION); + // + // Connect platform console + // + Status = PlatformBdsConnectConsole (gPlatformConsole); + if (EFI_ERROR (Status)) { + // + // Here OEM/IBV can customize with defined action + // + PlatformBdsNoConsoleAction (); + } + // + // Create a 300ms duration event to ensure user has enough input time to enter Setup + // + Status = gBS->CreateEvent ( + EFI_EVENT_TIMER, + 0, + NULL, + NULL, + &UserInputDurationTime + ); + ASSERT (Status == EFI_SUCCESS); + Status = gBS->SetTimer (UserInputDurationTime, TimerRelative, 3000000); + ASSERT (Status == EFI_SUCCESS); + // + // Memory test and Logo show + // + PlatformBdsDiagnostics (IGNORE, TRUE); + + // + // Perform some platform specific connect sequence + // + PlatformBdsConnectSequence (); + + // + // Give one chance to enter the setup if we + // have the time out + // + if (Timeout != 0) { + PlatformBdsEnterFrontPage (Timeout, FALSE); + } + + // + //BdsLibConnectAll (); + //BdsLibEnumerateAllBootOption (BootOptionList); + + // + // Please uncomment above ConnectAll and EnumerateAll code and remove following first boot + // checking code in real production tip. + // + // In BOOT_WITH_FULL_CONFIGURATION boot mode, should always connect every device + // and do enumerate all the default boot options. But in development system board, the boot mode + // cannot be BOOT_ASSUMING_NO_CONFIGURATION_CHANGES because the machine box + // is always open. So the following code only do the ConnectAll and EnumerateAll at first boot. + // + Status = BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder"); + if (EFI_ERROR(Status)) { + // + // If cannot find "BootOrder" variable, it may be first boot. + // Try to connect all devices and enumerate all boot options here. + // + BdsLibConnectAll (); + BdsLibEnumerateAllBootOption (BootOptionList); + } + + // + // To give the User a chance to enter Setup here, if user set TimeOut is 0. + // BDS should still give user a chance to enter Setup + // + // Connect first boot option, and then check user input before exit + // + for (Link = BootOptionList->ForwardLink; Link != BootOptionList;Link = Link->ForwardLink) { + BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE); + if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) { + // + // skip the header of the link list, becuase it has no boot option + // + continue; + } else { + // + // Make sure the boot option device path connected, but ignore the BBS device path + // + if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) { + BdsLibConnectDevicePath (BootOption->DevicePath); + } + break; + } + } + + // + // Check whether the user input after the duration time has expired + // + OldTpl = BdsLibGetCurrentTpl(); + gBS->RestoreTPL (TPL_APPLICATION); + gBS->WaitForEvent (1, &UserInputDurationTime, &Index); + gBS->CloseEvent (UserInputDurationTime); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + gBS->RaiseTPL (OldTpl); + + if (!EFI_ERROR (Status)) { + // + // Enter Setup if user input + // + Timeout = 0xffff; + PlatformBdsEnterFrontPage (Timeout, FALSE); + } + + return ; + +} + +VOID +PlatformBdsBootSuccess ( + IN BDS_COMMON_OPTION *Option + ) +/*++ + +Routine Description: + + Hook point after a boot attempt succeeds. We don't expect a boot option to + return, so the EFI 1.0 specification defines that you will default to an + interactive mode and stop processing the BootOrder list in this case. This + is alos a platform implementation and can be customized by IBV/OEM. + +Arguments: + + Option - Pointer to Boot Option that succeeded to boot. + +Returns: + + None. + +--*/ +{ + CHAR16 *TmpStr; + + // + // If Boot returned with EFI_SUCCESS and there is not in the boot device + // select loop then we need to pop up a UI and wait for user input. + // + TmpStr = Option->StatusString; + if (TmpStr != NULL) { + BdsLibOutputStrings (gST->ConOut, TmpStr, Option->Description, L"\n\r", NULL); + gBS->FreePool (TmpStr); + } +} + +VOID +PlatformBdsBootFail ( + IN BDS_COMMON_OPTION *Option, + IN EFI_STATUS Status, + IN CHAR16 *ExitData, + IN UINTN ExitDataSize + ) +/*++ + +Routine Description: + + Hook point after a boot attempt fails. + +Arguments: + + Option - Pointer to Boot Option that failed to boot. + + Status - Status returned from failed boot. + + ExitData - Exit data returned from failed boot. + + ExitDataSize - Exit data size returned from failed boot. + +Returns: + + None. + +--*/ +{ + CHAR16 *TmpStr; + + // + // If Boot returned with failed status then we need to pop up a UI and wait + // for user input. + // + TmpStr = Option->StatusString; + if (TmpStr != NULL) { + BdsLibOutputStrings (gST->ConOut, TmpStr, Option->Description, L"\n\r", NULL); + gBS->FreePool (TmpStr); + } + +} + +EFI_STATUS +PlatformBdsNoConsoleAction ( + VOID + ) +/*++ + +Routine Description: + + This function is remained for IBV/OEM to do some platform action, + if there no console device can be connected. + +Arguments: + + None. + +Returns: + + EFI_SUCCESS - Direct return success now. + +--*/ +{ + return EFI_SUCCESS; +} + +EFI_STATUS +ConvertSystemTable ( + IN EFI_GUID *TableGuid, + IN OUT VOID **Table + ) +/*++ + +Routine Description: + Convert ACPI Table /Smbios Table /MP Table if its location is lower than Address:0x100000 + Assumption here: + As in legacy Bios, ACPI/Smbios/MP table is required to place in E/F Seg, + So here we just check if the range is E/F seg, + and if Not, assume the Memory type is EfiACPIReclaimMemory/EfiACPIMemoryNVS + +Arguments: + TableGuid - Guid of the table + Table - pointer to the table + +Returns: + EFI_SUCEESS - Convert Table successfully + Other - Failed + +--*/ +{ + EFI_STATUS Status; + VOID *AcpiHeader; + UINTN AcpiTableLen; + + // + // If match acpi guid (1.0, 2.0, or later), Convert ACPI table according to version. + // + AcpiHeader = (VOID*)(UINTN)(*(UINT64 *)(*Table)); + + if (CompareGuid(TableGuid, &gEfiAcpiTableGuid) || CompareGuid(TableGuid, &gEfiAcpi20TableGuid)){ + if (((EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiHeader)->Reserved == 0x00){ + // + // If Acpi 1.0 Table, then RSDP structure doesn't contain Length field, use structure size + // + AcpiTableLen = sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER); + } else if (((EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiHeader)->Reserved >= 0x02){ + // + // If Acpi 2.0 or later, use RSDP Length fied. + // + AcpiTableLen = ((EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiHeader)->Length; + } else { + // + // Invalid Acpi Version, return + // + return EFI_UNSUPPORTED; + } + Status = ConvertAcpiTable (AcpiTableLen, Table); + return Status; + } + + // + // If matches smbios guid, convert Smbios table. + // + if (CompareGuid(TableGuid, &gEfiSmbiosTableGuid)){ + Status = ConvertSmbiosTable (Table); + return Status; + } + + // + // If the table is MP table? + // + if (CompareGuid(TableGuid, &gEfiMpsTableGuid)){ + Status = ConvertMpsTable (Table); + return Status; + } + + return EFI_UNSUPPORTED; +} + +UINT8 +GetBufferCheckSum ( + IN VOID * Buffer, + IN UINTN Length + ) +/*++ + +Routine Description: + Caculate buffer checksum (8-bit) + +Arguments: + Buffer - Pointer to Buffer that to be caculated + Length - How many bytes are to be caculated + +Returns: + Checksum of the buffer + +--*/ +{ + UINT8 CheckSum; + UINT8 *Ptr8; + + CheckSum = 0; + Ptr8 = (UINT8 *) Buffer; + + while (Length > 0) { + CheckSum = (UINT8) (CheckSum + *Ptr8++); + Length--; + } + + return ((0xFF - CheckSum) + 1); +} + +EFI_STATUS +ConvertAcpiTable ( + IN UINTN TableLen, + IN OUT VOID **Table + ) +/*++ + +Routine Description: + Convert RSDP of ACPI Table if its location is lower than Address:0x100000 + Assumption here: + As in legacy Bios, ACPI table is required to place in E/F Seg, + So here we just check if the range is E/F seg, + and if Not, assume the Memory type is EfiACPIReclaimMemory/EfiACPIMemoryNVS + +Arguments: + TableLen - Acpi RSDP length + Table - pointer to the table + +Returns: + EFI_SUCEESS - Convert Table successfully + Other - Failed + +--*/ +{ + VOID *AcpiTableOri; + VOID *AcpiTableNew; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS BufferPtr; + + + AcpiTableOri = (VOID *)(UINTN)(*(UINT64*)(*Table)); + if (((UINTN)AcpiTableOri < 0x100000) && ((UINTN)AcpiTableOri > 0xE0000)) { + BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES(TableLen), + &BufferPtr + ); + ASSERT_EFI_ERROR (Status); + AcpiTableNew = (VOID *)(UINTN)BufferPtr; + CopyMem (AcpiTableNew, AcpiTableOri, TableLen); + } else { + AcpiTableNew = AcpiTableOri; + } + // + // Change configuration table Pointer + // + *Table = AcpiTableNew; + + return EFI_SUCCESS; +} + +EFI_STATUS +ConvertSmbiosTable ( + IN OUT VOID **Table + ) +/*++ + +Routine Description: + + Convert Smbios Table if the Location of the SMBios Table is lower than Addres 0x100000 + Assumption here: + As in legacy Bios, Smbios table is required to place in E/F Seg, + So here we just check if the range is F seg, + and if Not, assume the Memory type is EfiACPIMemoryNVS/EfiRuntimeServicesData +Arguments: + Table - pointer to the table + +Returns: + EFI_SUCEESS - Convert Table successfully + Other - Failed + +--*/ +{ + SMBIOS_TABLE_ENTRY_POINT *SmbiosTableNew; + SMBIOS_TABLE_ENTRY_POINT *SmbiosTableOri; + EFI_STATUS Status; + UINT32 SmbiosEntryLen; + UINT32 BufferLen; + EFI_PHYSICAL_ADDRESS BufferPtr; + + SmbiosTableNew = NULL; + SmbiosTableOri = NULL; + + // + // Get Smibos configuration Table + // + SmbiosTableOri = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN)(*(UINT64*)(*Table)); + + if ((SmbiosTableOri == NULL) || + ((UINTN)SmbiosTableOri > 0x100000) || + ((UINTN)SmbiosTableOri < 0xF0000)){ + return EFI_SUCCESS; + } + // + // Relocate the Smibos memory + // + BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS; + if (SmbiosTableOri->SmbiosBcdRevision != 0x21) { + SmbiosEntryLen = SmbiosTableOri->EntryPointLength; + } else { + // + // According to Smbios Spec 2.4, we should set entry point length as 0x1F if version is 2.1 + // + SmbiosEntryLen = 0x1F; + } + BufferLen = SmbiosEntryLen + SYS_TABLE_PAD(SmbiosEntryLen) + SmbiosTableOri->TableLength; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES(BufferLen), + &BufferPtr + ); + ASSERT_EFI_ERROR (Status); + SmbiosTableNew = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN)BufferPtr; + CopyMem ( + SmbiosTableNew, + SmbiosTableOri, + SmbiosEntryLen + ); + // + // Get Smbios Structure table address, and make sure the start address is 32-bit align + // + BufferPtr += SmbiosEntryLen + SYS_TABLE_PAD(SmbiosEntryLen); + CopyMem ( + (VOID *)(UINTN)BufferPtr, + (VOID *)(UINTN)(SmbiosTableOri->TableAddress), + SmbiosTableOri->TableLength + ); + SmbiosTableNew->TableAddress = (UINT32)BufferPtr; + SmbiosTableNew->IntermediateChecksum = 0; + SmbiosTableNew->IntermediateChecksum = + GetBufferCheckSum ((UINT8*)SmbiosTableNew + 0x10, SmbiosEntryLen -0x10); + // + // Change the SMBIOS pointer + // + *Table = SmbiosTableNew; + + return EFI_SUCCESS; +} + +EFI_STATUS +ConvertMpsTable ( + IN OUT VOID **Table + ) +/*++ + +Routine Description: + + Convert MP Table if the Location of the SMBios Table is lower than Addres 0x100000 + Assumption here: + As in legacy Bios, MP table is required to place in E/F Seg, + So here we just check if the range is E/F seg, + and if Not, assume the Memory type is EfiACPIMemoryNVS/EfiRuntimeServicesData +Arguments: + Table - pointer to the table + +Returns: + EFI_SUCEESS - Convert Table successfully + Other - Failed + +--*/ +{ + UINT32 Data32; + UINT32 FPLength; + EFI_LEGACY_MP_TABLE_FLOATING_POINTER *MpsFloatingPointerOri; + EFI_LEGACY_MP_TABLE_FLOATING_POINTER *MpsFloatingPointerNew; + EFI_LEGACY_MP_TABLE_HEADER *MpsTableOri; + EFI_LEGACY_MP_TABLE_HEADER *MpsTableNew; + VOID *OemTableOri; + VOID *OemTableNew; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS BufferPtr; + + // + // Get MP configuration Table + // + MpsFloatingPointerOri = (EFI_LEGACY_MP_TABLE_FLOATING_POINTER *)(UINTN)(*(UINT64*)(*Table)); + if (!(((UINTN)MpsFloatingPointerOri <= 0x100000) && + ((UINTN)MpsFloatingPointerOri >= 0xF0000))){ + return EFI_SUCCESS; + } + // + // Get Floating pointer structure length + // + FPLength = MpsFloatingPointerOri->Length * 16; + Data32 = FPLength + SYS_TABLE_PAD (FPLength); + MpsTableOri = (EFI_LEGACY_MP_TABLE_HEADER *)(UINTN)(MpsFloatingPointerOri->PhysicalAddress); + if (MpsTableOri != NULL) { + Data32 += MpsTableOri->BaseTableLength; + Data32 += MpsTableOri->ExtendedTableLength; + if (MpsTableOri->OemTablePointer != 0x00) { + Data32 += SYS_TABLE_PAD (Data32); + Data32 += MpsTableOri->OemTableSize; + } + } else { + return EFI_SUCCESS; + } + // + // Relocate memory + // + BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES(Data32), + &BufferPtr + ); + ASSERT_EFI_ERROR (Status); + MpsFloatingPointerNew = (EFI_LEGACY_MP_TABLE_FLOATING_POINTER *)(UINTN)BufferPtr; + CopyMem (MpsFloatingPointerNew, MpsFloatingPointerOri, FPLength); + // + // If Mp Table exists + // + if (MpsTableOri != NULL) { + // + // Get Mps table length, including Ext table + // + BufferPtr = BufferPtr + FPLength + SYS_TABLE_PAD (FPLength); + MpsTableNew = (EFI_LEGACY_MP_TABLE_HEADER *)(UINTN)BufferPtr; + CopyMem (MpsTableNew, MpsTableOri, MpsTableOri->BaseTableLength + MpsTableOri->ExtendedTableLength); + + if ((MpsTableOri->OemTableSize != 0x0000) && (MpsTableOri->OemTablePointer != 0x0000)){ + BufferPtr += MpsTableOri->BaseTableLength + MpsTableOri->ExtendedTableLength; + BufferPtr += SYS_TABLE_PAD (BufferPtr); + OemTableNew = (VOID *)(UINTN)BufferPtr; + OemTableOri = (VOID *)(UINTN)MpsTableOri->OemTablePointer; + CopyMem (OemTableNew, OemTableOri, MpsTableOri->OemTableSize); + MpsTableNew->OemTablePointer = (UINT32)(UINTN)OemTableNew; + } + MpsTableNew->Checksum = 0; + MpsTableNew->Checksum = GetBufferCheckSum (MpsTableNew, MpsTableOri->BaseTableLength); + MpsFloatingPointerNew->PhysicalAddress = (UINT32)(UINTN)MpsTableNew; + MpsFloatingPointerNew->Checksum = 0; + MpsFloatingPointerNew->Checksum = GetBufferCheckSum (MpsFloatingPointerNew, FPLength); + } + // + // Change the pointer + // + *Table = MpsFloatingPointerNew; + + return EFI_SUCCESS; +} diff --git a/DuetPkg/Library/DuetBdsLib/BdsPlatform.h b/DuetPkg/Library/DuetBdsLib/BdsPlatform.h new file mode 100644 index 0000000000..ce2a0ba2b8 --- /dev/null +++ b/DuetPkg/Library/DuetBdsLib/BdsPlatform.h @@ -0,0 +1,312 @@ +/*++ + +Copyright (c) 2006 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + BdsPlatform.h + +Abstract: + + Head file for BDS Platform specific code + +--*/ + +#ifndef _PLATFORM_SPECIFIC_BDS_PLATFORM_H_ +#define _PLATFORM_SPECIFIC_BDS_PLATFORM_H_ + + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +extern BDS_CONSOLE_CONNECT_ENTRY gPlatformConsole[]; +extern EFI_DEVICE_PATH_PROTOCOL *gPlatformConnectSequence[]; +extern EFI_DEVICE_PATH_PROTOCOL *gPlatformDriverOption[]; +extern EFI_DEVICE_PATH_PROTOCOL *gPlatformRootBridges[]; +extern ACPI_HID_DEVICE_PATH gPnpPs2KeyboardDeviceNode; +extern ACPI_HID_DEVICE_PATH gPnp16550ComPortDeviceNode; +extern UART_DEVICE_PATH gUartDeviceNode; +extern VENDOR_DEVICE_PATH gTerminalTypeDeviceNode; +// +// +// +#define VarConsoleInpDev L"ConInDev" +#define VarConsoleInp L"ConIn" +#define VarConsoleOutDev L"ConOutDev" +#define VarConsoleOut L"ConOut" +#define VarErrorOutDev L"ErrOutDev" +#define VarErrorOut L"ErrOut" + +#define PCI_DEVICE_PATH_NODE(Func, Dev) \ + { \ + HARDWARE_DEVICE_PATH, \ + HW_PCI_DP, \ + (UINT8) (sizeof (PCI_DEVICE_PATH)), \ + (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8), \ + (Func), \ + (Dev) \ + } + +#define PNPID_DEVICE_PATH_NODE(PnpId) \ + { \ + ACPI_DEVICE_PATH, \ + ACPI_DP, \ + (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), \ + (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8), \ + EISA_PNP_ID((PnpId)), \ + 0 \ + } + +#define gPciRootBridge \ + PNPID_DEVICE_PATH_NODE(0x0A03) + +#define gPciIsaBridge \ + PCI_DEVICE_PATH_NODE(0, 0x1f) + +#define gP2PBridge \ + PCI_DEVICE_PATH_NODE(0, 0x1e) + +#define gPnpPs2Keyboard \ + PNPID_DEVICE_PATH_NODE(0x0303) + +#define gPnp16550ComPort \ + PNPID_DEVICE_PATH_NODE(0x0501) + +#define gUart \ + { \ + MESSAGING_DEVICE_PATH, \ + MSG_UART_DP, \ + (UINT8) (sizeof (UART_DEVICE_PATH)), \ + (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8), \ + 0, \ + 115200, \ + 8, \ + 1, \ + 1 \ + } + +#define gPcAnsiTerminal \ + { \ + MESSAGING_DEVICE_PATH, \ + MSG_VENDOR_DP, \ + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), \ + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8), \ + DEVICE_PATH_MESSAGING_PC_ANSI \ + } + +#define gEndEntire \ + { \ + END_DEVICE_PATH_TYPE, \ + END_ENTIRE_DEVICE_PATH_SUBTYPE, \ + END_DEVICE_PATH_LENGTH, \ + 0 \ + } + +#define PCI_CLASS_SCC 0x07 +#define PCI_SUBCLASS_SERIAL 0x00 +#define PCI_IF_16550 0x02 +#define IS_PCI_16550SERIAL(_p) IS_CLASS3 (_p, PCI_CLASS_SCC, PCI_SUBCLASS_SERIAL, PCI_IF_16550) + +#define EFI_SYSTEM_TABLE_MAX_ADDRESS 0xFFFFFFFF +#define SYS_TABLE_PAD(ptr) (((~ptr) +1) & 0x07 ) +// +// Platform Root Bridge +// +typedef struct { + ACPI_HID_DEVICE_PATH PciRootBridge; + EFI_DEVICE_PATH_PROTOCOL End; +} PLATFORM_ROOT_BRIDGE_DEVICE_PATH; + +typedef struct { + ACPI_HID_DEVICE_PATH PciRootBridge; + PCI_DEVICE_PATH IsaBridge; + ACPI_HID_DEVICE_PATH Keyboard; + EFI_DEVICE_PATH_PROTOCOL End; +} PLATFORM_DUMMY_ISA_KEYBOARD_DEVICE_PATH; + +typedef struct { + ACPI_HID_DEVICE_PATH PciRootBridge; + PCI_DEVICE_PATH IsaBridge; + ACPI_HID_DEVICE_PATH IsaSerial; + UART_DEVICE_PATH Uart; + VENDOR_DEVICE_PATH TerminalType; + EFI_DEVICE_PATH_PROTOCOL End; +} PLATFORM_DUMMY_ISA_SERIAL_DEVICE_PATH; + +typedef struct { + ACPI_HID_DEVICE_PATH PciRootBridge; + PCI_DEVICE_PATH VgaDevice; + EFI_DEVICE_PATH_PROTOCOL End; +} PLATFORM_DUMMY_PCI_VGA_DEVICE_PATH; + +typedef struct { + ACPI_HID_DEVICE_PATH PciRootBridge; + PCI_DEVICE_PATH PciBridge; + PCI_DEVICE_PATH SerialDevice; + UART_DEVICE_PATH Uart; + VENDOR_DEVICE_PATH TerminalType; + EFI_DEVICE_PATH_PROTOCOL End; +} PLATFORM_DUMMY_PCI_SERIAL_DEVICE_PATH; + +// +// the short form device path for Usb keyboard +// +#define CLASS_HID 3 +#define SUBCLASS_BOOT 1 +#define PROTOCOL_KEYBOARD 1 + +typedef struct { + USB_CLASS_DEVICE_PATH UsbClass; + EFI_DEVICE_PATH_PROTOCOL End; +} USB_CLASS_FORMAT_DEVICE_PATH; + +extern PLATFORM_ROOT_BRIDGE_DEVICE_PATH gPlatformRootBridge0; + +// +// Platform BDS Functions +// +VOID +PlatformBdsInit ( + IN EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData + ) +; + +VOID +PlatformBdsPolicyBehavior ( + IN EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData, + IN LIST_ENTRY *DriverOptionList, + IN LIST_ENTRY *BootOptionList + ) +; + +VOID +PlatformBdsGetDriverOption ( + IN LIST_ENTRY *BdsDriverLists + ) +; + +EFI_STATUS +BdsMemoryTest ( + EXTENDMEM_COVERAGE_LEVEL Level + ) +; + +EFI_STATUS +PlatformBdsShowProgress ( + EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground, + EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground, + CHAR16 *Title, + EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor, + UINTN Progress, + UINTN PreviousValue + ) +; + +VOID +PlatformBdsConnectSequence ( + VOID + ) +; + +VOID +PlatformBdsBootFail ( + IN BDS_COMMON_OPTION *Option, + IN EFI_STATUS Status, + IN CHAR16 *ExitData, + IN UINTN ExitDataSize + ) +; + +VOID +PlatformBdsBootSuccess ( + IN BDS_COMMON_OPTION *Option + ) +; + +EFI_STATUS +ProcessCapsules ( + EFI_BOOT_MODE BootMode + ) +; + +EFI_STATUS +PlatformBdsConnectConsole ( + IN BDS_CONSOLE_CONNECT_ENTRY *PlatformConsole + ) +; + +EFI_STATUS +PlatformBdsNoConsoleAction ( + VOID + ) +; + +EFI_STATUS +ConvertMpsTable ( + IN OUT VOID **Table + ) +; + +EFI_STATUS +ConvertSmbiosTable ( + IN OUT VOID **Table + ) +; + +EFI_STATUS +ConvertAcpiTable ( + IN UINTN TableLen, + IN OUT VOID **Table + ) +; + +EFI_STATUS +ConvertSystemTable ( + IN EFI_GUID *TableGuid, + IN OUT VOID **Table + ) +; + +VOID +PlatformBdsEnterFrontPage ( + IN UINT16 TimeoutDefault, + IN BOOLEAN ConnectAllHappened + ) +; + +#endif // _PLATFORM_SPECIFIC_BDS_PLATFORM_H_ diff --git a/DuetPkg/Library/DuetBdsLib/PlatformBds.inf b/DuetPkg/Library/DuetBdsLib/PlatformBds.inf new file mode 100644 index 0000000000..12d507b5d6 --- /dev/null +++ b/DuetPkg/Library/DuetBdsLib/PlatformBds.inf @@ -0,0 +1,64 @@ +#/*++ +# +# Copyright (c) 2006 - 2007, Intel Corporation +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# PlatformBds.inf +# +# Abstract: +# +# Component description file for Bds module. +# +#--*/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DuetBds + FILE_GUID = A6F691AC-31C8-4444-854C-E2C1A6950F92 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = PlatformBdsLib|DXE_DRIVER + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x0002000A + + +[Sources.common] + BdsPlatform.c + PlatformData.c + BdsPlatform.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Nt32Pkg/Nt32Pkg.dec + DuetPkg/DuetPkg.dec + +[LibraryClasses] + BaseLib + MemoryAllocationLib + UefiBootServicesTableLib + BaseMemoryLib + DebugLib + PcdLib + GraphicsLib + GenericBdsLib + HobLib + UefiLib + DevicePathLib + +[Guids] + gEfiDefaultBmpLogoGuid + gEfiGlobalVariableGuid + gEfiPciExpressBaseAddressGuid + gEfiAcpi20TableGuid + gEfiMpsTableGuid + gEfiSmbiosTableGuid + gEfiAcpiTableGuid \ No newline at end of file diff --git a/DuetPkg/Library/DuetBdsLib/PlatformData.c b/DuetPkg/Library/DuetBdsLib/PlatformData.c new file mode 100644 index 0000000000..e1a0cde3d4 --- /dev/null +++ b/DuetPkg/Library/DuetBdsLib/PlatformData.c @@ -0,0 +1,157 @@ +/*++ + +Copyright (c) 2006 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PlatformData.c + +Abstract: + + Defined the platform specific device path which will be used by + platform Bbd to perform the platform policy connect. + +--*/ + +#include "BdsPlatform.h" + +// +// Predefined platform default time out value +// +UINT16 gPlatformBootTimeOutDefault = 3; + +ACPI_HID_DEVICE_PATH gPnpPs2KeyboardDeviceNode = gPnpPs2Keyboard; +ACPI_HID_DEVICE_PATH gPnp16550ComPortDeviceNode = gPnp16550ComPort; +UART_DEVICE_PATH gUartDeviceNode = gUart; +VENDOR_DEVICE_PATH gTerminalTypeDeviceNode = gPcAnsiTerminal; + +// +// Predefined platform root bridge +// +PLATFORM_ROOT_BRIDGE_DEVICE_PATH gPlatformRootBridge0 = { + gPciRootBridge, + gEndEntire +}; + +EFI_DEVICE_PATH_PROTOCOL *gPlatformRootBridges[] = { + (EFI_DEVICE_PATH_PROTOCOL *) &gPlatformRootBridge0, + NULL +}; + +USB_CLASS_FORMAT_DEVICE_PATH gUsbClassKeyboardDevicePath = { + { + { + MESSAGING_DEVICE_PATH, + MSG_USB_CLASS_DP, + (UINT8) (sizeof (USB_CLASS_DEVICE_PATH)), + (UINT8) ((sizeof (USB_CLASS_DEVICE_PATH)) >> 8) + }, + 0xffff, // VendorId + 0xffff, // ProductId + CLASS_HID, // DeviceClass + SUBCLASS_BOOT, // DeviceSubClass + PROTOCOL_KEYBOARD // DeviceProtocol + }, + + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + END_DEVICE_PATH_LENGTH, + 0 + } +}; + +/* +// +// Platform specific Dummy ISA keyboard device path +// +PLATFORM_DUMMY_ISA_KEYBOARD_DEVICE_PATH gDummyIsaKeyboardDevicePath = { + gPciRootBridge, + gPciIsaBridge, + gPnpPs2Keyboard, + gEndEntire +}; + +// +// Platform specific Dummy ISA serial device path +// +PLATFORM_DUMMY_ISA_SERIAL_DEVICE_PATH gDummyIsaSerialDevicePath = { + gPciRootBridge, + gPciIsaBridge, + gPnp16550ComPort, + gUart, + gPcAnsiTerminal, + gEndEntire +}; + +// +// Platform specific Dummy PCI VGA device path +// +PLATFORM_DUMMY_PCI_VGA_DEVICE_PATH gDummyPciVgaDevicePath = { + gPciRootBridge, + PCI_DEVICE_PATH_NODE(0, 0x2), + gEndEntire +}; + +// +// Platform specific Dummy PCI serial device path +// +PLATFORM_DUMMY_PCI_SERIAL_DEVICE_PATH gDummyPciSerialDevicePath = { + gPciRootBridge, + gP2PBridge, + PCI_DEVICE_PATH_NODE(0, 0x0), + gUart, + gPcAnsiTerminal, + gEndEntire +}; +*/ +// +// Predefined platform default console device path +// +BDS_CONSOLE_CONNECT_ENTRY gPlatformConsole[] = { + // + // need update dynamically + // +// { +// (EFI_DEVICE_PATH_PROTOCOL *) &gDummyIsaSerialDevicePath, +// (CONSOLE_OUT | CONSOLE_IN | STD_ERROR) +// }, +// { +// (EFI_DEVICE_PATH_PROTOCOL *) &gDummyIsaKeyboardDevicePath, +// (CONSOLE_IN | STD_ERROR) +// }, +// { +// (EFI_DEVICE_PATH_PROTOCOL *) &gDummyPciVgaDevicePath, +// CONSOLE_OUT +// }, +// { +// (EFI_DEVICE_PATH_PROTOCOL *) &gDummyPciSerialDevicePath, +// (CONSOLE_OUT | CONSOLE_IN | STD_ERROR) +// }, + { + (EFI_DEVICE_PATH_PROTOCOL*) &gUsbClassKeyboardDevicePath, + CONSOLE_IN + }, + { + NULL, + 0 + } +}; + +// +// Predefined platform specific driver option +// +EFI_DEVICE_PATH_PROTOCOL *gPlatformDriverOption[] = { NULL }; + +// +// Predefined platform connect sequence +// +EFI_DEVICE_PATH_PROTOCOL *gPlatformConnectSequence[] = { NULL }; + diff --git a/DuetPkg/PcRtc/Ia32/RealTimeClock.c b/DuetPkg/PcRtc/Ia32/RealTimeClock.c new file mode 100644 index 0000000000..dc2a79b948 --- /dev/null +++ b/DuetPkg/PcRtc/Ia32/RealTimeClock.c @@ -0,0 +1,170 @@ +/*++ + +Copyright (c) 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + Ia32PcRtc.c + +Abstract: + +--*/ +#include "RealTimeClock.h" + +static PC_RTC_MODULE_GLOBALS mModuleGlobal; + +EFI_STATUS +EFIAPI +PcRtcEfiGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Time - TODO: add argument description + Capabilities - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + return PcRtcGetTime (Time, Capabilities, &mModuleGlobal); +} + +EFI_STATUS +EFIAPI +PcRtcEfiSetTime ( + IN EFI_TIME *Time + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Time - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + return PcRtcSetTime (Time, &mModuleGlobal); +} + +EFI_STATUS +EFIAPI +PcRtcEfiGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Enabled - TODO: add argument description + Pending - TODO: add argument description + Time - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + return PcRtcGetWakeupTime (Enabled, Pending, Time, &mModuleGlobal); +} + +EFI_STATUS +EFIAPI +PcRtcEfiSetWakeupTime ( + IN BOOLEAN Enabled, + OUT EFI_TIME *Time + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Enabled - TODO: add argument description + Time - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + return PcRtcSetWakeupTime (Enabled, Time, &mModuleGlobal); +} + +EFI_STATUS +EFIAPI +InitializeRealTimeClock ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Arguments: + + + +Returns: +--*/ +// TODO: ImageHandle - add argument and description to function comment +// TODO: SystemTable - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_HANDLE NewHandle; + + + EfiInitializeLock (&mModuleGlobal.RtcLock, TPL_HIGH_LEVEL); + + Status = PcRtcInit (&mModuleGlobal); + if (EFI_ERROR (Status)) { + return Status; + } + + SystemTable->RuntimeServices->GetTime = PcRtcEfiGetTime; + SystemTable->RuntimeServices->SetTime = PcRtcEfiSetTime; + SystemTable->RuntimeServices->GetWakeupTime = PcRtcEfiGetWakeupTime; + SystemTable->RuntimeServices->SetWakeupTime = PcRtcEfiSetWakeupTime; + + NewHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &NewHandle, + &gEfiRealTimeClockArchProtocolGuid, + NULL, + NULL + ); + + return Status; +} diff --git a/DuetPkg/PcRtc/Ia32RealTimeClock.dxs b/DuetPkg/PcRtc/Ia32RealTimeClock.dxs new file mode 100644 index 0000000000..ff9f52fb7a --- /dev/null +++ b/DuetPkg/PcRtc/Ia32RealTimeClock.dxs @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + Ia32PcRtc.dxs + +Abstract: + Dependency expression source file. + +--*/ + + +#include "EfiDepex.h" + +#include EFI_ARCH_PROTOCOL_DEFINITION (Cpu) +#include EFI_ARCH_PROTOCOL_DEFINITION (Metronome) +#include EFI_PROTOCOL_DEFINITION (CpuIo) + +DEPENDENCY_START + EFI_CPU_ARCH_PROTOCOL_GUID AND EFI_METRONOME_ARCH_PROTOCOL_GUID AND EFI_CPU_IO_PROTOCOL_GUID +DEPENDENCY_END diff --git a/DuetPkg/PcRtc/Ipf/IpfPcRtc.c b/DuetPkg/PcRtc/Ipf/IpfPcRtc.c new file mode 100644 index 0000000000..ef2260b214 --- /dev/null +++ b/DuetPkg/PcRtc/Ipf/IpfPcRtc.c @@ -0,0 +1,185 @@ +/*++ + +Copyright (c) 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + IpfPcRtc.c + +Abstract: + Register the extended SAL infrastructure. + + Make the EFI RT APIs call extended SAL calls via the RT lib wrappers. + We can not do this on IA-32 as RT lib wrappers call via rRT. + +--*/ + +#include "RealTimeClock.h" + +// +// Don't use directly after virtual address have been registered. +// +static PC_RTC_MODULE_GLOBALS mModuleGlobal; + +SAL_RETURN_REGS +PcRtcEsalServicesClassCommonEntry ( + IN UINT64 FunctionId, + IN UINT64 Arg2, + IN UINT64 Arg3, + IN UINT64 Arg4, + IN UINT64 Arg5, + IN UINT64 Arg6, + IN UINT64 Arg7, + IN UINT64 Arg8, + IN SAL_EXTENDED_SAL_PROC ExtendedSalProc, + IN BOOLEAN VirtualMode, + IN PC_RTC_MODULE_GLOBALS *Global + ) +/*++ + +Routine Description: + + Main entry for Extended SAL Reset Services + +Arguments: + + FunctionId Function Id which needed to be called. + Arg2 EFI_RESET_TYPE, whether WARM of COLD reset + Arg3 Last EFI_STATUS + Arg4 Data Size of UNICODE STRING passed in ARG5 + Arg5 Unicode String which CHAR16* + +Returns: + + SAL_RETURN_REGS + +--*/ +// TODO: Arg6 - add argument and description to function comment +// TODO: Arg7 - add argument and description to function comment +// TODO: Arg8 - add argument and description to function comment +// TODO: ExtendedSalProc - add argument and description to function comment +// TODO: VirtualMode - add argument and description to function comment +// TODO: Global - add argument and description to function comment +{ + EFI_STATUS EfiStatus; + SAL_RETURN_REGS ReturnVal; + + switch (FunctionId) { + case GetTime: + EfiStatus = PcRtcGetTime ((EFI_TIME *) Arg2, (EFI_TIME_CAPABILITIES *) Arg3, Global); + break; + + case SetTime: + EfiStatus = PcRtcSetTime ((EFI_TIME *) Arg2, Global); + break; + + case GetWakeupTime: + EfiStatus = PcRtcGetWakeupTime ((BOOLEAN *) Arg2, (BOOLEAN *) Arg3, (EFI_TIME *) Arg4, Global); + break; + + case SetWakeupTime: + EfiStatus = PcRtcSetWakeupTime ((BOOLEAN) Arg2, (EFI_TIME *) Arg3, Global); + break; + + case InitializeThreshold: + EfiStatus = EFI_SAL_NOT_IMPLEMENTED; + break; + + case BumpThresholdCount: + EfiStatus = EFI_SAL_NOT_IMPLEMENTED; + break; + + case GetThresholdCount: + EfiStatus = EFI_SAL_NOT_IMPLEMENTED; + break; + + case GetRtcFreq: + EfiStatus = EFI_SAL_NOT_IMPLEMENTED; + break; + + default: + EfiStatus = EFI_SAL_INVALID_ARGUMENT; + break;; + } + + ReturnVal.Status = EfiStatus; + return ReturnVal; +} + +EFI_STATUS +EFIAPI +InitializePcRtc ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Arguments: + + + +Returns: +--*/ +// TODO: ImageHandle - add argument and description to function comment +// TODO: SystemTable - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_TIME Time; + EFI_TIME_CAPABILITIES Capabilities; + EFI_STATUS EfiStatus; + + EfiInitializeRuntimeDriverLib (ImageHandle, SystemTable, NULL); + + EfiInitializeLock (&mModuleGlobal.RtcLock, EFI_TPL_HIGH_LEVEL); + + EfiStatus = PcRtcInit (&mModuleGlobal); + if (EFI_ERROR (EfiStatus)) { + return EfiStatus; + } + + RegisterEsalClass ( + &gEfiExtendedSalRtcServicesProtocolGuid, + &mModuleGlobal, + PcRtcEsalServicesClassCommonEntry, + GetTime, + PcRtcEsalServicesClassCommonEntry, + SetTime, + PcRtcEsalServicesClassCommonEntry, + GetWakeupTime, + PcRtcEsalServicesClassCommonEntry, + SetWakeupTime, + PcRtcEsalServicesClassCommonEntry, + GetRtcFreq, + PcRtcEsalServicesClassCommonEntry, + InitializeThreshold, + PcRtcEsalServicesClassCommonEntry, + BumpThresholdCount, + PcRtcEsalServicesClassCommonEntry, + GetThresholdCount, + NULL + ); + // + // the following code is to initialize the RTC fields in case the values read + // back from CMOS are invalid at the first time. + // + EfiStatus = PcRtcGetTime (&Time, &Capabilities, &mModuleGlobal); + if (EFI_ERROR (EfiStatus)) { + Time.Second = RTC_INIT_SECOND; + Time.Minute = RTC_INIT_MINUTE; + Time.Hour = RTC_INIT_HOUR; + Time.Day = RTC_INIT_DAY; + Time.Month = RTC_INIT_MONTH; + Time.Year = RTC_INIT_YEAR; + PcRtcSetTime (&Time, &mModuleGlobal); + } + + return EFI_SUCCESS; +} diff --git a/DuetPkg/PcRtc/IpfRealTimeClock.dxs b/DuetPkg/PcRtc/IpfRealTimeClock.dxs new file mode 100644 index 0000000000..4d05b4f8a3 --- /dev/null +++ b/DuetPkg/PcRtc/IpfRealTimeClock.dxs @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + IpfPcRtc.dxs + +Abstract: + Dependency expression source file. + +--*/ + + +#include "EfiDepex.h" + +#include EFI_PROTOCOL_DEFINITION (ExtendedSalGuid) +#include EFI_ARCH_PROTOCOL_DEFINITION (Metronome) + +DEPENDENCY_START + EFI_EXTENDED_SAL_BASE_IO_SERVICES_PROTOCOL_GUID AND EFI_METRONOME_ARCH_PROTOCOL_GUID +DEPENDENCY_END diff --git a/DuetPkg/PcRtc/RealTimeClock.c b/DuetPkg/PcRtc/RealTimeClock.c new file mode 100644 index 0000000000..b677cc5c95 --- /dev/null +++ b/DuetPkg/PcRtc/RealTimeClock.c @@ -0,0 +1,1065 @@ +/*++ + +Copyright (c) 2005 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PcRtc.c + +Abstract: + + RTC Architectural Protocol GUID as defined in EFI 2.0 + +--*/ + +#include "RealTimeClock.h" + +BOOLEAN +DayValid ( + IN EFI_TIME *Time + ); + +BOOLEAN +IsLeapYear ( + IN EFI_TIME *Time + ); + +BOOLEAN +IsWithinOneDay ( + IN EFI_TIME *From, + IN EFI_TIME *To + ); + +INTN +CompareHMS ( + IN EFI_TIME *From, + IN EFI_TIME *To + ); + +UINT8 +RtcRead ( + IN UINT8 Address + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Address - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80))); + return IoRead8 (PCAT_RTC_DATA_REGISTER); +} + +INTN +CompareHMS ( + IN EFI_TIME *From, + IN EFI_TIME *To + ) +/*++ + +Routine Description: + + Compare the Hour, Minute and Second of the 'From' time and the 'To' time. + Only compare H/M/S in EFI_TIME and ignore other fields here. + +Arguments: + + From - the first time + To - the second time + +Returns: + + >0 : The H/M/S of the 'From' time is later than those of 'To' time + ==0 : The H/M/S of the 'From' time is same as those of 'To' time + <0 : The H/M/S of the 'From' time is earlier than those of 'To' time + +--*/ + +{ + if ((From->Hour > To->Hour) || + ((From->Hour == To->Hour) && (From->Minute > To->Minute)) || + ((From->Hour == To->Hour) && (From->Minute == To->Minute) && (From->Second > To->Second))) { + return 1; + } else if ((From->Hour == To->Hour) && (From->Minute == To->Minute) && (From->Second == To->Second)) { + return 0; + } else { + return -1; + } +} + +VOID +RtcWrite ( + IN UINT8 Address, + IN UINT8 Data + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Address - TODO: add argument description + Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80))); + IoWrite8 (PCAT_RTC_DATA_REGISTER, Data); +} + +EFI_STATUS +PcRtcInit ( + IN PC_RTC_MODULE_GLOBALS *Global + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Global - TODO: add argument description + +Returns: + + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + EFI_STATUS Status; + RTC_REGISTER_A RegisterA; + RTC_REGISTER_B RegisterB; + RTC_REGISTER_C RegisterC; + RTC_REGISTER_D RegisterD; + UINT8 Century; + EFI_TIME Time; + + // + // Acquire RTC Lock to make access to RTC atomic + // + EfiAcquireLock (&Global->RtcLock); + + // + // Initialize RTC Register + // + // Make sure Division Chain is properly configured, + // or RTC clock won't "tick" -- time won't increment + // + RegisterA.Data = RTC_INIT_REGISTER_A; + RtcWrite (RTC_ADDRESS_REGISTER_A, RegisterA.Data); + + // + // Read Register B + // + RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); + + // + // Clear RTC flag register + // + RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C); + + // + // Clear RTC register D + // + RegisterD.Data = RTC_INIT_REGISTER_D; + RtcWrite (RTC_ADDRESS_REGISTER_D, RegisterD.Data); + + // + // Wait for up to 0.1 seconds for the RTC to be updated + // + Status = RtcWaitToUpdate (100000); + if (EFI_ERROR (Status)) { + EfiReleaseLock (&Global->RtcLock); + return EFI_DEVICE_ERROR; + } + // + // Get the Time/Date/Daylight Savings values. + // + Time.Second = RtcRead (RTC_ADDRESS_SECONDS); + Time.Minute = RtcRead (RTC_ADDRESS_MINUTES); + Time.Hour = RtcRead (RTC_ADDRESS_HOURS); + Time.Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH); + Time.Month = RtcRead (RTC_ADDRESS_MONTH); + Time.Year = RtcRead (RTC_ADDRESS_YEAR); + + ConvertRtcTimeToEfiTime (&Time, RegisterB); + + if (RtcTestCenturyRegister () == EFI_SUCCESS) { + Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f)); + } else { + Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY)); + } + + Time.Year = (UINT16) (Century * 100 + Time.Year); + + // + // Set RTC configuration after get original time + // + RtcWrite (RTC_ADDRESS_REGISTER_B, RTC_INIT_REGISTER_B); + + // + // Release RTC Lock. + // + EfiReleaseLock (&Global->RtcLock); + + // + // Validate time fields + // + Status = RtcTimeFieldsValid (&Time); + if (EFI_ERROR (Status)) { + Time.Second = RTC_INIT_SECOND; + Time.Minute = RTC_INIT_MINUTE; + Time.Hour = RTC_INIT_HOUR; + Time.Day = RTC_INIT_DAY; + Time.Month = RTC_INIT_MONTH; + Time.Year = RTC_INIT_YEAR; + } + // + // Reset time value according to new RTC configuration + // + PcRtcSetTime (&Time, Global); + + return EFI_SUCCESS; +} + +EFI_STATUS +PcRtcGetTime ( + OUT EFI_TIME *Time, + IN EFI_TIME_CAPABILITIES *Capabilities, + IN PC_RTC_MODULE_GLOBALS *Global + ) +/*++ + +Routine Description: + + Arguments: + + Returns: +--*/ +// TODO: Time - add argument and description to function comment +// TODO: Capabilities - add argument and description to function comment +// TODO: Global - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + RTC_REGISTER_B RegisterB; + UINT8 Century; + UINTN BufferSize; + + // + // Check parameters for null pointer + // + if (Time == NULL) { + return EFI_INVALID_PARAMETER; + + } + // + // Acquire RTC Lock to make access to RTC atomic + // + EfiAcquireLock (&Global->RtcLock); + + // + // Wait for up to 0.1 seconds for the RTC to be updated + // + Status = RtcWaitToUpdate (100000); + if (EFI_ERROR (Status)) { + EfiReleaseLock (&Global->RtcLock); + return Status; + } + // + // Read Register B + // + RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); + + // + // Get the Time/Date/Daylight Savings values. + // + Time->Second = RtcRead (RTC_ADDRESS_SECONDS); + Time->Minute = RtcRead (RTC_ADDRESS_MINUTES); + Time->Hour = RtcRead (RTC_ADDRESS_HOURS); + Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH); + Time->Month = RtcRead (RTC_ADDRESS_MONTH); + Time->Year = RtcRead (RTC_ADDRESS_YEAR); + + ConvertRtcTimeToEfiTime (Time, RegisterB); + + if (RtcTestCenturyRegister () == EFI_SUCCESS) { + Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f)); + } else { + Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY)); + } + + Time->Year = (UINT16) (Century * 100 + Time->Year); + + // + // Release RTC Lock. + // + EfiReleaseLock (&Global->RtcLock); + + // + // Get the variable that containts the TimeZone and Daylight fields + // + Time->TimeZone = Global->SavedTimeZone; + Time->Daylight = Global->Daylight; + + BufferSize = sizeof (INT16) + sizeof (UINT8); + + // + // Make sure all field values are in correct range + // + Status = RtcTimeFieldsValid (Time); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // Fill in Capabilities if it was passed in + // + if (Capabilities) { + Capabilities->Resolution = 1; + // + // 1 hertz + // + Capabilities->Accuracy = 50000000; + // + // 50 ppm + // + Capabilities->SetsToZero = FALSE; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PcRtcSetTime ( + IN EFI_TIME *Time, + IN PC_RTC_MODULE_GLOBALS *Global + ) +/*++ + +Routine Description: + + Arguments: + + Returns: +--*/ +// TODO: Time - add argument and description to function comment +// TODO: Global - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + EFI_STATUS Status; + EFI_TIME RtcTime; + RTC_REGISTER_B RegisterB; + UINT8 Century; + + if (Time == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Make sure that the time fields are valid + // + Status = RtcTimeFieldsValid (Time); + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem (&RtcTime, Time, sizeof (EFI_TIME)); + + // + // Acquire RTC Lock to make access to RTC atomic + // + EfiAcquireLock (&Global->RtcLock); + + // + // Wait for up to 0.1 seconds for the RTC to be updated + // + Status = RtcWaitToUpdate (100000); + if (EFI_ERROR (Status)) { + EfiReleaseLock (&Global->RtcLock); + return Status; + } + // + // Read Register B, and inhibit updates of the RTC + // + RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); + RegisterB.Bits.SET = 1; + RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); + + ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century); + + RtcWrite (RTC_ADDRESS_SECONDS, RtcTime.Second); + RtcWrite (RTC_ADDRESS_MINUTES, RtcTime.Minute); + RtcWrite (RTC_ADDRESS_HOURS, RtcTime.Hour); + RtcWrite (RTC_ADDRESS_DAY_OF_THE_MONTH, RtcTime.Day); + RtcWrite (RTC_ADDRESS_MONTH, RtcTime.Month); + RtcWrite (RTC_ADDRESS_YEAR, (UINT8) RtcTime.Year); + if (RtcTestCenturyRegister () == EFI_SUCCESS) { + Century = (UINT8) ((Century & 0x7f) | (RtcRead (RTC_ADDRESS_CENTURY) & 0x80)); + } + + RtcWrite (RTC_ADDRESS_CENTURY, Century); + + // + // Allow updates of the RTC registers + // + RegisterB.Bits.SET = 0; + RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); + + // + // Release RTC Lock. + // + EfiReleaseLock (&Global->RtcLock); + + // + // Set the variable that containts the TimeZone and Daylight fields + // + Global->SavedTimeZone = Time->TimeZone; + Global->Daylight = Time->Daylight; + return Status; +} + +EFI_STATUS +EFIAPI +PcRtcGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time, + IN PC_RTC_MODULE_GLOBALS *Global + ) +/*++ + +Routine Description: + + Arguments: + + + +Returns: +--*/ +// TODO: Enabled - add argument and description to function comment +// TODO: Pending - add argument and description to function comment +// TODO: Time - add argument and description to function comment +// TODO: Global - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + RTC_REGISTER_B RegisterB; + RTC_REGISTER_C RegisterC; + UINT8 Century; + + // + // Check paramters for null pointers + // + if ((Enabled == NULL) || (Pending == NULL) || (Time == NULL)) { + return EFI_INVALID_PARAMETER; + + } + // + // Acquire RTC Lock to make access to RTC atomic + // + EfiAcquireLock (&Global->RtcLock); + + // + // Wait for up to 0.1 seconds for the RTC to be updated + // + Status = RtcWaitToUpdate (100000); + if (EFI_ERROR (Status)) { + EfiReleaseLock (&Global->RtcLock); + return EFI_DEVICE_ERROR; + } + // + // Read Register B and Register C + // + RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); + RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C); + + // + // Get the Time/Date/Daylight Savings values. + // + *Enabled = RegisterB.Bits.AIE; + if (*Enabled) { + Time->Second = RtcRead (RTC_ADDRESS_SECONDS_ALARM); + Time->Minute = RtcRead (RTC_ADDRESS_MINUTES_ALARM); + Time->Hour = RtcRead (RTC_ADDRESS_HOURS_ALARM); + Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH); + Time->Month = RtcRead (RTC_ADDRESS_MONTH); + Time->Year = RtcRead (RTC_ADDRESS_YEAR); + } else { + Time->Second = 0; + Time->Minute = 0; + Time->Hour = 0; + Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH); + Time->Month = RtcRead (RTC_ADDRESS_MONTH); + Time->Year = RtcRead (RTC_ADDRESS_YEAR); + } + + ConvertRtcTimeToEfiTime (Time, RegisterB); + + if (RtcTestCenturyRegister () == EFI_SUCCESS) { + Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f)); + } else { + Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY)); + } + + Time->Year = (UINT16) (Century * 100 + Time->Year); + + // + // Release RTC Lock. + // + EfiReleaseLock (&Global->RtcLock); + + // + // Make sure all field values are in correct range + // + Status = RtcTimeFieldsValid (Time); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + *Pending = RegisterC.Bits.AF; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcRtcSetWakeupTime ( + IN BOOLEAN Enable, + OUT EFI_TIME *Time, + IN PC_RTC_MODULE_GLOBALS *Global + ) +/*++ + +Routine Description: + + Arguments: + + + +Returns: +--*/ +// TODO: Enable - add argument and description to function comment +// TODO: Time - add argument and description to function comment +// TODO: Global - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + EFI_TIME RtcTime; + RTC_REGISTER_B RegisterB; + UINT8 Century; + EFI_TIME_CAPABILITIES Capabilities; + + if (Enable) { + + if (Time == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Make sure that the time fields are valid + // + Status = RtcTimeFieldsValid (Time); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + // + // Just support set alarm time within 24 hours + // + PcRtcGetTime (&RtcTime, &Capabilities, Global); + if (!IsWithinOneDay (&RtcTime, Time)) { + return EFI_UNSUPPORTED; + } + // + // Make a local copy of the time and date + // + CopyMem (&RtcTime, Time, sizeof (EFI_TIME)); + + } + // + // Acquire RTC Lock to make access to RTC atomic + // + EfiAcquireLock (&Global->RtcLock); + + // + // Wait for up to 0.1 seconds for the RTC to be updated + // + Status = RtcWaitToUpdate (100000); + if (EFI_ERROR (Status)) { + EfiReleaseLock (&Global->RtcLock); + return EFI_DEVICE_ERROR; + } + // + // Read Register B, and inhibit updates of the RTC + // + RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); + + RegisterB.Bits.SET = 1; + RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); + + if (Enable) { + ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century); + + // + // Set RTC alarm time + // + RtcWrite (RTC_ADDRESS_SECONDS_ALARM, RtcTime.Second); + RtcWrite (RTC_ADDRESS_MINUTES_ALARM, RtcTime.Minute); + RtcWrite (RTC_ADDRESS_HOURS_ALARM, RtcTime.Hour); + + RegisterB.Bits.AIE = 1; + + } else { + RegisterB.Bits.AIE = 0; + } + // + // Allow updates of the RTC registers + // + RegisterB.Bits.SET = 0; + RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); + + // + // Release RTC Lock. + // + EfiReleaseLock (&Global->RtcLock); + + return EFI_SUCCESS; +} + +UINT8 +BcdToDecimal ( + IN UINT8 BcdValue + ) +/*++ + +Routine Description: + + Arguments: + + + +Returns: +--*/ +// TODO: BcdValue - add argument and description to function comment +{ + UINTN High; + UINTN Low; + + High = BcdValue >> 4; + Low = BcdValue - (High << 4); + + return (UINT8) (Low + (High * 10)); +} + +EFI_STATUS +RtcTestCenturyRegister ( + VOID + ) +/*++ + +Routine Description: + + Arguments: + + + +Returns: +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + UINT8 Century; + UINT8 Temp; + + Century = RtcRead (RTC_ADDRESS_CENTURY); + // + // RtcWrite (RTC_ADDRESS_CENTURY, 0x00); + // + Temp = (UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f); + RtcWrite (RTC_ADDRESS_CENTURY, Century); + if (Temp == 0x19 || Temp == 0x20) { + return EFI_SUCCESS; + } + + return EFI_DEVICE_ERROR; +} + +VOID +ConvertRtcTimeToEfiTime ( + IN EFI_TIME *Time, + IN RTC_REGISTER_B RegisterB + ) +/*++ + +Routine Description: + + Arguments: + + + +Returns: +--*/ +// TODO: Time - add argument and description to function comment +// TODO: RegisterB - add argument and description to function comment +{ + BOOLEAN PM; + + if ((Time->Hour) & 0x80) { + PM = TRUE; + } else { + PM = FALSE; + } + + Time->Hour = (UINT8) (Time->Hour & 0x7f); + + if (RegisterB.Bits.DM == 0) { + Time->Year = BcdToDecimal ((UINT8) Time->Year); + Time->Month = BcdToDecimal (Time->Month); + Time->Day = BcdToDecimal (Time->Day); + Time->Hour = BcdToDecimal (Time->Hour); + Time->Minute = BcdToDecimal (Time->Minute); + Time->Second = BcdToDecimal (Time->Second); + } + // + // If time is in 12 hour format, convert it to 24 hour format + // + if (RegisterB.Bits.MIL == 0) { + if (PM && Time->Hour < 12) { + Time->Hour = (UINT8) (Time->Hour + 12); + } + + if (!PM && Time->Hour == 12) { + Time->Hour = 0; + } + } + + Time->Nanosecond = 0; + Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE; + Time->Daylight = 0; +} + +EFI_STATUS +RtcWaitToUpdate ( + UINTN Timeout + ) +/*++ + +Routine Description: + + Arguments: + + +Returns: +--*/ +// TODO: Timeout - add argument and description to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + RTC_REGISTER_A RegisterA; + RTC_REGISTER_D RegisterD; + + // + // See if the RTC is functioning correctly + // + RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D); + + if (RegisterD.Bits.VRT == 0) { + return EFI_DEVICE_ERROR; + } + // + // Wait for up to 0.1 seconds for the RTC to be ready. + // + Timeout = (Timeout / 10) + 1; + RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A); + while (RegisterA.Bits.UIP == 1 && Timeout > 0) { + MicroSecondDelay (10); + RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A); + Timeout--; + } + + RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D); + if (Timeout == 0 || RegisterD.Bits.VRT == 0) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +RtcTimeFieldsValid ( + IN EFI_TIME *Time + ) +/*++ + +Routine Description: + + Arguments: + + Returns: +--*/ +// TODO: Time - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + if (Time->Year < 1998 || + Time->Year > 2099 || + Time->Month < 1 || + Time->Month > 12 || + (!DayValid (Time)) || + Time->Hour > 23 || + Time->Minute > 59 || + Time->Second > 59 || + Time->Nanosecond > 999999999 || + (!(Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE || (Time->TimeZone >= -1440 && Time->TimeZone <= 1440))) || + (Time->Daylight & (~(EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT))) + ) { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +BOOLEAN +DayValid ( + IN EFI_TIME *Time + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Time - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + + INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + if (Time->Day < 1 || + Time->Day > DayOfMonth[Time->Month - 1] || + (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28)) + ) { + return FALSE; + } + + return TRUE; +} + +BOOLEAN +IsLeapYear ( + IN EFI_TIME *Time + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Time - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + if (Time->Year % 4 == 0) { + if (Time->Year % 100 == 0) { + if (Time->Year % 400 == 0) { + return TRUE; + } else { + return FALSE; + } + } else { + return TRUE; + } + } else { + return FALSE; + } +} + +VOID +ConvertEfiTimeToRtcTime ( + IN EFI_TIME *Time, + IN RTC_REGISTER_B RegisterB, + IN UINT8 *Century + ) +/*++ + +Routine Description: + + Arguments: + + +Returns: +--*/ +// TODO: Time - add argument and description to function comment +// TODO: RegisterB - add argument and description to function comment +// TODO: Century - add argument and description to function comment +{ + BOOLEAN PM; + + PM = TRUE; + // + // Adjust hour field if RTC in in 12 hour mode + // + if (RegisterB.Bits.MIL == 0) { + if (Time->Hour < 12) { + PM = FALSE; + } + + if (Time->Hour >= 13) { + Time->Hour = (UINT8) (Time->Hour - 12); + } else if (Time->Hour == 0) { + Time->Hour = 12; + } + } + // + // Set the Time/Date/Daylight Savings values. + // + *Century = DecimaltoBcd ((UINT8) (Time->Year / 100)); + + Time->Year = (UINT16) (Time->Year % 100); + + if (RegisterB.Bits.DM == 0) { + Time->Year = DecimaltoBcd ((UINT8) Time->Year); + Time->Month = DecimaltoBcd (Time->Month); + Time->Day = DecimaltoBcd (Time->Day); + Time->Hour = DecimaltoBcd (Time->Hour); + Time->Minute = DecimaltoBcd (Time->Minute); + Time->Second = DecimaltoBcd (Time->Second); + } + // + // If we are in 12 hour mode and PM is set, then set bit 7 of the Hour field. + // + if (RegisterB.Bits.MIL == 0 && PM) { + Time->Hour = (UINT8) (Time->Hour | 0x80); + } +} + +BOOLEAN +IsWithinOneDay ( + IN EFI_TIME *From, + IN EFI_TIME *To + ) +/*++ + +Routine Description: + + Judge whether two days are adjacent. + +Arguments: + + From - the first day + To - the second day + +Returns: + + TRUE - The interval of two days are within one day. + FALSE - The interval of two days exceed ony day or parameter error. + +--*/ +{ + UINT8 DayOfMonth[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + BOOLEAN Adjacent = FALSE; + + if (From->Year == To->Year) { + if (From->Month == To->Month) { + if ((From->Day + 1) == To->Day) { + if ((CompareHMS(From, To) >= 0)) { + Adjacent = TRUE; + } + } else if (From->Day == To->Day) { + if ((CompareHMS(From, To) <= 0)) { + Adjacent = TRUE; + } + } + } else if (((From->Month + 1) == To->Month) && (To->Day == 1)) { + if ((From->Month == 2) && !IsLeapYear(From)) { + if (From->Day == 28) { + if ((CompareHMS(From, To) >= 0)) { + Adjacent = TRUE; + } + } + } else if (From->Day == DayOfMonth[From->Month - 1]) { + if ((CompareHMS(From, To) >= 0)) { + Adjacent = TRUE; + } + } + } + } else if (((From->Year + 1) == To->Year) && + (From->Month == 12) && + (From->Day == 31) && + (To->Month == 1) && + (To->Day == 1)) { + if ((CompareHMS(From, To) >= 0)) { + Adjacent = TRUE; + } + } + + return Adjacent; +} + +UINT8 +DecimaltoBcd ( + IN UINT8 DecValue + ) +/*++ + +Routine Description: + + Arguments: + +Returns: + +--*/ +// TODO: DecValue - add argument and description to function comment +{ + UINTN High; + UINTN Low; + + High = DecValue / 10; + Low = DecValue - (High * 10); + + return (UINT8) (Low + (High << 4)); +} diff --git a/DuetPkg/PcRtc/RealTimeClock.h b/DuetPkg/PcRtc/RealTimeClock.h new file mode 100644 index 0000000000..f157813cf7 --- /dev/null +++ b/DuetPkg/PcRtc/RealTimeClock.h @@ -0,0 +1,491 @@ +/*++ + +Copyright (c) 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PcRtc.h + +Abstract: + + Include for real time clock driver + +Revision History + + +--*/ + +#ifndef _RTC_H_ +#define _RTC_H_ + +#include + +#include + +#include +#include +#include +#include +#include + +typedef struct { + EFI_LOCK RtcLock; + UINT16 SavedTimeZone; + UINT8 Daylight; +} PC_RTC_MODULE_GLOBALS; + +#define PCAT_RTC_ADDRESS_REGISTER 0x70 +#define PCAT_RTC_DATA_REGISTER 0x71 + +// +// Dallas DS12C887 Real Time Clock +// +#define RTC_ADDRESS_SECONDS 0 // R/W Range 0..59 +#define RTC_ADDRESS_SECONDS_ALARM 1 // R/W Range 0..59 +#define RTC_ADDRESS_MINUTES 2 // R/W Range 0..59 +#define RTC_ADDRESS_MINUTES_ALARM 3 // R/W Range 0..59 +#define RTC_ADDRESS_HOURS 4 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM +#define RTC_ADDRESS_HOURS_ALARM 5 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM +#define RTC_ADDRESS_DAY_OF_THE_WEEK 6 // R/W Range 1..7 +#define RTC_ADDRESS_DAY_OF_THE_MONTH 7 // R/W Range 1..31 +#define RTC_ADDRESS_MONTH 8 // R/W Range 1..12 +#define RTC_ADDRESS_YEAR 9 // R/W Range 0..99 +#define RTC_ADDRESS_REGISTER_A 10 // R/W[0..6] R0[7] +#define RTC_ADDRESS_REGISTER_B 11 // R/W +#define RTC_ADDRESS_REGISTER_C 12 // RO +#define RTC_ADDRESS_REGISTER_D 13 // RO +#define RTC_ADDRESS_CENTURY 50 // R/W Range 19..20 Bit 8 is R/W +// +// Date and time initial values. +// They are used if the RTC values are invalid during driver initialization +// +#define RTC_INIT_SECOND 0 +#define RTC_INIT_MINUTE 0 +#define RTC_INIT_HOUR 0 +#define RTC_INIT_DAY 1 +#define RTC_INIT_MONTH 1 +#define RTC_INIT_YEAR 2001 + +// +// Register initial values +// +#define RTC_INIT_REGISTER_A 0x26 +#define RTC_INIT_REGISTER_B 0x02 +#define RTC_INIT_REGISTER_D 0x0 + +#pragma pack(1) +// +// Register A +// +typedef struct { + UINT8 RS : 4; // Rate Selection Bits + UINT8 DV : 3; // Divisor + UINT8 UIP : 1; // Update in progress +} RTC_REGISTER_A_BITS; + +typedef union { + RTC_REGISTER_A_BITS Bits; + UINT8 Data; +} RTC_REGISTER_A; + +// +// Register B +// +typedef struct { + UINT8 DSE : 1; // 0 - Daylight saving disabled 1 - Daylight savings enabled + UINT8 MIL : 1; // 0 - 12 hour mode 1 - 24 hour mode + UINT8 DM : 1; // 0 - BCD Format 1 - Binary Format + UINT8 SQWE : 1; // 0 - Disable SQWE output 1 - Enable SQWE output + UINT8 UIE : 1; // 0 - Update INT disabled 1 - Update INT enabled + UINT8 AIE : 1; // 0 - Alarm INT disabled 1 - Alarm INT Enabled + UINT8 PIE : 1; // 0 - Periodic INT disabled 1 - Periodic INT Enabled + UINT8 SET : 1; // 0 - Normal operation. 1 - Updates inhibited +} RTC_REGISTER_B_BITS; + +typedef union { + RTC_REGISTER_B_BITS Bits; + UINT8 Data; +} RTC_REGISTER_B; + +// +// Register C +// +typedef struct { + UINT8 Reserved : 4; // Read as zero. Can not be written. + UINT8 UF : 1; // Update End Interrupt Flag + UINT8 AF : 1; // Alarm Interrupt Flag + UINT8 PF : 1; // Periodic Interrupt Flag + UINT8 IRQF : 1; // Iterrupt Request Flag = PF & PIE | AF & AIE | UF & UIE +} RTC_REGISTER_C_BITS; + +typedef union { + RTC_REGISTER_C_BITS Bits; + UINT8 Data; +} RTC_REGISTER_C; + +// +// Register D +// +typedef struct { + UINT8 Reserved : 7; // Read as zero. Can not be written. + UINT8 VRT : 1; // Valid RAM and Time +} RTC_REGISTER_D_BITS; + +typedef union { + RTC_REGISTER_D_BITS Bits; + UINT8 Data; +} RTC_REGISTER_D; + +#pragma pack() + +EFI_STATUS +PcRtcInit ( + IN PC_RTC_MODULE_GLOBALS *Global + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Global - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PcRtcSetTime ( + IN EFI_TIME *Time, + IN PC_RTC_MODULE_GLOBALS *Global + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Time - TODO: add argument description + Global - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PcRtcGetTime ( + OUT EFI_TIME *Time, + IN EFI_TIME_CAPABILITIES *Capabilities, + IN PC_RTC_MODULE_GLOBALS *Global + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Time - TODO: add argument description + Capabilities - TODO: add argument description + Global - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +PcRtcSetWakeupTime ( + IN BOOLEAN Enable, + OUT EFI_TIME *Time, + IN PC_RTC_MODULE_GLOBALS *Global + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Enable - TODO: add argument description + Time - TODO: add argument description + Global - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +PcRtcGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time, + IN PC_RTC_MODULE_GLOBALS *Global + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Enabled - TODO: add argument description + Pending - TODO: add argument description + Time - TODO: add argument description + Global - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +InitializePcRtc ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageHandle - TODO: add argument description + SystemTable - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +UINT8 +BcdToDecimal ( + IN UINT8 BcdValue + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + BcdValue - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +RtcTimeFieldsValid ( + IN EFI_TIME *Time + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Time - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +UINT8 +DecimaltoBcd ( + IN UINT8 DecValue + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + DecValue - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +ConvertEfiTimeToRtcTime ( + IN EFI_TIME *Time, + IN RTC_REGISTER_B RegisterB, + IN UINT8 *Century + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Time - TODO: add argument description + RegisterB - TODO: add argument description + Century - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +RtcTestCenturyRegister ( + VOID + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + None + +Returns: + + TODO: add return values + +--*/ +; + +VOID +ConvertRtcTimeToEfiTime ( + IN EFI_TIME *Time, + IN RTC_REGISTER_B RegisterB + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Time - TODO: add argument description + RegisterB - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +RtcWaitToUpdate ( + UINTN Timeout + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Timeout - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +UINT8 +RtcSaveContext ( + IN PC_RTC_MODULE_GLOBALS *Global + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Global - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +RtcRestoreContext ( + IN UINT8 SavedAddressRegister, + IN PC_RTC_MODULE_GLOBALS *Global + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SavedAddressRegister - TODO: add argument description + Global - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/DuetPkg/PcRtc/RealTimeClock.inf b/DuetPkg/PcRtc/RealTimeClock.inf new file mode 100644 index 0000000000..0a9059422c --- /dev/null +++ b/DuetPkg/PcRtc/RealTimeClock.inf @@ -0,0 +1,63 @@ +#/*++ +# +# Copyright (c) 2005, Intel Corporation +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# Abstract: +# +#--*/ + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = RealTimeClock + FILE_GUID = 378D7B65-8DA9-4773-B6E4-A47826A833E1 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x00020000 + + ENTRY_POINT = InitializeRealTimeClock + +[Packages] + MdePkg/MdePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + DuetPkg/DuetPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiLib + IoLib + TimerLib + BaseMemoryLib + +[Sources.common] + RealTimeClock.c + RealTimeClock.h + +[Sources.ia32] + Ia32/RealTimeClock.c + +[Sources.x64] + x64/RealTimeClock.c + +[Sources.ipf] + Ipf/RealTimeClock.c + +[Protocols] + gEfiCpuArchProtocolGuid + gEfiMetronomeArchProtocolGuid + gEfiCpuIoProtocolGuid + gEfiRealTimeClockArchProtocolGuid + +[Depex] + gEfiCpuArchProtocolGuid AND gEfiMetronomeArchProtocolGuid AND gEfiCpuIoProtocolGuid \ No newline at end of file diff --git a/DuetPkg/PcRtc/x64/RealTimeClock.c b/DuetPkg/PcRtc/x64/RealTimeClock.c new file mode 100644 index 0000000000..4f4410eb21 --- /dev/null +++ b/DuetPkg/PcRtc/x64/RealTimeClock.c @@ -0,0 +1,170 @@ +/*++ + +Copyright (c) 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + x64PcRtc.c + +Abstract: + +--*/ + +#include "RealTimeClock.h" + +static PC_RTC_MODULE_GLOBALS mModuleGlobal; + +EFI_STATUS +EFIAPI +PcRtcEfiGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Time - TODO: add argument description + Capabilities - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + return PcRtcGetTime (Time, Capabilities, &mModuleGlobal); +} + +EFI_STATUS +EFIAPI +PcRtcEfiSetTime ( + IN EFI_TIME *Time + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Time - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + return PcRtcSetTime (Time, &mModuleGlobal); +} + +EFI_STATUS +EFIAPI +PcRtcEfiGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Enabled - TODO: add argument description + Pending - TODO: add argument description + Time - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + return PcRtcGetWakeupTime (Enabled, Pending, Time, &mModuleGlobal); +} + +EFI_STATUS +EFIAPI +PcRtcEfiSetWakeupTime ( + IN BOOLEAN Enabled, + OUT EFI_TIME *Time + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Enabled - TODO: add argument description + Time - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + return PcRtcSetWakeupTime (Enabled, Time, &mModuleGlobal); +} + +EFI_STATUS +EFIAPI +InitializeRealTimeClock ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Arguments: + + + +Returns: +--*/ +// TODO: ImageHandle - add argument and description to function comment +// TODO: SystemTable - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_HANDLE NewHandle; + + EfiInitializeLock (&mModuleGlobal.RtcLock, TPL_HIGH_LEVEL); + + Status = PcRtcInit (&mModuleGlobal); + if (EFI_ERROR (Status)) { + return Status; + } + + SystemTable->RuntimeServices->GetTime = PcRtcEfiGetTime; + SystemTable->RuntimeServices->SetTime = PcRtcEfiSetTime; + SystemTable->RuntimeServices->GetWakeupTime = PcRtcEfiGetWakeupTime; + SystemTable->RuntimeServices->SetWakeupTime = PcRtcEfiSetWakeupTime; + + NewHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &NewHandle, + &gEfiRealTimeClockArchProtocolGuid, + NULL, + NULL + ); + + return Status; +} diff --git a/DuetPkg/PcRtc/x64RealTimeClock.dxs b/DuetPkg/PcRtc/x64RealTimeClock.dxs new file mode 100644 index 0000000000..3497da0635 --- /dev/null +++ b/DuetPkg/PcRtc/x64RealTimeClock.dxs @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + x64PcRtc.dxs + +Abstract: + Dependency expression source file. + +--*/ + + +#include "EfiDepex.h" + +#include EFI_ARCH_PROTOCOL_DEFINITION (Cpu) +#include EFI_ARCH_PROTOCOL_DEFINITION (Metronome) +#include EFI_PROTOCOL_DEFINITION (CpuIo) + +DEPENDENCY_START + EFI_CPU_ARCH_PROTOCOL_GUID AND EFI_METRONOME_ARCH_PROTOCOL_GUID AND EFI_CPU_IO_PROTOCOL_GUID +DEPENDENCY_END diff --git a/DuetPkg/PciRootBridgeNoEnumerationDxe/DeviceIo.c b/DuetPkg/PciRootBridgeNoEnumerationDxe/DeviceIo.c new file mode 100644 index 0000000000..286c03ef4c --- /dev/null +++ b/DuetPkg/PciRootBridgeNoEnumerationDxe/DeviceIo.c @@ -0,0 +1,845 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DeviceIo.c + +Abstract: + + EFI PC-AT PCI Device IO driver + +--*/ +#include "PcatPciRootBridge.h" +#include "DeviceIo.h" + +EFI_STATUS +DeviceIoConstructor ( + IN EFI_HANDLE Handle, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN UINT16 PrimaryBus, + IN UINT16 SubordinateBus + ) +/*++ + +Routine Description: + + Initialize and install a Device IO protocol on a empty device path handle. + +Arguments: + + Handle - Handle of PCI RootBridge IO instance + PciRootBridgeIo - PCI RootBridge IO instance + DevicePath - Device Path of PCI RootBridge IO instance + PrimaryBus - Primary Bus + SubordinateBus - Subordinate Bus + +Returns: + + EFI_SUCCESS - This driver is added to ControllerHandle. + EFI_ALREADY_STARTED - This driver is already running on ControllerHandle. + Others - This driver does not support this device. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + // + // Initialize the Device IO device instance. + // + Private = AllocateZeroPool (sizeof (DEVICE_IO_PRIVATE_DATA)); + if (Private == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Private->Signature = DEVICE_IO_PRIVATE_DATA_SIGNATURE; + Private->Handle = Handle; + Private->PciRootBridgeIo = PciRootBridgeIo; + Private->DevicePath = DevicePath; + Private->PrimaryBus = PrimaryBus; + Private->SubordinateBus = SubordinateBus; + + Private->DeviceIo.Mem.Read = DeviceIoMemRead; + Private->DeviceIo.Mem.Write = DeviceIoMemWrite; + Private->DeviceIo.Io.Read = DeviceIoIoRead; + Private->DeviceIo.Io.Write = DeviceIoIoWrite; + Private->DeviceIo.Pci.Read = DeviceIoPciRead; + Private->DeviceIo.Pci.Write = DeviceIoPciWrite; + Private->DeviceIo.PciDevicePath = DeviceIoPciDevicePath; + Private->DeviceIo.Map = DeviceIoMap; + Private->DeviceIo.Unmap = DeviceIoUnmap; + Private->DeviceIo.AllocateBuffer = DeviceIoAllocateBuffer; + Private->DeviceIo.Flush = DeviceIoFlush; + Private->DeviceIo.FreeBuffer = DeviceIoFreeBuffer; + + // + // Install protocol interfaces for the Device IO device. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Private->Handle, + &gEfiDeviceIoProtocolGuid, + &Private->DeviceIo, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +EFI_STATUS +EFIAPI +DeviceIoMemRead ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform reading memory mapped I/O space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The destination buffer to store results. + +Returns: + + EFI_SUCCESS - The data was read from the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + if (Width > MMIO_COPY_UINT64) { + return EFI_INVALID_PARAMETER; + } + if (Width >= MMIO_COPY_UINT8) { + Width = Width - MMIO_COPY_UINT8; + Status = Private->PciRootBridgeIo->CopyMem ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + (UINT64) Buffer, + Address, + Count + ); + } else { + Status = Private->PciRootBridgeIo->Mem.Read ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + Count, + Buffer + ); + } + + return Status; +} + + + +EFI_STATUS +EFIAPI +DeviceIoMemWrite ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform writing memory mapped I/O space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The source buffer of data to be written. + +Returns: + + EFI_SUCCESS - The data was written to the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + if (Width > MMIO_COPY_UINT64) { + return EFI_INVALID_PARAMETER; + } + if (Width >= MMIO_COPY_UINT8) { + Width = Width - MMIO_COPY_UINT8; + Status = Private->PciRootBridgeIo->CopyMem ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + (UINT64) Buffer, + Count + ); + } else { + Status = Private->PciRootBridgeIo->Mem.Write ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + Count, + Buffer + ); + } + + return Status; +} + +EFI_STATUS +EFIAPI +DeviceIoIoRead ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform reading I/O space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The destination buffer to store results. + +Returns: + + EFI_SUCCESS - The data was read from the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + if (Width >= MMIO_COPY_UINT8) { + return EFI_INVALID_PARAMETER; + } + + Status = Private->PciRootBridgeIo->Io.Read ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + Count, + Buffer + ); + + return Status; +} + +EFI_STATUS +EFIAPI +DeviceIoIoWrite ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform writing I/O space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The source buffer of data to be written. + +Returns: + + EFI_SUCCESS - The data was written to the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + if (Width >= MMIO_COPY_UINT8) { + return EFI_INVALID_PARAMETER; + } + + Status = Private->PciRootBridgeIo->Io.Write ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + Count, + Buffer + ); + + return Status; +} + +EFI_STATUS +EFIAPI +DeviceIoPciRead ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform reading PCI configuration space of device + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The destination buffer to store results. + +Returns: + + EFI_SUCCESS - The data was read from the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + if (Width < 0 || Width >= MMIO_COPY_UINT8) { + return EFI_INVALID_PARAMETER; + } + + Status = Private->PciRootBridgeIo->Pci.Read ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + Count, + Buffer + ); + + return Status; +} + +EFI_STATUS +EFIAPI +DeviceIoPciWrite ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform writing PCI configuration space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The source buffer of data to be written. + +Returns: + + EFI_SUCCESS - The data was written to the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + if (Width < 0 || Width >= MMIO_COPY_UINT8) { + return EFI_INVALID_PARAMETER; + } + + Status = Private->PciRootBridgeIo->Pci.Write ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + Count, + Buffer + ); + + return Status; +} + +EFI_DEVICE_PATH_PROTOCOL * +AppendPciDevicePath ( + IN DEVICE_IO_PRIVATE_DATA *Private, + IN UINT8 Bus, + IN UINT8 Device, + IN UINT8 Function, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN OUT UINT16 *BridgePrimaryBus, + IN OUT UINT16 *BridgeSubordinateBus + ) +/*++ + +Routine Description: + + Append a PCI device path node to another device path. + +Arguments: + + Private - A pointer to DEVICE_IO_PRIVATE_DATA instance. + Bus - PCI bus number of the device. + Device - PCI device number of the device. + Function - PCI function number of the device. + DevicePath - Original device path which will be appended a PCI device path node. + BridgePrimaryBus - Primary bus number of the bridge. + BridgeSubordinateBus - Subordinate bus number of the bridge. + +Returns: + + Pointer to the appended PCI device path. + +--*/ +{ + UINT16 ThisBus; + UINT8 ThisDevice; + UINT8 ThisFunc; + UINT64 Address; + PCI_TYPE01 PciBridge; + PCI_TYPE01 *PciPtr; + EFI_DEVICE_PATH_PROTOCOL *ReturnDevicePath; + PCI_DEVICE_PATH PciNode; + + PciPtr = &PciBridge; + for (ThisBus = *BridgePrimaryBus; ThisBus <= *BridgeSubordinateBus; ThisBus++) { + for (ThisDevice = 0; ThisDevice <= PCI_MAX_DEVICE; ThisDevice++) { + for (ThisFunc = 0; ThisFunc <= PCI_MAX_FUNC; ThisFunc++) { + Address = EFI_PCI_ADDRESS (ThisBus, ThisDevice, ThisFunc, 0); + ZeroMem (PciPtr, sizeof (PCI_TYPE01)); + Private->DeviceIo.Pci.Read ( + &Private->DeviceIo, + IO_UINT32, + Address, + 1, + &(PciPtr->Hdr.VendorId) + ); + if ((PciPtr->Hdr.VendorId == 0xffff) && (ThisFunc == 0)) { + break; + } + if (PciPtr->Hdr.VendorId == 0xffff) { + continue; + } + + Private->DeviceIo.Pci.Read ( + &Private->DeviceIo, + IO_UINT32, + Address, + sizeof (PCI_TYPE01) / sizeof (UINT32), + PciPtr + ); + if (IS_PCI_BRIDGE (PciPtr)) { + if (Bus >= PciPtr->Bridge.SecondaryBus && Bus <= PciPtr->Bridge.SubordinateBus) { + + PciNode.Header.Type = HARDWARE_DEVICE_PATH; + PciNode.Header.SubType = HW_PCI_DP; + SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode)); + + PciNode.Device = ThisDevice; + PciNode.Function = ThisFunc; + ReturnDevicePath = AppendDevicePathNode (DevicePath, &PciNode.Header); + + *BridgePrimaryBus = PciPtr->Bridge.SecondaryBus; + *BridgeSubordinateBus = PciPtr->Bridge.SubordinateBus; + return ReturnDevicePath; + } + } + + if ((ThisFunc == 0) && ((PciPtr->Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x0)) { + // + // Skip sub functions, this is not a multi function device + // + break; + } + } + } + } + + ZeroMem (&PciNode, sizeof (PciNode)); + PciNode.Header.Type = HARDWARE_DEVICE_PATH; + PciNode.Header.SubType = HW_PCI_DP; + SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode)); + PciNode.Device = Device; + PciNode.Function = Function; + + ReturnDevicePath = AppendDevicePathNode (DevicePath, &PciNode.Header); + + *BridgePrimaryBus = 0xffff; + *BridgeSubordinateBus = 0xffff; + return ReturnDevicePath; +} + +EFI_STATUS +EFIAPI +DeviceIoPciDevicePath ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN UINT64 Address, + IN OUT EFI_DEVICE_PATH_PROTOCOL **PciDevicePath + ) +/*++ + +Routine Description: + + Provides an EFI Device Path for a PCI device with the given PCI configuration space address. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Address - The PCI configuration space address of the device whose Device Path + is going to be returned. + PciDevicePath - A pointer to the pointer for the EFI Device Path for PciAddress. + Memory for the Device Path is allocated from the pool. + +Returns: + + EFI_SUCCESS - The PciDevicePath returns a pointer to a valid EFI Device Path. + EFI_UNSUPPORTED - The PciAddress does not map to a valid EFI Device Path. + EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources. + +--*/ +{ + DEVICE_IO_PRIVATE_DATA *Private; + UINT16 PrimaryBus; + UINT16 SubordinateBus; + UINT8 Bus; + UINT8 Device; + UINT8 Func; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + Bus = (UINT8) (((UINT32) Address >> 24) & 0xff); + Device = (UINT8) (((UINT32) Address >> 16) & 0xff); + Func = (UINT8) (((UINT32) Address >> 8) & 0xff); + + if (Bus < Private->PrimaryBus || Bus > Private->SubordinateBus) { + return EFI_UNSUPPORTED; + } + + *PciDevicePath = Private->DevicePath; + PrimaryBus = Private->PrimaryBus; + SubordinateBus = Private->SubordinateBus; + do { + *PciDevicePath = AppendPciDevicePath ( + Private, + Bus, + Device, + Func, + *PciDevicePath, + &PrimaryBus, + &SubordinateBus + ); + if (*PciDevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } while (PrimaryBus != 0xffff); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DeviceIoMap ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_OPERATION_TYPE Operation, + IN EFI_PHYSICAL_ADDRESS *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +/*++ + +Routine Description: + + Provides the device-specific addresses needed to access system memory. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Operation - Indicates if the bus master is going to read or write to system memory. + HostAddress - The system memory address to map to the device. + NumberOfBytes - On input the number of bytes to map. On output the number of bytes + that were mapped. + DeviceAddress - The resulting map address for the bus master device to use to access the + hosts HostAddress. + Mapping - A resulting value to pass to Unmap(). + +Returns: + + EFI_SUCCESS - The range was mapped for the returned NumberOfBytes. + EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined. + EFI_UNSUPPORTED - The HostAddress cannot be mapped as a common buffer. + EFI_DEVICE_ERROR - The system hardware could not map the requested address. + EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + if (Operation < 0 || Operation > EfiBusMasterCommonBuffer) { + return EFI_INVALID_PARAMETER; + } + + if (((UINTN) (*HostAddress) != (*HostAddress)) && Operation == EfiBusMasterCommonBuffer) { + return EFI_UNSUPPORTED; + } + + Status = Private->PciRootBridgeIo->Map ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) Operation, + (VOID *) (UINTN) (*HostAddress), + NumberOfBytes, + DeviceAddress, + Mapping + ); + + return Status; +} + +EFI_STATUS +EFIAPI +DeviceIoUnmap ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN VOID *Mapping + ) +/*++ + +Routine Description: + + Completes the Map() operation and releases any corresponding resources. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Mapping - The mapping value returned from Map(). + +Returns: + + EFI_SUCCESS - The range was unmapped. + EFI_DEVICE_ERROR - The data was not committed to the target system memory. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + Status = Private->PciRootBridgeIo->Unmap ( + Private->PciRootBridgeIo, + Mapping + ); + + return Status; +} + +EFI_STATUS +EFIAPI +DeviceIoAllocateBuffer ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN OUT EFI_PHYSICAL_ADDRESS *PhysicalAddress + ) +/*++ + +Routine Description: + + Allocates pages that are suitable for an EFIBusMasterCommonBuffer mapping. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Type - The type allocation to perform. + MemoryType - The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + Pages - The number of pages to allocate. + PhysicalAddress - A pointer to store the base address of the allocated range. + +Returns: + + EFI_SUCCESS - The requested memory pages were allocated. + EFI_OUT_OF_RESOURCES - The memory pages could not be allocated. + EFI_INVALID_PARAMETER - The requested memory type is invalid. + EFI_UNSUPPORTED - The requested PhysicalAddress is not supported on + this platform. + +--*/ +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS HostAddress; + + HostAddress = *PhysicalAddress; + + if ((MemoryType != EfiBootServicesData) && (MemoryType != EfiRuntimeServicesData)) { + return EFI_INVALID_PARAMETER; + } + + if ((Type >= MaxAllocateType) || (Type < AllocateAnyPages)) { + return EFI_INVALID_PARAMETER; + } + + if ((Type == AllocateAddress) && (HostAddress + EFI_PAGES_TO_SIZE (Pages) - 1 > MAX_COMMON_BUFFER)) { + return EFI_UNSUPPORTED; + } + + if ((AllocateAnyPages == Type) || (AllocateMaxAddress == Type && HostAddress > MAX_COMMON_BUFFER)) { + Type = AllocateMaxAddress; + HostAddress = MAX_COMMON_BUFFER; + } + + Status = gBS->AllocatePages ( + Type, + MemoryType, + Pages, + &HostAddress + ); + if (EFI_ERROR (Status)) { + return Status; + } + + + *PhysicalAddress = HostAddress; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DeviceIoFlush ( + IN EFI_DEVICE_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + + Flushes any posted write data to the device. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + +Returns: + + EFI_SUCCESS - The buffers were flushed. + EFI_DEVICE_ERROR - The buffers were not flushed due to a hardware error. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + Status = Private->PciRootBridgeIo->Flush (Private->PciRootBridgeIo); + + return Status; +} + +EFI_STATUS +EFIAPI +DeviceIoFreeBuffer ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN UINTN Pages, + IN EFI_PHYSICAL_ADDRESS HostAddress + ) +/*++ + +Routine Description: + + Frees pages that were allocated with AllocateBuffer(). + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Pages - The number of pages to free. + HostAddress - The base address of the range to free. + +Returns: + + EFI_SUCCESS - The requested memory pages were freed. + EFI_NOT_FOUND - The requested memory pages were not allocated with + AllocateBuffer(). + EFI_INVALID_PARAMETER - HostAddress is not page aligned or Pages is invalid. + +--*/ +{ + if (((HostAddress & EFI_PAGE_MASK) != 0) || (Pages <= 0)) { + return EFI_INVALID_PARAMETER; + } + + return gBS->FreePages (HostAddress, Pages); +} diff --git a/DuetPkg/PciRootBridgeNoEnumerationDxe/DeviceIo.h b/DuetPkg/PciRootBridgeNoEnumerationDxe/DeviceIo.h new file mode 100644 index 0000000000..71d3a41e28 --- /dev/null +++ b/DuetPkg/PciRootBridgeNoEnumerationDxe/DeviceIo.h @@ -0,0 +1,449 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DeviceIo.h + +Abstract: + + Private Data definition for Device IO driver + +--*/ + +#ifndef _DEVICE_IO_H +#define _DEVICE_IO_H + + + +#define DEVICE_IO_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('d', 'e', 'v', 'I') + +#define MAX_COMMON_BUFFER 0x00000000FFFFFFFF + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + EFI_DEVICE_IO_PROTOCOL DeviceIo; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINT16 PrimaryBus; + UINT16 SubordinateBus; +} DEVICE_IO_PRIVATE_DATA; + +#define DEVICE_IO_PRIVATE_DATA_FROM_THIS(a) CR (a, DEVICE_IO_PRIVATE_DATA, DeviceIo, DEVICE_IO_PRIVATE_DATA_SIGNATURE) + +EFI_STATUS +DeviceIoConstructor ( + IN EFI_HANDLE Handle, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN UINT16 PrimaryBus, + IN UINT16 SubordinateBus + ) +/*++ + +Routine Description: + + Initialize and install a Device IO protocol on a empty device path handle. + +Arguments: + + Handle - Handle of PCI RootBridge IO instance + PciRootBridgeIo - PCI RootBridge IO instance + DevicePath - Device Path of PCI RootBridge IO instance + PrimaryBus - Primary Bus + SubordinateBus - Subordinate Bus + +Returns: + + EFI_SUCCESS - This driver is added to ControllerHandle. + EFI_ALREADY_STARTED - This driver is already running on ControllerHandle. + Others - This driver does not support this device. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoMemRead ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform reading memory mapped I/O space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The destination buffer to store results. + +Returns: + + EFI_SUCCESS - The data was read from the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoMemWrite ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform writing memory mapped I/O space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The source buffer of data to be written. + +Returns: + + EFI_SUCCESS - The data was written to the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoIoRead ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform reading I/O space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The destination buffer to store results. + +Returns: + + EFI_SUCCESS - The data was read from the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoIoWrite ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform writing I/O space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The source buffer of data to be written. + +Returns: + + EFI_SUCCESS - The data was written to the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoPciRead ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform reading PCI configuration space of device + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The destination buffer to store results. + +Returns: + + EFI_SUCCESS - The data was read from the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoPciWrite ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform writing PCI configuration space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The source buffer of data to be written. + +Returns: + + EFI_SUCCESS - The data was written to the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoPciDevicePath ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN UINT64 Address, + IN OUT EFI_DEVICE_PATH_PROTOCOL **PciDevicePath + ) +/*++ + +Routine Description: + + Append a PCI device path node to another device path. + +Arguments: + + This - A pointer to EFI_DEVICE_IO_PROTOCOL. + Address - PCI bus,device, function. + PciDevicePath - PCI device path. + +Returns: + + Pointer to the appended PCI device path. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoMap ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_OPERATION_TYPE Operation, + IN EFI_PHYSICAL_ADDRESS *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +/*++ + +Routine Description: + + Provides the device-specific addresses needed to access system memory. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Operation - Indicates if the bus master is going to read or write to system memory. + HostAddress - The system memory address to map to the device. + NumberOfBytes - On input the number of bytes to map. On output the number of bytes + that were mapped. + DeviceAddress - The resulting map address for the bus master device to use to access the + hosts HostAddress. + Mapping - A resulting value to pass to Unmap(). + +Returns: + + EFI_SUCCESS - The range was mapped for the returned NumberOfBytes. + EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined. + EFI_UNSUPPORTED - The HostAddress cannot be mapped as a common buffer. + EFI_DEVICE_ERROR - The system hardware could not map the requested address. + EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoUnmap ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN VOID *Mapping + ) +/*++ + +Routine Description: + + Completes the Map() operation and releases any corresponding resources. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Mapping - The mapping value returned from Map(). + +Returns: + + EFI_SUCCESS - The range was unmapped. + EFI_DEVICE_ERROR - The data was not committed to the target system memory. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoAllocateBuffer ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN OUT EFI_PHYSICAL_ADDRESS *HostAddress + ) +/*++ + +Routine Description: + + Allocates pages that are suitable for an EFIBusMasterCommonBuffer mapping. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Type - The type allocation to perform. + MemoryType - The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + Pages - The number of pages to allocate. + HostAddress - A pointer to store the base address of the allocated range. + +Returns: + + EFI_SUCCESS - The requested memory pages were allocated. + EFI_OUT_OF_RESOURCES - The memory pages could not be allocated. + EFI_INVALID_PARAMETER - The requested memory type is invalid. + EFI_UNSUPPORTED - The requested PhysicalAddress is not supported on + this platform. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoFlush ( + IN EFI_DEVICE_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + + Flushes any posted write data to the device. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + +Returns: + + EFI_SUCCESS - The buffers were flushed. + EFI_DEVICE_ERROR - The buffers were not flushed due to a hardware error. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoFreeBuffer ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN UINTN Pages, + IN EFI_PHYSICAL_ADDRESS HostAddress + ) +/*++ + +Routine Description: + + Frees pages that were allocated with AllocateBuffer(). + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Pages - The number of pages to free. + HostAddress - The base address of the range to free. + +Returns: + + EFI_SUCCESS - The requested memory pages were freed. + EFI_NOT_FOUND - The requested memory pages were not allocated with + AllocateBuffer(). + EFI_INVALID_PARAMETER - HostAddress is not page aligned or Pages is invalid. + +--*/ +; + +#endif + diff --git a/DuetPkg/PciRootBridgeNoEnumerationDxe/Ia32/PcatIo.c b/DuetPkg/PciRootBridgeNoEnumerationDxe/Ia32/PcatIo.c new file mode 100644 index 0000000000..0cbf047254 --- /dev/null +++ b/DuetPkg/PciRootBridgeNoEnumerationDxe/Ia32/PcatIo.c @@ -0,0 +1,734 @@ +/*++ + +Copyright (c) 2005 - 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PcatPciRootBridgeIo.c + +Abstract: + + EFI PC AT PCI Root Bridge Io Protocol + +Revision History + +--*/ + +#include "PcatPciRootBridge.h" + +static BOOLEAN mPciOptionRomTableInstalled = FALSE; +static EFI_PCI_OPTION_ROM_TABLE mPciOptionRomTable = {0, NULL}; + +EFI_STATUS +EFIAPI +PcatRootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + return gCpuIo->Io.Read ( + gCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) Width, + UserAddress, + Count, + UserBuffer + ); +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + return gCpuIo->Io.Write ( + gCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) Width, + UserAddress, + Count, + UserBuffer + ); + +} + +EFI_STATUS +PcatRootBridgeIoGetIoPortMapping ( + OUT EFI_PHYSICAL_ADDRESS *IoPortMapping, + OUT EFI_PHYSICAL_ADDRESS *MemoryPortMapping + ) +/*++ + + Get the IO Port Mapping. For IA-32 it is always 0. + +--*/ +{ + *IoPortMapping = 0; + *MemoryPortMapping = 0; + + return EFI_SUCCESS; +} + +EFI_STATUS +PcatRootBridgeIoPciRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN BOOLEAN Write, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + PCI_CONFIG_ACCESS_CF8 Pci; + PCI_CONFIG_ACCESS_CF8 PciAligned; + UINT32 InStride; + UINT32 OutStride; + UINTN PciData; + UINTN PciDataStride; + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress; + UINT64 PciExpressRegAddr; + BOOLEAN UsePciExpressAccess; + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + if ((Width & 0x03) >= EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + InStride = 1 << (Width & 0x03); + OutStride = InStride; + if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) { + InStride = 0; + } + + if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) { + OutStride = 0; + } + + UsePciExpressAccess = FALSE; + + CopyMem (&PciAddress, &UserAddress, sizeof(UINT64)); + + if (PciAddress.ExtendedRegister > 0xFF) { + // + // Check PciExpressBaseAddress + // + if ((PrivateData->PciExpressBaseAddress == 0) || + (PrivateData->PciExpressBaseAddress >= EFI_MAX_ADDRESS)) { + return EFI_UNSUPPORTED; + } else { + UsePciExpressAccess = TRUE; + } + } else { + if (PciAddress.ExtendedRegister != 0) { + Pci.Bits.Reg = PciAddress.ExtendedRegister & 0xFF; + } else { + Pci.Bits.Reg = PciAddress.Register; + } + // + // Note: We can also use PciExpress access here, if wanted. + // + } + + if (!UsePciExpressAccess) { + Pci.Bits.Func = PciAddress.Function; + Pci.Bits.Dev = PciAddress.Device; + Pci.Bits.Bus = PciAddress.Bus; + Pci.Bits.Reserved = 0; + Pci.Bits.Enable = 1; + + // + // PCI Config access are all 32-bit alligned, but by accessing the + // CONFIG_DATA_REGISTER (0xcfc) with different widths more cycle types + // are possible on PCI. + // + // To read a byte of PCI config space you load 0xcf8 and + // read 0xcfc, 0xcfd, 0xcfe, 0xcff + // + PciDataStride = Pci.Bits.Reg & 0x03; + + while (Count) { + PciAligned = Pci; + PciAligned.Bits.Reg &= 0xfc; + PciData = (UINTN)PrivateData->PciData + PciDataStride; + EfiAcquireLock(&PrivateData->PciLock); + This->Io.Write (This, EfiPciWidthUint32, PrivateData->PciAddress, 1, &PciAligned); + if (Write) { + This->Io.Write (This, Width, PciData, 1, UserBuffer); + } else { + This->Io.Read (This, Width, PciData, 1, UserBuffer); + } + EfiReleaseLock(&PrivateData->PciLock); + UserBuffer = ((UINT8 *)UserBuffer) + OutStride; + PciDataStride = (PciDataStride + InStride) % 4; + Pci.Bits.Reg += InStride; + Count -= 1; + } + } else { + // + // Access PCI-Express space by using memory mapped method. + // + PciExpressRegAddr = (PrivateData->PciExpressBaseAddress) | + (PciAddress.Bus << 20) | + (PciAddress.Device << 15) | + (PciAddress.Function << 12); + if (PciAddress.ExtendedRegister != 0) { + PciExpressRegAddr += PciAddress.ExtendedRegister; + } else { + PciExpressRegAddr += PciAddress.Register; + } + while (Count) { + if (Write) { + This->Mem.Write (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer); + } else { + This->Mem.Read (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer); + } + + UserBuffer = ((UINT8 *) UserBuffer) + OutStride; + PciExpressRegAddr += InStride; + Count -= 1; + } + } + + return EFI_SUCCESS; +} + +static +VOID +ScanPciBus( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + EFI_PCI_BUS_SCAN_CALLBACK Callback, + VOID *Context + ) + +{ + UINT16 Bus; + UINT16 Device; + UINT16 Func; + UINT64 Address; + PCI_TYPE00 PciHeader; + + // + // Loop through all busses + // + for (Bus = MinBus; Bus <= MaxBus; Bus++) { + // + // Loop 32 devices per bus + // + for (Device = MinDevice; Device <= MaxDevice; Device++) { + // + // Loop through 8 functions per device + // + for (Func = MinFunc; Func <= MaxFunc; Func++) { + + // + // Compute the EFI Address required to access the PCI Configuration Header of this PCI Device + // + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); + + // + // Read the VendorID from this PCI Device's Confioguration Header + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &PciHeader.Hdr.VendorId); + + // + // If VendorId = 0xffff, there does not exist a device at this + // location. For each device, if there is any function on it, + // there must be 1 function at Function 0. So if Func = 0, there + // will be no more functions in the same device, so we can break + // loop to deal with the next device. + // + if (PciHeader.Hdr.VendorId == 0xffff && Func == 0) { + break; + } + + if (PciHeader.Hdr.VendorId != 0xffff) { + + // + // Read the HeaderType to determine if this is a multi-function device + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint8, Address + 0x0e, 1, &PciHeader.Hdr.HeaderType); + + // + // Call the callback function for the device that was found + // + Callback( + IoDev, + MinBus, MaxBus, + MinDevice, MaxDevice, + MinFunc, MaxFunc, + Bus, + Device, + Func, + Context + ); + + // + // If this is not a multi-function device, we can leave the loop + // to deal with the next device. + // + if ((PciHeader.Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00 && Func == 0) { + break; + } + } + } + } + } +} + +static +VOID +CheckForRom ( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + UINT16 Bus, + UINT16 Device, + UINT16 Func, + IN VOID *VoidContext + ) +{ + EFI_STATUS Status; + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; + UINT64 Address; + PCI_TYPE00 PciHeader; + PCI_TYPE01 *PciBridgeHeader; + UINT32 Register; + UINT32 RomBar; + UINT32 RomBarSize; + EFI_PHYSICAL_ADDRESS RomBuffer; + UINT32 MaxRomSize; + EFI_PCI_EXPANSION_ROM_HEADER EfiRomHeader; + PCI_DATA_STRUCTURE Pcir; + EFI_PCI_OPTION_ROM_DESCRIPTOR *TempPciOptionRomDescriptors; + BOOLEAN LastImage; + + Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; + + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); + + // + // Save the contents of the PCI Configuration Header + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader); + + if (IS_PCI_BRIDGE(&PciHeader)) { + + PciBridgeHeader = (PCI_TYPE01 *)(&PciHeader); + + // + // See if the PCI-PCI Bridge has its secondary interface enabled. + // + if (PciBridgeHeader->Bridge.SubordinateBus >= PciBridgeHeader->Bridge.SecondaryBus) { + + // + // Disable the Prefetchable Memory Window + // + Register = 0x00000000; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x26, 1, &Register); + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x2c, 1, &Register); + Register = 0xffffffff; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x24, 1, &Register); + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x28, 1, &Register); + + // + // Program Memory Window to the PCI Root Bridge Memory Window + // + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x20, 4, &Context->PpbMemoryWindow); + + // + // Enable the Memory decode for the PCI-PCI Bridge + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + Register |= 0x02; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + + // + // Recurse on the Secondary Bus Number + // + ScanPciBus( + IoDev, + PciBridgeHeader->Bridge.SecondaryBus, PciBridgeHeader->Bridge.SecondaryBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + CheckForRom, Context + ); + } + } else { + + // + // Check if an Option ROM Register is present and save the Option ROM Window Register + // + RomBar = 0xffffffff; + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + + RomBarSize = (~(RomBar & 0xfffff800)) + 1; + + // + // Make sure the size of the ROM is between 0 and 16 MB + // + if (RomBarSize > 0 && RomBarSize <= 0x01000000) { + + // + // Program Option ROM Window Register to the PCI Root Bridge Window and Enable the Option ROM Window + // + RomBar = (Context->PpbMemoryWindow & 0xffff) << 16; + RomBar = ((RomBar - 1) & (~(RomBarSize - 1))) + RomBarSize; + if (RomBar < (Context->PpbMemoryWindow & 0xffff0000)) { + MaxRomSize = (Context->PpbMemoryWindow & 0xffff0000) - RomBar; + RomBar = RomBar + 1; + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + RomBar = RomBar - 1; + + // + // Enable the Memory decode for the PCI Device + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + Register |= 0x02; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + + // + // Follow the chain of images to determine the size of the Option ROM present + // Keep going until the last image is found by looking at the Indicator field + // or the size of an image is 0, or the size of all the images is bigger than the + // size of the window programmed into the PPB. + // + RomBarSize = 0; + do { + + LastImage = TRUE; + + ZeroMem (&EfiRomHeader, sizeof(EfiRomHeader)); + IoDev->Mem.Read ( + IoDev, + EfiPciWidthUint8, + RomBar + RomBarSize, + sizeof(EfiRomHeader), + &EfiRomHeader + ); + + Pcir.ImageLength = 0; + + if (EfiRomHeader.Signature == 0xaa55) { + + ZeroMem (&Pcir, sizeof(Pcir)); + IoDev->Mem.Read ( + IoDev, + EfiPciWidthUint8, + RomBar + RomBarSize + EfiRomHeader.PcirOffset, + sizeof(Pcir), + &Pcir + ); + + if ((Pcir.Indicator & 0x80) == 0x00) { + LastImage = FALSE; + } + + RomBarSize += Pcir.ImageLength * 512; + } + } while (!LastImage && RomBarSize < MaxRomSize && Pcir.ImageLength !=0); + + if (RomBarSize > 0) { + + // + // Allocate a memory buffer for the Option ROM contents. + // + Status = gBS->AllocatePages( + AllocateAnyPages, + EfiBootServicesData, + EFI_SIZE_TO_PAGES(RomBarSize), + &RomBuffer + ); + + if (!EFI_ERROR (Status)) { + + // + // Copy the contents of the Option ROM to the memory buffer + // + IoDev->Mem.Read (IoDev, EfiPciWidthUint32, RomBar, RomBarSize / sizeof(UINT32), (VOID *)(UINTN)RomBuffer); + + Status = gBS->AllocatePool( + EfiBootServicesData, + ((UINT32)mPciOptionRomTable.PciOptionRomCount + 1) * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR), + &TempPciOptionRomDescriptors + ); + if (mPciOptionRomTable.PciOptionRomCount > 0) { + CopyMem( + TempPciOptionRomDescriptors, + mPciOptionRomTable.PciOptionRomDescriptors, + (UINT32)mPciOptionRomTable.PciOptionRomCount * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR) + ); + + gBS->FreePool(mPciOptionRomTable.PciOptionRomDescriptors); + } + + mPciOptionRomTable.PciOptionRomDescriptors = TempPciOptionRomDescriptors; + + TempPciOptionRomDescriptors = &(mPciOptionRomTable.PciOptionRomDescriptors[(UINT32)mPciOptionRomTable.PciOptionRomCount]); + + TempPciOptionRomDescriptors->RomAddress = RomBuffer; + TempPciOptionRomDescriptors->MemoryType = EfiBootServicesData; + TempPciOptionRomDescriptors->RomLength = RomBarSize; + TempPciOptionRomDescriptors->Seg = (UINT32)IoDev->SegmentNumber; + TempPciOptionRomDescriptors->Bus = (UINT8)Bus; + TempPciOptionRomDescriptors->Dev = (UINT8)Device; + TempPciOptionRomDescriptors->Func = (UINT8)Func; + TempPciOptionRomDescriptors->ExecutedLegacyBiosImage = TRUE; + TempPciOptionRomDescriptors->DontLoadEfiRom = FALSE; + + mPciOptionRomTable.PciOptionRomCount++; + } + } + + // + // Disable the Memory decode for the PCI-PCI Bridge + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + Register &= (~0x02); + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + } + } + } + + // + // Restore the PCI Configuration Header + // + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader); +} + +static +VOID +SaveCommandRegister ( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + UINT16 Bus, + UINT16 Device, + UINT16 Func, + IN VOID *VoidContext + ) + +{ + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; + UINT64 Address; + UINTN Index; + UINT16 Command; + + Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; + + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4); + + Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func; + + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]); + + // + // Clear the memory enable bit + // + Command = Context->CommandRegisterBuffer[Index] & (~0x02); + + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Command); +} + +static +VOID +RestoreCommandRegister ( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + UINT16 Bus, + UINT16 Device, + UINT16 Func, + IN VOID *VoidContext + ) + +{ + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; + UINT64 Address; + UINTN Index; + + Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; + + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4); + + Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func; + + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]); +} + +EFI_STATUS +ScanPciRootBridgeForRoms( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev + ) + +{ + EFI_STATUS Status; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; + UINT16 MinBus; + UINT16 MaxBus; + UINT64 RootWindowBase; + UINT64 RootWindowLimit; + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT Context; + + if (mPciOptionRomTableInstalled == FALSE) { + gBS->InstallConfigurationTable(&gEfiPciOptionRomTableGuid, &mPciOptionRomTable); + mPciOptionRomTableInstalled = TRUE; + } + + Status = IoDev->Configuration(IoDev, &Descriptors); + if (EFI_ERROR (Status) || Descriptors == NULL) { + return EFI_NOT_FOUND; + } + + MinBus = 0xffff; + MaxBus = 0xffff; + RootWindowBase = 0; + RootWindowLimit = 0; + while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) { + // + // Find bus range + // + if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) { + MinBus = (UINT16)Descriptors->AddrRangeMin; + MaxBus = (UINT16)Descriptors->AddrRangeMax; + } + // + // Find memory descriptors that are not prefetchable + // + if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM && Descriptors->SpecificFlag == 0) { + // + // Find Memory Descriptors that are less than 4GB, so the PPB Memory Window can be used for downstream devices + // + if (Descriptors->AddrRangeMax < 0x100000000) { + // + // Find the largest Non-Prefetchable Memory Descriptor that is less than 4GB + // + if ((Descriptors->AddrRangeMax - Descriptors->AddrRangeMin) > (RootWindowLimit - RootWindowBase)) { + RootWindowBase = Descriptors->AddrRangeMin; + RootWindowLimit = Descriptors->AddrRangeMax; + } + } + } + Descriptors ++; + } + + // + // Make sure a bus range was found + // + if (MinBus == 0xffff || MaxBus == 0xffff) { + return EFI_NOT_FOUND; + } + + // + // Make sure a non-prefetchable memory region was found + // + if (RootWindowBase == 0 && RootWindowLimit == 0) { + return EFI_NOT_FOUND; + } + + // + // Round the Base and Limit values to 1 MB boudaries + // + RootWindowBase = ((RootWindowBase - 1) & 0xfff00000) + 0x00100000; + RootWindowLimit = ((RootWindowLimit + 1) & 0xfff00000) - 1; + + // + // Make sure that the size of the rounded window is greater than zero + // + if (RootWindowLimit <= RootWindowBase) { + return EFI_NOT_FOUND; + } + + // + // Allocate buffer to save the Command register from all the PCI devices + // + Context.CommandRegisterBuffer = NULL; + Status = gBS->AllocatePool( + EfiBootServicesData, + sizeof(UINT16) * (MaxBus - MinBus + 1) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1), + &Context.CommandRegisterBuffer + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Context.PpbMemoryWindow = (((UINT32)RootWindowBase) >> 16) | ((UINT32)RootWindowLimit & 0xffff0000); + + // + // Save the Command register from all the PCI devices, and disable the I/O, Mem, and BusMaster bits + // + ScanPciBus( + IoDev, + MinBus, MaxBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + SaveCommandRegister, &Context + ); + + // + // Recursively scan all the busses for PCI Option ROMs + // + ScanPciBus( + IoDev, + MinBus, MinBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + CheckForRom, &Context + ); + + // + // Restore the Command register in all the PCI devices + // + ScanPciBus( + IoDev, + MinBus, MaxBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + RestoreCommandRegister, &Context + ); + + // + // Free the buffer used to save all the Command register values + // + gBS->FreePool(Context.CommandRegisterBuffer); + + return EFI_SUCCESS; +} diff --git a/DuetPkg/PciRootBridgeNoEnumerationDxe/Ipf/PcatIo.c b/DuetPkg/PciRootBridgeNoEnumerationDxe/Ipf/PcatIo.c new file mode 100644 index 0000000000..9979d47c4e --- /dev/null +++ b/DuetPkg/PciRootBridgeNoEnumerationDxe/Ipf/PcatIo.c @@ -0,0 +1,459 @@ +/*++ + +Copyright (c) 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PcatPciRootBridgeIo.c + +Abstract: + + EFI PC AT PCI Root Bridge Io Protocol + +Revision History + +--*/ + +#include "PcatPciRootBridge.h" +#include "pci22.h" +#include "SalProc.h" + +#include EFI_GUID_DEFINITION (SalSystemTable) + +// +// Might be good to put this in an include file, but people may start +// using it! They should always access the EFI abstraction that is +// contained in this file. Just a little information hiding. +// +#define PORT_TO_MEM(_Port) ( ((_Port) & 0xffffffffffff0000) | (((_Port) & 0xfffc) << 10) | ((_Port) & 0x0fff) ) + +// +// Macro's with casts make this much easier to use and read. +// +#define PORT_TO_MEM8(_Port) (*(UINT8 *)(PORT_TO_MEM(_Port))) +#define PORT_TO_MEM16(_Port) (*(UINT16 *)(PORT_TO_MEM(_Port))) +#define PORT_TO_MEM32(_Port) (*(UINT32 *)(PORT_TO_MEM(_Port))) + +#define EFI_PCI_ADDRESS_IA64(_seg, _bus,_dev,_func,_reg) \ + ( (UINT64) ( (((UINTN)_seg) << 24) + (((UINTN)_bus) << 16) + (((UINTN)_dev) << 11) + (((UINTN)_func) << 8) + ((UINTN)_reg)) ) + +// +// Local variables for performing SAL Proc calls +// +static PLABEL mSalProcPlabel; +static CALL_SAL_PROC mGlobalSalProc; + +EFI_STATUS +PcatRootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + UINTN InStride; + UINTN OutStride; + UINTN AlignMask; + UINTN Address; + PTR Buffer; + UINT16 Data16; + UINT32 Data32; + + + if ( UserBuffer == NULL ) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + Address = (UINTN) UserAddress; + Buffer.buf = (UINT8 *)UserBuffer; + + if ( Address < PrivateData->IoBase || Address > PrivateData->IoLimit ) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + if ((Width & 0x03) == EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if ( Address & AlignMask ) { + return EFI_INVALID_PARAMETER; + } + + InStride = 1 << (Width & 0x03); + OutStride = InStride; + if (Width >=EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + InStride = 0; + } + if (Width >=EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { + OutStride = 0; + } + Width = Width & 0x03; + + Address += PrivateData->PhysicalIoBase; + + // + // Loop for each iteration and move the data + // + + switch (Width) { + case EfiPciWidthUint8: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + MEMORY_FENCE(); + *Buffer.ui8 = PORT_TO_MEM8(Address); + MEMORY_FENCE(); + } + break; + + case EfiPciWidthUint16: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + MEMORY_FENCE(); + if (Buffer.ui & 0x1) { + Data16 = PORT_TO_MEM16(Address); + *Buffer.ui8 = (UINT8)(Data16 & 0xff); + *(Buffer.ui8+1) = (UINT8)((Data16 >> 8) & 0xff); + } else { + *Buffer.ui16 = PORT_TO_MEM16(Address); + } + MEMORY_FENCE(); + } + break; + + case EfiPciWidthUint32: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + MEMORY_FENCE(); + if (Buffer.ui & 0x3) { + Data32 = PORT_TO_MEM32(Address); + *Buffer.ui8 = (UINT8)(Data32 & 0xff); + *(Buffer.ui8+1) = (UINT8)((Data32 >> 8) & 0xff); + *(Buffer.ui8+2) = (UINT8)((Data32 >> 16) & 0xff); + *(Buffer.ui8+3) = (UINT8)((Data32 >> 24) & 0xff); + } else { + *Buffer.ui32 = PORT_TO_MEM32(Address); + } + MEMORY_FENCE(); + } + break; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PcatRootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + UINTN InStride; + UINTN OutStride; + UINTN AlignMask; + UINTN Address; + PTR Buffer; + UINT16 Data16; + UINT32 Data32; + + if ( UserBuffer == NULL ) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + Address = (UINTN) UserAddress; + Buffer.buf = (UINT8 *)UserBuffer; + + if ( Address < PrivateData->IoBase || Address > PrivateData->IoLimit ) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + if ((Width & 0x03) == EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if ( Address & AlignMask ) { + return EFI_INVALID_PARAMETER; + } + + InStride = 1 << (Width & 0x03); + OutStride = InStride; + if (Width >=EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + InStride = 0; + } + if (Width >=EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { + OutStride = 0; + } + Width = Width & 0x03; + + Address += PrivateData->PhysicalIoBase; + + // + // Loop for each iteration and move the data + // + + switch (Width) { + case EfiPciWidthUint8: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + MEMORY_FENCE(); + PORT_TO_MEM8(Address) = *Buffer.ui8; + MEMORY_FENCE(); + } + break; + + case EfiPciWidthUint16: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + MEMORY_FENCE(); + if (Buffer.ui & 0x1) { + Data16 = *Buffer.ui8; + Data16 = Data16 | (*(Buffer.ui8+1) << 8); + PORT_TO_MEM16(Address) = Data16; + } else { + PORT_TO_MEM16(Address) = *Buffer.ui16; + } + MEMORY_FENCE(); + } + break; + case EfiPciWidthUint32: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + MEMORY_FENCE(); + if (Buffer.ui & 0x3) { + Data32 = *Buffer.ui8; + Data32 = Data32 | (*(Buffer.ui8+1) << 8); + Data32 = Data32 | (*(Buffer.ui8+2) << 16); + Data32 = Data32 | (*(Buffer.ui8+3) << 24); + PORT_TO_MEM32(Address) = Data32; + } else { + PORT_TO_MEM32(Address) = *Buffer.ui32; + } + MEMORY_FENCE(); + } + break; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PcatRootBridgeIoGetIoPortMapping ( + OUT EFI_PHYSICAL_ADDRESS *IoPortMapping, + OUT EFI_PHYSICAL_ADDRESS *MemoryPortMapping + ) +/*++ + + Get the IO Port Map from the SAL System Table. + +--*/ +{ + SAL_SYSTEM_TABLE_ASCENDING_ORDER *SalSystemTable; + SAL_ST_MEMORY_DESCRIPTOR_ENTRY *SalMemDesc; + EFI_STATUS Status; + + // + // On all Itanium architectures, bit 63 is the I/O bit for performming Memory Mapped I/O operations + // + *MemoryPortMapping = 0x8000000000000000; + + Status = EfiLibGetSystemConfigurationTable(&gEfiSalSystemTableGuid, &SalSystemTable); + if (EFI_ERROR(Status)) { + return EFI_NOT_FOUND; + } + + // + // BugBug: Add code to test checksum on the Sal System Table + // + if (SalSystemTable->Entry0.Type != 0) { + return EFI_UNSUPPORTED; + } + + mSalProcPlabel.ProcEntryPoint = SalSystemTable->Entry0.SalProcEntry; + mSalProcPlabel.GP = SalSystemTable->Entry0.GlobalDataPointer; + mGlobalSalProc = (CALL_SAL_PROC)&mSalProcPlabel.ProcEntryPoint; + + // + // The SalSystemTable pointer includes the Type 0 entry. + // The SalMemDesc is Type 1 so it comes next. + // + SalMemDesc = (SAL_ST_MEMORY_DESCRIPTOR_ENTRY *)(SalSystemTable + 1); + while (SalMemDesc->Type == SAL_ST_MEMORY_DESCRIPTOR) { + if (SalMemDesc->MemoryType == SAL_IO_PORT_MAPPING) { + *IoPortMapping = SalMemDesc->PhysicalMemoryAddress; + *IoPortMapping |= 0x8000000000000000; + return EFI_SUCCESS; + } + SalMemDesc++; + } + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PcatRootBridgeIoPciRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN BOOLEAN Write, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT UINT8 *UserBuffer + ) +{ + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + UINTN AlignMask; + UINTN InStride; + UINTN OutStride; + UINT64 Address; + DEFIO_PCI_ADDR *Defio; + PTR Buffer; + UINT32 Data32; + UINT16 Data16; + rArg Return; + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + if ((Width & 0x03) == EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if ( UserAddress & AlignMask ) { + return EFI_INVALID_PARAMETER; + } + + InStride = 1 << (Width & 0x03); + OutStride = InStride; + if (Width >=EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + InStride = 0; + } + if (Width >=EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { + OutStride = 0; + } + Width = Width & 0x03; + + Defio = (DEFIO_PCI_ADDR *)&UserAddress; + + if ((Defio->Function > PCI_MAX_FUNC) || (Defio->Device > PCI_MAX_DEVICE)) { + return EFI_UNSUPPORTED; + } + + Buffer.buf = (UINT8 *)UserBuffer; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + Address = EFI_PCI_ADDRESS_IA64( + This->SegmentNumber, + Defio->Bus, + Defio->Device, + Defio->Function, + Defio->Register + ); + + // + // PCI Config access are all 32-bit alligned, but by accessing the + // CONFIG_DATA_REGISTER (0xcfc) with different widths more cycle types + // are possible on PCI. + // + // SalProc takes care of reading the proper register depending on stride + // + + EfiAcquireLock(&PrivateData->PciLock); + + while (Count) { + + if(Write) { + + if (Buffer.ui & 0x3) { + Data32 = (*(Buffer.ui8+0) << 0); + Data32 |= (*(Buffer.ui8+1) << 8); + Data32 |= (*(Buffer.ui8+2) << 16); + Data32 |= (*(Buffer.ui8+3) << 24); + } else { + Data32 = *Buffer.ui32; + } + + Return.p0 = -3; + Return = mGlobalSalProc((UINT64) SAL_PCI_CONFIG_WRITE, + Address, 1 << Width, Data32, 0, 0, 0, 0); + + if(Return.p0) { + EfiReleaseLock(&PrivateData->PciLock); + return EFI_UNSUPPORTED; + } + + } else { + + Return.p0 = -3; + Return = mGlobalSalProc((UINT64) SAL_PCI_CONFIG_READ, + Address, 1 << Width, 0, 0, 0, 0, 0); + + if(Return.p0) { + EfiReleaseLock(&PrivateData->PciLock); + return EFI_UNSUPPORTED; + } + + switch (Width) { + case EfiPciWidthUint8: + *Buffer.ui8 = (UINT8)Return.p1; + break; + case EfiPciWidthUint16: + if (Buffer.ui & 0x1) { + Data16 = (UINT16)Return.p1; + *(Buffer.ui8 + 0) = Data16 & 0xff; + *(Buffer.ui8 + 1) = (Data16 >> 8) & 0xff; + } else { + *Buffer.ui16 = (UINT16)Return.p1; + } + break; + case EfiPciWidthUint32: + if (Buffer.ui & 0x3) { + Data32 = (UINT32)Return.p1; + *(Buffer.ui8 + 0) = (UINT8)(Data32 & 0xff); + *(Buffer.ui8 + 1) = (UINT8)((Data32 >> 8) & 0xff); + *(Buffer.ui8 + 2) = (UINT8)((Data32 >> 16) & 0xff); + *(Buffer.ui8 + 3) = (UINT8)((Data32 >> 24) & 0xff); + } else { + *Buffer.ui32 = (UINT32)Return.p1; + } + break; + } + } + + Address += InStride; + Buffer.buf += OutStride; + Count -= 1; + } + + EfiReleaseLock(&PrivateData->PciLock); + + return EFI_SUCCESS; +} + +EFI_STATUS +ScanPciRootBridgeForRoms( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev + ) + +{ + return EFI_UNSUPPORTED; +} diff --git a/DuetPkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridge.c b/DuetPkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridge.c new file mode 100644 index 0000000000..ff53bb5c78 --- /dev/null +++ b/DuetPkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridge.c @@ -0,0 +1,1018 @@ +/*++ + +Copyright (c) 2005 - 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PcatPciRootBridge.c + +Abstract: + + EFI PC-AT PCI Root Bridge Controller + +--*/ + +#include "PcatPciRootBridge.h" +#include "DeviceIo.h" + +EFI_CPU_IO_PROTOCOL *gCpuIo; + +EFI_STATUS +EFIAPI +InitializePcatPciRootBridge ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + Initializes the PCI Root Bridge Controller + +Arguments: + ImageHandle - + SystemTable - + +Returns: + None + +--*/ +{ + EFI_STATUS Status; + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + UINTN PciSegmentIndex; + UINTN PciRootBridgeIndex; + UINTN PrimaryBusIndex; + UINTN NumberOfPciRootBridges; + UINTN NumberOfPciDevices; + UINTN Device; + UINTN Function; + UINT16 VendorId; + PCI_TYPE01 PciConfigurationHeader; + UINT64 Address; + UINT64 Value; + UINT64 Base; + UINT64 Limit; + + // + // Initialize gCpuIo now since the chipset init code requires it. + // + Status = gBS->LocateProtocol (&gEfiCpuIoProtocolGuid, NULL, &gCpuIo); + ASSERT_EFI_ERROR (Status); + + // + // Initialize variables required to search all PCI segments for PCI devices + // + PciSegmentIndex = 0; + PciRootBridgeIndex = 0; + NumberOfPciRootBridges = 0; + PrimaryBusIndex = 0; + + while (PciSegmentIndex <= PCI_MAX_SEGMENT) { + + PrivateData = NULL; + Status = gBS->AllocatePool( + EfiBootServicesData, + sizeof (PCAT_PCI_ROOT_BRIDGE_INSTANCE), + &PrivateData + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + ZeroMem (PrivateData, sizeof (PCAT_PCI_ROOT_BRIDGE_INSTANCE)); + + // + // Initialize the signature of the private data structure + // + PrivateData->Signature = PCAT_PCI_ROOT_BRIDGE_SIGNATURE; + PrivateData->Handle = NULL; + PrivateData->DevicePath = NULL; + InitializeListHead (&PrivateData->MapInfo); + + // + // Initialize the PCI root bridge number and the bus range for that root bridge + // + PrivateData->RootBridgeNumber = (UINT32)PciRootBridgeIndex; + PrivateData->PrimaryBus = (UINT32)PrimaryBusIndex; + PrivateData->SubordinateBus = (UINT32)PrimaryBusIndex; + + PrivateData->IoBase = 0xffffffff; + PrivateData->MemBase = 0xffffffff; + PrivateData->Mem32Base = 0xffffffffffffffff; + PrivateData->Pmem32Base = 0xffffffffffffffff; + PrivateData->Mem64Base = 0xffffffffffffffff; + PrivateData->Pmem64Base = 0xffffffffffffffff; + + // + // The default mechanism for performing PCI Configuration cycles is to + // use the I/O ports at 0xCF8 and 0xCFC. This is only used for IA-32. + // IPF uses SAL calls to perform PCI COnfiguration cycles + // + PrivateData->PciAddress = 0xCF8; + PrivateData->PciData = 0xCFC; + + // + // Get the physical I/O base for performing PCI I/O cycles + // For IA-32, this is always 0, because IA-32 has IN and OUT instructions + // For IPF, a SAL call is made to retrieve the base address for PCI I/O cycles + // + Status = PcatRootBridgeIoGetIoPortMapping ( + &PrivateData->PhysicalIoBase, + &PrivateData->PhysicalMemoryBase + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Get PCI Express Base Address + // + PrivateData->PciExpressBaseAddress = GetPciExpressBaseAddressForRootBridge (PciSegmentIndex, PciRootBridgeIndex); + if (PrivateData->PciExpressBaseAddress != 0) { + DEBUG ((EFI_D_ERROR, "PCIE Base - 0x%lx\n", PrivateData->PciExpressBaseAddress)); + } + + // + // Create a lock for performing PCI Configuration cycles + // + EfiInitializeLock (&PrivateData->PciLock, TPL_HIGH_LEVEL); + + // + // Initialize the attributes for this PCI root bridge + // + PrivateData->Attributes = 0; + + // + // Build the EFI Device Path Protocol instance for this PCI Root Bridge + // + Status = PcatRootBridgeDevicePathConstructor (&PrivateData->DevicePath, PciRootBridgeIndex, (PrivateData->PciExpressBaseAddress != 0) ? TRUE : FALSE); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Build the PCI Root Bridge I/O Protocol instance for this PCI Root Bridge + // + Status = PcatRootBridgeIoConstructor (&PrivateData->Io, PciSegmentIndex); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Scan all the PCI devices on the primary bus of the PCI root bridge + // + for (Device = 0, NumberOfPciDevices = 0; Device <= PCI_MAX_DEVICE; Device++) { + + for (Function = 0; Function <= PCI_MAX_FUNC; Function++) { + + // + // Compute the PCI configuration address of the PCI device to probe + // + Address = EFI_PCI_ADDRESS (PrimaryBusIndex, Device, Function, 0); + + // + // Read the Vendor ID from the PCI Configuration Header + // + Status = PrivateData->Io.Pci.Read ( + &PrivateData->Io, + EfiPciWidthUint16, + Address, + sizeof (VendorId), + &VendorId + ); + if ((EFI_ERROR (Status)) || ((VendorId == 0xffff) && (Function == 0))) { + // + // If the PCI Configuration Read fails, or a PCI device does not exist, then + // skip this entire PCI device + // + break; + } + if (VendorId == 0xffff) { + // + // If PCI function != 0, VendorId == 0xFFFF, we continue to search PCI function. + // + continue; + } + + // + // Read the entire PCI Configuration Header + // + Status = PrivateData->Io.Pci.Read ( + &PrivateData->Io, + EfiPciWidthUint32, + Address, + sizeof (PciConfigurationHeader) / sizeof (UINT32), + &PciConfigurationHeader + ); + if (EFI_ERROR (Status)) { + // + // If the entire PCI Configuration Header can not be read, then skip this entire PCI device + // + break; + } + + // + // Increment the number of PCI device found on the primary bus of the PCI root bridge + // + NumberOfPciDevices++; + + // + // Look for devices with the VGA Palette Snoop enabled in the COMMAND register of the PCI Config Header + // + if (PciConfigurationHeader.Hdr.Command & 0x20) { + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; + } + + // + // If the device is a PCI-PCI Bridge, then look at the Subordinate Bus Number + // + if (IS_PCI_BRIDGE(&PciConfigurationHeader)) { + // + // Get the Bus range that the PPB is decoding + // + if (PciConfigurationHeader.Bridge.SubordinateBus > PrivateData->SubordinateBus) { + // + // If the suborinate bus number of the PCI-PCI bridge is greater than the PCI root bridge's + // current subordinate bus number, then update the PCI root bridge's subordinate bus number + // + PrivateData->SubordinateBus = PciConfigurationHeader.Bridge.SubordinateBus; + } + + // + // Get the I/O range that the PPB is decoding + // + Value = PciConfigurationHeader.Bridge.IoBase & 0x0f; + Base = ((UINT32)PciConfigurationHeader.Bridge.IoBase & 0xf0) << 8; + Limit = (((UINT32)PciConfigurationHeader.Bridge.IoLimit & 0xf0) << 8) | 0x0fff; + if (Value == 0x01) { + Base |= ((UINT32)PciConfigurationHeader.Bridge.IoBaseUpper16 << 16); + Limit |= ((UINT32)PciConfigurationHeader.Bridge.IoLimitUpper16 << 16); + } + if (Base < Limit) { + if (PrivateData->IoBase > Base) { + PrivateData->IoBase = Base; + } + if (PrivateData->IoLimit < Limit) { + PrivateData->IoLimit = Limit; + } + } + + // + // Get the Memory range that the PPB is decoding + // + Base = ((UINT32)PciConfigurationHeader.Bridge.MemoryBase & 0xfff0) << 16; + Limit = (((UINT32)PciConfigurationHeader.Bridge.MemoryLimit & 0xfff0) << 16) | 0xfffff; + if (Base < Limit) { + if (PrivateData->MemBase > Base) { + PrivateData->MemBase = Base; + } + if (PrivateData->MemLimit < Limit) { + PrivateData->MemLimit = Limit; + } + if (PrivateData->Mem32Base > Base) { + PrivateData->Mem32Base = Base; + } + if (PrivateData->Mem32Limit < Limit) { + PrivateData->Mem32Limit = Limit; + } + } + + // + // Get the Prefetchable Memory range that the PPB is decoding + // + Value = PciConfigurationHeader.Bridge.PrefetchableMemoryBase & 0x0f; + Base = ((UINT32)PciConfigurationHeader.Bridge.PrefetchableMemoryBase & 0xfff0) << 16; + Limit = (((UINT32)PciConfigurationHeader.Bridge.PrefetchableMemoryLimit & 0xfff0) << 16) | 0xffffff; + if (Value == 0x01) { + Base |= LShiftU64((UINT64)PciConfigurationHeader.Bridge.PrefetchableBaseUpper32,32); + Limit |= LShiftU64((UINT64)PciConfigurationHeader.Bridge.PrefetchableLimitUpper32,32); + } + if (Base < Limit) { + if (PrivateData->MemBase > Base) { + PrivateData->MemBase = Base; + } + if (PrivateData->MemLimit < Limit) { + PrivateData->MemLimit = Limit; + } + if (Value == 0x00) { + if (PrivateData->Pmem32Base > Base) { + PrivateData->Pmem32Base = Base; + } + if (PrivateData->Pmem32Limit < Limit) { + PrivateData->Pmem32Limit = Limit; + } + } + if (Value == 0x01) { + if (PrivateData->Pmem64Base > Base) { + PrivateData->Pmem64Base = Base; + } + if (PrivateData->Pmem64Limit < Limit) { + PrivateData->Pmem64Limit = Limit; + } + } + } + + // + // Look at the PPB Configuration for legacy decoding attributes + // + if (PciConfigurationHeader.Bridge.BridgeControl & 0x04) { + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO; + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO; + } + if (PciConfigurationHeader.Bridge.BridgeControl & 0x08) { + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY; + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO; + } + + } else { + // + // Parse the BARs of the PCI device to determine what I/O Ranges, + // Memory Ranges, and Prefetchable Memory Ranges the device is decoding + // + if ((PciConfigurationHeader.Hdr.HeaderType & HEADER_LAYOUT_CODE) == HEADER_TYPE_DEVICE) { + Status = PcatPciRootBridgeParseBars ( + PrivateData, + PciConfigurationHeader.Hdr.Command, + PrimaryBusIndex, + Device, + Function + ); + } + + // + // See if the PCI device is an IDE controller + // + if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x01 && + PciConfigurationHeader.Hdr.ClassCode[1] == 0x01 ) { + if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x80) { + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO; + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO; + } + if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x01) { + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO; + } + if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x04) { + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO; + } + } + + // + // See if the PCI device is a legacy VGA controller + // + if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x00 && + PciConfigurationHeader.Hdr.ClassCode[1] == 0x01 ) { + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY; + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO; + } + + // + // See if the PCI device is a standard VGA controller + // + if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x03 && + PciConfigurationHeader.Hdr.ClassCode[1] == 0x00 ) { + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY; + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO; + } + + // + // See if the PCI Device is a PCI - ISA or PCI - EISA + // or ISA_POSITIVIE_DECODE Bridge device + // + if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x06) { + if (PciConfigurationHeader.Hdr.ClassCode[1] == 0x01 || + PciConfigurationHeader.Hdr.ClassCode[1] == 0x02 || + PciConfigurationHeader.Hdr.ClassCode[1] == 0x80 ) { + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO; + PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO; + + if (PrivateData->MemBase > 0xa0000) { + PrivateData->MemBase = 0xa0000; + } + if (PrivateData->MemLimit < 0xbffff) { + PrivateData->MemLimit = 0xbffff; + } + } + } + } + + // + // If this device is not a multi function device, then skip the rest of this PCI device + // + if (Function == 0 && !(PciConfigurationHeader.Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION)) { + break; + } + } + } + + // + // After scanning all the PCI devices on the PCI root bridge's primary bus, update the + // Primary Bus Number for the next PCI root bridge to be this PCI root bridge's subordinate + // bus number + 1. + // + PrimaryBusIndex = PrivateData->SubordinateBus + 1; + + // + // If at least one PCI device was found on the primary bus of this PCI root bridge, then the PCI root bridge + // exists. + // + if (NumberOfPciDevices > 0) { + + // + // Adjust the I/O range used for bounds checking for the legacy decoding attributed + // + if (PrivateData->Attributes & 0x7f) { + PrivateData->IoBase = 0; + if (PrivateData->IoLimit < 0xffff) { + PrivateData->IoLimit = 0xffff; + } + } + + // + // Adjust the Memory range used for bounds checking for the legacy decoding attributed + // + if (PrivateData->Attributes & EFI_PCI_ATTRIBUTE_VGA_MEMORY) { + if (PrivateData->MemBase > 0xa0000) { + PrivateData->MemBase = 0xa0000; + } + if (PrivateData->MemLimit < 0xbffff) { + PrivateData->MemLimit = 0xbffff; + } + } + + // + // Build ACPI descriptors for the resources on the PCI Root Bridge + // + Status = ConstructConfiguration(PrivateData); + ASSERT_EFI_ERROR (Status); + + // + // Create the handle for this PCI Root Bridge + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &PrivateData->Handle, + &gEfiDevicePathProtocolGuid, + PrivateData->DevicePath, + &gEfiPciRootBridgeIoProtocolGuid, + &PrivateData->Io, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Contruct DeviceIoProtocol + // + Status = DeviceIoConstructor ( + PrivateData->Handle, + &PrivateData->Io, + PrivateData->DevicePath, + (UINT16)PrivateData->PrimaryBus, + (UINT16)PrivateData->SubordinateBus + ); + ASSERT_EFI_ERROR (Status); + + // + // Scan this PCI Root Bridge for PCI Option ROMs and add them to the PCI Option ROM Table + // + Status = ScanPciRootBridgeForRoms(&PrivateData->Io); + + // + // Increment the index for the next PCI Root Bridge + // + PciRootBridgeIndex++; + + } else { + + // + // If no PCI Root Bridges were found on the current PCI segment, then exit + // + if (NumberOfPciRootBridges == 0) { + Status = EFI_SUCCESS; + goto Done; + } + + } + + // + // If the PrimaryBusIndex is greater than the maximum allowable PCI bus number, then + // the PCI Segment Number is incremented, and the next segment is searched starting at Bus #0 + // Otherwise, the search is continued on the next PCI Root Bridge + // + if (PrimaryBusIndex > PCI_MAX_BUS) { + PciSegmentIndex++; + NumberOfPciRootBridges = 0; + PrimaryBusIndex = 0; + } else { + NumberOfPciRootBridges++; + } + + } + + return EFI_SUCCESS; + +Done: + // + // Clean up memory allocated for the PCI Root Bridge that was searched but not created. + // + if (PrivateData) { + if (PrivateData->DevicePath) { + gBS->FreePool(PrivateData->DevicePath); + } + gBS->FreePool (PrivateData); + } + + // + // If no PCI Root Bridges were discovered, then return the error condition from scanning the + // first PCI Root Bridge + // + if (PciRootBridgeIndex == 0) { + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ConstructConfiguration( + IN OUT PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ + +{ + EFI_STATUS Status; + UINT8 NumConfig; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration; + EFI_ACPI_END_TAG_DESCRIPTOR *ConfigurationEnd; + + NumConfig = 0; + PrivateData->Configuration = NULL; + + if (PrivateData->SubordinateBus >= PrivateData->PrimaryBus) { + NumConfig++; + } + if (PrivateData->IoLimit >= PrivateData->IoBase) { + NumConfig++; + } + if (PrivateData->Mem32Limit >= PrivateData->Mem32Base) { + NumConfig++; + } + if (PrivateData->Pmem32Limit >= PrivateData->Pmem32Base) { + NumConfig++; + } + if (PrivateData->Mem64Limit >= PrivateData->Mem64Base) { + NumConfig++; + } + if (PrivateData->Pmem64Limit >= PrivateData->Pmem64Base) { + NumConfig++; + } + + if ( NumConfig == 0 ) { + + // + // If there is no resource request + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR), + &PrivateData->Configuration + ); + if (EFI_ERROR (Status )) { + return Status; + } + + Configuration = PrivateData->Configuration; + + ZeroMem ( + Configuration, + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR) + ); + + Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + Configuration++; + + ConfigurationEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *)(Configuration); + ConfigurationEnd->Desc = ACPI_END_TAG_DESCRIPTOR; + ConfigurationEnd->Checksum = 0; + } + + // + // If there is at least one type of resource request, + // allocate a acpi resource node + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR), + &PrivateData->Configuration + ); + if (EFI_ERROR (Status )) { + return Status; + } + + Configuration = PrivateData->Configuration; + + ZeroMem ( + Configuration, + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR) + ); + + if (PrivateData->SubordinateBus >= PrivateData->PrimaryBus) { + Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS; + Configuration->SpecificFlag = 0; + Configuration->AddrRangeMin = PrivateData->PrimaryBus; + Configuration->AddrRangeMax = PrivateData->SubordinateBus; + Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1; + Configuration++; + } + // + // Deal with io aperture + // + if (PrivateData->IoLimit >= PrivateData->IoBase) { + Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_IO; + Configuration->SpecificFlag = 1; //non ISA range + Configuration->AddrRangeMin = PrivateData->IoBase; + Configuration->AddrRangeMax = PrivateData->IoLimit; + Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1; + Configuration++; + } + + // + // Deal with mem32 aperture + // + if (PrivateData->Mem32Limit >= PrivateData->Mem32Base) { + Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + Configuration->SpecificFlag = 0; //Nonprefechable + Configuration->AddrSpaceGranularity = 32; //32 bit + Configuration->AddrRangeMin = PrivateData->Mem32Base; + Configuration->AddrRangeMax = PrivateData->Mem32Limit; + Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1; + Configuration++; + } + + // + // Deal with Pmem32 aperture + // + if (PrivateData->Pmem32Limit >= PrivateData->Pmem32Base) { + Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + Configuration->SpecificFlag = 0x6; //prefechable + Configuration->AddrSpaceGranularity = 32; //32 bit + Configuration->AddrRangeMin = PrivateData->Pmem32Base; + Configuration->AddrRangeMax = PrivateData->Pmem32Limit; + Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1; + Configuration++; + } + + // + // Deal with mem64 aperture + // + if (PrivateData->Mem64Limit >= PrivateData->Mem64Base) { + Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + Configuration->SpecificFlag = 0; //nonprefechable + Configuration->AddrSpaceGranularity = 64; //32 bit + Configuration->AddrRangeMin = PrivateData->Mem64Base; + Configuration->AddrRangeMax = PrivateData->Mem64Limit; + Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1; + Configuration++; + } + + // + // Deal with Pmem64 aperture + // + if (PrivateData->Pmem64Limit >= PrivateData->Pmem64Base) { + Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + Configuration->SpecificFlag = 0x06; //prefechable + Configuration->AddrSpaceGranularity = 64; //32 bit + Configuration->AddrRangeMin = PrivateData->Pmem64Base; + Configuration->AddrRangeMax = PrivateData->Pmem64Limit; + Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1; + Configuration++; + } + + // + // put the checksum + // + ConfigurationEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *)(Configuration); + ConfigurationEnd->Desc = ACPI_END_TAG_DESCRIPTOR; + ConfigurationEnd->Checksum = 0; + + return EFI_SUCCESS; +} + +EFI_STATUS +PcatPciRootBridgeBarExisted ( + IN PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData, + IN UINT64 Address, + OUT UINT32 *OriginalValue, + OUT UINT32 *Value + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + UINT32 AllOnes; + EFI_TPL OldTpl; + + // + // Preserve the original value + // + Status = PrivateData->Io.Pci.Read ( + &PrivateData->Io, + EfiPciWidthUint32, + Address, + 1, + OriginalValue + ); + + // + // Raise TPL to high level to disable timer interrupt while the BAR is probed + // + OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + + AllOnes = 0xffffffff; + + Status = PrivateData->Io.Pci.Write ( + &PrivateData->Io, + EfiPciWidthUint32, + Address, + 1, + &AllOnes + ); + Status = PrivateData->Io.Pci.Read ( + &PrivateData->Io, + EfiPciWidthUint32, + Address, + 1, + Value + ); + + // + //Write back the original value + // + Status = PrivateData->Io.Pci.Write ( + &PrivateData->Io, + EfiPciWidthUint32, + Address, + 1, + OriginalValue + ); + + // + // Restore TPL to its original level + // + gBS->RestoreTPL (OldTpl); + + if ( *Value == 0 ) { + return EFI_DEVICE_ERROR; + } + return EFI_SUCCESS; +} + +EFI_STATUS +PcatPciRootBridgeParseBars ( + IN PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData, + IN UINT16 Command, + IN UINTN Bus, + IN UINTN Device, + IN UINTN Function + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + UINT64 Address; + UINT32 OriginalValue; + UINT32 Value; + UINT32 OriginalUpperValue; + UINT32 UpperValue; + UINT64 Mask; + UINTN Offset; + UINT64 Base; + UINT64 Length; + UINT64 Limit; + + for (Offset = 0x10; Offset < 0x28; Offset += 4) { + Address = EFI_PCI_ADDRESS (Bus, Device, Function, Offset); + Status = PcatPciRootBridgeBarExisted ( + PrivateData, + Address, + &OriginalValue, + &Value + ); + + if (!EFI_ERROR (Status )) { + if ( Value & 0x01 ) { + if (Command & 0x0001) { + // + //Device I/Os + // + Mask = 0xfffffffc; + Base = OriginalValue & Mask; + Length = ((~(Value & Mask)) & Mask) + 0x04; + if (!(Value & 0xFFFF0000)){ + Length &= 0x0000FFFF; + } + Limit = Base + Length - 1; + + if (Base < Limit) { + if (PrivateData->IoBase > Base) { + PrivateData->IoBase = (UINT32)Base; + } + if (PrivateData->IoLimit < Limit) { + PrivateData->IoLimit = (UINT32)Limit; + } + } + } + + } else { + + if (Command & 0x0002) { + + Mask = 0xfffffff0; + Base = OriginalValue & Mask; + Length = Value & Mask; + + if ((Value & 0x07) != 0x04) { + Length = ((~Length) + 1) & 0xffffffff; + } else { + Offset += 4; + Address = EFI_PCI_ADDRESS (Bus, Device, Function, Offset); + + Status = PcatPciRootBridgeBarExisted ( + PrivateData, + Address, + &OriginalUpperValue, + &UpperValue + ); + + Base = Base | LShiftU64((UINT64)OriginalUpperValue,32); + Length = Length | LShiftU64((UINT64)UpperValue,32); + Length = (~Length) + 1; + } + + Limit = Base + Length - 1; + + if (Base < Limit) { + if (PrivateData->MemBase > Base) { + PrivateData->MemBase = Base; + } + if (PrivateData->MemLimit < Limit) { + PrivateData->MemLimit = Limit; + } + + switch (Value &0x07) { + case 0x00: ////memory space; anywhere in 32 bit address space + if (Value & 0x08) { + if (PrivateData->Pmem32Base > Base) { + PrivateData->Pmem32Base = Base; + } + if (PrivateData->Pmem32Limit < Limit) { + PrivateData->Pmem32Limit = Limit; + } + } else { + if (PrivateData->Mem32Base > Base) { + PrivateData->Mem32Base = Base; + } + if (PrivateData->Mem32Limit < Limit) { + PrivateData->Mem32Limit = Limit; + } + } + break; + case 0x04: //memory space; anywhere in 64 bit address space + if (Value & 0x08) { + if (PrivateData->Pmem64Base > Base) { + PrivateData->Pmem64Base = Base; + } + if (PrivateData->Pmem64Limit < Limit) { + PrivateData->Pmem64Limit = Limit; + } + } else { + if (PrivateData->Mem64Base > Base) { + PrivateData->Mem64Base = Base; + } + if (PrivateData->Mem64Limit < Limit) { + PrivateData->Mem64Limit = Limit; + } + } + break; + } + } + } + } + } + } + return EFI_SUCCESS; +} + +UINT64 +GetPciExpressBaseAddressForRootBridge ( + IN UINTN HostBridgeNumber, + IN UINTN RootBridgeNumber + ) +/*++ + +Routine Description: + This routine is to get PciExpress Base Address for this RootBridge + +Arguments: + HostBridgeNumber - The number of HostBridge + RootBridgeNumber - The number of RootBridge + +Returns: + UINT64 - PciExpressBaseAddress for this HostBridge and RootBridge + +--*/ +{ + EFI_PCI_EXPRESS_BASE_ADDRESS_INFORMATION *PciExpressBaseAddressInfo; + UINTN BufferSize; + UINT32 Index; + UINT32 Number; + VOID *HobList; + EFI_STATUS Status; + EFI_PEI_HOB_POINTERS GuidHob; + + // + // Get Hob List from configuration table + // + Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList); + if (EFI_ERROR (Status)) { + return 0; + } + + // + // Get PciExpressAddressInfo Hob + // + PciExpressBaseAddressInfo = NULL; + BufferSize = 0; + GuidHob.Raw = GetNextGuidHob (&gEfiPciExpressBaseAddressGuid, &HobList); + if (GuidHob.Raw != NULL) { + PciExpressBaseAddressInfo = GET_GUID_HOB_DATA (GuidHob.Guid); + BufferSize = GET_GUID_HOB_DATA_SIZE (GuidHob.Guid); + } else { + return 0; + } + + // + // Search the PciExpress Base Address in the Hob for current RootBridge + // + Number = (UINT32)(BufferSize / sizeof(EFI_PCI_EXPRESS_BASE_ADDRESS_INFORMATION)); + for (Index = 0; Index < Number; Index++) { + if ((PciExpressBaseAddressInfo[Index].HostBridgeNumber == HostBridgeNumber) && + (PciExpressBaseAddressInfo[Index].RootBridgeNumber == RootBridgeNumber)) { + return PciExpressBaseAddressInfo[Index].PciExpressBaseAddress; + } + } + + // + // Do not find the PciExpress Base Address in the Hob + // + return 0; +} + diff --git a/DuetPkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridge.h b/DuetPkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridge.h new file mode 100644 index 0000000000..50bd9b43b2 --- /dev/null +++ b/DuetPkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridge.h @@ -0,0 +1,215 @@ +/*++ + +Copyright (c) 2005 - 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PcatPciRootBridge.h + +Abstract: + + The driver for the host to pci bridge (root bridge). + +--*/ + +#ifndef _PCAT_PCI_ROOT_BRIDGE_H_ +#define _PCAT_PCI_ROOT_BRIDGE_H_ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +// +// Driver Instance Data Prototypes +// +#define PCAT_PCI_ROOT_BRIDGE_SIGNATURE EFI_SIGNATURE_32('p', 'c', 'r', 'b') + +typedef struct { + UINT32 Signature; + EFI_HANDLE Handle; + + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL Io; + EFI_CPU_IO_PROTOCOL *CpuIo; + + UINT32 RootBridgeNumber; + UINT32 PrimaryBus; + UINT32 SubordinateBus; + + UINT64 MemBase; // Offsets host to bus memory addr. + UINT64 MemLimit; // Max allowable memory access + + UINT64 IoBase; // Offsets host to bus io addr. + UINT64 IoLimit; // Max allowable io access + + UINT64 PciAddress; + UINT64 PciData; + + UINT64 PhysicalMemoryBase; + UINT64 PhysicalIoBase; + + EFI_LOCK PciLock; + + UINT64 Attributes; + + UINT64 Mem32Base; + UINT64 Mem32Limit; + UINT64 Pmem32Base; + UINT64 Pmem32Limit; + UINT64 Mem64Base; + UINT64 Mem64Limit; + UINT64 Pmem64Base; + UINT64 Pmem64Limit; + + UINT64 PciExpressBaseAddress; + + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration; + + LIST_ENTRY MapInfo; +} PCAT_PCI_ROOT_BRIDGE_INSTANCE; + +// +// Driver Instance Data Macros +// +#define DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(a) \ + CR(a, PCAT_PCI_ROOT_BRIDGE_INSTANCE, Io, PCAT_PCI_ROOT_BRIDGE_SIGNATURE) + +#define VOLATILE volatile +// +// Private data types +// +typedef union { + UINT8 VOLATILE *buf; + UINT8 VOLATILE *ui8; + UINT16 VOLATILE *ui16; + UINT32 VOLATILE *ui32; + UINT64 VOLATILE *ui64; + UINTN VOLATILE ui; +} PTR; + +typedef struct { + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation; + UINTN NumberOfBytes; + UINTN NumberOfPages; + EFI_PHYSICAL_ADDRESS HostAddress; + EFI_PHYSICAL_ADDRESS MappedHostAddress; +} MAP_INFO; + +typedef struct { + LIST_ENTRY Link; + MAP_INFO * Map; +} MAP_INFO_INSTANCE; + +typedef +VOID +(*EFI_PCI_BUS_SCAN_CALLBACK) ( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + UINT16 Bus, + UINT16 Device, + UINT16 Func, + IN VOID *Context + ); + +typedef struct { + UINT16 *CommandRegisterBuffer; + UINT32 PpbMemoryWindow; +} PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT; + +// +// Driver Protocol Constructor Prototypes +// +EFI_STATUS +ConstructConfiguration( + IN OUT PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData + ); + +EFI_STATUS +PcatPciRootBridgeParseBars ( + IN PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData, + IN UINT16 Command, + IN UINTN Bus, + IN UINTN Device, + IN UINTN Function + ); + +EFI_STATUS +ScanPciRootBridgeForRoms( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev + ); + +EFI_STATUS +PcatRootBridgeDevicePathConstructor ( + IN EFI_DEVICE_PATH_PROTOCOL **Protocol, + IN UINTN RootBridgeNumber, + IN BOOLEAN IsPciExpress + ); + +EFI_STATUS +PcatRootBridgeIoConstructor ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Protocol, + IN UINTN SegmentNumber + ); + +EFI_STATUS +PcatRootBridgeIoGetIoPortMapping ( + OUT EFI_PHYSICAL_ADDRESS *IoPortMapping, + OUT EFI_PHYSICAL_ADDRESS *MemoryPortMapping + ); + +EFI_STATUS +PcatRootBridgeIoPciRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN BOOLEAN Write, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +UINT64 +GetPciExpressBaseAddressForRootBridge ( + IN UINTN HostBridgeNumber, + IN UINTN RootBridgeNumber + ); + +// +// Driver entry point prototype +// +EFI_STATUS +EFIAPI +InitializePcatPciRootBridge ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +extern EFI_CPU_IO_PROTOCOL *gCpuIo; + +#endif diff --git a/DuetPkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridgeDevicePath.c b/DuetPkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridgeDevicePath.c new file mode 100644 index 0000000000..ab1b5d8c56 --- /dev/null +++ b/DuetPkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridgeDevicePath.c @@ -0,0 +1,87 @@ +/*++ + +Copyright (c) 2005 - 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PcatPciRootBridgeDevicePath.c + +Abstract: + + EFI PCAT PCI Root Bridge Device Path Protocol + +Revision History + +--*/ + +#include "PcatPciRootBridge.h" + +// +// Static device path declarations for this driver. +// + +typedef struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH; + +static EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath = { + { + ACPI_DEVICE_PATH, + ACPI_DP, + (UINT8) (sizeof(ACPI_HID_DEVICE_PATH)), + (UINT8) ((sizeof(ACPI_HID_DEVICE_PATH)) >> 8), + EISA_PNP_ID(0x0A03), + 0 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + END_DEVICE_PATH_LENGTH, + 0 + } +}; + +EFI_STATUS +PcatRootBridgeDevicePathConstructor ( + IN EFI_DEVICE_PATH_PROTOCOL **Protocol, + IN UINTN RootBridgeNumber, + IN BOOLEAN IsPciExpress + ) +/*++ + +Routine Description: + + Construct the device path protocol + +Arguments: + + Protocol - protocol to initialize + +Returns: + + None + +--*/ +{ + ACPI_HID_DEVICE_PATH *AcpiDevicePath; + + *Protocol = DuplicateDevicePath((EFI_DEVICE_PATH_PROTOCOL *)(&mEfiPciRootBridgeDevicePath)); + + AcpiDevicePath = (ACPI_HID_DEVICE_PATH *)(*Protocol); + + AcpiDevicePath->UID = (UINT32)RootBridgeNumber; + + if (IsPciExpress) { + AcpiDevicePath->HID = EISA_PNP_ID(0x0A08); + } + + return EFI_SUCCESS; +} + diff --git a/DuetPkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridgeIo.c b/DuetPkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridgeIo.c new file mode 100644 index 0000000000..abb6acbd96 --- /dev/null +++ b/DuetPkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridgeIo.c @@ -0,0 +1,1054 @@ +/*++ + +Copyright (c) 2005 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PcatPciRootBridgeIo.c + +Abstract: + + EFI PC AT PCI Root Bridge Io Protocol + +Revision History + +--*/ + +#include "PcatPciRootBridge.h" + +// +// Protocol Member Function Prototypes +// +EFI_STATUS +EFIAPI +PcatRootBridgeIoPollMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoPollIo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoCopyMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 DestAddress, + IN UINT64 SrcAddress, + IN UINTN Count + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoPciRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoPciWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoMap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoUnmap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoAllocateBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoFreeBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINTN Pages, + OUT VOID *HostAddress + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoFlush ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoGetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT UINT64 *Supported, + OUT UINT64 *Attributes + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoSetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN OUT UINT64 *ResourceBase, + IN OUT UINT64 *ResourceLength + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoConfiguration ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT VOID **Resources + ); + +// +// Private Function Prototypes +// +STATIC +EFI_STATUS +EFIAPI +PcatRootBridgeIoMemRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + IN BOOLEAN InStrideFlag, + IN PTR In, + IN BOOLEAN OutStrideFlag, + OUT PTR Out + ); + +EFI_STATUS +PcatRootBridgeIoConstructor ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Protocol, + IN UINTN SegmentNumber + ) +/*++ + +Routine Description: + + Contruct the Pci Root Bridge Io protocol + +Arguments: + + Protocol - protocol to initialize + +Returns: + + None + +--*/ +{ + Protocol->ParentHandle = NULL; + + Protocol->PollMem = PcatRootBridgeIoPollMem; + Protocol->PollIo = PcatRootBridgeIoPollIo; + + Protocol->Mem.Read = PcatRootBridgeIoMemRead; + Protocol->Mem.Write = PcatRootBridgeIoMemWrite; + + Protocol->Io.Read = PcatRootBridgeIoIoRead; + Protocol->Io.Write = PcatRootBridgeIoIoWrite; + + Protocol->CopyMem = PcatRootBridgeIoCopyMem; + + Protocol->Pci.Read = PcatRootBridgeIoPciRead; + Protocol->Pci.Write = PcatRootBridgeIoPciWrite; + + Protocol->Map = PcatRootBridgeIoMap; + Protocol->Unmap = PcatRootBridgeIoUnmap; + + Protocol->AllocateBuffer = PcatRootBridgeIoAllocateBuffer; + Protocol->FreeBuffer = PcatRootBridgeIoFreeBuffer; + + Protocol->Flush = PcatRootBridgeIoFlush; + + Protocol->GetAttributes = PcatRootBridgeIoGetAttributes; + Protocol->SetAttributes = PcatRootBridgeIoSetAttributes; + + Protocol->Configuration = PcatRootBridgeIoConfiguration; + + Protocol->SegmentNumber = (UINT32)SegmentNumber; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoPollMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + EFI_STATUS Status; + UINT64 NumberOfTicks; + UINTN Remainder; + + if (Result == NULL) { + return EFI_INVALID_PARAMETER; + } + + + if (Width < 0 || Width > EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + // + // No matter what, always do a single poll. + // + Status = This->Mem.Read (This, Width, Address, 1, Result); + if ( EFI_ERROR(Status) ) { + return Status; + } + if ( (*Result & Mask) == Value ) { + return EFI_SUCCESS; + } + + if ( Delay != 0 ) { + + NumberOfTicks = DivU64x32Remainder (Delay, 100, &Remainder); + if ( Remainder !=0 ) { + NumberOfTicks += 1; + } + NumberOfTicks += 1; + + while ( NumberOfTicks ) { + + gBS->Stall (10); + + Status = This->Mem.Read (This, Width, Address, 1, Result); + if ( EFI_ERROR(Status) ) { + return Status; + } + + if ( (*Result & Mask) == Value ) { + return EFI_SUCCESS; + } + + NumberOfTicks -= 1; + } + } + return EFI_TIMEOUT; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoPollIo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + EFI_STATUS Status; + UINT64 NumberOfTicks; + UINTN Remainder; + + if (Result == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width > EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + // + // No matter what, always do a single poll. + // + Status = This->Io.Read (This, Width, Address, 1, Result); + if ( EFI_ERROR(Status) ) { + return Status; + } + if ( (*Result & Mask) == Value ) { + return EFI_SUCCESS; + } + + if (Delay != 0) { + + NumberOfTicks = DivU64x32Remainder (Delay, 100, &Remainder); + if ( Remainder !=0 ) { + NumberOfTicks += 1; + } + NumberOfTicks += 1; + + while ( NumberOfTicks ) { + + gBS->Stall(10); + + Status = This->Io.Read (This, Width, Address, 1, Result); + if ( EFI_ERROR(Status) ) { + return Status; + } + + if ( (*Result & Mask) == Value ) { + return EFI_SUCCESS; + } + + NumberOfTicks -= 1; + } + } + return EFI_TIMEOUT; +} + +BOOLEAN +PcatRootBridgeMemAddressValid ( + IN PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData, + IN UINT64 Address + ) +{ + if ((Address >= PrivateData->PciExpressBaseAddress) && (Address < PrivateData->PciExpressBaseAddress + 0x10000000)) { + return TRUE; + } + if ((Address >= PrivateData->MemBase) && (Address < PrivateData->MemLimit)) { + return TRUE; + } + + return FALSE; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + UINTN AlignMask; + PTR In; + PTR Out; + + if ( Buffer == NULL ) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + if (!PcatRootBridgeMemAddressValid (PrivateData, Address)) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if (Address & AlignMask) { + return EFI_INVALID_PARAMETER; + } + + Address += PrivateData->PhysicalMemoryBase; + + In.buf = Buffer; + Out.buf = (VOID *)(UINTN) Address; + if (Width >= EfiPciWidthUint8 && Width <= EfiPciWidthUint64) { + return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out); + } + if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out); + } + if (Width >= EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { + return PcatRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out); + } + + return EFI_INVALID_PARAMETER; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + UINTN AlignMask; + PTR In; + PTR Out; + + if ( Buffer == NULL ) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + if (!PcatRootBridgeMemAddressValid (PrivateData, Address)) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if (Address & AlignMask) { + return EFI_INVALID_PARAMETER; + } + + Address += PrivateData->PhysicalMemoryBase; + + In.buf = (VOID *)(UINTN) Address; + Out.buf = Buffer; + if (Width >= EfiPciWidthUint8 && Width <= EfiPciWidthUint64) { + return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out); + } + if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + return PcatRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out); + } + if (Width >= EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { + return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out); + } + + return EFI_INVALID_PARAMETER; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoCopyMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 DestAddress, + IN UINT64 SrcAddress, + IN UINTN Count + ) + +{ + EFI_STATUS Status; + BOOLEAN Direction; + UINTN Stride; + UINTN Index; + UINT64 Result; + + if (Width < 0 || Width > EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + if (DestAddress == SrcAddress) { + return EFI_SUCCESS; + } + + Stride = (UINTN)1 << Width; + + Direction = TRUE; + if ((DestAddress > SrcAddress) && (DestAddress < (SrcAddress + Count * Stride))) { + Direction = FALSE; + SrcAddress = SrcAddress + (Count-1) * Stride; + DestAddress = DestAddress + (Count-1) * Stride; + } + + for (Index = 0;Index < Count;Index++) { + Status = PcatRootBridgeIoMemRead ( + This, + Width, + SrcAddress, + 1, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + Status = PcatRootBridgeIoMemWrite ( + This, + Width, + DestAddress, + 1, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + if (Direction) { + SrcAddress += Stride; + DestAddress += Stride; + } else { + SrcAddress -= Stride; + DestAddress -= Stride; + } + } + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoPciRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + return PcatRootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer); +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoPciWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + return PcatRootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer); +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoMap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) + +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS PhysicalAddress; + MAP_INFO *MapInfo; + MAP_INFO_INSTANCE *MapInstance; + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + + if ( HostAddress == NULL || NumberOfBytes == NULL || + DeviceAddress == NULL || Mapping == NULL ) { + + return EFI_INVALID_PARAMETER; + } + + // + // Perform a fence operation to make sure all memory operations are flushed + // + MemoryFence(); + + // + // Initialize the return values to their defaults + // + *Mapping = NULL; + + // + // Make sure that Operation is valid + // + if (Operation < 0 || Operation >= EfiPciOperationMaximum) { + return EFI_INVALID_PARAMETER; + } + + // + // Most PCAT like chipsets can not handle performing DMA above 4GB. + // If any part of the DMA transfer being mapped is above 4GB, then + // map the DMA transfer to a buffer below 4GB. + // + PhysicalAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress; + if ((PhysicalAddress + *NumberOfBytes) > 0x100000000) { + + // + // Common Buffer operations can not be remapped. If the common buffer + // if above 4GB, then it is not possible to generate a mapping, so return + // an error. + // + if (Operation == EfiPciOperationBusMasterCommonBuffer || Operation == EfiPciOperationBusMasterCommonBuffer64) { + return EFI_UNSUPPORTED; + } + + // + // Allocate a MAP_INFO structure to remember the mapping when Unmap() is + // called later. + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof(MAP_INFO), + &MapInfo + ); + if (EFI_ERROR (Status)) { + *NumberOfBytes = 0; + return Status; + } + + // + // Return a pointer to the MAP_INFO structure in Mapping + // + *Mapping = MapInfo; + + // + // Initialize the MAP_INFO structure + // + MapInfo->Operation = Operation; + MapInfo->NumberOfBytes = *NumberOfBytes; + MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES(*NumberOfBytes); + MapInfo->HostAddress = PhysicalAddress; + MapInfo->MappedHostAddress = 0x00000000ffffffff; + + // + // Allocate a buffer below 4GB to map the transfer to. + // + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiBootServicesData, + MapInfo->NumberOfPages, + &MapInfo->MappedHostAddress + ); + if (EFI_ERROR(Status)) { + gBS->FreePool (MapInfo); + *NumberOfBytes = 0; + return Status; + } + + // + // If this is a read operation from the Bus Master's point of view, + // then copy the contents of the real buffer into the mapped buffer + // so the Bus Master can read the contents of the real buffer. + // + if (Operation == EfiPciOperationBusMasterRead || Operation == EfiPciOperationBusMasterRead64) { + CopyMem ( + (VOID *)(UINTN)MapInfo->MappedHostAddress, + (VOID *)(UINTN)MapInfo->HostAddress, + MapInfo->NumberOfBytes + ); + } + + + Status =gBS->AllocatePool ( + EfiBootServicesData, + sizeof(MAP_INFO_INSTANCE), + &MapInstance + ); + if (EFI_ERROR(Status)) { + gBS->FreePages (MapInfo->MappedHostAddress,MapInfo->NumberOfPages); + gBS->FreePool (MapInfo); + *NumberOfBytes = 0; + return Status; + } + + MapInstance->Map=MapInfo; + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + InsertTailList(&PrivateData->MapInfo,&MapInstance->Link); + + // + // The DeviceAddress is the address of the maped buffer below 4GB + // + *DeviceAddress = MapInfo->MappedHostAddress; + } else { + // + // The transfer is below 4GB, so the DeviceAddress is simply the HostAddress + // + *DeviceAddress = PhysicalAddress; + } + + // + // Perform a fence operation to make sure all memory operations are flushed + // + MemoryFence(); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoUnmap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN VOID *Mapping + ) + +{ + MAP_INFO *MapInfo; + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + LIST_ENTRY *Link; + + // + // Perform a fence operation to make sure all memory operations are flushed + // + MemoryFence(); + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + // + // See if the Map() operation associated with this Unmap() required a mapping buffer. + // If a mapping buffer was not required, then this function simply returns EFI_SUCCESS. + // + if (Mapping != NULL) { + // + // Get the MAP_INFO structure from Mapping + // + MapInfo = (MAP_INFO *)Mapping; + + for (Link = PrivateData->MapInfo.ForwardLink; Link != &PrivateData->MapInfo; Link = Link->ForwardLink) { + if (((MAP_INFO_INSTANCE*)Link)->Map == MapInfo) + break; + } + + if (Link == &PrivateData->MapInfo) { + return EFI_INVALID_PARAMETER; + } + + RemoveEntryList(Link); + ((MAP_INFO_INSTANCE*)Link)->Map = NULL; + gBS->FreePool((MAP_INFO_INSTANCE*)Link); + + // + // If this is a write operation from the Bus Master's point of view, + // then copy the contents of the mapped buffer into the real buffer + // so the processor can read the contents of the real buffer. + // + if (MapInfo->Operation == EfiPciOperationBusMasterWrite || MapInfo->Operation == EfiPciOperationBusMasterWrite64) { + CopyMem ( + (VOID *)(UINTN)MapInfo->HostAddress, + (VOID *)(UINTN)MapInfo->MappedHostAddress, + MapInfo->NumberOfBytes + ); + } + + // + // Free the mapped buffer and the MAP_INFO structure. + // + gBS->FreePages (MapInfo->MappedHostAddress, MapInfo->NumberOfPages); + gBS->FreePool (Mapping); + } + + // + // Perform a fence operation to make sure all memory operations are flushed + // + MemoryFence(); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoAllocateBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS PhysicalAddress; + + // + // Validate Attributes + // + if (Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) { + return EFI_UNSUPPORTED; + } + + // + // Check for invalid inputs + // + if (HostAddress == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData + // + if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) { + return EFI_INVALID_PARAMETER; + } + + // + // Limit allocations to memory below 4GB + // + PhysicalAddress = (EFI_PHYSICAL_ADDRESS)(0xffffffff); + + Status = gBS->AllocatePages (AllocateMaxAddress, MemoryType, Pages, &PhysicalAddress); + if (EFI_ERROR (Status)) { + return Status; + } + + *HostAddress = (VOID *)(UINTN)PhysicalAddress; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoFreeBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINTN Pages, + OUT VOID *HostAddress + ) + +{ + + if( HostAddress == NULL ){ + return EFI_INVALID_PARAMETER; + } + return gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress, Pages); +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoFlush ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This + ) + +{ + // + // Perform a fence operation to make sure all memory operations are flushed + // + MemoryFence(); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoGetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT UINT64 *Supported, OPTIONAL + OUT UINT64 *Attributes + ) + +{ + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + if (Attributes == NULL && Supported == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Supported is an OPTIONAL parameter. See if it is NULL + // + if (Supported) { + // + // This is a generic driver for a PC-AT class system. It does not have any + // chipset specific knowlegde, so none of the attributes can be set or + // cleared. Any attempt to set attribute that are already set will succeed, + // and any attempt to set an attribute that is not supported will fail. + // + *Supported = PrivateData->Attributes; + } + + // + // Set Attrbutes to the attributes detected when the PCI Root Bridge was initialized + // + + if (Attributes) { + *Attributes = PrivateData->Attributes; + } + + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoSetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN OUT UINT64 *ResourceBase, + IN OUT UINT64 *ResourceLength + ) + +{ + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + // + // This is a generic driver for a PC-AT class system. It does not have any + // chipset specific knowlegde, so none of the attributes can be set or + // cleared. Any attempt to set attribute that are already set will succeed, + // and any attempt to set an attribute that is not supported will fail. + // + if (Attributes & (~PrivateData->Attributes)) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoConfiguration ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT VOID **Resources + ) + +{ + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + *Resources = PrivateData->Configuration; + + return EFI_SUCCESS; +} + +// +// Internal function +// + +STATIC +EFI_STATUS +EFIAPI +PcatRootBridgeIoMemRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + IN BOOLEAN InStrideFlag, + IN PTR In, + IN BOOLEAN OutStrideFlag, + OUT PTR Out + ) +/*++ + +Routine Description: + + Private service to provide the memory read/write + +Arguments: + + Width of the Memory Access + Count of the number of accesses to perform + +Returns: + + Status + + EFI_SUCCESS - Successful transaction + EFI_INVALID_PARAMETER - Unsupported width and address combination + +--*/ +{ + UINTN Stride; + UINTN InStride; + UINTN OutStride; + + + Width = Width & 0x03; + Stride = (UINTN)1 << Width; + InStride = InStrideFlag ? Stride : 0; + OutStride = OutStrideFlag ? Stride : 0; + + // + // Loop for each iteration and move the data + // + switch (Width) { + case EfiPciWidthUint8: + for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { + MemoryFence(); + *In.ui8 = *Out.ui8; + MemoryFence(); + } + break; + case EfiPciWidthUint16: + for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { + MemoryFence(); + *In.ui16 = *Out.ui16; + MemoryFence(); + } + break; + case EfiPciWidthUint32: + for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { + MemoryFence(); + *In.ui32 = *Out.ui32; + MemoryFence(); + } + break; + default: + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + diff --git a/DuetPkg/PciRootBridgeNoEnumerationDxe/PciRootBridgeNoEnumeration.inf b/DuetPkg/PciRootBridgeNoEnumerationDxe/PciRootBridgeNoEnumeration.inf new file mode 100644 index 0000000000..fa0596db13 --- /dev/null +++ b/DuetPkg/PciRootBridgeNoEnumerationDxe/PciRootBridgeNoEnumeration.inf @@ -0,0 +1,70 @@ +#/*++ +# +# Copyright (c) 2005 - 2006, Intel Corporation +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# Abstract: +# +#--*/ + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PcatPciRootBridge + FILE_GUID = 0F7EC77A-1EE1-400f-A99D-7CBD1FEB181E + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x00020000 + + ENTRY_POINT = InitializePcatPciRootBridge + +[Packages] + MdePkg/MdePkg.dec + DuetPkg/DuetPkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiLib + MemoryAllocationLib + UefiBootServicesTableLib + DebugLib + BaseMemoryLib + DevicePathLib + HobLib + +[Sources.common] + PcatPciRootBridge.h + PcatPciRootBridge.c + PcatPciRootBridgeDevicePath.c + PcatPciRootBridgeIo.c + DeviceIo.h + DeviceIo.c + +[Sources.ia32] + ia32\PcatIo.c + +[Sources.x64] + x64\PcatIo.c + +[Sources.ipf] + Ipf\PcatIo.c + +[Protocols] + gEfiPciRootBridgeIoProtocolGuid + gEfiDeviceIoProtocolGuid + gEfiPciExpressBaseAddressGuid + gEfiCpuIoProtocolGuid + +[Guids] + gEfiPciOptionRomTableGuid \ No newline at end of file diff --git a/DuetPkg/PciRootBridgeNoEnumerationDxe/x64/PcatIo.c b/DuetPkg/PciRootBridgeNoEnumerationDxe/x64/PcatIo.c new file mode 100644 index 0000000000..830dcbb8c7 --- /dev/null +++ b/DuetPkg/PciRootBridgeNoEnumerationDxe/x64/PcatIo.c @@ -0,0 +1,732 @@ +/*++ + +Copyright (c) 2005 - 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + PcatPciRootBridgeIo.c + +Abstract: + + EFI PC AT PCI Root Bridge Io Protocol + +Revision History + +--*/ + +#include "PcatPciRootBridge.h" + +static BOOLEAN mPciOptionRomTableInstalled = FALSE; +static EFI_PCI_OPTION_ROM_TABLE mPciOptionRomTable = {0, NULL}; + +EFI_STATUS +PcatRootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + return gCpuIo->Io.Read ( + gCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) Width, + UserAddress, + Count, + UserBuffer + ); +} + +EFI_STATUS +PcatRootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + return gCpuIo->Io.Write ( + gCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) Width, + UserAddress, + Count, + UserBuffer + ); + +} + +EFI_STATUS +PcatRootBridgeIoGetIoPortMapping ( + OUT EFI_PHYSICAL_ADDRESS *IoPortMapping, + OUT EFI_PHYSICAL_ADDRESS *MemoryPortMapping + ) +/*++ + + Get the IO Port Mapping. For IA-32 it is always 0. + +--*/ +{ + *IoPortMapping = 0; + *MemoryPortMapping = 0; + + return EFI_SUCCESS; +} + +EFI_STATUS +PcatRootBridgeIoPciRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN BOOLEAN Write, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + PCI_CONFIG_ACCESS_CF8 Pci; + PCI_CONFIG_ACCESS_CF8 PciAligned; + UINT32 InStride; + UINT32 OutStride; + UINTN PciData; + UINTN PciDataStride; + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress; + UINT64 PciExpressRegAddr; + BOOLEAN UsePciExpressAccess; + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + if ((Width & 0x03) >= EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + InStride = 1 << (Width & 0x03); + OutStride = InStride; + if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) { + InStride = 0; + } + + if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) { + OutStride = 0; + } + + UsePciExpressAccess = FALSE; + + EfiCopyMem (&PciAddress, &UserAddress, sizeof(UINT64)); + + if (PciAddress.ExtendedRegister > 0xFF) { + // + // Check PciExpressBaseAddress + // + if ((PrivateData->PciExpressBaseAddress == 0) || + (PrivateData->PciExpressBaseAddress >= EFI_MAX_ADDRESS)) { + return EFI_UNSUPPORTED; + } else { + UsePciExpressAccess = TRUE; + } + } else { + if (PciAddress.ExtendedRegister != 0) { + Pci.Reg = PciAddress.ExtendedRegister & 0xFF; + } else { + Pci.Reg = PciAddress.Register; + } + // + // Note: We can also use PciExpress access here, if wanted. + // + } + + if (!UsePciExpressAccess) { + Pci.Func = PciAddress.Function; + Pci.Dev = PciAddress.Device; + Pci.Bus = PciAddress.Bus; + Pci.Reserved = 0; + Pci.Enable = 1; + + // + // PCI Config access are all 32-bit alligned, but by accessing the + // CONFIG_DATA_REGISTER (0xcfc) with different widths more cycle types + // are possible on PCI. + // + // To read a byte of PCI config space you load 0xcf8 and + // read 0xcfc, 0xcfd, 0xcfe, 0xcff + // + PciDataStride = Pci.Reg & 0x03; + + while (Count) { + PciAligned = Pci; + PciAligned.Reg &= 0xfc; + PciData = (UINTN)PrivateData->PciData + PciDataStride; + EfiAcquireLock(&PrivateData->PciLock); + This->Io.Write (This, EfiPciWidthUint32, PrivateData->PciAddress, 1, &PciAligned); + if (Write) { + This->Io.Write (This, Width, PciData, 1, UserBuffer); + } else { + This->Io.Read (This, Width, PciData, 1, UserBuffer); + } + EfiReleaseLock(&PrivateData->PciLock); + UserBuffer = ((UINT8 *)UserBuffer) + OutStride; + PciDataStride = (PciDataStride + InStride) % 4; + Pci.Reg += InStride; + Count -= 1; + } + } else { + // + // Access PCI-Express space by using memory mapped method. + // + PciExpressRegAddr = (PrivateData->PciExpressBaseAddress) | + (PciAddress.Bus << 20) | + (PciAddress.Device << 15) | + (PciAddress.Function << 12); + if (PciAddress.ExtendedRegister != 0) { + PciExpressRegAddr += PciAddress.ExtendedRegister; + } else { + PciExpressRegAddr += PciAddress.Register; + } + while (Count) { + if (Write) { + This->Mem.Write (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer); + } else { + This->Mem.Read (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer); + } + + UserBuffer = ((UINT8 *) UserBuffer) + OutStride; + PciExpressRegAddr += InStride; + Count -= 1; + } + } + + return EFI_SUCCESS; +} + +static +VOID +ScanPciBus( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + EFI_PCI_BUS_SCAN_CALLBACK Callback, + VOID *Context + ) + +{ + UINT16 Bus; + UINT16 Device; + UINT16 Func; + UINT64 Address; + PCI_TYPE00 PciHeader; + + // + // Loop through all busses + // + for (Bus = MinBus; Bus <= MaxBus; Bus++) { + // + // Loop 32 devices per bus + // + for (Device = MinDevice; Device <= MaxDevice; Device++) { + // + // Loop through 8 functions per device + // + for (Func = MinFunc; Func <= MaxFunc; Func++) { + + // + // Compute the EFI Address required to access the PCI Configuration Header of this PCI Device + // + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); + + // + // Read the VendorID from this PCI Device's Confioguration Header + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &PciHeader.Hdr.VendorId); + + // + // If VendorId = 0xffff, there does not exist a device at this + // location. For each device, if there is any function on it, + // there must be 1 function at Function 0. So if Func = 0, there + // will be no more functions in the same device, so we can break + // loop to deal with the next device. + // + if (PciHeader.Hdr.VendorId == 0xffff && Func == 0) { + break; + } + + if (PciHeader.Hdr.VendorId != 0xffff) { + + // + // Read the HeaderType to determine if this is a multi-function device + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint8, Address + 0x0e, 1, &PciHeader.Hdr.HeaderType); + + // + // Call the callback function for the device that was found + // + Callback( + IoDev, + MinBus, MaxBus, + MinDevice, MaxDevice, + MinFunc, MaxFunc, + Bus, + Device, + Func, + Context + ); + + // + // If this is not a multi-function device, we can leave the loop + // to deal with the next device. + // + if ((PciHeader.Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00 && Func == 0) { + break; + } + } + } + } + } +} + +static +VOID +CheckForRom ( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + UINT16 Bus, + UINT16 Device, + UINT16 Func, + IN VOID *VoidContext + ) +{ + EFI_STATUS Status; + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; + UINT64 Address; + PCI_TYPE00 PciHeader; + PCI_TYPE01 *PciBridgeHeader; + UINT32 Register; + UINT32 RomBar; + UINT32 RomBarSize; + EFI_PHYSICAL_ADDRESS RomBuffer; + UINT32 MaxRomSize; + EFI_PCI_EXPANSION_ROM_HEADER EfiRomHeader; + PCI_DATA_STRUCTURE Pcir; + EFI_PCI_OPTION_ROM_DESCRIPTOR *TempPciOptionRomDescriptors; + BOOLEAN LastImage; + + Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; + + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); + + // + // Save the contents of the PCI Configuration Header + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader); + + if (IS_PCI_BRIDGE(&PciHeader)) { + + PciBridgeHeader = (PCI_TYPE01 *)(&PciHeader); + + // + // See if the PCI-PCI Bridge has its secondary interface enabled. + // + if (PciBridgeHeader->Bridge.SubordinateBus >= PciBridgeHeader->Bridge.SecondaryBus) { + + // + // Disable the Prefetchable Memory Window + // + Register = 0x00000000; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x26, 1, &Register); + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x2c, 1, &Register); + Register = 0xffffffff; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x24, 1, &Register); + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x28, 1, &Register); + + // + // Program Memory Window to the PCI Root Bridge Memory Window + // + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x20, 4, &Context->PpbMemoryWindow); + + // + // Enable the Memory decode for the PCI-PCI Bridge + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + Register |= 0x02; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + + // + // Recurse on the Secondary Bus Number + // + ScanPciBus( + IoDev, + PciBridgeHeader->Bridge.SecondaryBus, PciBridgeHeader->Bridge.SecondaryBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + CheckForRom, Context + ); + } + } else { + + // + // Check if an Option ROM Register is present and save the Option ROM Window Register + // + RomBar = 0xffffffff; + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + + RomBarSize = (~(RomBar & 0xfffff800)) + 1; + + // + // Make sure the size of the ROM is between 0 and 16 MB + // + if (RomBarSize > 0 && RomBarSize <= 0x01000000) { + + // + // Program Option ROM Window Register to the PCI Root Bridge Window and Enable the Option ROM Window + // + RomBar = (Context->PpbMemoryWindow & 0xffff) << 16; + RomBar = ((RomBar - 1) & (~(RomBarSize - 1))) + RomBarSize; + if (RomBar < (Context->PpbMemoryWindow & 0xffff0000)) { + MaxRomSize = (Context->PpbMemoryWindow & 0xffff0000) - RomBar; + RomBar = RomBar + 1; + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + RomBar = RomBar - 1; + + // + // Enable the Memory decode for the PCI Device + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + Register |= 0x02; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + + // + // Follow the chain of images to determine the size of the Option ROM present + // Keep going until the last image is found by looking at the Indicator field + // or the size of an image is 0, or the size of all the images is bigger than the + // size of the window programmed into the PPB. + // + RomBarSize = 0; + do { + + LastImage = TRUE; + + EfiZeroMem (&EfiRomHeader, sizeof(EfiRomHeader)); + IoDev->Mem.Read ( + IoDev, + EfiPciWidthUint8, + RomBar + RomBarSize, + sizeof(EfiRomHeader), + &EfiRomHeader + ); + + Pcir.ImageLength = 0; + + if (EfiRomHeader.Signature == 0xaa55) { + + EfiZeroMem (&Pcir, sizeof(Pcir)); + IoDev->Mem.Read ( + IoDev, + EfiPciWidthUint8, + RomBar + RomBarSize + EfiRomHeader.PcirOffset, + sizeof(Pcir), + &Pcir + ); + + if ((Pcir.Indicator & 0x80) == 0x00) { + LastImage = FALSE; + } + + RomBarSize += Pcir.ImageLength * 512; + } + } while (!LastImage && RomBarSize < MaxRomSize && Pcir.ImageLength !=0); + + if (RomBarSize > 0) { + + // + // Allocate a memory buffer for the Option ROM contents. + // + Status = gBS->AllocatePages( + AllocateAnyPages, + EfiBootServicesData, + EFI_SIZE_TO_PAGES(RomBarSize), + &RomBuffer + ); + + if (!EFI_ERROR (Status)) { + + // + // Copy the contents of the Option ROM to the memory buffer + // + IoDev->Mem.Read (IoDev, EfiPciWidthUint32, RomBar, RomBarSize / sizeof(UINT32), (VOID *)(UINTN)RomBuffer); + + Status = gBS->AllocatePool( + EfiBootServicesData, + ((UINT32)mPciOptionRomTable.PciOptionRomCount + 1) * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR), + &TempPciOptionRomDescriptors + ); + if (mPciOptionRomTable.PciOptionRomCount > 0) { + EfiCopyMem( + TempPciOptionRomDescriptors, + mPciOptionRomTable.PciOptionRomDescriptors, + (UINT32)mPciOptionRomTable.PciOptionRomCount * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR) + ); + + gBS->FreePool(mPciOptionRomTable.PciOptionRomDescriptors); + } + + mPciOptionRomTable.PciOptionRomDescriptors = TempPciOptionRomDescriptors; + + TempPciOptionRomDescriptors = &(mPciOptionRomTable.PciOptionRomDescriptors[(UINT32)mPciOptionRomTable.PciOptionRomCount]); + + TempPciOptionRomDescriptors->RomAddress = RomBuffer; + TempPciOptionRomDescriptors->MemoryType = EfiBootServicesData; + TempPciOptionRomDescriptors->RomLength = RomBarSize; + TempPciOptionRomDescriptors->Seg = (UINT32)IoDev->SegmentNumber; + TempPciOptionRomDescriptors->Bus = (UINT8)Bus; + TempPciOptionRomDescriptors->Dev = (UINT8)Device; + TempPciOptionRomDescriptors->Func = (UINT8)Func; + TempPciOptionRomDescriptors->ExecutedLegacyBiosImage = TRUE; + TempPciOptionRomDescriptors->DontLoadEfiRom = FALSE; + + mPciOptionRomTable.PciOptionRomCount++; + } + } + + // + // Disable the Memory decode for the PCI-PCI Bridge + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + Register &= (~0x02); + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + } + } + } + + // + // Restore the PCI Configuration Header + // + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader); +} + +static +VOID +SaveCommandRegister ( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + UINT16 Bus, + UINT16 Device, + UINT16 Func, + IN VOID *VoidContext + ) + +{ + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; + UINT64 Address; + UINTN Index; + UINT16 Command; + + Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; + + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4); + + Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func; + + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]); + + // + // Clear the memory enable bit + // + Command = Context->CommandRegisterBuffer[Index] & (~0x02); + + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Command); +} + +static +VOID +RestoreCommandRegister ( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + UINT16 Bus, + UINT16 Device, + UINT16 Func, + IN VOID *VoidContext + ) + +{ + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; + UINT64 Address; + UINTN Index; + + Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; + + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4); + + Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func; + + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]); +} + +EFI_STATUS +ScanPciRootBridgeForRoms( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev + ) + +{ + EFI_STATUS Status; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; + UINT16 MinBus; + UINT16 MaxBus; + UINT64 RootWindowBase; + UINT64 RootWindowLimit; + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT Context; + + if (mPciOptionRomTableInstalled == FALSE) { + gBS->InstallConfigurationTable(&gEfiPciOptionRomTableGuid, &mPciOptionRomTable); + mPciOptionRomTableInstalled = TRUE; + } + + Status = IoDev->Configuration(IoDev, &Descriptors); + if (EFI_ERROR (Status) || Descriptors == NULL) { + return EFI_NOT_FOUND; + } + + MinBus = 0xffff; + MaxBus = 0xffff; + RootWindowBase = 0; + RootWindowLimit = 0; + while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) { + // + // Find bus range + // + if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) { + MinBus = (UINT16)Descriptors->AddrRangeMin; + MaxBus = (UINT16)Descriptors->AddrRangeMax; + } + // + // Find memory descriptors that are not prefetchable + // + if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM && Descriptors->SpecificFlag == 0) { + // + // Find Memory Descriptors that are less than 4GB, so the PPB Memory Window can be used for downstream devices + // + if (Descriptors->AddrRangeMax < 0x100000000) { + // + // Find the largest Non-Prefetchable Memory Descriptor that is less than 4GB + // + if ((Descriptors->AddrRangeMax - Descriptors->AddrRangeMin) > (RootWindowLimit - RootWindowBase)) { + RootWindowBase = Descriptors->AddrRangeMin; + RootWindowLimit = Descriptors->AddrRangeMax; + } + } + } + Descriptors ++; + } + + // + // Make sure a bus range was found + // + if (MinBus == 0xffff || MaxBus == 0xffff) { + return EFI_NOT_FOUND; + } + + // + // Make sure a non-prefetchable memory region was found + // + if (RootWindowBase == 0 && RootWindowLimit == 0) { + return EFI_NOT_FOUND; + } + + // + // Round the Base and Limit values to 1 MB boudaries + // + RootWindowBase = ((RootWindowBase - 1) & 0xfff00000) + 0x00100000; + RootWindowLimit = ((RootWindowLimit + 1) & 0xfff00000) - 1; + + // + // Make sure that the size of the rounded window is greater than zero + // + if (RootWindowLimit <= RootWindowBase) { + return EFI_NOT_FOUND; + } + + // + // Allocate buffer to save the Command register from all the PCI devices + // + Context.CommandRegisterBuffer = NULL; + Status = gBS->AllocatePool( + EfiBootServicesData, + sizeof(UINT16) * (MaxBus - MinBus + 1) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1), + &Context.CommandRegisterBuffer + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Context.PpbMemoryWindow = (((UINT32)RootWindowBase) >> 16) | ((UINT32)RootWindowLimit & 0xffff0000); + + // + // Save the Command register from all the PCI devices, and disable the I/O, Mem, and BusMaster bits + // + ScanPciBus( + IoDev, + MinBus, MaxBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + SaveCommandRegister, &Context + ); + + // + // Recursively scan all the busses for PCI Option ROMs + // + ScanPciBus( + IoDev, + MinBus, MinBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + CheckForRom, &Context + ); + + // + // Restore the Command register in all the PCI devices + // + ScanPciBus( + IoDev, + MinBus, MaxBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + RestoreCommandRegister, &Context + ); + + // + // Free the buffer used to save all the Command register values + // + gBS->FreePool(Context.CommandRegisterBuffer); + + return EFI_SUCCESS; +} diff --git a/DuetPkg/RtPlatformStatusCode/RtPlatformStatusCode.c b/DuetPkg/RtPlatformStatusCode/RtPlatformStatusCode.c new file mode 100644 index 0000000000..bf00b02146 --- /dev/null +++ b/DuetPkg/RtPlatformStatusCode/RtPlatformStatusCode.c @@ -0,0 +1,146 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + RtPlatformStatusCode.c + +Abstract: + + Contains NT32 specific implementations required to use status codes. + +--*/ + +// +// Statements that include other files. +// +#include "Tiano.h" +#include "EfiCommonLib.h" +#include "EfiRuntimeLib.h" +#include "EfiStatusCode.h" +#include "EfiHobLib.h" +#include "RtMemoryStatusCodeLib.h" +#include "BsDataHubStatusCodeLib.h" + +// +// Consumed protocols +// +#include EFI_ARCH_PROTOCOL_CONSUMER (StatusCode) + +// +// GUID definitions +// +#include EFI_GUID_DEFINITION (Hob) + +// +// Globals only work at BootService Time. NOT at Runtime! +// +EFI_REPORT_STATUS_CODE mPeiReportStatusCode; + +// +// Function implementations +// +EFI_RUNTIMESERVICE +EFI_STATUS +EFIAPI +RtPlatformReportStatusCode ( + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value, + IN UINT32 Instance, + IN EFI_GUID * CallerId, + IN EFI_STATUS_CODE_DATA * Data OPTIONAL + ) +/*++ + +Routine Description: + + Call all status code listeners in the MonoStatusCode. + +Arguments: + + Same as ReportStatusCode service + +Returns: + + EFI_SUCCESS Always returns success. + +--*/ +{ + RtMemoryReportStatusCode (CodeType, Value, Instance, CallerId, Data); + if (EfiAtRuntime ()) { + // + // For now all we do is post code at runtime + // + return EFI_SUCCESS; + } + + BsDataHubReportStatusCode (CodeType, Value, Instance, CallerId, Data); + + // + // Call back into PEI to get status codes. This is because SecMain contains + // status code that reports to Win32. + // + if (mPeiReportStatusCode != NULL) { + return mPeiReportStatusCode (CodeType, Value, Instance, CallerId, Data); + } + + return EFI_SUCCESS; +} + +EFI_BOOTSERVICE +VOID +EFIAPI +RtPlatformInitializeStatusCode ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Initialize the status code listeners. + +Arguments: + + (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT) + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + VOID *HobList; + VOID *Pointer; + + RtMemoryInitializeStatusCode (ImageHandle, SystemTable); + BsDataHubInitializeStatusCode (ImageHandle, SystemTable); + + // + // Play any prior status codes to the data hub. + // + PlaybackStatusCodes (BsDataHubReportStatusCode); + + // + // If PEI has a ReportStatusCode callback find it and use it before StdErr + // is connected. + // + mPeiReportStatusCode = NULL; + + Status = EfiLibGetSystemConfigurationTable (&gEfiHobListGuid, &HobList); + if (!EFI_ERROR (Status)) { + Status = GetNextGuidHob (&HobList, &gEfiStatusCodeRuntimeProtocolGuid, &Pointer, NULL); + if (!EFI_ERROR (Status)) { + mPeiReportStatusCode = (EFI_REPORT_STATUS_CODE) (*(UINTN *) Pointer); + } + } +} diff --git a/DuetPkg/RtPlatformStatusCode/RtPlatformStatusCode.inf b/DuetPkg/RtPlatformStatusCode/RtPlatformStatusCode.inf new file mode 100644 index 0000000000..d142cebab8 --- /dev/null +++ b/DuetPkg/RtPlatformStatusCode/RtPlatformStatusCode.inf @@ -0,0 +1,47 @@ +#/*++ +# +# Copyright (c) 2006, Intel Corporation +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# Module Name: +# +# RtPlatformStatusCode.inf +# +# Abstract: +# +# Library selecting the listeners for the platform +# +#--*/ + +[defines] +BASE_NAME = RtPlatformStatusCodeLib +COMPONENT_TYPE = LIBRARY + +[sources.common] + RtPlatformStatusCode.c + +[includes.common] + $(EDK_SOURCE)\Foundation\Framework + $(EDK_SOURCE)\Foundation + $(EDK_SOURCE)\Foundation\Efi + . + $(EDK_SOURCE)\Sample\Platform\Generic\RuntimeDxe\StatusCode\Lib\Include + $(EDK_SOURCE)\Foundation\Include + $(EDK_SOURCE)\Foundation\Efi\Include + $(EDK_SOURCE)\Foundation\Framework\Include + $(EDK_SOURCE)\Foundation\Include\IndustryStandard + $(EDK_SOURCE)\Foundation\Core\Dxe + $(EDK_SOURCE)\Foundation\Library\Dxe\Include + +[libraries.common] + HobLib + RtMemoryStatusCodeLib + BsDataHubStatusCodeLib + +[nmake.common] -- 2.39.2