Compare commits

...

No commits in common. "1c7aa6edda81e2a2138a69f2b7880a2c83b5a14a" and "a5e4d1920066b074918662d75f2455e33051c215" have entirely different histories.

286 changed files with 13983 additions and 3143 deletions

13
.gitignore vendored
View File

@ -1,3 +1,14 @@
kern/compile/
/.depend
/.settings
/.project
/.cproject
/.root
/kern/compile/
/defs.mk
build
/userland/testbin/randcall/calls.c
/root/
*.swo
*.swp
build/*
**/build

View File

@ -46,7 +46,6 @@ tools:
build:
(cd userland && $(MAKE) build)
(cd man && $(MAKE) install-staging)
(cd testscripts && $(MAKE) build)
includes tags depend:
(cd kern && $(MAKE) $@)

View File

@ -128,3 +128,4 @@ I would put the machine dependent stuffs in `kern/arch` and everything else outs
The function `splx()` and `splhigh()` is used to enable and restore interrupts
This would not be sufficient to ensure mutual exclusion as we still need spinlocks.

View File

@ -0,0 +1,46 @@
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <kern/secret.h>
#ifdef HOST
#include "hostcompat.h"
#endif
/* printf variant that is quiet during automated testing */
int
tprintf(const char *fmt, ...)
{
int chars;
va_list ap;
#ifdef SECRET_TESTING
return 0;
#endif
va_start(ap, fmt);
chars = vprintf(fmt, ap);
va_end(ap);
return chars;
}
/* printf variant that is loud during automated testing */
int
nprintf(const char *fmt, ...)
{
int chars;
va_list ap;
#ifndef SECRET_TESTING
return 0;
#endif
va_start(ap, fmt);
chars = vprintf(fmt, ap);
va_end(ap);
return chars;
}

2511
common/libtest161/config.h Normal file

File diff suppressed because it is too large Load Diff

206
common/libtest161/secure.c Normal file
View File

@ -0,0 +1,206 @@
// Beware, this code is shared between the kernel and userspace.
#ifdef _KERNEL
#include <types.h>
#include <lib.h>
#include <kern/errno.h>
#else
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#endif
#include <kern/secure.h>
#include "sha256.h"
// The full length (with null) of the hex string of a byte array
#define HEXLEN(a) 2*a+1
#define SHA256_BLOCK_SIZE 64
#define SHA256_OUTPUT_SIZE 32
// Keep this divisible by 4, or else change make_salt()
#define SALT_BYTES 8
// inner and outer padding for HMAC.
static const unsigned char ipad[SHA256_BLOCK_SIZE] = { [0 ... SHA256_BLOCK_SIZE-1] = 0x36 };
static const unsigned char opad[SHA256_BLOCK_SIZE] = { [0 ... SHA256_BLOCK_SIZE-1] = 0x5c };
// Hack for not having a userspace malloc until ASST3. We 'allocate' these statuc buffers.
// This works because the process single-threaded.
#define NUM_BUFFERS 4
#define BUFFER_LEN 1024
static char temp_buffers[NUM_BUFFERS][BUFFER_LEN];
static int buf_num = 0;
#ifndef _KERNEL
static int did_random = 0;
#define NSEC_PER_MSEC 1000000ULL
#define MSEC_PER_SEC 1000ULL
#endif
// Both userspace and the kernel are using the temp buffers now.
static void * _alloc(size_t size)
{
(void)size;
void *ptr = temp_buffers[buf_num];
buf_num++;
buf_num = buf_num % NUM_BUFFERS;
return ptr;
}
static void _free(void *ptr)
{
(void)ptr;
}
/*
* hamc_sha256 follows FIPS 198-1 HMAC using sha256.
* See http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf for details.
* NOTE: This is only thread-safe if called from within secprintf()!!!
*/
static int hmac_sha256(const char *msg, size_t msg_len, const char *key, size_t key_len,
unsigned char output[SHA256_OUTPUT_SIZE])
{
// We use a total of 320 bytes of array data on the stack
unsigned char k0[SHA256_BLOCK_SIZE];
// Steps 1-3. Anything less than 64 bytes gets 0s appended.
memset(k0, 0, SHA256_BLOCK_SIZE);
if (key_len <= SHA256_BLOCK_SIZE) {
memcpy(k0, key, key_len);
} else {
mbedtls_sha256((unsigned char *)key, key_len, k0, 0);
}
// Steps 4 and 7.
unsigned char k_ipad[SHA256_BLOCK_SIZE];
unsigned char k_opad[SHA256_BLOCK_SIZE];
int i;
for (i = 0; i < SHA256_BLOCK_SIZE; i++) {
k_ipad[i] = k0[i] ^ ipad[i];
k_opad[i] = k0[i] ^ opad[i];
}
// Step 5 (K0 xor ipad) || msg
// We have no idea how big the message is so we allocate this on the heap.
unsigned char *data = (unsigned char *)_alloc(msg_len + SHA256_BLOCK_SIZE);
if (!data)
return ENOMEM;
memcpy(data, k_ipad, SHA256_BLOCK_SIZE);
memcpy(data+SHA256_BLOCK_SIZE, msg, msg_len);
// Step6: H((k0 xor ipad) || msg)
unsigned char h1[SHA256_OUTPUT_SIZE];
mbedtls_sha256(data, msg_len + SHA256_BLOCK_SIZE, h1, 0);
_free(data);
// Step 8: (k0 xor opad) || H((k0 xor ipad) || msg)
unsigned char inner[SHA256_OUTPUT_SIZE + SHA256_BLOCK_SIZE];
memcpy(inner, k_opad, SHA256_BLOCK_SIZE);
memcpy(inner + SHA256_BLOCK_SIZE, h1, SHA256_OUTPUT_SIZE);
// Step 9: Finally, H((k0 xor opad) || H((k0 xor ipad) || msg))
mbedtls_sha256(inner, SHA256_OUTPUT_SIZE + SHA256_BLOCK_SIZE, output, 0);
return 0;
}
static inline char to_hex(int n)
{
return n < 10 ? '0'+n : 'a' + (n-10);
}
static void array_to_hex(unsigned char *a, size_t len, char *res)
{
size_t i, j;
j = 0;
for (i = 0; i < len; i++) {
res[j++] = to_hex(a[i] >> 4);
res[j++] = to_hex(a[i] & 0xF);
}
res[j] = '\0';
}
static void make_salt(char *salt_str)
{
#ifndef _KERNEL
if (!did_random) {
did_random = 1;
time_t sec;
unsigned long ns;
unsigned long long ms;
__time(&sec, &ns);
ms = (unsigned long long)sec * MSEC_PER_SEC;
ms += (ns / NSEC_PER_MSEC);
srandom((unsigned long)ms);
}
#endif
// Compute salt value
uint32_t salt[SALT_BYTES/sizeof(uint32_t)];
size_t i;
for (i = 0; i < SALT_BYTES/sizeof(uint32_t); i++)
{
salt[i] = random();
}
// Convert to hex string
array_to_hex((unsigned char *)salt, SALT_BYTES, salt_str);
}
int hmac(const char *msg, size_t msg_len, const char *key, size_t key_len,
char **hash_str)
{
*hash_str = _alloc(HEXLEN(SHA256_OUTPUT_SIZE));
if (!(*hash_str))
return ENOMEM;
// Hash it
unsigned char hash[SHA256_OUTPUT_SIZE];
int res = hmac_sha256(msg, msg_len, key, key_len, hash);
if (res)
return res;
// Convert to hex string
array_to_hex(hash, SHA256_OUTPUT_SIZE, *hash_str);
return 0;
}
// NOTE: This is only thread-safe if called from within secprintf()!!!
int hmac_salted(const char *msg, size_t msg_len, const char *key, size_t key_len,
char **hash_str, char **salt_str)
{
*salt_str = _alloc(HEXLEN(SALT_BYTES));
if (!(*salt_str))
return ENOMEM;
// Create the salt value
make_salt(*salt_str);
// Concatenate the key and salt, with the resulting string being null-terminated
size_t key2_len = key_len + HEXLEN(SALT_BYTES)-1;
char *key2 = (char *)_alloc(key2_len+1);
if (!key2)
return ENOMEM;
strcpy(key2, key);
strcpy(key2+key_len, *salt_str);
key2[key2_len] = '\0';
// Hash it
return hmac(msg, msg_len, key2, key2_len, hash_str);
}

451
common/libtest161/sha256.c Normal file
View File

@ -0,0 +1,451 @@
/*
* FIPS-180-2 compliant SHA-256 implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The SHA-256 Secure Hash Standard was published by NIST in 2002.
*
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_SHA256_C)
#include "sha256.h"
#ifdef _KERNEL
#include <types.h>
#include <lib.h>
#else
#include <types/size_t.h>
#include <string.h>
#endif // _KERNEL
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_SHA256_ALT)
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n,b,i) \
do { \
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \
| ( (uint32_t) (b)[(i) + 1] << 16 ) \
| ( (uint32_t) (b)[(i) + 2] << 8 ) \
| ( (uint32_t) (b)[(i) + 3] ); \
} while( 0 )
#endif
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n,b,i) \
do { \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
} while( 0 )
#endif
void mbedtls_sha256_init( mbedtls_sha256_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_sha256_context ) );
}
void mbedtls_sha256_free( mbedtls_sha256_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_zeroize( ctx, sizeof( mbedtls_sha256_context ) );
}
void mbedtls_sha256_clone( mbedtls_sha256_context *dst,
const mbedtls_sha256_context *src )
{
*dst = *src;
}
/*
* SHA-256 context setup
*/
void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 )
{
ctx->total[0] = 0;
ctx->total[1] = 0;
if( is224 == 0 )
{
/* SHA-256 */
ctx->state[0] = 0x6A09E667;
ctx->state[1] = 0xBB67AE85;
ctx->state[2] = 0x3C6EF372;
ctx->state[3] = 0xA54FF53A;
ctx->state[4] = 0x510E527F;
ctx->state[5] = 0x9B05688C;
ctx->state[6] = 0x1F83D9AB;
ctx->state[7] = 0x5BE0CD19;
}
else
{
/* SHA-224 */
ctx->state[0] = 0xC1059ED8;
ctx->state[1] = 0x367CD507;
ctx->state[2] = 0x3070DD17;
ctx->state[3] = 0xF70E5939;
ctx->state[4] = 0xFFC00B31;
ctx->state[5] = 0x68581511;
ctx->state[6] = 0x64F98FA7;
ctx->state[7] = 0xBEFA4FA4;
}
ctx->is224 = is224;
}
#if !defined(MBEDTLS_SHA256_PROCESS_ALT)
static const uint32_t K[] =
{
0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
};
#define SHR(x,n) ((x & 0xFFFFFFFF) >> n)
#define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3))
#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10))
#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
#define F0(x,y,z) ((x & y) | (z & (x | y)))
#define F1(x,y,z) (z ^ (x & (y ^ z)))
#define R(t) \
( \
W[t] = S1(W[t - 2]) + W[t - 7] + \
S0(W[t - 15]) + W[t - 16] \
)
#define P(a,b,c,d,e,f,g,h,x,K) \
{ \
temp1 = h + S3(e) + F1(e,f,g) + K + x; \
temp2 = S2(a) + F0(a,b,c); \
d += temp1; h = temp1 + temp2; \
}
void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] )
{
uint32_t temp1, temp2, W[64];
uint32_t A[8];
unsigned int i;
for( i = 0; i < 8; i++ )
A[i] = ctx->state[i];
#if defined(MBEDTLS_SHA256_SMALLER)
for( i = 0; i < 64; i++ )
{
if( i < 16 )
GET_UINT32_BE( W[i], data, 4 * i );
else
R( i );
P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] );
temp1 = A[7]; A[7] = A[6]; A[6] = A[5]; A[5] = A[4]; A[4] = A[3];
A[3] = A[2]; A[2] = A[1]; A[1] = A[0]; A[0] = temp1;
}
#else /* MBEDTLS_SHA256_SMALLER */
for( i = 0; i < 16; i++ )
GET_UINT32_BE( W[i], data, 4 * i );
for( i = 0; i < 16; i += 8 )
{
P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i+0], K[i+0] );
P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i+1], K[i+1] );
P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i+2], K[i+2] );
P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i+3], K[i+3] );
P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i+4], K[i+4] );
P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i+5], K[i+5] );
P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i+6], K[i+6] );
P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i+7], K[i+7] );
}
for( i = 16; i < 64; i += 8 )
{
P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i+0), K[i+0] );
P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i+1), K[i+1] );
P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i+2), K[i+2] );
P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i+3), K[i+3] );
P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i+4), K[i+4] );
P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i+5), K[i+5] );
P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i+6), K[i+6] );
P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i+7), K[i+7] );
}
#endif /* MBEDTLS_SHA256_SMALLER */
for( i = 0; i < 8; i++ )
ctx->state[i] += A[i];
}
#endif /* !MBEDTLS_SHA256_PROCESS_ALT */
/*
* SHA-256 process buffer
*/
void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input,
size_t ilen )
{
size_t fill;
uint32_t left;
if( ilen == 0 )
return;
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += (uint32_t) ilen;
ctx->total[0] &= 0xFFFFFFFF;
if( ctx->total[0] < (uint32_t) ilen )
ctx->total[1]++;
if( left && ilen >= fill )
{
memcpy( (void *) (ctx->buffer + left), input, fill );
mbedtls_sha256_process( ctx, ctx->buffer );
input += fill;
ilen -= fill;
left = 0;
}
while( ilen >= 64 )
{
mbedtls_sha256_process( ctx, input );
input += 64;
ilen -= 64;
}
if( ilen > 0 )
memcpy( (void *) (ctx->buffer + left), input, ilen );
}
static const unsigned char sha256_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
* SHA-256 final digest
*/
void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] )
{
uint32_t last, padn;
uint32_t high, low;
unsigned char msglen[8];
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_UINT32_BE( high, msglen, 0 );
PUT_UINT32_BE( low, msglen, 4 );
last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
mbedtls_sha256_update( ctx, sha256_padding, padn );
mbedtls_sha256_update( ctx, msglen, 8 );
PUT_UINT32_BE( ctx->state[0], output, 0 );
PUT_UINT32_BE( ctx->state[1], output, 4 );
PUT_UINT32_BE( ctx->state[2], output, 8 );
PUT_UINT32_BE( ctx->state[3], output, 12 );
PUT_UINT32_BE( ctx->state[4], output, 16 );
PUT_UINT32_BE( ctx->state[5], output, 20 );
PUT_UINT32_BE( ctx->state[6], output, 24 );
if( ctx->is224 == 0 )
PUT_UINT32_BE( ctx->state[7], output, 28 );
}
#endif /* !MBEDTLS_SHA256_ALT */
/*
* output = SHA-256( input buffer )
*/
void mbedtls_sha256( const unsigned char *input, size_t ilen,
unsigned char output[32], int is224 )
{
mbedtls_sha256_context ctx;
mbedtls_sha256_init( &ctx );
mbedtls_sha256_starts( &ctx, is224 );
mbedtls_sha256_update( &ctx, input, ilen );
mbedtls_sha256_finish( &ctx, output );
mbedtls_sha256_free( &ctx );
}
#if defined(MBEDTLS_SELF_TEST)
/*
* FIPS-180-2 test vectors
*/
static const unsigned char sha256_test_buf[3][57] =
{
{ "abc" },
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
{ "" }
};
static const int sha256_test_buflen[3] =
{
3, 56, 1000
};
static const unsigned char sha256_test_sum[6][32] =
{
/*
* SHA-224 test vectors
*/
{ 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22,
0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3,
0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7,
0xE3, 0x6C, 0x9D, 0xA7 },
{ 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC,
0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50,
0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19,
0x52, 0x52, 0x25, 0x25 },
{ 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8,
0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B,
0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE,
0x4E, 0xE7, 0xAD, 0x67 },
/*
* SHA-256 test vectors
*/
{ 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD },
{ 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 },
{ 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92,
0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67,
0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E,
0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 }
};
/*
* Checkup routine
*/
int mbedtls_sha256_self_test( int verbose )
{
int i, j, k, buflen, ret = 0;
unsigned char buf[1024];
unsigned char sha256sum[32];
mbedtls_sha256_context ctx;
mbedtls_sha256_init( &ctx );
for( i = 0; i < 6; i++ )
{
j = i % 3;
k = i < 3;
if( verbose != 0 )
mbedtls_printf( " SHA-%d test #%d: ", 256 - k * 32, j + 1 );
mbedtls_sha256_starts( &ctx, k );
if( j == 2 )
{
memset( buf, 'a', buflen = 1000 );
for( j = 0; j < 1000; j++ )
mbedtls_sha256_update( &ctx, buf, buflen );
}
else
mbedtls_sha256_update( &ctx, sha256_test_buf[j],
sha256_test_buflen[j] );
mbedtls_sha256_finish( &ctx, sha256sum );
if( memcmp( sha256sum, sha256_test_sum[i], 32 - k * 4 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto exit;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
exit:
mbedtls_sha256_free( &ctx );
return( ret );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_SHA256_C */

146
common/libtest161/sha256.h Normal file
View File

@ -0,0 +1,146 @@
/**
* \file sha256.h
*
* \brief SHA-224 and SHA-256 cryptographic hash function
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_SHA256_H
#define MBEDTLS_SHA256_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#ifdef _KERNEL
#include <types.h>
#include <lib.h>
#else
#include <types/size_t.h>
#include <stdint.h>
#endif //_KERNEL
#if !defined(MBEDTLS_SHA256_ALT)
// Regular implementation
//
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief SHA-256 context structure
*/
typedef struct
{
uint32_t total[2]; /*!< number of bytes processed */
uint32_t state[8]; /*!< intermediate digest state */
unsigned char buffer[64]; /*!< data block being processed */
int is224; /*!< 0 => SHA-256, else SHA-224 */
}
mbedtls_sha256_context;
/**
* \brief Initialize SHA-256 context
*
* \param ctx SHA-256 context to be initialized
*/
void mbedtls_sha256_init( mbedtls_sha256_context *ctx );
/**
* \brief Clear SHA-256 context
*
* \param ctx SHA-256 context to be cleared
*/
void mbedtls_sha256_free( mbedtls_sha256_context *ctx );
/**
* \brief Clone (the state of) a SHA-256 context
*
* \param dst The destination context
* \param src The context to be cloned
*/
void mbedtls_sha256_clone( mbedtls_sha256_context *dst,
const mbedtls_sha256_context *src );
/**
* \brief SHA-256 context setup
*
* \param ctx context to be initialized
* \param is224 0 = use SHA256, 1 = use SHA224
*/
void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 );
/**
* \brief SHA-256 process buffer
*
* \param ctx SHA-256 context
* \param input buffer holding the data
* \param ilen length of the input data
*/
void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input,
size_t ilen );
/**
* \brief SHA-256 final digest
*
* \param ctx SHA-256 context
* \param output SHA-224/256 checksum result
*/
void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] );
/* Internal use */
void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] );
#ifdef __cplusplus
}
#endif
#else /* MBEDTLS_SHA256_ALT */
#include "sha256_alt.h"
#endif /* MBEDTLS_SHA256_ALT */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Output = SHA-256( input buffer )
*
* \param input buffer holding the data
* \param ilen length of the input data
* \param output SHA-224/256 checksum result
* \param is224 0 = use SHA256, 1 = use SHA224
*/
void mbedtls_sha256( const unsigned char *input, size_t ilen,
unsigned char output[32], int is224 );
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int mbedtls_sha256_self_test( int verbose );
#ifdef __cplusplus
}
#endif
#endif /* mbedtls_sha256.h */

188
common/libtest161/test161.c Normal file
View File

