1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
/* tag: x86 context switching
*
* 2003-10 by SONE Takeshi
*
* See the file "COPYING" for further information about
* the copyright and warranty status of this work.
*/
#include "openbios/config.h"
#include "openbios/kernel.h"
#include "segment.h"
#include "context.h"
#include "sys_info.h"
#include "boot.h"
#define MAIN_STACK_SIZE 16384
#define IMAGE_STACK_SIZE 4096
#define debug printk
static void start_main(void); /* forward decl. */
void __exit_context(void); /* assembly routine */
/*
* Main context structure
* It is placed at the bottom of our stack, and loaded by assembly routine
* to start us up.
*/
static struct context main_ctx __attribute__((section (".initctx"))) = {
.gdt_base = (uint32_t) gdt,
.gdt_limit = GDT_LIMIT,
.cs = FLAT_CS,
.ds = FLAT_DS,
.es = FLAT_DS,
.fs = FLAT_DS,
.gs = FLAT_DS,
.ss = FLAT_DS,
.esp = (uint32_t) ESP_LOC(&main_ctx),
.eip = (uint32_t) start_main,
.return_addr = (uint32_t) __exit_context,
};
/* This is used by assembly routine to load/store the context which
* it is to switch/switched. */
struct context *__context = &main_ctx;
/* Stack for loaded ELF image */
static uint8_t image_stack[IMAGE_STACK_SIZE];
/* Pointer to startup context (physical address) */
unsigned long __boot_ctx;
/*
* Main starter
* This is the C function that runs first.
*/
static void start_main(void)
{
int retval;
extern int openbios(void);
extern void init_exceptions(void);
/* Save startup context, so we can refer to it later.
* We have to keep it in physical address since we will relocate. */
__boot_ctx = virt_to_phys(__context);
init_exceptions();
/* Start the real fun */
retval = openbios();
/* Pass return value to startup context. Bootloader may see it. */
boot_ctx->eax = retval;
/* Returning from here should jump to __exit_context */
__context = boot_ctx;
}
/* Setup a new context using the given stack.
*/
struct context *
init_context(uint8_t *stack, uint32_t stack_size, int num_params)
{
struct context *ctx;
ctx = (struct context *)
(stack + stack_size - (sizeof(*ctx) + num_params*sizeof(uint32_t)));
memset(ctx, 0, sizeof(*ctx));
/* Fill in reasonable default for flat memory model */
ctx->gdt_base = virt_to_phys(gdt);
ctx->gdt_limit = GDT_LIMIT;
ctx->cs = FLAT_CS;
ctx->ds = FLAT_DS;
ctx->es = FLAT_DS;
ctx->fs = FLAT_DS;
ctx->gs = FLAT_DS;
ctx->ss = FLAT_DS;
ctx->esp = virt_to_phys(ESP_LOC(ctx));
ctx->return_addr = virt_to_phys(__exit_context);
return ctx;
}
/* Switch to another context. */
struct context *switch_to(struct context *ctx)
{
struct context *save, *ret;
debug("switching to new context:\n");
save = __context;
__context = ctx;
asm ("pushl %cs; call __switch_context");
ret = __context;
__context = save;
return ret;
}
/* Start ELF Boot image */
unsigned int start_elf(unsigned long entry_point, unsigned long param)
{
struct context *ctx;
ctx = init_context(image_stack, sizeof image_stack, 1);
ctx->eip = entry_point;
ctx->param[0] = param;
ctx->eax = 0xe1fb007;
ctx->ebx = param;
ctx = switch_to(ctx);
return ctx->eax;
}
|