Assembler code in __range_ok macros - linux

Can you explain me this code ? I really don't understand it.
See http://lxr.free-electrons.com/source/arch/arm/include/asm/uaccess.h#L70
#define __addr_ok(addr) ({ \
unsigned long flag; \
__asm__("cmp %2, %0; movlo %0, #0" \
: "=&r" (flag) \
: "" (current_thread_info()->addr_limit), "r" (addr) \
: "cc"); \
(flag == 0); })
/* We use 33-bit arithmetic here... */
#define __range_ok(addr,size) ({ \
unsigned long flag, roksum; \
__chk_user_ptr(addr); \
__asm__("adds %1, %2, %3; sbcccs %1, %1, %0; movcc %0, #0" \
: "=&r" (flag), "=&r" (roksum) \
: "r" (addr), "Ir" (size), "" (current_thread_info()->addr_limit) \
: "cc"); \
flag; })
This is from ARM Linux kernel, __range_ok

As a general source of info regarding the register usage and other decorations, look at the docs for GCC Extended Inline Assembly
I suggest you run this source through
gcc .... -S
to see what the resultant assmebly generated is.
You could also run
objdump -dC -S <objectfile.o>
You will need objdump from your cross-compiler toolchain.
Also, compile with debug information to get source annotation (-S).
Compile with -O0 to avoid confusion due to optimization.

Related

What language is this old program written in?

