Merge branch 'master' into ohligs
This commit is contained in:
commit
429c2a99d7
17 changed files with 272 additions and 213 deletions
|
@ -59,7 +59,7 @@ void switch_task(uint32_t id);
|
|||
* - 0 on success
|
||||
* - -EINVAL (-22) on failure
|
||||
*/
|
||||
int create_default_frame(task_t* task, entry_point_t ep, void* arg);
|
||||
int create_default_frame(task_t* task, internal_entry_point_t ep, void* arg);
|
||||
|
||||
/** @brief Register a task's TSS at GDT
|
||||
*
|
||||
|
|
|
@ -496,8 +496,8 @@ global apic_lint1
|
|||
global apic_error
|
||||
global apic_svr
|
||||
|
||||
global tss_switch
|
||||
tss_switch:
|
||||
global switch_task
|
||||
switch_task:
|
||||
mov eax, [esp+4]
|
||||
add ax, WORD 5
|
||||
mov bx, WORD 8
|
||||
|
|
|
@ -52,23 +52,6 @@ size_t get_stack(uint32_t id)
|
|||
return (size_t) kstacks[id] + KERNEL_STACK_SIZE - sizeof(size_t);
|
||||
}
|
||||
|
||||
void switch_task(uint32_t id)
|
||||
{
|
||||
#if MAX_CORES > 1
|
||||
/*
|
||||
* On SMP systems, the task switch on an other could be in progress...
|
||||
* => we need to check, if the task is still busy
|
||||
*/
|
||||
volatile gdt_entry_t* newgdt = (volatile gdt_entry_t*) gdt+id-5;
|
||||
|
||||
while (newgdt->access & GDT_FLAG_TSS_BUSY) {
|
||||
NOP1;
|
||||
}
|
||||
#endif
|
||||
|
||||
tss_switch(id);
|
||||
}
|
||||
|
||||
int register_task(task_t* task) {
|
||||
uint16_t sel;
|
||||
uint32_t id = task->id;
|
||||
|
@ -142,7 +125,7 @@ int arch_fork(task_t* task)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int create_default_frame(task_t* task, entry_point_t ep, void* arg)
|
||||
int create_default_frame(task_t* task, internal_entry_point_t ep, void* arg)
|
||||
{
|
||||
uint16_t cs = 0x08;
|
||||
uint16_t ds = 0x10;
|
||||
|
|
|
@ -229,8 +229,8 @@ static void fault_handler(struct state *s)
|
|||
{
|
||||
if (s->int_no < 32) {
|
||||
kputs(exception_messages[s->int_no]);
|
||||
kprintf(" Exception (%d) at 0x%x:0x%x on core %d, error code 0x%x, eflags 0x%x\n",
|
||||
s->int_no, s->cs, CORE_ID, s->eip, s->error, s->eflags);
|
||||
kprintf(" Exception (%d) at 0x%x:0x%x on core %u, error code 0x%x, eflags 0x%x\n",
|
||||
s->int_no, s->cs, s->eip, CORE_ID, s->error, s->eflags);
|
||||
|
||||
/* Now, we signalize that we have handled the interrupt */
|
||||
if (apic_is_enabled())
|
||||
|
|
|
@ -258,6 +258,34 @@ again:
|
|||
return ERR_OK;
|
||||
}
|
||||
|
||||
static void rckemacif_input(struct netif* netif, struct pbuf* p)
|
||||
{
|
||||
struct eth_hdr *ethhdr;
|
||||
|
||||
/* points to packet payload, which starts with an Ethernet header */
|
||||
ethhdr = p->payload;
|
||||
|
||||
switch (htons(ethhdr->type)) {
|
||||
/* IP or ARP packet? */
|
||||
case ETHTYPE_ARP:
|
||||
case ETHTYPE_IP:
|
||||
#if PPPOE_SUPPORT
|
||||
/* PPPoE packet? */
|
||||
case ETHTYPE_PPPOEDISC:
|
||||
case ETHTYPE_PPPOE:
|
||||
#endif /* PPPOE_SUPPORT */
|
||||
/* full packet send to tcpip_thread to process */
|
||||
if (mynetif->input(p, mynetif) != ERR_OK) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_input: IP input error\n"));
|
||||
pbuf_free(p);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pbuf_free(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void rckemacif_rx_handler(struct netif* netif, unsigned int write_offset)
|
||||
{
|
||||
rckemacif_t* rckemacif = netif->state;
|
||||
|
@ -372,7 +400,7 @@ out:
|
|||
#if ETH_PAD_SIZE
|
||||
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
|
||||
#endif
|
||||
mailbox_ptr_post(&rckemacif->mbox, (void*)p);
|
||||
rckemacif_input(netif, p);
|
||||
LINK_STATS_INC(link.recv);
|
||||
} else {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_rx_inthandler: not enough memory!\n"));
|
||||
|
@ -422,48 +450,6 @@ nexttry:
|
|||
*((volatile unsigned*) (FPGA_BASE + IRQ_RESET + rckemacif->core * 2 * 4)) = (1 << rckemacif->num_emac);
|
||||
}
|
||||
|
||||
err_t rckemacif_wait(struct netif* netif, uint32_t poll)
|
||||
{
|
||||
rckemacif_t* rckemacif = netif->state;
|
||||
struct eth_hdr *ethhdr;
|
||||
struct pbuf *p = NULL;
|
||||
err_t err = ERR_OK;
|
||||
|
||||
if (poll) {
|
||||
if (mailbox_ptr_tryfetch(&(rckemacif->mbox), (void**) &p))
|
||||
return err;
|
||||
} else {
|
||||
mailbox_ptr_fetch(&(rckemacif->mbox), (void**) &p);
|
||||
}
|
||||
|
||||
/* points to packet payload, which starts with an Ethernet header */
|
||||
ethhdr = p->payload;
|
||||
|
||||
//LWIP_DEBUGF(NETIF_DEBUG, ("Got packet of type 0x%x!\n", htons(ethhdr->type)));
|
||||
|
||||
switch (htons(ethhdr->type)) {
|
||||
/* IP or ARP packet? */
|
||||
case ETHTYPE_ARP:
|
||||
case ETHTYPE_IP:
|
||||
#if PPPOE_SUPPORT
|
||||
/* PPPoE packet? */
|
||||
case ETHTYPE_PPPOEDISC:
|
||||
case ETHTYPE_PPPOE:
|
||||
#endif /* PPPOE_SUPPORT */
|
||||
/* full packet send to tcpip_thread to process */
|
||||
if ((err = mynetif->input(p, mynetif)) != ERR_OK) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_poll: IP input error\n"));
|
||||
pbuf_free(p);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pbuf_free(p);
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
err_t rckemacif_init(struct netif* netif)
|
||||
{
|
||||
rckemacif_t* rckemacif;
|
||||
|
@ -516,8 +502,6 @@ err_t rckemacif_init(struct netif* netif)
|
|||
memset(rckemacif->tx_buffer, 0x00, 0x20);
|
||||
memset(rckemacif->tx_buffer + 0x20, 0xDA, BUFFER_SIZE - 0x20);
|
||||
rckemacif->tx_buffer_max = CLINE_PACKETS(BUFFER_SIZE) - 1;
|
||||
|
||||
mailbox_ptr_init(&rckemacif->mbox);
|
||||
netif->state = rckemacif;
|
||||
|
||||
/* Depending on core location read own private data
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#define __HAVE_RCKEMAC_H__
|
||||
|
||||
#include <metalsvm/stddef.h>
|
||||
#include <metalsvm/mailbox.h>
|
||||
|
||||
#if defined(CONFIG_LWIP) && defined(CONFIG_ROCKCREEK)
|
||||
|
||||
|
@ -40,17 +39,8 @@ typedef struct rckemacif {
|
|||
void* irq_address;
|
||||
uint32_t core;
|
||||
uint32_t num_emac;
|
||||
mailbox_ptr_t mbox;
|
||||
} rckemacif_t;
|
||||
|
||||
/*
|
||||
* Wait for incoming messages.
|
||||
*
|
||||
* poll = 0 : wait blocks until a message is received
|
||||
* poll != 0: non-blocking wait
|
||||
*/
|
||||
err_t rckemacif_wait(struct netif* netif, uint32_t poll);
|
||||
|
||||
/*
|
||||
* Initialize the eMAC network driver
|
||||
*/
|
||||
|
|
|
@ -110,8 +110,7 @@ static err_t rtl8139if_output(struct netif* netif, struct pbuf* p)
|
|||
return ERR_OK;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void rtl8139if_input(struct netif* netif, struct pbuf* p)
|
||||
static void rtl8139if_input(struct netif* netif, struct pbuf* p)
|
||||
{
|
||||
struct eth_hdr *ethhdr;
|
||||
|
||||
|
@ -138,7 +137,6 @@ void rtl8139if_input(struct netif* netif, struct pbuf* p)
|
|||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void rtl_rx_inthandler(struct netif* netif)
|
||||
{
|
||||
|
@ -175,8 +173,7 @@ static void rtl_rx_inthandler(struct netif* netif)
|
|||
#if ETH_PAD_SIZE
|
||||
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
|
||||
#endif
|
||||
mailbox_ptr_post(&rtl8139if->mbox, (void*)p);
|
||||
//rtl8139if_input(netif, p);
|
||||
rtl8139if_input(netif, p);
|
||||
LINK_STATS_INC(link.recv);
|
||||
} else {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_rx_inthandler: not enough memory!\n"));
|
||||
|
@ -268,46 +265,6 @@ static void rtl8139if_handler(struct state* s)
|
|||
}
|
||||
}
|
||||
|
||||
err_t rtl8139if_wait(struct netif* netif, uint32_t poll)
|
||||
{
|
||||
rtl1839if_t* rtl8139if = netif->state;
|
||||
struct eth_hdr *ethhdr;
|
||||
struct pbuf *p = NULL;
|
||||
err_t err = ERR_OK;
|
||||
|
||||
if (poll) {
|
||||
if (mailbox_ptr_tryfetch(&(rtl8139if->mbox), (void**) &p))
|
||||
return err;
|
||||
} else {
|
||||
mailbox_ptr_fetch(&(rtl8139if->mbox), (void**) &p);
|
||||
}
|
||||
|
||||
/* points to packet payload, which starts with an Ethernet header */
|
||||
ethhdr = p->payload;
|
||||
|
||||
switch (htons(ethhdr->type)) {
|
||||
/* IP or ARP packet? */
|
||||
case ETHTYPE_ARP:
|
||||
case ETHTYPE_IP:
|
||||
#if PPPOE_SUPPORT
|
||||
/* PPPoE packet? */
|
||||
case ETHTYPE_PPPOEDISC:
|
||||
case ETHTYPE_PPPOE:
|
||||
#endif /* PPPOE_SUPPORT */
|
||||
/* full packet send to tcpip_thread to process */
|
||||
if ((err = mynetif->input(p, mynetif)) != ERR_OK) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_poll: IP input error\n"));
|
||||
pbuf_free(p);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pbuf_free(p);
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
err_t rtl8139if_init(struct netif* netif)
|
||||
{
|
||||
rtl1839if_t* rtl8139if;
|
||||
|
@ -348,7 +305,6 @@ err_t rtl8139if_init(struct netif* netif)
|
|||
rtl8139if->tx_buffer[2] = rtl8139if->tx_buffer[1] + 4096;
|
||||
rtl8139if->tx_buffer[3] = rtl8139if->tx_buffer[2] + 4096;
|
||||
|
||||
mailbox_ptr_init(&rtl8139if->mbox);
|
||||
netif->state = rtl8139if;
|
||||
mynetif = netif;
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
#define __HAVE_RTL8139_H__
|
||||
|
||||
#include <metalsvm/stddef.h>
|
||||
#include <metalsvm/mailbox.h>
|
||||
#include <metalsvm/spinlock.h>
|
||||
|
||||
#if defined(CONFIG_LWIP) && defined(CONFIG_PCI)
|
||||
|
||||
// the registers are at the following places
|
||||
|
@ -226,17 +227,8 @@ typedef struct rtl1839if {
|
|||
uint32_t tx_complete;
|
||||
uint16_t rx_pos;
|
||||
uint8_t tx_inuse[4];
|
||||
mailbox_ptr_t mbox;
|
||||
} rtl1839if_t;
|
||||
|
||||
/*
|
||||
* Wait for incoming messages.
|
||||
*
|
||||
* poll = 0 : wait blocks until a message is received
|
||||
* poll != 0: non-blocking wait
|
||||
*/
|
||||
err_t rtl8139if_wait(struct netif* netif, uint32_t poll);
|
||||
|
||||
/*
|
||||
* Initialize the network driver for the RealTek RTL8139 family
|
||||
*/
|
||||
|
|
|
@ -36,6 +36,7 @@ typedef unsigned int tid_t;
|
|||
#define per_core(name) name
|
||||
#define DECLARE_PER_CORE(type, name) extern type name;
|
||||
#define DEFINE_PER_CORE(type, name, def_value) type name = def_value;
|
||||
#define DEFINE_PER_CORE_STATIC(type, name, def_value) static type name = def_value;
|
||||
#define CORE_ID 0
|
||||
#else
|
||||
#define per_core(name) (*__get_percore_##name())
|
||||
|
@ -51,6 +52,16 @@ typedef unsigned int tid_t;
|
|||
}
|
||||
#define DEFINE_PER_CORE(type, name, def_value) \
|
||||
aligned_##name name[MAX_CORES] = {[0 ... MAX_CORES-1] = {def_value}};
|
||||
#define DEFINE_PER_CORE_STATIC(type, name, def_value) \
|
||||
typedef struct { type var __attribute__ ((aligned (CACHE_LINE))); } aligned_##name;\
|
||||
static aligned_##name name[MAX_CORES] = {[0 ... MAX_CORES-1] = {def_value}}; \
|
||||
inline static type* __get_percore_##name(void) {\
|
||||
type* ret; \
|
||||
uint32_t flags = irq_nested_disable(); \
|
||||
ret = &(name[smp_id()].var); \
|
||||
irq_nested_enable(flags);\
|
||||
return ret; \
|
||||
}
|
||||
#define CORE_ID smp_id()
|
||||
#endif
|
||||
|
||||
|
|
|
@ -42,17 +42,19 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#define TASK_INVALID 0
|
||||
#define TASK_READY 1
|
||||
#define TASK_READY 1
|
||||
#define TASK_RUNNING 2
|
||||
#define TASK_BLOCKED 3
|
||||
#define TASK_FINISHED 4
|
||||
#define TASK_IDLE 5
|
||||
#define TASK_IDLE 5
|
||||
|
||||
#define TASK_DEFAULT_FLAGS 0
|
||||
#define TASK_FPU_INIT (1 << 0)
|
||||
#define TASK_FPU_USED (1 << 1)
|
||||
#define TASK_DEFAULT_FLAGS 0
|
||||
#define TASK_FPU_INIT (1 << 0)
|
||||
#define TASK_FPU_USED (1 << 1)
|
||||
#define TASK_SWITCH_IN_PROGESS (1 << 2)
|
||||
|
||||
typedef int (STDCALL *entry_point_t)(void*);
|
||||
typedef int (*entry_point_t)(void*);
|
||||
typedef int (STDCALL *internal_entry_point_t)(void*);
|
||||
struct page_dir;
|
||||
|
||||
/* @brief The task_t structure */
|
||||
|
|
102
kernel/init.c
102
kernel/init.c
|
@ -48,8 +48,6 @@
|
|||
void echo_init(void);
|
||||
void ping_init(void);
|
||||
|
||||
static volatile int done = 0;
|
||||
|
||||
/*
|
||||
* Note that linker symbols are not variables, they have no memory allocated for
|
||||
* maintaining a value, rather their address is their value.
|
||||
|
@ -70,17 +68,42 @@ int lowlevel_init(void)
|
|||
}
|
||||
|
||||
#if defined(CONFIG_LWIP) && (defined(CONFIG_PCI) || defined(CONFIG_ROCKCREEK))
|
||||
static tid_t netid;
|
||||
static struct netif* default_netif = NULL;
|
||||
static volatile uint32_t lwip_initialized = 0;
|
||||
|
||||
int STDCALL network_task(void* arg)
|
||||
static void tcp_init_ok(void* e)
|
||||
{
|
||||
struct netif netif;
|
||||
kputs("TCP/IP init COMPLETE!!\n");
|
||||
lwip_initialized = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
int network_init(void)
|
||||
{
|
||||
#if defined(CONFIG_LWIP) && (defined(CONFIG_PCI) || defined(CONFIG_ROCKCREEK))
|
||||
struct ip_addr ipaddr;
|
||||
struct ip_addr netmask;
|
||||
struct ip_addr gw;
|
||||
|
||||
kputs("Network task is started\n");
|
||||
kputs("Initialize network...\n");
|
||||
|
||||
// Initialize lwIP modules
|
||||
tcpip_init(tcp_init_ok, NULL);
|
||||
|
||||
while(!lwip_initialized) {
|
||||
reschedule();
|
||||
}
|
||||
|
||||
// Set up the lwIP network interface
|
||||
// Allocate and configure netif
|
||||
default_netif = (struct netif *) mem_malloc(sizeof(struct netif));
|
||||
if(default_netif == NULL)
|
||||
{
|
||||
kprintf("ERROR: Out of memory for default netif\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(default_netif, 0x00, sizeof(struct netif));
|
||||
#ifdef CONFIG_ROCKCREEK
|
||||
/* Set network address variables */
|
||||
IP4_ADDR(&gw, 192,168,4,254);
|
||||
|
@ -88,7 +111,7 @@ int STDCALL network_task(void* arg)
|
|||
IP4_ADDR(&netmask, 255,255,255,0);
|
||||
|
||||
/* Bring up the network interface */
|
||||
if (!netif_add(&netif, &ipaddr, &netmask, &gw, NULL, rckemacif_init, ethernet_input)) {
|
||||
if (!netif_add(default_netif, &ipaddr, &netmask, &gw, NULL, rckemacif_init, tcpip_input)) {
|
||||
#else
|
||||
/* Clear network address because we use DHCP to get an ip address */
|
||||
IP4_ADDR(&gw, 0,0,0,0);
|
||||
|
@ -96,82 +119,61 @@ int STDCALL network_task(void* arg)
|
|||
IP4_ADDR(&netmask, 0,0,0,0);
|
||||
|
||||
/* Bring up the network interface */
|
||||
if (!netif_add(&netif, &ipaddr, &netmask, &gw, NULL, rtl8139if_init, ethernet_input)) {
|
||||
if (!netif_add(default_netif, &ipaddr, &netmask, &gw, NULL, rtl8139if_init, tcpip_input)) {
|
||||
#endif
|
||||
kputs("Unable to add network interface\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
netif_set_default(&netif);
|
||||
netif_set_up(&netif);
|
||||
netif_set_default(default_netif);
|
||||
netif_set_up(default_netif);
|
||||
|
||||
/* test if interface is really up */
|
||||
if (!netif_is_up(&netif)) {
|
||||
if (!netif_is_up(default_netif)) {
|
||||
kputs("network interface is not up\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_ROCKCREEK
|
||||
kprintf("Starting DHCPCD...\n");
|
||||
dhcp_start(&netif);
|
||||
dhcp_start(default_netif);
|
||||
|
||||
int mscnt = 0;
|
||||
/* wait for ip address */
|
||||
while(!netif.ip_addr.addr) {
|
||||
rtl8139if_wait(&netif, 1);
|
||||
reschedule();
|
||||
while(!default_netif->ip_addr.addr) {
|
||||
sys_msleep(DHCP_FINE_TIMER_MSECS);
|
||||
dhcp_fine_tmr();
|
||||
mscnt += DHCP_FINE_TIMER_MSECS;
|
||||
if (mscnt >= DHCP_COARSE_TIMER_SECS*1000) {
|
||||
dhcp_coarse_tmr();
|
||||
mscnt = 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
mmnif_open();
|
||||
//mmnif_open();
|
||||
#endif
|
||||
|
||||
// start echo and ping server
|
||||
echo_init();
|
||||
ping_init();
|
||||
|
||||
while(!done) {
|
||||
#ifdef CONFIG_PCI
|
||||
rtl8139if_wait(&netif, 0);
|
||||
#elif defined(CONFIG_ROCKCREEK)
|
||||
rckemacif_wait(&netif, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef CONFIG_ROCKCREEK
|
||||
dhcp_release(&netif);
|
||||
dhcp_stop(&netif);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int network_shutdown(void)
|
||||
{
|
||||
#if defined(CONFIG_LWIP) && defined(CONFIG_ROCKCREEK)
|
||||
mmnif_close();
|
||||
//mmnif_close();
|
||||
#elif defined(CONFIG_LWIP) && defined(CONFIG_PCI)
|
||||
dhcp_release(default_netif);
|
||||
dhcp_stop(default_netif);
|
||||
#endif
|
||||
done = 1;
|
||||
|
||||
mem_free(default_netif);
|
||||
default_netif = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tcp_init_ok(void* e)
|
||||
{
|
||||
kprintf("TCP/IP init COMPLETE!!");
|
||||
}
|
||||
|
||||
int network_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#if defined(CONFIG_LWIP)
|
||||
// Initialize lwIP modules
|
||||
tcpip_init(tcp_init_ok, NULL);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_LWIP) && (defined(CONFIG_PCI) || defined(CONFIG_ROCKCREEK))
|
||||
ret = create_kernel_task(&netid, network_task, NULL);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -212,11 +212,11 @@ ping_thread(void *arg)
|
|||
|
||||
lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
|
||||
for(i=0; i<10; i++) {
|
||||
for(i=0; i<5; i++) {
|
||||
ping_target = PING_TARGET;
|
||||
|
||||
if (ping_send(s, &ping_target) == ERR_OK) {
|
||||
LWIP_DEBUGF( PING_DEBUG, ("ping: send "));
|
||||
LWIP_DEBUGF( PING_DEBUG, ("ping: send on core %d to " , CORE_ID));
|
||||
ip_addr_debug_print(PING_DEBUG, &ping_target);
|
||||
LWIP_DEBUGF( PING_DEBUG, ("\n"));
|
||||
|
||||
|
|
117
kernel/tasks.c
117
kernel/tasks.c
|
@ -53,6 +53,7 @@ static task_t task_table[MAX_TASKS] = { \
|
|||
static spinlock_irqsave_t table_lock = SPINLOCK_IRQSAVE_INIT;
|
||||
|
||||
DEFINE_PER_CORE(task_t*, current_task, task_table+0);
|
||||
DEFINE_PER_CORE_STATIC(task_t*, old_task, NULL);
|
||||
|
||||
/** @brief helper function for the assembly code to determine the current task
|
||||
* @return Pointer to the task_t structure of current task
|
||||
|
@ -171,6 +172,24 @@ void NORETURN abort(void) {
|
|||
do_exit(-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief: if the task switch is finished, we reset
|
||||
* the TASK_SWITCH_IN_PROGRESS bit
|
||||
*/
|
||||
inline static void task_switch_finished(void)
|
||||
{
|
||||
uint32_t flags = irq_nested_disable();
|
||||
|
||||
// do we already reset the TASK_SWITCH_IN_PROGRESS bit?
|
||||
task_t* old = per_core(old_task);
|
||||
if (old) {
|
||||
old->flags &= ~TASK_SWITCH_IN_PROGESS;
|
||||
per_core(old_task) = NULL;
|
||||
}
|
||||
|
||||
irq_nested_enable(flags);
|
||||
}
|
||||
|
||||
/** @brief Create a task with a specific entry point
|
||||
*
|
||||
* @param id Pointer to a tid_t struct were the id shall be set
|
||||
|
@ -180,7 +199,7 @@ void NORETURN abort(void) {
|
|||
* - 0 on success
|
||||
* - -ENOMEM (-12) or -EINVAL (-22) on failure
|
||||
*/
|
||||
static int create_task(tid_t* id, entry_point_t ep, void* arg)
|
||||
static int create_task(tid_t* id, internal_entry_point_t ep, void* arg)
|
||||
{
|
||||
task_t* curr_task;
|
||||
int ret = -ENOMEM;
|
||||
|
@ -233,7 +252,6 @@ create_task_out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int sys_fork(void)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
|
@ -300,6 +318,10 @@ int sys_fork(void)
|
|||
// Leave the function without releasing the locks
|
||||
// because the locks are already released
|
||||
// by the parent task!
|
||||
|
||||
// first switch to the new current task
|
||||
// => signalizes a successful task switch
|
||||
task_switch_finished();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -318,15 +340,54 @@ create_task_out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int create_kernel_task(tid_t* id, entry_point_t ep, void* arg)
|
||||
/** @brief Structure which keeps all
|
||||
* relevant data for a new kernel task to start */
|
||||
typedef struct {
|
||||
/// entry point of the kernel task
|
||||
entry_point_t func;
|
||||
/// arguments
|
||||
void* args;
|
||||
} kernel_args_t;
|
||||
|
||||
/** @brief This call is used to adapt create_task calls
|
||||
* which want to have a start function and argument list */
|
||||
static int STDCALL kernel_entry(void* args)
|
||||
{
|
||||
return create_task(id, ep, arg);
|
||||
int ret;
|
||||
kernel_args_t* kernel_args = (kernel_args_t*) args;
|
||||
|
||||
// first switch to the new current task
|
||||
// => signalizes a successful task switch
|
||||
task_switch_finished();
|
||||
|
||||
if (BUILTIN_EXPECT(!kernel_args, 0))
|
||||
return -EINVAL;
|
||||
|
||||
ret = kernel_args->func(kernel_args->args);
|
||||
|
||||
kfree(kernel_args, sizeof(kernel_args_t));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int create_kernel_task(tid_t* id, entry_point_t ep, void* args)
|
||||
{
|
||||
kernel_args_t* kernel_args;
|
||||
|
||||
kernel_args = kmalloc(sizeof(kernel_args_t));
|
||||
if (BUILTIN_EXPECT(!kernel_args, 0))
|
||||
return -ENOMEM;
|
||||
|
||||
kernel_args->func = ep;
|
||||
kernel_args->args = args;
|
||||
|
||||
return create_task(id, kernel_entry, kernel_args);
|
||||
}
|
||||
|
||||
#define MAX_ARGS (PAGE_SIZE - 2*sizeof(int) - sizeof(vfs_node_t*))
|
||||
|
||||
/** @brief Structure which keeps all
|
||||
* relevant data for a new task to start */
|
||||
* relevant data for a new user task to start */
|
||||
typedef struct {
|
||||
/// Points to the node with the executable in the file system
|
||||
vfs_node_t* node;
|
||||
|
@ -543,7 +604,20 @@ invalid:
|
|||
* which want to have a start function and argument list */
|
||||
static int STDCALL user_entry(void* arg)
|
||||
{
|
||||
return load_task((load_args_t*) arg);
|
||||
int ret;
|
||||
|
||||
// first switch to the new current task
|
||||
// => signalizes a successful task switch
|
||||
task_switch_finished();
|
||||
|
||||
if (BUILTIN_EXPECT(!arg, 0))
|
||||
return -EINVAL;
|
||||
|
||||
ret = load_task((load_args_t*) arg);
|
||||
|
||||
kfree(arg, sizeof(load_args_t));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Luxus-edition of create_user_task functions. Just call with an exe name
|
||||
|
@ -732,14 +806,14 @@ int block_task(tid_t id)
|
|||
|
||||
spinlock_irqsave_lock(&table_lock);
|
||||
|
||||
if ((task_table[id].status == TASK_RUNNING) || (task_table[id].status == TASK_READY)) {
|
||||
if ((task_table[id].status == TASK_RUNNING) || (task_table[id].status == TASK_READY)) {
|
||||
task_table[id].status = TASK_BLOCKED;
|
||||
ret = 0;
|
||||
} else kprintf("Unable to block task %d!\n", id);
|
||||
|
||||
spinlock_irqsave_unlock(&table_lock);
|
||||
spinlock_irqsave_unlock(&table_lock);
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief _The_ scheduler procedure
|
||||
|
@ -753,13 +827,18 @@ void scheduler(void)
|
|||
unsigned int i;
|
||||
unsigned int new_id;
|
||||
|
||||
// let's play it save
|
||||
// => check if we already signalizes that the previous switch
|
||||
// is finished
|
||||
task_switch_finished();
|
||||
|
||||
#if MAX_CORES > 1
|
||||
spinlock_irqsave_lock(&table_lock);
|
||||
#endif
|
||||
|
||||
orig_task = curr_task = per_core(current_task);
|
||||
|
||||
/* signalize that this task could be reused */
|
||||
/* signalizes that this task could be reused */
|
||||
if (curr_task->status == TASK_FINISHED)
|
||||
curr_task->status = TASK_INVALID;
|
||||
|
||||
|
@ -772,16 +851,26 @@ void scheduler(void)
|
|||
for(i=1, new_id=(curr_task->id + 1) % MAX_TASKS;
|
||||
i<MAX_TASKS; i++, new_id=(new_id+1) % MAX_TASKS)
|
||||
{
|
||||
if (task_table[new_id].status == TASK_READY) {
|
||||
if (curr_task->status == TASK_RUNNING)
|
||||
if ((task_table[new_id].status == TASK_READY) && !(task_table[new_id].flags & TASK_SWITCH_IN_PROGESS)) {
|
||||
if (curr_task->status == TASK_RUNNING) {
|
||||
curr_task->status = TASK_READY;
|
||||
curr_task->flags |= TASK_SWITCH_IN_PROGESS;
|
||||
per_core(old_task) = curr_task;
|
||||
} else per_core(old_task) = NULL;
|
||||
|
||||
task_table[new_id].status = TASK_RUNNING;
|
||||
curr_task = per_core(current_task) = task_table+new_id;
|
||||
|
||||
goto get_task_out;
|
||||
}
|
||||
|
||||
//if ((task_table[new_id].status == TASK_READY) && (task_table[new_id].flags & TASK_SWITCH_IN_PROGESS))
|
||||
// kprintf("task switch %d is in progress\n", new_id);
|
||||
}
|
||||
|
||||
// old task will never rescheduled
|
||||
per_core(old_task) = NULL;
|
||||
|
||||
if ((curr_task->status == TASK_RUNNING) || (curr_task->status == TASK_IDLE))
|
||||
goto get_task_out;
|
||||
|
||||
|
@ -798,8 +887,10 @@ get_task_out:
|
|||
spinlock_irqsave_unlock(&table_lock);
|
||||
#endif
|
||||
|
||||
if (curr_task != orig_task)
|
||||
if (curr_task != orig_task) {
|
||||
switch_task(new_id);
|
||||
task_switch_finished();
|
||||
}
|
||||
}
|
||||
|
||||
void reschedule(void)
|
||||
|
|
|
@ -39,7 +39,7 @@ static sem_t consuming, producing;
|
|||
static mailbox_int32_t mbox;
|
||||
static int val = 0;
|
||||
|
||||
static int STDCALL consumer(void* arg)
|
||||
static int consumer(void* arg)
|
||||
{
|
||||
int i, m = 0;
|
||||
|
||||
|
@ -58,7 +58,7 @@ static int STDCALL consumer(void* arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int STDCALL producer(void* arg)
|
||||
static int producer(void* arg)
|
||||
{
|
||||
int i;
|
||||
int mail[5] = {1, 2, 3, 4, 5};
|
||||
|
@ -78,7 +78,7 @@ static int STDCALL producer(void* arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int STDCALL foo(void* arg)
|
||||
static int foo(void* arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -94,7 +94,7 @@ static int STDCALL foo(void* arg)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_ROCKCREEK
|
||||
int STDCALL mail_ping(void* arg) {
|
||||
int mail_ping(void* arg) {
|
||||
int i;
|
||||
|
||||
for(i=0; i<20; i++) {
|
||||
|
@ -107,7 +107,7 @@ int STDCALL mail_ping(void* arg) {
|
|||
}
|
||||
#endif
|
||||
|
||||
static int STDCALL join_test(void* arg)
|
||||
static int join_test(void* arg)
|
||||
{
|
||||
tid_t id, ret;
|
||||
int result = -1234;
|
||||
|
@ -125,7 +125,7 @@ static int STDCALL join_test(void* arg)
|
|||
}
|
||||
|
||||
#if defined(CONFIG_LWIP) && defined(CONFIG_ROCKCREEK)
|
||||
static int STDCALL server_task(void* e)
|
||||
static int server_task(void* e)
|
||||
{
|
||||
int sockfd, newsockfd, portno, clilen;
|
||||
char buffer[256];
|
||||
|
@ -193,7 +193,7 @@ static int STDCALL server_task(void* e)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int STDCALL client_task(void* e)
|
||||
static int client_task(void* e)
|
||||
{
|
||||
char dir[256];
|
||||
int sd;
|
||||
|
|
|
@ -74,13 +74,16 @@ sys_msleep(u32_t ms)
|
|||
}
|
||||
}
|
||||
|
||||
/* sys_thread_new(): Spawns a new thread with given attributes as supportet
|
||||
/* sys_thread_new(): Spawns a new thread with given attributes as supported
|
||||
* Note: In MetalSVM this is realized as kernel tasks
|
||||
*/
|
||||
sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
|
||||
{
|
||||
tid_t tmp;
|
||||
|
||||
kprintf("Create LWIP task %s\n", name);
|
||||
create_kernel_task(&tmp,thread,arg);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
@ -252,4 +255,21 @@ err_t sys_mutex_new(sys_mutex_t * mutex)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if SYS_LIGHTWEIGHT_PROT
|
||||
#if MAX_CORES > 1
|
||||
static spinlock_irqsave_t lwprot_lock = SPINLOCK_IRQSAVE_INIT;
|
||||
|
||||
sys_prot_t sys_arch_protect(void)
|
||||
{
|
||||
spinlock_irqsave_lock(&lwprot_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_arch_unprotect(sys_prot_t pval)
|
||||
{
|
||||
spinlock_irqsave_unlock(&lwprot_lock);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* !NO_SYS */
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <asm/tasks.h>
|
||||
#include <metalsvm/mailbox.h>
|
||||
#include <metalsvm/errno.h>
|
||||
#include <asm/irqflags.h>
|
||||
|
||||
#define EWOULDBLOCK EAGAIN /* Operation would block */
|
||||
|
||||
|
@ -22,4 +23,24 @@ typedef struct
|
|||
|
||||
typedef tid_t* sys_thread_t;
|
||||
|
||||
#if SYS_LIGHTWEIGHT_PROT
|
||||
#if MAX_CORES > 1
|
||||
typedef uint32_t sys_prot_t;
|
||||
sys_prot_t sys_arch_protect(void);
|
||||
void sys_arch_unprotect(sys_prot_t pval);
|
||||
#else
|
||||
typedef uint32_t sys_prot_t;
|
||||
|
||||
static inline sys_prot_t sys_arch_protect(void)
|
||||
{
|
||||
return irq_nested_disable();
|
||||
}
|
||||
|
||||
static inline void sys_arch_unprotect(sys_prot_t pval)
|
||||
{
|
||||
irq_nested_enable(pval);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* __ARCH_SYS_ARCH_H__ */
|
||||
|
|
|
@ -3,6 +3,13 @@
|
|||
#ifndef __LWIPOPTS_H__
|
||||
#define __LWIPOPTS_H_
|
||||
|
||||
/**
|
||||
* SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain
|
||||
* critical regions during buffer allocation, deallocation and memory
|
||||
* allocation and deallocation.
|
||||
*/
|
||||
#define SYS_LIGHTWEIGHT_PROT 1
|
||||
|
||||
/**
|
||||
* NO_SYS==1: Provides VERY minimal functionality. Otherwise,
|
||||
* use lwIP facilities.
|
||||
|
|
Loading…
Add table
Reference in a new issue