34 Commits

Author SHA1 Message Date
NIIBE Yutaka
9977bac715 Version 2.3.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-10-12 11:09:38 +09:00
NIIBE Yutaka
446e31a7c4 usbip: Fix the value of URB_DATA_SIZE again.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-10-11 10:22:19 +09:00
NIIBE Yutaka
f10cdce66c more fix for libccid.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-10-04 13:58:44 +09:00
NIIBE Yutaka
86ccc02be7 Fix USB emulation driver for GNU/Linux.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-10-04 10:05:45 +09:00
NIIBE Yutaka
d36e9274b1 Add comment for chopstx_mutex_lock.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-10-04 09:26:50 +09:00
NIIBE Yutaka
5a3a3e98d4 Version 2.2.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-26 09:16:49 +09:00
NIIBE Yutaka
7ad2c9030a One more change for Cortex-M3/M4 asm for shorter result.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-26 09:15:18 +09:00
NIIBE Yutaka
a70b1acbf6 Change asm for Cortex-M0/3/4.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-25 12:52:26 +09:00
NIIBE Yutaka
fd8bb46b8b Fix for Cortex-M0.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-25 10:35:29 +09:00
NIIBE Yutaka
95fe257dc0 cortex-m: Fix chx_handle_intr.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-19 15:56:43 +09:00
NIIBE Yutaka
2fb3c1c503 GNU/Linux: Use getrandom for ADC driver.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-17 16:24:22 +09:00
NIIBE Yutaka
f84f6c1cac GNU/Linux: Add start-up message for USB driver.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-17 10:29:08 +09:00
NIIBE Yutaka
68b78a0ade GNU/Linux: Fix AckBtn driver, again.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-17 10:12:08 +09:00
NIIBE Yutaka
8c48b0d7d3 GNU/Linux: Fix AckBtn driver.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-17 09:53:49 +09:00
NIIBE Yutaka
b3c35aebdd Add new driver for AckBtn for GNU/Linux emulation.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-17 09:47:19 +09:00
NIIBE Yutaka
c0f3567ed6 Version 2.1.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-12 09:19:08 +09:00
NIIBE Yutaka
27791641aa GNU/Linux: Fix the example.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-10 14:49:19 +09:00
NIIBE Yutaka
eaa47d5059 Update copyright notices.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-10 10:44:37 +09:00
NIIBE Yutaka
b491d815e5 GNU/Linux: Fix the example to cancel the input on timeout.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-10 10:19:06 +09:00
NIIBE Yutaka
c1433f1520 GNU/Linux: Application can exit by SIGINT or SIGTERM.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-10 09:33:53 +09:00
NIIBE Yutaka
bd66c51e35 Fix chx_recv_irq.
Fixes-commit: d2df891ba5
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-10 09:22:37 +09:00
NIIBE Yutaka
bd8f39f3c9 GNU/Linux: Add/fix comments.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-10 09:05:16 +09:00
NIIBE Yutaka
88909bab49 GNU/Linux: Make sure thread struct is cleared.
Also, added a comment for makecontext.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-09 16:50:48 +09:00
NIIBE Yutaka
66f08d87e4 Fix example for GNU/Linux emulation.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-09 16:38:13 +09:00
NIIBE Yutaka
7b7335bc5d Fix GNU/Linux emulation.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-09 16:36:40 +09:00
NIIBE Yutaka
af3ef1f93d Add comments to show access to RUNNING.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-09 13:33:51 +09:00
NIIBE Yutaka
d2df891ba5 Fix chx_recv_irq.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-08 17:33:24 +09:00
NIIBE Yutaka
cfcdeebb78 More fixes for Cortex-M0/Cortex-M3/Cortex-M4 implementations.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-08 12:22:16 +09:00
NIIBE Yutaka
2832104263 Rewrite the ChangeLog entry.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-05 15:30:56 +09:00
NIIBE Yutaka
b0986cdb09 Fix preemption.
Consider the sequence:

   chx_handle_intr -> chx_handle_intr -> preempt

We can't use R0 passing as an argument to preempt.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-05 11:26:20 +09:00
NIIBE Yutaka
c3f00e1c69 cortex-m: Multiple interrupts handling may occur on Cortex-M3 too.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-05 10:54:41 +09:00
NIIBE Yutaka
6d46ea2a4c cortex-m: Don't share return path between PREEMPT and SVC.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-05 10:49:09 +09:00
NIIBE Yutaka
7035103a49 Fix the previous commit.
Handle the case when multiple interrupts are active simultaneously.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-05 09:38:38 +09:00
NIIBE Yutaka
8b6c1ebd24 Fixes for FSM-55.
I realized that tail-chaining doesn't work with STM32F0.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-04 15:32:23 +09:00
18 changed files with 760 additions and 265 deletions

101
ChangeLog
View File

@@ -1,3 +1,104 @@
2021-10-12 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 2.3
* doc/chopstx.texi (VERSION): 2.3.
2021-10-11 NIIBE Yutaka <gniibe@fsij.org>
* mcu/usb-usbip.c (URB_DATA_SIZE): Tweak the value.
2021-02-26 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 2.2
* doc/chopstx.texi (VERSION): 2.2.
2021-02-25 NIIBE Yutaka <gniibe@fsij.org>
* rules.mk (MCFLAGS): Add -masm-syntax-unified.
* entry-cortex-m.c (entry): Use Thumb-16 instruction in unified
asm syntax. This means that no output change for Cortex-M0,
but change for Cortex-M3/M4 (shorter, different semantics).
* example-fsm-55/reset.c (reset): Likewise.
* chopstx-cortex-m.c
[__ARM_ARCH_6M__] (involuntary_context_switch): Use unified syntax.
[__ARM_ARCH_7M__] (involuntary_context_switch): Use Thumb-16
instruction.
[__ARM_ARCH_6M__] (chx_handle_intr): Use unified syntax.
[__ARM_ARCH_7M__] (chx_handle_intr): Use Thumb-16 instruction.
[__ARM_ARCH_6M__] (voluntary_context_switch): Use unified syntax.
[__ARM_ARCH_7M__] (svc): Use Thumb-16 instruction.
2021-02-19 NIIBE Yutaka <gniibe@fsij.org>
* chopstx-cortex-m.c (chx_handle_intr): Fix SUB instruction.
2021-02-17 NIIBE Yutaka <gniibe@fsij.org>
* contrib/adc-gnu-linux.c (adc_start_conversion): Use getrandom.
* mcu/usb-usbip.c (usbip_run_server): Add start-up message.
2021-02-16 NIIBE Yutaka <gniibe@fsij.org>
* contrib/ackbtn-gnu-linux.c: New.
2021-02-12 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 2.1
* doc/chopstx.texi (VERSION): 2.1.
2021-02-10 NIIBE Yutaka <gniibe@fsij.org>
* example-cdc-gnu-linux/usb-cdc.c (tty_recv): Cancel the input.
* chopstx.c (chx_recv_irq): Bug fix when no waiter.
* chopstx-gnu-linux.c (chopstx_create_arch): Fix ARGC of
makecontext call.
(chx_idle): Support exit by SIGINT or SIGTERM.
2021-02-09 NIIBE Yutaka <gniibe@fsij.org>
* chopstx-gnu-linux.c (chopstx_create_arch): Clear TP.
* example-cdc-gnu-linux/sample.c (main): Handle timeout by canceling
input.
* chopstx-gnu-linux.c (voluntary_context_switch): Fix for the case
when chx_idle suggests no context switch (tp_prev == tp_next).
2021-02-08 NIIBE Yutaka <gniibe@fsij.org>
* entry-cortex-m.c (vector_table): No use of PENDV exception.
Use chx_handle_intr for SysTick.
* example-fsm-55/reset.c (vector): Likewise.
* chopstx-cortex-m.c (preempting): Remove.
(CPU_EXCEPTION_PRIORITY_PENDSV): Remove.
(chx_interrupt_controller_init): No setup for PENDV.
(chx_request_preemption_possibly): Remove.
(involuntary_context_switch): New.
(chx_timer_handler): Remove.
(chx_handle_intr): Use involuntary_context_switch directly.
(preempt): Remove.
2021-02-05 NIIBE Yutaka <gniibe@fsij.org>
* chopstx-cortex-m.c (preempting): New value to hold the pointer
to preempting thread, which will become RUNNING.
(chx_request_preemption_possibly): New.
(chx_timer_handler, chx_handle_intr): Use the new function.
(preempt): Recover R0 from PREEMPTING and clear PREEMPTING.
(svc): Don't share return path with preempt.
2021-02-04 NIIBE Yutaka <gniibe@fsij.org>
* board/board-fsm-55.h (VAL_GPIO_LED_MODER): Support SWD
debugging.
2020-06-26 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 2.0

