From 3786c9e9e597637d954a54c1d2a2c748c161d2e6 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Mon, 13 Oct 2014 14:53:21 +0800 Subject: [PATCH 01/43] [arm64] fix minor issue in the interrupt function 1.don't update F bit in arch_[dis|en]able_ints 2.get interrupt flag through daif instead of cspr Change-Id: I1dbbe9493e1036a25095226f44607a5e3d62aaab Signed-off-by: Xiang Xiao --- arch/arm64/include/arch/arch_ops.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/arch/arch_ops.h b/arch/arm64/include/arch/arch_ops.h index 2a12d7bee..4efa24e15 100644 --- a/arch/arm64/include/arch/arch_ops.h +++ b/arch/arm64/include/arch/arch_ops.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -36,12 +37,12 @@ static inline void arch_enable_ints(void) { CF; - __asm__ volatile("msr daifclr, #3" ::: "memory"); + __asm__ volatile("msr daifclr, #2" ::: "memory"); } static inline void arch_disable_ints(void) { - __asm__ volatile("msr daifset, #3" ::: "memory"); + __asm__ volatile("msr daifset, #2" ::: "memory"); CF; } @@ -50,8 +51,8 @@ static inline bool arch_ints_disabled(void) { unsigned int state; - __asm__ volatile("mrs %0, cpsr" : "=r"(state)); - state &= (1<<7); + __asm__ volatile("mrs %0, daif" : "=r"(state)); + state &= (1<<1); return !!state; } From 97f625effadd46c2db0b9f0659309bb00f307a5e Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Mon, 13 Oct 2014 14:57:36 +0800 Subject: [PATCH 02/43] [arm64] implement fiq arch function Change-Id: Iecbb55c13f00ea8eacf0db74112df6889a71d444 Signed-off-by: Xiang Xiao --- arch/arm64/include/arch/arch_ops.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm64/include/arch/arch_ops.h b/arch/arm64/include/arch/arch_ops.h index 4efa24e15..6a9e74536 100644 --- a/arch/arm64/include/arch/arch_ops.h +++ b/arch/arm64/include/arch/arch_ops.h @@ -57,6 +57,28 @@ static inline bool arch_ints_disabled(void) return !!state; } +static inline void arch_enable_fiqs(void) +{ + CF; + __asm__ volatile("msr daifclr, #1" ::: "memory"); +} + +static inline void arch_disable_fiqs(void) +{ + __asm__ volatile("msr daifset, #1" ::: "memory"); + CF; +} + +static inline bool arch_fiqs_disabled(void) +{ + unsigned int state = 0; + + __asm__ volatile("mrs %0, daif" : "=r"(state)); + state &= (1<<0); + + return !!state; +} + static inline int atomic_add(volatile int *ptr, int val) { #if USE_GCC_ATOMICS From 87d0bf04076fe6263b0c7fb27ae698f1d5851b39 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Mon, 13 Oct 2014 15:22:04 +0800 Subject: [PATCH 03/43] [arm64] always use gcc builtin atomic operation and remove the inline assemble code because they can't build with a64 Change-Id: Ia2ada6ab5c670ba97fd6260b7085e068d282417e Signed-off-by: Xiang Xiao --- arch/arm64/include/arch/arch_ops.h | 99 +----------------------------- 1 file changed, 2 insertions(+), 97 deletions(-) diff --git a/arch/arm64/include/arch/arch_ops.h b/arch/arm64/include/arch/arch_ops.h index 6a9e74536..84d941ccd 100644 --- a/arch/arm64/include/arch/arch_ops.h +++ b/arch/arm64/include/arch/arch_ops.h @@ -30,7 +30,6 @@ #include #include -#define USE_GCC_ATOMICS 1 #define ENABLE_CYCLE_COUNTER 1 // override of some routines @@ -81,122 +80,28 @@ static inline bool arch_fiqs_disabled(void) static inline int atomic_add(volatile int *ptr, int val) { -#if USE_GCC_ATOMICS return __atomic_fetch_add(ptr, val, __ATOMIC_RELAXED); -#else - int old; - int temp; - int test; - - do { - __asm__ volatile( - "ldrex %[old], [%[ptr]]\n" - "adds %[temp], %[old], %[val]\n" - "strex %[test], %[temp], [%[ptr]]\n" - : [old]"=&r" (old), [temp]"=&r" (temp), [test]"=&r" (test) - : [ptr]"r" (ptr), [val]"r" (val) - : "memory", "cc"); - - } while (test != 0); - - return old; -#endif } static inline int atomic_or(volatile int *ptr, int val) { -#if USE_GCC_ATOMICS return __atomic_fetch_or(ptr, val, __ATOMIC_RELAXED); -#else - int old; - int temp; - int test; - - do { - __asm__ volatile( - "ldrex %[old], [%[ptr]]\n" - "orrs %[temp], %[old], %[val]\n" - "strex %[test], %[temp], [%[ptr]]\n" - : [old]"=&r" (old), [temp]"=&r" (temp), [test]"=&r" (test) - : [ptr]"r" (ptr), [val]"r" (val) - : "memory", "cc"); - - } while (test != 0); - - return old; -#endif } static inline int atomic_and(volatile int *ptr, int val) { -#if USE_GCC_ATOMICS return __atomic_fetch_and(ptr, val, __ATOMIC_RELAXED); -#else - int old; - int temp; - int test; - - do { - __asm__ volatile( - "ldrex %[old], [%[ptr]]\n" - "ands %[temp], %[old], %[val]\n" - "strex %[test], %[temp], [%[ptr]]\n" - : [old]"=&r" (old), [temp]"=&r" (temp), [test]"=&r" (test) - : [ptr]"r" (ptr), [val]"r" (val) - : "memory", "cc"); - - } while (test != 0); - - return old; -#endif } static inline int atomic_swap(volatile int *ptr, int val) { -#if USE_GCC_ATOMICS return __atomic_exchange_n(ptr, val, __ATOMIC_RELAXED); -#else - int old; - int test; - - do { - __asm__ volatile( - "ldrex %[old], [%[ptr]]\n" - "strex %[test], %[val], [%[ptr]]\n" - : [old]"=&r" (old), [test]"=&r" (test) - : [ptr]"r" (ptr), [val]"r" (val) - : "memory"); - - } while (test != 0); - - return old; -#endif } static inline int atomic_cmpxchg(volatile int *ptr, int oldval, int newval) { - int old; - int test; - - do { - __asm__ volatile( - "ldrex %[old], [%[ptr]]\n" - "mov %[test], #0\n" - "teq %[old], %[oldval]\n" -#if ARM_ISA_ARMV7M - "bne 0f\n" - "strex %[test], %[newval], [%[ptr]]\n" - "0:\n" -#else - "strexeq %[test], %[newval], [%[ptr]]\n" -#endif - : [old]"=&r" (old), [test]"=&r" (test) - : [ptr]"r" (ptr), [oldval]"Ir" (oldval), [newval]"r" (newval) - : "cc"); - - } while (test != 0); - - return old; + __atomic_compare_exchange_n(ptr, &oldval, newval, true, __ATOMIC_RELAXED, __ATOMIC_RELAXED); + return oldval; } static inline uint32_t arch_cycle_count(void) From 25f84f6f37667ffafea0c271c29643e9a88daec6 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Mon, 13 Oct 2014 17:16:55 +0800 Subject: [PATCH 04/43] [arm] don't use strexeq which is arm only inst in atomic_cmpxchg because atomic_cmpxchg may inline in the thumb compiler environment Change-Id: Ifc424327211859662866022c1a9dec30618f72e6 Signed-off-by: Xiang Xiao --- arch/arm/include/arch/arch_ops.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/include/arch/arch_ops.h b/arch/arm/include/arch/arch_ops.h index 1c91f3c08..a300d98a2 100644 --- a/arch/arm/include/arch/arch_ops.h +++ b/arch/arm/include/arch/arch_ops.h @@ -196,13 +196,9 @@ static inline int atomic_cmpxchg(volatile int *ptr, int oldval, int newval) "ldrex %[old], [%[ptr]]\n" "mov %[test], #0\n" "teq %[old], %[oldval]\n" -#if ARM_ISA_ARMV7M "bne 0f\n" "strex %[test], %[newval], [%[ptr]]\n" "0:\n" -#else - "strexeq %[test], %[newval], [%[ptr]]\n" -#endif : [old]"=&r" (old), [test]"=&r" (test) : [ptr]"r" (ptr), [oldval]"Ir" (oldval), [newval]"r" (newval) : "cc"); From a05d6c5fae7fdf7bc3e94ca59c2a0adb484b0ab4 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Mon, 13 Oct 2014 16:27:15 +0800 Subject: [PATCH 05/43] [kernel] move spinlock out of arch/arm/include/arch/arch_ops.h because spinlock could implement in all supported arch Signed-off-by: Xiang Xiao Change-Id: Icfb0bfbd569320cc6b3f4dc13b39f73a45ae1f92 --- arch/arm/arm/ops.S | 30 +-------- arch/arm/include/arch/arch_ops.h | 57 +--------------- dev/interrupt/arm_gic/arm_gic.c | 2 + include/arch/ops.h | 7 ++ include/kernel/spinlock.h | 112 +++++++++++++++++++++++++++++++ 5 files changed, 123 insertions(+), 85 deletions(-) create mode 100644 include/kernel/spinlock.h diff --git a/arch/arm/arm/ops.S b/arch/arm/arm/ops.S index cae2baed3..6b40ea262 100644 --- a/arch/arm/arm/ops.S +++ b/arch/arm/arm/ops.S @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -93,35 +94,6 @@ FUNCTION(_atomic_or) mov r0, r12 bx lr -FUNCTION(spin_trylock) - mov r2, r0 - mov r1, #1 - ldrex r0, [r2] - cmp r0, #0 - strexeq r0, r1, [r2] - dmb - bx lr - -FUNCTION(spin_lock) - mov r1, #1 -1: - ldrex r2, [r0] - cmp r2, #0 - wfene - strexeq r2, r1, [r0] - cmpeq r2, #0 - bne 1b - dmb - bx lr - -FUNCTION(spin_unlock) - mov r1, #0 - dmb - str r1, [r0] - dsb - sev - bx lr - /* void arch_idle(); */ FUNCTION(arch_idle) #if ARM_ARCH_LEVEL >= 7 diff --git a/arch/arm/include/arch/arch_ops.h b/arch/arm/include/arch/arch_ops.h index a300d98a2..f1a9d44a8 100644 --- a/arch/arm/include/arch/arch_ops.h +++ b/arch/arm/include/arch/arch_ops.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -287,62 +288,6 @@ static inline uint32_t arch_cycle_count(void) { return _arch_cycle_count(); } #endif -typedef unsigned long spin_lock_t; -void spin_lock(spin_lock_t *lock); /* interrupts should already be disabled */ -int spin_trylock(spin_lock_t *lock); /* Returns 0 on success, non-0 on failure */ -void spin_unlock(spin_lock_t *lock); - -typedef ulong spin_lock_saved_state_t; -typedef ulong spin_lock_save_flags_t; - -enum { - /* Possible future flags: - * SPIN_LOCK_FLAG_PMR_MASK = 0x000000ff, - * SPIN_LOCK_FLAG_PREEMPTION = 0x10000000, - * SPIN_LOCK_FLAG_SET_PMR = 0x20000000, - */ - - /* ARM specific flags */ - SPIN_LOCK_FLAG_IRQ = 0x40000000, - SPIN_LOCK_FLAG_FIQ = 0x80000000, /* Do not use unless IRQs are already disabled */ - SPIN_LOCK_FLAG_IRQ_FIQ = SPIN_LOCK_FLAG_IRQ | SPIN_LOCK_FLAG_FIQ, - - /* Generic flags */ - SPIN_LOCK_FLAG_INTERRUPTS = SPIN_LOCK_FLAG_IRQ, -}; - -enum { - /* private */ - SPIN_LOCK_STATE_RESTORE_IRQ = 1, - SPIN_LOCK_STATE_RESTORE_FIQ = 2, -}; - -static inline void -spin_lock_save(spin_lock_t *lock, spin_lock_saved_state_t *statep, spin_lock_save_flags_t flags) -{ - spin_lock_saved_state_t state = 0; - if ((flags & SPIN_LOCK_FLAG_IRQ) && !arch_ints_disabled()) { - state |= SPIN_LOCK_STATE_RESTORE_IRQ; - arch_disable_ints(); - } - if ((flags & SPIN_LOCK_FLAG_FIQ) && !arch_fiqs_disabled()) { - state |= SPIN_LOCK_STATE_RESTORE_FIQ; - arch_disable_fiqs(); - } - *statep = state; - spin_lock(lock); -} - -static inline void -spin_unlock_restore(spin_lock_t *lock, spin_lock_saved_state_t old_state, spin_lock_save_flags_t flags) -{ - spin_unlock(lock); - if ((flags & SPIN_LOCK_FLAG_FIQ) && (old_state & SPIN_LOCK_STATE_RESTORE_FIQ)) - arch_enable_fiqs(); - if ((flags & SPIN_LOCK_FLAG_IRQ) && (old_state & SPIN_LOCK_STATE_RESTORE_IRQ)) - arch_enable_ints(); -} - #endif // ASSEMBLY #endif diff --git a/dev/interrupt/arm_gic/arm_gic.c b/dev/interrupt/arm_gic/arm_gic.c index e49a404bb..6a939d69a 100644 --- a/dev/interrupt/arm_gic/arm_gic.c +++ b/dev/interrupt/arm_gic/arm_gic.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -25,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/include/arch/ops.h b/include/arch/ops.h index d0e4f2ee7..3db68d7b7 100644 --- a/include/arch/ops.h +++ b/include/arch/ops.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -38,10 +39,16 @@ static void arch_disable_ints(void); static bool arch_ints_disabled(void); static bool arch_in_int_handler(void); +/* optional fast irq for some arch(e.g. arm) */ +static void arch_enable_fiqs(void); +static void arch_disable_fiqs(void); +static bool arch_fiqs_disabled(void); + static int atomic_swap(volatile int *ptr, int val); static int atomic_add(volatile int *ptr, int val); static int atomic_and(volatile int *ptr, int val); static int atomic_or(volatile int *ptr, int val); +static int atomic_cmpxchg(volatile int *ptr, int oldval, int newval); static uint32_t arch_cycle_count(void); diff --git a/include/kernel/spinlock.h b/include/kernel/spinlock.h new file mode 100644 index 000000000..ab48db6e0 --- /dev/null +++ b/include/kernel/spinlock.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef __KERNEL_SPIN_LOCK_H +#define __KERNEL_SPIN_LOCK_H + +#include +#include +#include + +typedef int spin_lock_t; + +/* interrupts should already be disabled */ +static inline void spin_lock(spin_lock_t *lock) +{ + while (atomic_cmpxchg(lock, 0, 1) != 0) { + // nothing to do; + } + CF; +} + +/* Returns 0 on success, non-0 on failure */ +static inline int spin_trylock(spin_lock_t *lock) +{ + if (atomic_cmpxchg(lock, 0, 1) == 0) { + CF; + return 0; + } + return ERR_BUSY; +} + +static inline void spin_unlock(spin_lock_t *lock) +{ + CF; + if (atomic_cmpxchg(lock, 1, 0) != 1) { + DEBUG_ASSERT(0); + } +} + +typedef ulong spin_lock_saved_state_t; +typedef ulong spin_lock_save_flags_t; + +enum { + /* Possible future flags: + * SPIN_LOCK_FLAG_PMR_MASK = 0x000000ff, + * SPIN_LOCK_FLAG_PREEMPTION = 0x10000000, + * SPIN_LOCK_FLAG_SET_PMR = 0x20000000, + */ + + /* ARM specific flags */ + SPIN_LOCK_FLAG_IRQ = 0x40000000, + SPIN_LOCK_FLAG_FIQ = 0x80000000, /* Do not use unless IRQs are already disabled */ + SPIN_LOCK_FLAG_IRQ_FIQ = SPIN_LOCK_FLAG_IRQ | SPIN_LOCK_FLAG_FIQ, + + /* Generic flags */ + SPIN_LOCK_FLAG_INTERRUPTS = SPIN_LOCK_FLAG_IRQ, +}; + +enum { + /* private */ + SPIN_LOCK_STATE_RESTORE_IRQ = 1, + SPIN_LOCK_STATE_RESTORE_FIQ = 2, +}; + +static inline void +spin_lock_save(spin_lock_t *lock, spin_lock_saved_state_t *statep, spin_lock_save_flags_t flags) +{ + spin_lock_saved_state_t state = 0; + if ((flags & SPIN_LOCK_FLAG_IRQ) && !arch_ints_disabled()) { + state |= SPIN_LOCK_STATE_RESTORE_IRQ; + arch_disable_ints(); + } + if ((flags & SPIN_LOCK_FLAG_FIQ) && !arch_fiqs_disabled()) { + state |= SPIN_LOCK_STATE_RESTORE_FIQ; + arch_disable_fiqs(); + } + *statep = state; + spin_lock(lock); +} + +static inline void +spin_unlock_restore(spin_lock_t *lock, spin_lock_saved_state_t old_state, spin_lock_save_flags_t flags) +{ + spin_unlock(lock); + if ((flags & SPIN_LOCK_FLAG_FIQ) && (old_state & SPIN_LOCK_STATE_RESTORE_FIQ)) + arch_enable_fiqs(); + if ((flags & SPIN_LOCK_FLAG_IRQ) && (old_state & SPIN_LOCK_STATE_RESTORE_IRQ)) + arch_enable_ints(); +} + +#endif + From 144dc4d9adf288e9a9ac9e46258a42252c66cb31 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Wed, 15 Oct 2014 14:29:09 +0800 Subject: [PATCH 06/43] [arm_gic] remove arm 32bit specific code so the same driver could work on both 32bit and 64bit platform Change-Id: I6955300ee40e43a3dbc853cd24328ceb94657468 Signed-off-by: Xiang Xiao --- dev/interrupt/arm_gic/arm_gic.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/dev/interrupt/arm_gic/arm_gic.c b/dev/interrupt/arm_gic/arm_gic.c index 6a939d69a..97df79b09 100644 --- a/dev/interrupt/arm_gic/arm_gic.c +++ b/dev/interrupt/arm_gic/arm_gic.c @@ -30,8 +30,6 @@ #include #include #include -#include -#include #include #include #if WITH_LIB_SM @@ -291,7 +289,7 @@ status_t unmask_interrupt(unsigned int vector) } static -enum handler_return __platform_irq(struct arm_iframe *frame) +enum handler_return __platform_irq(void *frame) { // get the current vector unsigned int vector = GICREG(0, GICC_IAR) & 0x3ff; @@ -304,7 +302,7 @@ enum handler_return __platform_irq(struct arm_iframe *frame) THREAD_STATS_INC(interrupts); KEVLOG_IRQ_ENTER(vector); -// printf("platform_irq: spsr 0x%x, pc 0x%x, currthread %p, vector %d\n", frame->spsr, frame->pc, current_thread, vector); +// printf("platform_irq: currthread %p, vector %d\n", get_current_thread(), vector); // deliver the interrupt enum handler_return ret; @@ -322,7 +320,7 @@ enum handler_return __platform_irq(struct arm_iframe *frame) return ret; } -enum handler_return platform_irq(struct arm_iframe *frame) +enum handler_return platform_irq(void *frame) { #if WITH_LIB_SM uint32_t ahppir = GICREG(0, GICC_AHPPIR); @@ -363,7 +361,7 @@ enum handler_return platform_irq(struct arm_iframe *frame) #endif } -void platform_fiq(struct arm_iframe *frame) +void platform_fiq(void *frame) { #if WITH_LIB_SM sm_handle_irq(); From dbbc3315d8cb5e6283a12e227ef2f2dae9d339bd Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Mon, 13 Oct 2014 14:53:21 +0800 Subject: [PATCH 07/43] [arm64] fix minor issue in the interrupt function 1.don't update F bit in arch_[dis|en]able_ints 2.get interrupt flag through daif instead of cspr Change-Id: I1dbbe9493e1036a25095226f44607a5e3d62aaab Signed-off-by: Xiang Xiao --- arch/arm64/include/arch/arch_ops.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/arch/arch_ops.h b/arch/arm64/include/arch/arch_ops.h index 2a12d7bee..4efa24e15 100644 --- a/arch/arm64/include/arch/arch_ops.h +++ b/arch/arm64/include/arch/arch_ops.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -36,12 +37,12 @@ static inline void arch_enable_ints(void) { CF; - __asm__ volatile("msr daifclr, #3" ::: "memory"); + __asm__ volatile("msr daifclr, #2" ::: "memory"); } static inline void arch_disable_ints(void) { - __asm__ volatile("msr daifset, #3" ::: "memory"); + __asm__ volatile("msr daifset, #2" ::: "memory"); CF; } @@ -50,8 +51,8 @@ static inline bool arch_ints_disabled(void) { unsigned int state; - __asm__ volatile("mrs %0, cpsr" : "=r"(state)); - state &= (1<<7); + __asm__ volatile("mrs %0, daif" : "=r"(state)); + state &= (1<<1); return !!state; } From 251ce8028469f9e8af7f70035a8c227d3395f75d Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Mon, 13 Oct 2014 14:57:36 +0800 Subject: [PATCH 08/43] [arm64] implement fiq arch function Change-Id: Iecbb55c13f00ea8eacf0db74112df6889a71d444 Signed-off-by: Xiang Xiao --- arch/arm64/include/arch/arch_ops.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm64/include/arch/arch_ops.h b/arch/arm64/include/arch/arch_ops.h index 4efa24e15..6a9e74536 100644 --- a/arch/arm64/include/arch/arch_ops.h +++ b/arch/arm64/include/arch/arch_ops.h @@ -57,6 +57,28 @@ static inline bool arch_ints_disabled(void) return !!state; } +static inline void arch_enable_fiqs(void) +{ + CF; + __asm__ volatile("msr daifclr, #1" ::: "memory"); +} + +static inline void arch_disable_fiqs(void) +{ + __asm__ volatile("msr daifset, #1" ::: "memory"); + CF; +} + +static inline bool arch_fiqs_disabled(void) +{ + unsigned int state = 0; + + __asm__ volatile("mrs %0, daif" : "=r"(state)); + state &= (1<<0); + + return !!state; +} + static inline int atomic_add(volatile int *ptr, int val) { #if USE_GCC_ATOMICS From fb61b20028dfdffa6279878aa613ffb8a10ce3c9 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Mon, 13 Oct 2014 15:22:04 +0800 Subject: [PATCH 09/43] [arm64] always use gcc builtin atomic operation and remove the inline assemble code because they can't build with a64 Change-Id: Ia2ada6ab5c670ba97fd6260b7085e068d282417e Signed-off-by: Xiang Xiao --- arch/arm64/include/arch/arch_ops.h | 99 +----------------------------- 1 file changed, 2 insertions(+), 97 deletions(-) diff --git a/arch/arm64/include/arch/arch_ops.h b/arch/arm64/include/arch/arch_ops.h index 6a9e74536..84d941ccd 100644 --- a/arch/arm64/include/arch/arch_ops.h +++ b/arch/arm64/include/arch/arch_ops.h @@ -30,7 +30,6 @@ #include #include -#define USE_GCC_ATOMICS 1 #define ENABLE_CYCLE_COUNTER 1 // override of some routines @@ -81,122 +80,28 @@ static inline bool arch_fiqs_disabled(void) static inline int atomic_add(volatile int *ptr, int val) { -#if USE_GCC_ATOMICS return __atomic_fetch_add(ptr, val, __ATOMIC_RELAXED); -#else - int old; - int temp; - int test; - - do { - __asm__ volatile( - "ldrex %[old], [%[ptr]]\n" - "adds %[temp], %[old], %[val]\n" - "strex %[test], %[temp], [%[ptr]]\n" - : [old]"=&r" (old), [temp]"=&r" (temp), [test]"=&r" (test) - : [ptr]"r" (ptr), [val]"r" (val) - : "memory", "cc"); - - } while (test != 0); - - return old; -#endif } static inline int atomic_or(volatile int *ptr, int val) { -#if USE_GCC_ATOMICS return __atomic_fetch_or(ptr, val, __ATOMIC_RELAXED); -#else - int old; - int temp; - int test; - - do { - __asm__ volatile( - "ldrex %[old], [%[ptr]]\n" - "orrs %[temp], %[old], %[val]\n" - "strex %[test], %[temp], [%[ptr]]\n" - : [old]"=&r" (old), [temp]"=&r" (temp), [test]"=&r" (test) - : [ptr]"r" (ptr), [val]"r" (val) - : "memory", "cc"); - - } while (test != 0); - - return old; -#endif } static inline int atomic_and(volatile int *ptr, int val) { -#if USE_GCC_ATOMICS return __atomic_fetch_and(ptr, val, __ATOMIC_RELAXED); -#else - int old; - int temp; - int test; - - do { - __asm__ volatile( - "ldrex %[old], [%[ptr]]\n" - "ands %[temp], %[old], %[val]\n" - "strex %[test], %[temp], [%[ptr]]\n" - : [old]"=&r" (old), [temp]"=&r" (temp), [test]"=&r" (test) - : [ptr]"r" (ptr), [val]"r" (val) - : "memory", "cc"); - - } while (test != 0); - - return old; -#endif } static inline int atomic_swap(volatile int *ptr, int val) { -#if USE_GCC_ATOMICS return __atomic_exchange_n(ptr, val, __ATOMIC_RELAXED); -#else - int old; - int test; - - do { - __asm__ volatile( - "ldrex %[old], [%[ptr]]\n" - "strex %[test], %[val], [%[ptr]]\n" - : [old]"=&r" (old), [test]"=&r" (test) - : [ptr]"r" (ptr), [val]"r" (val) - : "memory"); - - } while (test != 0); - - return old; -#endif } static inline int atomic_cmpxchg(volatile int *ptr, int oldval, int newval) { - int old; - int test; - - do { - __asm__ volatile( - "ldrex %[old], [%[ptr]]\n" - "mov %[test], #0\n" - "teq %[old], %[oldval]\n" -#if ARM_ISA_ARMV7M - "bne 0f\n" - "strex %[test], %[newval], [%[ptr]]\n" - "0:\n" -#else - "strexeq %[test], %[newval], [%[ptr]]\n" -#endif - : [old]"=&r" (old), [test]"=&r" (test) - : [ptr]"r" (ptr), [oldval]"Ir" (oldval), [newval]"r" (newval) - : "cc"); - - } while (test != 0); - - return old; + __atomic_compare_exchange_n(ptr, &oldval, newval, true, __ATOMIC_RELAXED, __ATOMIC_RELAXED); + return oldval; } static inline uint32_t arch_cycle_count(void) From e7d8ba949b88a6e7a02ccadbad7f410e8f87fcbb Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Mon, 13 Oct 2014 17:16:55 +0800 Subject: [PATCH 10/43] [arm] don't use strexeq which is arm only inst in atomic_cmpxchg because atomic_cmpxchg may inline in the thumb compiler environment Change-Id: Ifc424327211859662866022c1a9dec30618f72e6 Signed-off-by: Xiang Xiao --- arch/arm/include/arch/arch_ops.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/include/arch/arch_ops.h b/arch/arm/include/arch/arch_ops.h index 1c91f3c08..a300d98a2 100644 --- a/arch/arm/include/arch/arch_ops.h +++ b/arch/arm/include/arch/arch_ops.h @@ -196,13 +196,9 @@ static inline int atomic_cmpxchg(volatile int *ptr, int oldval, int newval) "ldrex %[old], [%[ptr]]\n" "mov %[test], #0\n" "teq %[old], %[oldval]\n" -#if ARM_ISA_ARMV7M "bne 0f\n" "strex %[test], %[newval], [%[ptr]]\n" "0:\n" -#else - "strexeq %[test], %[newval], [%[ptr]]\n" -#endif : [old]"=&r" (old), [test]"=&r" (test) : [ptr]"r" (ptr), [oldval]"Ir" (oldval), [newval]"r" (newval) : "cc"); From a3c1cf38e70b56905a730238f4b658b97b6e1161 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Mon, 13 Oct 2014 16:27:15 +0800 Subject: [PATCH 11/43] [kernel] move spinlock out of arch/arm/include/arch/arch_ops.h because spinlock could implement in all supported arch Signed-off-by: Xiang Xiao Change-Id: Icfb0bfbd569320cc6b3f4dc13b39f73a45ae1f92 --- arch/arm/arm/ops.S | 30 +-------- arch/arm/include/arch/arch_ops.h | 57 +--------------- dev/interrupt/arm_gic/arm_gic.c | 2 + include/arch/ops.h | 7 ++ include/kernel/spinlock.h | 112 +++++++++++++++++++++++++++++++ 5 files changed, 123 insertions(+), 85 deletions(-) create mode 100644 include/kernel/spinlock.h diff --git a/arch/arm/arm/ops.S b/arch/arm/arm/ops.S index cae2baed3..6b40ea262 100644 --- a/arch/arm/arm/ops.S +++ b/arch/arm/arm/ops.S @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -93,35 +94,6 @@ FUNCTION(_atomic_or) mov r0, r12 bx lr -FUNCTION(spin_trylock) - mov r2, r0 - mov r1, #1 - ldrex r0, [r2] - cmp r0, #0 - strexeq r0, r1, [r2] - dmb - bx lr - -FUNCTION(spin_lock) - mov r1, #1 -1: - ldrex r2, [r0] - cmp r2, #0 - wfene - strexeq r2, r1, [r0] - cmpeq r2, #0 - bne 1b - dmb - bx lr - -FUNCTION(spin_unlock) - mov r1, #0 - dmb - str r1, [r0] - dsb - sev - bx lr - /* void arch_idle(); */ FUNCTION(arch_idle) #if ARM_ARCH_LEVEL >= 7 diff --git a/arch/arm/include/arch/arch_ops.h b/arch/arm/include/arch/arch_ops.h index a300d98a2..f1a9d44a8 100644 --- a/arch/arm/include/arch/arch_ops.h +++ b/arch/arm/include/arch/arch_ops.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -287,62 +288,6 @@ static inline uint32_t arch_cycle_count(void) { return _arch_cycle_count(); } #endif -typedef unsigned long spin_lock_t; -void spin_lock(spin_lock_t *lock); /* interrupts should already be disabled */ -int spin_trylock(spin_lock_t *lock); /* Returns 0 on success, non-0 on failure */ -void spin_unlock(spin_lock_t *lock); - -typedef ulong spin_lock_saved_state_t; -typedef ulong spin_lock_save_flags_t; - -enum { - /* Possible future flags: - * SPIN_LOCK_FLAG_PMR_MASK = 0x000000ff, - * SPIN_LOCK_FLAG_PREEMPTION = 0x10000000, - * SPIN_LOCK_FLAG_SET_PMR = 0x20000000, - */ - - /* ARM specific flags */ - SPIN_LOCK_FLAG_IRQ = 0x40000000, - SPIN_LOCK_FLAG_FIQ = 0x80000000, /* Do not use unless IRQs are already disabled */ - SPIN_LOCK_FLAG_IRQ_FIQ = SPIN_LOCK_FLAG_IRQ | SPIN_LOCK_FLAG_FIQ, - - /* Generic flags */ - SPIN_LOCK_FLAG_INTERRUPTS = SPIN_LOCK_FLAG_IRQ, -}; - -enum { - /* private */ - SPIN_LOCK_STATE_RESTORE_IRQ = 1, - SPIN_LOCK_STATE_RESTORE_FIQ = 2, -}; - -static inline void -spin_lock_save(spin_lock_t *lock, spin_lock_saved_state_t *statep, spin_lock_save_flags_t flags) -{ - spin_lock_saved_state_t state = 0; - if ((flags & SPIN_LOCK_FLAG_IRQ) && !arch_ints_disabled()) { - state |= SPIN_LOCK_STATE_RESTORE_IRQ; - arch_disable_ints(); - } - if ((flags & SPIN_LOCK_FLAG_FIQ) && !arch_fiqs_disabled()) { - state |= SPIN_LOCK_STATE_RESTORE_FIQ; - arch_disable_fiqs(); - } - *statep = state; - spin_lock(lock); -} - -static inline void -spin_unlock_restore(spin_lock_t *lock, spin_lock_saved_state_t old_state, spin_lock_save_flags_t flags) -{ - spin_unlock(lock); - if ((flags & SPIN_LOCK_FLAG_FIQ) && (old_state & SPIN_LOCK_STATE_RESTORE_FIQ)) - arch_enable_fiqs(); - if ((flags & SPIN_LOCK_FLAG_IRQ) && (old_state & SPIN_LOCK_STATE_RESTORE_IRQ)) - arch_enable_ints(); -} - #endif // ASSEMBLY #endif diff --git a/dev/interrupt/arm_gic/arm_gic.c b/dev/interrupt/arm_gic/arm_gic.c index e49a404bb..6a939d69a 100644 --- a/dev/interrupt/arm_gic/arm_gic.c +++ b/dev/interrupt/arm_gic/arm_gic.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -25,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/include/arch/ops.h b/include/arch/ops.h index d0e4f2ee7..3db68d7b7 100644 --- a/include/arch/ops.h +++ b/include/arch/ops.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -38,10 +39,16 @@ static void arch_disable_ints(void); static bool arch_ints_disabled(void); static bool arch_in_int_handler(void); +/* optional fast irq for some arch(e.g. arm) */ +static void arch_enable_fiqs(void); +static void arch_disable_fiqs(void); +static bool arch_fiqs_disabled(void); + static int atomic_swap(volatile int *ptr, int val); static int atomic_add(volatile int *ptr, int val); static int atomic_and(volatile int *ptr, int val); static int atomic_or(volatile int *ptr, int val); +static int atomic_cmpxchg(volatile int *ptr, int oldval, int newval); static uint32_t arch_cycle_count(void); diff --git a/include/kernel/spinlock.h b/include/kernel/spinlock.h new file mode 100644 index 000000000..ab48db6e0 --- /dev/null +++ b/include/kernel/spinlock.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef __KERNEL_SPIN_LOCK_H +#define __KERNEL_SPIN_LOCK_H + +#include +#include +#include + +typedef int spin_lock_t; + +/* interrupts should already be disabled */ +static inline void spin_lock(spin_lock_t *lock) +{ + while (atomic_cmpxchg(lock, 0, 1) != 0) { + // nothing to do; + } + CF; +} + +/* Returns 0 on success, non-0 on failure */ +static inline int spin_trylock(spin_lock_t *lock) +{ + if (atomic_cmpxchg(lock, 0, 1) == 0) { + CF; + return 0; + } + return ERR_BUSY; +} + +static inline void spin_unlock(spin_lock_t *lock) +{ + CF; + if (atomic_cmpxchg(lock, 1, 0) != 1) { + DEBUG_ASSERT(0); + } +} + +typedef ulong spin_lock_saved_state_t; +typedef ulong spin_lock_save_flags_t; + +enum { + /* Possible future flags: + * SPIN_LOCK_FLAG_PMR_MASK = 0x000000ff, + * SPIN_LOCK_FLAG_PREEMPTION = 0x10000000, + * SPIN_LOCK_FLAG_SET_PMR = 0x20000000, + */ + + /* ARM specific flags */ + SPIN_LOCK_FLAG_IRQ = 0x40000000, + SPIN_LOCK_FLAG_FIQ = 0x80000000, /* Do not use unless IRQs are already disabled */ + SPIN_LOCK_FLAG_IRQ_FIQ = SPIN_LOCK_FLAG_IRQ | SPIN_LOCK_FLAG_FIQ, + + /* Generic flags */ + SPIN_LOCK_FLAG_INTERRUPTS = SPIN_LOCK_FLAG_IRQ, +}; + +enum { + /* private */ + SPIN_LOCK_STATE_RESTORE_IRQ = 1, + SPIN_LOCK_STATE_RESTORE_FIQ = 2, +}; + +static inline void +spin_lock_save(spin_lock_t *lock, spin_lock_saved_state_t *statep, spin_lock_save_flags_t flags) +{ + spin_lock_saved_state_t state = 0; + if ((flags & SPIN_LOCK_FLAG_IRQ) && !arch_ints_disabled()) { + state |= SPIN_LOCK_STATE_RESTORE_IRQ; + arch_disable_ints(); + } + if ((flags & SPIN_LOCK_FLAG_FIQ) && !arch_fiqs_disabled()) { + state |= SPIN_LOCK_STATE_RESTORE_FIQ; + arch_disable_fiqs(); + } + *statep = state; + spin_lock(lock); +} + +static inline void +spin_unlock_restore(spin_lock_t *lock, spin_lock_saved_state_t old_state, spin_lock_save_flags_t flags) +{ + spin_unlock(lock); + if ((flags & SPIN_LOCK_FLAG_FIQ) && (old_state & SPIN_LOCK_STATE_RESTORE_FIQ)) + arch_enable_fiqs(); + if ((flags & SPIN_LOCK_FLAG_IRQ) && (old_state & SPIN_LOCK_STATE_RESTORE_IRQ)) + arch_enable_ints(); +} + +#endif + From 0f60ee838d6ffe05bfe49c4bd0d90dda7d9dccfc Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Wed, 15 Oct 2014 14:29:09 +0800 Subject: [PATCH 12/43] [arm_gic] remove arm 32bit specific code so the same driver could work on both 32bit and 64bit platform Change-Id: I6955300ee40e43a3dbc853cd24328ceb94657468 Signed-off-by: Xiang Xiao --- dev/interrupt/arm_gic/arm_gic.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/dev/interrupt/arm_gic/arm_gic.c b/dev/interrupt/arm_gic/arm_gic.c index 6a939d69a..97df79b09 100644 --- a/dev/interrupt/arm_gic/arm_gic.c +++ b/dev/interrupt/arm_gic/arm_gic.c @@ -30,8 +30,6 @@ #include #include #include -#include -#include #include #include #if WITH_LIB_SM @@ -291,7 +289,7 @@ status_t unmask_interrupt(unsigned int vector) } static -enum handler_return __platform_irq(struct arm_iframe *frame) +enum handler_return __platform_irq(void *frame) { // get the current vector unsigned int vector = GICREG(0, GICC_IAR) & 0x3ff; @@ -304,7 +302,7 @@ enum handler_return __platform_irq(struct arm_iframe *frame) THREAD_STATS_INC(interrupts); KEVLOG_IRQ_ENTER(vector); -// printf("platform_irq: spsr 0x%x, pc 0x%x, currthread %p, vector %d\n", frame->spsr, frame->pc, current_thread, vector); +// printf("platform_irq: currthread %p, vector %d\n", get_current_thread(), vector); // deliver the interrupt enum handler_return ret; @@ -322,7 +320,7 @@ enum handler_return __platform_irq(struct arm_iframe *frame) return ret; } -enum handler_return platform_irq(struct arm_iframe *frame) +enum handler_return platform_irq(void *frame) { #if WITH_LIB_SM uint32_t ahppir = GICREG(0, GICC_AHPPIR); @@ -363,7 +361,7 @@ enum handler_return platform_irq(struct arm_iframe *frame) #endif } -void platform_fiq(struct arm_iframe *frame) +void platform_fiq(void *frame) { #if WITH_LIB_SM sm_handle_irq(); From 436c0dec09c381f1ca7b0f2a97d87c5ca9102728 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Wed, 8 Oct 2014 16:46:07 +0800 Subject: [PATCH 13/43] Revert "[app][aboot] remove some old Google code that hasn't been used in a while" Bring back the aboot support again. This reverts commit 8c6807188c07127df3ae1603af72a32fc9627b9f. Signed-off-by: Xiang Xiao Conflicts: include/lib/ptable.h lib/ptable/ptable.c lib/ptable/rules.mk Change-Id: I2f0ea48410d75d53f29fd4f2e0fcd7b4194572ea --- app/aboot/aboot.c | 346 ++++++++++++++++++++++++++++++++++++++ app/aboot/bootimg.h | 96 +++++++++++ app/aboot/fastboot.c | 390 +++++++++++++++++++++++++++++++++++++++++++ app/aboot/fastboot.h | 50 ++++++ app/aboot/rules.mk | 9 + include/dev/flash.h | 52 ++++++ 6 files changed, 943 insertions(+) create mode 100644 app/aboot/aboot.c create mode 100644 app/aboot/bootimg.h create mode 100644 app/aboot/fastboot.c create mode 100644 app/aboot/fastboot.h create mode 100644 app/aboot/rules.mk create mode 100644 include/dev/flash.h diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c new file mode 100644 index 000000000..bfac87775 --- /dev/null +++ b/app/aboot/aboot.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "bootimg.h" +#include "fastboot.h" + +#define TAGS_ADDR 0x10000100 +#define KERNEL_ADDR 0x10800000 +#define RAMDISK_ADDR 0x11000000 +#define DEFAULT_CMDLINE "mem=50M console=null"; + +static struct udc_device surf_udc_device = { + .vendor_id = 0x18d1, + .product_id = 0x0001, + .version_id = 0x0100, + .manufacturer = "Google", + .product = "Android", +}; + +struct atag_ptbl_entry { + char name[16]; + unsigned offset; + unsigned size; + unsigned flags; +}; + +void platform_uninit_timer(void); + +static void ptentry_to_tag(unsigned **ptr, struct ptentry *ptn) +{ + struct atag_ptbl_entry atag_ptn; + + memcpy(atag_ptn.name, ptn->name, 16); + atag_ptn.name[15] = '\0'; + atag_ptn.offset = ptn->start; + atag_ptn.size = ptn->length; + atag_ptn.flags = ptn->flags; + memcpy(*ptr, &atag_ptn, sizeof(struct atag_ptbl_entry)); + *ptr += sizeof(struct atag_ptbl_entry) / sizeof(unsigned); +} + +void boot_linux(void *kernel, unsigned *tags, + const char *cmdline, unsigned machtype, + void *ramdisk, unsigned ramdisk_size) +{ + unsigned *ptr = tags; + void (*entry)(unsigned,unsigned,unsigned*) = kernel; + struct ptable *ptable; + + /* CORE */ + *ptr++ = 2; + *ptr++ = 0x54410001; + + if (ramdisk_size) { + *ptr++ = 4; + *ptr++ = 0x54420005; + *ptr++ = (unsigned)ramdisk; + *ptr++ = ramdisk_size; + } + + if ((ptable = flash_get_ptable()) && (ptable->count != 0)) { + int i; + *ptr++ = 2 + (ptable->count * (sizeof(struct atag_ptbl_entry) / + sizeof(unsigned))); + *ptr++ = 0x4d534d70; + for (i = 0; i < ptable->count; ++i) + ptentry_to_tag(&ptr, ptable_get(ptable, i)); + } + + if (cmdline && cmdline[0]) { + unsigned n; + /* include terminating 0 and round up to a word multiple */ + n = (strlen(cmdline) + 4) & (~3); + *ptr++ = (n / 4) + 2; + *ptr++ = 0x54410009; + memcpy(ptr, cmdline, n); + ptr += (n / 4); + } + + /* END */ + *ptr++ = 0; + *ptr++ = 0; + + dprintf(INFO, "booting linux @ %p, ramdisk @ %p (%d)\n", + kernel, ramdisk, ramdisk_size); + if (cmdline) + dprintf(INFO, "cmdline: %s\n", cmdline); + + enter_critical_section(); + platform_uninit_timer(); + arch_disable_cache(UCACHE); + arch_disable_mmu(); + + entry(0, machtype, tags); + +} + +#define PAGE_MASK 2047 + +#define ROUND_TO_PAGE(x) (((x) + PAGE_MASK) & (~PAGE_MASK)) + +static unsigned char buf[2048]; + +int boot_linux_from_flash(void) +{ + struct boot_img_hdr *hdr = (void*) buf; + unsigned n; + struct ptentry *ptn; + struct ptable *ptable; + unsigned offset = 0; + const char *cmdline; + + ptable = flash_get_ptable(); + if (ptable == NULL) { + dprintf(CRITICAL, "ERROR: Partition table not found\n"); + return -1; + } + + ptn = ptable_find(ptable, "boot"); + if (ptn == NULL) { + dprintf(CRITICAL, "ERROR: No boot partition found\n"); + return -1; + } + + if (flash_read(ptn, offset, buf, 2048)) { + dprintf(CRITICAL, "ERROR: Cannot read boot image header\n"); + return -1; + } + offset += 2048; + + if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) { + dprintf(CRITICAL, "ERROR: Invaled boot image heador\n"); + return -1; + } + + n = ROUND_TO_PAGE(hdr->kernel_size); + if (flash_read(ptn, offset, (void *)hdr->kernel_addr, n)) { + dprintf(CRITICAL, "ERROR: Cannot read kernel image\n"); + return -1; + } + offset += n; + + n = ROUND_TO_PAGE(hdr->ramdisk_size); + if (flash_read(ptn, offset, (void *)hdr->ramdisk_addr, n)) { + dprintf(CRITICAL, "ERROR: Cannot read ramdisk image\n"); + return -1; + } + offset += n; + + dprintf(INFO, "\nkernel @ %x (%d bytes)\n", hdr->kernel_addr, + hdr->kernel_size); + dprintf(INFO, "ramdisk @ %x (%d bytes)\n", hdr->ramdisk_addr, + hdr->ramdisk_size); + + if (hdr->cmdline[0]) { + cmdline = (char*) hdr->cmdline; + } else { + cmdline = DEFAULT_CMDLINE; + } + dprintf(INFO, "cmdline = '%s'\n", cmdline); + + /* TODO: create/pass atags to kernel */ + + dprintf(INFO, "\nBooting Linux\n"); + boot_linux((void *)hdr->kernel_addr, (void *)TAGS_ADDR, + (const char *)cmdline, LINUX_MACHTYPE, + (void *)hdr->ramdisk_addr, hdr->ramdisk_size); + + return 0; +} + +void cmd_boot(const char *arg, void *data, unsigned sz) +{ + unsigned kernel_actual; + unsigned ramdisk_actual; + static struct boot_img_hdr hdr; + char *ptr = ((char*) data); + + if (sz < sizeof(hdr)) { + fastboot_fail("invalid bootimage header"); + return; + } + + memcpy(&hdr, data, sizeof(hdr)); + + /* ensure commandline is terminated */ + hdr.cmdline[BOOT_ARGS_SIZE-1] = 0; + + kernel_actual = ROUND_TO_PAGE(hdr.kernel_size); + ramdisk_actual = ROUND_TO_PAGE(hdr.ramdisk_size); + + if (2048 + kernel_actual + ramdisk_actual < sz) { + fastboot_fail("incomplete bootimage"); + return; + } + + memmove((void*) KERNEL_ADDR, ptr + 2048, hdr.kernel_size); + memmove((void*) RAMDISK_ADDR, ptr + 2048 + kernel_actual, hdr.ramdisk_size); + + fastboot_okay(""); + udc_stop(); + + + boot_linux((void*) KERNEL_ADDR, (void*) TAGS_ADDR, + (const char*) hdr.cmdline, LINUX_MACHTYPE, + (void*) RAMDISK_ADDR, hdr.ramdisk_size); +} + +void cmd_erase(const char *arg, void *data, unsigned sz) +{ + struct ptentry *ptn; + struct ptable *ptable; + + ptable = flash_get_ptable(); + if (ptable == NULL) { + fastboot_fail("partition table doesn't exist"); + return; + } + + ptn = ptable_find(ptable, arg); + if (ptn == NULL) { + fastboot_fail("unknown partition name"); + return; + } + + if (flash_erase(ptn)) { + fastboot_fail("failed to erase partition"); + return; + } + fastboot_okay(""); +} + +void cmd_flash(const char *arg, void *data, unsigned sz) +{ + struct ptentry *ptn; + struct ptable *ptable; + unsigned extra = 0; + + ptable = flash_get_ptable(); + if (ptable == NULL) { + fastboot_fail("partition table doesn't exist"); + return; + } + + ptn = ptable_find(ptable, arg); + if (ptn == NULL) { + fastboot_fail("unknown partition name"); + return; + } + + if (!strcmp(ptn->name, "boot") || !strcmp(ptn->name, "recovery")) { + if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) { + fastboot_fail("image is not a boot image"); + return; + } + } + + if (!strcmp(ptn->name, "system") || !strcmp(ptn->name, "userdata")) + extra = 64; + else + sz = ROUND_TO_PAGE(sz); + + dprintf(INFO, "writing %d bytes to '%s'\n", sz, ptn->name); + if (flash_write(ptn, extra, data, sz)) { + fastboot_fail("flash write failure"); + return; + } + dprintf(INFO, "partition '%s' updated\n", ptn->name); + fastboot_okay(""); +} + +void cmd_continue(const char *arg, void *data, unsigned sz) +{ + fastboot_okay(""); + udc_stop(); + + boot_linux_from_flash(); +} + +void aboot_init(const struct app_descriptor *app) +{ + if (keys_get_state(KEY_BACK) != 0) + goto fastboot; + + boot_linux_from_flash(); + dprintf(CRITICAL, "ERROR: Could not do normal boot. Reverting " + "to fastboot mode.\n"); + +fastboot: + udc_init(&surf_udc_device); + + fastboot_register("boot", cmd_boot); + fastboot_register("erase:", cmd_erase); + fastboot_register("flash:", cmd_flash); + fastboot_register("continue", cmd_continue); + fastboot_publish("product", "swordfish"); + fastboot_publish("kernel", "lk"); + + fastboot_init((void*) 0x10100000, 100 * 1024 * 1024); + udc_start(); +} + +APP_START(aboot) + .init = aboot_init, +APP_END + diff --git a/app/aboot/bootimg.h b/app/aboot/bootimg.h new file mode 100644 index 000000000..a73ef41c3 --- /dev/null +++ b/app/aboot/bootimg.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _BOOT_IMAGE_H_ +#define _BOOT_IMAGE_H_ + +typedef struct boot_img_hdr boot_img_hdr; + +#define BOOT_MAGIC "ANDROID!" +#define BOOT_MAGIC_SIZE 8 +#define BOOT_NAME_SIZE 16 +#define BOOT_ARGS_SIZE 512 + +struct boot_img_hdr { + unsigned char magic[BOOT_MAGIC_SIZE]; + + unsigned kernel_size; /* size in bytes */ + unsigned kernel_addr; /* physical load addr */ + + unsigned ramdisk_size; /* size in bytes */ + unsigned ramdisk_addr; /* physical load addr */ + + unsigned second_size; /* size in bytes */ + unsigned second_addr; /* physical load addr */ + + unsigned tags_addr; /* physical addr for kernel tags */ + unsigned page_size; /* flash page size we assume */ + unsigned unused[2]; /* future expansion: should be 0 */ + + unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */ + + unsigned char cmdline[BOOT_ARGS_SIZE]; + + unsigned id[8]; /* timestamp / checksum / sha1 / etc */ +}; + +/* +** +-----------------+ +** | boot header | 1 page +** +-----------------+ +** | kernel | n pages +** +-----------------+ +** | ramdisk | m pages +** +-----------------+ +** | second stage | o pages +** +-----------------+ +** +** n = (kernel_size + page_size - 1) / page_size +** m = (ramdisk_size + page_size - 1) / page_size +** o = (second_size + page_size - 1) / page_size +** +** 0. all entities are page_size aligned in flash +** 1. kernel and ramdisk are required (size != 0) +** 2. second is optional (second_size == 0 -> no second) +** 3. load each element (kernel, ramdisk, second) at +** the specified physical address (kernel_addr, etc) +** 4. prepare tags at tag_addr. kernel_args[] is +** appended to the kernel commandline in the tags. +** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr +** 6. if second_size != 0: jump to second_addr +** else: jump to kernel_addr +*/ + +boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, + void *ramdisk, unsigned ramdisk_size, + void *second, unsigned second_size, + unsigned page_size, + unsigned *bootimg_size); + +void bootimg_set_cmdline(boot_img_hdr *hdr, const char *cmdline); +#endif diff --git a/app/aboot/fastboot.c b/app/aboot/fastboot.c new file mode 100644 index 000000000..a716f5682 --- /dev/null +++ b/app/aboot/fastboot.c @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +void boot_linux(void *bootimg, unsigned sz); + +/* todo: give lk strtoul and nuke this */ +static unsigned hex2unsigned(const char *x) +{ + unsigned n = 0; + + while (*x) { + switch (*x) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + n = (n << 4) | (*x - '0'); + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + n = (n << 4) | (*x - 'a' + 10); + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + n = (n << 4) | (*x - 'A' + 10); + break; + default: + return n; + } + x++; + } + + return n; +} + +struct fastboot_cmd { + struct fastboot_cmd *next; + const char *prefix; + unsigned prefix_len; + void (*handle)(const char *arg, void *data, unsigned sz); +}; + +struct fastboot_var { + struct fastboot_var *next; + const char *name; + const char *value; +}; + +static struct fastboot_cmd *cmdlist; + +void fastboot_register(const char *prefix, + void (*handle)(const char *arg, void *data, unsigned sz)) +{ + struct fastboot_cmd *cmd; + cmd = malloc(sizeof(*cmd)); + if (cmd) { + cmd->prefix = prefix; + cmd->prefix_len = strlen(prefix); + cmd->handle = handle; + cmd->next = cmdlist; + cmdlist = cmd; + } +} + +static struct fastboot_var *varlist; + +void fastboot_publish(const char *name, const char *value) +{ + struct fastboot_var *var; + var = malloc(sizeof(*var)); + if (var) { + var->name = name; + var->value = value; + var->next = varlist; + varlist = var; + } +} + + +static event_t usb_online; +static event_t txn_done; +static unsigned char buffer[4096]; +static struct udc_endpoint *in, *out; +static struct udc_request *req; +int txn_status; + +static void *download_base; +static unsigned download_max; +static unsigned download_size; + +#define STATE_OFFLINE 0 +#define STATE_COMMAND 1 +#define STATE_COMPLETE 2 +#define STATE_ERROR 3 + +static unsigned fastboot_state = STATE_OFFLINE; + +static void req_complete(struct udc_request *req, unsigned actual, int status) +{ + txn_status = status; + req->length = actual; + event_signal(&txn_done, 0); +} + +static int usb_read(void *_buf, unsigned len) +{ + int r; + unsigned xfer; + unsigned char *buf = _buf; + int count = 0; + + if (fastboot_state == STATE_ERROR) + goto oops; + + while (len > 0) { + xfer = (len > 4096) ? 4096 : len; + req->buf = buf; + req->length = xfer; + req->complete = req_complete; + r = udc_request_queue(out, req); + if (r < 0) { + dprintf(INFO, "usb_read() queue failed\n"); + goto oops; + } + event_wait(&txn_done); + + if (txn_status < 0) { + dprintf(INFO, "usb_read() transaction failed\n"); + goto oops; + } + + count += req->length; + buf += req->length; + len -= req->length; + + /* short transfer? */ + if (req->length != xfer) break; + } + + return count; + +oops: + fastboot_state = STATE_ERROR; + return -1; +} + +static int usb_write(void *buf, unsigned len) +{ + int r; + + if (fastboot_state == STATE_ERROR) + goto oops; + + req->buf = buf; + req->length = len; + req->complete = req_complete; + r = udc_request_queue(in, req); + if (r < 0) { + dprintf(INFO, "usb_write() queue failed\n"); + goto oops; + } + event_wait(&txn_done); + if (txn_status < 0) { + dprintf(INFO, "usb_write() transaction failed\n"); + goto oops; + } + return req->length; + +oops: + fastboot_state = STATE_ERROR; + return -1; +} + +void fastboot_ack(const char *code, const char *reason) +{ + char response[64]; + + if (fastboot_state != STATE_COMMAND) + return; + + if (reason == 0) + reason = ""; + + snprintf(response, 64, "%s%s", code, reason); + fastboot_state = STATE_COMPLETE; + + usb_write(response, strlen(response)); + +} + +void fastboot_fail(const char *reason) +{ + fastboot_ack("FAIL", reason); +} + +void fastboot_okay(const char *info) +{ + fastboot_ack("OKAY", info); +} + +static void cmd_getvar(const char *arg, void *data, unsigned sz) +{ + struct fastboot_var *var; + + for (var = varlist; var; var = var->next) { + if (!strcmp(var->name, arg)) { + fastboot_okay(var->value); + return; + } + } + fastboot_okay(""); +} + +static void cmd_download(const char *arg, void *data, unsigned sz) +{ + char response[64]; + unsigned len = hex2unsigned(arg); + int r; + + download_size = 0; + if (len > download_max) { + fastboot_fail("data too large"); + return; + } + + sprintf(response,"DATA%08x", len); + if (usb_write(response, strlen(response)) < 0) + return; + + r = usb_read(download_base, len); + if ((r < 0) || (r != len)) { + fastboot_state = STATE_ERROR; + return; + } + download_size = len; + fastboot_okay(""); +} + +static void fastboot_command_loop(void) +{ + struct fastboot_cmd *cmd; + int r; + dprintf(INFO,"fastboot: processing commands\n"); + +again: + while (fastboot_state != STATE_ERROR) { + r = usb_read(buffer, 64); + if (r < 0) break; + buffer[r] = 0; + dprintf(INFO,"fastboot: %s\n", buffer); + + for (cmd = cmdlist; cmd; cmd = cmd->next) { + if (memcmp(buffer, cmd->prefix, cmd->prefix_len)) + continue; + fastboot_state = STATE_COMMAND; + cmd->handle((const char*) buffer + cmd->prefix_len, + (void*) download_base, download_size); + if (fastboot_state == STATE_COMMAND) + fastboot_fail("unknown reason"); + goto again; + } + + fastboot_fail("unknown command"); + + } + fastboot_state = STATE_OFFLINE; + dprintf(INFO,"fastboot: oops!\n"); +} + +static int fastboot_handler(void *arg) +{ + for (;;) { + event_wait(&usb_online); + fastboot_command_loop(); + } + return 0; +} + +static void fastboot_notify(struct udc_gadget *gadget, unsigned event) +{ + if (event == UDC_EVENT_ONLINE) { + event_signal(&usb_online, 0); + } else if (event == UDC_EVENT_OFFLINE) { + event_unsignal(&usb_online); + } +} + +static struct udc_endpoint *fastboot_endpoints[2]; + +static struct udc_gadget fastboot_gadget = { + .notify = fastboot_notify, + .ifc_class = 0xff, + .ifc_subclass = 0x42, + .ifc_protocol = 0x03, + .ifc_endpoints = 2, + .ifc_string = "fastboot", + .ept = fastboot_endpoints, +}; + +int fastboot_init(void *base, unsigned size) +{ + thread_t *thr; + dprintf(INFO, "fastboot_init()\n"); + + download_base = base; + download_max = size; + + event_init(&usb_online, 0, EVENT_FLAG_AUTOUNSIGNAL); + event_init(&txn_done, 0, EVENT_FLAG_AUTOUNSIGNAL); + + in = udc_endpoint_alloc(UDC_TYPE_BULK_IN, 512); + if (!in) + goto fail_alloc_in; + out = udc_endpoint_alloc(UDC_TYPE_BULK_OUT, 512); + if (!out) + goto fail_alloc_out; + + fastboot_endpoints[0] = in; + fastboot_endpoints[1] = out; + + req = udc_request_alloc(); + if (!req) + goto fail_alloc_req; + + if (udc_register_gadget(&fastboot_gadget)) + goto fail_udc_register; + + fastboot_register("getvar:", cmd_getvar); + fastboot_register("download:", cmd_download); + fastboot_publish("version", "0.5"); + + thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, 4096); + thread_resume(thr); + return 0; + +fail_udc_register: + udc_request_free(req); +fail_alloc_req: + udc_endpoint_free(out); +fail_alloc_out: + udc_endpoint_free(in); +fail_alloc_in: + return -1; +} diff --git a/app/aboot/fastboot.h b/app/aboot/fastboot.h new file mode 100644 index 000000000..ca0fb5737 --- /dev/null +++ b/app/aboot/fastboot.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __APP_FASTBOOT_H +#define __APP_FASTBOOT_H + +int fastboot_init(void *xfer_buffer, unsigned max); + +/* register a command handler + * - command handlers will be called if their prefix matches + * - they are expected to call fastboot_okay() or fastboot_fail() + * to indicate success/failure before returning + */ +void fastboot_register(const char *prefix, + void (*handle)(const char *arg, void *data, unsigned size)); + +/* publish a variable readable by the built-in getvar command */ +void fastboot_publish(const char *name, const char *value); + +/* only callable from within a command handler */ +void fastboot_okay(const char *result); +void fastboot_fail(const char *reason); + + +#endif diff --git a/app/aboot/rules.mk b/app/aboot/rules.mk new file mode 100644 index 000000000..320b4e171 --- /dev/null +++ b/app/aboot/rules.mk @@ -0,0 +1,9 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/aboot.c \ + $(LOCAL_DIR)/fastboot.c + +include make/module.mk diff --git a/include/dev/flash.h b/include/dev/flash.h new file mode 100644 index 000000000..95b5ba3e5 --- /dev/null +++ b/include/dev/flash.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef __DEV_FLASH_H +#define __DEV_FLASH_H + +#include + +void flash_init(struct ptable *ptable); +struct ptable *flash_get_ptable(void); + +/* flash operations */ +int flash_erase(struct ptentry *ptn); +int flash_read_ext(struct ptentry *ptn, unsigned extra_per_page, + unsigned offset, void *data, unsigned bytes); +int flash_write(struct ptentry *ptn, unsigned extra_per_page, const void *data, + unsigned bytes); + +static inline int flash_read(struct ptentry *ptn, unsigned offset, void *data, + unsigned bytes) +{ + return flash_read_ext(ptn, 0, offset, data, bytes); +} + + +#endif /* __DEV_FLASH_H */ From 33731333587e83868f8f67458a00da2b108a857c Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Mon, 13 Oct 2014 18:12:51 +0800 Subject: [PATCH 14/43] [lib][partition] put partition related code into one folder so the code organization more clearer: 1.move lib/partition to lib/partition/mbr 2.move lib/ptable to lib/partition/ptable 3.update rules.mk to pointer the new location Change-Id: I0d173acc7bacd23c890caffbf4049e9fe91fa31c Signed-off-by: Xiang Xiao --- app/lkboot/rules.mk | 2 +- app/zynq-common/rules.mk | 2 +- lib/partition/{ => mbr}/partition.c | 0 lib/partition/{ => mbr}/rules.mk | 0 lib/{ => partition}/ptable/ptable.c | 0 lib/{ => partition}/ptable/rules.mk | 0 project/armemu-test.mk | 2 +- 7 files changed, 3 insertions(+), 3 deletions(-) rename lib/partition/{ => mbr}/partition.c (100%) rename lib/partition/{ => mbr}/rules.mk (100%) rename lib/{ => partition}/ptable/ptable.c (100%) rename lib/{ => partition}/ptable/rules.mk (100%) diff --git a/app/lkboot/rules.mk b/app/lkboot/rules.mk index d369afb7c..09c0d3ff3 100644 --- a/app/lkboot/rules.mk +++ b/app/lkboot/rules.mk @@ -5,7 +5,7 @@ MODULE := $(LOCAL_DIR) MODULE_DEPS += \ lib/bio \ lib/minip \ - lib/ptable \ + lib/partition/ptable \ lib/sysparam MODULE_SRCS += \ diff --git a/app/zynq-common/rules.mk b/app/zynq-common/rules.mk index 73edb9047..4318bf288 100644 --- a/app/zynq-common/rules.mk +++ b/app/zynq-common/rules.mk @@ -5,7 +5,7 @@ MODULE := $(LOCAL_DIR) MODULE_DEPS += \ lib/minip \ lib/sysparam \ - lib/ptable + lib/partition/ptable GLOBAL_DEFINES += \ SYSPARAM_ALLOW_WRITE=1 diff --git a/lib/partition/partition.c b/lib/partition/mbr/partition.c similarity index 100% rename from lib/partition/partition.c rename to lib/partition/mbr/partition.c diff --git a/lib/partition/rules.mk b/lib/partition/mbr/rules.mk similarity index 100% rename from lib/partition/rules.mk rename to lib/partition/mbr/rules.mk diff --git a/lib/ptable/ptable.c b/lib/partition/ptable/ptable.c similarity index 100% rename from lib/ptable/ptable.c rename to lib/partition/ptable/ptable.c diff --git a/lib/ptable/rules.mk b/lib/partition/ptable/rules.mk similarity index 100% rename from lib/ptable/rules.mk rename to lib/partition/ptable/rules.mk diff --git a/project/armemu-test.mk b/project/armemu-test.mk index cb23048c5..172aacd61 100644 --- a/project/armemu-test.mk +++ b/project/armemu-test.mk @@ -5,7 +5,7 @@ LOCAL_DIR := $(GET_LOCAL_DIR) TARGET := armemu MODULES += \ lib/bio \ - lib/partition \ + lib/partition/mbr \ lib/bcache \ lib/fs \ lib/fs/ext2 \ From 1a22e1dc645506bc596bdb3925bcae61f872dcbb Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Tue, 14 Oct 2014 10:36:26 +0800 Subject: [PATCH 15/43] [lib][ptable] support access table entry by index Change-Id: I8e5fc9c7d1ce9364d7926e901f0f42a73fa8ab01 Signed-off-by: Xiang Xiao --- include/lib/ptable.h | 3 +++ lib/partition/ptable/ptable.c | 36 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/include/lib/ptable.h b/include/lib/ptable.h index af7f8f582..479393893 100644 --- a/include/lib/ptable.h +++ b/include/lib/ptable.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2013, Google, Inc. All rights reserved * Copyright (c) 2014, Travis Geiselbrecht + * Copyright (c) 2014, Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -30,6 +31,7 @@ status_t ptable_scan(bdev_t *bdev, uint64_t offset); bool ptable_found_valid(void); +int ptable_get_count(void); #define MAX_FLASH_PTABLE_NAME_LEN 12 @@ -40,6 +42,7 @@ struct ptable_entry { uint8_t name[MAX_FLASH_PTABLE_NAME_LEN]; }; +status_t ptable_get(int n, struct ptable_entry *entry); status_t ptable_find(const char *name, struct ptable_entry *entry) __NONNULL((1)); status_t ptable_create_default(bdev_t *bdev, uint64_t offset) __NONNULL(); diff --git a/lib/partition/ptable/ptable.c b/lib/partition/ptable/ptable.c index 791913051..9920c5efe 100644 --- a/lib/partition/ptable/ptable.c +++ b/lib/partition/ptable/ptable.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2013, Google, Inc. All rights reserved * Copyright (c) 2014, Travis Geiselbrecht + * Copyright (c) 2014, Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -286,6 +287,41 @@ bool ptable_found_valid(void) return ptable.valid; } +int ptable_get_count(void) +{ + int count = 0; + + if (ptable.valid) { + struct ptable_mem_entry *mentry; + list_for_every_entry(&ptable.list, mentry, struct ptable_mem_entry, node) { + count++; + } + } + + return count; +} + +status_t ptable_get(int n, struct ptable_entry *_entry) +{ + if (!ptable.valid) + return ERR_NOT_FOUND; + + struct ptable_mem_entry *mentry; + list_for_every_entry(&ptable.list, mentry, struct ptable_mem_entry, node) { + const struct ptable_entry *entry = &mentry->entry; + if (n-- == 0) { + /* copy the entry to the passed in pointer */ + if (_entry) { + memcpy(_entry, entry, sizeof(struct ptable_entry)); + } + + return NO_ERROR; + } + } + + return ERR_NOT_FOUND; +} + status_t ptable_find(const char *name, struct ptable_entry *_entry) { if (!ptable.valid) From 7e8cec0abea883c80e9e4cae7b3f80bd505d686b Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Tue, 14 Oct 2014 13:32:32 +0800 Subject: [PATCH 16/43] [app][aboot] port to the new ptable interface Change-Id: Ia681906e2aa7f428b6eb7a5d3825b18daaf46faa Signed-off-by: Xiang Xiao --- app/aboot/aboot.c | 64 +++++++++++++++++--------------------------- app/aboot/fastboot.c | 4 ++- include/dev/flash.h | 12 ++++----- 3 files changed, 33 insertions(+), 47 deletions(-) diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c index bfac87775..1da7534cf 100644 --- a/app/aboot/aboot.c +++ b/app/aboot/aboot.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2009, Google Inc. + * Copyright (c) 2014, Xiaomi Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -66,13 +68,13 @@ struct atag_ptbl_entry { void platform_uninit_timer(void); -static void ptentry_to_tag(unsigned **ptr, struct ptentry *ptn) +static void ptentry_to_tag(unsigned **ptr, struct ptable_entry *ptn) { struct atag_ptbl_entry atag_ptn; memcpy(atag_ptn.name, ptn->name, 16); atag_ptn.name[15] = '\0'; - atag_ptn.offset = ptn->start; + atag_ptn.offset = ptn->offset; atag_ptn.size = ptn->length; atag_ptn.flags = ptn->flags; memcpy(*ptr, &atag_ptn, sizeof(struct atag_ptbl_entry)); @@ -85,7 +87,7 @@ void boot_linux(void *kernel, unsigned *tags, { unsigned *ptr = tags; void (*entry)(unsigned,unsigned,unsigned*) = kernel; - struct ptable *ptable; + int count; /* CORE */ *ptr++ = 2; @@ -98,13 +100,18 @@ void boot_linux(void *kernel, unsigned *tags, *ptr++ = ramdisk_size; } - if ((ptable = flash_get_ptable()) && (ptable->count != 0)) { + count = ptable_get_count(); + if (count != 0) { int i; - *ptr++ = 2 + (ptable->count * (sizeof(struct atag_ptbl_entry) / + *ptr++ = 2 + (count * (sizeof(struct atag_ptbl_entry) / sizeof(unsigned))); *ptr++ = 0x4d534d70; - for (i = 0; i < ptable->count; ++i) - ptentry_to_tag(&ptr, ptable_get(ptable, i)); + for (i = 0; i < count; ++i) { + struct ptable_entry entry; + bzero(&entry, sizeof(entry)); + ptable_get(i, &entry); + ptentry_to_tag(&ptr, &entry); + } } if (cmdline && cmdline[0]) { @@ -145,19 +152,12 @@ int boot_linux_from_flash(void) { struct boot_img_hdr *hdr = (void*) buf; unsigned n; - struct ptentry *ptn; - struct ptable *ptable; + struct ptable_entry entry; + struct ptable_entry *ptn = &entry; unsigned offset = 0; const char *cmdline; - ptable = flash_get_ptable(); - if (ptable == NULL) { - dprintf(CRITICAL, "ERROR: Partition table not found\n"); - return -1; - } - - ptn = ptable_find(ptable, "boot"); - if (ptn == NULL) { + if (ptable_find("boot", ptn) != 0) { dprintf(CRITICAL, "ERROR: No boot partition found\n"); return -1; } @@ -248,17 +248,10 @@ void cmd_boot(const char *arg, void *data, unsigned sz) void cmd_erase(const char *arg, void *data, unsigned sz) { - struct ptentry *ptn; - struct ptable *ptable; - - ptable = flash_get_ptable(); - if (ptable == NULL) { - fastboot_fail("partition table doesn't exist"); - return; - } + struct ptable_entry entry; + struct ptable_entry *ptn = &entry; - ptn = ptable_find(ptable, arg); - if (ptn == NULL) { + if (ptable_find(arg, ptn) != 0) { fastboot_fail("unknown partition name"); return; } @@ -272,30 +265,23 @@ void cmd_erase(const char *arg, void *data, unsigned sz) void cmd_flash(const char *arg, void *data, unsigned sz) { - struct ptentry *ptn; - struct ptable *ptable; + struct ptable_entry entry; + struct ptable_entry *ptn = &entry; unsigned extra = 0; - ptable = flash_get_ptable(); - if (ptable == NULL) { - fastboot_fail("partition table doesn't exist"); - return; - } - - ptn = ptable_find(ptable, arg); - if (ptn == NULL) { + if (ptable_find(arg, ptn) != 0) { fastboot_fail("unknown partition name"); return; } - if (!strcmp(ptn->name, "boot") || !strcmp(ptn->name, "recovery")) { + if (!strcmp((char *)ptn->name, "boot") || !strcmp((char *)ptn->name, "recovery")) { if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) { fastboot_fail("image is not a boot image"); return; } } - if (!strcmp(ptn->name, "system") || !strcmp(ptn->name, "userdata")) + if (!strcmp((char *)ptn->name, "system") || !strcmp((char *)ptn->name, "userdata")) extra = 64; else sz = ROUND_TO_PAGE(sz); diff --git a/app/aboot/fastboot.c b/app/aboot/fastboot.c index a716f5682..1d6ef5c2f 100644 --- a/app/aboot/fastboot.c +++ b/app/aboot/fastboot.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2009, Google Inc. + * Copyright (c) 2014, Xiaomi Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,6 +29,7 @@ #include #include +#include #include #include #include @@ -274,7 +276,7 @@ static void cmd_download(const char *arg, void *data, unsigned sz) return; r = usb_read(download_base, len); - if ((r < 0) || (r != len)) { + if ((r < 0) || ((unsigned)r != len)) { fastboot_state = STATE_ERROR; return; } diff --git a/include/dev/flash.h b/include/dev/flash.h index 95b5ba3e5..b590517f0 100644 --- a/include/dev/flash.h +++ b/include/dev/flash.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2008, Google Inc. + * Copyright (c) 2014, Xiaomi Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,17 +33,14 @@ #include -void flash_init(struct ptable *ptable); -struct ptable *flash_get_ptable(void); - /* flash operations */ -int flash_erase(struct ptentry *ptn); -int flash_read_ext(struct ptentry *ptn, unsigned extra_per_page, +int flash_erase(struct ptable_entry *ptn); +int flash_read_ext(struct ptable_entry *ptn, unsigned extra_per_page, unsigned offset, void *data, unsigned bytes); -int flash_write(struct ptentry *ptn, unsigned extra_per_page, const void *data, +int flash_write(struct ptable_entry *ptn, unsigned extra_per_page, const void *data, unsigned bytes); -static inline int flash_read(struct ptentry *ptn, unsigned offset, void *data, +static inline int flash_read(struct ptable_entry *ptn, unsigned offset, void *data, unsigned bytes) { return flash_read_ext(ptn, 0, offset, data, bytes); From 551993508325d01882e089b6ec855bdd1aca313d Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Wed, 15 Oct 2014 13:43:14 +0800 Subject: [PATCH 17/43] [time] support mdelay and udelay function Change-Id: Iaddec5e8c87d24f2d9490ea0e483c8a439609d2d Signed-off-by: Xiang Xiao --- include/kernel/timer.h | 4 ++++ kernel/timer.c | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/include/kernel/timer.h b/include/kernel/timer.h index 0da1a0f0e..1083c3b8e 100644 --- a/include/kernel/timer.h +++ b/include/kernel/timer.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2009 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -65,5 +66,8 @@ void timer_set_oneshot(timer_t *, lk_time_t delay, timer_callback, void *arg); void timer_set_periodic(timer_t *, lk_time_t period, timer_callback, void *arg); void timer_cancel(timer_t *); +void udelay(unsigned usecs); +void mdelay(unsigned msecs); + #endif diff --git a/kernel/timer.c b/kernel/timer.c index 0b7088707..0e3767979 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2009 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -277,4 +278,18 @@ void timer_init(void) #endif } +void udelay(unsigned usecs) +{ + lk_bigtime_t start = current_time_hires(); + + while ((current_time_hires() - start) < usecs) + ; +} +void mdelay(unsigned msecs) +{ + lk_time_t start = current_time(); + + while ((current_time() - start) < msecs) + ; +} From 8703775163ddc819ada16ecaffd369ba0511c0fd Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Wed, 15 Oct 2014 13:54:49 +0800 Subject: [PATCH 18/43] provide linux-style read[w|b]()/write[w|b]() in reg.h Change-Id: I1ed607a9703e9e19ce78b0b27dd4ddeaf86bad59 Signed-off-by: Xiang Xiao --- include/reg.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/reg.h b/include/reg.h index 91ee64ad1..71750e3ee 100644 --- a/include/reg.h +++ b/include/reg.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -39,4 +40,10 @@ #define writel(v, a) (*REG32(a) = (v)) #define readl(a) (*REG32(a)) +#define writew(v, a) (*REG16(a) = (v)) +#define readw(a) (*REG16(a)) + +#define writeb(v, a) (*REG8(a) = (v)) +#define readb(a) (*REG8(a)) + #endif From 46a861843d2018aae1ebd247be3b6ef7a2a7d0ea Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Thu, 16 Oct 2014 10:55:29 +0800 Subject: [PATCH 19/43] [vm] add vaddr_to_paddr function and make paddr_to_kvaddr/vaddr_to_paddr is callable even without vm Change-Id: I8e2e670e93ae9afc04dd8d0ef3ae4fa5982d6564 Signed-off-by: Xiang Xiao --- include/kernel/vm.h | 16 +++++++++++++++- kernel/vm/vm.c | 9 +++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/include/kernel/vm.h b/include/kernel/vm.h index e586cb0a5..70dd5a610 100644 --- a/include/kernel/vm.h +++ b/include/kernel/vm.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -150,8 +151,21 @@ void *pmm_alloc_kpages(uint count, struct list_node *list); /* Helper routine for pmm_alloc_kpages. */ static inline void *pmm_alloc_kpage(void) { return pmm_alloc_kpages(1, NULL); } -/* physical to virtual */ +/* physical <==> virtual */ +#if WITH_KERNEL_VM void *paddr_to_kvaddr(paddr_t pa); +paddr_t vaddr_to_paddr(void *va); +#else +static inline void *paddr_to_kvaddr(paddr_t pa) +{ + return (void *)pa; +} + +static inline paddr_t vaddr_to_paddr(void *va) +{ + return (paddr_t)va; +} +#endif /* virtual allocator */ typedef struct vmm_aspace { diff --git a/kernel/vm/vm.c b/kernel/vm/vm.c index 56eea298d..c20b96b5c 100644 --- a/kernel/vm/vm.c +++ b/kernel/vm/vm.c @@ -112,6 +112,15 @@ void *paddr_to_kvaddr(paddr_t pa) return NULL; } +paddr_t vaddr_to_paddr(void *va) +{ + paddr_t pa; + if (arch_mmu_query((vaddr_t)va, &pa, 0) < 0) { + pa = 0; + } + return pa; +} + static int cmd_vm(int argc, const cmd_args *argv) { if (argc < 2) { From 13e43e32840ee1b70ad71d24185cf2a9875854a1 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Thu, 16 Oct 2014 12:52:53 +0800 Subject: [PATCH 20/43] [arch] move the common code from arch_chain_load to chain_load and support chain_load for the no vm case Change-Id: Idbdb40b39b98c7fb80ed4b4d1ac0efb0171875f8 Signed-off-by: Xiang Xiao --- app/lkboot/commands.c | 3 +- arch/arm/arm-m/arch.c | 5 +-- arch/arm/arm/arch.c | 59 ++----------------------------- arch/arm/arm/asm.S | 12 +++---- arch/arm/include/arch/arm/mmu.h | 2 +- arch/arm/include/arch/defines.h | 3 ++ arch/arm64/arch.c | 3 +- arch/x86-64/arch.c | 8 +++++ arch/x86/arch.c | 9 +++-- include/arch.h | 3 +- include/kernel/thread.h | 3 ++ kernel/thread.c | 45 +++++++++++++++++++++++ lib/debugcommands/debugcommands.c | 3 +- 13 files changed, 85 insertions(+), 73 deletions(-) diff --git a/app/lkboot/commands.c b/app/lkboot/commands.c index 0a9a67f78..1969b58cf 100644 --- a/app/lkboot/commands.c +++ b/app/lkboot/commands.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2014 Brian Swetland + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -76,7 +77,7 @@ static int do_reboot(void *arg) { static int do_ramboot(void *arg) { thread_sleep(250); - arch_chain_load(lkb_iobuffer); + chain_load(lkb_iobuffer); return 0; } diff --git a/arch/arm/arm-m/arch.c b/arch/arm/arm-m/arch.c index dd8c12e50..4a08a61f8 100644 --- a/arch/arm/arm-m/arch.c +++ b/arch/arm/arm-m/arch.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2013 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -137,7 +138,7 @@ void arm_cm_irq_exit(bool reschedule) dec_critical_section(); } -void arch_chain_load(void *entry) +void arch_chain_load(paddr_t entry) { - PANIC_UNIMPLEMENTED; + PANIC_UNIMPLEMENTED; } diff --git a/arch/arm/arm/arch.c b/arch/arm/arm/arch.c index ea316a5a0..0b7052618 100644 --- a/arch/arm/arm/arch.c +++ b/arch/arm/arm/arch.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -106,6 +107,7 @@ void arch_quiesce(void) __asm__ volatile("mcr p15, 0, %0, c15, c12, 0" :: "r" (en)); #endif #endif + arch_disable_cache(UCACHE); } #if ARM_ISA_ARMV7 @@ -126,61 +128,4 @@ status_t arm_vtop(addr_t va, addr_t *pa) } #endif -void arch_chain_load(void *entry) -{ - LTRACEF("entry %p\n", entry); - - /* we are going to shut down the system, start by disabling interrupts */ - enter_critical_section(); - - /* give target and platform a chance to put hardware into a suitable - * state for chain loading. - */ - target_quiesce(); - platform_quiesce(); - - arch_quiesce(); - -#if WITH_KERNEL_VM - /* get the physical address of the entry point we're going to branch to */ - paddr_t entry_pa; - if (arm_vtop((addr_t)entry, &entry_pa) < 0) { - panic("error translating entry physical address\n"); - } - - /* add the low bits of the virtual address back */ - entry_pa |= ((addr_t)entry & 0xfff); - - LTRACEF("entry pa 0x%lx\n", entry_pa); - - /* figure out the mapping for the chain load routine */ - paddr_t loader_pa; - if (arm_vtop((addr_t)&arm_chain_load, &loader_pa) < 0) { - panic("error translating loader physical address\n"); - } - - /* add the low bits of the virtual address back */ - loader_pa |= ((addr_t)&arm_chain_load & 0xfff); - - paddr_t loader_pa_section = ROUNDDOWN(loader_pa, SECTION_SIZE); - - LTRACEF("loader address %p, phys 0x%lx, surrounding large page 0x%lx\n", - &arm_chain_load, loader_pa, loader_pa_section); - - /* using large pages, map around the target location */ - arch_mmu_map(loader_pa_section, loader_pa_section, (2 * SECTION_SIZE / PAGE_SIZE), 0); - - LTRACEF("disabling instruction/data cache\n"); - arch_disable_cache(UCACHE); - - LTRACEF("branching to physical address of loader\n"); - - /* branch to the physical address version of the chain loader routine */ - void (*loader)(paddr_t entry) __NO_RETURN = (void *)loader_pa; - loader(entry_pa); -#else -#error handle the non vm path (should be simpler) -#endif -} - /* vim: set ts=4 sw=4 noexpandtab: */ diff --git a/arch/arm/arm/asm.S b/arch/arm/arm/asm.S index 915559eb6..d2d6cc37d 100644 --- a/arch/arm/arm/asm.S +++ b/arch/arm/arm/asm.S @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -101,12 +102,10 @@ FUNCTION(arm_save_mode_regs) .text -/* void arm_chain_load(paddr_t entry) __NO_RETURN; */ +/* void arch_chain_load(paddr_t entry) __NO_RETURN; */ /* shut down the system, branching into the secondary system */ -FUNCTION(arm_chain_load) -#if !WITH_KERNEL_VM -#error implement non VM based chain load -#else +FUNCTION(arch_chain_load) +#if WITH_KERNEL_VM /* The MMU is initialized and running at this point, so we'll need to * make sure we can disable it and continue to run. The caller should @@ -123,11 +122,10 @@ FUNCTION(arm_chain_load) /* Write back SCTLR */ mcr p15, 0, r1, c1, c0, 0 isb +#endif // WITH_KERNEL_VM /* call the entry point */ bx r0 -#endif // WITH_KERNEL_VM - /* vim: set ts=4 sw=4 noexpandtab: */ diff --git a/arch/arm/include/arch/arm/mmu.h b/arch/arm/include/arch/arm/mmu.h index 2d20e09ab..c29a13246 100644 --- a/arch/arm/include/arch/arm/mmu.h +++ b/arch/arm/include/arch/arm/mmu.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2008-2014 Travis Geiselbrecht * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -25,7 +26,6 @@ #define __ARCH_ARM_MMU_H #define MB (1024U*1024U) -#define SECTION_SIZE MB #define SUPERSECTION_SIZE (16 * MB) #if defined(ARM_ISA_ARMV6) | defined(ARM_ISA_ARMV7) diff --git a/arch/arm/include/arch/defines.h b/arch/arm/include/arch/defines.h index 899afc32e..cf5f05f04 100644 --- a/arch/arm/include/arch/defines.h +++ b/arch/arm/include/arch/defines.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -27,6 +28,8 @@ #define PAGE_SIZE 4096 #define PAGE_SIZE_SHIFT 12 +#define SECTION_SIZE (1024 * 1024) + #if ARM_CPU_ARM7 /* irrelevant, no consistent cache */ #define CACHE_LINE 32 diff --git a/arch/arm64/arch.c b/arch/arm64/arch.c index 099edefcd..e78242a6f 100644 --- a/arch/arm64/arch.c +++ b/arch/arm64/arch.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -51,7 +52,7 @@ void arch_idle(void) __asm__ volatile("wfi"); } -void arch_chain_load(void *entry) +void arch_chain_load(paddr_t entry) { PANIC_UNIMPLEMENTED; } diff --git a/arch/x86-64/arch.c b/arch/x86-64/arch.c index 3f0430ef3..31235616c 100644 --- a/arch/x86-64/arch.c +++ b/arch/x86-64/arch.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2009 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -60,4 +61,11 @@ void arch_init(void) { } +void arch_quiesce(void) +{ +} +void arch_chain_load(paddr_t entry) +{ + PANIC_UNIMPLEMENTED; +} diff --git a/arch/x86/arch.c b/arch/x86/arch.c index 5051e11b7..7ca1178f8 100644 --- a/arch/x86/arch.c +++ b/arch/x86/arch.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2009 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -60,8 +61,12 @@ void arch_init(void) { } -void arch_chain_load(void *entry) +void arch_quiesce(void) { - PANIC_UNIMPLEMENTED; +} + +void arch_chain_load(paddr_t entry) +{ + PANIC_UNIMPLEMENTED; } diff --git a/include/arch.h b/include/arch.h index 5253ed082..fb7187cc8 100644 --- a/include/arch.h +++ b/include/arch.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -31,7 +32,7 @@ __BEGIN_CDECLS void arch_early_init(void); void arch_init(void); void arch_quiesce(void); -void arch_chain_load(void *entry) __NO_RETURN; +void arch_chain_load(paddr_t entry) __NO_RETURN; __END_CDECLS diff --git a/include/kernel/thread.h b/include/kernel/thread.h index fa6186253..099cd96d4 100644 --- a/include/kernel/thread.h +++ b/include/kernel/thread.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -185,6 +186,8 @@ static inline __ALWAYS_INLINE uint32_t tls_set(uint entry, uint32_t val) return oldval; } +void chain_load(void *entry) __NO_RETURN; + /* thread level statistics */ #if LK_DEBUGLEVEL > 1 #define THREAD_STATS 1 diff --git a/kernel/thread.c b/kernel/thread.c index 128bb030a..f2bb525dc 100644 --- a/kernel/thread.c +++ b/kernel/thread.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2009 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -37,9 +38,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -48,6 +51,10 @@ #define THREAD_CHECKS 1 #endif +#ifndef SECTION_SIZE +#define SECTION_SIZE PAGE_SIZE +#endif + #if THREAD_STATS struct thread_stats thread_stats; #endif @@ -1062,5 +1069,43 @@ status_t thread_unblock_from_wait_queue(thread_t *t, status_t wait_queue_error) return NO_ERROR; } +void chain_load(void *entry) +{ + /* we are going to shut down the system, start by disabling interrupts */ + enter_critical_section(); + + /* give target and platform a chance to put hardware into a suitable + * state for chain loading. + */ + target_quiesce(); + platform_quiesce(); + + arch_quiesce(); + +#if WITH_KERNEL_VM + /* get the physical address of the entry point we're going to branch to */ + paddr_t entry_pa = vaddr_to_paddr(entry); + /* add the low bits of the virtual address back */ + entry_pa |= ((addr_t)entry % PAGE_SIZE); + + /* figure out the mapping for the chain load routine */ + paddr_t loader_pa = vaddr_to_paddr(&arch_chain_load); + /* add the low bits of the virtual address back */ + loader_pa |= ((addr_t)&arch_chain_load % PAGE_SIZE); + + paddr_t loader_pa_section = ROUNDDOWN(loader_pa, SECTION_SIZE); + + /* using large pages, map around the target location */ + arch_mmu_map(loader_pa_section, loader_pa_section, (2 * SECTION_SIZE / PAGE_SIZE), 0); + + /* branch to the physical address version of the chain loader routine */ + void (*loader)(paddr_t entry) __NO_RETURN = (void *)loader_pa; + loader(entry_pa); +#else + /* branch to the chain loader routine */ + arch_chain_load((paddr_t)entry); +#endif +} + /* vim: set ts=4 sw=4 noexpandtab: */ diff --git a/lib/debugcommands/debugcommands.c b/lib/debugcommands/debugcommands.c index f0b6b9368..606bb3e98 100644 --- a/lib/debugcommands/debugcommands.c +++ b/lib/debugcommands/debugcommands.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2012 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -269,7 +270,7 @@ static int cmd_chain(int argc, const cmd_args *argv) return -1; } - arch_chain_load((void *)argv[1].u); + chain_load((void *)argv[1].u); return 0; } From d3b4bfcbd7400676258baeaade5f9865ab3ae83b Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Thu, 16 Oct 2014 14:57:23 +0800 Subject: [PATCH 21/43] [arch] support chain_load with arguments(max 4) arch specified code need pass these arguments to the entry pointer with the suitable approach Change-Id: I1204b87de9b81ee81526b402a20eeef2774e5774 Signed-off-by: Xiang Xiao --- arch/arm/arm-m/arch.c | 2 +- arch/arm/arm/asm.S | 11 ++++++----- arch/arm64/arch.c | 2 +- arch/x86-64/arch.c | 2 +- arch/x86/arch.c | 2 +- include/arch.h | 2 +- include/kernel/thread.h | 4 ++++ kernel/thread.c | 22 +++++++++++++++++++++- 8 files changed, 36 insertions(+), 11 deletions(-) diff --git a/arch/arm/arm-m/arch.c b/arch/arm/arm-m/arch.c index 4a08a61f8..a67b32f18 100644 --- a/arch/arm/arm-m/arch.c +++ b/arch/arm/arm-m/arch.c @@ -138,7 +138,7 @@ void arm_cm_irq_exit(bool reschedule) dec_critical_section(); } -void arch_chain_load(paddr_t entry) +void arch_chain_load(uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, paddr_t entry) { PANIC_UNIMPLEMENTED; } diff --git a/arch/arm/arm/asm.S b/arch/arm/arm/asm.S index d2d6cc37d..ca74f6a62 100644 --- a/arch/arm/arm/asm.S +++ b/arch/arm/arm/asm.S @@ -102,9 +102,10 @@ FUNCTION(arm_save_mode_regs) .text -/* void arch_chain_load(paddr_t entry) __NO_RETURN; */ +/* void arch_chain_load(uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, paddr_t entry) __NO_RETURN; */ /* shut down the system, branching into the secondary system */ FUNCTION(arch_chain_load) + ldr r4, [sp] #if WITH_KERNEL_VM /* The MMU is initialized and running at this point, so we'll need to @@ -114,18 +115,18 @@ FUNCTION(arch_chain_load) * point in physical space. */ /* Read SCTLR */ - mrc p15, 0, r1, c1, c0, 0 + mrc p15, 0, r5, c1, c0, 0 /* Turn off the MMU */ - bic r1, r1, #0x1 + bic r5, r5, #0x1 /* Write back SCTLR */ - mcr p15, 0, r1, c1, c0, 0 + mcr p15, 0, r5, c1, c0, 0 isb #endif // WITH_KERNEL_VM /* call the entry point */ - bx r0 + bx r4 /* vim: set ts=4 sw=4 noexpandtab: */ diff --git a/arch/arm64/arch.c b/arch/arm64/arch.c index e78242a6f..a0d16b176 100644 --- a/arch/arm64/arch.c +++ b/arch/arm64/arch.c @@ -52,7 +52,7 @@ void arch_idle(void) __asm__ volatile("wfi"); } -void arch_chain_load(paddr_t entry) +void arch_chain_load(uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, paddr_t entry) { PANIC_UNIMPLEMENTED; } diff --git a/arch/x86-64/arch.c b/arch/x86-64/arch.c index 31235616c..72f3967bf 100644 --- a/arch/x86-64/arch.c +++ b/arch/x86-64/arch.c @@ -65,7 +65,7 @@ void arch_quiesce(void) { } -void arch_chain_load(paddr_t entry) +void arch_chain_load(uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, paddr_t entry) { PANIC_UNIMPLEMENTED; } diff --git a/arch/x86/arch.c b/arch/x86/arch.c index 7ca1178f8..d1324c165 100644 --- a/arch/x86/arch.c +++ b/arch/x86/arch.c @@ -65,7 +65,7 @@ void arch_quiesce(void) { } -void arch_chain_load(paddr_t entry) +void arch_chain_load(uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, paddr_t entry) { PANIC_UNIMPLEMENTED; } diff --git a/include/arch.h b/include/arch.h index fb7187cc8..d118f6e45 100644 --- a/include/arch.h +++ b/include/arch.h @@ -32,7 +32,7 @@ __BEGIN_CDECLS void arch_early_init(void); void arch_init(void); void arch_quiesce(void); -void arch_chain_load(paddr_t entry) __NO_RETURN; +void arch_chain_load(uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, paddr_t entry) __NO_RETURN; __END_CDECLS diff --git a/include/kernel/thread.h b/include/kernel/thread.h index 099cd96d4..39b2b7536 100644 --- a/include/kernel/thread.h +++ b/include/kernel/thread.h @@ -187,6 +187,10 @@ static inline __ALWAYS_INLINE uint32_t tls_set(uint entry, uint32_t val) } void chain_load(void *entry) __NO_RETURN; +void chain_load1(void *entry, uintptr_t a0) __NO_RETURN; +void chain_load2(void *entry, uintptr_t a0, uintptr_t a1) __NO_RETURN; +void chain_load3(void *entry, uintptr_t a0, uintptr_t a1, uintptr_t a2) __NO_RETURN; +void chain_load4(void *entry, uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3) __NO_RETURN; /* thread level statistics */ #if LK_DEBUGLEVEL > 1 diff --git a/kernel/thread.c b/kernel/thread.c index f2bb525dc..81b830de9 100644 --- a/kernel/thread.c +++ b/kernel/thread.c @@ -1070,6 +1070,26 @@ status_t thread_unblock_from_wait_queue(thread_t *t, status_t wait_queue_error) } void chain_load(void *entry) +{ + chain_load1(entry, 0); +} + +void chain_load1(void *entry, uintptr_t a0) +{ + chain_load2(entry, a0, 0); +} + +void chain_load2(void *entry, uintptr_t a0, uintptr_t a1) +{ + chain_load3(entry, a0, a1, 0); +} + +void chain_load3(void *entry, uintptr_t a0, uintptr_t a1, uintptr_t a2) +{ + chain_load4(entry, a0, a1, a2, 0); +} + +void chain_load4(void *entry, uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3) { /* we are going to shut down the system, start by disabling interrupts */ enter_critical_section(); @@ -1103,7 +1123,7 @@ void chain_load(void *entry) loader(entry_pa); #else /* branch to the chain loader routine */ - arch_chain_load((paddr_t)entry); + arch_chain_load(a0, a1, a2, a3, (paddr_t)entry); #endif } From 2c3fdcc306202510cd014284e3d6c2235b530bc4 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Fri, 17 Oct 2014 10:42:13 +0800 Subject: [PATCH 22/43] [vm] remove __MMU_INITIAL_MAPPING_XXXX_OFFSET and related STATIC_ASSERT because these definition isn't suitable for 64bit cpu and make compiler error Change-Id: Ic896b62b5545e89b52324a49c03430aae73f9cb7 Signed-off-by: Xiang Xiao --- include/kernel/vm.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/include/kernel/vm.h b/include/kernel/vm.h index 70dd5a610..75be15cdf 100644 --- a/include/kernel/vm.h +++ b/include/kernel/vm.h @@ -23,13 +23,6 @@ */ #pragma once -/* some assembly #defines, need to match the structure below */ -#define __MMU_INITIAL_MAPPING_PHYS_OFFSET 0 -#define __MMU_INITIAL_MAPPING_VIRT_OFFSET 4 -#define __MMU_INITIAL_MAPPING_SIZE_OFFSET 8 -#define __MMU_INITIAL_MAPPING_FLAGS_OFFSET 12 -#define __MMU_INITIAL_MAPPING_SIZE 20 - /* flags for initial mapping struct */ #define MMU_INITIAL_MAPPING_TEMPORARY (0x1) #define MMU_INITIAL_MAPPING_FLAG_UNCACHED (0x2) @@ -58,13 +51,6 @@ struct mmu_initial_mapping { const char *name; }; -/* Assert that the assembly macros above match this struct. */ -STATIC_ASSERT(__offsetof(struct mmu_initial_mapping, phys) == __MMU_INITIAL_MAPPING_PHYS_OFFSET); -STATIC_ASSERT(__offsetof(struct mmu_initial_mapping, virt) == __MMU_INITIAL_MAPPING_VIRT_OFFSET); -STATIC_ASSERT(__offsetof(struct mmu_initial_mapping, size) == __MMU_INITIAL_MAPPING_SIZE_OFFSET); -STATIC_ASSERT(__offsetof(struct mmu_initial_mapping, flags) == __MMU_INITIAL_MAPPING_FLAGS_OFFSET); -STATIC_ASSERT(sizeof(struct mmu_initial_mapping) == __MMU_INITIAL_MAPPING_SIZE); - /* Platform or target must fill out one of these to set up the initial memory map * for kernel and enough IO space to boot. */ From e9789e0aafa8076e203e1704bd68cbf687452e2e Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Thu, 16 Oct 2014 15:13:50 +0800 Subject: [PATCH 23/43] [app][aboot] ensure aboot work well for no identity mapping by replace pointer cast with paddr_to_kvaddr/vaddr_to_paddr/chain_load3 and get the address from boot image header instead of the hardcode value Change-Id: I5b9ce69ca2d23997948631f2b5807d24762b1cc2 Signed-off-by: Xiang Xiao --- app/aboot/aboot.c | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c index 1da7534cf..074574bb8 100644 --- a/app/aboot/aboot.c +++ b/app/aboot/aboot.c @@ -32,12 +32,10 @@ #include #include -#include -#include #include #include #include -#include +#include #include #include @@ -46,9 +44,6 @@ #include "bootimg.h" #include "fastboot.h" -#define TAGS_ADDR 0x10000100 -#define KERNEL_ADDR 0x10800000 -#define RAMDISK_ADDR 0x11000000 #define DEFAULT_CMDLINE "mem=50M console=null"; static struct udc_device surf_udc_device = { @@ -66,8 +61,6 @@ struct atag_ptbl_entry { unsigned flags; }; -void platform_uninit_timer(void); - static void ptentry_to_tag(unsigned **ptr, struct ptable_entry *ptn) { struct atag_ptbl_entry atag_ptn; @@ -86,7 +79,6 @@ void boot_linux(void *kernel, unsigned *tags, void *ramdisk, unsigned ramdisk_size) { unsigned *ptr = tags; - void (*entry)(unsigned,unsigned,unsigned*) = kernel; int count; /* CORE */ @@ -96,7 +88,7 @@ void boot_linux(void *kernel, unsigned *tags, if (ramdisk_size) { *ptr++ = 4; *ptr++ = 0x54420005; - *ptr++ = (unsigned)ramdisk; + *ptr++ = vaddr_to_paddr(ramdisk); *ptr++ = ramdisk_size; } @@ -133,13 +125,7 @@ void boot_linux(void *kernel, unsigned *tags, if (cmdline) dprintf(INFO, "cmdline: %s\n", cmdline); - enter_critical_section(); - platform_uninit_timer(); - arch_disable_cache(UCACHE); - arch_disable_mmu(); - - entry(0, machtype, tags); - + chain_load3(kernel, 0, machtype, vaddr_to_paddr(tags)); } #define PAGE_MASK 2047 @@ -156,6 +142,8 @@ int boot_linux_from_flash(void) struct ptable_entry *ptn = &entry; unsigned offset = 0; const char *cmdline; + void *kernel; + void *ramdisk; if (ptable_find("boot", ptn) != 0) { dprintf(CRITICAL, "ERROR: No boot partition found\n"); @@ -174,14 +162,16 @@ int boot_linux_from_flash(void) } n = ROUND_TO_PAGE(hdr->kernel_size); - if (flash_read(ptn, offset, (void *)hdr->kernel_addr, n)) { + kernel = paddr_to_kvaddr(hdr->kernel_addr); + if (flash_read(ptn, offset, kernel, n)) { dprintf(CRITICAL, "ERROR: Cannot read kernel image\n"); return -1; } offset += n; n = ROUND_TO_PAGE(hdr->ramdisk_size); - if (flash_read(ptn, offset, (void *)hdr->ramdisk_addr, n)) { + ramdisk = paddr_to_kvaddr(hdr->ramdisk_addr); + if (flash_read(ptn, offset, ramdisk, n)) { dprintf(CRITICAL, "ERROR: Cannot read ramdisk image\n"); return -1; } @@ -202,9 +192,9 @@ int boot_linux_from_flash(void) /* TODO: create/pass atags to kernel */ dprintf(INFO, "\nBooting Linux\n"); - boot_linux((void *)hdr->kernel_addr, (void *)TAGS_ADDR, + boot_linux(kernel, paddr_to_kvaddr(hdr->tags_addr), (const char *)cmdline, LINUX_MACHTYPE, - (void *)hdr->ramdisk_addr, hdr->ramdisk_size); + ramdisk, hdr->ramdisk_size); return 0; } @@ -215,6 +205,8 @@ void cmd_boot(const char *arg, void *data, unsigned sz) unsigned ramdisk_actual; static struct boot_img_hdr hdr; char *ptr = ((char*) data); + void *kernel; + void *ramdisk; if (sz < sizeof(hdr)) { fastboot_fail("invalid bootimage header"); @@ -234,16 +226,19 @@ void cmd_boot(const char *arg, void *data, unsigned sz) return; } - memmove((void*) KERNEL_ADDR, ptr + 2048, hdr.kernel_size); - memmove((void*) RAMDISK_ADDR, ptr + 2048 + kernel_actual, hdr.ramdisk_size); + kernel = paddr_to_kvaddr(hdr.kernel_addr); + memmove(kernel, ptr + 2048, hdr.kernel_size); + + ramdisk = paddr_to_kvaddr(hdr.ramdisk_addr); + memmove(ramdisk, ptr + 2048 + kernel_actual, hdr.ramdisk_size); fastboot_okay(""); udc_stop(); - boot_linux((void*) KERNEL_ADDR, (void*) TAGS_ADDR, + boot_linux(kernel, paddr_to_kvaddr(hdr.tags_addr), (const char*) hdr.cmdline, LINUX_MACHTYPE, - (void*) RAMDISK_ADDR, hdr.ramdisk_size); + ramdisk, hdr.ramdisk_size); } void cmd_erase(const char *arg, void *data, unsigned sz) From d2a62c9eda2012c8ff0991d10a4b532b2f21722e Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Fri, 17 Oct 2014 19:29:42 +0800 Subject: [PATCH 24/43] [arch][arm] don't change V bit for pre armv7 because VBAR just exist on armv7 and replace KERNEL_BASE with _start since KERNEL_BASE isn't defined when WITH_KERNEL_VM=0 Change-Id: Ic2496fe9de901564975142073121ee540972c00a Signed-off-by: Xiang Xiao --- arch/arm/arm/arch.c | 3 ++- arch/arm/arm/start.S | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/arm/arm/arch.c b/arch/arm/arm/arch.c index 0b7052618..2eadd2a76 100644 --- a/arch/arm/arm/arch.c +++ b/arch/arm/arm/arch.c @@ -43,7 +43,8 @@ void arch_early_init(void) /* set the vector base to our exception vectors so we dont need to double map at 0 */ #if ARM_ISA_ARMV7 - arm_write_vbar(KERNEL_BASE + KERNEL_LOAD_OFFSET); + extern void _start(void); + arm_write_vbar((vaddr_t)_start); #endif #if ARM_WITH_MMU diff --git a/arch/arm/arm/start.S b/arch/arm/arm/start.S index 38ef59ea5..a1ac962e6 100644 --- a/arch/arm/arm/start.S +++ b/arch/arm/arm/start.S @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2013 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -47,14 +48,17 @@ arm_reset: #if ARM_WITH_CP15 mrc p15, 0, r0, c1, c0, 0 /* XXX this is currently for arm926, revist with armv6 cores */ - /* new thumb behavior, low exception vectors, i/d cache disable, mmu disabled */ - bic r0, r0, #(1<<15| 1<<13 | 1<<12) + /* new thumb behavior, i/d cache disable, mmu disabled */ + bic r0, r0, #(1<<15| 1<<12) bic r0, r0, #(1<<2 | 1<<1 | 1<<0) #if ARM_ARCH_LEVEL < 6 /* enable alignment faults on pre-ARMv6 hardware. On v6+, * GCC is free to generate unaligned accesses. */ orr r0, r0, #(1<<1) +#elif ARM_ARCH_LEVEL == 7 + /* low exception vectors */ + bic r0, r0, #(1<<13) #endif mcr p15, 0, r0, c1, c0, 0 #endif From d54159de220c5818979e51fa353cfb0bc1045c80 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Sat, 18 Oct 2014 11:58:23 +0800 Subject: [PATCH 25/43] [arch][arm] make WITH_KERNEL_VM selectable and turn on WITH_KERNEL_VM by default Change-Id: I64e8f157e8fda223bc25de4735828b37e3a88151 Signed-off-by: Xiang Xiao --- arch/arm/rules.mk | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/arm/rules.mk b/arch/arm/rules.mk index a4119b3a8..25d4b53d7 100644 --- a/arch/arm/rules.mk +++ b/arch/arm/rules.mk @@ -55,7 +55,6 @@ endif ifeq ($(ARM_CPU),cortex-a8) GLOBAL_DEFINES += \ ARM_WITH_CP15=1 \ - ARM_WITH_MMU=1 \ ARM_ISA_ARMv7=1 \ ARM_ISA_ARMv7A=1 \ ARM_WITH_VFP=1 \ @@ -71,7 +70,6 @@ endif ifeq ($(ARM_CPU),cortex-a9) GLOBAL_DEFINES += \ ARM_WITH_CP15=1 \ - ARM_WITH_MMU=1 \ ARM_ISA_ARMv7=1 \ ARM_ISA_ARMv7A=1 \ ARM_WITH_THUMB=1 \ @@ -84,7 +82,6 @@ ifeq ($(ARM_CPU),cortex-a9-neon) GLOBAL_DEFINES += \ ARM_CPU_CORTEX_A9=1 \ ARM_WITH_CP15=1 \ - ARM_WITH_MMU=1 \ ARM_ISA_ARMv7=1 \ ARM_ISA_ARMv7A=1 \ ARM_WITH_VFP=1 \ @@ -101,7 +98,6 @@ endif ifeq ($(ARM_CPU),arm1136j-s) GLOBAL_DEFINES += \ ARM_WITH_CP15=1 \ - ARM_WITH_MMU=1 \ ARM_ISA_ARMv6=1 \ ARM_WITH_THUMB=1 \ ARM_WITH_CACHE=1 \ @@ -112,7 +108,6 @@ endif ifeq ($(ARM_CPU),arm1176jzf-s) GLOBAL_DEFINES += \ ARM_WITH_CP15=1 \ - ARM_WITH_MMU=1 \ ARM_ISA_ARMv6=1 \ ARM_WITH_VFP=1 \ ARM_WITH_THUMB=1 \ @@ -161,12 +156,14 @@ ARCH_OPTFLAGS := -O2 WITH_LINKER_GC ?= 1 # we have a mmu and want the vmm/pmm -WITH_KERNEL_VM=1 +WITH_KERNEL_VM?=1 +ifeq ($(WITH_KERNEL_VM),1) # for arm, have the kernel occupy the entire top 3GB of virtual space, # but put the kernel itself at 0x80000000. # this leaves 0x40000000 - 0x80000000 open for kernel space to use. GLOBAL_DEFINES += \ + ARM_WITH_MMU=1 \ KERNEL_ASPACE_BASE=0x40000000 \ KERNEL_ASPACE_SIZE=0xc0000000 @@ -176,6 +173,11 @@ KERNEL_LOAD_OFFSET ?= 0 GLOBAL_DEFINES += \ KERNEL_BASE=$(KERNEL_BASE) \ KERNEL_LOAD_OFFSET=$(KERNEL_LOAD_OFFSET) +else +KERNEL_BASE ?= $(MEMBASE) +KERNEL_LOAD_OFFSET ?= 0 +endif + endif ifeq ($(SUBARCH),arm-m) MODULE_SRCS += \ From 128c5e50260a0c416475e11e6f63e6930dcdfa51 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Fri, 17 Oct 2014 17:30:23 +0800 Subject: [PATCH 26/43] [arch][arm] support compile cortex-a7 Change-Id: I6fe3a7fa5750c0d4397f4764fbd6edf4c40cd80e Signed-off-by: Xiang Xiao --- arch/arm/include/arch/defines.h | 2 ++ arch/arm/rules.mk | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/arch/arm/include/arch/defines.h b/arch/arm/include/arch/defines.h index cf5f05f04..fd8e7b4d2 100644 --- a/arch/arm/include/arch/defines.h +++ b/arch/arm/include/arch/defines.h @@ -37,6 +37,8 @@ #define CACHE_LINE 32 #elif ARM_CPU_ARM1136 #define CACHE_LINE 32 +#elif ARM_CPU_CORTEX_A7 +#define CACHE_LINE 64 #elif ARM_CPU_CORTEX_A8 #define CACHE_LINE 64 #elif ARM_CPU_CORTEX_A9 diff --git a/arch/arm/rules.mk b/arch/arm/rules.mk index 25d4b53d7..5b9bda51b 100644 --- a/arch/arm/rules.mk +++ b/arch/arm/rules.mk @@ -52,6 +52,21 @@ HANDLED_CORE := true ENABLE_THUMB := true SUBARCH := arm-m endif +ifeq ($(ARM_CPU),cortex-a7) +GLOBAL_DEFINES += \ + ARM_CPU_CORTEX_A7=1 \ + ARM_WITH_CP15=1 \ + ARM_ISA_ARMv7=1 \ + ARM_ISA_ARMv7A=1 \ + ARM_WITH_VFP=1 \ + ARM_WITH_NEON=1 \ + ARM_WITH_THUMB=1 \ + ARM_WITH_THUMB2=1 \ + ARM_WITH_CACHE=1 +GLOBAL_COMPILEFLAGS += -mcpu=cortex-a7 +HANDLED_CORE := true +GLOBAL_COMPILEFLAGS += -mfpu=neon-vfpv4 -mfloat-abi=softfp +endif ifeq ($(ARM_CPU),cortex-a8) GLOBAL_DEFINES += \ ARM_WITH_CP15=1 \ From 212f5a865308a47c153140c06610378079c45e6b Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Sun, 19 Oct 2014 22:22:58 +0800 Subject: [PATCH 27/43] [lib][heap] heap_grow reduce grow size when memory nearly exhaust Change-Id: I2421b536d11c043e9d07ef23638a02652ddda6da Signed-off-by: Xiang Xiao --- lib/heap/heap.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/heap/heap.c b/lib/heap/heap.c index 604b4f340..2f93f189b 100644 --- a/lib/heap/heap.c +++ b/lib/heap/heap.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2008-2009,2012,2014 Travis Geiselbrecht * Copyright (c) 2009 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -54,6 +55,8 @@ STATIC_ASSERT(IS_PAGE_ALIGNED(HEAP_GROW_SIZE)); +static ssize_t heap_grow(size_t len); + #elif WITH_STATIC_HEAP #if !defined(HEAP_START) || !defined(HEAP_LEN) @@ -105,8 +108,6 @@ struct alloc_struct_begin { #endif }; -static ssize_t heap_grow(size_t len); - static void dump_free_chunk(struct free_heap_chunk *chunk) { dprintf(INFO, "\t\tbase %p, end 0x%lx, len 0x%zx\n", chunk, (vaddr_t)chunk + chunk->len, chunk->len); @@ -403,9 +404,7 @@ void *heap_alloc(size_t size, unsigned int alignment) #if WITH_KERNEL_VM /* try to grow the heap if we can */ if (ptr == NULL && retry_count == 0) { - size_t growby = MAX(HEAP_GROW_SIZE, ROUNDUP(size, PAGE_SIZE)); - - ssize_t err = heap_grow(growby); + ssize_t err = heap_grow(size); if (err >= 0) { retry_count++; goto retry; @@ -501,33 +500,34 @@ void heap_get_stats(struct heap_stats *ptr) mutex_release(&theheap.lock); } +#if WITH_KERNEL_VM static ssize_t heap_grow(size_t size) { -#if WITH_KERNEL_VM size = ROUNDUP(size, PAGE_SIZE); - void *ptr = pmm_alloc_kpages(size / PAGE_SIZE, NULL); - if (!ptr) - return ERR_NO_MEMORY; + for (size_t growby = MAX(HEAP_GROW_SIZE, size); growby >= size; growby /= 2) { + void *ptr = pmm_alloc_kpages(growby / PAGE_SIZE, NULL); + if (ptr) { + LTRACEF("growing heap by 0x%zx bytes, new ptr %p\n", growby, ptr); - LTRACEF("growing heap by 0x%zx bytes, new ptr %p\n", size, ptr); + heap_insert_free_chunk(heap_create_free_chunk(ptr, growby, true)); - heap_insert_free_chunk(heap_create_free_chunk(ptr, size, true)); + /* change the heap start and end variables */ + if ((uintptr_t)ptr < (uintptr_t)theheap.base) + theheap.base = ptr; - /* change the heap start and end variables */ - if ((uintptr_t)ptr < (uintptr_t)theheap.base) - theheap.base = ptr; + uintptr_t endptr = (uintptr_t)ptr + growby; + if (endptr > (uintptr_t)theheap.base + theheap.len) { + theheap.len = (uintptr_t)endptr - (uintptr_t)theheap.base; + } - uintptr_t endptr = (uintptr_t)ptr + size; - if (endptr > (uintptr_t)theheap.base + theheap.len) { - theheap.len = (uintptr_t)endptr - (uintptr_t)theheap.base; + return growby; + } } - return size; -#else return ERR_NO_MEMORY; -#endif } +#endif void heap_init(void) { From 1a6d9d6c74c229114bd4c9ccee8c5d6c41efbf9d Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Sun, 19 Oct 2014 23:11:57 +0800 Subject: [PATCH 28/43] [lib][heap] fill the delayed free block with FREE_FILL and don't fill the alloced block from pmm_alloc_kpages Change-Id: Ic879f1e1d7159cf87b37f553e30d2c654ddcc509 Signed-off-by: Xiang Xiao --- lib/heap/heap.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/heap/heap.c b/lib/heap/heap.c index 2f93f189b..06ae5b2c5 100644 --- a/lib/heap/heap.c +++ b/lib/heap/heap.c @@ -187,8 +187,12 @@ static void heap_test(void) // try to insert this free chunk into the free list, consuming the chunk by merging it with // nearby ones if possible. Returns base of whatever chunk it became in the list. -static struct free_heap_chunk *heap_insert_free_chunk(struct free_heap_chunk *chunk) +static struct free_heap_chunk *heap_insert_free_chunk(struct free_heap_chunk *chunk, bool allow_debug) { +#if DEBUG_HEAP + if (allow_debug) + memset(chunk + 1, FREE_FILL, chunk->len - sizeof(*chunk)); +#endif #if LK_DEBUGLEVEL > INFO vaddr_t chunk_end = (vaddr_t)chunk + chunk->len; #endif @@ -249,15 +253,10 @@ static struct free_heap_chunk *heap_insert_free_chunk(struct free_heap_chunk *ch return chunk; } -static struct free_heap_chunk *heap_create_free_chunk(void *ptr, size_t len, bool allow_debug) +static struct free_heap_chunk *heap_create_free_chunk(void *ptr, size_t len) { DEBUG_ASSERT((len % sizeof(void *)) == 0); // size must be aligned on pointer boundary -#if DEBUG_HEAP - if (allow_debug) - memset(ptr, FREE_FILL, len); -#endif - struct free_heap_chunk *chunk = (struct free_heap_chunk *)ptr; chunk->len = len; @@ -280,7 +279,7 @@ static void heap_free_delayed_list(void) while ((chunk = list_remove_head_type(&list, struct free_heap_chunk, node))) { LTRACEF("freeing chunk %p\n", chunk); - heap_insert_free_chunk(chunk); + heap_insert_free_chunk(chunk, true); } } @@ -348,7 +347,7 @@ void *heap_alloc(size_t size, unsigned int alignment) if (chunk->len > size + sizeof(struct free_heap_chunk)) { // there's enough space in this chunk to create a new one after the allocation - struct free_heap_chunk *newchunk = heap_create_free_chunk((uint8_t *)ptr + size, chunk->len - size, true); + struct free_heap_chunk *newchunk = heap_create_free_chunk((uint8_t *)ptr + size, chunk->len - size); // truncate this chunk chunk->len -= chunk->len - size; @@ -448,7 +447,7 @@ void heap_free(void *ptr) LTRACEF("allocation was %zd bytes long at ptr %p\n", as->size, as->ptr); // looks good, create a free chunk and add it to the pool - heap_insert_free_chunk(heap_create_free_chunk(as->ptr, as->size, true)); + heap_insert_free_chunk(heap_create_free_chunk(as->ptr, as->size), true); } void heap_delayed_free(void *ptr) @@ -461,7 +460,7 @@ void heap_delayed_free(void *ptr) DEBUG_ASSERT(as->magic == HEAP_MAGIC); - struct free_heap_chunk *chunk = heap_create_free_chunk(as->ptr, as->size, false); + struct free_heap_chunk *chunk = heap_create_free_chunk(as->ptr, as->size); enter_critical_section(); list_add_head(&theheap.delayed_free_list, &chunk->node); @@ -510,7 +509,7 @@ static ssize_t heap_grow(size_t size) if (ptr) { LTRACEF("growing heap by 0x%zx bytes, new ptr %p\n", growby, ptr); - heap_insert_free_chunk(heap_create_free_chunk(ptr, growby, true)); + heap_insert_free_chunk(heap_create_free_chunk(ptr, growby), false); /* change the heap start and end variables */ if ((uintptr_t)ptr < (uintptr_t)theheap.base) @@ -559,13 +558,13 @@ void heap_init(void) LTRACEF("base %p size %zd bytes\n", theheap.base, theheap.len); // create an initial free chunk - heap_insert_free_chunk(heap_create_free_chunk(theheap.base, theheap.len, false)); + heap_insert_free_chunk(heap_create_free_chunk(theheap.base, theheap.len), false); } /* add a new block of memory to the heap */ void heap_add_block(void *ptr, size_t len) { - heap_insert_free_chunk(heap_create_free_chunk(ptr, len, false)); + heap_insert_free_chunk(heap_create_free_chunk(ptr, len), false); } #if LK_DEBUGLEVEL > 1 From a8c679f48cffc501c729aea727966c7ccd8f95f4 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Mon, 20 Oct 2014 02:03:04 +0800 Subject: [PATCH 29/43] [lib][heap] make the heap usable as soon as possible now the heap could be used even in the early init phase and replace boot allocator with the heap Change-Id: If9af3912b8685498218dc23ac899758f43f787fa Signed-off-by: Xiang Xiao --- include/kernel/vm.h | 4 +++ include/lk/init.h | 8 +++--- kernel/vm/bootalloc.c | 52 ------------------------------------ kernel/vm/pmm.c | 6 ++--- kernel/vm/rules.mk | 1 - kernel/vm/vm.c | 22 +++------------- kernel/vm/vm_priv.h | 6 +---- lib/heap/heap.c | 61 +++++++++++++++++++++++++++++++------------ top/main.c | 10 +++---- 9 files changed, 65 insertions(+), 105 deletions(-) delete mode 100644 kernel/vm/bootalloc.c diff --git a/include/kernel/vm.h b/include/kernel/vm.h index 75be15cdf..703a8605b 100644 --- a/include/kernel/vm.h +++ b/include/kernel/vm.h @@ -137,6 +137,10 @@ void *pmm_alloc_kpages(uint count, struct list_node *list); /* Helper routine for pmm_alloc_kpages. */ static inline void *pmm_alloc_kpage(void) { return pmm_alloc_kpages(1, NULL); } + /* mark the physical pages backing a range of virtual as in use. + * allocate the physical pages and throw them away */ +void mark_pages_in_use(vaddr_t va, size_t len); + /* physical <==> virtual */ #if WITH_KERNEL_VM void *paddr_to_kvaddr(paddr_t pa); diff --git a/include/lk/init.h b/include/lk/init.h index a0ca318e4..8ed4be3ea 100644 --- a/include/lk/init.h +++ b/include/lk/init.h @@ -14,10 +14,10 @@ typedef void (*lk_init_hook)(uint level); enum lk_init_level { LK_INIT_LEVEL_EARLIEST = 1, - LK_INIT_LEVEL_ARCH_EARLY = 0x10000, - LK_INIT_LEVEL_PLATFORM_EARLY = 0x20000, - LK_INIT_LEVEL_TARGET_EARLY = 0x30000, - LK_INIT_LEVEL_HEAP = 0x40000, + LK_INIT_LEVEL_HEAP = 0x10000, + LK_INIT_LEVEL_ARCH_EARLY = 0x20000, + LK_INIT_LEVEL_PLATFORM_EARLY = 0x30000, + LK_INIT_LEVEL_TARGET_EARLY = 0x40000, LK_INIT_LEVEL_VM = 0x50000, LK_INIT_LEVEL_KERNEL = 0x60000, LK_INIT_LEVEL_THREADING = 0x70000, diff --git a/kernel/vm/bootalloc.c b/kernel/vm/bootalloc.c deleted file mode 100644 index 8847bcabb..000000000 --- a/kernel/vm/bootalloc.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2014 Travis Geiselbrecht - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include -#include "vm_priv.h" - -#include -#include -#include -#include - -#define LOCAL_TRACE 0 - -/* cheezy allocator that chews up space just after the end of the kernel mapping */ - -/* track how much memory we've used */ -extern int _end; - -uintptr_t boot_alloc_start = (uintptr_t)&_end; -uintptr_t boot_alloc_end = (uintptr_t)&_end; - -void *boot_alloc_mem(size_t len) -{ - uintptr_t ptr; - - ptr = ALIGN(boot_alloc_end, 8); - boot_alloc_end = (ptr + ALIGN(len, 8)); - - LTRACEF("len %zu, ptr %p\n", len, (void *)ptr); - - return (void *)ptr; -} - diff --git a/kernel/vm/pmm.c b/kernel/vm/pmm.c index a5815d976..617490fd6 100644 --- a/kernel/vm/pmm.c +++ b/kernel/vm/pmm.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -102,10 +103,7 @@ status_t pmm_add_arena(pmm_arena_t *arena) /* allocate an array of pages to back this one */ size_t page_count = arena->size / PAGE_SIZE; - arena->page_array = boot_alloc_mem(page_count * sizeof(vm_page_t)); - - /* initialize all of the pages */ - memset(arena->page_array, 0, page_count * sizeof(vm_page_t)); + arena->page_array = calloc(page_count, sizeof(vm_page_t)); /* add them to the free list */ for (size_t i = 0; i < page_count; i++) { diff --git a/kernel/vm/rules.mk b/kernel/vm/rules.mk index d511c1ccd..d71fb6219 100644 --- a/kernel/vm/rules.mk +++ b/kernel/vm/rules.mk @@ -3,7 +3,6 @@ LOCAL_DIR := $(GET_LOCAL_DIR) MODULE := $(LOCAL_DIR) MODULE_SRCS += \ - $(LOCAL_DIR)/bootalloc.c \ $(LOCAL_DIR)/pmm.c \ $(LOCAL_DIR)/vm.c \ $(LOCAL_DIR)/vmm.c \ diff --git a/kernel/vm/vm.c b/kernel/vm/vm.c index c20b96b5c..4635c60e5 100644 --- a/kernel/vm/vm.c +++ b/kernel/vm/vm.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -35,9 +36,7 @@ extern int _start; extern int _end; -/* mark the physical pages backing a range of virtual as in use. - * allocate the physical pages and throw them away */ -static void mark_pages_in_use(vaddr_t va, size_t len) +void mark_pages_in_use(vaddr_t va, size_t len) { LTRACEF("va 0x%lx, len 0x%zx\n", va, len); @@ -64,7 +63,7 @@ static void mark_pages_in_use(vaddr_t va, size_t len) } } -static void vm_init_preheap(uint level) +static void vm_init(uint level) { LTRACE_ENTRY; @@ -72,18 +71,6 @@ static void vm_init_preheap(uint level) LTRACEF("marking all kernel pages as used\n"); mark_pages_in_use((vaddr_t)&_start, ((uintptr_t)&_end - (uintptr_t)&_start)); - /* mark the physical pages used by the boot time allocator */ - if (boot_alloc_end != boot_alloc_start) { - LTRACEF("marking boot alloc used from 0x%lx to 0x%lx\n", boot_alloc_start, boot_alloc_end); - - mark_pages_in_use(boot_alloc_start, boot_alloc_end - boot_alloc_start); - } -} - -static void vm_init_postheap(uint level) -{ - LTRACE_ENTRY; - vmm_init(); /* create vmm regions to cover what is already there from the initial mapping table */ @@ -174,6 +161,5 @@ STATIC_COMMAND("vm", "vm commands", &cmd_vm) #endif STATIC_COMMAND_END(vm); -LK_INIT_HOOK(vm_preheap, &vm_init_preheap, LK_INIT_LEVEL_HEAP - 1); -LK_INIT_HOOK(vm, &vm_init_postheap, LK_INIT_LEVEL_VM); +LK_INIT_HOOK(vm, &vm_init, LK_INIT_LEVEL_VM); diff --git a/kernel/vm/vm_priv.h b/kernel/vm/vm_priv.h index 939a5bf48..78d0fcdc8 100644 --- a/kernel/vm/vm_priv.h +++ b/kernel/vm/vm_priv.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -26,11 +27,6 @@ #include #include -/* simple boot time allocator */ -void *boot_alloc_mem(size_t len) __MALLOC; -extern uintptr_t boot_alloc_start; -extern uintptr_t boot_alloc_end; - paddr_t page_to_address(const vm_page_t *page); vm_page_t *address_to_page(paddr_t addr); diff --git a/lib/heap/heap.c b/lib/heap/heap.c index 06ae5b2c5..5a5207c19 100644 --- a/lib/heap/heap.c +++ b/lib/heap/heap.c @@ -34,6 +34,7 @@ #include #include #include +#include #define LOCAL_TRACE 0 @@ -45,6 +46,17 @@ #define HEAP_MAGIC 'HEAP' +#if WITH_STATIC_HEAP + +/* WITH_STATIC_HEAP can't work with WITH_KERNEL_VM */ +STATIC_ASSERT(!WITH_KERNEL_VM); + +#if !defined(HEAP_START) || !defined(HEAP_LEN) +#error WITH_STATIC_HEAP set but no HEAP_START or HEAP_LEN defined +#endif + +#else + #if WITH_KERNEL_VM #include @@ -57,14 +69,9 @@ STATIC_ASSERT(IS_PAGE_ALIGNED(HEAP_GROW_SIZE)); static ssize_t heap_grow(size_t len); -#elif WITH_STATIC_HEAP - -#if !defined(HEAP_START) || !defined(HEAP_LEN) -#error WITH_STATIC_HEAP set but no HEAP_START or HEAP_LEN defined #endif -#else -/* not a static vm, not using the kernel vm */ +/* not a static vm */ extern int _end; extern int _end_of_ram; @@ -85,6 +92,7 @@ struct free_heap_chunk { struct heap { void *base; size_t len; + bool postvm; size_t remaining; size_t low_watermark; mutex_t lock; @@ -326,7 +334,7 @@ void *heap_alloc(size_t size, unsigned int alignment) } #if WITH_KERNEL_VM - int retry_count = 0; + int retry_count = !theheap.postvm; retry: #endif mutex_acquire(&theheap.lock); @@ -526,6 +534,36 @@ static ssize_t heap_grow(size_t size) return ERR_NO_MEMORY; } + +static void heap_init_postvm(uint level) +{ + LTRACE_ENTRY; + + // flush the delayed free list + if (unlikely(!list_is_empty(&theheap.delayed_free_list))) { + heap_free_delayed_list(); + } + + // mark the alloced memory from vm + vaddr_t alloced = HEAP_START; + struct free_heap_chunk *chunk; + list_for_every_entry(&theheap.free_list, chunk, struct free_heap_chunk, node) { + vaddr_t freed = (vaddr_t)chunk; + if (alloced < freed) { + mark_pages_in_use(alloced, freed - alloced); + } + alloced = freed + chunk->len; + } + if (alloced < HEAP_START + HEAP_LEN) { + mark_pages_in_use(alloced, HEAP_START + HEAP_LEN - alloced); + } + + // switch to vm by emptying the free list + list_initialize(&theheap.free_list); + theheap.postvm = true; +} + +LK_INIT_HOOK(heap, &heap_init_postvm, LK_INIT_LEVEL_VM + 1); #endif void heap_init(void) @@ -542,17 +580,8 @@ void heap_init(void) list_initialize(&theheap.delayed_free_list); // set the heap range -#if WITH_KERNEL_VM - theheap.base = pmm_alloc_kpages(HEAP_GROW_SIZE / PAGE_SIZE, NULL); - theheap.len = HEAP_GROW_SIZE; - - if (theheap.base == 0) { - panic("HEAP: error allocating initial heap size\n"); - } -#else theheap.base = (void *)HEAP_START; theheap.len = HEAP_LEN; -#endif theheap.remaining = 0; // will get set by heap_insert_free_chunk() theheap.low_watermark = theheap.len; LTRACEF("base %p size %zd bytes\n", theheap.base, theheap.len); diff --git a/top/main.c b/top/main.c index 3ecb2470c..fa50f3f76 100644 --- a/top/main.c +++ b/top/main.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -69,6 +70,10 @@ void lk_main(void) // get us into some sort of thread context thread_init_early(); + // bring up the kernel heap + lk_init_level(LK_INIT_LEVEL_HEAP - 1); + heap_init(); + // early arch stuff lk_init_level(LK_INIT_LEVEL_ARCH_EARLY - 1); arch_early_init(); @@ -87,11 +92,6 @@ void lk_main(void) dprintf(SPEW, "calling constructors\n"); call_constructors(); - // bring up the kernel heap - dprintf(SPEW, "initializing heap\n"); - lk_init_level(LK_INIT_LEVEL_HEAP - 1); - heap_init(); - // initialize the kernel lk_init_level(LK_INIT_LEVEL_KERNEL - 1); kernel_init(); From 6dd14323972249f13d6bfd3ea91fadf28cb3ef23 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Tue, 21 Oct 2014 21:19:12 +0800 Subject: [PATCH 30/43] [arch][arm] ARM_CPU support cortex-a7-neon and cortex-a8-neon so the platform could decide whether enable vfp/neon per needed Change-Id: Ia922efaae556e95701383a1c4184a69e4891eddc Signed-off-by: Xiang Xiao --- arch/arm/rules.mk | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm/rules.mk b/arch/arm/rules.mk index 5b9bda51b..888d9894c 100644 --- a/arch/arm/rules.mk +++ b/arch/arm/rules.mk @@ -53,6 +53,18 @@ ENABLE_THUMB := true SUBARCH := arm-m endif ifeq ($(ARM_CPU),cortex-a7) +GLOBAL_DEFINES += \ + ARM_CPU_CORTEX_A7=1 \ + ARM_WITH_CP15=1 \ + ARM_ISA_ARMv7=1 \ + ARM_ISA_ARMv7A=1 \ + ARM_WITH_THUMB=1 \ + ARM_WITH_THUMB2=1 \ + ARM_WITH_CACHE=1 +GLOBAL_COMPILEFLAGS += -mcpu=cortex-a7 +HANDLED_CORE := true +endif +ifeq ($(ARM_CPU),cortex-a7-neon) GLOBAL_DEFINES += \ ARM_CPU_CORTEX_A7=1 \ ARM_WITH_CP15=1 \ @@ -68,6 +80,18 @@ HANDLED_CORE := true GLOBAL_COMPILEFLAGS += -mfpu=neon-vfpv4 -mfloat-abi=softfp endif ifeq ($(ARM_CPU),cortex-a8) +GLOBAL_DEFINES += \ + ARM_WITH_CP15=1 \ + ARM_ISA_ARMv7=1 \ + ARM_ISA_ARMv7A=1 \ + ARM_WITH_THUMB=1 \ + ARM_WITH_THUMB2=1 \ + ARM_WITH_CACHE=1 \ + ARM_WITH_L2=1 +GLOBAL_COMPILEFLAGS += -mcpu=$(ARM_CPU) +HANDLED_CORE := true +endif +ifeq ($(ARM_CPU),cortex-a8-neon) GLOBAL_DEFINES += \ ARM_WITH_CP15=1 \ ARM_ISA_ARMv7=1 \ From 7940351df498287d5bbd8dc8e4620ac8419cbe94 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Mon, 20 Oct 2014 13:27:52 +0800 Subject: [PATCH 31/43] [dev] define device_class for each class to standardize the class name Change-Id: I742090d06a999b3b851f8b1a76d1599c45657f91 Signed-off-by: Xiang Xiao --- dev/class/block_api.c | 5 +++++ dev/class/fb_api.c | 5 +++++ dev/class/i2c_api.c | 5 +++++ dev/class/netif_api.c | 5 +++++ dev/class/spi_api.c | 5 +++++ dev/class/uart_api.c | 5 +++++ include/dev/class/block.h | 3 +++ include/dev/class/fb.h | 3 +++ include/dev/class/i2c.h | 3 +++ include/dev/class/netif.h | 3 +++ include/dev/class/spi.h | 3 +++ include/dev/class/uart.h | 2 ++ platform/pc/ide.c | 2 ++ platform/pc/pcnet.c | 2 ++ platform/pc/uart.c | 7 ++----- 15 files changed, 53 insertions(+), 5 deletions(-) diff --git a/dev/class/block_api.c b/dev/class/block_api.c index 014eaba9d..92a34aee9 100644 --- a/dev/class/block_api.c +++ b/dev/class/block_api.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -24,6 +25,10 @@ #include #include +struct device_class class_block = { + .name = "block", +}; + ssize_t class_block_get_size(struct device *dev) { struct block_ops *ops = device_get_driver_ops(dev, struct block_ops, std); diff --git a/dev/class/fb_api.c b/dev/class/fb_api.c index 314442ef9..12e731825 100644 --- a/dev/class/fb_api.c +++ b/dev/class/fb_api.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -24,6 +25,10 @@ #include #include +struct device_class class_fb = { + .name = "fb", +}; + status_t class_fb_set_mode(struct device *dev, size_t width, size_t height, size_t bpp) { struct fb_ops *ops = device_get_driver_ops(dev, struct fb_ops, std); diff --git a/dev/class/i2c_api.c b/dev/class/i2c_api.c index 60e2a8a86..2b0e921c5 100644 --- a/dev/class/i2c_api.c +++ b/dev/class/i2c_api.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -24,6 +25,10 @@ #include #include +struct device_class class_i2c = { + .name = "i2c", +}; + status_t class_i2c_write(struct device *dev, uint8_t addr, const void *buf, size_t len) { struct i2c_ops *ops = device_get_driver_ops(dev, struct i2c_ops, std); diff --git a/dev/class/netif_api.c b/dev/class/netif_api.c index 87d617b0d..41e536ba1 100644 --- a/dev/class/netif_api.c +++ b/dev/class/netif_api.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -24,6 +25,10 @@ #include #include +struct device_class class_netif = { + .name = "netif", +}; + status_t class_netif_set_state(struct device *dev, struct netstack_state *state) { struct netif_ops *ops = device_get_driver_ops(dev, struct netif_ops, std); diff --git a/dev/class/spi_api.c b/dev/class/spi_api.c index 9453dc383..6ab442363 100644 --- a/dev/class/spi_api.c +++ b/dev/class/spi_api.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -24,6 +25,10 @@ #include #include +struct device_class class_spi = { + .name = "spi", +}; + ssize_t class_spi_transaction(struct device *dev, struct spi_transaction *txn, size_t count) { struct spi_ops *ops = device_get_driver_ops(dev, struct spi_ops, std); diff --git a/dev/class/uart_api.c b/dev/class/uart_api.c index 31e2c9daa..9bc0e0169 100644 --- a/dev/class/uart_api.c +++ b/dev/class/uart_api.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -24,6 +25,10 @@ #include #include +struct device_class class_uart = { + .name = "uart", +}; + ssize_t class_uart_read(struct device *dev, void *buf, size_t len) { struct uart_ops *ops = device_get_driver_ops(dev, struct uart_ops, std); diff --git a/include/dev/class/block.h b/include/dev/class/block.h index 240699d89..3d9ba2aae 100644 --- a/include/dev/class/block.h +++ b/include/dev/class/block.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -41,6 +42,8 @@ struct block_ops { __BEGIN_CDECLS +extern struct device_class class_block; + ssize_t class_block_get_size(struct device *dev); ssize_t class_block_get_count(struct device *dev); ssize_t class_block_write(struct device *dev, off_t offset, const void *buf, size_t count); diff --git a/include/dev/class/fb.h b/include/dev/class/fb.h index e29b266ee..4ee481bae 100644 --- a/include/dev/class/fb.h +++ b/include/dev/class/fb.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -46,6 +47,8 @@ struct fb_ops { __BEGIN_CDECLS +extern struct device_class class_fb; + status_t class_fb_set_mode(struct device *dev, size_t width, size_t height, size_t bpp); status_t class_fb_get_info(struct device *dev, struct fb_info *info); status_t class_fb_update(struct device *dev); diff --git a/include/dev/class/i2c.h b/include/dev/class/i2c.h index d38fbcb18..1ed2630e8 100644 --- a/include/dev/class/i2c.h +++ b/include/dev/class/i2c.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -39,6 +40,8 @@ struct i2c_ops { __BEGIN_CDECLS +extern struct device_class class_i2c; + status_t class_i2c_write(struct device *dev, uint8_t addr, const void *buf, size_t len); status_t class_i2c_read(struct device *dev, uint8_t addr, void *buf, size_t len); status_t class_i2c_write_reg(struct device *dev, uint8_t addr, uint8_t reg, uint8_t value); diff --git a/include/dev/class/netif.h b/include/dev/class/netif.h index 099b40cfb..1a8210945 100644 --- a/include/dev/class/netif.h +++ b/include/dev/class/netif.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -45,6 +46,8 @@ struct netif_ops { __BEGIN_CDECLS +extern struct device_class class_netif; + /* netif API */ status_t class_netif_set_state(struct device *dev, struct netstack_state *state); ssize_t class_netif_get_hwaddr(struct device *dev, void *buf, size_t max_len); diff --git a/include/dev/class/spi.h b/include/dev/class/spi.h index dad895942..fc27eeab4 100644 --- a/include/dev/class/spi.h +++ b/include/dev/class/spi.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -51,6 +52,8 @@ struct spi_ops { __BEGIN_CDECLS +extern struct device_class class_spi; + ssize_t class_spi_transaction(struct device *dev, struct spi_transaction *txn, size_t count); __END_CDECLS diff --git a/include/dev/class/uart.h b/include/dev/class/uart.h index aabf101fc..f9eb1a9c6 100644 --- a/include/dev/class/uart.h +++ b/include/dev/class/uart.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -33,6 +34,7 @@ struct uart_ops { ssize_t (*write)(struct device *dev, const void *buf, size_t len); }; +extern struct device_class class_uart; ssize_t class_uart_read(struct device *dev, void *buf, size_t len); ssize_t class_uart_write(struct device *dev, const void *buf, size_t len); diff --git a/platform/pc/ide.c b/platform/pc/ide.c index f973371bf..1378818da 100644 --- a/platform/pc/ide.c +++ b/platform/pc/ide.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -177,6 +178,7 @@ static ssize_t ide_read(struct device *dev, off_t offset, void *buf, size_t coun static struct block_ops the_ops = { .std = { + .device_class = &class_block, .init = ide_init, }, .get_block_size = ide_get_block_size, diff --git a/platform/pc/pcnet.c b/platform/pc/pcnet.c index 3d373336f..911b6408a 100644 --- a/platform/pc/pcnet.c +++ b/platform/pc/pcnet.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -99,6 +100,7 @@ static status_t pcnet_output(struct device *dev, struct pbuf *p); static struct netif_ops pcnet_ops = { .std = { + .device_class = &class_netif, .init = pcnet_init, }, diff --git a/platform/pc/uart.c b/platform/pc/uart.c index 268c9a457..07e09c5ee 100644 --- a/platform/pc/uart.c +++ b/platform/pc/uart.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -33,10 +34,6 @@ #include #include -struct device_class uart_device_class = { - .name = "uart", -}; - struct uart_driver_state { struct cbuf rx_buf; struct cbuf tx_buf; @@ -52,7 +49,7 @@ static ssize_t uart_write(struct device *dev, const void *buf, size_t len); static struct uart_ops the_ops = { .std = { - .device_class = &uart_device_class, + .device_class = &class_uart, .init = uart_init, }, .read = uart_read, From 4a1420cba5e0feb0679d9f86de41f4f836360831 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Tue, 21 Oct 2014 11:14:37 +0800 Subject: [PATCH 32/43] [dev] device driver support the init order Change-Id: I2147b841a5d0671c74224bad70a3c80eb563cb73 Signed-off-by: Xiang Xiao --- dev/driver.c | 97 ++++++++++++++++++++++++++++++++++++------ include/dev/driver.h | 5 ++- target/pc-x86/config.c | 7 +-- 3 files changed, 92 insertions(+), 17 deletions(-) diff --git a/dev/driver.c b/dev/driver.c index 4b31ac1fd..3a1ee96eb 100644 --- a/dev/driver.c +++ b/dev/driver.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -29,48 +30,118 @@ extern struct device __devices[]; extern struct device __devices_end[]; -status_t device_init_all(void) +static int device_get_next_order(int order) +{ + int next = INT_MAX; + + struct device *dev = __devices; + while (dev != __devices_end) { + if (dev->order > order && dev->order < next) { + next = dev->order; + } + dev++; + } + + return next; +} + +static status_t device_init_order(int order) { status_t res = NO_ERROR; struct device *dev = __devices; while (dev != __devices_end) { - status_t code = device_init(dev); + if (dev->order == order) { + status_t code = device_init(dev); - if (code < 0) { - TRACEF("Driver init failed for driver \"%s\", device \"%s\", reason %d\n", - dev->driver->type, dev->name, code); + if (code < 0) { + TRACEF("Driver init failed for driver \"%s\", device \"%s\", reason %d\n", + dev->driver->type, dev->name, code); + + res = code; + } + } + dev++; + } + return res; +} + +status_t device_init_all(void) +{ + status_t res = NO_ERROR; + int order = INT_MIN; + + while (true) { + order = device_get_next_order(order); + if (order == INT_MAX) { + break; + } + status_t code = device_init_order(order); + if (code < 0) { res = code; } + } + return res; +} + +static int device_get_prev_order(int order) +{ + int prev = INT_MIN; + + struct device *dev = __devices; + while (dev != __devices_end) { + if (dev->order < order && dev->order > prev) { + prev = dev->order; + } dev++; } - return res; + return prev; } -status_t device_fini_all(void) +status_t device_fini_order(int order) { status_t res = NO_ERROR; struct device *dev = __devices; while (dev != __devices_end) { - status_t code = device_fini(dev); + if (dev->order == order) { + status_t code = device_fini(dev); - if (code < 0) { - TRACEF("Driver fini failed for driver \"%s\", device \"%s\", reason %d\n", - dev->driver->type, dev->name, code); + if (code < 0) { + TRACEF("Driver fini failed for driver \"%s\", device \"%s\", reason %d\n", + dev->driver->type, dev->name, code); - res = code; + res = code; + } } - dev++; } return res; } +status_t device_fini_all(void) +{ + status_t res = NO_ERROR; + int order = INT_MAX; + + while (true) { + order = device_get_prev_order(order); + if (order == INT_MIN) { + break; + } + status_t code = device_fini_order(order); + if (code < 0) { + res = code; + } + } + + return res; +} + status_t device_init(struct device *dev) { if (!dev) diff --git a/include/dev/driver.h b/include/dev/driver.h index 790317b5c..754d2f31a 100644 --- a/include/dev/driver.h +++ b/include/dev/driver.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2012 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -44,6 +45,7 @@ struct device { void *state; // TODO: add generic state, such as suspend/resume state, etc... + int order; }; /* device class, mainly used as a unique magic pointer to validate ops */ @@ -75,13 +77,14 @@ struct driver { .ops = ops_, \ } -#define DEVICE_INSTANCE(type_, name_, config_) \ +#define DEVICE_INSTANCE(type_, name_, config_, order_) \ extern struct driver concat(__driver_, type_); \ struct device concat(__device_, concat(type_, concat(_, name_))) \ __SECTION(".devices") = { \ .name = #name_, \ .driver = &concat(__driver_, type_), \ .config = config_, \ + .order = order_, \ } /* diff --git a/target/pc-x86/config.c b/target/pc-x86/config.c index d2126cda8..0c181a836 100644 --- a/target/pc-x86/config.c +++ b/target/pc-x86/config.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -48,13 +49,13 @@ static const struct platform_uart_config uart0_config = { .tx_buf_len = 1024, }; -DEVICE_INSTANCE(uart, uart0, &uart0_config); +DEVICE_INSTANCE(uart, uart0, &uart0_config, 0); #ifndef ARCH_X86_64 static const struct platform_ide_config ide0_config = { }; -DEVICE_INSTANCE(ide, ide0, &ide0_config); +DEVICE_INSTANCE(ide, ide0, &ide0_config, 0); static const struct platform_pcnet_config pcnet0_config = { .vendor_id = 0x1022, @@ -62,7 +63,7 @@ static const struct platform_pcnet_config pcnet0_config = { .index = 0, }; -DEVICE_INSTANCE(netif, pcnet0, &pcnet0_config); +DEVICE_INSTANCE(netif, pcnet0, &pcnet0_config, 0); #endif void target_init(void) { From 32c61d5b8e376204c2aa71547377538a15bd5eb2 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Tue, 21 Oct 2014 11:26:35 +0800 Subject: [PATCH 33/43] [dev] add device_find for dynamic device search which is companion with device_get_by_name(compile time) Change-Id: I0d642caf4d5c3958cf189cb4da6b1eb1076208af Signed-off-by: Xiang Xiao --- dev/driver.c | 12 ++++++++++++ include/dev/driver.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/dev/driver.c b/dev/driver.c index 3a1ee96eb..30a1f1091 100644 --- a/dev/driver.c +++ b/dev/driver.c @@ -25,6 +25,7 @@ #include #include #include +#include #include extern struct device __devices[]; @@ -202,3 +203,14 @@ status_t device_resume(struct device *dev) return ERR_NOT_SUPPORTED; } +struct device *device_find(const char *name) +{ + struct device *dev = __devices; + while (dev != __devices_end) { + if (!strcmp(dev->name, name)) { + return dev; + } + } + + return NULL; +} diff --git a/include/dev/driver.h b/include/dev/driver.h index 754d2f31a..7932ab54b 100644 --- a/include/dev/driver.h +++ b/include/dev/driver.h @@ -112,5 +112,7 @@ status_t device_fini(struct device *dev); status_t device_suspend(struct device *dev); status_t device_resume(struct device *dev); +struct device *device_find(const char *name); + #endif From eff3731cfefeb59664253e8f72831858087a04e9 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Tue, 21 Oct 2014 15:21:44 +0800 Subject: [PATCH 34/43] [dev] add the generic 16550 uart driver Change-Id: I5449ecccea9c344d9d9dd9c74c32495c460780a9 Signed-off-by: Xiang Xiao --- dev/uart/16550/16550.c | 380 ++++++++++++++++++++++++ dev/uart/16550/include/dev/uart/16550.h | 43 +++ dev/uart/16550/rules.mk | 14 + 3 files changed, 437 insertions(+) create mode 100644 dev/uart/16550/16550.c create mode 100644 dev/uart/16550/include/dev/uart/16550.h create mode 100644 dev/uart/16550/rules.mk diff --git a/dev/uart/16550/16550.c b/dev/uart/16550/16550.c new file mode 100644 index 000000000..7b6d60ccf --- /dev/null +++ b/dev/uart/16550/16550.c @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2012 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define UART_RBR 0 +#define UART_THR 0 +#define UART_IER 1 +#define UART_IIR 2 +#define UART_FCR 2 +#define UART_LCR 3 +#define UART_MCR 4 +#define UART_LSR 5 +#define UART_MSR 6 +#define UART_SCR 7 +#define UART_DLL 0 +#define UART_DLM 1 + +#define UART_IER_ERBFI 0x01 +#define UART_IER_ETBEI 0x02 +#define UART_IER_ELSI 0x04 +#define UART_IER_EDSSI 0x08 + +#define UART_IIR_DSSI 0x00 +#define UART_IIR_NONE 0x01 +#define UART_IIR_TBEI 0x02 +#define UART_IIR_RBFI 0x04 +#define UART_IIR_LSI 0x06 +#define UART_IIR_TIMEOUT 0x0C +#define UART_IIR_MASK 0x0F + +#define UART_FCR_FIFO_ENABLE 0x01 +#define UART_FCR_RCVR_RESET 0x02 +#define UART_FCR_XMIT_RESET 0x04 +#define UART_FCR_DMA_SELECT 0x08 +#define UART_FCR_RCVR_TRIG1 0x00 +#define UART_FCR_RCVR_TRIG4 0x40 +#define UART_FCR_RCVR_TRIG8 0x80 +#define UART_FCR_RCVR_TRIG14 0xC0 + +#define UART_LCR_WLEN5 0x00 +#define UART_LCR_WLEN6 0x01 +#define UART_LCR_WLEN7 0x02 +#define UART_LCR_WLEN8 0x03 +#define UART_LCR_STOP 0x04 +#define UART_LCR_PARITY 0x08 +#define UART_LCR_EVEN 0x10 +#define UART_LCR_STICK 0x20 +#define UART_LCR_BREAK 0x40 +#define UART_LCR_DLAB 0x80 + +#define UART_MCR_DTR 0x01 +#define UART_MCR_RTS 0x02 +#define UART_MCR_OUT1 0x04 +#define UART_MCR_OUT2 0x08 +#define UART_MCR_LOOP 0x10 +#define UART_MCR_AFE 0x20 + +#define UART_LSR_DR 0x01 +#define UART_LSR_OE 0x02 +#define UART_LSR_PE 0x04 +#define UART_LSR_FE 0x08 +#define UART_LSR_BI 0x10 +#define UART_LSR_THRE 0x20 +#define UART_LSR_TEMT 0x40 +#define UART_LSR_FIFOE 0x80 + +#define UART_RXBUF_SIZE 32 + +struct uart_state { + struct cbuf rxbuf; +}; + +// internal function +static uint8_t uart_get(struct device *dev, off_t offset) +{ + const struct uart_16550_config* config = dev->config; + uintptr_t addr = config->base + offset * config->stride; + + switch (config->unit) { + case 1: +#ifdef UART_16550_IOPORT + return inp(addr); +#else + return readb(addr); +#endif + case 2: +#ifdef UART_16550_IOPORT + return inpw(addr); +#else + return readw(addr); +#endif + case 4: +#ifdef UART_16550_IOPORT + return inpd(addr); +#else + return readl(addr); +#endif + default: + return 0; + } +} + +static void uart_set(struct device *dev, off_t offset, uint8_t value) +{ + const struct uart_16550_config* config = dev->config; + uintptr_t addr = config->base + offset * config->stride; + + switch (config->unit) { + case 1: +#ifdef UART_16550_IOPORT + outp(addr, value); +#else + writeb(value, addr); +#endif + break; + case 2: +#ifdef UART_16550_IOPORT + outpw(addr, value); +#else + writew(value, addr); +#endif + break; + case 4: +#ifdef UART_16550_IOPORT + outpd(addr, value); +#else + writel(value, addr); +#endif + break; + } +} + +static void uart_set_baud(struct device *dev, unsigned baud) +{ + const struct uart_16550_config* config = dev->config; + unsigned divisor = config->clock_rate / (16 * baud); + uint8_t lcr = uart_get(dev, UART_LCR); + + uart_set(dev, UART_LCR, lcr | UART_LCR_DLAB); + uart_set(dev, UART_DLL, divisor); + uart_set(dev, UART_DLM, divisor >> 8); + uart_set(dev, UART_LCR, lcr); +} + +static void uart_init_baud(struct device *dev) +{ + const struct uart_16550_config* config = dev->config; + uart_set_baud(dev, config->baud_rate); +} + +static void uart_init_fcr(struct device *dev) +{ + uart_set(dev, UART_FCR, UART_FCR_RCVR_RESET | UART_FCR_XMIT_RESET); + uart_set(dev, UART_FCR, UART_FCR_FIFO_ENABLE); +} + +static void uart_init_lcr(struct device *dev) +{ + const struct uart_16550_config* config = dev->config; + uint8_t lcr = 0; + + switch (config->word_length) { + case 5: + lcr |= UART_LCR_WLEN5; + break; + case 6: + lcr |= UART_LCR_WLEN6; + break; + case 7: + lcr |= UART_LCR_WLEN7; + break; + case 8: + lcr |= UART_LCR_WLEN8; + break; + } + + lcr |= config->stop_bits > 1 ? UART_LCR_STOP : 0; + lcr |= config->parity_enable ? UART_LCR_PARITY : 0; + lcr |= config->even_parity ? UART_LCR_EVEN : 0; + + uart_set(dev, UART_LCR, lcr); +} + +static void uart_init_mcr(struct device *dev) +{ + const struct uart_16550_config* config = dev->config; + if (config->autoflow_enable) { + uint8_t mcr = uart_get(dev, UART_MCR); + mcr |= UART_MCR_AFE; + uart_set(dev, UART_MCR, mcr); + } +} + +static void uart_init_config(struct device *dev) +{ + uart_init_baud(dev); + uart_init_fcr(dev); + uart_init_lcr(dev); + uart_init_mcr(dev); +} + +static enum handler_return uart_irq_handler(void *arg) +{ + bool resched = false; + struct device *dev = arg; + struct uart_state *state = dev->state; + + while (uart_get(dev, UART_LSR) & UART_LSR_DR) { + uint8_t c = uart_get(dev, UART_RBR); + cbuf_write(&state->rxbuf, &c, 1, false); + resched = true; + } + + return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE; +} + +static void uart_init_irq(struct device *dev) +{ + const struct uart_16550_config* config = dev->config; + uart_set(dev, UART_IER, UART_IER_ERBFI | UART_IER_ELSI); + register_int_handler(config->irq, uart_irq_handler, dev); + unmask_interrupt(config->irq); +} + +static void uart_fini_irq(struct device *dev) +{ + const struct uart_16550_config* config = dev->config; + mask_interrupt(config->irq); + uart_set(dev, UART_IER, 0); +} + +// new uart api +static status_t uart_init(struct device *dev) +{ + if (!dev->config) { + return ERR_NOT_CONFIGURED; + } + + struct uart_state *state = malloc(sizeof(*state)); + if (!state) { + return ERR_NO_MEMORY; + } + + dev->state = state; + cbuf_initialize(&state->rxbuf, UART_RXBUF_SIZE); + + uart_init_config(dev); + uart_init_irq(dev); + + return NO_ERROR; +} + +static status_t uart_fini(struct device *dev) +{ + uart_fini_irq(dev); + free(dev->state); + dev->state = NULL; + return NO_ERROR; +} + +static ssize_t uart_read(struct device *dev, void *buf, size_t len) +{ + struct uart_state *state = dev->state; + return cbuf_read(&state->rxbuf, buf, len, true); +} + +static ssize_t uart_write(struct device *dev, const void *buf_, size_t len) +{ + const char *buf = buf_; + for (size_t i = 0; i < len; i++) { + while (!(uart_get(dev, UART_LSR) & UART_LSR_THRE)) { + ; // wait for the xmit fifo available + } + uart_set(dev, UART_THR, *buf++); + } + return len; +} + +static struct uart_ops uart_ops = { + .std = { + .device_class = &class_uart, + .init = uart_init, + .fini = uart_fini, + }, + .read = uart_read, + .write = uart_write, +}; + +DRIVER_EXPORT(uart_16550, &uart_ops.std); + +// old uart api +#ifndef UART_16550_NOOLD +static struct device *uart_find(int port) +{ + char name[16]; + sprintf(name, "uart%d", port); + return device_find(name); +} + +int uart_putc(int port, char c) +{ + int ret = ERR_INVALID_ARGS; + struct device *dev = uart_find(port); + if (dev) { + ret = uart_write(dev, &c, 1); + } + return ret; +} + +int uart_getc(int port, bool wait) +{ + int ret = ERR_INVALID_ARGS; + struct device *dev = uart_find(port); + if (dev) { + char c; + struct uart_state *state = dev->state; + if (cbuf_read_char(&state->rxbuf, &c, wait) == 1) { + ret = c; + } else { + ret = ERR_NOT_READY; + } + } + return ret; +} + +void uart_flush_tx(int port) +{ + struct device *dev = uart_find(port); + if (dev) { + while (!(uart_get(dev, UART_LSR) & UART_LSR_TEMT)) { + ; // wait for the xmit fifo empty + } + } +} + +void uart_flush_rx(int port) +{ + while (uart_getc(port, false) >= 0) { + ; // nothing to do + } +} + +void uart_init_port(int port, uint baud) +{ + struct device *dev = uart_find(port); + if (dev) { + uart_set_baud(dev, baud); + } +} +#endif + diff --git a/dev/uart/16550/include/dev/uart/16550.h b/dev/uart/16550/include/dev/uart/16550.h new file mode 100644 index 000000000..57d687595 --- /dev/null +++ b/dev/uart/16550/include/dev/uart/16550.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2012 Corey Tabaka + * Copyright (c) 2014 Xiaomi Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __DEV_UART_16550_H +#define __DEV_UART_16550_H + +struct uart_16550_config { + unsigned irq; + uintptr_t base; + size_t unit; + size_t stride; + unsigned clock_rate; + unsigned baud_rate; + size_t word_length; + size_t stop_bits; + bool parity_enable; + bool even_parity; + bool autoflow_enable; +}; + +#endif + diff --git a/dev/uart/16550/rules.mk b/dev/uart/16550/rules.mk new file mode 100644 index 000000000..834a1ba8e --- /dev/null +++ b/dev/uart/16550/rules.mk @@ -0,0 +1,14 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +GLOBAL_INCLUDES += \ + $(LOCAL_DIR)/include + +MODULE_SRCS += \ + $(LOCAL_DIR)/16550.c + +MODULE_DEPS += \ + lib/cbuf + +include make/module.mk From 6fb5802e449dbb0a09b31e6d1624b86ba2c6be85 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Wed, 22 Oct 2014 17:48:47 +0800 Subject: [PATCH 35/43] [dev][timer][arm_generic] fix fixed_point.h can't find compiler error and disable local trace Change-Id: I2b1a397481385e510b1255044686c624bec1f81e Signed-off-by: Xiang Xiao --- dev/timer/arm_generic/arm_generic_timer.c | 4 ++-- dev/timer/arm_generic/rules.mk | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/dev/timer/arm_generic/arm_generic_timer.c b/dev/timer/arm_generic/arm_generic_timer.c index ae39443c3..83d5542c4 100644 --- a/dev/timer/arm_generic/arm_generic_timer.c +++ b/dev/timer/arm_generic/arm_generic_timer.c @@ -27,11 +27,11 @@ #include #include -#define LOCAL_TRACE 1 +#define LOCAL_TRACE 0 #define LTRACEF_LEVEL(level, x...) do { if (LOCAL_TRACE >= level) { TRACEF(x); } } while (0) -#include "fixed_point.h" +#include static platform_timer_callback t_callback; diff --git a/dev/timer/arm_generic/rules.mk b/dev/timer/arm_generic/rules.mk index e847918f4..aae920c76 100644 --- a/dev/timer/arm_generic/rules.mk +++ b/dev/timer/arm_generic/rules.mk @@ -11,4 +11,7 @@ GLOBAL_DEFINES += \ MODULE_SRCS += \ $(LOCAL_DIR)/arm_generic_timer.c +MODULE_DEPS += \ + lib/fixed_point + include make/module.mk From 5b112f3e234bc36fc6aae885e8e2ae7002a18c38 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Wed, 22 Oct 2014 22:17:39 +0800 Subject: [PATCH 36/43] [dev][timer][arm_generic] add arm_generic_timer_init_freq so platform could pass in the frequency if needed Change-Id: Icbe8de0e66eeb7e884dbda3c7df343d4d1b1357c Signed-off-by: Xiang Xiao --- dev/timer/arm_generic/arm_generic_timer.c | 12 ++++++++++++ .../arm_generic/include/dev/timer/arm_generic.h | 1 + 2 files changed, 13 insertions(+) diff --git a/dev/timer/arm_generic/arm_generic_timer.c b/dev/timer/arm_generic/arm_generic_timer.c index 83d5542c4..9b4cc8d07 100644 --- a/dev/timer/arm_generic/arm_generic_timer.c +++ b/dev/timer/arm_generic/arm_generic_timer.c @@ -63,6 +63,12 @@ static uint32_t read_cntfrq(void) return cntfrq; } +static void write_cntfrq(uint32_t cntfrq) +{ + LTRACEF("cntfrq: 0x%08x, %u\n", cntfrq, cntfrq); + __asm__ volatile("mcr p15, 0, %0, c14, c0, 0" :: "r" (cntfrq)); +} + static uint32_t read_cntp_ctl(void) { uint32_t cntp_ctl; @@ -256,3 +262,9 @@ void arm_generic_timer_init(int irq) unmask_interrupt(irq); } +void arm_generic_timer_init_freq(int irq, uint32_t freq) +{ + write_cntfrq(freq); + arm_generic_timer_init(irq); +} + diff --git a/dev/timer/arm_generic/include/dev/timer/arm_generic.h b/dev/timer/arm_generic/include/dev/timer/arm_generic.h index f7f95ced7..646993a13 100644 --- a/dev/timer/arm_generic/include/dev/timer/arm_generic.h +++ b/dev/timer/arm_generic/include/dev/timer/arm_generic.h @@ -26,6 +26,7 @@ #include void arm_generic_timer_init(int irq); +void arm_generic_timer_init_freq(int irq, uint32_t freq); void arm_generic_timer_init_secondary_cpu(void); #endif From 5efcb333403d84e634f0562389d864821b6631e8 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Thu, 23 Oct 2014 14:31:13 +0800 Subject: [PATCH 37/43] [lib][sysparam] add sysparam_add_nosave function the caller can decide whether save sysparam to block device Change-Id: I70c206d2ff2794b2163603aedf3528969c85bd57 Signed-off-by: Xiang Xiao --- include/lib/sysparam.h | 2 + lib/sysparam/sysparam.c | 120 +++++++++++++++++++++++++--------------- 2 files changed, 78 insertions(+), 44 deletions(-) diff --git a/include/lib/sysparam.h b/include/lib/sysparam.h index 4841a21b2..7dc440c40 100644 --- a/include/lib/sysparam.h +++ b/include/lib/sysparam.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2013, Google, Inc. All rights reserved + * Copyright (c) 2014, Xiaomi, Inc. All rights reserved * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -41,6 +42,7 @@ status_t sysparam_get_ptr(const char *name, const void **ptr, size_t *len); #if SYSPARAM_ALLOW_WRITE status_t sysparam_add(const char *name, const void *value, size_t len); +status_t sysparam_add_nosave(const char *name, const void *value, size_t len); status_t sysparam_remove(const char *name); status_t sysparam_lock(const char *name); status_t sysparam_write(void); diff --git a/lib/sysparam/sysparam.c b/lib/sysparam/sysparam.c index 6e57c4ae0..bd3826ab5 100644 --- a/lib/sysparam/sysparam.c +++ b/lib/sysparam/sysparam.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013, Google, Inc. All rights reserved + * Copyright (c) 2014, Xiaomi, Inc. All rights reserved * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -40,7 +41,8 @@ #define SYSPARAM_MAGIC 'SYSP' -#define SYSPARAM_FLAG_LOCK 0x1 +#define SYSPARAM_FLAG_LOCK 0x1 +#define SYSPARAM_FLAG_NOSAVE 0x2 struct sysparam_phys { uint32_t magic; @@ -95,6 +97,11 @@ static inline bool sysparam_is_locked(const struct sysparam *param) return param->flags & SYSPARAM_FLAG_LOCK; } +static inline bool sysparam_is_saved(const struct sysparam *param) +{ + return !(param->flags & SYSPARAM_FLAG_NOSAVE); +} + static inline size_t sysparam_len(const struct sysparam_phys *sp) { size_t len = sizeof(struct sysparam_phys); @@ -260,11 +267,13 @@ status_t sysparam_reload(void) struct sysparam *param; struct sysparam *temp; list_for_every_entry_safe(¶ms.list, param, temp, struct sysparam, node) { - list_delete(¶m->node); + if (sysparam_is_saved(param)) { + list_delete(¶m->node); - free(param->name); - free(param->data); - free(param); + free(param->name); + free(param->data); + free(param); + } } /* reset the list back to scratch */ @@ -333,9 +342,11 @@ status_t sysparam_write(void) struct sysparam *param; off_t total_len = 0; list_for_every_entry(¶ms.list, param, struct sysparam, node) { - total_len += sizeof(struct sysparam_phys); - total_len += ROUNDUP(strlen(param->name), 4); - total_len += ROUNDUP(param->datalen, 4); + if (sysparam_is_saved(param)) { + total_len += sizeof(struct sysparam_phys); + total_len += ROUNDUP(strlen(param->name), 4); + total_len += ROUNDUP(param->datalen, 4); + } } if (total_len > params.len) @@ -359,39 +370,41 @@ status_t sysparam_write(void) /* serialize all of the parameters */ off_t pos = 0; list_for_every_entry(¶ms.list, param, struct sysparam, node) { - struct sysparam_phys phys; - - /* start filling out a struct */ - phys.magic = SYSPARAM_MAGIC; - phys.crc32 = 0; - phys.flags = param->flags; - phys.namelen = strlen(param->name); - phys.datalen = param->datalen; - - /* calculate the crc of the entire thing + padding */ - uint32_t zero = 0; - uint32_t sum = crc32(0, (const void *)&phys.flags, 8); - sum = crc32(sum, (const void *)param->name, strlen(param->name)); - if (strlen(param->name) % 4) - sum = crc32(sum, (const void *)&zero, 4 - (strlen(param->name) % 4)); - sum = crc32(sum, (const void *)param->data, ROUNDUP(param->datalen, 4)); - phys.crc32 = sum; - - /* structure portion */ - memcpy(buf + pos, &phys, sizeof(struct sysparam_phys)); - pos += sizeof(struct sysparam_phys); - - /* name portion */ - memcpy(buf + pos, param->name, strlen(param->name)); - pos += ROUNDUP(strlen(param->name), 2); - if (pos % 4) { - /* write 2 zeros to realign */ - pos += 2; - } + if (sysparam_is_saved(param)) { + struct sysparam_phys phys; + + /* start filling out a struct */ + phys.magic = SYSPARAM_MAGIC; + phys.crc32 = 0; + phys.flags = param->flags; + phys.namelen = strlen(param->name); + phys.datalen = param->datalen; + + /* calculate the crc of the entire thing + padding */ + uint32_t zero = 0; + uint32_t sum = crc32(0, (const void *)&phys.flags, 8); + sum = crc32(sum, (const void *)param->name, strlen(param->name)); + if (strlen(param->name) % 4) + sum = crc32(sum, (const void *)&zero, 4 - (strlen(param->name) % 4)); + sum = crc32(sum, (const void *)param->data, ROUNDUP(param->datalen, 4)); + phys.crc32 = sum; + + /* structure portion */ + memcpy(buf + pos, &phys, sizeof(struct sysparam_phys)); + pos += sizeof(struct sysparam_phys); + + /* name portion */ + memcpy(buf + pos, param->name, strlen(param->name)); + pos += ROUNDUP(strlen(param->name), 2); + if (pos % 4) { + /* write 2 zeros to realign */ + pos += 2; + } - /* data portion */ - memcpy(buf + pos, param->data, param->datalen); - pos += ROUNDUP(param->datalen, 4); + /* data portion */ + memcpy(buf + pos, param->data, param->datalen); + pos += ROUNDUP(param->datalen, 4); + } } /* write the block out */ @@ -423,6 +436,23 @@ status_t sysparam_add(const char *name, const void *value, size_t len) return NO_ERROR; } +status_t sysparam_add_nosave(const char *name, const void *value, size_t len) +{ + struct sysparam *param; + + param = sysparam_find(name); + if (param) + return ERR_ALREADY_EXISTS; + + param = sysparam_create(name, strlen(name), value, len, SYSPARAM_FLAG_NOSAVE); + if (!param) + return ERR_NO_MEMORY; + + list_add_tail(¶ms.list, ¶m->node); + + return NO_ERROR; +} + status_t sysparam_remove(const char *name) { struct sysparam *param; @@ -433,6 +463,8 @@ status_t sysparam_remove(const char *name) if (sysparam_is_locked(param)) return ERR_NOT_ALLOWED; + if (sysparam_is_saved(param)) + params.dirty = true; list_delete(¶m->node); @@ -440,8 +472,6 @@ status_t sysparam_remove(const char *name) free(param->data); free(param); - params.dirty = true; - return NO_ERROR; } @@ -456,7 +486,8 @@ status_t sysparam_lock(const char *name) /* set the lock bit if it isn't already */ if (!sysparam_is_locked(param)) { param->flags |= SYSPARAM_FLAG_LOCK; - params.dirty = true; + if (sysparam_is_saved(param)) + params.dirty = true; } return NO_ERROR; @@ -474,8 +505,9 @@ void sysparam_dump(bool show_all) struct sysparam *param; list_for_every_entry(¶ms.list, param, struct sysparam, node) { - printf("________%c %-16s : ", + printf("________%c%c %-16s : ", (param->flags & SYSPARAM_FLAG_LOCK) ? 'L' : '_', + (param->flags & SYSPARAM_FLAG_NOSAVE) ? '_' : 'S', param->name); const uint8_t *dat = (const uint8_t *)param->data; From 1921230a93ad20432423b37a14c8211f040d21a8 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Thu, 23 Oct 2014 14:38:46 +0800 Subject: [PATCH 38/43] [app][aboot] implement cmd_getvar base on sysparam the platform/target could extend fastboot variable more easier Change-Id: I927b0bc6c2efaf8d13c741955c81d7fcf9cb1859 Signed-off-by: Xiang Xiao --- app/aboot/fastboot.c | 32 ++++++++++---------------------- app/aboot/rules.mk | 6 ++++++ 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/app/aboot/fastboot.c b/app/aboot/fastboot.c index 1d6ef5c2f..d45cbd6a7 100644 --- a/app/aboot/fastboot.c +++ b/app/aboot/fastboot.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -88,12 +89,6 @@ struct fastboot_cmd { void (*handle)(const char *arg, void *data, unsigned sz); }; -struct fastboot_var { - struct fastboot_var *next; - const char *name; - const char *value; -}; - static struct fastboot_cmd *cmdlist; void fastboot_register(const char *prefix, @@ -110,18 +105,10 @@ void fastboot_register(const char *prefix, } } -static struct fastboot_var *varlist; - void fastboot_publish(const char *name, const char *value) { - struct fastboot_var *var; - var = malloc(sizeof(*var)); - if (var) { - var->name = name; - var->value = value; - var->next = varlist; - varlist = var; - } + sysparam_remove(name); + sysparam_add_nosave(name, value, strlen(value)); } @@ -248,13 +235,14 @@ void fastboot_okay(const char *info) static void cmd_getvar(const char *arg, void *data, unsigned sz) { - struct fastboot_var *var; + char *value = data; + ssize_t len; - for (var = varlist; var; var = var->next) { - if (!strcmp(var->name, arg)) { - fastboot_okay(var->value); - return; - } + len = sysparam_read(arg, value, sz); + if (len > 0) { + value[len] = 0; + fastboot_okay(value); + return; } fastboot_okay(""); } diff --git a/app/aboot/rules.mk b/app/aboot/rules.mk index 320b4e171..8a2aed9ba 100644 --- a/app/aboot/rules.mk +++ b/app/aboot/rules.mk @@ -2,8 +2,14 @@ LOCAL_DIR := $(GET_LOCAL_DIR) MODULE := $(LOCAL_DIR) +GLOBAL_DEFINES += \ + SYSPARAM_ALLOW_WRITE=1 + MODULE_SRCS += \ $(LOCAL_DIR)/aboot.c \ $(LOCAL_DIR)/fastboot.c +MODULE_DEPS += \ + lib/sysparam + include make/module.mk From 1d59d43f1392f5b6f126a0ab1e825f765936377b Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Fri, 24 Oct 2014 10:41:20 +0800 Subject: [PATCH 39/43] [vm] allocate vm_page array from self when heap exhaust do this only for already mapped arena(PMM_ARENA_FLAG_KMAP) Change-Id: I0baa6cbe0aab0525d9b5c37674119379cb989cde Signed-off-by: Xiang Xiao --- kernel/vm/pmm.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/kernel/vm/pmm.c b/kernel/vm/pmm.c index 617490fd6..bef68a529 100644 --- a/kernel/vm/pmm.c +++ b/kernel/vm/pmm.c @@ -83,6 +83,23 @@ status_t pmm_add_arena(pmm_arena_t *arena) DEBUG_ASSERT(IS_PAGE_ALIGNED(arena->size)); DEBUG_ASSERT(arena->size > 0); + /* allocate an array of pages to back this one */ + size_t page_count = arena->size / PAGE_SIZE; + arena->page_array = calloc(page_count, sizeof(vm_page_t)); + if (!arena->page_array) { /* heap exhaust */ + /* allocate from self if memory map already setup */ + if (arena->flags & PMM_ARENA_FLAG_KMAP) { + arena->size -= PAGE_ALIGN(page_count * sizeof(vm_page_t)); + arena->page_array = paddr_to_kvaddr(arena->base + arena->size); + + page_count = arena->size / PAGE_SIZE; + memset(arena->page_array, 0, page_count * sizeof(vm_page_t)); + } else { + LTRACEF("failing to allocate page_array\n"); + return ERR_NO_MEMORY; + } + } + /* walk the arena list and add arena based on priority order */ pmm_arena_t *a; list_for_every_entry(&arena_list, a, pmm_arena_t, node) { @@ -101,10 +118,6 @@ status_t pmm_add_arena(pmm_arena_t *arena) arena->free_count = 0; list_initialize(&arena->free_list); - /* allocate an array of pages to back this one */ - size_t page_count = arena->size / PAGE_SIZE; - arena->page_array = calloc(page_count, sizeof(vm_page_t)); - /* add them to the free list */ for (size_t i = 0; i < page_count; i++) { vm_page_t *p = &arena->page_array[i]; From c7c2e2d7f9295cfa039409c455816c543b7adbc0 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Sat, 25 Oct 2014 15:43:46 +0800 Subject: [PATCH 40/43] [vm] fix address calculation beyond 4G issue Change-Id: Ic37b00bf63e50bfee5847b2bdda9577d00d3844d Signed-off-by: Xiang Xiao --- include/kernel/vm.h | 2 +- kernel/vm/pmm.c | 8 ++++---- kernel/vm/vm.c | 2 +- kernel/vm/vmm.c | 9 +++++---- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/include/kernel/vm.h b/include/kernel/vm.h index 703a8605b..fa644094a 100644 --- a/include/kernel/vm.h +++ b/include/kernel/vm.h @@ -78,7 +78,7 @@ STATIC_ASSERT(KERNEL_ASPACE_BASE + (KERNEL_ASPACE_SIZE - 1) > KERNEL_ASPACE_BASE static inline bool is_kernel_address(vaddr_t va) { - return (va >= KERNEL_ASPACE_BASE && va <= (KERNEL_ASPACE_BASE + KERNEL_ASPACE_SIZE)); + return (va >= KERNEL_ASPACE_BASE && va <= (KERNEL_ASPACE_BASE + (KERNEL_ASPACE_SIZE - 1))); } /* physical allocator */ diff --git a/kernel/vm/pmm.c b/kernel/vm/pmm.c index bef68a529..f69bbaf71 100644 --- a/kernel/vm/pmm.c +++ b/kernel/vm/pmm.c @@ -42,10 +42,10 @@ static struct list_node arena_list = LIST_INITIAL_VALUE(arena_list); ((uintptr_t)(page) < ((uintptr_t)(arena)->page_array + (arena)->size / PAGE_SIZE * sizeof(vm_page_t)))) #define PAGE_ADDRESS_FROM_ARENA(page, arena) \ - (paddr_t)(((uintptr_t)page - (uintptr_t)a->page_array) / sizeof(vm_page_t)) * PAGE_SIZE + a->base; + (paddr_t)((((uintptr_t)(page) - (uintptr_t)(arena)->page_array) / sizeof(vm_page_t)) * PAGE_SIZE + (arena)->base) #define ADDRESS_IN_ARENA(address, arena) \ - ((address) >= (arena)->base && (address) <= (arena)->base + (arena)->size) + ((address) >= (arena)->base && (address) <= (arena)->base + ((arena)->size - 1)) static inline bool page_is_free(const vm_page_t *page) { @@ -67,7 +67,7 @@ vm_page_t *address_to_page(paddr_t addr) { pmm_arena_t *a; list_for_every_entry(&arena_list, a, pmm_arena_t, node) { - if (addr >= a->base && addr <= a->base + a->size - 1) { + if (ADDRESS_IN_ARENA(addr, a)) { size_t index = (addr - a->base) / PAGE_SIZE; return &a->page_array[index]; } @@ -281,7 +281,7 @@ uint pmm_alloc_contiguous(uint count, uint8_t alignment_log2, paddr_t *pa, struc * is not aligned on the same boundary requested. */ paddr_t rounded_base = ROUNDUP(a->base, 1UL << alignment_log2); - if (rounded_base < a->base || rounded_base >= a->base + a->size) + if (!ADDRESS_IN_ARENA(rounded_base, a)) continue; uint aligned_offset = (rounded_base - a->base) / PAGE_SIZE; diff --git a/kernel/vm/vm.c b/kernel/vm/vm.c index 4635c60e5..cdd3def69 100644 --- a/kernel/vm/vm.c +++ b/kernel/vm/vm.c @@ -91,7 +91,7 @@ void *paddr_to_kvaddr(paddr_t pa) while (map->size > 0) { if (!(map->flags & MMU_INITIAL_MAPPING_TEMPORARY) && pa >= map->phys && - pa <= map->phys + map->size) { + pa <= map->phys + (map->size - 1)) { return (void *)(map->virt + (pa - map->phys)); } map++; diff --git a/kernel/vm/vmm.c b/kernel/vm/vmm.c index c7b9731af..852dcedc8 100644 --- a/kernel/vm/vmm.c +++ b/kernel/vm/vmm.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2014 Travis Geiselbrecht + * Copyright (c) 2014 Xiaomi Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -85,12 +86,12 @@ static size_t trim_to_aspace(const vmm_aspace_t *aspace, vaddr_t vaddr, size_t s //LTRACEF("vaddr 0x%lx size 0x%zx offset 0x%zx aspace base 0x%lx aspace size 0x%zx\n", // vaddr, size, offset, aspace->base, aspace->size); - if (offset + size < offset) - size = ULONG_MAX - offset - 1; + if (offset + size - 1 < offset) + size = ULONG_MAX - offset; //LTRACEF("size now 0x%zx\n", size); - if (offset + size >= aspace->size - 1) + if (offset + size - 1 >= aspace->size) size = aspace->size - offset; //LTRACEF("size now 0x%zx\n", size); @@ -483,7 +484,7 @@ status_t vmm_alloc(vmm_aspace_t *aspace, const char *name, size_t size, void **p vaddr_t va = r->base; DEBUG_ASSERT(IS_PAGE_ALIGNED(va)); while ((p = list_remove_head_type(&page_list, vm_page_t, node))) { - DEBUG_ASSERT(va < r->base + r->size); + DEBUG_ASSERT(va <= r->base + r->size - 1); paddr_t pa = page_to_address(p); DEBUG_ASSERT(IS_PAGE_ALIGNED(pa)); From f79ab9866837db08436aa0e7907030c1e8cdabbb Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Sat, 25 Oct 2014 01:08:09 +0800 Subject: [PATCH 41/43] [dev] add device_init_range to init device in [first, last] and extend fini funtion in the same way Change-Id: Ic0ba2fb8f4e37b64a8518d03ba62ea69b62319e2 Signed-off-by: Xiang Xiao --- dev/driver.c | 36 +++++++++++++++++++----------------- include/dev/driver.h | 3 +++ 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/dev/driver.c b/dev/driver.c index 30a1f1091..0bf709eb5 100644 --- a/dev/driver.c +++ b/dev/driver.c @@ -31,6 +31,16 @@ extern struct device __devices[]; extern struct device __devices_end[]; +status_t device_init_all(void) +{ + return device_init_range(INT_MIN + 1, INT_MAX - 1); +} + +status_t device_fini_all(void) +{ + return device_fini_range(INT_MIN + 1, INT_MAX - 1); +} + static int device_get_next_order(int order) { int next = INT_MAX; @@ -68,20 +78,16 @@ static status_t device_init_order(int order) return res; } -status_t device_init_all(void) +status_t device_init_range(int first, int last) { status_t res = NO_ERROR; - int order = INT_MIN; - while (true) { - order = device_get_next_order(order); - if (order == INT_MAX) { - break; - } - status_t code = device_init_order(order); + while (first <= last) { + status_t code = device_init_order(first); if (code < 0) { res = code; } + first = device_get_next_order(first); } return res; @@ -102,7 +108,7 @@ static int device_get_prev_order(int order) return prev; } -status_t device_fini_order(int order) +static status_t device_fini_order(int order) { status_t res = NO_ERROR; @@ -124,20 +130,16 @@ status_t device_fini_order(int order) return res; } -status_t device_fini_all(void) +status_t device_fini_range(int first, int last) { status_t res = NO_ERROR; - int order = INT_MAX; - while (true) { - order = device_get_prev_order(order); - if (order == INT_MIN) { - break; - } - status_t code = device_fini_order(order); + while (first <= last) { + status_t code = device_fini_order(last); if (code < 0) { res = code; } + last = device_get_prev_order(last); } return res; diff --git a/include/dev/driver.h b/include/dev/driver.h index 7932ab54b..ae44ae955 100644 --- a/include/dev/driver.h +++ b/include/dev/driver.h @@ -106,6 +106,9 @@ struct driver { status_t device_init_all(void); status_t device_fini_all(void); +status_t device_init_range(int first, int last); +status_t device_fini_range(int first, int last); + status_t device_init(struct device *dev); status_t device_fini(struct device *dev); From 32f7b9454dc2388fd7473d61e04bb8ebcd7f5c1c Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Sat, 25 Oct 2014 00:52:07 +0800 Subject: [PATCH 42/43] [dev][16550] add reserved state in config structure and automatically call uart_init if not yet, so the debug message could output at the very early stage. Change-Id: Id704ac6d827b3b697cc40765786844a872a5f451 Signed-off-by: Xiang Xiao --- dev/uart/16550/16550.c | 84 +++++++++++++++---------- dev/uart/16550/include/dev/uart/16550.h | 11 ++++ 2 files changed, 62 insertions(+), 33 deletions(-) diff --git a/dev/uart/16550/16550.c b/dev/uart/16550/16550.c index 7b6d60ccf..e20f4ab02 100644 --- a/dev/uart/16550/16550.c +++ b/dev/uart/16550/16550.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #define UART_RBR 0 @@ -93,12 +92,6 @@ #define UART_LSR_TEMT 0x40 #define UART_LSR_FIFOE 0x80 -#define UART_RXBUF_SIZE 32 - -struct uart_state { - struct cbuf rxbuf; -}; - // internal function static uint8_t uart_get(struct device *dev, off_t offset) { @@ -232,7 +225,7 @@ static enum handler_return uart_irq_handler(void *arg) { bool resched = false; struct device *dev = arg; - struct uart_state *state = dev->state; + struct uart_16550_state *state = dev->state; while (uart_get(dev, UART_LSR) & UART_LSR_DR) { uint8_t c = uart_get(dev, UART_RBR); @@ -261,48 +254,66 @@ static void uart_fini_irq(struct device *dev) // new uart api static status_t uart_init(struct device *dev) { - if (!dev->config) { - return ERR_NOT_CONFIGURED; - } - - struct uart_state *state = malloc(sizeof(*state)); - if (!state) { - return ERR_NO_MEMORY; - } + if (!dev->state) { + const struct uart_16550_config* config = dev->config; + if (!dev->config) { + return ERR_NOT_CONFIGURED; + } - dev->state = state; - cbuf_initialize(&state->rxbuf, UART_RXBUF_SIZE); + struct uart_16550_state *state = config->state; + if (!state) { + state = malloc(sizeof(*state)); + if (!state) { + return ERR_NO_MEMORY; + } + } - uart_init_config(dev); - uart_init_irq(dev); + cbuf_initialize_etc(&state->rxbuf, UART_RXBUF_SIZE, state->buf); + dev->state = state; + uart_init_config(dev); + uart_init_irq(dev); + } return NO_ERROR; } static status_t uart_fini(struct device *dev) { - uart_fini_irq(dev); - free(dev->state); - dev->state = NULL; + const struct uart_16550_config* config = dev->config; + if (dev->state) { + uart_fini_irq(dev); + if (dev->state != config->state) { + free(dev->state); + } + dev->state = NULL; + } return NO_ERROR; } static ssize_t uart_read(struct device *dev, void *buf, size_t len) { - struct uart_state *state = dev->state; - return cbuf_read(&state->rxbuf, buf, len, true); + ssize_t ret = uart_init(dev); + if (ret >= 0) { + struct uart_16550_state *state = dev->state; + ret = cbuf_read(&state->rxbuf, buf, len, true); + } + return ret; } static ssize_t uart_write(struct device *dev, const void *buf_, size_t len) { - const char *buf = buf_; - for (size_t i = 0; i < len; i++) { - while (!(uart_get(dev, UART_LSR) & UART_LSR_THRE)) { - ; // wait for the xmit fifo available + ssize_t ret = uart_init(dev); + if (ret >= 0) { + const char *buf = buf_; + for (size_t i = 0; i < len; i++) { + while (!(uart_get(dev, UART_LSR) & UART_LSR_THRE)) { + ; // wait for the xmit fifo available + } + uart_set(dev, UART_THR, *buf++); } - uart_set(dev, UART_THR, *buf++); + ret = len; } - return len; + return ret; } static struct uart_ops uart_ops = { @@ -323,7 +334,14 @@ static struct device *uart_find(int port) { char name[16]; sprintf(name, "uart%d", port); - return device_find(name); + + struct device *dev = device_find(name); + if (dev) { + if (uart_init(dev) < 0) { + dev = NULL; + } + } + return dev; } int uart_putc(int port, char c) @@ -342,7 +360,7 @@ int uart_getc(int port, bool wait) struct device *dev = uart_find(port); if (dev) { char c; - struct uart_state *state = dev->state; + struct uart_16550_state *state = dev->state; if (cbuf_read_char(&state->rxbuf, &c, wait) == 1) { ret = c; } else { diff --git a/dev/uart/16550/include/dev/uart/16550.h b/dev/uart/16550/include/dev/uart/16550.h index 57d687595..2c45a11dc 100644 --- a/dev/uart/16550/include/dev/uart/16550.h +++ b/dev/uart/16550/include/dev/uart/16550.h @@ -25,6 +25,15 @@ #ifndef __DEV_UART_16550_H #define __DEV_UART_16550_H +#include + +#define UART_RXBUF_SIZE 32 + +struct uart_16550_state { + struct cbuf rxbuf; + char buf[UART_RXBUF_SIZE]; +}; + struct uart_16550_config { unsigned irq; uintptr_t base; @@ -37,6 +46,8 @@ struct uart_16550_config { bool parity_enable; bool even_parity; bool autoflow_enable; + /* optional reserved state */ + struct uart_16550_state *state; }; #endif From 9be54e0778fc06c396e1177de7aba3437facaa9d Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Mon, 27 Oct 2014 21:38:28 +0800 Subject: [PATCH 43/43] [dev] move dev to next for each loop in device_find Change-Id: I792623ca1486071a15c3373fac10cf24dde0c869 Signed-off-by: Xiang Xiao --- dev/driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/driver.c b/dev/driver.c index 0bf709eb5..f15b51ebc 100644 --- a/dev/driver.c +++ b/dev/driver.c @@ -212,7 +212,7 @@ struct device *device_find(const char *name) if (!strcmp(dev->name, name)) { return dev; } + dev++; } - return NULL; }