@ -0,0 +1,188 @@
// Beware, this code is shared between the kernel and userspace.
#ifdef _KERNEL
#include <types.h>
#include <lib.h>
#include <synch.h>
#include <kern/errno.h>
#include <kern/secure.h>
#include <kern/test161.h>
#else
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <test161/test161.h>
#include <test161/secure.h>
#endif
// Hack for allocating userspace memory without malloc, and for
// allowing secprintf in kmalloc when we're out of memory.
#define BUFFER_SIZE 1024
static char temp_buffer[BUFFER_SIZE];
#ifndef _KERNEL
static char write_buffer[BUFFER_SIZE];
#endif
#ifdef _KERNEL
// secprintf needs to be synchronized in the kernel because multiple threads
// may be trying to secprintf at the same time.
static struct semaphore *test161_sem;
#endif
// For now, allocating just passes a reference to our static temp buffer, and
// free does nothing.
static inline void * _alloc()
{
return temp_buffer;
}
static inline void _free(void *ptr)
{
(void)ptr;
}
/*
* Common success function for kernel tests. If SECRET_TESTING is defined,
* ksecprintf will compute the hmac/sha256 hash of any message using the
* shared secret and a random salt value. The (secure) server also knows
* the secret and can verify the message was generated by a trusted source.
* The salt value prevents against replay attacks.
*/
int
success(int status, const char * secret, const char * name) {
if (status == TEST161_SUCCESS) {
return secprintf(secret, "SUCCESS", name);
} else {
return secprintf(secret, "FAIL", name);
}
}
int
partial_credit(const char *secret, const char *name, int scored, int total)
{
char buffer[128];
snprintf(buffer, 128, "PARTIAL CREDIT %d OF %d", scored, total);
return secprintf(secret, buffer, name);
}
#ifndef _KERNEL
// Borrowed from parallelvm. We need atomic console writes so our
// output doesn't get intermingled since test161 works with lines.
static
int
say(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsnprintf(write_buffer, BUFFER_SIZE, fmt, ap);
va_end(ap);
return write(STDOUT_FILENO, write_buffer, strlen(write_buffer));
}
#endif
#ifndef SECRET_TESTING
int
snsecprintf(size_t len, char *buffer, const char *secret, const char *msg, const char *name)
{
(void)secret;
return snprintf(buffer, len, "%s: %s", name, msg);
}
int
secprintf(const char * secret, const char * msg, const char * name)
{
(void)secret;
#ifdef _KERNEL
return kprintf("\n%s: %s\n", name, msg);
#else
return say("\n%s: %s\n", name, msg);
#endif
}
#else
static int
secprintf_common(int use_buf, size_t b_len, char *buffer,
const char *secret, const char *msg, const char *name)
{
char *hash, *salt, *fullmsg;
int res;
size_t len;
#ifdef _KERNEL
if (test161_sem == NULL) {
panic("test161_sem is NULL. Your kernel is missing test161_bootstrap.");
}
P(test161_sem);
#endif
hash = salt = fullmsg = NULL;
// test161 expects "name: msg"
len = strlen(name) + strlen(msg) + 3; // +3 for " :" and null terminator
fullmsg = (char *)_alloc(len);
if (fullmsg == NULL) {
res = -ENOMEM;
goto out;
}
snprintf(fullmsg, len, "%s: %s", name, msg);
res = hmac_salted(fullmsg, len-1, secret, strlen(secret), &hash, &salt);
if (res) {
res = -res;
goto out;
}
if (!use_buf) {
#ifdef _KERNEL
res = kprintf("\n(%s, %s, %s, %s: %s)\n", name, hash, salt, name, msg);
#else
res = say("\n(%s, %s, %s, %s: %s)\n", name, hash, salt, name, msg);
#endif
} else {
res = snprintf(buffer, b_len, "\n(%s, %s, %s, %s: %s)\n", name, hash, salt, name, msg);
}
out:
// These may be NULL, but that's OK
_free(hash);
_free(salt);
_free(fullmsg);
#ifdef _KERNEL
V(test161_sem);
#endif
return res;
}
int
snsecprintf(size_t b_len, char *buffer, const char *secret, const char *msg, const char *name)
{
return secprintf_common(1, b_len, buffer, secret, msg, name);
}
int
secprintf(const char * secret, const char * msg, const char * name)
{
return secprintf_common(0, 0, NULL, secret, msg, name);
}
#endif
#ifdef _KERNEL
void test161_bootstrap()
{
test161_sem = sem_create("test161", 1);
if (test161_sem == NULL) {
panic("Failed to create test161 secprintf semaphore");
}
}
#endif

28
configure vendored
View File

@ -29,9 +29,6 @@ DEBUG='-O2'
# when make runs rather than when this script runs.
OSTREE='$(HOME)/os161/root'
# By default don't explicitly configure a Python interpreter.
PYTHON_INTERPRETER=
# Assume this
HOST_CC=gcc
@ -137,28 +134,6 @@ else
HOST_CFLAGS="${HOST_CFLAGS} -DDECLARE_NTOHLL"
fi
# Look for a Python interpreter.
PYTHON=
for PYNAME in \
python python2.7 \
/usr/local/bin/python /usr/local/bin/python2.7 \
/usr/pkg/bin/python /usr/pkg/bin/python2.7 \
/opt/bin/python /opt/bin/python2.7 \
; do
PYVERSION=`($PYNAME -V) 2>&1 || echo none`
case "$PYVERSION" in
Python\ 2.*|Python\ 3.*) PYTHON=$PYNAME;;
none) ;;
*) ;; # ?
esac
done
case "$PYTHON" in
python) ;;
/*) PYTHON_INTERPRETER="$PYTHON";;
*) PYTHON_INTERPRETER="/usr/bin/env $PYTHON";;
esac
####################
# Now generate defs.mk.
@ -192,8 +167,5 @@ EOF
if [ "x$HOST_CFLAGS" != x ]; then
echo "HOST_CFLAGS+=$HOST_CFLAGS"
fi
if [ "x$PYTHON_INTERPRETER" != x ]; then
echo "PYTHON_INTERPRETER=$PYTHON_INTERPRETER"
fi
) > defs.mk

22
defs.mk
View File

@ -1,22 +0,0 @@
# This file was generated by configure. Edits will disappear if you rerun
# configure. If you find that you need to edit this file to make things
# work, let the course staff know and we'll try to fix the configure script.
#
# The purpose of this file is to hold all the makefile definitions
# needed to adjust the OS/161 build process to any particular
# environment. If I've done it right, all you need to do is rerun the
# configure script and make clean if you start working on a different
# host OS. If I've done it mostly right, you may need to edit this
# file but you still hopefully won't need to edit any of the
# makefiles.
#
# The things that can be set here are documented in mk/os161.config.mk.
#
OSTREE=/root/os161/root
PLATFORM=sys161
MACHINE=mips
COMPAT_CFLAGS= -DNEED_NTOHLL
COMPAT_TARGETS=
HOST_CFLAGS+= -DDECLARE_NTOHLL
PYTHON_INTERPRETER=/usr/bin/env

View File

@ -126,6 +126,15 @@ free_kpages(vaddr_t addr)
(void)addr;
}
unsigned
int
coremap_used_bytes() {
/* dumbvm doesn't track page allocations. Return 0 so that khu works. */
return 0;
}
void
vm_tlbshootdown(const struct tlbshootdown *ts)
{

33
kern/conf/ASST1 Normal file
View File

@ -0,0 +1,33 @@
# Kernel config file using dumbvm.
# This should be used until you have your own VM system.
include conf/conf.kern # get definitions of available options
debug # Compile with debug info.
#
# Device drivers for hardware.
#
device lamebus0 # System/161 main bus
device emu* at lamebus* # Emulator passthrough filesystem
device ltrace* at lamebus* # trace161 trace control device
device ltimer* at lamebus* # Timer device
device lrandom* at lamebus* # Random device
device lhd* at lamebus* # Disk device
device lser* at lamebus* # Serial port
#device lscreen* at lamebus* # Text screen (not supported yet)
#device lnet* at lamebus* # Network interface (not supported yet)
device beep0 at ltimer* # Abstract beep handler device
device con0 at lser* # Abstract console on serial port
#device con0 at lscreen* # Abstract console on screen (not supported)
device rtclock0 at ltimer* # Abstract realtime clock
device random0 at lrandom* # Abstract randomness device
#options net # Network stack (not supported)
options semfs # Semaphores for userland
options sfs # Always use the file system
#options netfs # You might write this as a project.
options dumbvm # Chewing gum and baling wire.
options synchprobs # Uncomment to enable ASST1 synchronization problems

33
kern/conf/ASST2 Normal file
View File

@ -0,0 +1,33 @@
# Kernel config file using dumbvm.
# This should be used until you have your own VM system.
include conf/conf.kern # get definitions of available options
debug # Compile with debug info.
#
# Device drivers for hardware.
#
device lamebus0 # System/161 main bus
device emu* at lamebus* # Emulator passthrough filesystem
device ltrace* at lamebus* # trace161 trace control device
device ltimer* at lamebus* # Timer device
device lrandom* at lamebus* # Random device
device lhd* at lamebus* # Disk device
device lser* at lamebus* # Serial port
#device lscreen* at lamebus* # Text screen (not supported yet)
#device lnet* at lamebus* # Network interface (not supported yet)
device beep0 at ltimer* # Abstract beep handler device
device con0 at lser* # Abstract console on serial port
#device con0 at lscreen* # Abstract console on screen (not supported)
device rtclock0 at ltimer* # Abstract realtime clock
device random0 at lrandom* # Abstract randomness device
#options net # Network stack (not supported)
options semfs # Semaphores for userland
options sfs # Always use the file system
#options netfs # You might write this as a project.
options dumbvm # Chewing gum and baling wire.
#options synchprobs # Uncomment to enable ASST1 synchronization problems

33
kern/conf/ASST3 Normal file
View File

@ -0,0 +1,33 @@
# Kernel config file for an ordinary, generic kernel.
# This config file should be used once you start working on
# your own VM system.
include conf/conf.kern # get definitions of available options
debug # Compile with debug info.
#
# Device drivers for hardware.
#
device lamebus0 # System/161 main bus
device emu* at lamebus* # Emulator passthrough filesystem
device ltrace* at lamebus* # trace161 trace control device
device ltimer* at lamebus* # Timer device
device lrandom* at lamebus* # Random device
device lhd* at lamebus* # Disk device
device lser* at lamebus* # Serial port
#device lscreen* at lamebus* # Text screen (not supported yet)
#device lnet* at lamebus* # Network interface (not supported yet)
device beep0 at ltimer* # Abstract beep handler device
device con0 at lser* # Abstract console on serial port
#device con0 at lscreen* # Abstract console on screen (not supported)
device rtclock0 at ltimer* # Abstract realtime clock
device random0 at lrandom* # Abstract randomness device
#options net # Network stack (not supported)
options semfs # Semaphores for userland
options sfs # Always use the file system
#options netfs # You might write this as a project.
#options dumbvm # Use your own VM system now.

View File

@ -32,4 +32,4 @@ options sfs # Always use the file system
#options netfs # You might write this as a project.
options dumbvm # Chewing gum and baling wire.
options synchprobs
options synchprobs # Uncomment to enable ASST1 synchronization problems

View File

@ -309,6 +309,14 @@ file ../common/libc/string/strlen.c
file ../common/libc/string/strrchr.c
file ../common/libc/string/strtok_r.c
#
# libtest161 shared code and security functions
#
file ../common/libtest161/test161.c
file ../common/libtest161/secure.c
file ../common/libtest161/sha256.c
########################################
# #
# Core kernel source files #
@ -437,12 +445,19 @@ file test/threadlisttest.c
file test/threadtest.c
file test/tt3.c
file test/synchtest.c
file test/rwtest.c
file test/semunit.c
file test/hmacunit.c
file test/kmalloctest.c
file test/fstest.c
file test/lib.c
optfile net test/nettest.c
defoption synchprobs
optfile synchprobs synchprobs/whalemating.c
optfile synchprobs synchprobs/stoplight.c
optfile synchprobs test/synchprobs.c
optfile synchprobs synchprobs/whalemating.c
optfile synchprobs synchprobs/stoplight.c
optfile synchprobs test/synchprobs.c
defoption automationtest
optfile automationtest test/automationtest.c

View File

@ -208,7 +208,7 @@ echo "$CONFNAME" $CONFTMP | awk '
#
if [ ! -d "$COMPILEDIR" ]; then
mkdir $COMPILEDIR
mkdir -p $COMPILEDIR
fi
echo -n 'Generating files...'

View File

@ -35,6 +35,7 @@
#include <threadlist.h>
#include <machine/vm.h> /* for TLBSHOOTDOWN_MAX */
extern unsigned num_cpus;
/*
* Per-cpu structure

View File

@ -0,0 +1,50 @@
/*
* NO NOT MODIFY THIS FILE
*
* All the contents of this file are overwritten during automated
* testing. Please consider this before changing anything in this file.
*/
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of the University 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 UNIVERSITY 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 UNIVERSITY 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 _SECRET_H_
#define _SECRET_H_
/*
* During automated testing all instances of KERNEL_SECRET in trusted tests
* are rewritten to a random value to ensure that the kernel is actually
* running the appropriate tests. So this value is never actually used, but
* allows normally compilation and operation.
*/
#undef SECRET_TESTING
#define SECRET "SECRET"
#endif /* _SECRET_H_ */

View File

@ -0,0 +1,18 @@
#ifndef _KERN_SECURE_H_
#define _KERN_SECURE_H_
/*
* Compute the FIPS 198-1 complient HMAC of msg using SHA256.
*
* hmac_with_salt uses a salted key and sets salt_str to this value (in hex).
* Both functions below create hash_str with the hex readable version of the hash.
*
* Callers need to free hash_str (and salt_str) when done.
*/
int hmac(const char *msg, size_t msg_len, const char *key, size_t key_len,
char **hash_str);
int hmac_salted(const char *msg, size_t msg_len, const char *key, size_t key_len,
char **hash_str, char **salt_str);
#endif //_KERN_SECURE_H_

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of the University 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 UNIVERSITY 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 UNIVERSITY 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 _KERN_TEST161_H_
#define _KERN_TEST161_H_
#define TEST161_SUCCESS 0
#define TEST161_FAIL 1
#include <kern/secret.h>
#ifdef _KERNEL
#define __TEST161_PROGRESS_N(iter, mod) do { \
if (((iter) % mod) == 0) { \
kprintf("."); \
} \
} while (0)
#else
#include <stdio.h>
#define __TEST161_PROGRESS_N(iter, mod) do { \
if (((iter) % mod) == 0) { \
printf("."); \
} \
} while (0)
#endif
// Always loud
#define TEST161_LPROGRESS_N(iter, mod) __TEST161_PROGRESS_N(iter, mod)
#define TEST161_LPROGRESS(iter) __TEST161_PROGRESS_N(iter, 100)
// Depends on whether or not it's automated testing. Some tests are
// quite verbose with useful information so these should just stay quiet.
#ifdef SECRET_TESTING
#define TEST161_TPROGRESS_N(iter, mod) __TEST161_PROGRESS_N(iter, mod)
#define TEST161_TPROGRESS(iter) __TEST161_PROGRESS_N(iter, 100)
#else
#define TEST161_TPROGRESS_N(iter, mod)
#define TEST161_TPROGRESS(iter)
#endif
int success(int, const char *, const char *);
int secprintf(const char *secret, const char *msg, const char *name);
int snsecprintf(size_t len, char *buffer, const char *secret, const char *msg, const char *name);
int partial_credit(const char *secret, const char *name, int scored, int total);
#ifdef _KERNEL
void test161_bootstrap(void);
#endif
#endif /* _KERN_TEST161_H_ */

View File

@ -129,6 +129,8 @@ uint32_t random(void);
void *kmalloc(size_t size);
void kfree(void *ptr);
void kheap_printstats(void);
void kheap_printused(void);
unsigned long kheap_getused(void);
void kheap_nextgeneration(void);
void kheap_dump(void);
void kheap_dumpall(void);

47
kern/include/prompt.h Normal file
View File

@ -0,0 +1,47 @@
/*
* NO NOT MODIFY THIS FILE
*
* All the contents of this file are overwritten during automated
* testing. Please consider this before changing anything in this file.
*/
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of the University 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 UNIVERSITY 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 UNIVERSITY 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 _PROMPT_H_
#define _PROMPT_H_
/*
* You can set a custom prompt here, but the default will be used during
* testing.
*/
#define KERNEL_PROMPT "OS/161 kernel [? for menu]: "
#endif /* _PROMPT_H_ */

View File

@ -74,8 +74,8 @@ int splx(int);
/*
* Integer interrupt priority levels.
*/
#define IPL_NONE 0
#define IPL_HIGH 1
#define IPL_NONE 0
#define IPL_HIGH 1
/*
* Lower-level functions for explicitly raising and lowering
@ -92,9 +92,18 @@ void spllower(int oldipl, int newipl);
////////////////////////////////////////////////////////////
SPL_INLINE
int spl0(void) { return splx(IPL_NONE); }
int
spl0(void)
{
return splx(IPL_NONE);
}
SPL_INLINE
int splhigh(void) { return splx(IPL_HIGH); }
int
splhigh(void)
{
return splx(IPL_HIGH);
}
#endif /* _SPL_H_ */

View File

@ -34,6 +34,7 @@
* Header file for synchronization primitives.
*/
#include <spinlock.h>
/*
@ -43,10 +44,10 @@
* internally.
*/
struct semaphore {
char *sem_name;
struct wchan *sem_wchan;
struct spinlock sem_lock;
volatile unsigned sem_count;
char *sem_name;
struct wchan *sem_wchan;
struct spinlock sem_lock;
volatile unsigned sem_count;
};
struct semaphore *sem_create(const char *name, unsigned initial_count);
@ -61,6 +62,7 @@ void sem_destroy(struct semaphore *);
void P(struct semaphore *);
void V(struct semaphore *);
/*
* Simple lock for mutual exclusion.
*
@ -71,10 +73,10 @@ void V(struct semaphore *);
* (should be) made internally.
*/
struct lock {
char *lk_name;
HANGMAN_LOCKABLE(lk_hangman); /* Deadlock detector hook. */
// add what you need here
// (don't forget to mark things volatile as needed)
char *lk_name;
HANGMAN_LOCKABLE(lk_hangman); /* Deadlock detector hook. */
// add what you need here
// (don't forget to mark things volatile as needed)
};
struct lock *lock_create(const char *name);
@ -95,6 +97,7 @@ void lock_acquire(struct lock *);
void lock_release(struct lock *);
bool lock_do_i_hold(struct lock *);
/*
* Condition variable.
*
@ -110,9 +113,9 @@ bool lock_do_i_hold(struct lock *);
*/
struct cv {
char *cv_name;
// add what you need here
// (don't forget to mark things volatile as needed)
char *cv_name;
// add what you need here
// (don't forget to mark things volatile as needed)
};
struct cv *cv_create(const char *name);
@ -135,4 +138,40 @@ void cv_wait(struct cv *cv, struct lock *lock);
void cv_signal(struct cv *cv, struct lock *lock);
void cv_broadcast(struct cv *cv, struct lock *lock);
/*
* Reader-writer locks.
*
* When the lock is created, no thread should be holding it. Likewise,
* when the lock is destroyed, no thread should be holding it.
*
* The name field is for easier debugging. A copy of the name is
* (should be) made internally.
*/
struct rwlock {
char *rwlock_name;
// add what you need here
// (don't forget to mark things volatile as needed)
};
struct rwlock * rwlock_create(const char *);
void rwlock_destroy(struct rwlock *);
/*
* Operations:
* rwlock_acquire_read - Get the lock for reading. Multiple threads can
* hold the lock for reading at the same time.
* rwlock_release_read - Free the lock.
* rwlock_acquire_write - Get the lock for writing. Only one thread can
* hold the write lock at one time.
* rwlock_release_write - Free the write lock.
*
* These operations must be atomic. You get to write them.
*/
void rwlock_acquire_read(struct rwlock *);
void rwlock_release_read(struct rwlock *);
void rwlock_acquire_write(struct rwlock *);
void rwlock_release_write(struct rwlock *);
#endif /* _SYNCH_H_ */

View File

@ -30,6 +30,13 @@
#ifndef _TEST_H_
#define _TEST_H_
/* Get __PF() for declaring printf-like functions. */
#include <cdefs.h>
#include <kern/secret.h>
#include "opt-synchprobs.h"
#include "opt-automationtest.h"
/*
* Declarations for test code and other miscellaneous high-level
* functions.
@ -52,8 +59,20 @@ int threadtest2(int, char **);
int threadtest3(int, char **);
int semtest(int, char **);
int locktest(int, char **);
int locktest2(int, char **);
int locktest3(int, char **);
int locktest4(int, char **);
int locktest5(int, char **);
int cvtest(int, char **);
int cvtest2(int, char **);
int cvtest3(int, char **);
int cvtest4(int, char **);
int cvtest5(int, char **);
int rwtest(int, char **);
int rwtest2(int, char **);
int rwtest3(int, char **);
int rwtest4(int, char **);
int rwtest5(int, char **);
/* semaphore unit tests */
int semu1(int, char **);
@ -88,11 +107,15 @@ int longstress(int, char **);
int createstress(int, char **);
int printfile(int, char **);
/* HMAC/hash tests */
int hmacu1(int, char**);
/* other tests */
int kmalloctest(int, char **);
int kmallocstress(int, char **);
int kmalloctest3(int, char **);
int kmalloctest4(int, char **);
int kmalloctest5(int, char **);
int nettest(int, char **);
/* Routine for running a user-level program. */
@ -104,5 +127,75 @@ void menu(char *argstr);
/* The main function, called from start.S. */
void kmain(char *bootstring);
#if OPT_SYNCHPROBS
/*
* Synchronization driver primitives.
*/
void male_start(uint32_t);
void male_end(uint32_t);
void female_start(uint32_t);
void female_end(uint32_t);
void matchmaker_start(uint32_t);
void matchmaker_end(uint32_t);
int whalemating(int, char **);
void inQuadrant(int, uint32_t);
void leaveIntersection(uint32_t);
int stoplight(int, char **);
/*
* Synchronization problem primitives.
*/
/*
* whalemating.c.
*/
void whalemating_init(void);
void whalemating_cleanup(void);
void male(uint32_t);
void female(uint32_t);
void matchmaker(uint32_t);
/*
* stoplight.c.
*/
void gostraight(uint32_t, uint32_t);
void turnleft(uint32_t, uint32_t);
void turnright(uint32_t, uint32_t);
void stoplight_init(void);
void stoplight_cleanup(void);
#endif
/*
* Automation tests for detecting kernel deadlocks and livelocks.
*/
#if OPT_AUTOMATIONTEST
int dltest(int, char **);
int ll1test(int, char **);
int ll16test(int, char **);
#endif
void random_yielder(uint32_t);
void random_spinner(uint32_t);
/*
* kprintf variants that do not (or only) print during automated testing.
*/
#ifdef SECRET_TESTING
#define kprintf_t(...) kprintf(__VA_ARGS__)
#define kprintf_n(...) silent(__VA_ARGS__)
#else
#define kprintf_t(...) silent(__VA_ARGS__)
#define kprintf_n(...) kprintf(__VA_ARGS__)
#endif
static inline void silent(const char * fmt, ...) { (void)fmt; };
#endif /* _TEST_H_ */

View File