52
NEWS
View File

@@ -1,6 +1,58 @@
NEWS - Noteworthy changes
* Major changes in Chopstx 2.3
Released 2021-10-12
** Fix of USB driver for GNU/Linux emulation
Fix the value of URB_DATA_SIZE, so that Gnuk can work with PC/SC.
* Major changes in Chopstx 2.2
Released 2021-02-25
** Acknowledge button support for GNU/Linux emulation
User is asked acknowledge by RET with standard input.
** USB driver for GNU/Linux emulation
It shows start-up message now.
** ADC driver for GNU/Linux emulation
It uses getrandom(2), output is not deterministic any more.
** Bug fix for Cortex-M3/M4 Support
In 2.1, preemption doesn't work well, because of the difference of
assembler syntax.
* Major changes in Chopstx 2.1
Released 2021-02-12
** GNU/Linux emulation change
The process can be asked to exit by SIGINT or SIGTERM.
** Bug fix for interrupt handling
The check to find waiting thread was wrong. If no waiting thread,
it failed.
** Bug fix for GNU/Linux emulation
In 2.0, GNU/Linux emulation doesn't work well with chx_idle when it
handles interrupt synchronously and the waken thread is the same one
which called chx_idle.
** Bug fix for Cortex-M0/M3/M4 Support
In 2.0, Cortex-M0 with no tail-chaining support (e.g. STM32F030)
doesn't work. In 2.0, Cortex-M3/M4 may fail when two or more
interrupts occur simultaneously; A waken thread (which is about to
preempt RUNNING) by the first interrupt may be lost (and never
scheduled again), by the second interrupt handling before the call of
preempt function.
* Major changes in Chopstx 2.0
Released 2020-06-26

15
README
View File

@@ -1,6 +1,6 @@
Chopstx - Threads and only Threads
Version 2.0
2020-06-26
Version 2.3
2021-10-12
Niibe Yutaka
Flying Stone Technology
@@ -9,7 +9,7 @@ What's Chopstx?
Chopstx is an RT thread library for STM32F103 and GD32F103 (ARM
Cortex-M3), STM32F030 (ARM Cortex-M0), MKL27Z (ARM Cortex-M0plus),
STM32L432 (ARM Cortex-M4), GD32V103 (RISC-V Bumblebee) and emulation
STM32L432 (ARM Cortex-M4), GD32VF103 (RISC-V Bumblebee) and emulation
on GNU/Linux.
While most RTOSes come with many features, drivers, and protocol
@@ -28,7 +28,8 @@ Note that this library is _not_ related to the hand game:
https://en.wikipedia.org/wiki/Chopsticks_(hand_game)
Thanks to Yao Wei and Enrico Zini for giving me an opportunity
visiting the wiki page above, when my children were playing the game.
visiting the wiki page above in Debconf Taiwan, when my children were
playing the game.
License
@@ -65,7 +66,7 @@ Convenience function to determine the bottom of thread stack,
configuration of thread size by compiler's output would be next things
to be done.
Experimental SMP port for Cortex-A7 is under development. For SMP,
more careful considerations for shared access to objects of struct
chx_pq is needed. So, modifications required will not be small.
We have an experimental SMP port for Cortex-A7. For SMP, more careful
considerations for shared access to objects of struct chx_pq is
needed. So, modifications required will not be small.
--

View File

@@ -1 +1 @@
release/2.0
release/2.3

View File

@@ -19,10 +19,13 @@
/*
* Port A setup.
* PA5 - ON (LED 1:ON 0:OFF)
* PA4 - Pull DOWN
* PA5 - ON (LED 1:ON 0:OFF)
*
* PA13 - SWDIO
* PA14 - SWCLK
*/
#define VAL_GPIO_LED_MODER 0x00145555 /* Output Pin0-7, Pin9 and Pin10 */
#define VAL_GPIO_LED_MODER 0x28145555 /* Output Pin0-7, Pin9 and Pin10 */
#define VAL_GPIO_LED_OTYPER 0x0000001f /* Open-drain for Pin0-4, Push-Pull*/
#define VAL_GPIO_LED_OSPEEDR 0x003cffff /* High speed */
#define VAL_GPIO_LED_PUPDR 0x00000000 /* No pull-up/pull-down */

View File

