A sample and extended code snippnet for copying data between kernel and userland. please refer to 3.1.5 Accessing User Memory(https://web.stanford.edu/~ouster/cgi-bin/cs140-spring18/pintos/pintos_3.html#SEC39) for more details.
Last active
October 30, 2023 11:46
-
-
Save Stfort52/3e37fe90b0de04cc46db62ff4449ef9e to your computer and use it in GitHub Desktop.
inline assembly snippets for pintOS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @brief Get a user byte | |
* | |
* @param uaddr user address to get byte from | |
* @return char user byte obtained, can be -1 on segfault. | |
* | |
* please note that it's impossible to distinguish between real -1 and segment -1, | |
* outside of this function's context. | |
*/ | |
static char | |
get_user_byte (const uint8_t *uaddr) | |
{ | |
int result; | |
asm ("movl $1f, %0; movzbl %1, %0; 1:" | |
: "=&a" (result) : "m" (*uaddr)); | |
return result; | |
} | |
/** | |
* @brief Get a user dword | |
* | |
* @param uaddr user address to get byte from | |
* @return int user dword obtained, can be -1 on segfault. | |
* | |
* please note that it's impossible to distinguish between real -1 and segment -1, | |
* outside of this function's context. | |
*/ | |
static int | |
get_user_dword (const uint32_t *uaddr) | |
{ | |
int result; | |
asm ("movl $1f, %0; movl %1, %0; 1:" | |
: "=&a" (result) : "m" (*uaddr)); | |
return result; | |
} | |
/** | |
* @brief Get the user string | |
* | |
* @param uaddr user address to copy from | |
* @param kaddr kernel address to copy to | |
* @param length maximum copy length | |
* @return true succeeded to get user string | |
* @return false segmentation fault occured | |
* | |
* please note that `rep` prefixes check for ecx == 0 before they decrement. | |
*/ | |
static bool | |
get_user_str (char *uaddr, char *kaddr, size_t length) | |
{ | |
int result; | |
asm ("cld; movl $1f, %0; rep movsb; movl $0, %%eax; 1:" | |
: "=&a" (result), "+S" (uaddr), "+D" (kaddr), "+c" (length) : : "memory"); | |
return result == 0; | |
} | |
/** | |
* @brief Put string to userland | |
* | |
* @param uaddr user address to copy to | |
* @param kaddr kernel address to copy from | |
* @param length maximum copy length | |
* @return true succeeded to put string to userland | |
* @return false segmentation fault occured | |
* | |
* please note that `rep` prefixes check for ecx == 0 before they decrement. | |
*/ | |
static bool | |
put_user_str (char *uaddr, char *kaddr, size_t length) | |
{ | |
int result; | |
asm("cld; movl $1f, %0; rep movsb; movl $0, %%eax; 1:" | |
: "=&a" (result), "+D" (uaddr), "+S" (kaddr), "+c" (length) : : "memory"); | |
return result == 0; | |
} | |
/** | |
* @brief scan user string, finding byte. similar to strchr() | |
* | |
* @param uaddr user address to start searching | |
* @param byte the byte to search | |
* @param maxlen maximum search length | |
* @return char* pointer to the byte found. NULL if not found. -1 on segmentation fault | |
* | |
* please note that `loop` instructions, unlike `rep` instructions, decrement eax before they check. | |
* using scasb will really simplify this into a simple `cld; repne scasb` but scans are designed to work with eax/ax/al. | |
*/ | |
static char * | |
scan_user_str (char *uaddr, const uint8_t byte, size_t maxlen) | |
{ | |
char * result; | |
asm("movl $1f, %0; test %%ecx, %%ecx; jz 3f; \n" //if maxlen == 0 then GOTO 3f; fi | |
"2: movzbl (%%esi), %%edx; cmp %%edx, %%ebx; jz 4f; inc %%esi; loop 2b;\n" //while(maxlen) if *uaddr == byte then GOTO 4f; else then uaddr++; maxlen--; fi | |
"3: xor %%eax, %%eax; jmp 1f; \n" //return 0; | |
"4: movl %%esi, %%eax; 1:" //return uaddr; | |
: "=&a" (result), "+S" (uaddr), "+c" (maxlen): "b"(byte) : "memory", "edx"); | |
return result; | |
} | |
/** | |
* @brief copy string from userland to kernel, stop on meeting byte. | |
* | |
* @param uaddr user address to copy from | |
* @param kaddr kernel address to copy to | |
* @param byte terminator byte | |
* @param maxlen maximum size to copy | |
* @return size_t size actually copied, including the byte found. -1 on segmentation fault | |
* | |
* please note that `loop` instructions, unlike `rep` instructions, decrement eax before they check. | |
* using scasb will really simplify this into a simple `cld; repne scasb` but scans are designed to work with eax/ax/al. | |
*/ | |
static size_t | |
scan_copy_user_str (char *uaddr, char *kaddr, const uint8_t byte, size_t maxlen) | |
{ | |
size_t result, leftover; | |
asm("movl $1f, %0; test %%ecx, %%ecx; jz 1f; \n" //if maxlen == 0 then goto 1f; fi | |
"2: movzbl (%%esi), %%edx; movb %%dl, (%%edi); cmp %%edx, %%ebx; jz 3f; \n" | |
"inc %%esi; inc %%edi; loop 2b; jmp 1f; \n" // while(maxlen) *kaddr = *uaddr; if *uaddr == byte then GOTO 3f; else then uaddr++; kaddr++; maxlen--; fi GOTO 1f; | |
"3: dec %%ecx; 1:" //dec maxlen; | |
: "=&a" (result), "+S" (uaddr), "+D" (kaddr), "=c" (leftover) | |
: "c" (maxlen), "b"(byte) : "memory", "edx"); | |
return result == 0xffffffff ? -1 : maxlen - leftover; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment