1 /** @file 2 Support functions for UEFI protocol notification infrastructure. 3 4 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials are licensed and made available 6 under the terms and conditions of the BSD License which accompanies this 7 distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include "PiSmmCore.h" 16 17 /** 18 Signal event for every protocol in protocol entry. 19 20 @param Prot Protocol interface 21 22 **/ 23 VOID 24 SmmNotifyProtocol ( 25 IN PROTOCOL_INTERFACE *Prot 26 ) 27 { 28 PROTOCOL_ENTRY *ProtEntry; 29 PROTOCOL_NOTIFY *ProtNotify; 30 LIST_ENTRY *Link; 31 32 ProtEntry = Prot->Protocol; 33 for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) { 34 ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE); 35 ProtNotify->Function (&ProtEntry->ProtocolID, Prot->Interface, Prot->Handle); 36 } 37 } 38 39 /** 40 Removes Protocol from the protocol list (but not the handle list). 41 42 @param Handle The handle to remove protocol on. 43 @param Protocol GUID of the protocol to be moved 44 @param Interface The interface of the protocol 45 46 @return Protocol Entry 47 48 **/ 49 PROTOCOL_INTERFACE * 50 SmmRemoveInterfaceFromProtocol ( 51 IN IHANDLE *Handle, 52 IN EFI_GUID *Protocol, 53 IN VOID *Interface 54 ) 55 { 56 PROTOCOL_INTERFACE *Prot; 57 PROTOCOL_NOTIFY *ProtNotify; 58 PROTOCOL_ENTRY *ProtEntry; 59 LIST_ENTRY *Link; 60 61 Prot = SmmFindProtocolInterface (Handle, Protocol, Interface); 62 if (Prot != NULL) { 63 64 ProtEntry = Prot->Protocol; 65 66 // 67 // If there's a protocol notify location pointing to this entry, back it up one 68 // 69 for(Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) { 70 ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE); 71 72 if (ProtNotify->Position == &Prot->ByProtocol) { 73 ProtNotify->Position = Prot->ByProtocol.BackLink; 74 } 75 } 76 77 // 78 // Remove the protocol interface entry 79 // 80 RemoveEntryList (&Prot->ByProtocol); 81 } 82 83 return Prot; 84 } 85 86 /** 87 Add a new protocol notification record for the request protocol. 88 89 @param Protocol The requested protocol to add the notify 90 registration 91 @param Function Points to the notification function 92 @param Registration Returns the registration record 93 94 @retval EFI_SUCCESS Successfully returned the registration record 95 that has been added or unhooked 96 @retval EFI_INVALID_PARAMETER Protocol is NULL or Registration is NULL 97 @retval EFI_OUT_OF_RESOURCES Not enough memory resource to finish the request 98 @retval EFI_NOT_FOUND If the registration is not found when Function == NULL 99 100 **/ 101 EFI_STATUS 102 EFIAPI 103 SmmRegisterProtocolNotify ( 104 IN CONST EFI_GUID *Protocol, 105 IN EFI_SMM_NOTIFY_FN Function, 106 OUT VOID **Registration 107 ) 108 { 109 PROTOCOL_ENTRY *ProtEntry; 110 PROTOCOL_NOTIFY *ProtNotify; 111 LIST_ENTRY *Link; 112 EFI_STATUS Status; 113 114 if (Protocol == NULL || Registration == NULL) { 115 return EFI_INVALID_PARAMETER; 116 } 117 118 if (Function == NULL) { 119 // 120 // Get the protocol entry per Protocol 121 // 122 ProtEntry = SmmFindProtocolEntry ((EFI_GUID *) Protocol, FALSE); 123 if (ProtEntry != NULL) { 124 ProtNotify = (PROTOCOL_NOTIFY * )*Registration; 125 for (Link = ProtEntry->Notify.ForwardLink; 126 Link != &ProtEntry->Notify; 127 Link = Link->ForwardLink) { 128 // 129 // Compare the notification record 130 // 131 if (ProtNotify == (CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE))){ 132 // 133 // If Registration is an existing registration, then unhook it 134 // 135 ProtNotify->Signature = 0; 136 RemoveEntryList (&ProtNotify->Link); 137 FreePool (ProtNotify); 138 return EFI_SUCCESS; 139 } 140 } 141 } 142 // 143 // If the registration is not found 144 // 145 return EFI_NOT_FOUND; 146 } 147 148 ProtNotify = NULL; 149 150 // 151 // Get the protocol entry to add the notification too 152 // 153 ProtEntry = SmmFindProtocolEntry ((EFI_GUID *) Protocol, TRUE); 154 if (ProtEntry != NULL) { 155 // 156 // Find whether notification already exist 157 // 158 for (Link = ProtEntry->Notify.ForwardLink; 159 Link != &ProtEntry->Notify; 160 Link = Link->ForwardLink) { 161 162 ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE); 163 if (CompareGuid (&ProtNotify->Protocol->ProtocolID, Protocol) && 164 (ProtNotify->Function == Function)) { 165 166 // 167 // Notification already exist 168 // 169 *Registration = ProtNotify; 170 171 return EFI_SUCCESS; 172 } 173 } 174 175 // 176 // Allocate a new notification record 177 // 178 ProtNotify = AllocatePool (sizeof(PROTOCOL_NOTIFY)); 179 if (ProtNotify != NULL) { 180 ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE; 181 ProtNotify->Protocol = ProtEntry; 182 ProtNotify->Function = Function; 183 // 184 // Start at the ending 185 // 186 ProtNotify->Position = ProtEntry->Protocols.BackLink; 187 188 InsertTailList (&ProtEntry->Notify, &ProtNotify->Link); 189 } 190 } 191 192 // 193 // Done. If we have a protocol notify entry, then return it. 194 // Otherwise, we must have run out of resources trying to add one 195 // 196 Status = EFI_OUT_OF_RESOURCES; 197 if (ProtNotify != NULL) { 198 *Registration = ProtNotify; 199 Status = EFI_SUCCESS; 200 } 201 return Status; 202 } 203