Problem Set 4 Harvard Extension School CSCI E-92: Principles of Operating Systems Spring 2024 Due: March 31, 2024 at Midnight ET (Eastern Time) Total of 150 Points 1. (150 Points) Freescale K70 Programming. Write a C program (with embedded assembler as necessary) for the Freescale K70/MK70FN1M0 Tower Development Kit that implements the following constructs. Continuing with the requirements from the last Problem Set, you should no longer make any use of the fgetc, fputc, fputs, or fprintf calls (or any other built-in system calls to perform input or output) except for outputting either debugging messages or catastrophic messages from your OS. Instead, your code should use your own I/O system. Any output over console I/O (semihosting) must be able to be disabled and removed from your program using an #if, #ifdef, or #ifndef preprocessor directive. Therefore, rather than performing I/O to the console window (we refer to this as "Console I/O") in the K70 IDE (CodeWarrior or KDS), you should perform I/O over the UART5 serial port as defined in part "g" of the Problem Set below and as demonstrated in the SerialIO sample program on the class web site. You may use the sscanf, snprintf, vsscanf, and vsnprintf calls -- we will refer to these functions as "formatted I/O to string" functions. Unlike in Problem Set 3, starting with this problem set, your shell/OS will perform all user interactions using device independent I/O from and to the default terminal input/output/error devices. So, if you are using your own definitions of stdin, stdout, and stderr, say as streams named myStdin, myStdout, and myStderr, then those streams should appear in the PCB as pre-opened streams associated with UART5. Those stream should be opened by your OS before the shell begins execution. If you are *not* using the formatted I/O to string functions and you are not using console I/O, your projects should now be built using "No I/O" under "I/O Support" in the "Language and Build Tools Options" screen in CodeWarrior or "-specs=nosys.specs -specs=nano.specs" in "Other linker flags" in KDS. If you are using the formatted I/O to string functions, your projects should still be built using "Debugger Console" under I/O Support in CodeWarrior -- this includes the full Embedded Warrior Library (EWL) which has support for snprintf, etc. And, if you are using console I/O output for debugging or for catastrophic messages, then you should enable the "Debugger Console" in CodeWarrior or semihosting in KDS ("-specs=rdimon.specs -specs=nano.specs" in "Other linker flags" in KDS). Also, for KDS "semihosting" needs to be enabled for the debugging interface you are using -- either P&E or Segger. a. Using mcg.h and mcg.c, initialize all processor clocks and transition to 120 MHz full speed core clock before running any code in this problem set. Also, the DDR clock is initialized to run at 150 MHz. NOTE: Changing the clock speeds will affect a variety of clock dependent code (including UART baud rates and timers). b. Using sdram.h and sdram.c, initialize the off-chip SDRAM in the Micron Technology MT47H64M16. Important note: mcgInit must be called before sdramInit is called (i.e., the K70 core clock must be running at full 120MHz speed before the MT47H64M16 SDRAM can be utilized). c. Modify your myMalloc and myFree to use the 128 MBytes of SDRAM memory from SDRAM_START to SDRAM_END of size SDRAM_SIZE bytes. These constants are #define'd in sdram.h. Note that SDRAM_END is the last byte in the external SDRAM -- not the first byte past the external SDRAM. Note that if you are implementing a TWR-LCD-RGB driver, you will need to allocate its framebuffer from the 128 MBytes of SDRAM. This can be accomplished by (1) pre-allocating the framebuffer in SDRAM prior to establishing the limits of SDRAM available to myMalloc or (2) using myMalloc to allocate the framebuffer. d. Design a supervisor call architecture for all of your system calls. Include a document for a systems programmer that describes how to invoke each of the supervisor calls that will be implemented in your OS (these include supervisor calls for your versions of malloc, free, fopen, fclose, fgetc, fputc, create, delete, mount, and umount although they may be named differently). Include a design document that describes the way that supervisor calls are implemented. See the mechanism demonstrated in the programs accessible from the class web site (under Hardware Releated References, The Freescale ARM, Sample programs for the Kinetis K70F120M/MK70FN1M0 (120 MHz)), Supervisor call (SVC) routines and Supervisor call (SVC) demonstration main program). e. Implement a supervisor call interface for all of your device independent I/O system calls from Problem Set 3. Extend your device independent I/O supervisor calls to support all additional devices implemented in your OS as required below. It is *not* possible to invoke supervisor calls from within supervisor call handler code. Instead of issuing an SVC instruction within the implementation of another supervisor call, simply directly call the implementation of the embedded supervisor call. See Application Note 11 for further information. f. Implement a supervisor call interface for your heap-based memory allocation and deallocation performed through malloc and free. g. Implement non-interrupt driven I/O (input and output) from/to UART5 through the connector on the TWR-SER board. Use busy waiting to wait for input characters. Before performing output, wait for the output hardware FIFO to have room available for the character. As with Problem Set 3, you should configure the UART for 115,200 baud with eight data bit, one stop bit, and no parity. Although you do not need to change the interrupt priority level of SVCall for this problem set, you should be aware of the interrupt priority level at which the supervisor call handler code runs. The supervisor call handler code (system handler 11 for exception number 11, SVCall) runs at an interrupt priority defined by the high-order byte of SCB_SHPR2 (System Handler Priority Register 2, SHPR2), as explained in B3.2.11, page B3-723 of the ARMv7-M Architecture Reference Manual, Errata markup, ARM DDI 0403Derrata 2010_Q3. Smaller interrupt priority numbers denote higher priority. Only an exception with a higher priority can preempt the current priority (See B1.5.4 on page B1-635 in the ARMv7-M Architecture Reference Manual, Errata markup, ARM DDI 0403Derrata 2010_Q3). During processor reset, the interrupt priority of the supervisor call handler code is set to zero. As a result, without changing the default interrupt priority of the supervisor call, it is not interruptable. In derivative.h, SCB_SHPR2_PRI_11_MASK, SCB_SHPR2_PRI_11_SHIFT, and SCB_SHPR2_PRI_11(x) are defined to allow access to the appropriate field of this system control register. h. Test your implementation of non-interrupt driven output to the four LED's from Problem Set 3 through the new device-independent supervisor calls. As was the case in PS3, each LED should appear as a separate device. For example, they might be named /dev/led/orange, /dev/led/yellow, /dev/led/green, and /dev/led/blue. As mentioned above, your device-independent implementation of LED output will now be accessible through your supervisor call interface. i. Test your implementation of non-interrupt driven input from the two momentary pushbuttons from Problem Set 3 through the new device-independent supervisor calls. As was the case in PS3, each pushbutton should appear as a separate device. As mentioned above, your device-independent implementation of pushbutton input should now be accessible through your supervisor call interface. j. Implement non-interrupt driven input from the analog potentiometer. Integrate your implementation of analog potentiometer input into your device-independent I/O architecture. k. Implement non-interrupt driven input from the thermistor. Integrate your implementation of thermistor intput into your device-independent I/O architecture. l. Implement non-interrupt driven input from the four touch sensors. Each touch sensor should appear as a separate device. Integrate your implementation of touch sensor input into your device-independent I/O architecture. m. Test your implementation of input from and output to the microSDHC FAT32 file system through the new device-independent supervisor calls. As was the case in PS3, your implementation of the FAT32 file system is integrated into and accessible through your device-independent I/O architecture. n. Modify your shell and all shell commands to use your SVC device-independent I/O interface rather than directly calling your system calls. All shell command interaction that previously was explicitly conducted with the UART should now use device-independent I/O operations to stdin, stdout, or stderr, as appropriate. o. Implement test programs that call all the supervisor calls above to demonstrate that the system works. All test programs must be implemented as shell commands using device-independent I/O. Here are some required shell commands, but you are welcome to implement additional commands: 1. cat2file : Continuously copy characters from serial input to the specified in the root directory. End on a ^D (control-D) input character. 2. cat : Display the contents of the specified in the root directory. This is a refinement of the "cat" command from PS3 in that it will now use the supervisor calls to perform both the input and output functions rather than using calls to system functions for FAT32 file operations and rather than directly outputting to the UART. 3. touch2led: Continuously copy from each touch sensor to the corresponding LED. End when all four touch sensors are "depressed." 4. pot2ser: Continuously output the value of the analog potentiomemter to the serial device as a decimal or hexadecimal number followed by a newline. End when SW1 is depressed. 5. therm2ser: Continuously output the value of the thermistor to the serial device as a decimal or hexadecimal number followed by a newline. End when SW1 is depressed. 6. pb2led: Continuously copy from SW1 to orange LED and SW2 to yellow LED. End when both SW1 and SW2 are depressed. p. Call the "privUnprivileged" function (declared and defined in priv.h and priv.c) in your main program after all devices have been initialized and before your shell is invoked. This will start your shell running in Thread mode with Unprivileged execution state. See the class web site for sample programs to perform all the tasks above at a basic level. Last revised 1-Apr-24