commit 03d41e2e229a4efb1587956b27a9675c13f34ff5
parent e6669b6ab2d027b1f21a416737d26d5788764888
Author: oblique <psyberbits@gmail.com>
Date: Fri, 26 Oct 2012 21:00:39 +0300
added: timers, scheduler, kernel threads
changes:
* improve exception handling
* fix some bugs in the allocator
* fix GIC controller
* add support for Dual-Mode Timers
* add scheduler
* add kernel threads
* change coding style of function declaration
Diffstat:
30 files changed, 1095 insertions(+), 123 deletions(-)
diff --git a/include/alloc.h b/include/alloc.h
@@ -5,6 +5,6 @@
void *kmalloc(size_t size);
void kfree(void *addr);
-void kdump();
+void kdump(void);
#endif /* __ALLOC_H */
diff --git a/include/dmtimer.h b/include/dmtimer.h
@@ -0,0 +1,11 @@
+#ifndef __DMTIMER_H
+#define __DMTIMER_H
+
+#include <kernel.h>
+
+typedef void (*dmtimer_callback_func)(int timer_id, struct regs *regs);
+
+int dmtimer_register(int id, dmtimer_callback_func func, u32 ms);
+int dmtimer_trigger(int id);
+
+#endif /* __DMTIMER_H */
diff --git a/include/errno.h b/include/errno.h
@@ -36,7 +36,9 @@
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
-#define MAX_ERRNO 34
+#define ENOSYS 35 /* Function not implemented */
+
+#define MAX_ERRNO 35
#define IS_ERR(x) ((unsigned long)(x) >= (unsigned long)-MAX_ERRNO)
#define PTR_ERR(x) ((unsigned long)(x))
#define ERR_PTR(x) ((void*)(x))
diff --git a/include/gic.h b/include/gic.h
@@ -0,0 +1,11 @@
+#ifndef __GIC_H
+#define __GIC_H
+
+#include <kernel.h>
+#include <irq.h>
+
+int gic_register(u32 irq_num, irq_callback_func func);
+void gic_handler(struct regs *regs);
+void gic_init(void);
+
+#endif /* __GIC_H */
diff --git a/include/irq.h b/include/irq.h
@@ -0,0 +1,14 @@
+#ifndef __IRQ_H
+#define __IRQ_H
+
+#include <kernel.h>
+
+typedef void (*irq_callback_func)(u32 irq_num, struct regs *regs);
+
+int irq_register(u32 irq_num, irq_callback_func func);
+
+/* board specific */
+#define HW_IRQ(x) (x + 32)
+#define NUM_OF_IRQ 160
+
+#endif /* __IRQ_H */
diff --git a/include/kernel.h b/include/kernel.h
@@ -3,10 +3,16 @@
#include <inttypes.h>
#include <stddef.h>
+#include <string.h>
#include <print.h>
#include <io.h>
#include <errno.h>
#include <varg.h>
+#include <regs.h>
+#include <alloc.h>
+#include <debug.h>
+
+#define __unused __attribute__((__unused__))
#define container_of(ptr, type, member) ({ \
const typeof(((type*)0)->member) *__mptr = (ptr); \
diff --git a/include/list.h b/include/list.h
@@ -12,6 +12,7 @@ struct list_head {
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
#define list_entry(ptr, type, member) container_of(ptr, type, member)
+#define list_first_entry(head_ptr, type, member) container_of((head_ptr)->next, type, member)
/* list_for_each - iterate over a list
* pos: the &struct list_head to use as a loop cursor.
@@ -30,7 +31,9 @@ struct list_head {
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
-static inline void INIT_LIST_HEAD(struct list_head *list) {
+static inline void
+INIT_LIST_HEAD(struct list_head *list)
+{
list->prev = list;
list->next = list;
}
@@ -38,30 +41,54 @@ static inline void INIT_LIST_HEAD(struct list_head *list) {
/* Note: list_empty() on entry does not return true after this, the entry is
* in an undefined state.
*/
-static inline void list_del(struct list_head *entry) {
+static inline void
+list_del(struct list_head *entry)
+{
entry->prev->next = entry->next;
entry->next->prev = entry->prev;
entry->next = NULL;
entry->prev = NULL;
}
-static inline void list_add(struct list_head *entry, struct list_head *head) {
+static inline void
+list_add(struct list_head *entry, struct list_head *head)
+{
head->next->prev = entry;
entry->next = head->next;
entry->prev = head;
head->next = entry;
}
-static inline void list_add_tail(struct list_head *entry, struct list_head *head) {
+static inline void
+list_add_tail(struct list_head *entry, struct list_head *head)
+{
head->prev->next = entry;
entry->next = head;
entry->prev = head->prev;
head->prev = entry;
}
-static inline int list_empty(struct list_head *head) {
+static inline int
+list_empty(const struct list_head *head)
+{
return head->next == head;
}
+/* list_is_singular - tests whether a list has just one entry. */
+static inline int
+list_is_singular(const struct list_head *head)
+{
+ return !list_empty(head) && (head->next == head->prev);
+}
+
+/* list_is_last - tests whether @list is the last entry in list @head
+ * list: the entry to test
+ * head: the head of the list
+ */
+static inline int
+list_is_last(const struct list_head *list, const struct list_head *head)
+{
+ return list->next == head;
+}
#endif /* __LIST_H */
diff --git a/include/mmu.h b/include/mmu.h
@@ -41,5 +41,7 @@ void mmu_enable();
void mmu_disable();
int mmu_map_page(void *phys, void *virt, uint_t npages, mmu_ap_t perms);
int kmmap(void *virt, uint_t npages, mmu_ap_t perms);
+uintptr_t virt_to_phys(void *virt);
+int virt_is_mapped(void *virt);
#endif /* __MMU_H */
diff --git a/include/regs.h b/include/regs.h
@@ -0,0 +1,56 @@
+#ifndef __REGS_H
+#define __REGS_H
+
+struct regs {
+ u32 cpsr;
+ union {
+ u32 r[16];
+ struct {
+ u32 r0;
+ u32 r1;
+ u32 r2;
+ u32 r3;
+ u32 r4;
+ u32 r5;
+ u32 r6;
+ u32 r7;
+ u32 r8;
+ u32 r9;
+ u32 r10;
+ u32 r11;
+ u32 r12;
+ u32 r13;
+ u32 r14;
+ u32 r15;
+ };
+ struct {
+ u32 a1; /* r0 */
+ u32 a2; /* r1 */
+ u32 a3; /* r2 */
+ u32 a4; /* r3 */
+ u32 v1; /* r4 */
+ u32 v2; /* r5 */
+ u32 v3; /* r6 */
+ u32 v4; /* r7 */
+ u32 v5; /* r8 */
+ union { /* r9 */
+ u32 v6;
+ u32 sb;
+ };
+ union { /* r10 */
+ u32 v7;
+ u32 sl;
+ };
+ union { /* r11 */
+ u32 v8;
+ u32 fp;
+ };
+ u32 ip; /* r12 */
+ u32 sp; /* r13 */
+ u32 lr; /* r14 */
+ u32 pc; /* r15 */
+ };
+ };
+};
+
+#endif /* __REGS_H */
diff --git a/include/sched.h b/include/sched.h
@@ -0,0 +1,42 @@
+#ifndef __SCHED_H
+#define __SCHED_H
+
+#include <kernel.h>
+#include <spinlock.h>
+#include <list.h>
+
+typedef u32 pid_t;
+
+
+typedef enum {
+ TASK_TERMINATE,
+ TASK_RUNNABLE,
+ TASK_RUNNING,
+ TASK_SLEEP
+} task_state_t;
+
+
+struct task_struct {
+ pid_t pid;
+ task_state_t state;
+ struct regs regs;
+ struct list_head list;
+ spinlock_t *lock;
+ void *stack_alloc;
+};
+
+
+extern struct task_struct *curr_task;
+
+static inline struct task_struct **
+current_task(void)
+{
+ return &curr_task;
+}
+
+#define current (*current_task())
+
+int kthread_create(void (*routine)(void *), void *arg);
+void schedule(void);
+
+#endif /* __SCHED_H */
diff --git a/include/spinlock.h b/include/spinlock.h
@@ -5,7 +5,9 @@
typedef unsigned int spinlock_t;
-static inline void spinlock_lock(spinlock_t *sl) {
+static inline void
+spinlock_lock(spinlock_t *sl)
+{
asm volatile (
"1: \n\t"
"ldrex v1, [%0] \n\t"
@@ -19,7 +21,9 @@ static inline void spinlock_lock(spinlock_t *sl) {
);
}
-static inline void spinlock_unlock(spinlock_t *sl) {
+static inline void
+spinlock_unlock(spinlock_t *sl)
+{
asm volatile (
"str %1, [%0]"
:
@@ -29,7 +33,9 @@ static inline void spinlock_unlock(spinlock_t *sl) {
}
/* returns 1 if locked and 0 if not */
-static inline int spinlock_trylock(spinlock_t *sl) {
+static inline int
+spinlock_trylock(spinlock_t *sl)
+{
unsigned int tmp;
asm volatile (
@@ -47,7 +53,9 @@ static inline int spinlock_trylock(spinlock_t *sl) {
return 0;
}
-static inline void INIT_SPINLOCK(spinlock_t *sl) {
+static inline void
+INIT_SPINLOCK(spinlock_t *sl)
+{
*sl = 0;
}
diff --git a/include/string.h b/include/string.h
@@ -1,47 +1,10 @@
#ifndef __STRING_H
#define __STRING_H
-static inline void *memset(void *s, int c, size_t n) {
- unsigned char *us = s;
+#include <inttypes.h>
- while (n) {
- *us = c;
- us++;
- n--;
- }
-
- return s;
-}
-
-static inline void *memcpy(void *s1, const void *s2, size_t n) {
- unsigned char *us1 = s1;
- const unsigned char *us2 = s2;
-
- while (n) {
- *us1 = *us2;
- us1++;
- us2++;
- n--;
- }
-
- return s1;
-}
-
-static inline int memcmp(const void *s1, const void *s2, size_t n) {
- const unsigned char *us1, *us2;
-
- us1 = s1;
- us2 = s2;
-
- while (n) {
- if (*us1 != *us2)
- return (*us1 - *us2 < 0) ? -1 : 1;
- us1++;
- us2++;
- n--;
- }
-
- return 0;
-}
+void *memset(void *s, int c, size_t n);
+void *memcpy(void *s1, const void *s2, size_t n);
+int memcmp(const void *s1, const void *s2, size_t n);
#endif /* __STRING_H */
diff --git a/include/uart.h b/include/uart.h
@@ -5,12 +5,16 @@
/* TRM p.4459 */
#define TX_FIFO_E (1<<5)
+#define RX_FIFO_E (1<<0)
+#define RHR_IT (1<<0)
+#define IT_PENDING (1<<0)
+#define IT_TYPE_RHR (2<<1)
/* TRM p.4444 */
struct uart {
union { /* 0x00 */
u32 thr;
- const u32 rhr;
+ u32 rhr;
u32 dll;
};
union { /* 0x04 */
@@ -18,7 +22,7 @@ struct uart {
u32 dlh;
};
union { /* 0x08 */
- const u32 iir;
+ u32 iir;
u32 fcr;
u32 efr;
};
@@ -28,12 +32,12 @@ struct uart {
u32 xon1_addr1;
};
union { /* 0x14 */
- const u32 lsr;
+ u32 lsr;
u32 xon2_addr2;
};
union { /* 0x18 */
u32 tcr;
- const u32 msr;
+ u32 msr;
u32 xoff1;
};
union { /* 0x1c */
@@ -44,37 +48,37 @@ struct uart {
u32 mdr1; /* 0x20 */
u32 mdr2; /* 0x24 */
union { /* 0x28 */
- const u32 sflsr;
+ u32 sflsr;
u32 txfll;
};
union { /* 0x2c */
- const u32 resume;
+ u32 resume;
u32 txflh;
};
union { /* 0x30 */
- const u32 sfregl;
+ u32 sfregl;
u32 rxfll;
};
union { /* 0x34 */
- const u32 sfregh;
+ u32 sfregh;
u32 rxflh;
};
union { /* 0x38 */
u32 blr;
- const u32 uasr;
+ u32 uasr;
};
u32 acreg; /* 0x3c */
u32 scr; /* 0x40 */
- const u32 ssr; /* 0x44 */
+ u32 ssr; /* 0x44 */
u32 eblr; /* 0x48 */
u32 __pad; /* 0x4c */
- const u32 mvr; /* 0x50 */
+ u32 mvr; /* 0x50 */
u32 sysc; /* 0x54 */
- const u32 syss; /* 0x58 */
+ u32 syss; /* 0x58 */
u32 wer; /* 0x5c */
u32 cfps; /* 0x60 */
- const u32 rxfifo_lvl; /* 0x64 */
- const u32 txfifo_lvl; /* 0x68 */
+ u32 rxfifo_lvl; /* 0x64 */
+ u32 txfifo_lvl; /* 0x68 */
u32 ier2; /* 0x6c */
u32 isr2; /* 0x70 */
u32 freq_sel; /* 0x74 */
diff --git a/kernel/abort.c b/kernel/abort.c
@@ -0,0 +1,19 @@
+#include <kernel.h>
+
+void
+abort_handler(struct regs *regs, int data)
+{
+ int i;
+
+ if (data)
+ kprintf("\n-DATA ABORT-\n");
+ else
+ kprintf("\n-PREFETCH ABORT-\n");
+
+ for (i = 0; i <= 12; i++)
+ kprintf("r%d: %p\n", i, regs->r[i]);
+ kprintf("sp: %p\n", regs->sp);
+ kprintf("lr: %p\n", regs->lr);
+ kprintf("pc: %p\n", regs->pc - 8);
+ kprintf("cpsr: %p\n", regs->cpsr);
+}
diff --git a/kernel/alloc.c b/kernel/alloc.c
@@ -24,7 +24,9 @@ static void *heap_last;
extern void *_kernel_heap_start;
extern void *_kernel_heap_end;
-static size_t roundup(size_t size) {
+static size_t
+roundup(size_t size)
+{
size_t ret;
if (size <= 16)
@@ -42,7 +44,9 @@ static size_t roundup(size_t size) {
return ret >> 1;
}
-void *kmalloc(size_t size) {
+void *
+kmalloc(size_t size)
+{
int ret;
uint_t npages;
uintptr_t heap_last_a, tmp_addr;
@@ -100,7 +104,9 @@ void *kmalloc(size_t size) {
return memc->start;
}
-void kfree(void *addr) {
+void
+kfree(void *addr)
+{
struct mem_chunk *memc, *tmp;
struct list_head *pos;
@@ -121,25 +127,29 @@ void kfree(void *addr) {
}
-void kdump() {
+void
+kdump(void)
+{
struct list_head *pos, *tmp;
struct mem_chunk *memc;
kprintf("alloc list\n");
list_for_each_safe(pos, tmp, &alloclist) {
memc = list_entry(pos, struct mem_chunk, list);
- kprintf("%p %p %d\n", memc, memc->start, memc->size);
+ kprintf("%p (phys: %p): %p %p %d\n", pos, virt_to_phys(pos), memc, memc->start, memc->size);
}
kprintf("\nfree list\n");
list_for_each_safe(pos, tmp, &freelist) {
memc = list_entry(pos, struct mem_chunk, list);
- kprintf("%p %p %d\n", memc, memc->start, memc->size);
+ kprintf("%p (phys: %p): %p %p %d\n", pos, virt_to_phys(pos), memc, memc->start, memc->size);
}
}
__attribute__ ((__constructor__))
-static void alloc_init() {
+static void
+alloc_init(void)
+{
INIT_LIST_HEAD(&freelist);
INIT_LIST_HEAD(&alloclist);
heap_last = &_kernel_heap_start;
diff --git a/kernel/debug.c b/kernel/debug.c
@@ -4,7 +4,9 @@
static u32 *gpio_wk7 = (u32*)0x4A31E058;
static u32 *gpio_wk8 = (u32*)0x4A31E05C;
-void set_led_d1(int on) {
+void
+set_led_d1(int on)
+{
u32 cur = readl(gpio_wk7) & 0xffff;
if (on)
cur |= 0x001B0000;
@@ -13,7 +15,9 @@ void set_led_d1(int on) {
writel(cur, gpio_wk7);
}
-void set_led_d2(int on) {
+void
+set_led_d2(int on)
+{
u32 cur = readl(gpio_wk8) & 0xffff0000;
if (on)
cur |= 0x001B;
@@ -22,7 +26,37 @@ void set_led_d2(int on) {
writel(cur, gpio_wk8);
}
-void set_leds(int on) {
+void
+set_leds(int on)
+{
set_led_d1(on);
set_led_d2(on);
}
+
+static void
+_kstackdump(void *sp)
+{
+ u32 *stack = sp;
+ int i;
+
+ for (i = 10; i >= 0; i--) {
+ kprintf("%p: %p\n", &stack[i], stack[i]);
+ }
+}
+
+__attribute__((__naked__))
+void
+kstackdump(void)
+{
+ asm volatile (
+ "mov r0, sp \n\t"
+ "str lr, [sp, #-4]! \n\t"
+ "ldr lr, =1f \n\t"
+ "mov pc, %0 \n\t"
+ "1: \n\t"
+ "ldr pc, [sp], #4 \n\t"
+ :
+ : "r" (_kstackdump)
+ : "r0"
+ );
+}
diff --git a/kernel/dmtimer.c b/kernel/dmtimer.c
@@ -0,0 +1,252 @@
+#include <kernel.h>
+#include <irq.h>
+#include <dmtimer.h>
+
+#define DMT_OVF_ENA_FLAG (1<<1)
+#define DMT_TCLR_ST (1<<0)
+#define DMT_TCLR_AR (1<<1)
+
+#define DMT_1MS_TIOCP_SOFTRESET (1<<1)
+#define DMT_1MS_TIOCP_SMARTIDLE (2<<3)
+#define DMT_1MS_TISTAT_RESETDONE (1<<0)
+
+/* gptimer1, gptimer2, gptimer10 */
+struct dm_gpt_1ms {
+ u32 tidr;
+ u32 _pad1[3];
+ u32 tiocp_1ms_cfg;
+ u32 tistat;
+ u32 tisr;
+ u32 tier;
+ u32 twer;
+ u32 tclr;
+ u32 tcrr;
+ u32 tldr;
+ u32 ttgr;
+ u32 twps;
+ u32 tmar;
+ u32 tcar1;
+ u32 tsicr;
+ u32 tcar2;
+ u32 tpir;
+ u32 tnir;
+ u32 tcvr;
+ u32 tocr;
+ u32 towr;
+};
+
+
+#define DMT_TIOCP_SOFTRESET (1<<0)
+#define DMT_TIOCP_SMARTIDLE (2<<2)
+
+/* gptimer3, gptimer4, gptimer5, gptimer6
+ * gptimer7, gptimer8, gptimer9, gptimer11
+ */
+struct dm_gpt {
+ u32 tidr;
+ u32 _pad1[3];
+ u32 tiocp_cfg;
+ u32 _pad2[4];
+ u32 irqstatus_raw;
+ u32 irqstatus;
+ u32 irqenable_set;
+ u32 irqenable_clr;
+ u32 irqwakeen;
+ u32 tclr;
+ u32 tcrr;
+ u32 tldr;
+ u32 ttgr;
+ u32 twps;
+ u32 tmar;
+ u32 tcar1;
+ u32 tsicr;
+ u32 tcar2;
+};
+
+
+#define DMT_1MS (1<<0)
+#define CM2_CLKSEL (1<<24)
+
+struct dmtimer {
+ u32 flags;
+ dmtimer_callback_func callback_func;
+ union {
+ u32 *mem;
+ struct dm_gpt_1ms *dmt_1ms;
+ struct dm_gpt *dmt;
+ };
+ /* L4PER CM2 register */
+ u32 *cm2r;
+} dmtimers[] = {
+ { DMT_1MS, NULL, { .mem = (u32*)0x4a318000 }, NULL }, /* GPTIMER1 */
+ { DMT_1MS, NULL, { .mem = (u32*)0x48032000 }, (u32*)0x4a009438 }, /* GPTIMER2 */
+ { 0, NULL, { .mem = (u32*)0x48034000 }, (u32*)0x4a009440 }, /* GPTIMER3 */
+ { 0, NULL, { .mem = (u32*)0x48036000 }, (u32*)0x4a009448 }, /* GPTIMER4 */
+
+ /* GPTIMER 5 - 8 are not implemented yet */
+ { 0, NULL, { .mem = (u32*)NULL }, NULL }, /* GPTIMER5 */
+ { 0, NULL, { .mem = (u32*)NULL }, NULL }, /* GPTIMER6 */
+ { 0, NULL, { .mem = (u32*)NULL }, NULL }, /* GPTIMER7 */
+ { 0, NULL, { .mem = (u32*)NULL }, NULL }, /* GPTIMER8 */
+
+ { 0, NULL, { .mem = (u32*)0x4803e000 }, (u32*)0x4a009450 }, /* GPTIMER9 */
+ { DMT_1MS, NULL, { .mem = (u32*)0x48086000 }, (u32*)0x4a009428 }, /* GPTIMER10 */
+ { 0, NULL, { .mem = (u32*)0x48088000 }, (u32*)0x4a009430 } /* GPTIMER11 */
+};
+
+
+
+static void
+dmtimer_irq_callback(u32 irq_num, struct regs *regs)
+{
+ u32 val;
+ int id;
+
+ if (irq_num < HW_IRQ(37) || irq_num > HW_IRQ(47))
+ return;
+
+ id = irq_num - HW_IRQ(37);
+
+ if (dmtimers[id].mem == NULL)
+ return;
+
+ /* read type of event */
+ if (dmtimers[id].flags & DMT_1MS)
+ val = readl(&dmtimers[id].dmt_1ms->tisr);
+ else
+ val = readl(&dmtimers[id].dmt->irqstatus);
+
+ if (dmtimers[id].callback_func)
+ dmtimers[id].callback_func(id + 1, regs);
+
+ /* clear event by writing 1 to the bits */
+ if (dmtimers[id].flags & DMT_1MS)
+ writel(val, &dmtimers[id].dmt_1ms->tisr);
+ else
+ writel(val, &dmtimers[id].dmt->irqstatus);
+}
+
+static int
+reset_timer(int id)
+{
+ u32 val;
+
+ if (id <= 0 || id > 11)
+ return -EINVAL;
+
+ id--;
+
+ /* not implemented yet */
+ if (dmtimers[id].mem == NULL)
+ return -ENOSYS;
+
+ if (dmtimers[id].flags & DMT_1MS) {
+ /* request reset */
+ writel(DMT_1MS_TIOCP_SOFTRESET, &dmtimers[id].dmt_1ms->tiocp_1ms_cfg);
+ /* wait until reset is done */
+ while (!(readl(&dmtimers[id].dmt_1ms->tistat) & DMT_1MS_TISTAT_RESETDONE))
+ ;
+ } else {
+ /* request reset */
+ writel(DMT_TIOCP_SOFTRESET, &dmtimers[id].dmt->tiocp_cfg);
+ /* wait until reset is done */
+ while (readl(&dmtimers[id].dmt->tiocp_cfg) & DMT_TIOCP_SOFTRESET)
+ ;
+ }
+
+ /* enable 32KHz clock */
+ if (dmtimers[id].cm2r) {
+ val = readl(dmtimers[id].cm2r);
+ val |= CM2_CLKSEL;
+ writel(val, dmtimers[id].cm2r);
+ }
+
+ return 0;
+}
+
+int
+dmtimer_trigger(int id)
+{
+ if (id <= 0 || id > 11)
+ return -EINVAL;
+
+ id--;
+
+ /* not implemented yet */
+ if (dmtimers[id].mem == NULL)
+ return -ENOSYS;
+
+ /* manually overflow the timer */
+ if (dmtimers[id].flags & DMT_1MS)
+ writel(0xffffffff, &dmtimers[id].dmt_1ms->tcrr);
+ else
+ writel(0xffffffff, &dmtimers[id].dmt->tcrr);
+
+ return 0;
+}
+
+int
+dmtimer_register(int id, dmtimer_callback_func func, u32 ms)
+{
+ int ret;
+ u32 val;
+
+ if (id <= 0 || id > 11 || ms == 0 || func == NULL)
+ return -EINVAL;
+
+ /* not implemented yet */
+ if (dmtimers[id - 1].mem == NULL)
+ return -ENOSYS;
+
+ ret = reset_timer(id);
+ if (ret)
+ return ret;
+
+ id--;
+ ret = irq_register(HW_IRQ(37) + id, dmtimer_irq_callback);
+ if (ret)
+ return ret;
+ dmtimers[id].callback_func = func;
+
+ if (dmtimers[id].flags & DMT_1MS) {
+ /* enable start-idle */
+ writel(DMT_1MS_TIOCP_SMARTIDLE, &dmtimers[id].dmt_1ms->tiocp_1ms_cfg);
+
+ /* set microseconds */
+ val = 0xffffffff;
+ val -= ms * 32;
+ writel(val, &dmtimers[id].dmt_1ms->tldr);
+
+ /* writing to TTGR causes TCRR to be loaded from TLDR */
+ writel(1, &dmtimers[id].dmt_1ms->ttgr);
+ /* enable overflow interrupt */
+ writel(DMT_OVF_ENA_FLAG, &dmtimers[id].dmt_1ms->tier);
+ /* start timer and enable autoreload */
+ writel(DMT_TCLR_ST | DMT_TCLR_AR, &dmtimers[id].dmt_1ms->tclr);
+ } else {
+ /* enable start-idle */
+ writel(DMT_TIOCP_SMARTIDLE, &dmtimers[id].dmt->tiocp_cfg);
+
+ /* set microseconds */
+ val = 0xffffffff;
+ val -= ms * 32;
+ writel(val, &dmtimers[id].dmt->tldr);
+
+ /* writing to TTGR causes TCRR to be loaded from TLDR */
+ writel(1, &dmtimers[id].dmt->ttgr);
+ /* enable overflow interrupt */
+ writel(DMT_OVF_ENA_FLAG, &dmtimers[id].dmt->irqenable_set);
+ /* start timer and enable autoreload */
+ writel(DMT_TCLR_ST | DMT_TCLR_AR, &dmtimers[id].dmt->tclr);
+ }
+
+ return 0;
+}
+
+void
+dmtimer_init(void)
+{
+ int i;
+ for (i = 1; i <= 11; i++)
+ reset_timer(i);
+}
diff --git a/kernel/gic.c b/kernel/gic.c
@@ -0,0 +1,110 @@
+#include <kernel.h>
+#include <irq.h>
+#include <gic.h>
+
+#define IAR_ID(x) (x & 0x3ff)
+
+/* GICv1 CPU interface registers */
+struct gicc {
+ u32 ctlr;
+ u32 pmr;
+ u32 bpr;
+ u32 iar;
+ u32 eoir;
+ u32 rpr;
+ u32 hppir;
+ u32 abpr;
+ u32 _pad[55];
+ u32 iidr;
+};
+
+#define MAX_IT_LINES_NUMBER 32
+
+/* GICv1 Distributor registers */
+struct gicd {
+ u32 ctlr;
+ u32 typer;
+ u32 iidr;
+ u32 _pad1[29];
+ u32 igrour[MAX_IT_LINES_NUMBER];
+ u32 isenabler[MAX_IT_LINES_NUMBER];
+ u32 icenabler[MAX_IT_LINES_NUMBER];
+ u32 ispendr[MAX_IT_LINES_NUMBER];
+ u32 icpendr[MAX_IT_LINES_NUMBER];
+ u32 isactiver[MAX_IT_LINES_NUMBER];
+ u32 _pad2[32];
+ u32 ipriorityr[8 * MAX_IT_LINES_NUMBER];
+ u32 itargetsr[8 * MAX_IT_LINES_NUMBER];
+ u32 icfgr[2 * MAX_IT_LINES_NUMBER];
+ u32 _pad3[128];
+ u32 sgir;
+};
+
+static struct gicc *gicc = (struct gicc*)0x48240100;
+static struct gicd *gicd = (struct gicd*)0x48241000;
+static irq_callback_func irq_handlers[NUM_OF_IRQ];
+
+
+int
+gic_register(u32 irq_num, irq_callback_func func)
+{
+ int i;
+ u32 val;
+
+ if (irq_num >= NUM_OF_IRQ)
+ return -EINVAL;
+
+ /* set callback function */
+ irq_handlers[irq_num] = func;
+
+ /* enable irq number */
+ i = irq_num / 32;
+ val = readl(&gicd->isenabler[i]);
+ val |= 1 << (irq_num % 32);
+ writel(val, &gicd->isenabler[i]);
+
+ /* send the interrupt to CPU0 */
+ i = irq_num / 4;
+ val = readl(&gicd->itargetsr[i]);
+ val &= ~(0xff << (8 * (irq_num % 4)));
+ val |= 1 << (8 * (irq_num % 4));
+ writel(val, &gicd->itargetsr[i]);
+
+ return 0;
+}
+
+void
+gic_handler(struct regs *regs)
+{
+ u32 iar, id;
+
+ /* read interrupt id */
+ iar = readl(&gicc->iar);
+ id = IAR_ID(iar);
+
+ /* call handler */
+ if (id < NUM_OF_IRQ && irq_handlers[id] != NULL)
+ irq_handlers[id](id, regs);
+
+ /* end of interrupt */
+ writel(iar, &gicc->eoir);
+}
+
+void
+gic_init(void)
+{
+ /* disable gic cpu interface */
+ writel(0, &gicc->ctlr);
+ /* disable gic distributor */
+ writel(0, &gicd->ctlr);
+
+ /* make sure that software interrupts are enabled */
+ writel(0xffff, &gicd->isenabler[0]);
+
+ /* set lower priority level */
+ writel(0xf0, &gicc->pmr);
+ /* enable gic cpu interface */
+ writel(1, &gicc->ctlr);
+ /* enable gic cpu distributor */
+ writel(1, &gicd->ctlr);
+}
diff --git a/kernel/interrupts.S b/kernel/interrupts.S
@@ -1,3 +1,5 @@
+#include <p_modes.h>
+
.section .text
.global vector_table_init
vector_table_init:
@@ -24,6 +26,48 @@ vector_table:
.ltorg
+@@ save all the registers
+.macro SAVE_ALL_EX
+ stmfd sp!, { lr } @ save lr (pc (r15) of the previous mode)
+ sub sp, sp, #8 @ make space for sp (r13) and lr (r14) registers
+ stmfd sp!, { r0 - r12 } @ save r0 until r12
+ mrs r0, spsr @ save spsr (cpsr of the previus mode)
+ str r0, [sp, #-4]! @ save cpsr
+ bic r0, r0, #0x60 @ clear F, T flags
+ orr r0, r0, #(1 << 7) @ set I flag
+ mrs r2, cpsr @ backup current cpsr
+ msr cpsr_c, r0 @ switch to previous mode
+ mov r0, sp
+ mov r1, lr
+ msr cpsr, r2 @ swith back to the current mode
+ str r0, [sp, #(4 * 14)] @ save sp (r13)
+ str r1, [sp, #(4 * 15)] @ save lr (r14)
+
+ ldr r0, [sp, #4] @ restore destroyed registers
+ ldr r1, [sp, #8]
+ ldr r2, [sp, #12]
+.endm
+
+@@ restore registers
+.macro RESTORE_ALL_EX
+ ldr r1, [sp, #(4 * 14)] @ load sp (r13)
+ ldr r2, [sp, #(4 * 15)] @ load lr (r14)
+ ldr r0, [sp]
+ bic r0, r0, #0x60
+ orr r0, r0, #(1 << 7) @ get the previous mode number
+ mrs r3, cpsr
+ msr cpsr_c, r0 @ switch to previous mode
+ mov sp, r1
+ mov lr, r2
+ msr cpsr, r3 @ swith back to the current mode
+ ldr r0, [sp], #4 @ load spsr (cpsr of the previus mode)
+ msr spsr, r0
+ ldmfd sp!, { r0 - r12 }
+ add sp, sp, #8 @ release the space we had for sp (r13) and lr (r14)
+ ldr lr, [sp], #4 @ load lr (pc (r15) of the previous mode)
+.endm
+
+
reset:
b .
@@ -47,11 +91,10 @@ swi_ex:
bic r6, r6, #0xff000000
stmfd sp!, { r4, r5 }
- ldr lr, =.Lsyscall_ret
+ ldr lr, =1f
ldr r7, =syscall_table
ldr pc, [r7, r6, lsl #2]
-
-.Lsyscall_ret:
+1:
add sp, sp, #8
ldr r6, [sp], #4
msr spsr, r6
@@ -59,19 +102,45 @@ swi_ex:
prefetch_abort:
- subs pc, lr, #4
+ @@ save registers
+ SAVE_ALL_EX
+ @@ set led d1 on
+ mov r0, #1
+ bl set_led_d1
+ @@ call handler
+ mov r0, sp @ pass a pointer to the registers
+ mov r1, #0 @ 0 = prefetch
+ bl abort_handler @ call handler
+
+ b . @ freeze
+ @subs pc, lr, #4
data_abort:
- subs pc, lr, #8
+ @@ save registers
+ SAVE_ALL_EX
+ @@ set led d2 on
+ mov r0, #1
+ bl set_led_d2
+ @@ call handler
+ mov r0, sp @ pass a pointer to the registers
+ mov r1, #1 @ 1 = data
+ bl abort_handler @ call handler
+
+ b . @ freeze
+ @subs pc, lr, #8
irq_ex:
- sub lr, lr, #4
- str lr, [sp, #-4]!
- mov r0, #1
- bl set_led_d1
- ldmfd sp!, { pc }^
+ @@ save registers
+ SAVE_ALL_EX
+ @@ call handler
+ mov r0, sp @ pass a pointer to the registers
+ bl irq_handler @ call irq_handler
+ @@ restore registers
+ RESTORE_ALL_EX
+ @@ exit exception
+ subs pc, lr, #4
fiq_ex:
diff --git a/kernel/irq.c b/kernel/irq.c
@@ -0,0 +1,21 @@
+#include <kernel.h>
+#include <gic.h>
+#include <irq.h>
+
+int
+irq_register(u32 irq_num, irq_callback_func func)
+{
+ return gic_register(irq_num, func);
+}
+
+void
+irq_handler(struct regs *regs)
+{
+ gic_handler(regs);
+}
+
+void
+irq_init(void)
+{
+ gic_init();
+}
diff --git a/kernel/kmain.c b/kernel/kmain.c
@@ -1,10 +1,21 @@
#include <kernel.h>
#include <alloc.h>
#include <string.h>
+#include <gic.h>
+#include <sched.h>
-void kmain(void) {
- kprintf("voron initial stage\n\n");
-
+static void
+thread_func(void *arg)
+{
+ u32 n = (u32)arg;
while (1)
- asm volatile("wfi");
+ kprintf("thread %d\n", n);
+}
+
+void
+kmain(void)
+{
+ kprintf("voron initial stage\n\n");
+ kthread_create(thread_func, (void*)1);
+ kthread_create(thread_func, (void*)2);
}
diff --git a/kernel/linker.ld b/kernel/linker.ld
@@ -49,6 +49,9 @@ SECTIONS
_fiq_stack_top = .;
. = . + 0x2000;
_irq_stack_top = .;
+ . = . + 0x2000;
+ _abort_stack_top = .;
+
_kernel_bin_end = .;
}
diff --git a/kernel/mm.c b/kernel/mm.c
@@ -18,7 +18,9 @@ static uint_t kheapbound_s;
static uint_t kheapbound_e;
/* set range of bits */
-static int set_bitmap_bits(uint_t start_bit, uint_t n, int flag) {
+static int
+set_bitmap_bits(uint_t start_bit, uint_t n, int flag)
+{
uint_t bound_s, bound_e, i;
u32 bits;
@@ -62,7 +64,10 @@ static int set_bitmap_bits(uint_t start_bit, uint_t n, int flag) {
return 0;
}
-void mm_init() {
+void *palloc(uint_t n);
+void
+mm_init()
+{
uint_t i;
size_t ramsz;
@@ -96,7 +101,9 @@ void mm_init() {
mmu_enable();
}
-void *palloc(uint_t npages) {
+void *
+palloc(uint_t npages)
+{
uint_t i, j, n;
uint_t sbit;
int ret;
@@ -114,7 +121,7 @@ void *palloc(uint_t npages) {
else if (!(bitmap[i] & (1 << j)))
n++;
if (n == npages) {
- sbit = i * 32 + j - n;
+ sbit = i * 32 + j - n + 1;
goto out;
}
}
@@ -131,7 +138,9 @@ out:
return (void*)((uintptr_t)sbit * PAGE_SIZE + (uintptr_t)&_ram_start);
}
-int pfree(void *paddr, uint_t npages) {
+int
+pfree(void *paddr, uint_t npages)
+{
uintptr_t paddr_a = (uintptr_t)paddr;
uint_t sbit;
diff --git a/kernel/mmu.c b/kernel/mmu.c
@@ -5,7 +5,9 @@
static u32 mmu_ttb[4096] __attribute__((__aligned__ (16 * 1024)));
static u32 l2[4096][256] __attribute__((__aligned__ (1024)));
-void mmu_init() {
+void
+mmu_init(void)
+{
int i;
for (i = 0; i < 4096; i++)
@@ -35,7 +37,9 @@ void mmu_init() {
);
}
-void mmu_enable() {
+void
+mmu_enable(void)
+{
asm volatile (
/* invalidate TLB */
"mcr p15, 0, v1, c8, c7, 0 \n\t"
@@ -47,7 +51,9 @@ void mmu_enable() {
);
}
-void mmu_disable() {
+void
+mmu_disable(void)
+{
asm volatile (
/* disable MMU */
"mrc p15, 0, v1, c1, c0, 0 \n\t"
@@ -57,7 +63,38 @@ void mmu_disable() {
);
}
-static int is_mapped_virt(void *virt) {
+uintptr_t
+virt_to_phys(void *virt)
+{
+ uint_t pte_idx, pde_idx;
+ u32 *pde;
+ uintptr_t virt_a;
+
+ virt_a = (uintptr_t)virt;
+ pde_idx = virt_a >> 20;
+
+ switch (mmu_ttb[pde_idx] & L1_TYPE_MASK) {
+ case 1: /* page table */
+ pde = (u32*)(mmu_ttb[pde_idx] & ~0x3ff);
+ pte_idx = (virt_a & 0xff000) >> 12;
+ if (pde[pte_idx] & L2_TYPE_MASK)
+ return ((pde[pte_idx] & ~0xfff) | (virt_a & 0xfff));
+ else
+ return 0; /* not mapped */
+ case 2: /* section */
+ return ((mmu_ttb[pde_idx] & ~0xfffff) | (virt_a & 0xfffff));
+ case 0: /* not mapped */
+ default:
+ return 0;
+ }
+
+ /* not mapped */
+ return 0;
+}
+
+int
+virt_is_mapped(void *virt)
+{
uint_t pte_idx, pde_idx;
u32 *pde;
uintptr_t virt_a;
@@ -84,7 +121,9 @@ static int is_mapped_virt(void *virt) {
}
/* map physical memory to virtual memory */
-int mmu_map_page(void *phys, void *virt, uint_t npages, mmu_ap_t perms) {
+int
+mmu_map_page(void *phys, void *virt, uint_t npages, mmu_ap_t perms)
+{
u32 pte, pte_perms;
u32 *pde;
uintptr_t phys_a, virt_a;
@@ -151,7 +190,9 @@ int mmu_map_page(void *phys, void *virt, uint_t npages, mmu_ap_t perms) {
return 0;
}
-int kmmap(void *virt, uint_t npages, mmu_ap_t perms) {
+int
+kmmap(void *virt, uint_t npages, mmu_ap_t perms)
+{
uint_t i;
uintptr_t virt_a;
void *pa;
@@ -166,13 +207,13 @@ int kmmap(void *virt, uint_t npages, mmu_ap_t perms) {
return -EFAULT;
for (i = 0; i < npages; i++) {
- if (is_mapped_virt((void*)virt_a)) {
+ if (virt_is_mapped((void*)virt_a)) {
kprintf("WARNING: %p virtual address is already maped\n", virt);
virt_a += PAGE_SIZE;
continue;
}
pa = palloc(1);
- mmu_map_page(pa, virt, 1, perms);
+ mmu_map_page(pa, (void*)virt_a, 1, perms);
virt_a += PAGE_SIZE;
}
diff --git a/kernel/print.c b/kernel/print.c
@@ -1,21 +1,29 @@
#include <kernel.h>
#include <rs232.h>
-int kputs(const char *s) {
+int
+kputs(const char *s)
+{
return rs232_puts(s);
}
-int kputchar(int c) {
+int
+kputchar(int c)
+{
return rs232_putchar(c);
}
-static inline int abs(int n) {
+static inline int
+abs(int n)
+{
if (n < 0)
return -n;
return n;
}
-static int print_int(int n) {
+static int
+print_int(int n)
+{
int ret = 0, i = 1;
if (n > 0) {
@@ -38,7 +46,9 @@ static int print_int(int n) {
return ret;
}
-static int print_hexint(uint_t n) {
+static int
+print_hexint(uint_t n)
+{
uint_t x, mask;
int i, bits, b, ret = 0;
@@ -72,7 +82,9 @@ static int print_hexint(uint_t n) {
return ret;
}
-static int print_pointer(uintptr_t p) {
+static int
+print_pointer(uintptr_t p)
+{
uintptr_t x, mask;
int i, bits, b, ret = 0;
@@ -102,7 +114,9 @@ static int print_pointer(uintptr_t p) {
return ret;
}
-int kprintf(const char *fmt, ...) {
+int
+kprintf(const char *fmt, ...)
+{
va_list ap;
int ret;
@@ -113,7 +127,9 @@ int kprintf(const char *fmt, ...) {
return ret;
}
-int kvprintf(const char *fmt, va_list ap) {
+int
+kvprintf(const char *fmt, va_list ap)
+{
int d, ret = 0;
uint_t x;
uintptr_t p;
diff --git a/kernel/rs232.c b/kernel/rs232.c
@@ -1,10 +1,15 @@
#include <kernel.h>
+#include <irq.h>
#include <rs232.h>
#include <uart.h>
+/* UART3 */
+#define UART_IRQ_NUM (HW_IRQ(74))
static struct uart *uart = (struct uart*)0x48020000;
-int rs232_puts(const char *s) {
+int
+rs232_puts(const char *s)
+{
int ret = 0;
while (s[ret]) {
@@ -15,7 +20,9 @@ int rs232_puts(const char *s) {
return ret;
}
-int rs232_putchar(int c) {
+int
+rs232_putchar(int c)
+{
if (c == '\n') {
while ((readl(&uart->lsr) & TX_FIFO_E) == 0)
;
@@ -28,3 +35,28 @@ int rs232_putchar(int c) {
writel(c, &uart->thr);
return c;
}
+
+int
+rs232_getchar(void)
+{
+ while ((readl(&uart->lsr) & RX_FIFO_E) == 0)
+ ;
+ return readl(&uart->rhr);
+}
+
+static void
+rs232_irq_handler(__unused u32 irq_num, __unused struct regs *regs)
+{
+ while(!(readl(&uart->iir) & IT_PENDING)) {
+ if (readl(&uart->iir) & IT_TYPE_RHR)
+ rs232_putchar(rs232_getchar());
+ }
+}
+
+__attribute__((constructor))
+void
+rs232_init(void)
+{
+ irq_register(UART_IRQ_NUM, rs232_irq_handler);
+ writel(RHR_IT, &uart->ier);
+}
diff --git a/kernel/sched.c b/kernel/sched.c
@@ -0,0 +1,134 @@
+#include <kernel.h>
+#include <list.h>
+#include <spinlock.h>
+#include <dmtimer.h>
+#include <sched.h>
+#include <mmu.h>
+#include <p_modes.h>
+
+struct task_struct *curr_task = NULL;
+static struct list_head task_list_head;
+static spinlock_t task_struct_lock = SPINLOCK_INIT;
+
+static pid_t
+get_new_pid(void)
+{
+ static pid_t currpid = 0;
+ static spinlock_t lock = SPINLOCK_INIT;
+ pid_t new_pid;
+
+ spinlock_lock(&lock);
+ new_pid = ++currpid;
+ spinlock_unlock(&lock);
+
+ return new_pid;
+}
+
+static void
+task_remove(void)
+{
+ current->state = TASK_TERMINATE;
+ /* force schedule */
+ schedule();
+}
+
+int
+kthread_create(void (*routine)(void *), void *arg)
+{
+ struct task_struct *task;
+
+ task = kmalloc(sizeof(*task));
+ if (!task)
+ return -ENOMEM;
+
+ /* allocate stack */
+ task->stack_alloc = kmalloc(PAGE_SIZE);
+ if (!task->stack_alloc) {
+ kfree(task);
+ return -ENOMEM;
+ }
+
+ task->state = TASK_RUNNABLE;
+ task->pid = get_new_pid();
+ task->lock = &task_struct_lock;
+ memset(&task->regs, 0, sizeof(task->regs));
+ /* set thread stack */
+ task->regs.sp = (u32)task->stack_alloc;
+ task->regs.sp += PAGE_SIZE;
+ /* set argument */
+ task->regs.r0 = (u32)arg;
+ /* set the function that new thread will execute
+ * we must add 4 because irq_ex will subtract 4 */
+ task->regs.pc = (u32)routine;
+ task->regs.pc += 4;
+ /* set return address */
+ task->regs.lr = (u32)&task_remove;
+ /* thread will run in System mode */
+ task->regs.cpsr = CPS_SYS;
+
+ /* add it to task list of the scheduler */
+ spinlock_lock(task->lock);
+ list_add(&task->list, &task_list_head);
+ spinlock_unlock(task->lock);
+
+ return 0;
+}
+
+void
+schedule(void)
+{
+ /* trigger scheduler timer */
+ dmtimer_trigger(1);
+ while(1)
+ asm volatile("wfi");
+}
+
+static void
+sched(struct regs *regs)
+{
+ struct task_struct *prev = current;
+
+ if (list_empty(&task_list_head))
+ return;
+
+ if (prev) {
+ if (prev->state != TASK_TERMINATE)
+ prev->regs = *regs;
+
+ if (list_is_last(&prev->list, &task_list_head))
+ current = list_first_entry(&task_list_head, struct task_struct, list);
+ else
+ current = list_entry(prev->list.next, struct task_struct, list);
+
+ if (prev->state == TASK_TERMINATE) {
+ spinlock_lock(prev->lock);
+ list_del(&prev->list);
+ spinlock_unlock(prev->lock);
+ kfree(prev->stack_alloc);
+ kfree(prev);
+ if (list_empty(&task_list_head))
+ current = NULL;
+ } else
+ current->state = TASK_RUNNABLE;
+ } else
+ current = list_first_entry(&task_list_head, struct task_struct, list);
+
+ if (current) {
+ current->state = TASK_RUNNING;
+ *regs = current->regs;
+ }
+}
+
+static void
+sched_handler(__unused int timer_id, struct regs *regs)
+{
+ sched(regs);
+}
+
+__attribute__((__constructor__))
+void
+sched_init(void)
+{
+ INIT_LIST_HEAD(&task_list_head);
+ dmtimer_register(1, sched_handler, 10);
+}
diff --git a/kernel/start.S b/kernel/start.S
@@ -33,31 +33,39 @@ _start:
bic r0, r0, #(1 << 2) @ set C flag to 0 (disable data cache)
mcr p15, 0, r0, c1, c0, 0
+ /* initialize memory management */
+ bl mm_init
+
+ /* initialize interrupts */
cps #CPS_FIQ @ change to FIQ mode
ldr sp, =_fiq_stack_top @ set FIQ stack
cps #CPS_IRQ @ change to IRQ mode
ldr sp, =_irq_stack_top @ set IRQ stack
- cps #CPS_SVC @ change to SVC mode
+ cps #CPS_ABT @ change to Abort mode
+ ldr sp, =_abort_stack_top @ set stack
+
+ cps #CPS_SVC @ change back to SVC mode
+ bl irq_init @ initialize controler
cpsie if @ enable interrupts
- bl mm_init
+ bl dmtimer_init
/* run constructors */
ldr r0, =_kernel_ctors_start
ldr r1, =_kernel_ctors_end
1:
teq r0, r1
- beq 2f
+ beq 3f
ldr r2, [r0], #4
stmfd sp!, { r0, r1 }
- ldr lr, =.Lctor_ret
+ ldr lr, =2f
mov pc, r2
-.Lctor_ret:
+2:
ldmfd sp!, { r0, r1 }
b 1b
-2:
+3:
/* example of calling a system call with at least 6 arguments */
mov r0, #1
@@ -82,8 +90,10 @@ _start:
swi #1
add sp, sp, #(7 * 4)
- bl kmain
- b .
+ ldr r0, =kmain
+ mov r1, #0
+ bl kthread_create
+ b schedule
.section .rodata
boot_msg:
diff --git a/kernel/string.c b/kernel/string.c
@@ -0,0 +1,51 @@
+#include <inttypes.h>
+#include <string.h>
+
+void *
+memset(void *s, int c, size_t n)
+{
+ unsigned char *us = s;
+
+ while (n) {
+ *us = c;
+ us++;
+ n--;
+ }
+
+ return s;
+}
+
+void *
+memcpy(void *s1, const void *s2, size_t n)
+{
+ unsigned char *us1 = s1;
+ const unsigned char *us2 = s2;
+
+ while (n) {
+ *us1 = *us2;
+ us1++;
+ us2++;
+ n--;
+ }
+
+ return s1;
+}
+
+int
+memcmp(const void *s1, const void *s2, size_t n)
+{
+ const unsigned char *us1, *us2;
+
+ us1 = s1;
+ us2 = s2;
+
+ while (n) {
+ if (*us1 != *us2)
+ return (*us1 - *us2 < 0) ? -1 : 1;
+ us1++;
+ us2++;
+ n--;
+ }
+
+ return 0;
+}
diff --git a/kernel/syscalls.c b/kernel/syscalls.c
@@ -1,6 +1,8 @@
#include <kernel.h>
-long sys_test_6_args(u32 a1, u32 a2, u32 a3, u32 a4, u32 a5, u32 a6) {
+long
+sys_test_6_args(u32 a1, u32 a2, u32 a3, u32 a4, u32 a5, u32 a6)
+{
kprintf("sys_test_6_args(%d, %d, %d, %d, %d, %d)\n", a1, a2, a3, a4, a5, a6);
return 0;
}
@@ -16,7 +18,9 @@ struct __test_7_args {
u32 a7;
};
-long sys_test_7_args(struct __test_7_args *a) {
+long
+sys_test_7_args(struct __test_7_args *a)
+{
kprintf("sys_test_7_args(%d, %d, %d, %d, %d, %d, %d)\n",
a->a1, a->a2, a->a3, a->a4, a->a5, a->a6, a->a7);
return 0;