"Hi, could you rewrite something for me", my boss said, "some legacy code". Yeah, legacy code written somewhere in early Mesozoic.
I have 30 hours left, and I still don't know, what kind of syntax is this! VHLD? VBA? Program is dedicated do to something with audio files, and dedicated to run under DOS.
Could you give me a hint what is this? How to compile it?
Code snippet:
enter \ Load - main screen
empty forth definitions decimal
application warning on
: TITLE ." KCS version 0.8 28-Jan-06" cr ;
cr .( Compiling: ) title 2 load
cr .( Save to disk? ) y/n
[if]
\ pad reserve # + 256 + limit s0 # - + set-limit
turnkey program KCS
[then]
\ Load - defaults
variable RESERVE 0 reserve ! \ reserved memory tally
defer ?BREAK ' noop is ?break \ break check off
defer SET-IO ' bios-io is set-io \ default console mode
defer ERRFIX ' noop is errfix \ reset on-error handler
blk # 1+ #screens 1- thru \ load electives & application
' (?break) is ?break \ enable user break
\ ' dos-io is set-io \ enable console redirection
\ ' deloutfile +is errfix \ delete outfile on error
\ wrtchk off \ disable overwrite check
\ Load - electives
1 fload DOSLIB \ load DOSLIB library
_Errors \ error handler
_Inout1 \ number output
_Inout2 \ string & number input
_String1 \ basic strings
\ _String2 \ extra strings
_Parsing \ command-line parsing
_Fileprims \ file primitives
_Files \ default files
_Bufinfile \ buffered input file
_Bufoutfile \ buffered output file
\ DECODE
\ Convert wave file to program
: DECODE ( -- )
0. decodecount 2! 0. paritycount 2! 0 errors !
skipheader
begin
['] decodebyte 1 ?catch 0=
while ( not EOF )
conout # if emit else writechar then
1 decodecount m+!
repeat
.decoded ;
\ SETMODE
\ Select Kansas City Standard or Processor Tech. CUTS mode
: SETMODE ( -- )
mode # if ( CUTS )
8 to databits 2 sbits ! 4 speed ! parity off pace off
nullcnt off
['] 0bit-sqr-cuts is 0bit-sqr ['] 1bit-sqr-cuts is 1bit-sqr
['] 0bit-sin-cuts is 0bit-sin ['] 1bit-sin-cuts is 1bit-sin
['] seekstart-cuts is seekstart ['] getbit-cuts is getbit
else ( KCS )
['] 0bit-sqr-kcs is 0bit-sqr ['] 1bit-sqr-kcs is 1bit-sqr
['] 0bit-sin-kcs is 0bit-sin ['] 1bit-sin-kcs is 1bit-sin
['] seekstart-kcs is seekstart ['] getbit-kcs is getbit
then ;
\ (RUN)
\ Run application
: (RUN) ( -- )
setmode
r/o openinfile
decoding # if
conout # 0= if r/w makeoutfile then
cr decode
else
r/w makeoutfile
cr encode
then
closefiles
;
\ DEFAULTS
\ Set application defaults
: DEFAULTS ( -- )
mode off decoding on strict off ignore off conout off
1 speed ! 2 sbits ! parity off 5 leadtime ! 10 nullchar !
pace off nullcnt off wave off tone off inverted off ;
defaults
\ RUN PROGRAM
\ Run application with error handling
: RUN ( -- )
['] (run) catch ?dup if >r errfix r> throw then ;
\ Main
: PROGRAM ( -- )
set-io \ set console mode
defaults \ set defaults
cr title \ show application name
parsecmd \ get options/filenames
run \ run application
cr ." done" \ show success
;
It's written in Forth, probably the DX-Forth dialect. The program decodes and encodes WAVE files that contain data in the Kansas City standard format. This format was used to record data on cassette tapes on early S-100 CP/M machines. Searching the web reveals that there was a program written in DX-Forth that could decode and encode WAVE files in this format, so I'm guessing it's the program you've be tasked with rewriting.
Rather than rewriting this code however, a simpler thing to do would be to use existing free software that already does the job. For example there's a program called py-kcs written in Python that should be a functional replacement and one called hx-kcs written in Haxe that can do decoding.

Linux try_cmpxchg mysterious inline assembly

I need some help understanding Linux's `try_cmpxchg semantics and implementation. In the kernel source, it is implemented as:
#define __raw_try_cmpxchg(_ptr, _pold, _new, size, lock) \
({ \
bool success; \
__typeof__(_ptr) _old = (_pold); \
__typeof__(*(_ptr)) __old = *_old; \
__typeof__(*(_ptr)) __new = (_new); \
switch (size) { \
case __X86_CASE_B: \
{ \
volatile u8 *__ptr = (volatile u8 *)(_ptr); \
asm volatile(lock "cmpxchgb %[new], %[ptr]" \
CC_SET(z) \
: CC_OUT(z) (success), \
[ptr] "+m" (*__ptr), \
[old] "+a" (__old) \
: [new] "q" (__new) \
: "memory"); \
break; \
} \
case __X86_CASE_W: \
{ \
volatile u16 *__ptr = (volatile u16 *)(_ptr); \
asm volatile(lock "cmpxchgw %[new], %[ptr]" \
CC_SET(z) \
: CC_OUT(z) (success), \
[ptr] "+m" (*__ptr), \
[old] "+a" (__old) \
: [new] "r" (__new) \
: "memory"); \
break; \
} \
case __X86_CASE_L: \
{ \
volatile u32 *__ptr = (volatile u32 *)(_ptr); \
asm volatile(lock "cmpxchgl %[new], %[ptr]" \
CC_SET(z) \
: CC_OUT(z) (success), \
[ptr] "+m" (*__ptr), \
[old] "+a" (__old) \
: [new] "r" (__new) \
: "memory"); \
break; \
} \
case __X86_CASE_Q: \
{ \
volatile u64 *__ptr = (volatile u64 *)(_ptr); \
asm volatile(lock "cmpxchgq %[new], %[ptr]" \
CC_SET(z) \
: CC_OUT(z) (success), \
[ptr] "+m" (*__ptr), \
[old] "+a" (__old) \
: [new] "r" (__new) \
: "memory"); \
break; \
} \
default: \
__cmpxchg_wrong_size(); \
} \
if (unlikely(!success)) \
*_old = __old; \
likely(success); \
})
#define __try_cmpxchg(ptr, pold, new, size) \
__raw_try_cmpxchg((ptr), (pold), (new), (size), LOCK_PREFIX)
#define try_cmpxchg(ptr, pold, new) \
__try_cmpxchg((ptr), (pold), (new), sizeof(*(ptr)))
I am curious what those CC_SET and CC_OUT means. They are defined as:
/*
* Macros to generate condition code outputs from inline assembly,
* The output operand must be type "bool".
*/
#ifdef __GCC_ASM_FLAG_OUTPUTS__
# define CC_SET(c) "\n\t/* output condition code " #c "*/\n"
# define CC_OUT(c) "=#cc" #c
#else
# define CC_SET(c) "\n\tset" #c " %[_cc_" #c "]\n"
# define CC_OUT(c) [_cc_ ## c] "=qm"
#endif
Also, it would be great if you can explain the exact semantics of try_cmpxchg (not quite understand how can a atomic cmpxchg fail...)
Newer versions of gcc (I believe from version 6) support specific flag outputs. The macros are there to use this support if available, else fall back to the old way by doing a setCC instruction and a temporary output.
As to how cmpxchg can "fail": it does a compare so it fails if that compare fails, in which case the destination is unchanged and the current value is fetched from memory. Consult an instruction set reference for the details.

Linux 64 bit context switch

in the switch_to macro in 32 bit mode, there the following code is executed before the __switch_to function is called:
asm volatile("pushfl\n\t" /* save flags */ \
"pushl %%ebp\n\t" /* save EBP */ \
"movl %%esp,%[prev_sp]\n\t" /* save ESP */ \
"movl %[next_sp],%%esp\n\t" /* restore ESP */ \
"movl $1f,%[prev_ip]\n\t" /* save EIP */ \
"pushl %[next_ip]\n\t" /* restore EIP */ \
__switch_canary \
"jmp __switch_to\n" /* regparm call */
The EIP is pushed onto the stack (restore EIP). When __switch_to finishes, there is a ret which returns to that location.
Here is the corrsponding 64 bit code:
asm volatile(SAVE_CONTEXT \
"movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */ \
"movq %P[threadrsp](%[next]),%%rsp\n\t" /* restore RSP */ \
"call __switch_to\n\t"
There, only the rsp is saved and restored. I think that the RIP is already at
the top of stack. But I cannot find the instruction where that is done.
How is the 64 bit context switch, especially for the RIP register, actually done?
Thanks in advance!
In 32 bit kernel, the thread.ip may be one of:
the 1 label in switch_to
ret_from_fork
ret_from_kernel_thread
The return to the proper place is ensured by simulating a call using a push + jmp pair.
In 64 bit kernel, thread.ip is not used like this. Execution always continues after the call (which used to be the 1 label in the 32 bit case). As such, there is no need to emulate the call, it can be done normally. Dispatching to ret_from_fork happens using a conditional jump after __switch_to returns (you have omitted this part):
#define switch_to(prev, next, last) \
asm volatile(SAVE_CONTEXT \
"movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */ \
"movq %P[threadrsp](%[next]),%%rsp\n\t" /* restore RSP */ \
"call __switch_to\n\t" \
"movq "__percpu_arg([current_task])",%%rsi\n\t" \
__switch_canary \
"movq %P[thread_info](%%rsi),%%r8\n\t" \
"movq %%rax,%%rdi\n\t" \
"testl %[_tif_fork],%P[ti_flags](%%r8)\n\t" \
"jnz ret_from_fork\n\t" \
RESTORE_CONTEXT \
The ret_from_kernel_thread is incorporated into the ret_from_fork path, using yet another conditional jump in entry_64.S:
ENTRY(ret_from_fork)
DEFAULT_FRAME
LOCK ; btr $TIF_FORK,TI_flags(%r8)
pushq_cfi $0x0002
popfq_cfi # reset kernel eflags
call schedule_tail # rdi: 'prev' task parameter
GET_THREAD_INFO(%rcx)
RESTORE_REST
testl $3, CS-ARGOFFSET(%rsp) # from kernel_thread?
jz 1f

code for wait_event_interruptible

Where can I find the code for wait_event_interruptible in Kernel tree.
What I can find is wait_event_interruptible is defined as __wait_event_interruptible in . But I am unable to find the code .
Please help me out.
Consider a process which has gone to sleep by wait_event_interruptible. Suppose if there is an interrupt now and the interrupt handler wakes(wake_up_event_interruptible) up the sleeping process. For the process to wake up successfully should the condition given in wait_event_interruptible be true ?
Thanks
It's in include/linux/wait.h:
#define wait_event_interruptible(wq, condition) \
({ \
int __ret = 0; \
if (!(condition)) \
__wait_event_interruptible(wq, condition, __ret); \
__ret; \
})
...
#define __wait_event_interruptible(wq, condition, ret) \
do { \
DEFINE_WAIT(__wait); \
\
for (;;) { \
prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE); \
if (condition) \
break; \
if (!signal_pending(current)) { \
schedule(); \
continue; \
} \
ret = -ERESTARTSYS; \
break; \
} \
finish_wait(&wq, &__wait); \
} while (0)
Answering your second question, yes.
Whenever an interrrupt handler (or any other thread for that matter) calls wake_up() on the waitqueue, all the threads waiting in the waitqueue are woken up and they check their conditions. Only those threads whose conditions are true continue, the rest go back to sleep.
See waitqueues in LDD3.
Use ctags or cscope so that you can easily find definitions like these.

Building 16 bit os - character array not working

I am building a 16 bit operating system. But character array does not seem to work.
Here is my example kernel code:
asm(".code16gcc\n");
void putchar(char);
int main()
{
char *str = "hello";
putchar('A');
if(str[0]== 'h')
putchar('h');
return 0;
}
void putchar(char val)
{
asm("movb %0, %%al\n"
"movb $0x0E, %%ah\n"
"int $0x10\n"
:
:"m"(val)
) ;
}
It prints:
A
that means putchar function is working properly but
if(str[0]== 'h')
putchar('h');
is not working.
I am compiling it by:
gcc -fno-toplevel-reorder -nostdinc -fno-builtin -I./include -c -o ./bin/kernel.o ./source/kernel.c
ld -Ttext=0x9000 -o ./bin/kernel.bin ./bin/kernel.o -e 0x0
What should I do?
Your data segment is probably not loaded in to the target. What are you doing after the link with your brand new kernel.bin file, which is in fact an elf file ?

Resources