@@ -2,7 +2,7 @@
* chopstx-cortex-m.c - Threads and only threads: Arch specific code
* for Cortex-M0/M3/M4
*
* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2018, 2019
* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2021
* Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -76,14 +76,14 @@ struct chx_stack_regs {
* ---------------------
* Prio 0x40: thread temporarily inhibiting schedule for critical region
* ...
* Prio 0xb0: systick, external interrupt, pendsv
* Prio 0xb0: systick, external interrupt
* =====================================
*
* Cortex-M0
* =====================================
* Prio 0x00: thread temporarily inhibiting schedule for critical region
* ...
* Prio 0x40: systick, external interrupt, pendsv
* Prio 0x40: systick, external interrupt
* Prio 0x80: svc (not used)
* =====================================
*/
@@ -95,7 +95,6 @@ struct chx_stack_regs {
/* ... */
#define CPU_EXCEPTION_PRIORITY_SYSTICK 0x40
#define CPU_EXCEPTION_PRIORITY_INTERRUPT CPU_EXCEPTION_PRIORITY_SYSTICK
#define CPU_EXCEPTION_PRIORITY_PENDSV CPU_EXCEPTION_PRIORITY_SYSTICK
#define CPU_EXCEPTION_PRIORITY_SVC 0x80 /* No use in this arch */
#elif defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
#define CPU_EXCEPTION_PRIORITY_SVC 0x30
@@ -104,7 +103,6 @@ struct chx_stack_regs {
/* ... */
#define CPU_EXCEPTION_PRIORITY_SYSTICK 0xb0
#define CPU_EXCEPTION_PRIORITY_INTERRUPT CPU_EXCEPTION_PRIORITY_SYSTICK
#define CPU_EXCEPTION_PRIORITY_PENDSV CPU_EXCEPTION_PRIORITY_SYSTICK
#else
#error "no support for this arch"
#endif
@@ -228,8 +226,7 @@ chx_interrupt_controller_init (void)
{
*AIRCR = 0x05FA0000 | ( 5 << 8); /* PRIGROUP = 5, 2-bit:2-bit. */
*SHPR2 = (CPU_EXCEPTION_PRIORITY_SVC << 24);
*SHPR3 = ((CPU_EXCEPTION_PRIORITY_SYSTICK << 24)
| (CPU_EXCEPTION_PRIORITY_PENDSV << 16));
*SHPR3 = (CPU_EXCEPTION_PRIORITY_SYSTICK << 24);
}
@@ -256,37 +253,107 @@ chx_cpu_sched_unlock (void)
}
static void
chx_request_preemption (void)
static void __attribute__ ((naked, used))
involuntary_context_switch (struct chx_thread *tp_next)
{
*ICSR = (1 << 28);
asm volatile ("" : : : "memory");
register struct chx_thread *tp_current asm ("r1");
asm (
"ldr r2, =running\n\t"
"ldr r1, [r2]"
: "=r" (tp_current)
: /* no input */
: "r2");
if (!tp_current)
/* It's idle thread. No need to save registers. */
;
else
{
/* Save registers onto CHX_THREAD struct. */
asm volatile (
"adds %0, #20\n\t"
"stm %0!, {r4, r5, r6, r7}\n\t"
"mov r2, r8\n\t"
"mov r3, r9\n\t"
"mov r4, r10\n\t"
"mov r5, r11\n\t"
"mrs r6, PSP\n\t" /* r13(=SP) in user space. */
"stm %0!, {r2, r3, r4, r5, r6}"
: "=r" (tp_current)
: "0" (tp_current)
/*
* Memory clobber constraint here is not accurate, but this
* works. R7 keeps its value, but having "r7" here prevents
* use of R7 before this asm statement.
*/
: "cc", "r2", "r3", "r4", "r5", "r6", "r7", "memory");
tp_next = chx_running_preempted (tp_next);
}
/* Registers on stack (PSP): r0, r1, r2, r3, r12, lr, pc, xpsr */
asm volatile (
/* Now, r0 points to the thread to be switched. */
/* Put it to *running. */
"ldr r1, =running\n\t"
/* Update running: chx_set_running */
"str r0, [r1]\n\t"
/**/
"adds r0, #20\n\t"
"ldm r0!, {r4, r5, r6, r7}\n\t"
#if defined(__ARM_ARCH_6M__)
"ldm r0!, {r1, r2, r3}\n\t"
"mov r8, r1\n\t"
"mov r9, r2\n\t"
"mov r10, r3\n\t"
"ldm r0!, {r1, r2}\n\t"
"mov r11, r1\n\t"
"msr PSP, r2\n\t"
#else
"ldr r8, [r0], #4\n\t"
"ldr r9, [r0], #4\n\t"
"ldr r10, [r0], #4\n\t"
"ldr r11, [r0], #4\n\t"
"ldr r1, [r0], #4\n\t"
"msr PSP, r1\n\t"
#endif
"movs r0, #0\n\t"
"subs r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
"bx r0"
: /* no output */ : "r" (tp_next) : "memory");
}
struct chx_thread *
chx_timer_handler (void)
{
struct chx_thread *tp_next;
tp_next = chx_timer_expired ();
if (tp_next)
chx_request_preemption ();
return tp_next;
}
static struct chx_thread *chx_timer_expired (void) __attribute__ ((noinline,used));
static struct chx_thread *chx_recv_irq (uint32_t irq_num) __attribute__ ((noinline,used));
struct chx_thread *
void __attribute__ ((naked))
chx_handle_intr (void)
{
register uint32_t irq_num;
struct chx_thread *tp_next;
register struct chx_thread *tp_next asm ("r0");;
asm volatile ("mrs %0, IPSR\n\t"
"sub %0, #16" /* Exception # - 16 = interrupt number. */
: "=r" (irq_num) : /* no input */ : "memory");
/* Exception # - 16 = interrupt number. */
"subs %0, #16\n\t"
"bpl 0f\n\t"
"bl chx_timer_expired\n\t"
"b 1f\n"
"0:\n\t"
"bl chx_recv_irq\n"
"1:"
: "=r" (tp_next) : /* no input */ : "cc", "memory");
tp_next = chx_recv_irq (irq_num);
if (tp_next)
chx_request_preemption ();
return tp_next;
asm volatile (
"b involuntary_context_switch"
: /*no input */ : /* no input */ : "memory");
else
asm volatile (
"movs r0, #0\n\t"
"subs r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
"bx r0"
: /*no input */ : /* no input */ : "memory");
}
static void
@@ -305,14 +372,14 @@ voluntary_context_switch (struct chx_thread *tp_next)
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
asm volatile (
"svc #0\n\t"
"add r1, r0, #16\n\t"
"ldr r0, [r1]" /* Get tp->v */
: "=r" (result) : "0" (tp_next): "memory");
"add r1, r0, #16\n\t"
"ldr r0, [r1]" /* Get tp->v */
: "=r" (result) : "0" (tp_next): "r1", "memory");
#else
register struct chx_thread *tp asm ("r1");
/* Build stack data as if it were an exception entry.
* And set the stop top to has RUNNNING.
* And set the stack top to have RUNNNING.
*/
/*
* r0: RUNNING scratch
@@ -326,10 +393,10 @@ voluntary_context_switch (struct chx_thread *tp_next)
*/
asm ("mov %0, lr\n\t"
"ldr r2, =.L_CONTEXT_SWITCH_FINISH\n\t"
"mov r3, #128\n\t"
"lsl r3, #17\n\t"
"movs r3, #128\n\t"
"lsls r3, #17\n\t"
"push {%0, r2, r3}\n\t"
"mov %0, #0\n\t"
"movs %0, #0\n\t"
"mov r2, %0\n\t"
"mov r3, %0\n\t"
"push {%0, r2, r3}\n\t"
@@ -338,10 +405,10 @@ voluntary_context_switch (struct chx_thread *tp_next)
"push {%0, r3}\n\t"
: "=r" (tp)
: /* no input */
: "r2", "r3", "memory");
: "cc", "r2", "r3", "memory");
/* Save registers onto CHX_THREAD struct. */
asm ("add r1, #20\n\t"
asm ("adds r1, #20\n\t"
"stm r1!, {r4, r5, r6, r7}\n\t"
"mov r2, r8\n\t"
"mov r3, r9\n\t"
@@ -349,10 +416,10 @@ voluntary_context_switch (struct chx_thread *tp_next)
"mov r5, r11\n\t"
"mov r6, sp\n\t"
"stm r1!, {r2, r3, r4, r5, r6}\n\t"
"sub r1, #56"
"subs r1, #56"
: /* no output */
: "r" (tp)
: "r2", "r3", "r4", "r5", "r6", "r7", "memory");
: "cc", "r2", "r3", "r4", "r5", "r6", "r7", "memory");
asm volatile (/* Now, r0 points to the thread to be switched. */
/* Put it to *running. */
@@ -373,7 +440,7 @@ voluntary_context_switch (struct chx_thread *tp_next)
/* Normal context switch */
"0:\n\t"
"add r0, #20\n\t"
"adds r0, #20\n\t"
"ldm r0!, {r4, r5, r6, r7}\n\t"
"ldm r0!, {r1, r2, r3}\n\t"
"mov r8, r1\n\t"
@@ -398,12 +465,12 @@ voluntary_context_switch (struct chx_thread *tp_next)
[28 or 32] <-- pc
*/
"ldr r0, [sp, #28]\n\t"
"lsl r1, r0, #23\n\t"
"lsls r1, r0, #23\n\t"
"bcc 2f\n\t"
/**/
"ldr r2, [sp, #24]\n\t"
"mov r1, #1\n\t"
"orr r2, r1\n\t" /* Ensure Thumb-mode */
"movs r1, #1\n\t"
"orrs r2, r1\n\t" /* Ensure Thumb-mode */
"str r2, [sp, #32]\n\t"
"msr APSR_nzcvq, r0\n\t"
/**/
@@ -416,8 +483,8 @@ voluntary_context_switch (struct chx_thread *tp_next)
"pop {pc}\n"
"2:\n\t"
"ldr r2, [sp, #24]\n\t"
"mov r1, #1\n\t"
"orr r2, r1\n\t" /* Ensure Thumb-mode */
"movs r1, #1\n\t"
"orrs r2, r1\n\t" /* Ensure Thumb-mode */
"str r2, [sp, #28]\n\t"
"msr APSR_nzcvq, r0\n\t"
/**/
@@ -429,13 +496,13 @@ voluntary_context_switch (struct chx_thread *tp_next)
"add sp, #12\n\t"
"pop {pc}\n\t"
".L_CONTEXT_SWITCH_FINISH:\n\t"
"add r0, #16\n\t"
"adds r0, #16\n\t"
"ldr r0, [r0]" /* Get tp->v */
: "=r" (result) /* Return value in R0 */
: "0" (tp_next)
: "memory");
: "cc", "memory");
#endif
return (uintptr_t)result;
return result;
}
extern void cause_link_time_error_unexpected_size_of_struct_chx_thread (void);
@@ -470,119 +537,6 @@ chopstx_create_arch (uintptr_t stack_addr, size_t stack_size,
return tp;
}
/*
* Lower layer architecture specific exception handling entries.
*
*/
void __attribute__ ((naked))
preempt (struct chx_thread * tp_next)
{
register struct chx_thread *tp_current asm ("r1");
asm ( "ldr r2, =running\n\t"
"ldr r1, [r2]"
: "=r" (tp_current)
: /* no input */
: "r2");
if (!tp_current)
/* It's idle thread. No need to save registers. */
;
else
{
/* Save registers onto CHX_THREAD struct. */
asm volatile (
"add %0, #20\n\t"
"stm %0!, {r4, r5, r6, r7}\n\t"
"mov r2, r8\n\t"
"mov r3, r9\n\t"
"mov r4, r10\n\t"
"mov r5, r11\n\t"
"mrs r6, PSP\n\t" /* r13(=SP) in user space. */
"stm %0!, {r2, r3, r4, r5, r6}"
: "=r" (tp_current)
: "0" (tp_current)
/*
* Memory clobber constraint here is not accurate, but this
* works. R7 keeps its value, but having "r7" here prevents
* use of R7 before this asm statement.
*/
: "r2", "r3", "r4", "r5", "r6", "r7", "memory");
tp_next = chx_running_preempted (tp_next);
}
/* Registers on stack (PSP): r0, r1, r2, r3, r12, lr, pc, xpsr */
asm volatile (
".L_CONTEXT_SWITCH:\n\t"
/* Now, r0 points to the thread to be switched. */
/* Put it to *running. */
"ldr r1, =running\n\t"
/* Update running. */
"str r0, [r1]\n\t"
#if defined(__ARM_ARCH_6M__)
"cmp r0, #0\n\t"
"beq 1f\n\t"
#else
"cbz r0, 1f\n\t"
#endif
/**/
"add r0, #20\n\t"
"ldm r0!, {r4, r5, r6, r7}\n\t"
#if defined(__ARM_ARCH_6M__)
"ldm r0!, {r1, r2, r3}\n\t"
"mov r8, r1\n\t"
"mov r9, r2\n\t"
"mov r10, r3\n\t"
"ldm r0!, {r1, r2}\n\t"
"mov r11, r1\n\t"
"msr PSP, r2\n\t"
#else
"ldr r8, [r0], #4\n\t"
"ldr r9, [r0], #4\n\t"
"ldr r10, [r0], #4\n\t"
"ldr r11, [r0], #4\n\t"
"ldr r1, [r0], #4\n\t"
"msr PSP, r1\n\t"
#endif
"mov r0, #0\n\t"
/* Unmask interrupts. */
#if defined(__ARM_ARCH_6M__)
"cpsie i\n\t"
#else
"msr BASEPRI, r0\n\t"
#endif
/**/
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
"bx r0\n"
"1:\n\t"
/* Spawn an IDLE thread. */
"ldr r0, =__main_stack_end__-32\n\t"
"msr PSP, r0\n\t"
"mov r1, #0\n\t"
"mov r2, #0\n\t"
"mov r3, #0\n\t"
"stm r0!, {r1, r2, r3}\n\t"
"stm r0!, {r1, r2, r3}\n\t"
"ldr r1, =chx_idle\n\t" /* PC = idle */
"mov r2, #0x010\n\t"
"lsl r2, r2, #20\n\t" /* xPSR = T-flag set (Thumb) */
"stm r0!, {r1, r2}\n\t"
/**/
/* Unmask interrupts. */
"mov r0, #0\n\t"
#if defined(__ARM_ARCH_6M__)
"cpsie i\n\t"
#else
"msr BASEPRI, r0\n"
#endif
/**/
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
"bx r0"
: /* no output */ : "r" (tp_next) : "memory");
}
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
/*
@@ -595,7 +549,7 @@ svc (void)
asm ("ldr r1, =running\n\t"
"ldr r1, [r1]\n\t"
"add r1, #20\n\t"
"adds r1, #20\n\t"
/* Save registers onto CHX_THREAD struct. */
"stm r1!, {r4, r5, r6, r7}\n\t"
"mov r2, r8\n\t"
@@ -605,14 +559,51 @@ svc (void)
"mrs r6, PSP\n\t" /* r13(=SP) in user space. */
"stm r1!, {r2, r3, r4, r5, r6}\n\t"
"ldr r0, [r6]\n\t"
"sub r1, #56\n\t"
"subs r1, #56\n\t"
"str r1, [r6]"
: "=r" (tp_next)
: /* no input */
: "r1", "r2", "r3", "r4", "r5", "r6", "memory");
: "cc", "r1", "r2", "r3", "r4", "r5", "r6", "memory");
asm volatile (
"b .L_CONTEXT_SWITCH"
/* Now, r0 points to the thread to be switched. */
/* Put it to *running. */
"ldr r1, =running\n\t"
/* Update running: chx_set_running */
"str r0, [r1]\n\t"
"cbz r0, 1f\n\t"
/**/
"adds r0, #20\n\t"
"ldm r0!, {r4, r5, r6, r7}\n\t"
"ldr r8, [r0], #4\n\t"
"ldr r9, [r0], #4\n\t"
"ldr r10, [r0], #4\n\t"
"ldr r11, [r0], #4\n\t"
"ldr r1, [r0], #4\n\t"
"msr PSP, r1\n\t"
/* Unmask interrupts. */
"movs r0, #0\n\t"
"msr BASEPRI, r0\n\t"
"subs r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
"bx r0\n"
"1:\n\t"
/* Spawn an IDLE thread. */
"ldr r0, =__main_stack_end__-32\n\t"
"msr PSP, r0\n\t"
"movs r1, #0\n\t"
"movs r2, #0\n\t"
"movs r3, #0\n\t"
"stm r0!, {r1, r2, r3}\n\t"
"stm r0!, {r1, r2, r3}\n\t"
"ldr r1, =chx_idle\n\t" /* PC = idle */
"movs r2, #0x010\n\t"
"lsls r2, r2, #20\n\t" /* xPSR = T-flag set (Thumb) */
"stm r0!, {r1, r2}\n\t"
/* Unmask interrupts. */
"movs r0, #0\n\t"
"msr BASEPRI, r0\n"
"subs r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
"bx r0"
: /* no output */ : "r" (tp_next) : "memory");
}
#endif

