
This commit removes all traces of Minix segments (the text/data/stack memory map abstraction in the kernel) and significance of Intel segments (hardware segments like CS, DS that add offsets to all addressing before page table translation). This ultimately simplifies the memory layout and addressing and makes the same layout possible on non-Intel architectures. There are only two types of addresses in the world now: virtual and physical; even the kernel and processes have the same virtual address space. Kernel and user processes can be distinguished at a glance as processes won't use 0xF0000000 and above. No static pre-allocated memory sizes exist any more. Changes to booting: . The pre_init.c leaves the kernel and modules exactly as they were left by the bootloader in physical memory . The kernel starts running using physical addressing, loaded at a fixed location given in its linker script by the bootloader. All code and data in this phase are linked to this fixed low location. . It makes a bootstrap pagetable to map itself to a fixed high location (also in linker script) and jumps to the high address. All code and data then use this high addressing. . All code/data symbols linked at the low addresses is prefixed by an objcopy step with __k_unpaged_*, so that that code cannot reference highly-linked symbols (which aren't valid yet) or vice versa (symbols that aren't valid any more). . The two addressing modes are separated in the linker script by collecting the unpaged_*.o objects and linking them with low addresses, and linking the rest high. Some objects are linked twice, once low and once high. . The bootstrap phase passes a lot of information (e.g. free memory list, physical location of the modules, etc.) using the kinfo struct. . After this bootstrap the low-linked part is freed. . The kernel maps in VM into the bootstrap page table so that VM can begin executing. Its first job is to make page tables for all other boot processes. So VM runs before RS, and RS gets a fully dynamic, VM-managed address space. VM gets its privilege info from RS as usual but that happens after RS starts running. . Both the kernel loading VM and VM organizing boot processes happen using the libexec logic. This removes the last reason for VM to still know much about exec() and vm/exec.c is gone. Further Implementation: . All segments are based at 0 and have a 4 GB limit. . The kernel is mapped in at the top of the virtual address space so as not to constrain the user processes. . Processes do not use segments from the LDT at all; there are no segments in the LDT any more, so no LLDT is needed. . The Minix segments T/D/S are gone and so none of the user-space or in-kernel copy functions use them. The copy functions use a process endpoint of NONE to realize it's a physical address, virtual otherwise. . The umap call only makes sense to translate a virtual address to a physical address now. . Segments-related calls like newmap and alloc_segments are gone. . All segments-related translation in VM is gone (vir2map etc). . Initialization in VM is simpler as no moving around is necessary. . VM and all other boot processes can be linked wherever they wish and will be mapped in at the right location by the kernel and VM respectively. Other changes: . The multiboot code is less special: it does not use mb_print for its diagnostics any more but uses printf() as normal, saving the output into the diagnostics buffer, only printing to the screen using the direct print functions if a panic() occurs. . The multiboot code uses the flexible 'free memory map list' style to receive the list of free memory if available. . The kernel determines the memory layout of the processes to a degree: it tells VM where the kernel starts and ends and where the kernel wants the top of the process to be. VM then uses this entire range, i.e. the stack is right at the top, and mmap()ped bits of memory are placed below that downwards, and the break grows upwards. Other Consequences: . Every process gets its own page table as address spaces can't be separated any more by segments. . As all segments are 0-based, there is no distinction between virtual and linear addresses, nor between userspace and kernel addresses. . Less work is done when context switching, leading to a net performance increase. (8% faster on my machine for 'make servers'.) . The layout and configuration of the GDT makes sysenter and syscall possible.
210 lines
6.4 KiB
C
210 lines
6.4 KiB
C
#ifndef _TYPE_H
|
|
#define _TYPE_H
|
|
#include <machine/multiboot.h>
|
|
|
|
#ifndef _MINIX_SYS_CONFIG_H
|
|
#include <minix/sys_config.h>
|
|
#endif
|
|
|
|
#ifndef _TYPES_H
|
|
#include <minix/types.h>
|
|
#endif
|
|
|
|
#include <minix/const.h>
|
|
#include <minix/com.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
/* Type definitions. */
|
|
typedef unsigned int vir_clicks; /* virtual addr/length in clicks */
|
|
typedef unsigned long phys_bytes; /* physical addr/length in bytes */
|
|
typedef unsigned int phys_clicks; /* physical addr/length in clicks */
|
|
typedef int endpoint_t; /* process identifier */
|
|
typedef int32_t cp_grant_id_t; /* A grant ID. */
|
|
typedef long unsigned int vir_bytes; /* virtual addresses/lengths in bytes */
|
|
|
|
/* Structure for virtual copying by means of a vector with requests. */
|
|
struct vir_addr {
|
|
endpoint_t proc_nr_e; /* NONE for phys, otherwise process endpoint */
|
|
vir_bytes offset;
|
|
};
|
|
|
|
#define phys_cp_req vir_cp_req
|
|
struct vir_cp_req {
|
|
struct vir_addr src;
|
|
struct vir_addr dst;
|
|
phys_bytes count;
|
|
};
|
|
|
|
/* Structures for SYS_VUMAP. */
|
|
struct vumap_vir {
|
|
union {
|
|
cp_grant_id_t u_grant; /* grant identifier, for non-SELF endpoint */
|
|
vir_bytes u_addr; /* local virtual address, for SELF endpoint */
|
|
} vv_u;
|
|
size_t vv_size; /* size in bytes */
|
|
};
|
|
#define vv_grant vv_u.u_grant
|
|
#define vv_addr vv_u.u_addr
|
|
|
|
struct vumap_phys {
|
|
phys_bytes vp_addr; /* physical address */
|
|
size_t vp_size; /* size in bytes */
|
|
};
|
|
|
|
/* I/O vector structures used in protocols between services. */
|
|
typedef struct {
|
|
vir_bytes iov_addr; /* address of an I/O buffer */
|
|
vir_bytes iov_size; /* sizeof an I/O buffer */
|
|
} iovec_t;
|
|
|
|
typedef struct {
|
|
cp_grant_id_t iov_grant; /* grant ID of an I/O buffer */
|
|
vir_bytes iov_size; /* sizeof an I/O buffer */
|
|
} iovec_s_t;
|
|
|
|
/* PM passes the address of a structure of this type to KERNEL when
|
|
* sys_sigsend() is invoked as part of the signal catching mechanism.
|
|
* The structure contain all the information that KERNEL needs to build
|
|
* the signal stack.
|
|
*/
|
|
struct sigmsg {
|
|
int sm_signo; /* signal number being caught */
|
|
unsigned long sm_mask; /* mask to restore when handler returns */
|
|
vir_bytes sm_sighandler; /* address of handler */
|
|
vir_bytes sm_sigreturn; /* address of _sigreturn in C library */
|
|
vir_bytes sm_stkptr; /* user stack pointer */
|
|
};
|
|
|
|
/* Load data accounted every this no. of seconds. */
|
|
#define _LOAD_UNIT_SECS 6 /* Changing this breaks ABI. */
|
|
|
|
/* Load data history is kept for this long. */
|
|
#define _LOAD_HISTORY_MINUTES 15 /* Changing this breaks ABI. */
|
|
#define _LOAD_HISTORY_SECONDS (60*_LOAD_HISTORY_MINUTES)
|
|
|
|
/* We need this many slots to store the load history. */
|
|
#define _LOAD_HISTORY (_LOAD_HISTORY_SECONDS/_LOAD_UNIT_SECS)
|
|
|
|
/* Runnable processes and other load-average information. */
|
|
struct loadinfo {
|
|
u16_t proc_load_history[_LOAD_HISTORY]; /* history of proc_s_cur */
|
|
u16_t proc_last_slot;
|
|
clock_t last_clock;
|
|
};
|
|
|
|
struct cpu_info {
|
|
u8_t vendor;
|
|
u8_t family;
|
|
u8_t model;
|
|
u8_t stepping;
|
|
u32_t freq; /* in MHz */
|
|
u32_t flags[2];
|
|
};
|
|
|
|
struct machine {
|
|
unsigned processors_count; /* how many cpus are available */
|
|
unsigned bsp_id; /* id of the bootstrap cpu */
|
|
int padding; /* used to be protected */
|
|
int apic_enabled; /* does the kernel use APIC or not? */
|
|
phys_bytes acpi_rsdp; /* where is the acpi RSDP */
|
|
};
|
|
|
|
struct io_range
|
|
{
|
|
unsigned ior_base; /* Lowest I/O port in range */
|
|
unsigned ior_limit; /* Highest I/O port in range */
|
|
};
|
|
|
|
struct mem_range
|
|
{
|
|
phys_bytes mr_base; /* Lowest memory address in range */
|
|
phys_bytes mr_limit; /* Highest memory address in range */
|
|
};
|
|
|
|
/* List of boot-time processes set in kernel/table.c. */
|
|
struct boot_image {
|
|
int proc_nr; /* process number to use */
|
|
char proc_name[PROC_NAME_LEN]; /* name in process table */
|
|
endpoint_t endpoint; /* endpoint number when started */
|
|
phys_bytes start_addr; /* Where it's in memory */
|
|
phys_bytes len;
|
|
};
|
|
|
|
/* Memory chunks. */
|
|
struct memory {
|
|
phys_bytes base;
|
|
phys_bytes size;
|
|
};
|
|
|
|
/* This is used to obtain system information through SYS_GETINFO. */
|
|
#define MAXMEMMAP 40
|
|
typedef struct kinfo {
|
|
/* Straight multiboot-provided info */
|
|
multiboot_info_t mbi;
|
|
multiboot_module_t module_list[MULTIBOOT_MAX_MODS];
|
|
multiboot_memory_map_t memmap[MAXMEMMAP]; /* free mem list */
|
|
phys_bytes mem_high_phys;
|
|
int mmap_size;
|
|
|
|
/* Multiboot-derived */
|
|
int mods_with_kernel; /* no. of mods incl kernel */
|
|
int kern_mod; /* which one is kernel */
|
|
|
|
/* Minix stuff, started at bootstrap phase */
|
|
int freepde_start; /* lowest pde unused kernel pde */
|
|
char param_buf[MULTIBOOT_PARAM_BUF_SIZE];
|
|
|
|
/* Minix stuff */
|
|
struct kmessages *kmess;
|
|
int do_serial_debug; /* system serial output */
|
|
int serial_debug_baud; /* serial baud rate */
|
|
int minix_panicing; /* are we panicing? */
|
|
vir_bytes user_sp; /* where does kernel want stack set */
|
|
vir_bytes user_end; /* upper proc limit */
|
|
vir_bytes vir_kern_start; /* kernel addrspace starts */
|
|
vir_bytes bootstrap_start, bootstrap_len;
|
|
struct boot_image boot_procs[NR_BOOT_PROCS];
|
|
int nr_procs; /* number of user processes */
|
|
int nr_tasks; /* number of kernel tasks */
|
|
char release[6]; /* kernel release number */
|
|
char version[6]; /* kernel version number */
|
|
} kinfo_t;
|
|
|
|
#define STATICINIT(v, n) \
|
|
if(!(v)) { \
|
|
if(!((v) = alloc_contig(sizeof(*(v)) * (n), 0, NULL))) { \
|
|
panic("allocating " #v " failed: %d", n); \
|
|
} \
|
|
}
|
|
|
|
/* The kernel outputs diagnostic messages in a circular buffer. */
|
|
struct kmessages {
|
|
int km_next; /* next index to write */
|
|
int km_size; /* current size in buffer */
|
|
char km_buf[_KMESS_BUF_SIZE]; /* buffer for messages */
|
|
char kmess_buf[80*25]; /* printable copy of message buffer */
|
|
int blpos; /* kmess_buf position */
|
|
};
|
|
|
|
#include <minix/config.h>
|
|
#include <machine/interrupt.h>
|
|
|
|
/* randomness struct: random sources after interrupts: */
|
|
#define RANDOM_SOURCES 16
|
|
#define RANDOM_ELEMENTS 64
|
|
|
|
typedef unsigned short rand_t;
|
|
|
|
struct k_randomness {
|
|
int random_elements, random_sources;
|
|
struct k_randomness_bin {
|
|
int r_next; /* next index to write */
|
|
int r_size; /* number of random elements */
|
|
rand_t r_buf[RANDOM_ELEMENTS]; /* buffer for random info */
|
|
} bin[RANDOM_SOURCES];
|
|
};
|
|
|
|
#endif /* _TYPE_H */
|
|
|