freebsd-dev/sys/boot/efi/libefi/time.c
Toomas Soome da8fb057e5 loader: network read rework
The current read from network is working from up to down - we have some
protocol needing the data from the network, so we build the buffer space
for that protocol, add the extra space for headers and pass this buffer
down to be filled by nif get call in hope, we have guessed the incoming
packet size right. Amazingly enough this approach mostly does work, but
not always...

So, this update does work from down to up - we allocate buffer (based
on MTU or frame size info), fill it up, and pass on for upper layers.
The obvious problem is that when we should free the buffer - if at all.

In the current implementation the upper layer will free the packet on error
or when the packet is no longer needed.

While working on the issue, the additional issue did pop up - the bios
implementation does not have generic get/put interface but is using pxe
udpsend/udpreceive instead. So the udp calls are gone and undi interface
is implemented instead. Which in turn means slight other changes as we
do not need to have duplicated pxe implementation and can just use dev_net.

To align packet content, the actual read from nic is using shifted buffer by
ETHER_ALIGN (2).

Reviewed by:	bapt
Differential Revision:	https://reviews.freebsd.org/D10232
2017-05-06 20:32:27 +00:00

235 lines
5.9 KiB
C

/*-
* Copyright (c) 1999, 2000
* Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by Intel Corporation and
* its contributors.
*
* 4. Neither the name of Intel Corporation or its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <efi.h>
#include <efilib.h>
#include <time.h>
#include <sys/time.h>
/*
// Accurate only for the past couple of centuries;
// that will probably do.
//
// (#defines From FreeBSD 3.2 lib/libc/stdtime/tzfile.h)
*/
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
#define SECSPERHOUR ( 60*60 )
#define SECSPERDAY (24 * SECSPERHOUR)
void
efi_time_init(void)
{
}
void
efi_time_fini(void)
{
}
static time_t
efi_time(EFI_TIME *ETime)
{
/*
// These arrays give the cumulative number of days up to the first of the
// month number used as the index (1 -> 12) for regular and leap years.
// The value at index 13 is for the whole year.
*/
static time_t CumulativeDays[2][14] = {
{0,
0,
31,
31 + 28,
31 + 28 + 31,
31 + 28 + 31 + 30,
31 + 28 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 },
{0,
0,
31,
31 + 29,
31 + 29 + 31,
31 + 29 + 31 + 30,
31 + 29 + 31 + 30 + 31,
31 + 29 + 31 + 30 + 31 + 30,
31 + 29 + 31 + 30 + 31 + 30 + 31,
31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }};
time_t UTime;
int Year;
/*
// Do a santity check
*/
if ( ETime->Year < 1998 || ETime->Year > 2099 ||
ETime->Month == 0 || ETime->Month > 12 ||
ETime->Day == 0 || ETime->Month > 31 ||
ETime->Hour > 23 ||
ETime->Minute > 59 ||
ETime->Second > 59 ||
ETime->TimeZone < -1440 ||
(ETime->TimeZone > 1440 && ETime->TimeZone != 2047) ) {
return (0);
}
/*
// Years
*/
UTime = 0;
for (Year = 1970; Year != ETime->Year; ++Year) {
UTime += (CumulativeDays[isleap(Year)][13] * SECSPERDAY);
}
/*
// UTime should now be set to 00:00:00 on Jan 1 of the file's year.
//
// Months
*/
UTime += (CumulativeDays[isleap(ETime->Year)][ETime->Month] * SECSPERDAY);
/*
// UTime should now be set to 00:00:00 on the first of the file's month and year
//
// Days -- Don't count the file's day
*/
UTime += (((ETime->Day > 0) ? ETime->Day-1:0) * SECSPERDAY);
/*
// Hours
*/
UTime += (ETime->Hour * SECSPERHOUR);
/*
// Minutes
*/
UTime += (ETime->Minute * 60);
/*
// Seconds
*/
UTime += ETime->Second;
/*
// EFI time is repored in local time. Adjust for any time zone offset to
// get true UT
*/
if ( ETime->TimeZone != EFI_UNSPECIFIED_TIMEZONE ) {
/*
// TimeZone is kept in minues...
*/
UTime += (ETime->TimeZone * 60);
}
return UTime;
}
static int
EFI_GetTimeOfDay(
OUT struct timeval *tp,
OUT struct timezone *tzp
)
{
EFI_TIME EfiTime;
EFI_TIME_CAPABILITIES Capabilities;
EFI_STATUS Status;
/*
// Get time from EFI
*/
Status = RS->GetTime(&EfiTime, &Capabilities);
if (EFI_ERROR(Status))
return (-1);
/*
// Convert to UNIX time (ie seconds since the epoch
*/
tp->tv_sec = efi_time( &EfiTime );
tp->tv_usec = 0; /* EfiTime.Nanosecond * 1000; */
/*
// Do something with the timezone if needed
*/
if (tzp) {
tzp->tz_minuteswest =
EfiTime.TimeZone == EFI_UNSPECIFIED_TIMEZONE ? 0 : EfiTime.TimeZone;
/*
// This isn't quit right since it doesn't deal with EFI_TIME_IN_DAYLIGHT
*/
tzp->tz_dsttime =
EfiTime.Daylight & EFI_TIME_ADJUST_DAYLIGHT ? 1 : 0;
}
return (0);
}
time_t
time(time_t *tloc)
{
struct timeval tv;
EFI_GetTimeOfDay(&tv, 0);
if (tloc)
*tloc = tv.tv_sec;
return tv.tv_sec;
}
time_t
getsecs(void)
{
return time(NULL);
}