View File

@@ -2,7 +2,7 @@
* chopstx-gnu-linux.c - Threads and only threads: Arch specific code
* for GNU/Linux emulation
*
* Copyright (C) 2017, 2018, 2019 Flying Stone Technology
* Copyright (C) 2017, 2018, 2019, 2021 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
@@ -27,6 +27,16 @@
*
*/
/*
* NOTE: This code is not portable. It's intended for GNU/Linux.
*
* This implementation depends on the feature of SA_SIGINFO of Linux,
* which signal handler takes three arguments. Also, it depends on
* GNU C library for how to use the makecontext function on 64-bit
* machine.
*
*/
#include <unistd.h>
#include <ucontext.h>
#include <signal.h>
@@ -164,7 +174,13 @@ chx_idle (void)
if (sig == SIGALRM)
tp_next = chx_timer_expired ();
else
tp_next = chx_recv_irq (sig);
{
tp_next = chx_recv_irq (sig);
/* Exit when there is no waiter and it's INT or TERM. */
if (tp_next == NULL
&& (sig == SIGINT || sig == SIGTERM))
exit (1);
}
}
return tp_next;
@@ -260,14 +276,23 @@ preempted_context_switch (struct chx_thread *tp_next)
static uintptr_t
voluntary_context_switch (struct chx_thread *tp_next)
{
struct chx_thread *tp, *tp_prev;
if (!tp_next)
tp_next = chx_idle ();
struct chx_thread *tp;
struct chx_thread *tp_prev;
tp_prev = chx_running ();
chx_set_running (tp_next);
swapcontext (&tp_prev->tc, &tp_next->tc);
if (!tp_next)
{
chx_set_running (NULL);
tp_next = chx_idle ();
chx_set_running (tp_next);
if (tp_prev != tp_next)
swapcontext (&tp_prev->tc, &tp_next->tc);
}
else
{
chx_set_running (tp_next);
swapcontext (&tp_prev->tc, &tp_next->tc);
}
chx_cpu_sched_unlock ();
tp = chx_running ();
@@ -298,13 +323,22 @@ chopstx_create_arch (uintptr_t stack_addr, size_t stack_size,
* signal blocked. The sigmask will be cleared in chx_thread_start.
*/
chx_cpu_sched_lock ();
memset (tp, 0, sizeof (struct chx_thread));
getcontext (&tp->tc);
tp->tc.uc_stack.ss_sp = (void *)stack_addr;
tp->tc.uc_stack.ss_size = stack_size;
tp->tc.uc_link = NULL;
/*
* makecontext is hard to use in a portable way, actually.
*
* On 64-bit machine, according to the standard, it should be coded
* to specify int (== 32-bit for LP64 machine) arguments that follow
* ARGC, so it is not that correct to specify two 64-bit arguments
* here. However, GNU C library allows this.
*/
makecontext (&tp->tc, (void (*)(void))chx_thread_start,
4, thread_entry, arg);
2, thread_entry, arg);
chx_cpu_sched_unlock ();
return tp;
}

