123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- /*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 2016 Free Software Foundation, Inc.
- *
- * GRUB is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GRUB is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <grub/random.h>
- #include <grub/i386/io.h>
- #include <grub/i386/tsc.h>
- #include <grub/i386/pmtimer.h>
- #include <grub/acpi.h>
- static int have_tsc = -1, have_pmtimer = -1;
- static grub_port_t pmtimer_port;
- static int
- detect_pmtimer (void)
- {
- struct grub_acpi_fadt *fadt;
- fadt = grub_acpi_find_fadt ();
- if (!fadt)
- return 0;
- pmtimer_port = fadt->pmtimer;
- if (!pmtimer_port)
- return 0;
- return 1;
- }
- static int
- pmtimer_tsc_get_random_bit (void)
- {
- /* It's hard to come up with figures about pmtimer and tsc jitter but
- 50 ppm seems to be typical. So we need 10^6/50 tsc cycles to get drift
- of one tsc cycle. With TSC at least of 800 MHz it means 1/(50*800)
- = 1/40000 s or about 3579545 / 40000 = 90 pmtimer ticks.
- This gives us rate of 40000 bit/s or 5 kB/s.
- */
- grub_uint64_t tsc_diff;
- tsc_diff = grub_pmtimer_wait_count_tsc (pmtimer_port, 90);
- if (tsc_diff == 0)
- {
- have_pmtimer = 0;
- return -1;
- }
- return tsc_diff & 1;
- }
- static int
- pmtimer_tsc_get_random_byte (void)
- {
- grub_uint8_t ret = 0;
- int i, c;
- for (i = 0; i < 8; i++)
- {
- c = pmtimer_tsc_get_random_bit ();
- if (c < 0)
- return -1;
- ret |= c << i;
- }
- return ret;
- }
- static int
- pmtimer_fill_buffer (void *buffer, grub_size_t sz)
- {
- grub_uint8_t *p = buffer;
- int c;
- while (sz)
- {
- c = pmtimer_tsc_get_random_byte ();
- if (c < 0)
- return 0;
- *p++ = c;
- sz--;
- }
- return 1;
- }
- int
- grub_crypto_arch_get_random (void *buffer, grub_size_t sz)
- {
- if (have_tsc == -1)
- have_tsc = grub_cpu_is_tsc_supported ();
- if (!have_tsc)
- return 0;
- if (have_pmtimer == -1)
- have_pmtimer = detect_pmtimer ();
- if (!have_pmtimer)
- return 0;
- return pmtimer_fill_buffer (buffer, sz);
- }
|