blob: 80271316aa675491f48f3be1b5159c906bedaf39 [file] [log] [blame] [edit]
// Copyright 2020 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#ifndef ZIRCON_KERNEL_LIB_ARCH_INCLUDE_LIB_ARCH_X86_DESCRIPTOR_H_
#define ZIRCON_KERNEL_LIB_ARCH_INCLUDE_LIB_ARCH_X86_DESCRIPTOR_H_
#include <hwreg/bitfields.h>
namespace arch {
// This represents the 32-bit descriptor format in the GDT or LDT.
// The 64-bit descriptor format below extends this. The low 32 bits
// are laid out the same in both formats.
struct Desc32 {
// These raw fields are normally accessed via the accessors defined below.
uint32_t limit_base_lo16;
uint32_t flags_base_hi16;
enum SegmentSystem : uint32_t {
SYSTEM = 0,
NONSYSTEM = 1,
};
enum SegmentType : uint32_t {
DATA_RO = 0b000,
DATA_RW = 0b001,
DATA_RO_DOWN = 0b010,
DATA_RW_DOWN = 0b011,
CODE_XO = 0b100,
CODE_RX = 0b101,
CODE_XO_CONFORMING = 0b110,
CODE_RX_CONFORMING = 0b111,
};
DEF_SUBFIELD(limit_base_lo16, 15, 0, limit_lo16);
DEF_SUBFIELD(limit_base_lo16, 31, 16, base_lo16);
DEF_SUBFIELD(flags_base_hi16, 7, 0, base_mid8);
DEF_ENUM_SUBFIELD(flags_base_hi16, SegmentType, 11, 9, type);
DEF_SUBBIT(flags_base_hi16, 8, accessed);
DEF_ENUM_SUBFIELD(flags_base_hi16, SegmentSystem, 12, 12, system);
DEF_SUBFIELD(flags_base_hi16, 14, 13, dpl);
DEF_SUBBIT(flags_base_hi16, 15, present);
DEF_SUBFIELD(flags_base_hi16, 19, 16, limit_hi4);
DEF_SUBBIT(flags_base_hi16, 20, avl);
DEF_SUBBIT(flags_base_hi16, 21, long_mode);
DEF_SUBBIT(flags_base_hi16, 22, addr32);
DEF_SUBBIT(flags_base_hi16, 23, granularity);
DEF_SUBFIELD(flags_base_hi16, 31, 24, base_hi8);
// The 32-bit base address is split across three fields.
constexpr uint32_t base() const { return base_lo16() | (base_mid8() << 16) | (base_hi8() << 24); }
constexpr auto& set_base(uint32_t base) {
set_base_lo16(base & 0xffff);
set_base_mid8((base >> 16) & 0xff);
set_base_hi8(base >> 24);
return *this;
}
// A segment's limit is the the size of the memory range starting at the
// base address, minus one. The 20-bit limit field is split across two
// fields, plus the granularity flag determines whether it's scaled by 12
// bits. The limit() and set_limit() accessors take a whole unscaled 32-bit
// value. If the low bits are 0xfff, then it's stored as a scaled value that
// can represent the full 32-bit size (with 4k granularity). Otherwise, it's
// stored unscaled and only has 20 bits (with byte granularity: max 1MB - 1).
constexpr auto limit() const {
return (limit_lo16() | (limit_hi4() << 16)) << (granularity() ? 12 : 0);
}
constexpr auto& set_limit(uint32_t value) {
// There are only 20 bits for the limit, so a byte-granularity limit can
// only go up to 2MB - 1 byte. If the granularity flag is set, then the
// limit is scaled up by 4KB and the low 12 bits are treated as all ones.
// So if the low bits of the intended 32-bit limit are all ones, then the
// limit can go up to 4GB - 1. Otherwise, it can only go up to 2MB - 1.
if ((value & 0xfff) == 0xfff) {
set_granularity(true);
value >>= 12;
} else {
set_granularity(false);
}
set_limit_lo16(value & 0xffff);
set_limit_hi4(value >> 16);
return *this;
}
// Non-system segments are most often "flat", i.e. base 0 and maximum size.
constexpr auto& make_flat() {
set_present(true);
set_system(arch::Desc32::SegmentSystem::NONSYSTEM);
set_addr32(true);
set_base(0);
set_limit(~uint32_t{0});
return *this;
}
};
// This represents the 64-bit descriptor format in the GDT or LDT. It's the
// same as the 32-bit format except for having a 64-bit base address. It
// inherits all the other fields from Desc32 and overrides the base accessors
// with a 64-bit version.
struct Desc64 : public Desc32 {
uint32_t base_hi32;
uint32_t rsvdz;
constexpr uint64_t base() const {
return (static_cast<uint64_t>(base_hi32) << 32) | Desc32::base();
}
constexpr auto& set_base(uint64_t base) {
base_hi32 = static_cast<uint32_t>(base >> 32);
return Desc32::set_base(static_cast<uint32_t>(base));
}
};
} // namespace arch
#endif // ZIRCON_KERNEL_LIB_ARCH_INCLUDE_LIB_ARCH_X86_DESCRIPTOR_H_