View File

@@ -2,7 +2,7 @@
* chopstx-riscv32.c - Threads and only threads: Arch specific code
* for RISC-V 32 IMAC (Bumblebee core)
*
* Copyright (C) 2019
* Copyright (C) 2019, 2021
* Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -514,7 +514,7 @@ voluntary_context_switch (struct chx_thread *tp_next)
*/
"# Call the IDLE function, interrupt masked.\n\t"
"mv tp,zero\n\t"
"csrw mscratch,tp\n\t"
"csrw mscratch,tp\n\t" /* chx_set_running */
"la sp,__main_stack_end__\n\t"
"call chx_idle\n"
".L_V_CONTEXT_SWITCH_BEGIN:\n"
@@ -523,7 +523,7 @@ voluntary_context_switch (struct chx_thread *tp_next)
"mv sp,%0\n\t"
RESTORE_CALLEE_SAVE_REGISTERS
/**/
"csrw mscratch,sp\n\t"
"csrw mscratch,sp\n\t" /* chx_set_running */
"lw a0,0(sp)\n\t"
"beqz a0,1f\n"
".L_RETURN_TO_PREEMPTED_THREAD:\n\t"
@@ -667,7 +667,7 @@ chx_handle_intr (void)
"mv sp,%0\n\t"
RESTORE_CALLEE_SAVE_REGISTERS
/**/
"csrw mscratch,sp\n\t"
"csrw mscratch,sp\n\t" /* chx_set_running */
"lw a0,0(sp)\n\t"
"bnez a0,.L_RETURN_TO_PREEMPTED_THREAD\n\t"
/**/

View File

@@ -1,7 +1,7 @@
/*
* chopstx.c - Threads and only threads.
*
* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020
* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021
* Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -460,7 +460,7 @@ chx_recv_irq (uint32_t irq_num)
break;
chx_spin_unlock (&q_intr.lock);
if (p)
if (p != (struct chx_pq *)&q_intr.q)
{
struct chx_px *px = (struct chx_px *)p;
@@ -949,7 +949,9 @@ chopstx_mutex_lock (chopstx_mutex_t *mutex)
* chopstx_mutex_unlock - Unlock the mutex
* @mutex: Mutex
*
* Unlock @mutex.
* Unlock @mutex. Note that Chopstx doesn't allow unlocking by
* non-owner of the lock. chopstx_mutex_unlock should be called
* by a thread which did chopstx_mutex_lock.
*/
void
chopstx_mutex_unlock (chopstx_mutex_t *mutex)

232
contrib/ackbtn-gnu-linux.c Normal file
View File

