1 /*++ 2 Emu RTC Architectural Protocol Driver as defined in PI 3 4 Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR> 5 Portions copyright (c) 2010 - 2011, Apple Inc. All rights reserved. 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 #include <PiDxe.h> 16 17 #include <Library/BaseLib.h> 18 #include <Library/DebugLib.h> 19 #include <Library/UefiLib.h> 20 #include <Library/UefiDriverEntryPoint.h> 21 #include <Library/EmuThunkLib.h> 22 #include <Library/MemoryAllocationLib.h> 23 #include <Library/UefiBootServicesTableLib.h> 24 25 #include <Protocol/RealTimeClock.h> 26 27 BOOLEAN 28 DayValid ( 29 IN EFI_TIME *Time 30 ); 31 32 BOOLEAN 33 IsLeapYear ( 34 IN EFI_TIME *Time 35 ); 36 37 EFI_STATUS 38 RtcTimeFieldsValid ( 39 IN EFI_TIME *Time 40 ); 41 42 EFI_STATUS 43 EFIAPI 44 InitializeRealTimeClock ( 45 IN EFI_HANDLE ImageHandle, 46 IN EFI_SYSTEM_TABLE *SystemTable 47 ); 48 49 EFI_STATUS 50 EFIAPI 51 EmuGetTime ( 52 OUT EFI_TIME * Time, 53 OUT EFI_TIME_CAPABILITIES * Capabilities OPTIONAL 54 ) 55 /*++ 56 57 Routine Description: 58 Service routine for RealTimeClockInstance->GetTime 59 60 Arguments: 61 62 Time - A pointer to storage that will receive a snapshot of the current time. 63 64 Capabilities - A pointer to storage that will receive the capabilities of the real time clock 65 in the platform. This includes the real time clock's resolution and accuracy. 66 All reported device capabilities are rounded up. This is an OPTIONAL argument. 67 68 Returns: 69 70 EFI_SUCEESS - The underlying GetSystemTime call occurred and returned 71 Note that in the NT32 emulation, the GetSystemTime call has no return value 72 thus you will always receive a EFI_SUCCESS on this. 73 74 **/ 75 { 76 77 // 78 // Check parameter for null pointer 79 // 80 if (Time == NULL) { 81 return EFI_INVALID_PARAMETER; 82 83 } 84 85 gEmuThunk->GetTime (Time, Capabilities); 86 87 return EFI_SUCCESS; 88 } 89 90 EFI_STATUS 91 EFIAPI 92 EmuSetTime ( 93 IN EFI_TIME *Time 94 ) 95 /*++ 96 97 Routine Description: 98 Service routine for RealTimeClockInstance->SetTime 99 100 Arguments: 101 102 Time - A pointer to storage containing the time and date information to 103 program into the real time clock. 104 105 Returns: 106 107 EFI_SUCEESS - The operation completed successfully. 108 109 EFI_INVALID_PARAMETER - One of the fields in Time is out of range. 110 111 EFI_DEVICE_ERROR - The operation could not be complete due to a device error. 112 113 **/ 114 { 115 EFI_STATUS Status; 116 117 if (Time == NULL) { 118 return EFI_INVALID_PARAMETER; 119 } 120 // 121 // Make sure that the time fields are valid 122 // 123 Status = RtcTimeFieldsValid (Time); 124 if (EFI_ERROR (Status)) { 125 return Status; 126 } 127 return EFI_UNSUPPORTED; 128 } 129 130 EFI_STATUS 131 EFIAPI 132 EmuGetWakeupTime ( 133 OUT BOOLEAN *Enabled, 134 OUT BOOLEAN *Pending, 135 OUT EFI_TIME *Time 136 ) 137 /*++ 138 139 Routine Description: 140 Service routine for RealTimeClockInstance->GetWakeupTime 141 142 Arguments: 143 This - Indicates the protocol instance structure. 144 145 Enabled - Indicates if the alarm is currently enabled or disabled. 146 147 Pending - Indicates if the alarm signal is pending and requires 148 acknowledgement. 149 150 Time - The current alarm setting. 151 152 Returns: 153 154 EFI_SUCEESS - The operation completed successfully. 155 156 EFI_DEVICE_ERROR - The operation could not be complete due to a device error. 157 158 EFI_UNSUPPORTED - The operation is not supported on this platform. 159 160 **/ 161 { 162 return EFI_UNSUPPORTED; 163 } 164 165 EFI_STATUS 166 EFIAPI 167 EmuSetWakeupTime ( 168 IN BOOLEAN Enable, 169 OUT EFI_TIME *Time 170 ) 171 /*++ 172 173 Routine Description: 174 Service routine for RealTimeClockInstance->SetWakeupTime 175 176 Arguments: 177 178 Enabled - Enable or disable the wakeup alarm. 179 180 Time - If enable is TRUE, the time to set the wakup alarm for. 181 If enable is FALSE, then this parameter is optional, and 182 may be NULL. 183 184 Returns: 185 186 EFI_SUCEESS - The operation completed successfully. 187 188 EFI_DEVICE_ERROR - The operation could not be complete due to a device error. 189 190 EFI_INVALID_PARAMETER - A field in Time is out of range. 191 192 EFI_UNSUPPORTED - The operation is not supported on this platform. 193 194 **/ 195 { 196 return EFI_UNSUPPORTED; 197 } 198 199 EFI_STATUS 200 EFIAPI 201 InitializeRealTimeClock ( 202 IN EFI_HANDLE ImageHandle, 203 IN EFI_SYSTEM_TABLE *SystemTable 204 ) 205 /*++ 206 207 Routine Description: 208 Install Real Time Clock Protocol 209 210 Arguments: 211 ImageHandle - Image Handle 212 SystemTable - Pointer to system table 213 214 Returns: 215 216 EFI_SUCEESS - Real Time Clock Services are installed into the Runtime Services Table 217 218 **/ 219 { 220 EFI_STATUS Status; 221 EFI_HANDLE Handle; 222 223 SystemTable->RuntimeServices->GetTime = EmuGetTime; 224 SystemTable->RuntimeServices->SetTime = EmuSetTime; 225 SystemTable->RuntimeServices->GetWakeupTime = EmuGetWakeupTime; 226 SystemTable->RuntimeServices->SetWakeupTime = EmuSetWakeupTime; 227 228 Handle = NULL; 229 Status = gBS->InstallMultipleProtocolInterfaces ( 230 &Handle, 231 &gEfiRealTimeClockArchProtocolGuid, 232 NULL, 233 NULL 234 ); 235 return Status; 236 } 237 238 EFI_STATUS 239 RtcTimeFieldsValid ( 240 IN EFI_TIME *Time 241 ) 242 /*++ 243 244 Routine Description: 245 246 Arguments: 247 248 Returns: 249 **/ 250 { 251 if (Time->Year < 1998 || 252 Time->Year > 2099 || 253 Time->Month < 1 || 254 Time->Month > 12 || 255 (!DayValid (Time)) || 256 Time->Hour > 23 || 257 Time->Minute > 59 || 258 Time->Second > 59 || 259 Time->Nanosecond > 999999999 || 260 (!(Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE || (Time->TimeZone >= -1440 && Time->TimeZone <= 1440))) || 261 (Time->Daylight & (~(EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT))) 262 ) { 263 return EFI_INVALID_PARAMETER; 264 } 265 266 return EFI_SUCCESS; 267 } 268 269 BOOLEAN 270 DayValid ( 271 IN EFI_TIME *Time 272 ) 273 { 274 275 STATIC const INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 276 277 if (Time->Day < 1 || 278 Time->Day > DayOfMonth[Time->Month - 1] || 279 (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28)) 280 ) { 281 return FALSE; 282 } 283 284 return TRUE; 285 } 286 287 BOOLEAN 288 IsLeapYear ( 289 IN EFI_TIME *Time 290 ) 291 { 292 if (Time->Year % 4 == 0) { 293 if (Time->Year % 100 == 0) { 294 if (Time->Year % 400 == 0) { 295 return TRUE; 296 } else { 297 return FALSE; 298 } 299 } else { 300 return TRUE; 301 } 302 } else { 303 return FALSE; 304 } 305 } 306