@ -48,6 +48,7 @@ struct cpu;
/* Size of kernel stacks; must be power of 2 */
#define STACK_SIZE 4096
#define MAX_NAME_LENGTH 64
/* Mask for extracting the stack base address of a kernel stack pointer */
#define STACK_MASK (~(vaddr_t)(STACK_SIZE-1))
@ -70,7 +71,16 @@ struct thread {
* These go up front so they're easy to get to even if the
* debugger is messed up.
*/
char *t_name; /* Name of this thread */
/*
* Name of this thread. Used to be dynamically allocated using kmalloc, but
* this can cause small changes in the amount of available memory due to the
* fact that it was cleaned up in exorcise. This produces more predictable
* behavior at the cost of a small amount of memory overhead and the
* inability to give threads huge names.
*/
char t_name[MAX_NAME_LENGTH];
const char *t_wchan_name; /* Name of wait channel, if sleeping */
threadstate_t t_state; /* State this thread is in */
@ -169,5 +179,7 @@ void schedule(void);
*/
void thread_consider_migration(void);
extern unsigned thread_count;
void thread_wait_for_count(unsigned);
#endif /* _THREAD_H_ */

View File

@ -55,6 +55,13 @@ int vm_fault(int faulttype, vaddr_t faultaddress);
vaddr_t alloc_kpages(unsigned npages);
void free_kpages(vaddr_t addr);
/*
* Return amount of memory (in bytes) used by allocated coremap pages. If
* there are ongoing allocations, this value could change after it is returned
* to the caller. But it should have been correct at some point in time.
*/
unsigned int coremap_used_bytes(void);
/* TLB shootdown handling called from interprocessor_interrupt */
void vm_tlbshootdown(const struct tlbshootdown *);

View File

@ -37,8 +37,11 @@
#include <current.h>
#include <synch.h>
#include <mainbus.h>
#include <vfs.h> // for vfs_sync()
#include <vfs.h> // for vfs_sync()
#include <lamebus/ltrace.h> // for ltrace_stop()
#include <kern/secret.h>
#include <test.h>
/* Flags word for DEBUG() macro. */
uint32_t dbflags = 0;
@ -49,66 +52,94 @@ static struct lock *kprintf_lock;
/* Lock for polled kprintfs */
static struct spinlock kprintf_spinlock;
/*
* Warning: all this has to work from interrupt handlers and when
* interrupts are disabled.
*/
/*
* Create the kprintf lock. Must be called before creating a second
* thread or enabling a second CPU.
*/
void kprintf_bootstrap(void) {
KASSERT(kprintf_lock == NULL);
void
kprintf_bootstrap(void)
{
KASSERT(kprintf_lock == NULL);
kprintf_lock = lock_create("kprintf_lock");
if (kprintf_lock == NULL) {
panic("Could not create kprintf_lock\n");
}
spinlock_init(&kprintf_spinlock);
kprintf_lock = lock_create("kprintf_lock");
if (kprintf_lock == NULL) {
panic("Could not create kprintf_lock\n");
}
spinlock_init(&kprintf_spinlock);
}
/*
* Send characters to the console. Backend for __printf.
*/
static void console_send(void *junk, const char *data, size_t len) {
size_t i;
static
void
console_send(void *junk, const char *data, size_t len)
{
size_t i;
(void)junk;
(void)junk;
for (i = 0; i < len; i++) {
putch(data[i]);
}
for (i=0; i<len; i++) {
putch(data[i]);
}
}
/*
* kprintf and tprintf helper function.
*/
static
inline
int
__kprintf(const char *fmt, va_list ap)
{
int chars;
bool dolock;
dolock = kprintf_lock != NULL
&& curthread->t_in_interrupt == false
&& curthread->t_curspl == 0
&& curcpu->c_spinlocks == 0;
if (dolock) {
lock_acquire(kprintf_lock);
}
else {
spinlock_acquire(&kprintf_spinlock);
}
chars = __vprintf(console_send, NULL, fmt, ap);
if (dolock) {
lock_release(kprintf_lock);
}
else {
spinlock_release(&kprintf_spinlock);
}
return chars;
}
/*
* Printf to the console.
*/
int kprintf(const char *fmt, ...) {
int chars;
va_list ap;
bool dolock;
int
kprintf(const char *fmt, ...)
{
int chars;
va_list ap;
dolock = kprintf_lock != NULL && curthread->t_in_interrupt == false &&
curthread->t_curspl == 0 && curcpu->c_spinlocks == 0;
va_start(ap, fmt);
chars = __kprintf(fmt, ap);
va_end(ap);
if (dolock) {
lock_acquire(kprintf_lock);
} else {
spinlock_acquire(&kprintf_spinlock);
}
va_start(ap, fmt);
chars = __vprintf(console_send, NULL, fmt, ap);
va_end(ap);
if (dolock) {
lock_release(kprintf_lock);
} else {
spinlock_release(&kprintf_spinlock);
}
return chars;
return chars;
}
/*
@ -116,83 +147,87 @@ int kprintf(const char *fmt, ...) {
* passed and then halts the system.
*/
void panic(const char *fmt, ...) {
va_list ap;
void
panic(const char *fmt, ...)
{
va_list ap;
/*
* When we reach panic, the system is usually fairly screwed up.
* It's not entirely uncommon for anything else we try to do
* here to trigger more panics.
*
* This variable makes sure that if we try to do something here,
* and it causes another panic, *that* panic doesn't try again;
* trying again almost inevitably causes infinite recursion.
*
* This is not excessively paranoid - these things DO happen!
*/
static volatile int evil;
/*
* When we reach panic, the system is usually fairly screwed up.
* It's not entirely uncommon for anything else we try to do
* here to trigger more panics.
*
* This variable makes sure that if we try to do something here,
* and it causes another panic, *that* panic doesn't try again;
* trying again almost inevitably causes infinite recursion.
*
* This is not excessively paranoid - these things DO happen!
*/
static volatile int evil;
if (evil == 0) {
evil = 1;
if (evil == 0) {
evil = 1;
/*
* Not only do we not want to be interrupted while
* panicking, but we also want the console to be
* printing in polling mode so as not to do context
* switches. So turn interrupts off on this CPU.
*/
splhigh();
}
/*
* Not only do we not want to be interrupted while
* panicking, but we also want the console to be
* printing in polling mode so as not to do context
* switches. So turn interrupts off on this CPU.
*/
splhigh();
}
if (evil == 1) {
evil = 2;
if (evil == 1) {
evil = 2;
/* Kill off other threads and halt other CPUs. */
thread_panic();
}
/* Kill off other threads and halt other CPUs. */
thread_panic();
}
if (evil == 2) {
evil = 3;
if (evil == 2) {
evil = 3;
/* Print the message. */
kprintf("panic: ");
va_start(ap, fmt);
__vprintf(console_send, NULL, fmt, ap);
va_end(ap);
}
/* Print the message. */
kprintf("panic: ");
va_start(ap, fmt);
__vprintf(console_send, NULL, fmt, ap);
va_end(ap);
}
if (evil == 3) {
evil = 4;
if (evil == 3) {
evil = 4;
/* Drop to the debugger. */
ltrace_stop(0);
}
/* Drop to the debugger. */
ltrace_stop(0);
}
if (evil == 4) {
evil = 5;
if (evil == 4) {
evil = 5;
/* Try to sync the disks. */
vfs_sync();
}
/* Try to sync the disks. */
vfs_sync();
}
if (evil == 5) {
evil = 6;
if (evil == 5) {
evil = 6;
/* Shut down or reboot the system. */
mainbus_panic();
}
/* Shut down or reboot the system. */
mainbus_panic();
}
/*
* Last resort, just in case.
*/
/*
* Last resort, just in case.
*/
for (;;)
;
for (;;);
}
/*
* Assertion failures go through this.
*/
void badassert(const char *expr, const char *file, int line, const char *func) {
panic("Assertion failed: %s, at %s:%d (%s)\n", expr, file, line, func);
void
badassert(const char *expr, const char *file, int line, const char *func)
{
panic("Assertion failed: %s, at %s:%d (%s)\n",
expr, file, line, func);
}

View File

@ -48,8 +48,10 @@
#include <device.h>
#include <syscall.h>
#include <test.h>
#include <kern/test161.h>
#include <version.h>
#include "autoconf.h" // for pseudoconfig
#include "autoconf.h" // for pseudoconfig
/*
* These two pieces of data are maintained by the makefiles and build system.
@ -70,85 +72,93 @@ static const char harvard_copyright[] =
"Copyright (c) 2000, 2001-2005, 2008-2011, 2013, 2014\n"
" President and Fellows of Harvard College. All rights reserved.\n";
/*
* Initial boot sequence.
*/
static void boot(void) {
/*
* The order of these is important!
* Don't go changing it without thinking about the consequences.
*
* Among other things, be aware that console output gets
* buffered up at first and does not actually appear until
* mainbus_bootstrap() attaches the console device. This can
* be remarkably confusing if a bug occurs at this point. So
* don't put new code before mainbus_bootstrap if you don't
* absolutely have to.
*
* Also note that the buffer for this is only 1k. If you
* overflow it, the system will crash without printing
* anything at all. You can make it larger though (it's in
* dev/generic/console.c).
*/
static
void
boot(void)
{
/*
* The order of these is important!
* Don't go changing it without thinking about the consequences.
*
* Among other things, be aware that console output gets
* buffered up at first and does not actually appear until
* mainbus_bootstrap() attaches the console device. This can
* be remarkably confusing if a bug occurs at this point. So
* don't put new code before mainbus_bootstrap if you don't
* absolutely have to.
*
* Also note that the buffer for this is only 1k. If you
* overflow it, the system will crash without printing
* anything at all. You can make it larger though (it's in
* dev/generic/console.c).
*/
kprintf("\n");
kprintf("OS/161 base system version %s\n", BASE_VERSION);
kprintf("%s", harvard_copyright);
kprintf("\n");
kprintf("\n");
kprintf("OS/161 base system version %s\n", BASE_VERSION);
kprintf("%s", harvard_copyright);
kprintf("\n");
kprintf("Minh Tran's system version %s (%s #%d)\n", GROUP_VERSION,
buildconfig, buildversion);
kprintf("\n");
kprintf("Put-your-group-name-here's system version %s (%s #%d)\n",
GROUP_VERSION, buildconfig, buildversion);
kprintf("\n");
/* Early initialization. */
ram_bootstrap();
proc_bootstrap();
thread_bootstrap();
hardclock_bootstrap();
vfs_bootstrap();
kheap_nextgeneration();
/* Early initialization. */
ram_bootstrap();
proc_bootstrap();
thread_bootstrap();
hardclock_bootstrap();
vfs_bootstrap();
kheap_nextgeneration();
/* Probe and initialize devices. Interrupts should come on. */
kprintf("Device probe...\n");
KASSERT(curthread->t_curspl > 0);
mainbus_bootstrap();
KASSERT(curthread->t_curspl == 0);
/* Now do pseudo-devices. */
pseudoconfig();
kprintf("\n");
kheap_nextgeneration();
/* Probe and initialize devices. Interrupts should come on. */
kprintf("Device probe...\n");
KASSERT(curthread->t_curspl > 0);
mainbus_bootstrap();
KASSERT(curthread->t_curspl == 0);
/* Now do pseudo-devices. */
pseudoconfig();
kprintf("\n");
kheap_nextgeneration();
/* Late phase of initialization. */
vm_bootstrap();
kprintf_bootstrap();
thread_start_cpus();
/* Late phase of initialization. */
vm_bootstrap();
kprintf_bootstrap();
thread_start_cpus();
test161_bootstrap();
/* Default bootfs - but ignore failure, in case emu0 doesn't exist */
vfs_setbootfs("emu0");
/* Default bootfs - but ignore failure, in case emu0 doesn't exist */
vfs_setbootfs("emu0");
kheap_nextgeneration();
kheap_nextgeneration();
/*
* Make sure various things aren't screwed up.
*/
COMPILE_ASSERT(sizeof(userptr_t) == sizeof(char *));
COMPILE_ASSERT(sizeof(*(userptr_t)0) == sizeof(char));
/*
* Make sure various things aren't screwed up.
*/
COMPILE_ASSERT(sizeof(userptr_t) == sizeof(char *));
COMPILE_ASSERT(sizeof(*(userptr_t)0) == sizeof(char));
}
/*
* Shutdown sequence. Opposite to boot().
*/
static void shutdown(void) {
static
void
shutdown(void)
{
kprintf("Shutting down.\n");
kprintf("Shutting down.\n");
vfs_clearbootfs();
vfs_clearcurdir();
vfs_unmountall();
vfs_clearbootfs();
vfs_clearcurdir();
vfs_unmountall();
thread_shutdown();
thread_shutdown();
splhigh();
splhigh();
}
/*****************************************/
@ -160,45 +170,49 @@ static void shutdown(void) {
* not because this is where system call code should go. Other syscall
* code should probably live in the "syscall" directory.
*/
int sys_reboot(int code) {
switch (code) {
case RB_REBOOT:
case RB_HALT:
case RB_POWEROFF:
break;
default:
return EINVAL;
}
int
sys_reboot(int code)
{
switch (code) {
case RB_REBOOT:
case RB_HALT:
case RB_POWEROFF:
break;
default:
return EINVAL;
}
shutdown();
shutdown();
switch (code) {
case RB_HALT:
kprintf("The system is halted.\n");
mainbus_halt();
break;
case RB_REBOOT:
kprintf("Rebooting...\n");
mainbus_reboot();
break;
case RB_POWEROFF:
kprintf("The system is halted.\n");
mainbus_poweroff();
break;
}
switch (code) {
case RB_HALT:
kprintf("The system is halted.\n");
mainbus_halt();
break;
case RB_REBOOT:
kprintf("Rebooting...\n");
mainbus_reboot();
break;
case RB_POWEROFF:
kprintf("The system is halted.\n");
mainbus_poweroff();
break;
}
panic("reboot operation failed\n");
return 0;
panic("reboot operation failed\n");
return 0;
}
/*
* Kernel main. Boot up, then fork the menu thread; wait for a reboot
* request, and then shut down.
*/
void kmain(char *arguments) {
boot();
void
kmain(char *arguments)
{
boot();
menu(arguments);
menu(arguments);
/* Should not get here */
/* Should not get here */
}

View File

@ -43,8 +43,11 @@
#include <sfs.h>
#include <syscall.h>
#include <test.h>
#include <prompt.h>
#include "opt-sfs.h"
#include "opt-net.h"
#include "opt-synchprobs.h"
#include "opt-automationtest.h"
/*
* In-kernel menu and command dispatcher.
@ -116,6 +119,7 @@ common_prog(int nargs, char **args)
{
struct proc *proc;
int result;
unsigned tc;
/* Create a process for the new program to run in. */
proc = proc_create_runprogram(args[0] /* name */);
@ -123,6 +127,8 @@ common_prog(int nargs, char **args)
return ENOMEM;
}
tc = thread_count;
result = thread_fork(args[0] /* thread name */,
proc /* new process */,
cmd_progthread /* thread function */,
@ -138,6 +144,10 @@ common_prog(int nargs, char **args)
* once you write the code for handling that.
*/
// Wait for all threads to finish cleanup, otherwise khu be a bit behind,
// especially once swapping is enabled.
thread_wait_for_count(tc);
return 0;
}
@ -465,6 +475,18 @@ cmd_kheapstats(int nargs, char **args)
return 0;
}
static
int
cmd_kheapused(int nargs, char **args)
{
(void)nargs;
(void)args;
kheap_printused();
return 0;
}
static
int
cmd_kheapgeneration(int nargs, char **args)
@ -560,16 +582,33 @@ static const char *testmenu[] = {
"[km2] kmalloc stress test ",
"[km3] Large kmalloc test ",
"[km4] Multipage kmalloc test ",
"[km5] kmalloc coremap alloc test ",
"[tt1] Thread test 1 ",
"[tt2] Thread test 2 ",
"[tt3] Thread test 3 ",
#if OPT_NET
"[net] Network test ",
#endif
"[sy1] Semaphore test ",
"[sy2] Lock test (1) ",
"[sy3] CV test (1) ",
"[sy4] CV test #2 (1) ",
"[sem1] Semaphore test ",
"[lt1] Lock test 1 (1) ",
"[lt2] Lock test 2 (1*) ",
"[lt3] Lock test 3 (1*) ",
"[lt4] Lock test 4 (1*) ",
"[lt5] Lock test 5 (1*) ",
"[cvt1] CV test 1 (1) ",
"[cvt2] CV test 2 (1) ",
"[cvt3] CV test 3 (1*) ",
"[cvt4] CV test 4 (1*) ",
"[cvt5] CV test 5 (1) ",
"[rwt1] RW lock test (1?) ",
"[rwt2] RW lock test 2 (1?) ",
"[rwt3] RW lock test 3 (1?) ",
"[rwt4] RW lock test 4 (1?) ",
"[rwt5] RW lock test 5 (1?) ",
#if OPT_SYNCHPROBS
"[sp1] Whalemating test (1) ",
"[sp2] Stoplight test (1) ",
#endif
"[semu1-22] Semaphore unit tests ",
"[fs1] Filesystem test ",
"[fs2] FS read stress ",
@ -577,6 +616,7 @@ static const char *testmenu[] = {
"[fs4] FS write stress 2 ",
"[fs5] FS long stress ",
"[fs6] FS create stress ",
"[hm1] HMAC unit test ",
NULL
};
@ -590,15 +630,41 @@ cmd_testmenu(int n, char **a)
showmenu("OS/161 tests menu", testmenu);
kprintf(" (1) These tests will fail until you finish the "
"synch assignment.\n");
kprintf(" (*) These tests will panic on success.\n");
kprintf(" (?) These tests are left to you to implement.\n");
kprintf("\n");
return 0;
}
#if OPT_AUTOMATIONTEST
static const char *automationmenu[] = {
"[dl] Deadlock test (*) ",
"[ll1] Livelock test (1 thread) ",
"[ll16] Livelock test (16 threads) ",
NULL
};
static
int
cmd_automationmenu(int n, char **a)
{
(void)n;
(void)a;
showmenu("OS/161 automation tests menu", automationmenu);
kprintf(" (*) These tests require locks.\n");
kprintf("\n");
return 0;
}
#endif
static const char *mainmenu[] = {
"[?o] Operations menu ",
"[?t] Tests menu ",
"[kh] Kernel heap stats ",
"[khu] Kernel heap usage ",
"[khgen] Next kernel heap generation ",
"[khdump] Dump kernel heap ",
"[q] Quit and shut down ",
@ -630,6 +696,9 @@ static struct {
{ "help", cmd_mainmenu },
{ "?o", cmd_opsmenu },
{ "?t", cmd_testmenu },
#if OPT_AUTOMATIONTEST
{ "?a", cmd_automationmenu },
#endif
/* operations */
{ "s", cmd_shell },
@ -650,6 +719,7 @@ static struct {
/* stats */
{ "kh", cmd_kheapstats },
{ "khu", cmd_kheapused },
{ "khgen", cmd_kheapgeneration },
{ "khdump", cmd_kheapdump },
@ -662,18 +732,35 @@ static struct {
{ "km2", kmallocstress },
{ "km3", kmalloctest3 },
{ "km4", kmalloctest4 },
{ "km5", kmalloctest5 },
#if OPT_NET
{ "net", nettest },
#endif
{ "tt1", threadtest },
{ "tt2", threadtest2 },
{ "tt3", threadtest3 },
{ "sy1", semtest },
/* synchronization assignment tests */
{ "sy2", locktest },
{ "sy3", cvtest },
{ "sy4", cvtest2 },
{ "sem1", semtest },
{ "lt1", locktest },
{ "lt2", locktest2 },
{ "lt3", locktest3 },
{ "lt4", locktest4 },
{ "lt5", locktest5 },
{ "cvt1", cvtest },
{ "cvt2", cvtest2 },
{ "cvt3", cvtest3 },
{ "cvt4", cvtest4 },
{ "cvt5", cvtest5 },
{ "rwt1", rwtest },
{ "rwt2", rwtest2 },
{ "rwt3", rwtest3 },
{ "rwt4", rwtest4 },
{ "rwt5", rwtest5 },
#if OPT_SYNCHPROBS
{ "sp1", whalemating },
{ "sp2", stoplight },
#endif
/* semaphore unit tests */
{ "semu1", semu1 },
@ -707,6 +794,16 @@ static struct {
{ "fs5", longstress },
{ "fs6", createstress },
/* HMAC unit tests */
{ "hm1", hmacu1 },
#if OPT_AUTOMATIONTEST
/* automation tests */
{ "dl", dltest },
{ "ll1", ll1test },
{ "ll16", ll16test },
#endif
{ NULL, NULL }
};
@ -820,7 +917,11 @@ menu(char *args)
menu_execute(args, 1);
while (1) {
kprintf("OS/161 kernel [? for menu]: ");
/*
* Defined in overwrite.h. If you want to change the kernel prompt, please
* do it in that file. Otherwise automated test testing will break.
*/
kprintf(KERNEL_PROMPT);
kgets(buf, sizeof(buf));
menu_execute(buf, 0);
}

118
kern/synchprobs/stoplight.c Normal file
View File

@ -0,0 +1,118 @@
/*
* Copyright (c) 2001, 2002, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of the University 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 UNIVERSITY 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 UNIVERSITY 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.
*/
/*
* Driver code is in kern/tests/synchprobs.c We will replace that file. This
* file is yours to modify as you see fit.
*
* You should implement your solution to the stoplight problem below. The
* quadrant and direction mappings for reference: (although the problem is, of
* course, stable under rotation)
*
* |0 |
* - --
* 01 1
* 3 32
* -- --
* | 2|
*
* As way to think about it, assuming cars drive on the right: a car entering
* the intersection from direction X will enter intersection quadrant X first.
* The semantics of the problem are that once a car enters any quadrant it has
* to be somewhere in the intersection until it call leaveIntersection(),
* which it should call while in the final quadrant.
*
* As an example, let's say a car approaches the intersection and needs to
* pass through quadrants 0, 3 and 2. Once you call inQuadrant(0), the car is
* considered in quadrant 0 until you call inQuadrant(3). After you call
* inQuadrant(2), the car is considered in quadrant 2 until you call
* leaveIntersection().
*
* You will probably want to write some helper functions to assist with the
* mappings. Modular arithmetic can help, e.g. a car passing straight through
* the intersection entering from direction X will leave to direction (X + 2)
* % 4 and pass through quadrants X and (X + 3) % 4. Boo-yah.
*
* Your solutions below should call the inQuadrant() and leaveIntersection()
* functions in synchprobs.c to record their progress.
*/
#include <types.h>
#include <lib.h>
#include <thread.h>
#include <test.h>
#include <synch.h>
/*
* Called by the driver during initialization.
*/
void
stoplight_init() {
return;
}
/*
* Called by the driver during teardown.
*/
void stoplight_cleanup() {
return;
}
void
turnright(uint32_t direction, uint32_t index)
{
(void)direction;
(void)index;
/*
* Implement this function.
*/
return;
}
void
gostraight(uint32_t direction, uint32_t index)
{
(void)direction;
(void)index;
/*
* Implement this function.
*/
return;
}
void
turnleft(uint32_t direction, uint32_t index)
{
(void)direction;
(void)index;
/*
* Implement this function.
*/
return;
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2001, 2002, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of the University 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 UNIVERSITY 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 UNIVERSITY 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.
*/
/*
* Driver code is in kern/tests/synchprobs.c We will
* replace that file. This file is yours to modify as you see fit.
*
* You should implement your solution to the whalemating problem below.
*/
#include <types.h>
#include <lib.h>
#include <thread.h>
#include <test.h>
#include <synch.h>
/*
* Called by the driver during initialization.
*/
void whalemating_init() {
return;
}
/*
* Called by the driver during teardown.
*/
void
whalemating_cleanup() {
return;
}
void
male(uint32_t index)
{
(void)index;
/*
* Implement this function by calling male_start and male_end when
* appropriate.
*/
return;
}
void
female(uint32_t index)
{
(void)index;
/*
* Implement this function by calling female_start and female_end when
* appropriate.
*/
return;
}
void
matchmaker(uint32_t index)
{
(void)index;
/*
* Implement this function by calling matchmaker_start and matchmaker_end
* when appropriate.
*/
return;
}

175
kern/test/automationtest.c Normal file
View File

@ -0,0 +1,175 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of the University 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 UNIVERSITY 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 UNIVERSITY 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.
*/
/*
* Automation test code for creating (and detecting) kernel dead and livelocks.
*/
#include <types.h>
#include <kern/wait.h>
#include <lib.h>
#include <clock.h>
#include <thread.h>
#include <synch.h>
#include <test.h>
#include <kern/secret.h>
#include <spinlock.h>
#define MAX_SPINNERS 16
static struct lock *deadlock_locks[2];
static struct semaphore *deadlock_sem;
struct spinlock spinners_lock[MAX_SPINNERS];
static
void
inititems(void)
{
int i;
for (i = 0; i < 2; i++) {
deadlock_locks[i] = lock_create("deadlock lock");
if (deadlock_locks[i] == NULL) {
panic("automationtest: lock_create failed\n");
}
}
deadlock_sem = sem_create("deadlock sem", 0);
if (deadlock_sem == NULL) {
panic("automationtest: sem_create failed\n");
}
for (i = 0; i < MAX_SPINNERS; i++) {
spinlock_init(&(spinners_lock[i]));
}
}
static
void
dltestthread(void *junk1, unsigned long junk2)
{
(void)junk1;
(void)junk2;
lock_acquire(deadlock_locks[1]);
V(deadlock_sem);
lock_acquire(deadlock_locks[0]);
}
int
dltest(int nargs, char **args)
{
int result;
(void)nargs;
(void)args;
inititems();
lock_acquire(deadlock_locks[0]);
result = thread_fork("dltest", NULL, dltestthread, NULL, (unsigned long)0);
if (result) {
panic("dltest: thread_fork failed: %s\n", strerror(result));
}
P(deadlock_sem);
lock_acquire(deadlock_locks[1]);
panic("dltest: didn't create deadlock (locks probably don't work)\n");
// 09 Jan 2015 : GWA : Shouldn't return.
return 0;
}
inline
static
void
infinite_spinner(unsigned long i)
{
(void)i;
volatile int j;
for (j=0; j<10000000; j++);
spinlock_acquire(&(spinners_lock[i]));
for (j=0; j<=1000; j++) {
if (j == 1000) {
j = 0;
}
}
panic("ll1test: infinite spin loop completed\n");
}
int
ll1test(int nargs, char **args)
{
(void)nargs;
(void)args;
inititems();
infinite_spinner((unsigned long) 0);
// 09 Jan 2015 : GWA : Shouldn't return.
return 0;
}
static
void
ll16testthread(void *junk1, unsigned long i)
{
(void)junk1;
infinite_spinner(i);
}
int
ll16test(int nargs, char **args)
{
int i, result;
inititems();
(void)nargs;
(void)args;
for (i=1; i<16; i++) {
result = thread_fork("ll16testthread", NULL, ll16testthread, NULL, (unsigned long)i);
if (result) {
panic("ll16test: thread_fork failed: %s\n", strerror(result));
}
}
infinite_spinner(0);
// 09 Jan 2015 : GWA : Shouldn't return.
return 0;
}

99
kern/test/hmacunit.c Normal file
View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2015
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of the University 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 UNIVERSITY 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 UNIVERSITY 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 <types.h>
#include <lib.h>
#include <spinlock.h>
#include <synch.h>
#include <thread.h>
#include <current.h>
#include <clock.h>
#include <test.h>
#include <kern/secure.h>
/*
* Unit tests for hmac/sha256 hashing.
*/
////////////////////////////////////////////////////////////
// support code
static
void
ok(void)
{
kprintf("Test passed.\n");
}
/*
* Unit test 1
*
* Test some known msg/key/hashes to make sure we produce the
* right results.
*/
static const char *plaintext1[] = {
"The quick brown fox jumps over the lazy dog",
"The only people for me are the mad ones",
"I don't exactly know what I mean by that, but I mean it.",
};
static const char *keys1[] = {
"xqWmgzbvGuLIeeKOrwMA",
"ZxuvolLXL7C68pDjsclX",
"PYeuVzKuB03awYDgJotS",
};
static const char *hashes1[] = {
"251ab1da03c94435daf44898fcd11606669e222270e4ac90d04a18a9df8fdfd6",
"75bbf48c53ccba08c244447ef7eff2e0a02f23acfdac6502282ec431823fb393",
"6d7d2b5eabcda504f26de7547185483b19f9953a6eaeec6c364bb45e20b28598",
};
#define N_TESTS_1 3
int
hmacu1(int nargs, char **args)
{
char *hash;
int res;
(void)nargs; (void)args;
int i;
for (i = 0; i < N_TESTS_1; i++)
{
res = hmac(plaintext1[i], strlen(plaintext1[i]), keys1[i], strlen(keys1[i]), &hash);
KASSERT(!res);
KASSERT(strcmp(hash, hashes1[i]) == 0);
kfree(hash);
}
ok();
/* clean up */
return 0;
}

View File

@ -33,13 +33,19 @@
#include <types.h>
#include <kern/errno.h>
#include <lib.h>
#include <cpu.h>
#include <thread.h>
#include <synch.h>
#include <vm.h> /* for PAGE_SIZE */
#include <test.h>
#include <kern/test161.h>
#include <mainbus.h>
#include "opt-dumbvm.h"
// from arch/mips/vm/ram.c
extern vaddr_t firstfree;
////////////////////////////////////////////////////////////
// km1/km2
@ -58,6 +64,12 @@
#define ITEMSIZE 997
#define NTHREADS 8
#define PROGRESS(iter) do { \
if ((iter % 100) == 0) { \
kprintf("."); \
} \
} while (0)
static
void
kmallocthread(void *sm, unsigned long num)
@ -69,15 +81,16 @@ kmallocthread(void *sm, unsigned long num)
int i;
for (i=0; i<NTRIES; i++) {
PROGRESS(i);
ptr = kmalloc(ITEMSIZE);
if (ptr==NULL) {
if (sem) {
kprintf("thread %lu: kmalloc returned NULL\n",
num);
goto done;
panic("kmalloc test failed");
}
kprintf("kmalloc returned null; test failed.\n");
goto done;
panic("kmalloc test failed");
}
if (oldptr2) {
kfree(oldptr2);
@ -85,7 +98,7 @@ kmallocthread(void *sm, unsigned long num)
oldptr2 = oldptr;
oldptr = ptr;
}
done:
if (oldptr2) {
kfree(oldptr2);
}
@ -105,7 +118,8 @@ kmalloctest(int nargs, char **args)
kprintf("Starting kmalloc test...\n");
kmallocthread(NULL, 0);
kprintf("kmalloc test done\n");
kprintf("\n");
success(TEST161_SUCCESS, SECRET, "km1");
return 0;
}
@ -140,7 +154,8 @@ kmallocstress(int nargs, char **args)
}
sem_destroy(sem);
kprintf("kmalloc stress test done\n");
kprintf("\n");
success(TEST161_SUCCESS, SECRET, "km2");
return 0;
}
@ -252,6 +267,7 @@ kmalloctest3(int nargs, char **args)
curpos = 0;
cursizeindex = 0;
for (i=0; i<numptrs; i++) {
PROGRESS(i);
cursize = sizes[cursizeindex];
ptr = ptrblocks[curblock][curpos];
KASSERT(ptr != NULL);
@ -282,13 +298,15 @@ kmalloctest3(int nargs, char **args)
/* Free the lower tier. */
for (i=0; i<numptrblocks; i++) {
PROGRESS(i);
KASSERT(ptrblocks[i] != NULL);
kfree(ptrblocks[i]);
}
/* Free the upper tier. */
kfree(ptrblocks);
kprintf("kmalloctest3: passed\n");
kprintf("\n");
success(TEST161_SUCCESS, SECRET, "km3");
return 0;
}
@ -300,20 +318,24 @@ void
kmalloctest4thread(void *sm, unsigned long num)
{
#define NUM_KM4_SIZES 5
#define ITERATIONS 50
static const unsigned sizes[NUM_KM4_SIZES] = { 1, 3, 5, 2, 4 };
struct semaphore *sem = sm;
void *ptrs[NUM_KM4_SIZES];
unsigned p, q;
unsigned i;
unsigned i, j, k;
uint32_t magic;
for (i=0; i<NUM_KM4_SIZES; i++) {
ptrs[i] = NULL;
}
p = 0;
q = NUM_KM4_SIZES / 2;
magic = random();
for (i=0; i<NTRIES; i++) {
PROGRESS(i);
if (ptrs[q] != NULL) {
kfree(ptrs[q]);
ptrs[q] = NULL;
@ -324,6 +346,24 @@ kmalloctest4thread(void *sm, unsigned long num)
"allocating %u pages failed\n",
num, sizes[p]);
}
// Write to each page of the allocated memory and make sure nothing
// overwrites it.
for (k = 0; k < sizes[p]; k++) {
*((uint32_t *)ptrs[p] + k*PAGE_SIZE/sizeof(uint32_t)) = magic;
}
for (j = 0; j < ITERATIONS; j++) {
random_yielder(4);
for (k = 0; k < sizes[p]; k++) {
uint32_t actual = *((uint32_t *)ptrs[p] + k*PAGE_SIZE/sizeof(uint32_t));
if (actual != magic) {
panic("km4: expected %u got %u. Your VM is broken!",
magic, actual);
}
}
}
magic++;
p = (p + 1) % NUM_KM4_SIZES;
q = (q + 1) % NUM_KM4_SIZES;
}
@ -375,6 +415,193 @@ kmalloctest4(int nargs, char **args)
}
sem_destroy(sem);
kprintf("Multipage kmalloc test done\n");
kprintf("\n");
success(TEST161_SUCCESS, SECRET, "km4");
return 0;
}
static inline
void
km5_usage()
{
kprintf("usage: km5 [--avail <num_pages>] [--kernel <num_pages>]\n");
}
/*
* Allocate and free all physical memory a number of times. Along the we, we
* check coremap_used_bytes to make sure it's reporting the number we're
* expecting.
*/
int
kmalloctest5(int nargs, char **args)
{
#define KM5_ITERATIONS 5
// We're expecting an even number of arguments, less arg[0].
if (nargs > 5 || (nargs % 2) == 0) {
km5_usage();
return 0;
}
unsigned avail_page_slack = 0, kernel_page_limit = 0;
int arg = 1;
while (arg < nargs) {
if (strcmp(args[arg], "--avail") == 0) {
arg++;
avail_page_slack = atoi(args[arg++]);
} else if (strcmp(args[arg], "--kernel") == 0) {
arg++;
kernel_page_limit = atoi(args[arg++]);
} else {
km5_usage();
return 0;
}
}
#if OPT_DUMBVM
kprintf("(This test will not work with dumbvm)\n");
#endif
// First, we need to figure out how much memory we're running with and how
// much space it will take up if we maintain a pointer to each allocated
// page. We do something similar to km3 - for 32 bit systems with
// PAGE_SIZE == 4096, we can store 1024 pointers on a page. We keep an array
// of page size blocks of pointers which in total can hold enough pointers
// for each page of available physical memory.
unsigned orig_used, ptrs_per_page, num_ptr_blocks, max_pages;
unsigned total_ram, avail_ram, magic, orig_magic, known_pages;
ptrs_per_page = PAGE_SIZE / sizeof(void *);
total_ram = mainbus_ramsize();
avail_ram = total_ram - (uint32_t)(firstfree - MIPS_KSEG0);
max_pages = (avail_ram + PAGE_SIZE-1) / PAGE_SIZE;
num_ptr_blocks = (max_pages + ptrs_per_page-1) / ptrs_per_page;
// The array can go on the stack, we won't have that many
// (sys161 16M max => 4 blocks)
void **ptrs[num_ptr_blocks];
for (unsigned i = 0; i < num_ptr_blocks; i++) {
ptrs[i] = kmalloc(PAGE_SIZE);
if (ptrs[i] == NULL) {
panic("Can't allocate ptr page!");
}
bzero(ptrs[i], PAGE_SIZE);
}
kprintf("km5 --> phys ram: %uk avail ram: %uk (%u pages) ptr blocks: %u\n", total_ram/1024,
avail_ram/1024, max_pages, num_ptr_blocks);
// Initially, there must be at least 1 page allocated for each thread stack,
// one page for kmalloc for this thread struct, plus what we just allocated).
// This probably isn't the GLB, but its a decent lower bound.
orig_used = coremap_used_bytes();
known_pages = num_cpus + num_ptr_blocks + 1;
if (orig_used < known_pages * PAGE_SIZE) {
panic ("Not enough pages initially allocated");
}
if ((orig_used % PAGE_SIZE) != 0) {
panic("Coremap used bytes should be a multiple of PAGE_SIZE");
}
// Test for kernel bloat.
if (kernel_page_limit > 0) {
uint32_t kpages = (total_ram - avail_ram + PAGE_SIZE) / PAGE_SIZE;
if (kpages > kernel_page_limit) {
panic("You're kernel is bloated! Max allowed pages: %d, used pages: %d",
kernel_page_limit, kpages);
}
}
orig_magic = magic = random();
for (int i = 0; i < KM5_ITERATIONS; i++) {
// Step 1: allocate all physical memory, with checks along the way
unsigned int block, pos, oom, pages, used, prev;
void *page;
block = pos = oom = pages = used = 0;
prev = orig_used;
while (pages < max_pages+1) {
PROGRESS(pages);
page = kmalloc(PAGE_SIZE);
if (page == NULL) {
oom = 1;
break;
}
// Make sure we can write to the page
*(uint32_t *)page = magic++;
// Make sure the number of used bytes is going up, and by increments of PAGE_SIZE
used = coremap_used_bytes();
if (used != prev + PAGE_SIZE) {
panic("Allocation not equal to PAGE_SIZE. prev: %u used: %u", prev, used);
}
prev = used;
ptrs[block][pos] = page;
pos++;
if (pos >= ptrs_per_page) {
pos = 0;
block++;
}
pages++;
}
// Step 2: Check that we were able to allocate a reasonable number of pages
unsigned expected;
if (avail_page_slack > 0 ) {
// max avail pages + what we can prove we allocated + some slack
expected = max_pages - (known_pages + avail_page_slack);
} else {
// At the very least, just so we know things are working.
expected = 3;
}
if (pages < expected) {
panic("Expected to allocate at least %d pages, only allocated %d",
expected, pages);
}
// We tried to allocate 1 more page than is available in physical memory. That
// should fail unless you're swapping out kernel pages, which you should
// probably not be doing.
if (!oom) {
panic("Allocated more pages than physical memory. Are you swapping kernel pages?");
}
// Step 3: free everything and check that we're back to where we started
for (block = 0; block < num_ptr_blocks; block++) {
for (pos = 0; pos < ptrs_per_page; pos++) {
if (ptrs[block][pos] != NULL) {
// Make sure we got unique addresses
if ((*(uint32_t *)ptrs[block][pos]) != orig_magic++) {
panic("km5: expected %u got %u - your VM is broken!",
orig_magic-1, (*(uint32_t *)ptrs[block][pos]));
}
kfree(ptrs[block][pos]);
}
}
}
// Check that we're back to where we started
used = coremap_used_bytes();
if (used != orig_used) {
panic("orig (%u) != used (%u)", orig_used, used);
}
}
//Clean up the pointer blocks
for (unsigned i = 0; i < num_ptr_blocks; i++) {
kfree(ptrs[i]);
}
kprintf("\n");
success(TEST161_SUCCESS, SECRET, "km5");
return 0;
}

28
kern/test/lib.c Normal file
View File

@ -0,0 +1,28 @@
#include <types.h>
#include <thread.h>
#include <test.h>
#include <lib.h>
/*
* Helper functions used by testing and problem driver code
* to establish better mixtures of threads.
*/
void
random_yielder(uint32_t max_yield_count)
{
uint32_t i;
for (i = 0; i < random() % max_yield_count; i++) {
thread_yield();
}
}
void
random_spinner(uint32_t max_spin_count)
{
uint32_t i;
volatile int spin;
for (i = 0; i < random() % max_spin_count; i++) {
spin += i;
}
}

67
kern/test/rwtest.c Normal file
View File

@ -0,0 +1,67 @@
/*
* All the contents of this file are overwritten during automated
* testing. Please consider this before changing anything in this file.
*/
#include <types.h>
#include <lib.h>
#include <clock.h>
#include <thread.h>
#include <synch.h>
#include <test.h>
#include <kern/test161.h>
#include <spinlock.h>
/*
* Use these stubs to test your reader-writer locks.
*/
int rwtest(int nargs, char **args) {
(void)nargs;
(void)args;
kprintf_n("rwt1 unimplemented\n");
success(TEST161_FAIL, SECRET, "rwt1");
return 0;
}
int rwtest2(int nargs, char **args) {
(void)nargs;
(void)args;
kprintf_n("rwt2 unimplemented\n");
success(TEST161_FAIL, SECRET, "rwt2");
return 0;
}
int rwtest3(int nargs, char **args) {
(void)nargs;
(void)args;
kprintf_n("rwt3 unimplemented\n");
success(TEST161_FAIL, SECRET, "rwt3");
return 0;
}
int rwtest4(int nargs, char **args) {
(void)nargs;
(void)args;
kprintf_n("rwt4 unimplemented\n");
success(TEST161_FAIL, SECRET, "rwt4");
return 0;
}
int rwtest5(int nargs, char **args) {
(void)nargs;
(void)args;
kprintf_n("rwt5 unimplemented\n");
success(TEST161_FAIL, SECRET, "rwt5");
return 0;
}

688
kern/test/synchprobs.c Normal file
View File

@ -0,0 +1,688 @@
/*
* All the contents of this file are overwritten during automated
* testing. Please consider this before changing anything in this file.
*/
#include <types.h>
#include <lib.h>
#include <thread.h>
#include <test.h>
#include <current.h>
#include <synch.h>
#include <kern/test161.h>
#include <spinlock.h>
#define PROBLEMS_MAX_YIELDER 16
#define PROBLEMS_MAX_SPINNER 8192
#define TEST161_SUCCESS 0
#define TEST161_FAIL 1
/*
* Shared initialization routines
*/
static uint32_t startcount;
static struct lock *testlock;
static struct cv *startcv;
static struct semaphore *startsem;
static struct semaphore *endsem;
struct spinlock status_lock;
static bool test_status = TEST161_FAIL;
const char *test_message;
static
bool
failif(bool condition, const char *message) {
if (condition) {
spinlock_acquire(&status_lock);
test_status = TEST161_FAIL;
test_message = message;
spinlock_release(&status_lock);
}
return condition;
}
/*
* Helper function to initialize the thread pool.
*/
static
void
initialize_thread(volatile void* threads[], uint32_t index) {
failif((threads[index] != NULL), "failed: incorrect thread type");
threads[index] = curthread->t_stack;
}
/*
* Helper function to check whether current thread is valid.
*/
static
void
check_thread(volatile void* threads[], uint32_t index) {
failif((threads[index] != curthread->t_stack), "failed: incorrect thread type");
}
/*
* Driver code for the whalemating problem.
*/
#define NMATING 10
#define MALE 0
#define FEMALE 1
#define MATCHMAKER 2
#define CHECK_TIMES 32
static volatile int male_start_count;
static volatile int male_end_count;
static volatile int female_start_count;
static volatile int female_end_count;
static volatile int matchmaker_start_count;
static volatile int matchmaker_end_count;
static volatile int match_count;
static volatile int concurrent_matchmakers;
static volatile int max_concurrent_matchmakers;
static volatile void* whale_threads[3 * NMATING];
static volatile int whale_roles[3 * NMATING];
static struct semaphore *matcher_sem;
/*
* Enforce male_start() and male_end() called from male thread.
* Similar for female and matchmaker threads
*/
static
void
check_role(uint32_t index, int role) {
failif((whale_roles[index] != role), "failed: incorrect role");
}
static
void
male_wrapper(void * unused1, unsigned long index) {
(void)unused1;
random_yielder(4);
lock_acquire(testlock);
initialize_thread(whale_threads, (uint32_t)index);
whale_roles[index] = MALE;
lock_release(testlock);
male((uint32_t)index);
return;
}
void
male_start(uint32_t index) {
(void)index;
lock_acquire(testlock);
check_thread(whale_threads, index);
check_role(index, MALE);
male_start_count++;
kprintf_n("%s starting\n", curthread->t_name);
kprintf_t(".");
lock_release(testlock);
random_yielder(PROBLEMS_MAX_YIELDER);
random_spinner(PROBLEMS_MAX_SPINNER);
V(startsem);
}
void
male_end(uint32_t index) {
(void)index;
lock_acquire(testlock);
check_thread(whale_threads, index);
check_role(index, MALE);
male_end_count++;
kprintf_n("%s ending\n", curthread->t_name);
kprintf_t(".");
lock_release(testlock);
random_yielder(PROBLEMS_MAX_YIELDER);
random_spinner(PROBLEMS_MAX_SPINNER);
V(endsem);
}
static
void
female_wrapper(void * unused1, unsigned long index) {
(void)unused1;
random_yielder(4);
lock_acquire(testlock);
initialize_thread(whale_threads, (uint32_t)index);
whale_roles[index] = FEMALE;
lock_release(testlock);
female((uint32_t)index);
return;
}
void
female_start(uint32_t index) {
(void) index;
lock_acquire(testlock);
check_thread(whale_threads, index);
check_role(index, FEMALE);
female_start_count++;
kprintf_n("%s starting\n", curthread->t_name);
kprintf_t(".");
lock_release(testlock);
random_yielder(PROBLEMS_MAX_YIELDER);
random_spinner(PROBLEMS_MAX_SPINNER);
V(startsem);
}
void
female_end(uint32_t index) {
(void) index;
lock_acquire(testlock);
check_thread(whale_threads, index);
check_role(index, FEMALE);
female_end_count++;
kprintf_n("%s ending\n", curthread->t_name);
kprintf_t(".");
lock_release(testlock);
random_yielder(PROBLEMS_MAX_YIELDER);
random_spinner(PROBLEMS_MAX_SPINNER);
V(endsem);
}
static
void
matchmaker_wrapper(void * unused1, unsigned long index) {
(void)unused1;
random_yielder(4);
lock_acquire(testlock);
initialize_thread(whale_threads, (uint32_t)index);
whale_roles[index] = MATCHMAKER;
lock_release(testlock);
matchmaker((uint32_t)index);
return;
}
void
matchmaker_start(uint32_t index) {
(void)index;
P(matcher_sem);
lock_acquire(testlock);
check_thread(whale_threads, index);
check_role(index, MATCHMAKER);
matchmaker_start_count++;
concurrent_matchmakers++;
if (concurrent_matchmakers > max_concurrent_matchmakers) {
max_concurrent_matchmakers = concurrent_matchmakers;
}
kprintf_n("%s starting\n", curthread->t_name);
kprintf_t(".");
lock_release(testlock);
random_yielder(PROBLEMS_MAX_YIELDER);
random_spinner(PROBLEMS_MAX_SPINNER);
V(startsem);
}
void
matchmaker_end(uint32_t index) {
(void)index;
lock_acquire(testlock);
check_thread(whale_threads, index);
check_role(index, MATCHMAKER);
match_count++;
matchmaker_end_count++;
concurrent_matchmakers--;
kprintf_n("%s ending\n", curthread->t_name);
kprintf_t(".");
lock_release(testlock);
random_yielder(PROBLEMS_MAX_YIELDER);
random_spinner(PROBLEMS_MAX_SPINNER);
V(endsem);
}
int
whalemating(int nargs, char **args) {
(void) nargs;
(void) args;
int i, j, err = 0;
char name[32];
bool loop_status;
int total_count = 0;
male_start_count = 0 ;
male_end_count = 0 ;
female_start_count = 0 ;
female_end_count = 0 ;
matchmaker_start_count = 0;
matchmaker_end_count = 0;
match_count = 0;
concurrent_matchmakers = 0;
max_concurrent_matchmakers = 0;
kprintf_n("Starting sp1...\n");
kprintf_n("If this tests hangs, your solution is incorrect.\n");
testlock = lock_create("testlock");
if (testlock == NULL) {
panic("sp1: lock_create failed\n");
}
startsem = sem_create("startsem", 0);
if (startsem == NULL) {
panic("sp1: sem_create failed\n");
}
endsem = sem_create("endsem", 0);
if (endsem == NULL) {
panic("sp1: sem_create failed\n");
}
matcher_sem = sem_create("matcher_sem", 0);
if (matcher_sem == NULL) {
panic("sp1: sem_create failed\n");
}
spinlock_init(&status_lock);
test_status = TEST161_SUCCESS;
test_message = "";
whalemating_init();
/* Start males and females only. */
for (i = 0; i < 2; i++) {
for (j = 0; j < NMATING; j++) {
kprintf_t(".");
int index = (i * NMATING) + j;
whale_threads[index] = NULL;
switch (i) {
case 0:
snprintf(name, sizeof(name), "Male Whale Thread %d", index);
err = thread_fork(name, NULL, male_wrapper, NULL, index);
break;
case 1:
snprintf(name, sizeof(name), "Female Whale Thread %d", index);
err = thread_fork(name, NULL, female_wrapper, NULL, index);
break;
}
total_count += 1;
if (err) {
panic("sp1: thread_fork failed: (%s)\n", strerror(err));
}
}
}
/* Wait for males and females to start. */
for (i = 0; i < NMATING * 2; i++) {
kprintf_t(".");
P(startsem);
}
/* Make sure nothing is happening... */
loop_status = TEST161_SUCCESS;
for (i = 0; i < CHECK_TIMES && loop_status == TEST161_SUCCESS; i++) {
kprintf_t(".");
random_spinner(PROBLEMS_MAX_SPINNER);
lock_acquire(testlock);
if ((male_start_count != NMATING) || (female_start_count != NMATING) ||
(matchmaker_start_count + male_end_count + female_end_count + matchmaker_end_count != 0)) {
loop_status = TEST161_FAIL;
}
lock_release(testlock);
}
if (failif((loop_status == TEST161_FAIL), "failed: uncoordinated matchmaking is occurring")) {
goto done;
}
/* Create the matchmakers */
for (j = 0; j < NMATING; j++) {
kprintf_t(".");
int index = (2 * NMATING) + j;
whale_threads[index] = NULL;
snprintf(name, sizeof(name), "Matchmaker Whale Thread %d", index);
err = thread_fork(name, NULL, matchmaker_wrapper, NULL, index);
if (err) {
panic("sp1: thread_fork failed: (%s)\n", strerror(err));
}
total_count++;
}
/*
* Release a random number of matchmakers and wait for them and their
* matches to finish.
*/
int pivot = (random() % (NMATING - 2)) + 1;
for (i = 0; i < pivot; i++) {
kprintf_t(".");
V(matcher_sem);
}
for (i = 0; i < 3 * pivot; i++) {
kprintf_t(".");
P(endsem);
total_count--;
}
/* Make sure nothing else is happening... */
loop_status = TEST161_SUCCESS;
for (i = 0; i < CHECK_TIMES && loop_status == TEST161_SUCCESS; i++) {
kprintf_t(".");
random_spinner(PROBLEMS_MAX_SPINNER);
lock_acquire(testlock);
if ((male_start_count != NMATING) || (female_start_count != NMATING) ||
(matchmaker_start_count != pivot) || (male_end_count != pivot) ||
(female_end_count != pivot) || (matchmaker_end_count != pivot)) {
loop_status = TEST161_FAIL;
}
lock_release(testlock);
}
if (failif((loop_status == TEST161_FAIL), "failed: uncoordinated matchmaking is occurring")) {
goto done;
}
/*
* Release the rest of the matchmakers and wait for everyone to finish.
*/
for (i = pivot; i < NMATING; i++) {
kprintf_t(".");
V(matcher_sem);
}
for (i = 0; i < 3; i++) {
for (j = pivot; j < NMATING; j++) {
kprintf_t(".");
P(endsem);
total_count--;
}
}
failif((max_concurrent_matchmakers == 1), "failed: no matchmaker concurrency");
whalemating_cleanup();
done:
for (i = 0; i < total_count; i++) {
P(endsem);
}
lock_destroy(testlock);
sem_destroy(startsem);
sem_destroy(endsem);
sem_destroy(matcher_sem);
kprintf_t("\n");
if (test_status != TEST161_SUCCESS) {
secprintf(SECRET, test_message, "sp1");
}
success(test_status, SECRET, "sp1");
return 0;
}
/*
* Driver code for the stoplight problem.
*/
#define NCARS 64
#define NUM_QUADRANTS 4
#define UNKNOWN_CAR -1
#define PASSED_CAR -2
#define GO_STRAIGHT 0
#define TURN_LEFT 1
#define TURN_RIGHT 2
static volatile int quadrant_array[NUM_QUADRANTS];
static volatile int max_car_count;
static volatile int all_quadrant;
static volatile int car_locations[NCARS];
static volatile int car_directions[NCARS];
static volatile int car_turns[NCARS];
static volatile int car_turn_times[NCARS];
static volatile void* car_threads[NCARS];
static
void
initialize_car_thread(uint32_t index, uint32_t direction, uint32_t turn) {
initialize_thread(car_threads, index);
car_directions[index] = direction;
car_turns[index] = turn;
car_turn_times[index] = 0;
}
static
void
check_intersection() {
int n = 0;
for (int i = 0; i < NUM_QUADRANTS; i++) {
failif((quadrant_array[i] > 1), "failed: collision");
n += quadrant_array[i];
}
max_car_count = n > max_car_count ? n : max_car_count;
}
/*
* When car move, must call this function and hold a lock.
* It first checks current intersection status make sure no more than one car in one quadrant.
* Then it removes current car from previous location.
* In the end, it returns current car's index for inQuadrant, to let inQuadrant update car_locations array.
*/
static
int
move(uint32_t index) {
check_thread(car_threads, index);
check_intersection();
int pre_location = car_locations[index];
if (pre_location != UNKNOWN_CAR && pre_location != PASSED_CAR) {
quadrant_array[pre_location]--;
}
return pre_location;
}
static
void
turnright_wrapper(void *index, unsigned long direction)
{
random_yielder(4);
lock_acquire(testlock);
initialize_car_thread((uint32_t)index, (uint32_t)direction, TURN_RIGHT);
startcount--;
if (startcount == 0) {
cv_broadcast(startcv, testlock);
} else {
cv_wait(startcv, testlock);
}
lock_release(testlock);
turnright((uint32_t)direction, (uint32_t)index);
V(endsem);
return;
}
static
void
gostraight_wrapper(void *index, unsigned long direction)
{
random_yielder(4);
lock_acquire(testlock);
initialize_car_thread((uint32_t)index, (uint32_t)direction, GO_STRAIGHT);
startcount--;
if (startcount == 0) {
cv_broadcast(startcv, testlock);
} else {
cv_wait(startcv, testlock);
}
lock_release(testlock);
gostraight((uint32_t)direction, (uint32_t)index);
V(endsem);
return;
}
static
void
turnleft_wrapper(void *index, unsigned long direction)
{
random_yielder(4);
lock_acquire(testlock);
initialize_car_thread((uint32_t)index, (uint32_t)direction, TURN_LEFT);
startcount--;
if (startcount == 0) {
cv_broadcast(startcv, testlock);
} else {
cv_wait(startcv, testlock);
}
lock_release(testlock);
turnleft((uint32_t)direction, (uint32_t)index);
V(endsem);
return;
}
void
inQuadrant(int quadrant, uint32_t index) {
random_yielder(PROBLEMS_MAX_YIELDER);
random_spinner(PROBLEMS_MAX_SPINNER);
lock_acquire(testlock);
int pre_quadrant = move(index);
int target_quadrant = car_directions[index];
switch (car_turn_times[index]) {
case 0:
failif((pre_quadrant != UNKNOWN_CAR), "failed: invalid turn");
break;
case 1:
failif((pre_quadrant != target_quadrant), "failed: invalid turn");
target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS;
break;
case 2:
target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS;
failif((pre_quadrant != target_quadrant), "failed: invalid turn");
target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS;
break;
default:
failif(true, "failed: invalid turn");
break;
}
failif((quadrant != target_quadrant), "failed: invalid turn");
car_turn_times[index]++;
failif((quadrant_array[quadrant] > 0), "failed: collision");
quadrant_array[quadrant]++;
car_locations[index] = quadrant;
all_quadrant++;
lock_release(testlock);
kprintf_n("%s in quadrant %d\n", curthread->t_name, quadrant);
}
void
leaveIntersection(uint32_t index) {
random_yielder(PROBLEMS_MAX_YIELDER);
random_spinner(PROBLEMS_MAX_SPINNER);
lock_acquire(testlock);
move(index);
switch (car_turns[index]) {
case GO_STRAIGHT:
failif((car_turn_times[index] != 2), "failed: incorrect turn");
break;
case TURN_LEFT:
failif((car_turn_times[index] != 3), "failed: incorrect turn");
break;
case TURN_RIGHT:
failif((car_turn_times[index] != 1), "failed: incorrect turn");
break;
default:
failif(true, "failed: incorrect turn");
break;
}
car_locations[index] = PASSED_CAR;
lock_release(testlock);
kprintf_n("%s left the intersection\n", curthread->t_name);
}
int stoplight(int nargs, char **args) {
(void) nargs;
(void) args;
int i, direction, turn, err = 0;
char name[32];
int required_quadrant = 0;
int passed = 0;
max_car_count = 0;
all_quadrant = 0;
kprintf_n("Starting sp2...\n");
kprintf_n("If this tests hangs, your solution is incorrect.\n");
for (i = 0; i < NUM_QUADRANTS; i++) {
quadrant_array[i] = 0;
}
for (i = 0; i < NCARS; i++) {
car_locations[i] = UNKNOWN_CAR;
car_threads[i] = NULL;
car_directions[i] = -1;
}
startcount = NCARS;
testlock = lock_create("testlock");
if (testlock == NULL) {
panic("sp2: lock_create failed\n");
}
startcv = cv_create("startcv");
if (startcv == NULL) {
panic("sp2: cv_create failed\n");
}
endsem = sem_create("endsem", 0);
if (endsem == NULL) {
panic("sp2: sem_create failed\n");
}
spinlock_init(&status_lock);
test_status = TEST161_SUCCESS;
stoplight_init();
for (i = 0; i < NCARS; i++) {
kprintf_t(".");
direction = random() % 4;
turn = random() % 3;
snprintf(name, sizeof(name), "Car Thread %d", i);
switch (turn) {
case GO_STRAIGHT:
err = thread_fork(name, NULL, gostraight_wrapper, (void *)i, direction);
required_quadrant += 2;
break;
case TURN_LEFT:
err = thread_fork(name, NULL, turnleft_wrapper, (void *)i, direction);
required_quadrant += 3;
break;
case TURN_RIGHT:
err = thread_fork(name, NULL, turnright_wrapper, (void *)i, direction);
required_quadrant += 1;
break;
}
if (err) {
panic("sp2: thread_fork failed: (%s)\n", strerror(err));
}
}
for (i = 0; i < NCARS; i++) {
kprintf_t(".");
P(endsem);
}
stoplight_cleanup();
for (i = 0; i < NCARS; i++) {
passed += car_locations[i] == PASSED_CAR ? 1 : 0;
}
if ((test_status == TEST161_SUCCESS) &&
(!(failif((passed != NCARS), "failed: not enough cars"))) &&
(!(failif((all_quadrant != required_quadrant), "failed: didn't do the right turns"))) &&
(!(failif((max_car_count <= 1), "failed: no concurrency achieved")))) {};
lock_destroy(testlock);
cv_destroy(startcv);
sem_destroy(endsem);
kprintf_t("\n");
if (test_status != TEST161_SUCCESS) {
secprintf(SECRET, test_message, "sp2");
}
success(test_status, SECRET, "sp2");
return 0;
}

View File

@ -29,6 +29,9 @@
/*
* Synchronization test code.
*
* All the contents of this file are overwritten during automated
* testing. Please consider this before changing anything in this file.
*/
#include <types.h>
@ -37,222 +40,462 @@
#include <thread.h>
#include <synch.h>
#include <test.h>
#include <kern/test161.h>
#include <spinlock.h>
#define CREATELOOPS 8
#define NSEMLOOPS 63
#define NLOCKLOOPS 120
#define NCVLOOPS 5
#define NTHREADS 32
#define SYNCHTEST_YIELDER_MAX 16
static volatile unsigned long testval1;
static volatile unsigned long testval2;
static volatile unsigned long testval3;
static struct semaphore *testsem;
static struct lock *testlock;
static struct cv *testcv;
static struct semaphore *donesem;
static volatile int32_t testval4;
static struct semaphore *testsem = NULL;
static struct semaphore *testsem2 = NULL;
static struct lock *testlock = NULL;
static struct lock *testlock2 = NULL;
static struct cv *testcv = NULL;
static struct semaphore *donesem = NULL;
struct spinlock status_lock;
static bool test_status = TEST161_FAIL;
static unsigned long semtest_current;
static
void
inititems(void)
{
if (testsem==NULL) {
testsem = sem_create("testsem", 2);
if (testsem == NULL) {
panic("synchtest: sem_create failed\n");
}
}
if (testlock==NULL) {
testlock = lock_create("testlock");
if (testlock == NULL) {
panic("synchtest: lock_create failed\n");
}
}
if (testcv==NULL) {
testcv = cv_create("testlock");
if (testcv == NULL) {
panic("synchtest: cv_create failed\n");
}
}
if (donesem==NULL) {
donesem = sem_create("donesem", 0);
if (donesem == NULL) {
panic("synchtest: sem_create failed\n");
}
bool
failif(bool condition) {
if (condition) {
spinlock_acquire(&status_lock);
test_status = TEST161_FAIL;
spinlock_release(&status_lock);
}
return condition;
}
static
void
semtestthread(void *junk, unsigned long num)
{
int i;
(void)junk;
int i;
random_yielder(4);
/*
* Only one of these should print at a time.
*/
P(testsem);
kprintf("Thread %2lu: ", num);
semtest_current = num;
kprintf_n("Thread %2lu: ", num);
for (i=0; i<NSEMLOOPS; i++) {
kprintf("%c", (int)num+64);
kprintf_t(".");
kprintf_n("%2lu", num);
random_yielder(4);
failif((semtest_current != num));
}
kprintf("\n");
kprintf_n("\n");
V(donesem);
}
int
semtest(int nargs, char **args)
{
int i, result;
(void)nargs;
(void)args;
inititems();
kprintf("Starting semaphore test...\n");
kprintf("If this hangs, it's broken: ");
int i, result;
kprintf_n("Starting sem1...\n");
for (i=0; i<CREATELOOPS; i++) {
kprintf_t(".");
testsem = sem_create("testsem", 2);
if (testsem == NULL) {
panic("sem1: sem_create failed\n");
}
donesem = sem_create("donesem", 0);
if (donesem == NULL) {
panic("sem1: sem_create failed\n");
}
if (i != CREATELOOPS - 1) {
sem_destroy(testsem);
sem_destroy(donesem);
}
}
spinlock_init(&status_lock);
test_status = TEST161_SUCCESS;
kprintf_n("If this hangs, it's broken: ");
P(testsem);
P(testsem);
kprintf("ok\n");
kprintf_n("OK\n");
kprintf_t(".");
for (i=0; i<NTHREADS; i++) {
kprintf_t(".");
result = thread_fork("semtest", NULL, semtestthread, NULL, i);
if (result) {
panic("semtest: thread_fork failed: %s\n",
panic("sem1: thread_fork failed: %s\n",
strerror(result));
}
}
for (i=0; i<NTHREADS; i++) {
kprintf_t(".");
V(testsem);
P(donesem);
}
/* so we can run it again */
V(testsem);
V(testsem);
sem_destroy(testsem);
sem_destroy(donesem);
testsem = donesem = NULL;
kprintf_t("\n");
success(test_status, SECRET, "sem1");
kprintf("Semaphore test done.\n");
return 0;
}
static
void
fail(unsigned long num, const char *msg)
{
kprintf("thread %lu: Mismatch on %s\n", num, msg);
kprintf("Test failed\n");
lock_release(testlock);
V(donesem);
thread_exit();
}
static
void
locktestthread(void *junk, unsigned long num)
{
int i;
(void)junk;
int i;
for (i=0; i<NLOCKLOOPS; i++) {
kprintf_t(".");
KASSERT(!(lock_do_i_hold(testlock)));
lock_acquire(testlock);
KASSERT(lock_do_i_hold(testlock));
random_yielder(4);
testval1 = num;
testval2 = num*num;
testval3 = num%3;
if (testval2 != testval1*testval1) {
fail(num, "testval2/testval1");
goto fail;
}
random_yielder(4);
KASSERT(lock_do_i_hold(testlock));
if (testval2%3 != (testval3*testval3)%3) {
fail(num, "testval2/testval3");
goto fail;
}
random_yielder(4);
KASSERT(lock_do_i_hold(testlock));
if (testval3 != testval1%3) {
fail(num, "testval3/testval1");
goto fail;
}
random_yielder(4);
KASSERT(lock_do_i_hold(testlock));
if (testval1 != num) {
fail(num, "testval1/num");
goto fail;
}
random_yielder(4);
KASSERT(lock_do_i_hold(testlock));
if (testval2 != num*num) {
fail(num, "testval2/num");
goto fail;
}
random_yielder(4);
KASSERT(lock_do_i_hold(testlock));
if (testval3 != num%3) {
fail(num, "testval3/num");
goto fail;
}
random_yielder(4);
KASSERT(lock_do_i_hold(testlock));
if (!(lock_do_i_hold(testlock))) {
goto fail;
}
random_yielder(4);
KASSERT(lock_do_i_hold(testlock));
lock_release(testlock);
KASSERT(!(lock_do_i_hold(testlock)));
}
V(donesem);
}
/* Check for solutions that don't track ownership properly */
for (i=0; i<NLOCKLOOPS; i++) {
kprintf_t(".");
if (lock_do_i_hold(testlock)) {
goto fail2;
}
}
V(donesem);
return;
fail:
lock_release(testlock);
fail2:
failif(true);
V(donesem);
return;
}
int
locktest(int nargs, char **args)
{
int i, result;
(void)nargs;
(void)args;
inititems();
kprintf("Starting lock test...\n");
int i, result;
kprintf_n("Starting lt1...\n");
for (i=0; i<CREATELOOPS; i++) {
kprintf_t(".");
testlock = lock_create("testlock");
if (testlock == NULL) {
panic("lt1: lock_create failed\n");
}
donesem = sem_create("donesem", 0);
if (donesem == NULL) {
panic("lt1: sem_create failed\n");
}
if (i != CREATELOOPS - 1) {
lock_destroy(testlock);
sem_destroy(donesem);
}
}
spinlock_init(&status_lock);
test_status = TEST161_SUCCESS;
for (i=0; i<NTHREADS; i++) {
result = thread_fork("synchtest", NULL, locktestthread,
NULL, i);
kprintf_t(".");
result = thread_fork("synchtest", NULL, locktestthread, NULL, i);
if (result) {
panic("locktest: thread_fork failed: %s\n",
strerror(result));
panic("lt1: thread_fork failed: %s\n", strerror(result));
}
}
for (i=0; i<NTHREADS; i++) {
kprintf_t(".");
P(donesem);
}
kprintf("Lock test done.\n");
lock_destroy(testlock);
sem_destroy(donesem);
testlock = NULL;
donesem = NULL;
kprintf_t("\n");
success(test_status, SECRET, "lt1");
return 0;
}
/*
* Note that the following tests that panic on success do minimal cleanup
* afterward. This is to avoid causing a panic that could be unintentiontally
* considered a success signal by test161. As a result, they leak memory,
* don't destroy synchronization primitives, etc.
*/
int
locktest2(int nargs, char **args) {
(void)nargs;
(void)args;
kprintf_n("Starting lt2...\n");
kprintf_n("(This test panics on success!)\n");
testlock = lock_create("testlock");
if (testlock == NULL) {
panic("lt2: lock_create failed\n");
}
secprintf(SECRET, "Should panic...", "lt2");
lock_release(testlock);
/* Should not get here on success. */
success(TEST161_FAIL, SECRET, "lt2");
/* Don't do anything that could panic. */
testlock = NULL;
return 0;
}
int
locktest3(int nargs, char **args) {
(void)nargs;
(void)args;
kprintf_n("Starting lt3...\n");
kprintf_n("(This test panics on success!)\n");
testlock = lock_create("testlock");
if (testlock == NULL) {
panic("lt3: lock_create failed\n");
}
secprintf(SECRET, "Should panic...", "lt3");
lock_acquire(testlock);
lock_destroy(testlock);
/* Should not get here on success. */
success(TEST161_FAIL, SECRET, "lt3");
/* Don't do anything that could panic. */
testlock = NULL;
return 0;
}
/*
* Used by both lt4 and lt5 below. Simply acquires a lock in a separate
* thread. Uses a semaphore as a barrier to make sure it gets the lock before
* the driver completes.
*/
static
void
locktestacquirer(void * junk, unsigned long num)
{
(void)junk;
(void)num;
lock_acquire(testlock);
V(donesem);
return;
}
int
locktest4(int nargs, char **args) {
(void) nargs;
(void) args;
int result;
kprintf_n("Starting lt4...\n");
kprintf_n("(This test panics on success!)\n");
testlock = lock_create("testlock");
if (testlock == NULL) {
panic("lt4: lock_create failed\n");
}
donesem = sem_create("donesem", 0);
if (donesem == NULL) {
lock_destroy(testlock);
panic("lt4: sem_create failed\n");
}
result = thread_fork("lt4", NULL, locktestacquirer, NULL, 0);
if (result) {
panic("lt4: thread_fork failed: %s\n", strerror(result));
}
P(donesem);
secprintf(SECRET, "Should panic...", "lt4");
lock_release(testlock);
/* Should not get here on success. */
success(TEST161_FAIL, SECRET, "lt4");
/* Don't do anything that could panic. */
testlock = NULL;
donesem = NULL;
return 0;
}
int
locktest5(int nargs, char **args) {
(void) nargs;
(void) args;
int result;
kprintf_n("Starting lt5...\n");
kprintf_n("(This test panics on success!)\n");
testlock = lock_create("testlock");
if (testlock == NULL) {
panic("lt5: lock_create failed\n");
}
donesem = sem_create("donesem", 0);
if (donesem == NULL) {
lock_destroy(testlock);
panic("lt5: sem_create failed\n");
}
result = thread_fork("lt5", NULL, locktestacquirer, NULL, 0);
if (result) {
panic("lt5: thread_fork failed: %s\n", strerror(result));
}
P(donesem);
secprintf(SECRET, "Should panic...", "lt5");
KASSERT(lock_do_i_hold(testlock));
/* Should not get here on success. */
success(TEST161_FAIL, SECRET, "lt5");
/* Don't do anything that could panic. */
testlock = NULL;
donesem = NULL;
return 0;
}
static
void
cvtestthread(void *junk, unsigned long num)
{
(void)junk;
int i;
volatile int j;
struct timespec ts1, ts2;
(void)junk;
for (i=0; i<NCVLOOPS; i++) {
kprintf_t(".");
lock_acquire(testlock);
while (testval1 != num) {
testval2 = 0;
random_yielder(4);
gettime(&ts1);
cv_wait(testcv, testlock);
gettime(&ts2);
random_yielder(4);
/* ts2 -= ts1 */
timespec_sub(&ts2, &ts1, &ts2);
/* Require at least 2000 cpu cycles (we're 25mhz) */
if (ts2.tv_sec == 0 && ts2.tv_nsec < 40*2000) {
kprintf("cv_wait took only %u ns\n",
ts2.tv_nsec);
kprintf("That's too fast... you must be "
"busy-looping\n");
kprintf_n("cv_wait took only %u ns\n", ts2.tv_nsec);
kprintf_n("That's too fast... you must be busy-looping\n");
failif(true);
V(donesem);
thread_exit();
}
testval2 = 0xFFFFFFFF;
}
kprintf("Thread %lu\n", num);
testval1 = (testval1 + NTHREADS - 1)%NTHREADS;
testval2 = num;
/*
* loop a little while to make sure we can measure the
@ -260,7 +503,13 @@ cvtestthread(void *junk, unsigned long num)
*/
for (j=0; j<3000; j++);
random_yielder(4);
cv_broadcast(testcv, testlock);
random_yielder(4);
failif((testval1 != testval2));
kprintf_n("Thread %lu\n", testval2);
testval1 = (testval1 + NTHREADS - 1) % NTHREADS;
lock_release(testlock);
}
V(donesem);
@ -269,30 +518,57 @@ cvtestthread(void *junk, unsigned long num)
int
cvtest(int nargs, char **args)
{
int i, result;
(void)nargs;
(void)args;
inititems();
kprintf("Starting CV test...\n");
kprintf("Threads should print out in reverse order.\n");
int i, result;
kprintf_n("Starting cvt1...\n");
for (i=0; i<CREATELOOPS; i++) {
kprintf_t(".");
testlock = lock_create("testlock");
if (testlock == NULL) {
panic("cvt1: lock_create failed\n");
}
testcv = cv_create("testcv");
if (testcv == NULL) {
panic("cvt1: cv_create failed\n");
}
donesem = sem_create("donesem", 0);
if (donesem == NULL) {
panic("cvt1: sem_create failed\n");
}
if (i != CREATELOOPS - 1) {
lock_destroy(testlock);
cv_destroy(testcv);
sem_destroy(donesem);
}
}
spinlock_init(&status_lock);
test_status = TEST161_SUCCESS;
testval1 = NTHREADS-1;
for (i=0; i<NTHREADS; i++) {
result = thread_fork("synchtest", NULL, cvtestthread, NULL, i);
kprintf_t(".");
result = thread_fork("cvt1", NULL, cvtestthread, NULL, (long unsigned) i);
if (result) {
panic("cvtest: thread_fork failed: %s\n",
strerror(result));
panic("cvt1: thread_fork failed: %s\n", strerror(result));
}
}
for (i=0; i<NTHREADS; i++) {
kprintf_t(".");
P(donesem);
}
kprintf("CV test done\n");
lock_destroy(testlock);
cv_destroy(testcv);
sem_destroy(donesem);
testlock = NULL;
testcv = NULL;
donesem = NULL;
kprintf_t("\n");
success(test_status, SECRET, "cvt1");
return 0;
}
@ -318,19 +594,28 @@ static
void
sleepthread(void *junk1, unsigned long junk2)
{
unsigned i, j;
(void)junk1;
(void)junk2;
unsigned i, j;
random_yielder(4);
for (j=0; j<NLOOPS; j++) {
kprintf_t(".");
for (i=0; i<NCVS; i++) {
lock_acquire(testlocks[i]);
random_yielder(4);
V(gatesem);
random_yielder(4);
spinlock_acquire(&status_lock);
testval4++;
spinlock_release(&status_lock);
cv_wait(testcvs[i], testlocks[i]);
random_yielder(4);
lock_release(testlocks[i]);
}
kprintf("sleepthread: %u\n", j);
kprintf_n("sleepthread: %u\n", j);
}
V(exitsem);
}
@ -339,19 +624,28 @@ static
void
wakethread(void *junk1, unsigned long junk2)
{
unsigned i, j;
(void)junk1;
(void)junk2;
unsigned i, j;
random_yielder(4);
for (j=0; j<NLOOPS; j++) {
kprintf_t(".");
for (i=0; i<NCVS; i++) {
random_yielder(4);
P(gatesem);
random_yielder(4);
lock_acquire(testlocks[i]);
random_yielder(4);
testval4--;
failif((testval4 != 0));
cv_signal(testcvs[i], testlocks[i]);
random_yielder(4);
lock_release(testlocks[i]);
}
kprintf("wakethread: %u\n", j);
kprintf_n("wakethread: %u\n", j);
}
V(exitsem);
}
@ -359,30 +653,44 @@ wakethread(void *junk1, unsigned long junk2)
int
cvtest2(int nargs, char **args)
{
unsigned i;
int result;
(void)nargs;
(void)args;
unsigned i;
int result;
kprintf_n("Starting cvt2...\n");
for (i=0; i<CREATELOOPS; i++) {
kprintf_t(".");
gatesem = sem_create("gatesem", 0);
if (gatesem == NULL) {
panic("cvt2: sem_create failed\n");
}
exitsem = sem_create("exitsem", 0);
if (exitsem == NULL) {
panic("cvt2: sem_create failed\n");
}
if (i != CREATELOOPS - 1) {
sem_destroy(gatesem);
sem_destroy(exitsem);
}
}
for (i=0; i<NCVS; i++) {
kprintf_t(".");
testlocks[i] = lock_create("cvtest2 lock");
testcvs[i] = cv_create("cvtest2 cv");
}
gatesem = sem_create("gatesem", 0);
exitsem = sem_create("exitsem", 0);
spinlock_init(&status_lock);
test_status = TEST161_SUCCESS;
kprintf("cvtest2...\n");
result = thread_fork("cvtest2", NULL, sleepthread, NULL, 0);
result = thread_fork("cvt2", NULL, sleepthread, NULL, 0);
if (result) {
panic("cvtest2: thread_fork failed\n");
panic("cvt2: thread_fork failed\n");
}
result = thread_fork("cvtest2", NULL, wakethread, NULL, 0);
result = thread_fork("cvt2", NULL, wakethread, NULL, 0);
if (result) {
panic("cvtest2: thread_fork failed\n");
panic("cvt2: thread_fork failed\n");
}
P(exitsem);
P(exitsem);
@ -390,12 +698,194 @@ cvtest2(int nargs, char **args)
sem_destroy(gatesem);
exitsem = gatesem = NULL;
for (i=0; i<NCVS; i++) {
kprintf_t(".");
lock_destroy(testlocks[i]);
cv_destroy(testcvs[i]);
testlocks[i] = NULL;
testcvs[i] = NULL;
}
kprintf("cvtest2 done\n");
kprintf_t("\n");
success(test_status, SECRET, "cvt2");
return 0;
}
int
cvtest3(int nargs, char **args) {
(void)nargs;
(void)args;
kprintf_n("Starting cvt3...\n");
kprintf_n("(This test panics on success!)\n");
testlock = lock_create("testlock");
if (testlock == NULL) {
panic("cvt3: lock_create failed\n");
}
testcv = cv_create("testcv");
if (testcv == NULL) {
panic("cvt3: cv_create failed\n");
}
secprintf(SECRET, "Should panic...", "cvt3");
cv_wait(testcv, testlock);
/* Should not get here on success. */
success(TEST161_FAIL, SECRET, "cvt3");
lock_destroy(testlock);
cv_destroy(testcv);
testcv = NULL;
testlock = NULL;
return 0;
}
int
cvtest4(int nargs, char **args) {
(void)nargs;
(void)args;
kprintf_n("Starting cvt4...\n");
kprintf_n("(This test panics on success!)\n");
testlock = lock_create("testlock");
if (testlock == NULL) {
panic("cvt4: lock_create failed\n");
}
testcv = cv_create("testcv");
if (testcv == NULL) {
panic("cvt4: cv_create failed\n");
}
secprintf(SECRET, "Should panic...", "cvt4");
cv_broadcast(testcv, testlock);
/* Should not get here on success. */
success(TEST161_FAIL, SECRET, "cvt4");
lock_destroy(testlock);
cv_destroy(testcv);
testcv = NULL;
testlock = NULL;
return 0;
}
static
void
sleeperthread(void *junk1, unsigned long junk2) {
(void)junk1;
(void)junk2;
random_yielder(4);
lock_acquire(testlock);
random_yielder(4);
failif((testval1 != 0));
testval1 = 1;
cv_signal(testcv, testlock);
random_yielder(4);
cv_wait(testcv, testlock);
failif((testval1 != 3));
testval1 = 4;
random_yielder(4);
lock_release(testlock);
random_yielder(4);
V(exitsem);
}
static
void
wakerthread(void *junk1, unsigned long junk2) {
(void)junk1;
(void)junk2;
random_yielder(4);
lock_acquire(testlock2);
failif((testval1 != 2));
testval1 = 3;
random_yielder(4);
cv_signal(testcv, testlock2);
random_yielder(4);
lock_release(testlock2);
random_yielder(4);
V(exitsem);
}
int
cvtest5(int nargs, char **args) {
(void)nargs;
(void)args;
int result;
kprintf_n("Starting cvt5...\n");
testlock = lock_create("testlock");
if (testlock == NULL) {
panic("cvt5: lock_create failed\n");
}
testlock2 = lock_create("testlock2");
if (testlock == NULL) {
panic("cvt5: lock_create failed\n");
}
testcv = cv_create("testcv");
if (testcv == NULL) {
panic("cvt5: cv_create failed\n");
}
exitsem = sem_create("exitsem", 0);
if (exitsem == NULL) {
panic("cvt5: sem_create failed\n");
}
spinlock_init(&status_lock);
test_status = TEST161_SUCCESS;
testval1 = 0;
lock_acquire(testlock);
lock_acquire(testlock2);
result = thread_fork("cvt5", NULL, sleeperthread, NULL, 0);
if (result) {
panic("cvt5: thread_fork failed\n");
}
result = thread_fork("cvt5", NULL, wakerthread, NULL, 0);
if (result) {
panic("cvt5: thread_fork failed\n");
}
random_yielder(4);
cv_wait(testcv, testlock);
failif((testval1 != 1));
testval1 = 2;
random_yielder(4);
lock_release(testlock);
random_yielder(4);
lock_release(testlock2);
P(exitsem);
P(exitsem);
failif((testval1 != 4));
sem_destroy(exitsem);
cv_destroy(testcv);
lock_destroy(testlock2);
lock_destroy(testlock);
success(test_status, SECRET, "cvt5");
exitsem = NULL;
testcv = NULL;
testlock2 = NULL;
testlock = NULL;
testsem2 = NULL;
testsem = NULL;
return 0;
}

View File

@ -66,10 +66,7 @@ fakethread_create(const char *name)
}
/* ignore most of the fields, zero everything for tidiness */
bzero(t, sizeof(*t));
t->t_name = kstrdup(name);
if (t->t_name == NULL) {
panic("threadlisttest: Out of memory\n");
}
strcpy(t->t_name, name);
t->t_stack = FAKE_MAGIC;
threadlistnode_init(&t->t_listnode, t);
return t;
@ -84,7 +81,6 @@ fakethread_destroy(struct thread *t)
{
KASSERT(t->t_stack == FAKE_MAGIC);
threadlistnode_cleanup(&t->t_listnode);
kfree(t->t_name);
kfree(t);
}

View File

@ -44,197 +44,226 @@
//
// Semaphore.
struct semaphore *sem_create(const char *name, unsigned initial_count) {
struct semaphore *sem;
struct semaphore *
sem_create(const char *name, unsigned initial_count)
{
struct semaphore *sem;
sem = kmalloc(sizeof(*sem));
if (sem == NULL) {
return NULL;
}
sem = kmalloc(sizeof(*sem));
if (sem == NULL) {
return NULL;
}
sem->sem_name = kstrdup(name);
if (sem->sem_name == NULL) {
kfree(sem);
return NULL;
}
sem->sem_name = kstrdup(name);
if (sem->sem_name == NULL) {
kfree(sem);
return NULL;
}
sem->sem_wchan = wchan_create(sem->sem_name);
if (sem->sem_wchan == NULL) {
kfree(sem->sem_name);
kfree(sem);
return NULL;
}
sem->sem_wchan = wchan_create(sem->sem_name);
if (sem->sem_wchan == NULL) {
kfree(sem->sem_name);
kfree(sem);
return NULL;
}
spinlock_init(&sem->sem_lock);
sem->sem_count = initial_count;
spinlock_init(&sem->sem_lock);
sem->sem_count = initial_count;
return sem;
return sem;
}
void sem_destroy(struct semaphore *sem) {
KASSERT(sem != NULL);
void
sem_destroy(struct semaphore *sem)
{
KASSERT(sem != NULL);
/* wchan_cleanup will assert if anyone's waiting on it */
spinlock_cleanup(&sem->sem_lock);
wchan_destroy(sem->sem_wchan);
kfree(sem->sem_name);
kfree(sem);
/* wchan_cleanup will assert if anyone's waiting on it */
spinlock_cleanup(&sem->sem_lock);
wchan_destroy(sem->sem_wchan);
kfree(sem->sem_name);
kfree(sem);
}
void P(struct semaphore *sem) {
KASSERT(sem != NULL);
void
P(struct semaphore *sem)
{
KASSERT(sem != NULL);
/*
* May not block in an interrupt handler.
*
* For robustness, always check, even if we can actually
* complete the P without blocking.
*/
KASSERT(curthread->t_in_interrupt == false);
/*
* May not block in an interrupt handler.
*
* For robustness, always check, even if we can actually
* complete the P without blocking.
*/
KASSERT(curthread->t_in_interrupt == false);
/* Use the semaphore spinlock to protect the wchan as well. */
spinlock_acquire(&sem->sem_lock);
while (sem->sem_count == 0) {
/*
*
* Note that we don't maintain strict FIFO ordering of
* threads going through the semaphore; that is, we
* might "get" it on the first try even if other
* threads are waiting. Apparently according to some
* textbooks semaphores must for some reason have
* strict ordering. Too bad. :-)
*
* Exercise: how would you implement strict FIFO
* ordering?
*/
wchan_sleep(sem->sem_wchan, &sem->sem_lock);
}
KASSERT(sem->sem_count > 0);
sem->sem_count--;
spinlock_release(&sem->sem_lock);
/* Use the semaphore spinlock to protect the wchan as well. */
spinlock_acquire(&sem->sem_lock);
while (sem->sem_count == 0) {
/*
*
* Note that we don't maintain strict FIFO ordering of
* threads going through the semaphore; that is, we
* might "get" it on the first try even if other
* threads are waiting. Apparently according to some
* textbooks semaphores must for some reason have
* strict ordering. Too bad. :-)
*
* Exercise: how would you implement strict FIFO
* ordering?
*/
wchan_sleep(sem->sem_wchan, &sem->sem_lock);
}
KASSERT(sem->sem_count > 0);
sem->sem_count--;
spinlock_release(&sem->sem_lock);
}
void V(struct semaphore *sem) {
KASSERT(sem != NULL);
void
V(struct semaphore *sem)
{
KASSERT(sem != NULL);
spinlock_acquire(&sem->sem_lock);
spinlock_acquire(&sem->sem_lock);
sem->sem_count++;
KASSERT(sem->sem_count > 0);
wchan_wakeone(sem->sem_wchan, &sem->sem_lock);
sem->sem_count++;
KASSERT(sem->sem_count > 0);
wchan_wakeone(sem->sem_wchan, &sem->sem_lock);
spinlock_release(&sem->sem_lock);
spinlock_release(&sem->sem_lock);
}
////////////////////////////////////////////////////////////
//
// Lock.
struct lock *lock_create(const char *name) {
struct lock *lock;
struct lock *
lock_create(const char *name)
{
struct lock *lock;
lock = kmalloc(sizeof(*lock));
if (lock == NULL) {
return NULL;
}
lock = kmalloc(sizeof(*lock));
if (lock == NULL) {
return NULL;
}
lock->lk_name = kstrdup(name);
if (lock->lk_name == NULL) {
kfree(lock);
return NULL;
}
lock->lk_name = kstrdup(name);
if (lock->lk_name == NULL) {
kfree(lock);
return NULL;
}
HANGMAN_LOCKABLEINIT(&lock->lk_hangman, lock->lk_name);
HANGMAN_LOCKABLEINIT(&lock->lk_hangman, lock->lk_name);
// add stuff here as needed
// add stuff here as needed
return lock;
return lock;
}
void lock_destroy(struct lock *lock) {
KASSERT(lock != NULL);
void
lock_destroy(struct lock *lock)
{
KASSERT(lock != NULL);
// add stuff here as needed
// add stuff here as needed
kfree(lock->lk_name);
kfree(lock);
kfree(lock->lk_name);
kfree(lock);
}
void lock_acquire(struct lock *lock) {
/* Call this (atomically) before waiting for a lock */
// HANGMAN_WAIT(&curthread->t_hangman, &lock->lk_hangman);
void
lock_acquire(struct lock *lock)
{
/* Call this (atomically) before waiting for a lock */
//HANGMAN_WAIT(&curthread->t_hangman, &lock->lk_hangman);
// Write this
// Write this
(void)lock; // suppress warning until code gets written
(void)lock; // suppress warning until code gets written
/* Call this (atomically) once the lock is acquired */
// HANGMAN_ACQUIRE(&curthread->t_hangman, &lock->lk_hangman);
/* Call this (atomically) once the lock is acquired */
//HANGMAN_ACQUIRE(&curthread->t_hangman, &lock->lk_hangman);
}
void lock_release(struct lock *lock) {
/* Call this (atomically) when the lock is released */
// HANGMAN_RELEASE(&curthread->t_hangman, &lock->lk_hangman);
void
lock_release(struct lock *lock)
{
/* Call this (atomically) when the lock is released */
//HANGMAN_RELEASE(&curthread->t_hangman, &lock->lk_hangman);
// Write this
// Write this
(void)lock; // suppress warning until code gets written
(void)lock; // suppress warning until code gets written
}
bool lock_do_i_hold(struct lock *lock) {
// Write this
bool
lock_do_i_hold(struct lock *lock)
{
// Write this
(void)lock; // suppress warning until code gets written
(void)lock; // suppress warning until code gets written
return true; // dummy until code gets written
return true; // dummy until code gets written
}
////////////////////////////////////////////////////////////
//
// CV
struct cv *cv_create(const char *name) {
struct cv *cv;
cv = kmalloc(sizeof(*cv));
if (cv == NULL) {
return NULL;
}
struct cv *
cv_create(const char *name)
{
struct cv *cv;
cv->cv_name = kstrdup(name);
if (cv->cv_name == NULL) {
kfree(cv);
return NULL;
}
cv = kmalloc(sizeof(*cv));
if (cv == NULL) {
return NULL;
}
// add stuff here as needed
cv->cv_name = kstrdup(name);
if (cv->cv_name==NULL) {
kfree(cv);
return NULL;
}
return cv;
// add stuff here as needed
return cv;
}
void cv_destroy(struct cv *cv) {
KASSERT(cv != NULL);
void
cv_destroy(struct cv *cv)
{
KASSERT(cv != NULL);
// add stuff here as needed
// add stuff here as needed
kfree(cv->cv_name);
kfree(cv);
kfree(cv->cv_name);
kfree(cv);
}
void cv_wait(struct cv *cv, struct lock *lock) {
// Write this
(void)cv; // suppress warning until code gets written
(void)lock; // suppress warning until code gets written
void
cv_wait(struct cv *cv, struct lock *lock)
{
// Write this
(void)cv; // suppress warning until code gets written
(void)lock; // suppress warning until code gets written
}
void cv_signal(struct cv *cv, struct lock *lock) {
// Write this
(void)cv; // suppress warning until code gets written
(void)lock; // suppress warning until code gets written
void
cv_signal(struct cv *cv, struct lock *lock)
{
// Write this
(void)cv; // suppress warning until code gets written
(void)lock; // suppress warning until code gets written
}
void cv_broadcast(struct cv *cv, struct lock *lock) {
// Write this
(void)cv; // suppress warning until code gets written
(void)lock; // suppress warning until code gets written
void
cv_broadcast(struct cv *cv, struct lock *lock)
{
// Write this
(void)cv; // suppress warning until code gets written
(void)lock; // suppress warning until code gets written
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -49,7 +49,7 @@ Standard C Library (libc, -lc)
<p>
<tt>#include &lt;unistd.h&gt;</tt><br>
<br>
<tt>void,</tt><br>
<tt>void</tt><br>
<tt>_exit(int </tt><em>exitcode</em><tt>);</tt>
</p>

View File

@ -55,8 +55,8 @@ Standard C Library (libc, -lc)
<h3>Description</h3>
<p>
The file handle <em>fd</em> is closed. The same file handle may then
be returned again from <A HREF=open.html>open</A>,
The file handle identified by file descriptor <em>fd</em> is closed.
The same file handle may then be returned again from <A HREF=open.html>open</A>,
<A HREF=dup2.html>dup2</A>, <A HREF=pipe.html>pipe</A>, or similar
calls.
</p>
@ -87,7 +87,7 @@ mentioned here.
<table width=90%>
<tr><td width=5% rowspan=10>&nbsp;</td>
<td width=10%>EBADF</td>
<td><em>fd</em> is not a valid file handle.</td></tr>
<td><em>fd</em> is not a valid file descriptor.</td></tr>
<tr><td>EIO</td> <td>A hard I/O error occurred.</td></tr>
</table>
</p>

View File

@ -55,9 +55,9 @@ Standard C Library (libc, -lc)
<h3>Description</h3>
<p>
<tt>dup2</tt> clones the file handle <em>oldfd</em> onto the file
handle <em>newfd</em>. If <em>newfd</em> names an already-open file,
that file is closed.
<tt>dup2</tt> clones the file handle identifed by file descriptor <em>oldfd</em>
onto the file handle identified by <em>newfd</em>. If <em>newfd</em>
names an already-open file, that file is closed.
</p>
<p>
@ -74,8 +74,8 @@ dup2 is most commonly used to relocate opened files onto
</p>
<p>
Both filehandles must be non-negative, and, if applicable, smaller
than the maximum allowed file handle number.
Both file descriptors must be non-negative, and, if applicable,
smaller than the maximum allowed file handle number.
</p>
<p>
@ -116,9 +116,9 @@ here.
<tr><td width=5% rowspan=3>&nbsp;</td>
<td width=10% valign=top>EBADF</td>
<td><em>oldfd</em> is not a valid file
handle, or <em>newfd</em> is a value
descriptor, or <em>newfd</em> is a value
that cannot be a valid file
handle.</td></tr>
descriptor.</td></tr>
<tr><td valign=top>EMFILE</td> <td>The process's file table was full, or a
process-specific limit on open files
was reached.</td></tr>

View File

@ -57,7 +57,7 @@ struct stat *</tt><em>statbuf</em><tt>);</tt>
<h3>Description</h3>
<p>
<tt>fstat</tt> retrieves status information about the file referred to
by the file handle <em>fd</em> and stores it in the stat structure
by the file descriptor <em>fd</em> and stores it in the stat structure
pointed to by <em>statbuf</em>.
</p>

View File

@ -87,8 +87,8 @@ mentioned here.
<table width=90%>
<tr><td width=5% rowspan=3>&nbsp;</td>
<td width=10% valign=top>EBADF</td>
<td><em>fd</em> is not a valid file handle, or
it is not open for writing.</td></tr>
<td><em>fd</em> is not a valid file descriptor,
or it is not open for writing.</td></tr>
<tr><td valign=top>EIO</td> <td>A hard I/O error occurred.</td></tr>
<tr><td valign=top>EFAULT</td> <td><em>buf</em> points to an invalid
address.</td></tr>

View File

@ -57,7 +57,7 @@ size_t </tt><em>buflen</em><tt>);</tt>
<h3>Description</h3>
<p>
<tt>getdirentry</tt> retrieves the next filename from a directory
referred to by the file handle <em>filehandle</em>. The name is stored
referred to by the file descriptor <em>fd</em>. The name is stored
in <em>buf</em>, an area of size <em>buflen</em>. The length of of the
name actually found is returned.
</p>

View File

@ -57,7 +57,7 @@ void *</tt><em>data</em><tt>);</tt>
<h3>Description</h3>
<p>
<tt>ioctl</tt> performs an object-specific operation <em>code</em> on
the object referred to by the file handle <em>fd</em>. The
the object referred to by the file descriptor <em>fd</em>. The
<em>data</em> argument may point to supplemental data required or
returned by the operation. The size of buffer required, if any, and
other such matters are operation-specific.

View File

@ -57,8 +57,8 @@ int </tt><em>whence</em><tt>);</tt>
<h3>Description</h3>
<p>
<tt>lseek</tt> alters the current seek position of the file handle
<em>filehandle</em>, seeking to a new position based on <em>pos</em>
and <em>whence</em>.
identified by file descriptor <em>fd</em>, seeking to a new position
based on <em>pos</em> and <em>whence</em>.
</p>
<p>
@ -122,7 +122,7 @@ mentioned here.
<tr><td width=5% rowspan=4>&nbsp;</td>
<td width=10% valign=top>EBADF</td>
<td><em>fd</em> is not a valid file
handle.</td></tr>
descriptor.</td></tr>
<tr><td valign=top>ESPIPE</td> <td><em>fd</em> refers to an object
which does not support seeking.</td></tr>
<tr><td valign=top>EINVAL</td> <td><em>whence</em> is invalid.</td></tr>

View File

@ -99,12 +99,12 @@ course's assignments.)
</p>
<p>
<tt>open</tt> returns a file handle suitable for passing to
<tt>open</tt> returns a file descriptor suitable for passing to
<A HREF=read.html>read</A>,
<A HREF=write.html>write</A>,
<A HREF=close.html>close</A>,
etc. This file handle must be greater than or equal to zero. Note
that file handles 0 (STDIN_FILENO), 1 (STDOUT_FILENO), and 2
etc. This file descriptor must be greater than or equal to zero. Note
that file descriptors 0 (STDIN_FILENO), 1 (STDOUT_FILENO), and 2
(STDERR_FILENO) are used in special ways and are typically assumed by
user-level code to always be open.
</p>
@ -128,9 +128,9 @@ contain <tt>..</tt> is usually not quite atomic.
<h3>Return Values</h3>
<p>
On success, <tt>open</tt> returns a nonnegative file handle. On error,
-1 is returned, and <A HREF=errno.html>errno</A> is set according to
the error encountered.
On success, <tt>open</tt> returns a nonnegative file descriptor. On
error, -1 is returned, and <A HREF=errno.html>errno</A> is set
according to the error encountered.
</p>
<h3>Errors</h3>

View File

@ -51,7 +51,7 @@ Standard C Library (libc, -lc)
<br>
<tt>ssize_t</tt><br>
<tt>write(int </tt><em>fd</em><tt>, const void *</tt><em>buf</em><tt>,
size_t </tt><em>nbytes</em><tt>);</tt>
size_t </tt><em>buflen</em><tt>);</tt>
</p>
<h3>Description</h3>

View File

@ -87,15 +87,6 @@
# These build variables can be set explicitly for further control if
# desired, but should in general not need attention.
#
# (Tools.)
#
# PYTHON_INTERPRETER Location of Python interpreter.
# Default is "/usr/bin/env python".
#
# This may need to be changed on some platforms; but the configure
# script is supposed to take care of it for you. If that fails, or
# picks the wrong thing, please file a bug report.
#
# (Locations.)
#
# BUILDTOP Top of tree where .o files go.
@ -479,7 +470,7 @@ MORECFLAGS+=-I$(INSTALLTOP)/include
LDFLAGS+=-nostdlib -L$(INSTALLTOP)/lib $(INSTALLTOP)/lib/crt0.o
MORELIBS+=-lc
LIBDEPS+=$(INSTALLTOP)/lib/crt0.o $(INSTALLTOP)/lib/libc.a
LIBS+=-ltest161
############################################################
# end.

View File

@ -56,7 +56,7 @@ all-local: $(MYBUILDDIR) .WAIT $(MYBUILDDIR)/$(_LIB_)
install-staging-local: $(TOOLDIR)/hostlib .WAIT $(TOOLDIR)/hostlib/$(_LIB_)
$(TOOLDIR)/hostlib/$(_LIB_): $(MYBUILDDIR)/$(_LIB_)
rm -f $(.TARGET)
ln $(MYBUILDDIR)/$(_LIB_) $(.TARGET) || \
ln $(MYBUILDDIR)/$(_LIB_) $(.TARGET) >/dev/null 2>&1 || \
cp $(MYBUILDDIR)/$(_LIB_) $(.TARGET)
install-local:

View File

@ -76,14 +76,14 @@ cleanhostprog:
install-staging-local: $(_INSTALLDIR_) .WAIT $(_INSTALLDIR_)/$(_PROG_)
$(_INSTALLDIR_)/$(_PROG_): $(MYBUILDDIR)/$(_PROG_)
rm -f $(.TARGET)
ln $(MYBUILDDIR)/$(_PROG_) $(.TARGET) || \
ln $(MYBUILDDIR)/$(_PROG_) $(.TARGET) >/dev/null 2>&1 || \
cp $(MYBUILDDIR)/$(_PROG_) $(.TARGET)
.if defined(HOSTBINDIR)
install-local: install-hostprog
install-hostprog: $(OSTREE)$(HOSTBINDIR) $(MYBUILDDIR)/$(_PROG_)
rm -f $(OSTREE)$(HOSTBINDIR)/$(_PROG_)
ln $(MYBUILDDIR)/$(_PROG_) $(OSTREE)$(HOSTBINDIR)/$(_PROG_) || \
ln $(MYBUILDDIR)/$(_PROG_) $(OSTREE)$(HOSTBINDIR)/$(_PROG_) >/dev/null 2>&1 || \
cp $(MYBUILDDIR)/$(_PROG_) $(OSTREE)$(HOSTBINDIR)/$(_PROG_)
.else
install-local:

View File

@ -163,6 +163,9 @@ includelinks:
clean:
rm -f *.o *.a tags $(KERNEL)
rm -rf includelinks
@ABSTOP=$$(readlink -f $(TOP))
rm -f $(OSTREE)/.src
rm -f $(TOP)/.root
distclean cleandir: clean
rm -f .depend
@ -188,6 +191,9 @@ install:
cp $(KERNEL) $(OSTREE)/$(KERNEL)-$(CONFNAME)
-rm -f $(OSTREE)/$(KERNEL)
ln -s $(KERNEL)-$(CONFNAME) $(OSTREE)/$(KERNEL)
@ABSTOP=$$(readlink -f $(TOP))
ln -Tsf $(ABSTOP) $(OSTREE)/.src
ln -Tsf $(OSTREE) $(ABSTOP)/.root
#
# Run tags on all the sources and header files. This is probably not

View File

@ -59,13 +59,13 @@ all-local: $(MYBUILDDIR) .WAIT $(MYBUILDDIR)/$(_LIB_)
install-staging-local: $(INSTALLTOP)$(LIBDIR) .WAIT $(INSTALLTOP)$(LIBDIR)/$(_LIB_)
$(INSTALLTOP)$(LIBDIR)/$(_LIB_): $(MYBUILDDIR)/$(_LIB_)
rm -f $(.TARGET)
ln $(MYBUILDDIR)/$(_LIB_) $(.TARGET) || \
ln $(MYBUILDDIR)/$(_LIB_) $(.TARGET) >/dev/null 2>&1 || \
cp $(MYBUILDDIR)/$(_LIB_) $(.TARGET)
install-local: $(OSTREE)$(LIBDIR) $(MYBUILDDIR)/$(_LIB_)
@echo "Warning: manually installing library without relinking anything"
rm -f $(OSTREE)$(LIBDIR)/$(_LIB_)
ln $(MYBUILDDIR)/$(_LIB_) $(OSTREE)$(LIBDIR)/$(_LIB_) || \
ln $(MYBUILDDIR)/$(_LIB_) $(OSTREE)$(LIBDIR)/$(_LIB_) >/dev/null 2>&1 || \
cp $(MYBUILDDIR)/$(_LIB_) $(OSTREE)$(LIBDIR)/$(_LIB_)
# Build the library.

View File

@ -44,14 +44,14 @@ install-staging-local: $(INSTALLTOP)$(MANDIR) .WAIT
install-staging-local: $(INSTALLTOP)$(MANDIR)/$(_F_)
$(INSTALLTOP)$(MANDIR)/$(_F_): $(_F_)
rm -f $(.TARGET)
ln $(_F_) $(.TARGET) || cp $(_F_) $(.TARGET)
ln $(_F_) $(.TARGET) >/dev/null 2>&1 || cp $(_F_) $(.TARGET)
.endfor
install-local: $(OSTREE)$(MANDIR) .WAIT installmanpages
installmanpages:
.for _F_ in $(MANFILES)
rm -f $(OSTREE)$(MANDIR)/$(_F_)
ln $(_F_) $(OSTREE)$(MANDIR)/$(_F_) || \
ln $(_F_) $(OSTREE)$(MANDIR)/$(_F_) >/dev/null 2>&1 || \
cp $(_F_) $(OSTREE)$(MANDIR)/$(_F_)
.endfor

View File

@ -61,13 +61,13 @@ cleanprog:
install-staging-local: $(INSTALLTOP)$(BINDIR) .WAIT $(INSTALLTOP)$(BINDIR)/$(PROG)
$(INSTALLTOP)$(BINDIR)/$(PROG): $(MYBUILDDIR)/$(PROG)
rm -f $(.TARGET)
ln $(MYBUILDDIR)/$(PROG) $(.TARGET) || \
ln $(MYBUILDDIR)/$(PROG) $(.TARGET) >/dev/null 2>&1 || \
cp $(MYBUILDDIR)/$(PROG) $(.TARGET)
install-local: install-prog
install-prog: $(OSTREE)$(BINDIR) $(MYBUILDDIR)/$(PROG)
rm -f $(OSTREE)$(BINDIR)/$(PROG)
ln $(MYBUILDDIR)/$(PROG) $(OSTREE)$(BINDIR)/$(PROG) || \
ln $(MYBUILDDIR)/$(PROG) $(OSTREE)$(BINDIR)/$(PROG) >/dev/null 2>&1 || \
cp $(MYBUILDDIR)/$(PROG) $(OSTREE)$(BINDIR)/$(PROG)
# Link the program.

61
test161/commands/asst2.tc Normal file
View File

@ -0,0 +1,61 @@
templates:
- name: /testbin/consoletest
panics: maybe
output:
- text: "/testbin/consoletest: Able was i ere i saw elbA"
- name: /testbin/opentest
panics: maybe
- name: /testbin/readwritetest
panics: maybe
output:
- text: "/testbin/readwritetest: h4xa0rRq0Vgbc96tiYJ^!#nXzZSAKPO"
- name: /testbin/closetest
panics: maybe
- name: /testbin/fileonlytest
panics: maybe
- name: /testbin/redirect
- name: /testbin/sparsefile
panics: maybe
- name: /testbin/badcall
- name: faulter
- name: /testbin/forkbomb
timesout: yes
timeout: 15.0
- name: kmalloc
output:
- text: "kmalloc: out of memory"
- name: /testbin/crash
- name: /testbin/forktest
- name: /testbin/randcall
- name: /testbin/shelltest
output:
- text: "/testbin/shelltest: line-1: Able was i ere i saw elbA"
- text: "/testbin/shelltest: line-2: Able was i ere i saw elbA"
- text: "/testbin/shelltest: line-3: Able was i ere i saw elbA"
- name: /testbin/argtest
input:
- "{{randString 1 2}}"
- "{{randString 4 5}}"
- "{{randString 9 10}}"
- "{{randString 10 11}}"
- "{{randString 11 12}}"
- "{{randString 12 13}}"
- "{{randString 13 14}}"
- "{{randString 200 513}}"
output:
- text: "/testbin/argtest: argc: {{add 1 .ArgLen}}"
- text: "/testbin/argtest: /testbin/argtest"
- text: "{{range $index, $element := .Args}}/testbin/argtest: {{$element}}\n{{end}}"
- text: "/testbin/argtest: [NULL]"
- name: /testbin/bigexec
- name: /testbin/factorial
input:
- "{{randInt 6 10}}"
output:
- text: "/testbin/factorial: {{$n:= index .Args 0 | atoi}}{{factorial $n}}\n"
- name: /testbin/add
input:
- "{{randInt 2 1000}}"
- "{{randInt 2 4000}}"
output:
- text: "/testbin/add: {{$x:= index .Args 0 | atoi}}{{$y := index .Args 1 | atoi}}{{add $x $y}}"

View File

@ -0,0 +1,6 @@
templates:
- name: km1
- name: km2
- name: km3
- name: km4
- name: km5

34
test161/commands/misc.tc Normal file
View File

@ -0,0 +1,34 @@
# These commands expect no output, but must not panic
templates:
- name: tt1
output:
- text: ""
- name: tt2
output:
- text: ""
- name: tt3
output:
- text: ""
- name: khu
output:
- text: ""
- name: q
output:
- text: ""
- name: s
output:
- text: ""
- name: boot
output:
- text:
- name: exit
output:
- text: ""

38
test161/commands/sync.tc Normal file
View File

@ -0,0 +1,38 @@
templates:
- name: sem1
- name: lt1
- name: lt2
panics: yes
output:
- text: "lt2: Should panic..."
- name: lt3
panics: yes
output:
- text: "lt3: Should panic..."
- name: cvt1
- name: cvt2
- name: cvt3
panics: yes
output:
- text: "cvt3: Should panic..."
- name: cvt4
panics: yes
output:
- text: "cvt4: Should panic..."
- name: cvt5
- name: rwt1
- name: rwt2
- name: rwt3
panics: yes
output:
- text: "rwt3: Should panic..."
- name: rwt4
panics: yes
output:
- text: "rwt4: Should panic..."
- name: rwt5
panics: yes
output:
- text: "rwt5: Should panic..."
- name: sp1
- name: sp2

52
test161/commands/vm.tc Normal file
View File

@ -0,0 +1,52 @@
templates:
#Single tests - everything has the default output
- name: /testbin/bigfork
- name: /testbin/ctest
- name: /testbin/huge
- name: /testbin/matmult
- name: /testbin/palin
- name: /testbin/parallelvm
- name: /testbin/sbrktest
- name: /testbin/sort
- name: /testbin/stacktest
- name: /testbin/zero
#Triples
- name: /testbin/triplehuge
output:
- {text: /testbin/huge, external: true, trusted: true}
- {text: /testbin/huge, external: true, trusted: true}
- {text: /testbin/huge, external: true, trusted: true}
- name: /testbin/triplemat
output:
- {text: /testbin/matmult, external: true, trusted: true}
- {text: /testbin/matmult, external: true, trusted: true}
- {text: /testbin/matmult, external: true, trusted: true}
- name: /testbin/triplesort
output:
- {text: /testbin/sort, external: true, trusted: true}
- {text: /testbin/sort, external: true, trusted: true}
- {text: /testbin/sort, external: true, trusted: true}
#Quints
- name: /testbin/quinthuge
output:
- {text: /testbin/huge, external: true, trusted: true}
- {text: /testbin/huge, external: true, trusted: true}
- {text: /testbin/huge, external: true, trusted: true}
- {text: /testbin/huge, external: true, trusted: true}
- {text: /testbin/huge, external: true, trusted: true}
- name: /testbin/quintmat
output:
- {text: /testbin/matmult, external: true, trusted: true}
- {text: /testbin/matmult, external: true, trusted: true}
- {text: /testbin/matmult, external: true, trusted: true}
- {text: /testbin/matmult, external: true, trusted: true}
- {text: /testbin/matmult, external: true, trusted: true}
- name: /testbin/quintsort
output:
- {text: /testbin/sort, external: true, trusted: true}
- {text: /testbin/sort, external: true, trusted: true}
- {text: /testbin/sort, external: true, trusted: true}
- {text: /testbin/sort, external: true, trusted: true}
- {text: /testbin/sort, external: true, trusted: true}

70
test161/tags/all.td Normal file
View File

@ -0,0 +1,70 @@
tags:
- name: badcall
desc: "All badcall tests for the various system calls"
- name: boot
desc: "Tests that check if your kernel can boot"
- name: console
desc: "Tests that check if you have a working userspace console"
- name: coremap
desc: "All coremap-related tests"
- name: crash
desc: "Tests that attempt to crash your kernel"
- name: cvs
desc: "Condition variable tests"
- name: filesyscalls
desc: "Filesystem syscall tests, e.g. read, write, open, close, etc."
- name: kleaks
desc: "Synch tests that also check for memory leaks"
- name: locks
desc: "Kernel lock tests"
- name: not-dumbvm
desc: "Tests that verify your coremap is not using dumbvm"
- name: not-dumbvm-vm
desc: "Tests that verify your VM system is not using dumbvm"
- name: proc
desc: "Misc. process system call tests"
- name: procsyscalls
desc: "Tests that test process system calls, e.g. fork, exec, waitpid"
- name: rwlocks
desc: "Reader/writer lock tests"
- name: sbrk
desc: "sbrk tests"
- name: semaphores
desc: "Kernel semaphore tests"
- name: shell
desc: "Tests that check for a working userspace shell"
- name: stability
desc: "System call stability tests that stress test and check various error conditions"
- name: stability-vm
desc: "VM stress testing"
- name: swap
desc: "Tests that stress test your VM swapping implementation"
- name: swap-basic
desc: "Less stressful swap tests to ensure a swapping implementation"
- name: synch
desc: "All sychronization primitive tests"
- name: synchprobs
desc: "Synchronization problems that test your ablility to use synch primitives"
- name: sys_close
desc: "close() syscall tests"
- name: sys_dup2
desc: "dup2() syscall tests"
- name: sys_exec
desc: "exec() syscall tests"
- name: sys_fork
desc: "fork() syscall tests"
- name: sys_lseek
desc: "lseek() syscall tests"
- name: sys_open
desc: "open() syscall tests"
- name: sys_read
desc: "read() syscall tests"
- name: sys_write
desc: "write() syscall tests"
- name: syscalls
desc: "Tests that check the basic functionality of your system call implementations"
- name: threads
desc: "Kernel thread tests"
- name: vm
desc: "All non-swapping VM tests"

40
test161/targets/asst1.tt Normal file
View File

@ -0,0 +1,40 @@
name: asst1
print_name: ASST1
description: >
In this assignment you will implement new synchronization
primitives for OS/161 and use them to solve several synchronization problems.
version: 1
points: 50
type: asst
kconfig: ASST1
tests:
- id: synch/lt1.t
points: 8
- id: synch/lt2.t
points: 1
- id: synch/lt3.t
points: 1
- id: synch/cvt1.t
points: 4
- id: synch/cvt2.t
points: 3
- id: synch/cvt3.t
points: 1
- id: synch/cvt4.t
points: 1
- id: synch/cvt5.t
points: 1
- id: synch/rwt1.t
points: 5
- id: synch/rwt2.t
points: 2
- id: synch/rwt3.t
points: 1
- id: synch/rwt4.t
points: 1
- id: synch/rwt5.t
points: 1
- id: synchprobs/sp1.t
points: 10
- id: synchprobs/sp2.t
points: 10

View File

@ -0,0 +1,51 @@
name: asst2-single
print_name: "ASST2 (Single)"
description: >
In this assignment you will add process and system call support to your
OS/161 kernel. This is the single-submitter version for students that are
working alone and were provided the file system system calls.
leaderboard: false
version: 1
points: 80
type: asst
kconfig: ASST2
userland: true
tests:
# Process system call tests (50 points)
- id: syscalls/forktest.t
points: 15
- id: syscalls/shell.t
points: 10
- id: syscalls/argtest.t
points: 5
- id: syscalls/bigexec.t
points: 10
- id: syscalls/factorial.t
points: 5
- id: syscalls/add.t
points: 5
# Stability tests (30 points)
# Bad calls (5 points)
- id: stability/badcall/badcall-execv.t
points: 3
- id: stability/badcall/badcall-waitpid.t
points: 2
# crash
- id: stability/crash/crash-allS.t
points: 3
# randcall
- id: stability/randcall.t
points: 2
commands:
- id: /testbin/randcall
args:
- "-f"
- "-c 100"
- "-r 421"
- "2"
# forkbomb
- id: stability/forkbomb.t
points: 10
# forktest
- id: stability/forktest-stability.t
points: 10

View File

@ -0,0 +1,15 @@
name: asst2.1
print_name: ASST2.1
description: >
In this part of the assignment, you will add console support.
version: 1
points: 20
type: asst
kconfig: ASST2
userland: true
meta_name: asst2
leaderboard: false
tests:
# Make sure the console works (10 points)
- id: syscalls/consoletest.t
points: 20

View File

@ -0,0 +1,76 @@
name: asst2.2
print_name: ASST2.1
description: >
In this assignment you will add process and system call support to your
OS/161 kernel.
version: 1
points: 130
type: asst
kconfig: ASST2
userland: true
meta_name: asst2
leaderboard: false
tests:
# File system system calls (47 points)
- id: syscalls/opentest.t
points: 5
- id: syscalls/closetest.t
points: 5
- id: syscalls/readwritetest.t
points: 10
- id: syscalls/fileonlytest.t
points: 12
- id: syscalls/redirect.t
points: 10
- id: syscalls/sparsefile.t
points: 5
# Process system call tests (47 points)
- id: syscalls/forktest.t
points: 15
- id: syscalls/shell.t
points: 10
- id: syscalls/argtest.t
points: 5
- id: syscalls/bigexec.t
points: 8
- id: syscalls/factorial.t
points: 5
- id: syscalls/add.t
points: 4
# Stability tests (36 points)
# Bad calls (8 points)
- id: stability/badcall/badcall-open.t
points: 1
- id: stability/badcall/badcall-close.t
points: 1
- id: stability/badcall/badcall-read.t
points: 1
- id: stability/badcall/badcall-write.t
points: 1
- id: stability/badcall/badcall-lseek.t
points: 1
- id: stability/badcall/badcall-dup2.t
points: 1
- id: stability/badcall/badcall-execv.t
points: 1
- id: stability/badcall/badcall-waitpid.t
points: 1
# crash
- id: stability/crash/crash-allS.t
points: 4
# randcall
- id: stability/randcall.t
points: 4
commands:
- id: /testbin/randcall
args:
- "-f"
- "-c 100"
- "-r 421"
- "2"
# forkbomb
- id: stability/forkbomb.t
points: 10
# forktest
- id: stability/forktest-stability.t
points: 10

12
test161/targets/asst2.tt Normal file
View File

@ -0,0 +1,12 @@
name: asst2
print_name: ASST2
description: >
In this assignment you will add process and system call support to your
OS/161 kernel.
version: 2
points: 150
type: asst
kconfig: ASST2
userland: true
is_meta_target: true
sub_target_names: ["asst2.1", "asst2.2"]

View File

@ -0,0 +1,31 @@
name: asst3.1
print_name: ASST3.1
description: >
In this part of ASST3, you will begin writing your own VM by adding your
coremap and page allocator.
version: 1
points: 60
type: asst
kconfig: ASST3
userland: true
meta_name: asst3
leaderboard: false
tests:
- id: coremap/not-dumbvm.t
points: 15
- id: coremap/km1.t
points: 5
mem_leak_points: 2
- id: coremap/km2.t
points: 5
mem_leak_points: 2
- id: coremap/km3.t
points: 5
mem_leak_points: 2
- id: coremap/km4.t
points: 15
mem_leak_points: 2
- id: coremap/coremap-loose.t
points: 5
- id: coremap/coremap-tight.t
points: 10

View File

@ -0,0 +1,55 @@
name: asst3.2
print_name: ASST3.2
description: >
In this part of ASST3, you will add virtual address spaces to your VM.
version: 1
points: 120
type: asst
kconfig: ASST3
userland: true
meta_name: asst3
leaderboard: false
tests:
# Basic VM (30 points)
- id: vm/not-dumbvm-vm.t
points: 5
- id: vm/sort.t
points: 5
- id: vm/palin.t
points: 5
- id: vm/matmult.t
mem_leak_points: 2
points: 5
- id: vm/ctest.t
points: 5
- id: vm/stacktest.t
points: 5
# Concurrent VM (50 points)
- id: vm/bigfork.t
points: 10
mem_leak_points: 2
- id: vm/parallelvm.t
points: 10
- id: vm/quintsort.t
points: 10
- id: vm/quintmat.t
points: 10
- id: vm/quinthuge.t
points: 10
# Heap (10 points)
- id: vm/sbrktest.t
points: 8
mem_leak_points: 2
- id: vm/sbrk-badcall.t
points: 2
# Stress tests/misc (30 points)
- id: vm/zero.t
points: 5
- id: vm/stability/vm-stability.t
points: 20
mem_leak_points: 2
- id: vm/stability/forkbomb.t
points: 5

View File

@ -0,0 +1,37 @@
name: asst3.3
print_name: ASST3.3
description: >
In this part of ASST3, you will add swapping to your VM.
version: 1
points: 120
type: asst
kconfig: ASST3
userland: true
meta_name: asst3
leaderboard: false
tests:
# Basic Swapping (40 points)
- id: vm/swap/sort.t
mem_leak_points: 2
points: 20
- id: vm/swap/matmult.t
mem_leak_points: 2
points: 20
# Concurrent Swapping (80 points)
- id: vm/swap/bigfork.t
points: 10
- id: vm/swap/bigfork-32.t
points: 15
mem_leak_points: 2
- id: vm/swap/parallelvm.t
points: 10
- id: vm/swap/parallelvm-32.t
points: 15
- id: vm/swap/quintsort.t
points: 10
- id: vm/swap/quintmat.t
points: 10
- id: vm/swap/quinthuge.t
points: 10
mem_leak_points: 2

12
test161/targets/asst3.tt Normal file
View File

@ -0,0 +1,12 @@
name: asst3
print_name: ASST3
description: >
In this assignment you will add support for virtual memory to your OS/161
kernel.
version: 4
points: 300
type: asst
kconfig: ASST3
userland: true
is_meta_target: true
sub_target_names: ["asst3.1", "asst3.2", "asst3.3"]

9
test161/tests/boot.t Normal file
View File

@ -0,0 +1,9 @@
---
name: Kernel Boot
description:
Tests whether your kernel will boot.
tags: [boot]
sys161:
cpus: 2
---
q

View File

@ -0,0 +1,11 @@
---
name: "Coremap Test (Loose Bounds)"
description: >
Allocates and frees all physical memory multiple times checking
that the amount allocated is within a reasonable bound.
tags: [coremap]
depends: [not-dumbvm.t]
sys161:
ram: 4M
---
| km5 --avail 32 --kernel 125

View File

@ -0,0 +1,11 @@
---
name: "Coremap Test (Tight Bounds)"
description: >
Allocates and frees all physical memory multiple times checking
that the amount allocated is within a reasonable bound.
tags: [coremap]
depends: [not-dumbvm.t]
sys161:
ram: 4M
---
| km5 --avail 20 --kernel 105

View File

@ -0,0 +1,9 @@
---
name: "Basic kmalloc Test"
description: >
Tests the kernel subpage allocator by allocating a large number of objects
and freeing them somewhat later.
tags: [coremap]
depends: [not-dumbvm.t]
---
| km1

View File

@ -0,0 +1,8 @@
---
name: "kmalloc Stress Test"
description: >
Similar to km1 but uses multiple concurrent threads.
tags: [coremap]
depends: [not-dumbvm.t]
---
| km2

View File

@ -0,0 +1,9 @@
---
name: "Large kmalloc Test"
description: >
Stresses the subpage allocator by allocating and freeing a large number of
objects of various sizes.
tags: [coremap]
depends: [not-dumbvm.t]
---
| km3 5000

View File

@ -0,0 +1,9 @@
---
name: "Multipage allococation Test"
description: >
Allocates and frees between 1 and 5 pages a number of times by a number of
concurrent threads.
tags: [coremap]
depends: [not-dumbvm.t]
---
| km4

View File

@ -0,0 +1,9 @@
---
name: "Smarter VM"
description:
Test whether you are using dumbvm by allocating and freeing all physical
memory multiple times.
tags: [coremap, not-dumbvm]
depends: [boot]
---
| km5

View File

@ -0,0 +1,10 @@
---
name: "Bad Close"
description: >
Stability test for sys_close.
tags: [badcall,stability]
depends: [shell]
sys161:
ram: 2M
---
$ /testbin/badcall f

View File

@ -0,0 +1,10 @@
---
name: "Bad Dup"
description:
Stability test for sys_dup2.
tags: [badcall,stability]
depends: [shell]
sys161:
ram: 2M
---
$ /testbin/badcall w

View File

@ -0,0 +1,10 @@
---
name: "Bad Exec"
description:
Stability test for sys_exec.
tags: [badcall,stability]
depends: [shell]
sys161:
ram: 2M
---
$ /testbin/badcall a

View File

@ -0,0 +1,10 @@
---
name: "Bad Seek"
description:
Stability test for sys_lseek.
tags: [badcall,stability]
depends: [shell]
sys161:
ram: 2M
---
$ /testbin/badcall j

View File

@ -0,0 +1,10 @@
---
name: "Bad Open"
description:
Stability test for sys_open.
tags: [badcall,stability]
depends: [shell]
sys161:
ram: 2M
---
$ /testbin/badcall c

View File

@ -0,0 +1,10 @@
---
name: "Bad Read"
description:
Stability test for sys_read.
tags: [badcall,stability]
depends: [shell]
sys161:
ram: 2M
---
$ /testbin/badcall d

View File

@ -0,0 +1,10 @@
---
name: "Bad Wait"
description:
Stability test for sys_wait.
tags: [badcall,stability]
depends: [shell]
sys161:
ram: 2M
---
$ /testbin/badcall b

View File

@ -0,0 +1,10 @@
---
name: "Bad Write"
description:
Stability test for sys_write.
tags: [badcall,stability]
depends: [shell]
sys161:
ram: 2M
---
$ /testbin/badcall e

View File

@ -0,0 +1,11 @@
---
name: "Crash"
description: >
Tests whether your system correctly handles a variety of bad process
behavior.
tags: [crash,stability]
depends: [shell,sys_fork]
sys161:
ram: 4M
---
$ /testbin/crash *

View File

@ -0,0 +1,10 @@
---
name: "Crash-template Test"
description:
Tests whether your system correctly handles a variety of
illegal attempts from userspace processes to access resources that
do not belong to it. Please see userland/testbin/crash for more info.
tags: [stability, crash]
depends: [console]
---
p /extratests/crash-template

View File

@ -0,0 +1,54 @@
import os,sys
import subprocess
RANGE=[chr(i) for i in range(ord('a'), ord('p'))]
# First create crash-a/b/c.t files
template = open('crash-template').read()
def add_sys161_opts(content, sys161_opts):
content = content.split('\n')
idx = content[1:].index('---') + 1
content.insert(idx, sys161_opts.strip())
content = '\n'.join(content)
return content
def create_crash(char, sys161_opts=None):
content = template.replace('-template', '-%s' % char)
content = content.replace(', crash]', ', crash-fork]')
content = content.replace('[console]', '[console, /asst2/process/forktest.t]')
if sys161_opts:
content = add_sys161_opts(content, sys161_opts)
with open('crash-%s.t' % char, 'w') as f:
f.write(content)
# now do the F version
content = template.replace('-template', '-%sF' % char)
if sys161_opts:
content = add_sys161_opts(content, sys161_opts)
with open('crash-%sF.t' % char, 'w') as f:
f.write(content)
for char in RANGE:
create_crash(char)
# Now do the 'all'
sys161_opts = \
'''
sys161:
ram: 2M
'''
create_crash('all', sys161_opts)
#p = subprocess.Popen('ls *.t', shell=True, stdout=subprocess.PIPE)
#stdout, stderr = p.communicate()
#files = stdout.strip().split('\n')
#
#for f in files:
# name, ext = os.path.splitext(f)
#
# new_file = name + 'F' + ext
# letters = name[name.index('-'):]
# subprocess.check_call('cp %s %s' % (f, new_file), shell=True)
# subprocess.check_call('''sed -i 's/%s/%sF/g' %s''' % (letters, letters, new_file), shell=True)

View File

@ -0,0 +1,10 @@
---
name: "Faulter Test"
description:
Tests whether kill_curthread is implemented correctly.
Attempts to access an invalid memory address expecting the kernel
to gracefully kill the current process instead of panicking.
tags: [proc]
depends: [console]
---
p /testbin/faulter

View File

@ -0,0 +1,17 @@
---
name: "Calm Like a Fork Bomb"
tags: [stability]
depends: [console,sys_fork]
sys161:
ram: 2M
monitor:
progresstimeout: 40.0
user:
enablemin: true
min: 0.001
max: 1.0
kernel:
enablemin: true
min: 0.01
---
p /testbin/forkbomb

View File

@ -0,0 +1,14 @@
---
name: "Fork Stability Test"
description:
Runs forktest 5 times to check for synchronization issues.
tags: [stability]
depends: [shell]
sys161:
ram: 16M
---
$ /testbin/forktest
$ /testbin/forktest
$ /testbin/forktest
$ /testbin/forktest
$ /testbin/forktest

View File

@ -0,0 +1,10 @@
---
name: "Randcall Test"
description: >
Invokes system calls with random arguments.
tags: [stability]
depends: [shell]
sys161:
ram: 16M
---
$ /testbin/randcall -f -c 100 -r 421 2

Some files were not shown because too many files have changed in this diff Show More