blob: 6618c9c72a7d3c90a11ab45690954c492535e6e1 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_FIRMWARE_GIGABOOT_SRC_BOOTBYTE_H_
#define SRC_FIRMWARE_GIGABOOT_SRC_BOOTBYTE_H_
#include <zircon/compiler.h>
__BEGIN_CDECLS
// flags and fields in RTC_BOOT_BYTE
#define RTC_BOOT_NORMAL 0x1u
#define RTC_BOOT_RECOVERY 0x2u
#define RTC_BOOT_BOOTLOADER 0x4u
#define RTC_BOOT_DEFAULT 0xFFu
#define RTC_BOOT_COUNT_MASK (0xf0u) // reboot_counter field mask
#ifdef GIGABOOT_HOST
// Fake bootbyte implementation for host tests.
// Make sure to call bootbyte_clear() after each test to avoid leaking state.
unsigned char bootbyte_read(void);
void bootbyte_clear(void);
void bootbyte_set_normal(void);
void bootbyte_set_recovery(void);
void bootbyte_set_bootloader(void);
// Extra test-only API.
void bootbyte_set_for_test(unsigned char value);
#else
#include <stdint.h>
// CMOS I/O port
#define RTC_BASE_PORT 0x70u
// CMOS register offset
#define RTC_BOOT_BYTE 48
// TODO(jonmayo): use a platform API instead of this hack
#if defined(__x86_64__)
static inline uint8_t inp(uint16_t _port) {
uint8_t rv;
__asm__ __volatile__("inb %1, %0" : "=a"(rv) : "dN"(_port));
return (rv);
}
static inline void outp(uint16_t _port, uint8_t _data) {
__asm__ __volatile__("outb %1, %0" : : "dN"(_port), "a"(_data));
}
static inline void rtc_write(unsigned char addr, unsigned char value) {
uint16_t ofs;
if (addr < 128) {
ofs = 0;
} else {
ofs = 2;
addr -= 128;
}
outp(RTC_BASE_PORT + ofs, addr);
outp(RTC_BASE_PORT + ofs + 1, value);
}
static inline unsigned char rtc_read(unsigned char addr) {
uint16_t ofs;
if (addr < 128) {
ofs = 0;
} else {
ofs = 2;
addr -= 128;
}
outp(RTC_BASE_PORT + ofs, addr);
return inp(RTC_BASE_PORT + ofs + 1);
}
static inline unsigned char bootbyte_read(void) { return rtc_read(RTC_BOOT_BYTE); }
static inline void bootbyte_clear(void) { rtc_write(RTC_BOOT_BYTE, RTC_BOOT_DEFAULT); }
static inline void bootbyte_set_normal(void) { rtc_write(RTC_BOOT_BYTE, RTC_BOOT_NORMAL); }
static inline void bootbyte_set_recovery(void) { rtc_write(RTC_BOOT_BYTE, RTC_BOOT_RECOVERY); }
static inline void bootbyte_set_bootloader(void) { rtc_write(RTC_BOOT_BYTE, RTC_BOOT_BOOTLOADER); }
#elif defined(__aarch64__)
// TODO(jonmayo): add support for aarch64. currently stubbed out with dummy behavior
static inline unsigned char bootbyte_read(void) { return 0xff; }
static inline void bootbyte_clear(void) {}
static inline void bootbyte_set_normal(void) {}
static inline void bootbyte_set_recovery(void) {}
static inline void bootbyte_set_bootloader(void) {}
#else
#error "add code for other arches here"
#endif
#endif // GIGABOOT_HOST
__END_CDECLS
#endif // SRC_FIRMWARE_GIGABOOT_SRC_BOOTBYTE_H_