@@ -0,0 +1,232 @@
/*
* ackbtn-gnu-linux.c - Acknowledge button support for GNU/Linux
*
* Copyright (C) 2021 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
*
* Chopstx is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Chopstx is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As additional permission under GNU GPL version 3 section 7, you may
* distribute non-source form of the Program without the copy of the
* GNU GPL normally required by section 4, provided you inform the
* recipients of GNU GPL by a written offer.
*
*/
#include <pthread.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <chopstx.h>
#include <stdio.h>
#include <signal.h>
#include <sys/eventfd.h>
#include <poll.h>
#include <errno.h>
#include <stdlib.h>
static pthread_t tid_main;
static pthread_t tid_ui;
static pthread_mutex_t mutex;
static pthread_cond_t cond;
static int enabled;
static int event_fd;
static void
ackbtn_intr (int signum, siginfo_t *siginfo, void *arg)
{
extern void chx_sigmask (ucontext_t *uc);
extern void chx_handle_intr (int signum);
ucontext_t *uc = arg;
(void)signum;
(void)siginfo;
chx_handle_intr (SIGUSR2);
chx_sigmask (uc);
}
#define ACKBTN_ACKED (1 << 0)
#define ACKBTN_TIMEOUT (1 << 2)
static void *
user_interaction (void *arg)
{
struct pollfd pollfds[2];
(void)arg;
pollfds[0].fd = 0; /* standard input */
pollfds[0].events = POLLIN;
pollfds[1].fd = event_fd;
pollfds[1].events = POLLIN;
fputs ("User interaction thread for AckBtn started.\n", stdout);
while (1)
{
unsigned int acked_or_timeout = 0;
char buf[256];
pthread_mutex_lock (&mutex);
while (!enabled)
pthread_cond_wait (&cond, &mutex);
pthread_mutex_unlock (&mutex);
/* Consume all input if any. */
while (1)
{
int r;
pollfds[0].revents = 0;
r = poll (pollfds, 1, 0);
if (r < 0)
{
if (errno == EINTR)
continue;
perror ("poll");
exit (1);
}
if (r == 0)
break;
if ((pollfds[0].revents & POLLIN))
read (0, buf, sizeof buf);
}
fputs ("Type RET to acknowledge (or wait for timeout) > ", stdout);
fflush (stdout);
while (!acked_or_timeout)
{
pollfds[0].revents = 0;
pollfds[1].revents = 0;
if (poll (pollfds, 2, -1) < 0)
{
if (errno == EINTR)
continue;
perror ("poll");
exit (1);
}
if ((pollfds[0].revents & POLLIN))
{
read (0, buf, sizeof buf);
acked_or_timeout |= ACKBTN_ACKED;
}
if ((pollfds[1].revents & POLLIN))
acked_or_timeout |= ACKBTN_TIMEOUT;
}
pthread_mutex_lock (&mutex);
if ((acked_or_timeout & ACKBTN_ACKED))
{
if ((acked_or_timeout & ACKBTN_TIMEOUT))
/* No output of newline, as it follows timeout message. */
fputs ("Input ignored", stdout);
else
{
pthread_kill (tid_main, SIGUSR2);
fputs ("Acknowledged\n", stdout);
}
}
if ((acked_or_timeout & ACKBTN_TIMEOUT))
fputs ("\nTimeout\n", stdout);
while (enabled)
pthread_cond_wait (&cond, &mutex);
read (event_fd, buf, sizeof (uint64_t));
pthread_mutex_unlock (&mutex);
}
}
void
ackbtn_init (chopstx_intr_t *intr)
{
int r;
sigset_t sigset;
struct sigaction act;
event_fd = eventfd (0, EFD_CLOEXEC);
if (event_fd < 0)
{
perror ("eventfd");
exit (1);
}
pthread_mutex_init (&mutex, NULL);
pthread_cond_init (&cond, NULL);
enabled = 0;
sigemptyset (&sigset);
sigaddset (&sigset, SIGUSR2);
sigaddset (&sigset, SIGALRM);
tid_main = pthread_self ();
/* Launch the thread for user interaction. */
pthread_sigmask (SIG_BLOCK, &sigset, NULL);
r = pthread_create (&tid_ui, NULL, user_interaction, NULL);
if (r)
{
fprintf (stderr, "ackbtn_init: %s\n", strerror (r));
exit (1);
}
act.sa_sigaction = ackbtn_intr;
sigfillset (&act.sa_mask);
act.sa_flags = SA_SIGINFO|SA_RESTART;
sigaction (SIGUSR2, &act, NULL);
pthread_sigmask (SIG_UNBLOCK, &sigset, NULL);
chopstx_claim_irq (intr, SIGUSR2);
}
void
ackbtn_enable (void)
{
pthread_mutex_lock (&mutex);
enabled = 1;
pthread_cond_signal (&cond);
pthread_mutex_unlock (&mutex);
}
void
ackbtn_disable (void)
{
const uint64_t l = 1;
pthread_mutex_lock (&mutex);
enabled = 0;
write (event_fd, &l, sizeof (l));
pthread_cond_signal (&cond);
pthread_mutex_unlock (&mutex);
}

View File

