% cd $HOME/cs350-os161/os161-1.99/kern/conf % ./config ASST2 % cd ../compile/ASST2 % bmake depend % bmake % bmake install
DEBUG(DB_EXEC, "ELF: Loading %lu bytes to 0x%lx\n", (unsigned long) filesize, (unsigned long) vaddr);The DEBUG macro and the various flags (like DB_EXEC) are defined in kern/include/lib.h. To control which DEBUG statements produce output, set the dbflags variable, which is found in kern/lib/kprintf.c. For example, setting
u_int32_t dbflags = 0;will turn off all debugging output, while
u_int32_t dbflags = DB_EXEC|DB_THREADS;will turn off everything except DEBUG statements that are labeled with DB_EXEC or DB_THREADS.
You can design your quick-and-dirty write system call so that it only handles writes to standard output, which are indicated by fd = 1 (see the manual page for the write system call). The kernel should direct writes to standard output to the console device, and a quick-and-dirty way for the kernel to do that is to use the kprintf function. You can use a simple kprintf-based implementation of write to test that control is actually getting to the system call handler, and that the handler is able to get the characters that the application wants to print.
Your final implementation of write should not be based on kprintf. One problem with the kprintf implementation of write is that kprintf assumes that its argument is a null-terminated character string. However, in general, the data that an application passes to a write system call may not consist of printable characters and will not, in general, be null-terminated. The kprintf-based write implementation is just a way to get an initial system call working quickly.
A related constraint is that the stack pointer should always start at an address that is 8-byte aligned (evenly divisible by 8). This is because the largest data types that require alignment (and which might be pushed onto a stack) are 8 bytes long, e.g., a double-precision floating point value.
int main(int argc, char **argv) { int file; if (argc < 3) { errx(1, "Usage: tailargv is a character pointer pointer - it points to an array of character pointers, each of which points to one of the arguments. For example, if the tail program is invoked from the kernel command line like this:"); } file = open(argv[1], O_RDONLY); if (file < 0) { err(1, "%s", argv[1]); } tail(file, atoi(argv[2]), argv[1]); close(file); return 0; }
OS/161 kernel [? for menu]: p testbin/sort foo 100Then the argv and argc variables should be set up as illustrated in the following illustration:
result = vfs_open("string", mode, &2vn);is incorrect and should bring a warning from the compiler. The problem is that vfs_open may modify its first argument, but "string" is an unmodifiable literal. So if, for example, you want to open the console, you need to do something like this instead:
char *console = NULL; console = kstrdup("con:"); result = vfs_open(console,mode,&vn); kfree(console);
You build all of the OS/161 application programs when you run bmake in the directory cs350-os161/os161-1.99. When you do this, the application program executable files are copied into subdirectories under cs350-os161/root/.
Once your OS/161 kernel has booted, you can launch an application program using the p command from the kernel menu. For example, to run the palin program, which is located in testbin, use the following command
OS/161 kernel [? for menu]: p testbin/palinAs usual, you can pass commands to the kernel on sys161 command line, e.g.,
sys161 kernel "p testbin/palin"
# Old/default value # 31 busctl ramsize=524288 # Changed to 2 MB. 31 busctl ramsize=2097152In particular, you will probably have to do this for applications like forktest, farm and sty.