Axel Dörfler e5b0e0b5e3 Changed the set_segment_descriptor()'s usage of the limit/granularity
flag. Now, it will choose how to set the granularity by evaluating the
limit.
This call was actually already used this way in the kernel, so that
the TLS and TSS segments were much too large (harmless but incorrect).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12231 a95241bf-73f2-0310-859d-f6bbb57e9c96
2005-04-04 14:34:18 +00:00

138 lines
3.3 KiB
C

/*
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
** Distributed under the terms of the NewOS License.
*/
#ifndef _KERNEL_ARCH_x86_DESCRIPTORS_H
#define _KERNEL_ARCH_x86_DESCRIPTORS_H
#define KERNEL_CODE_SEG 0x8
#define KERNEL_DATA_SEG 0x10
#define USER_CODE_SEG 0x1b
#define USER_DATA_SEG 0x23
#ifndef _ASSEMBLER
// this file can also be included from assembler as well
// (and is in arch_interrupts.S)
#define DOUBLE_FAULT_TSS_SEGMENT 5
#define TSS_BASE_SEGMENT 6
#define TLS_BASE_SEGMENT (TSS_BASE_SEGMENT + smp_get_num_cpus())
// defines entries in the GDT/LDT
typedef struct segment_descriptor {
uint16 limit_00_15; // bit 0 - 15
uint16 base_00_15; // 16 - 31
uint32 base_23_16 : 8; // 0 - 7
uint32 type : 4; // 8 - 11
uint32 desc_type : 1; // 12 (0 = system, 1 = code/data)
uint32 privilege_level : 2; // 13 - 14
uint32 present : 1; // 15
uint32 limit_19_16 : 4; // 16 - 19
uint32 available : 1; // 20
uint32 zero : 1; // 21
uint32 d_b : 1; // 22
uint32 granularity : 1; // 23
uint32 base_31_24 : 8; // 24 - 31
} segment_descriptor;
enum descriptor_privilege_levels {
DPL_KERNEL = 0,
DPL_USER = 3,
};
enum descriptor_types {
// segment types
DT_CODE_EXECUTE_ONLY = 0x8,
DT_CODE_ACCESSED = 0x9,
DT_CODE_READABLE = 0xa,
DT_CODE_CONFORM = 0xc,
DT_DATA_READ_ONLY = 0x0,
DT_DATA_ACCESSED = 0x1,
DT_DATA_WRITEABLE = 0x2,
DT_DATA_EXPANSION_DOWN = 0x4,
DT_TSS = 9,
/* non busy, 32 bit */
// descriptor types
DT_SYSTEM_SEGMENT = 0,
DT_CODE_DATA_SEGMENT = 1,
};
static inline void
clear_segment_descriptor(struct segment_descriptor *desc)
{
*(long long *)desc = 0;
}
static inline void
set_segment_descriptor_base(struct segment_descriptor *desc, addr_t base)
{
desc->base_00_15 = (addr_t)base & 0xffff; // base is 32 bits long
desc->base_23_16 = ((addr_t)base >> 16) & 0xff;
desc->base_31_24 = ((addr_t)base >> 24) & 0xff;
}
static inline void
set_segment_descriptor(struct segment_descriptor *desc, addr_t base, uint32 limit,
uint8 type, uint8 privilegeLevel)
{
set_segment_descriptor_base(desc, base);
// limit is 20 bits long
if (limit & 0xfff00000) {
desc->limit_00_15 = ((addr_t)limit >> 12) & 0x0ffff;
desc->limit_19_16 = ((addr_t)limit >> 28) & 0xf;
desc->granularity = 1; // 4 KB granularity
} else {
desc->limit_00_15 = (addr_t)limit & 0x0ffff;
desc->limit_19_16 = ((addr_t)limit >> 16) & 0xf;
desc->granularity = 0; // 1 byte granularity
}
limit >>= 12;
desc->type = type;
desc->desc_type = DT_CODE_DATA_SEGMENT;
desc->privilege_level = privilegeLevel;
desc->present = 1;
desc->available = 0; // system available bit is currently not used
desc->d_b = 1; // 32-bit code
desc->zero = 0;
}
static inline void
set_tss_descriptor(struct segment_descriptor *desc, addr_t base, uint32 limit)
{
// the TSS descriptor has a special layout different from the standard descriptor
set_segment_descriptor_base(desc, base);
desc->limit_00_15 = (addr_t)limit & 0x0ffff;
desc->limit_19_16 = 0;
desc->type = DT_TSS;
desc->desc_type = DT_SYSTEM_SEGMENT;
desc->privilege_level = DPL_KERNEL;
desc->present = 1;
desc->granularity = 1; // 4 GB size (in page size steps)
desc->available = 0; // system available bit is currently not used
desc->d_b = 0;
desc->zero = 0;
}
#endif /* _ASSEMBLER */
#endif /* _KERNEL_ARCH_x86_DESCRIPTORS_H */