@@ -3,7 +3,7 @@
* This ADC driver just fills pseudo random values.
* It's completely useless other than for NeuG.
*
* Copyright (C) 2017 Free Software Initiative of Japan
* Copyright (C) 2017, 2021 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
@@ -33,7 +33,7 @@
#include <chopstx.h>
#include "adc.h"
#define ADC_RANDOM_SEED 0x01034649 /* "Hello, father!" in Japanese */
#include <sys/random.h>
/*
* Do calibration for ADC.
@@ -41,7 +41,6 @@
int
adc_init (void)
{
srandom (ADC_RANDOM_SEED);
return 0;
}
@@ -55,8 +54,7 @@ uint32_t adc_buf[64];
void
adc_start_conversion (int offset, int count)
{
while (count--)
adc_buf[offset++] = random ();
getrandom (adc_buf+offset, count, 0);
}

View File

@@ -1,7 +1,7 @@
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename chopstx.info
@set VERSION 2.0
@set VERSION 2.3
@settitle Chopstx Reference Manual
@c Unify some of the indices.
@syncodeindex tp fn
@@ -11,7 +11,7 @@
This manual is for Chopstx (version @value{VERSION}).
@noindent
Copyright @copyright{} 2013, 2015, 2016, 2017, 2018, 2019, 2020 Flying Stone Technology @*
Copyright @copyright{} 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Flying Stone Technology @*
@quotation
Permission is granted to copy, distribute and/or modify this document
@@ -91,7 +91,7 @@ Indexes
Chopstx is an RT thread library for ARM Cortex-M0, Cortex-M0plus,
Cortex-M3, Cortex-M4 with no FPU or DSP, RISC-V Bumblebee, and
GNU/Linux emulation. Specifically, it is used for STM32F030, MKL27Z,
STM32F103, GD32F103, STM32L432, GD32V103 and as a command on
STM32F103, GD32F103, STM32L432, GD32VF103 and as a command on
GNU/Linux.
While most RTOSes come with many features, drivers, and stacks,
@@ -126,7 +126,7 @@ done by interrupt handler, bottom half, and thead is crucial for
applications' performance. And because the demarcation should be done
at an early stage of an application development, it has a tendency,
many parts are getting demanding higher priority. Amount of code for
higher priority interrupt hander is getting bigger and bigger, while
higher priority interrupt handler is getting bigger and bigger, while
losing performance.
On the other hand, ``Threads (and only Threads)'' programming style
@@ -239,7 +239,7 @@ chx_handle_intr entries.
Obviously, this is suboptimal. It kills the hardware effort to
decrease interrupt latency.
I is certainly possible to support configurable vector table and/or
It is certainly possible to support configurable vector table and/or
better dispatch.
The reason why I keep this badness is that I believe that when

View File

@@ -1,7 +1,7 @@
/*
* entry-cortex-m.c - Entry routine when reset and interrupt vectors.
*
* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2019
* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2019, 2021
* Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -65,23 +65,6 @@ extern uint8_t __main_stack_end__;
extern void svc (void);
#endif
/*
* In ARMv6-M Architecture Reference Manual and ARM v7-M Architecture
* Reference Manual, you can find a section B1.5.12 for tail-chaining.
*
* B1.5.12 Exceptions on exception return, and tail-chaining exceptions
*/
/*
* Because it is tail-chained, the preempt function has an argument
* with type of (struct chx_thread *), in fact.
*/
extern void preempt (void);
/*
* Following functions return type of (struct chx_thread *) for
* tail-chained function (the preempt function), for its argument.
*/
extern void chx_timer_handler (void);
extern void chx_handle_intr (void);
static void nmi (void)
@@ -130,7 +113,7 @@ entry (void)
{
asm volatile ("bl clock_init\n\t"
/* Clear BSS section. */
"mov r0, #0\n\t"
"movs r0, #0\n\t"
"ldr r1, =_bss_start\n\t"
"ldr r2, =_bss_end\n"
"0:\n\t"
@@ -138,7 +121,7 @@ entry (void)
"beq 1f\n\t"
#if defined(__ARM_ARCH_6M__)
"str r0, [r1]\n\t"
"add r1, #4\n\t"
"adds r1, #4\n\t"
#else
"str r0, [r1], #4\n\t"
#endif
@@ -154,8 +137,8 @@ entry (void)
#if defined(__ARM_ARCH_6M__)
"ldr r0, [r3]\n\t"
"str r0, [r1]\n\t"
"add r3, #4\n\t"
"add r1, #4\n\t"
"adds r3, #4\n\t"
"adds r1, #4\n\t"
#else
"ldr r0, [r3], #4\n\t"
"str r0, [r1], #4\n\t"
@@ -164,9 +147,9 @@ entry (void)
"3:\n\t"
/* Switch to PSP. */
"ldr r0, =__process0_stack_end__\n\t"
COMPOSE_STATEMENT ("sub r0, #", CHOPSTX_THREAD_SIZE, "\n\t")
COMPOSE_STATEMENT ("subs r0, #", CHOPSTX_THREAD_SIZE, "\n\t")
"msr PSP, r0\n\t" /* Process (main routine) stack. */
"mov r1, #2\n\t"
"movs r1, #2\n\t"
"msr CONTROL, r1\n\t"
"isb\n\t"
"bl chx_init\n\t"
@@ -174,7 +157,7 @@ entry (void)
"bl gpio_init\n\t"
/* Enable interrupts. */
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
"mov r0, #0\n\t"
"movs r0, #0\n\t"
"msr BASEPRI, r0\n\t"
#endif
"cpsie i\n\t"
@@ -208,8 +191,8 @@ handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
#endif
none, /* Debug */
none, /* reserved */
preempt, /* PendSV */
chx_timer_handler, /* SysTick */
none, /* PendSV */
chx_handle_intr, /* SysTick */
/* 0x40 */
chx_handle_intr /* WWDG */, chx_handle_intr /* PVD */,
chx_handle_intr /* TAMPER */, chx_handle_intr /* RTC */,

View File

@@ -179,7 +179,14 @@ main (int argc, const char *argv[])
if (size < 0)
goto connection_loop;
if (size == 1)
if (size == 0)
/* Timeout */
{
if (tty_send (tty, "\r\n", 2) < 0)
return 0;
break;
}
else if (size == 1)
/* Do nothing but prompt again. */
break;
else if (size)

View File

@@ -904,8 +904,18 @@ tty_recv (struct tty *t, char *buf, uint32_t *timeout)
chopstx_mutex_lock (&t->mtx);
r = check_rx (t);
chopstx_mutex_unlock (&t->mtx);
if (r || (timeout != NULL && *timeout == 0))
if (r)
break;
else if (timeout != NULL && *timeout == 0)
{
int i;
/* Cancel the input. */
for (i = 0; i < t->inputline_len; i++)
tty_send (t, "\x08\x20\x08", 3);
t->inputline_len = 0;
break;
}
}
chopstx_mutex_lock (&t->mtx);

View File

@@ -1,7 +1,7 @@
/*
* reset.c - No system routines, but only RESET handler for STM32F030.
*
* Copyright (C) 2015 Flying Stone Technology
* Copyright (C) 2015, 2021 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* Copying and distribution of this file, with or without modification,
@@ -19,10 +19,10 @@ reset (void)
{
asm volatile ("cpsid i\n\t" /* Mask all interrupts. */
"mov r0, pc\n\t" /* r0 = PC & ~0x0fff */
"mov r1, #0x10\n\t"
"lsl r1, #8\n\t"
"sub r1, r1, #1\n\t"
"bic r0, r0, r1\n\t"
"movs r1, #0x10\n\t"
"lsls r1, #8\n\t"
"subs r1, #1\n\t"
"bics r0, r0, r1\n\t"
"ldr r2, [r0]\n\t"
"msr MSP, r2\n\t" /* Main (exception handler) stack. */
"b entry\n\t"
@@ -31,8 +31,6 @@ reset (void)
}
extern uint8_t __main_stack_end__;
extern void preempt (void);
extern void chx_timer_handler (void);
extern void chx_handle_intr (void);
static void nmi (void)
@@ -84,8 +82,8 @@ handler vector[] __attribute__ ((section(".vectors"))) = {
none, /* SVCall */
none, /* Debug */
none, /* reserved */
preempt, /* PendSV */
chx_timer_handler, /* SysTick */
none, /* PendSV */
chx_handle_intr, /* SysTick */
/* 0x40 */
chx_handle_intr /* WWDG */, chx_handle_intr /* PVD */,
chx_handle_intr /* TAMPER */, chx_handle_intr /* RTC */,

View File

@@ -1,7 +1,7 @@
/*
* usb-usbip.c - USB Device Emulation (server side) by USBIP
*
* Copyright (C) 2017, 2018 g10 Code GmbH
* Copyright (C) 2017, 2018, 2021 g10 Code GmbH
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
@@ -22,10 +22,26 @@
*/
/*
FIXME:
RESET handling
USB Shutdown
Use reply structure of its own
* This driver is intended to emulate USB full-speed device, which
* maximum packet size is 64.
*
* "USBIP" is actually URB over network (instead of USB packet over
* network), and its (current) naive protocol may expose possible
* demarcation problem, which never occurs in real host-device; In
* real host-device relationship, it is host side, which does
* composition/decomposition of URB to/from packets. In an
* implmentation of USB device with USBIP, it needs to be device side,
* which does composition/decomposition of URB to/from packets.
*
* In this implementation of USB driver, URB_DATA_SIZE is defined as
* (65544+10), because (major) target device intended is CCID. In the
* CCID specification, you can find the value 65544+10.
*/
/*
* FIXME:
* RESET handling
* USB Shutdown
* Use reply structure of its own
*/
#include <pthread.h>
@@ -96,7 +112,7 @@ struct urb {
struct urb *next;
struct urb *prev;
uint16_t remain;
uint32_t remain;
char *data_p;
pthread_t tid;
@@ -236,7 +252,67 @@ attach_device (char busid[32], size_t *len_p)
return (const char *)&usbip_usb_device;
}
#define URB_DATA_SIZE 65535
/*
* The number 65544 comes from ISO 7816-4, which defines data format
* of smartcard; CLS INS P1 P2 occupies four octets. Then, Lc-octet
* to represent size of command data block, then command data block.
* Lastly, Le-octet to represent size of response data block to be
* returned.
*
* /----- for CLS INS P1 P2
* |
* | /-- for Lc
* | |
* | | /-- for data block
* | | |
* | | | /-- for Le
* | | | |
* v v v v
* 4 + 3 + 65535 + 2 = 65544
*
* The number 10 comes from the CCID protocol specification; It is the
* header size of CCID. Besides, we can find the number 65544 in the
* CCID protocol specification, too.
*
* And... we have "AND ONE MORE" three times.
*
* We accept that, as Buddha did.
*
* There are different interpretations for the historical fact and the
* idiom. Most likely, nowadays, here, third-time is considered a
* strikeout, perhaps, due to popularity of baseball.
*/
#define URB_DATA_SIZE (65544+10+1+1+1)
/*
* The reasons why there are "+1" three times.
*
* Wrong (1): +1, because of confusion of data size maximum.
* Wrong (2): +1, because of confusion of the size for Le.
* Wrong (3): +1, because of keeping applying old patch.
*
* Something like this may occur, unfortunately, in our world.
*
* We need to consider the real case of the max buffer size for
* libusb_bulk_transfer with CCID (let us call this "CASE_MAX").
*
* (1) Although the data size maximum (for all cases) is 65536, it
* only occurs when Le size is zero. In the particular case of
* CASE_MAX, it is actually 65535. When just applying the max value
* 65536, +1 occurs.
*
* (2) Although maximum size to represent Le is 3, it only occurs when
* Lc size is zero. In the particular case of CASE_MAX, it is
* actually 2. When just applying the max value 3, +1 occurs.
*
* (3) Fedora keeps a old patch for Ominikey 3121. The patch was
* written when the value of CMD_BUF_SIZE in libccid was small for
* short extended APDU exchange. In the patch, it uses the value 11
* for the header size (instead of 10) of TPDU, for its special
* support. Historically, CMD_BUF_SIZE in libccid was updated
* to bigger value to handle extended APDU exchange. When just applying
* the old patch using 11, +1 occurs.
*/
struct usbip_msg_cmd {
uint32_t devid;
@@ -299,12 +375,14 @@ static int write_data_transaction (struct usb_control *usbc_p,
static int read_data_transaction (struct usb_control *usbc_p,
int ep_num, char *buf, uint16_t count);
#define USB_MAX_PACKET_SIZE 64 /* For USB fullspeed device. */
static int
hc_handle_control_urb (struct urb *urb)
{
int r;
uint16_t count;
uint16_t remain = urb->len;
uint32_t remain = urb->len;
uint64_t l;
if ((debug & DEBUG_USB))
@@ -325,10 +403,10 @@ hc_handle_control_urb (struct urb *urb)
while (r == 0)
{
if (remain > 64)
count = 64;
if (remain > USB_MAX_PACKET_SIZE)
count = USB_MAX_PACKET_SIZE;
else
count = remain;
count = (uint16_t)remain;
read (usbc_ep0.eventfd, &l, sizeof (l));
r = control_write_data_transaction (urb->data_p, count);
@@ -337,7 +415,7 @@ hc_handle_control_urb (struct urb *urb)
urb->data_p += count;
remain -= count;
if (count < 64)
if (count < USB_MAX_PACKET_SIZE)
break;
}
if (r >= 0)
@@ -353,10 +431,10 @@ hc_handle_control_urb (struct urb *urb)
while (1)
{
if (remain > 64)
count = 64;
if (remain > USB_MAX_PACKET_SIZE)
count = USB_MAX_PACKET_SIZE;
else
count = remain;
count = (uint16_t)remain;
read (usbc_ep0.eventfd, &l, sizeof (l));
r = control_read_data_transaction (urb->data_p, count);
@@ -368,7 +446,7 @@ hc_handle_control_urb (struct urb *urb)
remain -= r;
urb->data_p += r;
if (r < 64)
if (r < USB_MAX_PACKET_SIZE)
break;
}
@@ -516,10 +594,10 @@ hc_handle_data_urb (struct usb_control *usbc_p)
if ((debug & DEBUG_USB))
puts ("hc_hdu 0");
if (urb->remain > 64)
count = 64;
if (urb->remain > USB_MAX_PACKET_SIZE)
count = USB_MAX_PACKET_SIZE;
else
count = urb->remain;
count = (uint16_t)urb->remain;
if (urb->dir == USBIP_DIR_OUT)
{ /* Output from host to device. */
@@ -533,7 +611,7 @@ hc_handle_data_urb (struct usb_control *usbc_p)
urb->data_p += count;
urb->remain -= count;
if (urb->remain == 0 || count < 64)
if (urb->remain == 0 || count < USB_MAX_PACKET_SIZE)
{
size_t len = urb->len - urb->remain;
@@ -565,7 +643,7 @@ hc_handle_data_urb (struct usb_control *usbc_p)
urb->remain -= r;
urb->data_p += r;
if (urb->remain == 0 || r < 64)
if (urb->remain == 0 || r < USB_MAX_PACKET_SIZE)
{
size_t len = urb->len - urb->remain;
@@ -596,7 +674,7 @@ issue_get_desc (void)
{
struct urb *urb;
urb = malloc (sizeof (struct urb) + 64);
urb = malloc (sizeof (struct urb) + USB_MAX_PACKET_SIZE);
urb->next = urb->prev = urb;
@@ -606,14 +684,14 @@ issue_get_desc (void)
urb->setup[3] = 1; /* Value H: desc_type */
urb->setup[4] = 0; /* Index */
urb->setup[5] = 0;
urb->setup[6] = 64; /* Length */
urb->setup[6] = USB_MAX_PACKET_SIZE; /* Length */
urb->setup[7] = 0;
urb->data_p = urb->data;
urb->seq = 0;
urb->devid = 0;
urb->dir = USBIP_DIR_IN;
urb->ep = 0;
urb->remain = urb->len = 64;
urb->remain = urb->len = USB_MAX_PACKET_SIZE;
hc_handle_control_urb (urb);
return urb;
}
@@ -729,7 +807,7 @@ usbip_handle_urb (uint32_t seq)
leave:
msg.cmd = htonl (REP_URB_SUBMIT);
msg.seq = htonl (urb->seq);
msg.seq = htonl (seq);
memset (&msg_rep, 0, sizeof (msg_rep));
msg_rep.status = htonl (r);
@@ -1080,6 +1158,11 @@ usbip_run_server (void *arg)
exit (1);
}
fputs ("USBIP thread started.\n", stdout);
fputs ("You can use this by attaching following commands:\n", stdout);
fputs (" # modprobe vhci_hcd\n", stdout);
fputs (" # usbip attach -r 127.0.0.1 -b 1-1\n", stdout);
pollfds[1].fd = shutdown_notify_fd;
pollfds[1].events = POLLIN;
pollfds[1].revents = 0;

View File

@@ -71,7 +71,7 @@ MCFLAGS = -march=rv32imac -mabi=ilp32
LDFLAGS = $(MCFLAGS) -nodefaultlibs -nostartfiles -lc -T$(LDSCRIPT) \
-Wl,-Map=$(BUILDDIR)/$(PROJECT).map,--cref,--no-warn-mismatch
else
MCFLAGS = -mcpu=$(MCU)
MCFLAGS = -mcpu=$(MCU) -masm-syntax-unified
LDFLAGS = $(MCFLAGS) -nostartfiles -T$(LDSCRIPT) \
-Wl,-Map=$(BUILDDIR)/$(PROJECT).map,--cref,--no-warn-mismatch,--gc-sections
endif