Skip to content

Commit

Permalink
x86: generate RAM-based GDT dynamically
Browse files Browse the repository at this point in the history
We will need this for stack memory protection scenarios
where a writable GDT with Task State Segment descriptors
will be used. The addresses of the TSS segments cannot be
put in the GDT via preprocessor magic due to architecture
requirments that the address be split up into different
fields in the segment descriptor.

Signed-off-by: Andrew Boie <[email protected]>
  • Loading branch information
Andrew Boie authored and Anas Nashif committed Jul 25, 2017
1 parent 8a102e4 commit 08c2913
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 42 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,9 @@ include $(srctree)/arch/x86/Makefile.idt
ifeq ($(CONFIG_X86_MMU),y)
include $(srctree)/arch/x86/Makefile.mmu
endif
ifeq ($(CONFIG_GDT_DYNAMIC),y)
include $(srctree)/arch/x86/Makefile.gdt
endif
endif

ifeq ($(CONFIG_GEN_ISR_TABLES),y)
Expand Down
26 changes: 26 additions & 0 deletions arch/x86/Makefile.gdt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
ifeq ($(KBUILD_VERBOSE),1)
GENGDT_EXTRA_ARGS := --verbose
else
GENGDT_EXTRA_ARGS :=
endif

GENGDT := $(srctree)/scripts/gen_gdt.py

OUTPUT_FORMAT ?= elf32-i386
OUTPUT_ARCH ?= i386

quiet_cmd_gen_gdt = GDT $@
cmd_gen_gdt = \
( \
$(GENGDT) --kernel $(PREBUILT_KERNEL) \
--output-gdt gdt.bin \
$(GENGDT_EXTRA_ARGS) && \
$(OBJCOPY) -I binary -B $(OUTPUT_ARCH) -O $(OUTPUT_FORMAT) \
--rename-section .data=gdt_ram_data gdt.bin $@ \
)

gdt.o: $(PREBUILT_KERNEL) $(GENGDT)
$(call cmd,gen_gdt)

GENERATED_KERNEL_OBJECT_FILES += gdt.o

1 change: 0 additions & 1 deletion arch/x86/core/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ obj-y += cpuhalt.o \

obj-$(CONFIG_IRQ_OFFLOAD) += irq_offload.o
obj-$(CONFIG_FP_SHARING) += float.o
obj-$(CONFIG_GDT_DYNAMIC) += gdt.o
obj-$(CONFIG_REBOOT_RST_CNT) += reboot_rst_cnt.o
obj-$(CONFIG_X86_MMU) += x86_mmu.o

Expand Down
40 changes: 0 additions & 40 deletions arch/x86/core/gdt.c

This file was deleted.

13 changes: 13 additions & 0 deletions include/arch/x86/linker.ld
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,19 @@ SECTIONS
#include <custom-rwdata.ld>
#endif

#ifdef CONFIG_GDT_DYNAMIC
. = ALIGN(8);
_gdt = .;
#ifdef LINKER_PASS2
KEEP(*(gdt_ram_data))
#else /* LINKER_PASS2 */

#define GDT_NUM_ENTRIES 3

. += GDT_NUM_ENTRIES * 8;
#endif /* LINKER_PASS2 */
#endif /* CONFIG_GDT_DYNAMIC */

#ifdef CONFIG_X86_MMU
/* Page Tables are located here if MMU is enabled.*/
MMU_PAGE_ALIGN
Expand Down
2 changes: 1 addition & 1 deletion include/arch/x86/segmentation.h
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ struct __packed far_ptr {
#define DT_INIT(entries) { sizeof(entries) - 1, &entries[0] }

#ifdef CONFIG_SET_GDT
/* This is either the ROM-based GDT in crt0.S or RAM-based in gdt.c,
/* This is either the ROM-based GDT in crt0.S or generated by gen_gdt.py,
* depending on CONFIG_GDT_DYNAMIC
*/
extern struct pseudo_descriptor _gdt;
Expand Down
117 changes: 117 additions & 0 deletions scripts/gen_gdt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/usr/bin/env python3
#
# Copyright (c) 2017 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0

import argparse
import sys
import struct
import os
from elftools.elf.elffile import ELFFile
from elftools.elf.sections import SymbolTableSection

gdt_pd_fmt = "<HIH"

FLAGS_GRAN = 1 << 7 # page granularity
ACCESS_EX = 1 << 3 # executable
ACCESS_DC = 1 << 2 # direction/conforming
ACCESS_RW = 1 << 1 # read or write permission

# 6 byte pseudo descriptor, but we're going to actually use this as the
# zero descriptor and return 8 bytes
def create_gdt_pseudo_desc(addr, size):
# ...and take back one byte for the Intel god whose Ark this is...
size = size - 1
return struct.pack(gdt_pd_fmt, size, addr, 0)


# Limit argument always in bytes
def chop_base_limit(base, limit):
base_lo = base & 0xFFFF
base_mid = (base >> 16) & 0xFF
base_hi = (base >> 24) & 0xFF

limit_lo = limit & 0xFFFF
limit_hi = (limit >> 16) & 0xF

return (base_lo, base_mid, base_hi, limit_lo, limit_hi)


gdt_ent_fmt = "<HHBBBB"

def create_code_data_entry(base, limit, dpl, flags, access):
base_lo, base_mid, base_hi, limit_lo, limit_hi = chop_base_limit(base,
limit)

# This is a valid descriptor
present = 1

# 32-bit protected mode
size = 1

# 1 = code or data, 0 = system type
desc_type = 1

# Just set accessed to 1 already so the CPU doesn't need it update it,
# prevents freakouts if the GDT is in ROM, we don't care about this
# bit in the OS
accessed = 1

access = access | (present << 7) | (desc_type << 4) | accessed
flags = flags | (size << 6) | limit_hi

return struct.pack(gdt_ent_fmt, limit_lo, base_lo, base_mid,
access, flags, base_hi)


def get_symbols(obj):
for section in obj.iter_sections():
if isinstance(section, SymbolTableSection):
return {sym.name: sym.entry.st_value
for sym in section.iter_symbols()}

raise LookupError("Could not find symbol table")


def parse_args():
global args
parser = argparse.ArgumentParser(description = __doc__,
formatter_class = argparse.RawDescriptionHelpFormatter)

parser.add_argument("-k", "--kernel", required=True,
help="Zephyr kernel image")
parser.add_argument("-v", "--verbose", action="store_true",
help="Print extra debugging information")
parser.add_argument("-o", "--output-gdt", required=True,
help="output GDT binary")
args = parser.parse_args()


def main():
parse_args()

with open(args.kernel, "rb") as fp:
kernel = ELFFile(fp)
syms = get_symbols(kernel)

num_entries = 3

gdt_base = syms["_gdt"]

with open(args.output_gdt, "wb") as fp:
# The pseudo descriptor is stuffed into the NULL descriptor
# since the CPU never looks at it
fp.write(create_gdt_pseudo_desc(gdt_base, num_entries * 8))

# Selector 0x08: code descriptor
fp.write(create_code_data_entry(0, 0xFFFFF, 0,
FLAGS_GRAN, ACCESS_EX | ACCESS_RW))

# Selector 0x10: data descriptor
fp.write(create_code_data_entry(0, 0xFFFFF, 0,
FLAGS_GRAN, ACCESS_RW))

if __name__ == "__main__":
main()

0 comments on commit 08c2913

Please sign in to comment.