Implement coroutines and test HTTP client.

parent 04ec27ab
Subproject commit 0a321290c2e2f1ab6c52a0ddbf03f746d2a0c479
Subproject commit cb3160d723851dfe2655ed6406d08cbbcfd17c68
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include <setjmp.h>
typedef struct {
bool runnable;
void *stack;
void (*target)(void*);
void *ctx;
jmp_buf caller_regs;
jmp_buf callee_regs;
} coro_t;
coro_t *curr_coro;
void coro_enter(coro_t *coro) {
_force_assert(!curr_coro);
_force_assert(coro->runnable);
curr_coro = coro;
if (setjmp(coro->caller_regs) == 0) {
longjmp(coro->callee_regs, 1);
}
curr_coro = NULL;
}
void coro_yield() {
coro_t *coro = curr_coro;
_force_assert(coro);
_force_assert(curr_coro);
if (setjmp(coro->callee_regs) == 0) {
longjmp(coro->caller_regs, 1);
}
}
void coro_wrapper() {
coro_t *coro = curr_coro;
_force_assert(coro);
coro->target(coro->ctx);
coro->runnable = false;
coro_yield();
// We should not arrive here, because we cannot return!
_force_assert(false);
}
coro_t *coro_init_with_stack_size(void (*target)(void*), void *ctx, size_t stack_size) {
coro_t *ret = malloc(sizeof(coro_t));
memset(ret, 0, sizeof(coro_t));
ret->runnable = true;
ret->stack = malloc(stack_size);
ret->target = target;
ret->ctx = ctx;
ret->callee_regs.esp = ((unsigned long) ret->stack) + stack_size;
ret->callee_regs.eip = (unsigned long) &coro_wrapper;
return ret;
}
coro_t *coro_init(void (*target)(void*), void *ctx) {
return coro_init_with_stack_size(target, ctx, 65536);
}
void coro_destroy(coro_t *coro) {
free(coro->stack);
free(coro);
}
#include "ipxe_handover.h"
int main(void);
void *get_table_start(const char *name);
void *get_table_end(const char *name);
void *asmc_malloc(size_t size);
void asmc_free(void *ptr);
void push_to_asmc(void *msg);
void *pop_from_asmc(void);
void coro_yield(void);
#ifndef __IPXE_HANDOVER_H
#define __IPXE_HANDOVER_H
#ifndef __ASMC_TYPES_H
typedef unsigned int size_t;
#endif
typedef struct {
char *name;
......@@ -5,7 +11,61 @@ typedef struct {
int len;
} table_sect;
typedef struct ipxe_list_elem {
struct ipxe_list_elem *next;
void *msg;
} ipxe_list_elem;
typedef struct ipxe_list {
ipxe_list_elem *head;
ipxe_list_elem *tail;
} ipxe_list;
typedef struct {
int sects_num;
table_sect *sects;
ipxe_list to_ipxe;
ipxe_list from_ipxe;
void (*coro_yield)();
void *(*malloc)(size_t size);
void (*free)(void *ptr);
} ipxe_handover;
static void ipxe_list_reset(ipxe_list *list) {
list->head = 0;
list->tail = 0;
}
static void ipxe_list_push(ipxe_handover *ih, ipxe_list *list, void *msg) {
ipxe_list_elem *e = ih->malloc(sizeof(ipxe_list_elem));
e->next = 0;
e->msg = msg;
if (!list->head) {
// Empty list, this is the first and last item
list->head = e;
list->tail = e;
} else {
// Pushing after tail
list->tail->next = e;
list->tail = e;
}
}
static void *ipxe_list_pop(ipxe_handover *ih, ipxe_list *list) {
ipxe_list_elem *e = list->head;
if (!e) {
// Empty list, return zero
return 0;
} else {
// Return head element
void *msg = e->msg;
list->head = e->next;
if (!list->head) {
list->tail = 0;
}
ih->free(e);
return msg;
}
}
#endif
......@@ -6,10 +6,9 @@
type definitions in this file must be manually kept in sync with
their original versions. */
#include "ipxe_asmc.h"
#include "ipxe_handover.h"
int main();
ipxe_handover *ih;
int pre_main(ipxe_handover *ih_) {
......@@ -48,3 +47,23 @@ void *get_table_end(const char *name) {
if (!sect) return EMPTY_LIST;
return sect->data + sect->len;
}
void *asmc_malloc(size_t size) {
return ih->malloc(size);
}
void asmc_free(void *ptr) {
ih->free(ptr);
}
void push_to_asmc(void *msg) {
ipxe_list_push(ih, &ih->from_ipxe, msg);
}
void *pop_from_asmc(void) {
return ipxe_list_pop(ih, &ih->to_ipxe);
}
void coro_yield(void) {
ih->coro_yield();
}
......@@ -6,6 +6,8 @@
#include <string.h>
#include <assert.h>
#include "coros.h"
#define USE_SOFTFLOAT 1
#define ONE_SOURCE 1
#include "tcc.h"
......@@ -20,6 +22,7 @@
#define IPXE_TEMP "/ram/ipxe"
const char *includes[] = {
ASMC_PREFIX,
IPXE_PREFIX,
IPXE_PREFIX "/include",
IPXE_PREFIX "/arch/x86/include",
......@@ -132,6 +135,16 @@ const char *sources[][2] = {
/* {IPXE_PREFIX "/core/blockdev.c", IPXE_TEMP "/blockdev.o"}, */
/* {IPXE_PREFIX "/core/edd.c", IPXE_TEMP "/edd.o"}, */
/* {IPXE_PREFIX "/core/quiesce.c", IPXE_TEMP "/quiesce.o"}, */
{IPXE_PREFIX "/net/tcp/http.c", IPXE_TEMP "/http.o"},
{IPXE_PREFIX "/net/tcp/httpcore.c", IPXE_TEMP "/httpcore.o"},
{IPXE_PREFIX "/net/tcp/httpconn.c", IPXE_TEMP "/httpconn.o"},
{IPXE_PREFIX "/core/pool.c", IPXE_TEMP "/pool.o"},
{IPXE_PREFIX "/core/blockdev.c", IPXE_TEMP "/blockdev.o"},
{IPXE_PREFIX "/core/linebuf.c", IPXE_TEMP "/linebuf.o"},
{IPXE_PREFIX "/core/xferbuf.c", IPXE_TEMP "/xferbuf.o"},
{IPXE_PREFIX "/usr/imgmgmt.c", IPXE_TEMP "/imgmgmt.o"},
{IPXE_PREFIX "/core/image.c", IPXE_TEMP "/image.o"},
{IPXE_PREFIX "/core/downloader.c", IPXE_TEMP "/downloader.o"},
};
#include "ipxe_handover.h"
......@@ -235,6 +248,7 @@ int main(int argc, char *argv[]) {
// First compile all files
for (int j = 0; j < sizeof(sources) / sizeof(sources[0]); j++) {
printf("Compiling %s to %s...", sources[j][0], sources[j][1]);
state = tcc_new();
tcc_set_options(state, "-nostdinc -nostdlib -include " IPXE_PREFIX "/include/compiler.h");
tcc_set_output_type(state, TCC_OUTPUT_OBJ);
......@@ -262,9 +276,11 @@ int main(int argc, char *argv[]) {
return 1;
}
tcc_delete(state);
printf(" done!\n");
}
// Then link everything together
printf("Linking IPXE...");
state = tcc_new();
tcc_set_options(state, "-nostdinc -nostdlib");
tcc_set_output_type(state, TCC_OUTPUT_MEMORY);
......@@ -281,6 +297,7 @@ int main(int argc, char *argv[]) {
printf("tcc_relocate() failed...\n");
return 1;
}
printf(" done!\n");
int (*main_symb)(ipxe_handover*) = tcc_get_symbol(state, "pre_main");
if (!main_symb) {
printf("tcc_get_symbol() failed...\n");
......@@ -288,6 +305,11 @@ int main(int argc, char *argv[]) {
}
ipxe_handover ih;
prepare_tables(state, &ih);
ipxe_list_reset(&ih.to_ipxe);
ipxe_list_reset(&ih.from_ipxe);
ih.coro_yield = coro_yield;
ih.malloc = malloc;
ih.free = free;
printf("Jumping into iPXE!\n");
res = main_symb(&ih);
......
......@@ -2,15 +2,15 @@
#define __SETJMP_H
typedef struct {
unsigned int eax;
unsigned int ebx;
unsigned int ecx;
unsigned int edx;
unsigned int esi;
unsigned int edi;
unsigned int ebp;
unsigned int esp;
unsigned int eip;
unsigned long eax;
unsigned long ebx;
unsigned long ecx;
unsigned long edx;
unsigned long esi;
unsigned long edi;
unsigned long ebp;
unsigned long esp;
unsigned long eip;
} jmp_buf;
#define setjmp(env) (__handles->platform_setjmp(&(env)))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment