Submit: Turn in your
    spinlock_util.S, spinlock.c and
    testcases.c
    source files using the
    turnin command on morbius.mscsnet.mu.edu or
    one of the other
    
      Systems Lab machines.
Work should be completed in pairs.  Be certain
    to include both names in the comment block at the top of all
    source code files. It would be courteous to confirm with your
    partner when submitting the assignment.  You may modify any files
    in the operating system, but only changes to
    spinlock_util.S and spinlock.c
    will be graded for this assignment.
What happens when multiple cores attempt to transmit output over the same UART at the same time -- without mutual exclusion? In short, Undesirable Behavior™.
Currently, your embedded operating system does not
    support mutual exclusion across multiple cores.  Refer
    to system/testcases.c. In its current state, unparking
    cores 1, 2, and 3 to a function that prints "Hello World
    from core n" yields a distorted mess of
    characters.
To amend this behavior, you will implement a multicore spinlock for your synchronous serial driver from the previous project.
For this assignment, you will have to complete the spinlock
    acquire function, _lock_acquire(),
    in system/spinlock_util.S.  You will also have to
    complete lock_acquire()
    and lock_release() in system/spinlock.c.
  
Make sure:
serial_lock
	in kprintf() (refer
	to include/spinlock.h).In the coming multicore assignments, you will be running your kernel on the Raspberry Pi 3 Model B+ platform, which has four cores within its ARM Cortex-A53 processor. In previous years, this course used single-core platforms (i.e., PowerPC machines, Linksys MIPS routers, Raspberry Pi 1 boards) to run student code. Since 2019, Marquette has used real multicore hardware (as opposed to virtual machines) to lead hands-on laboratory assignments in Operating Systems. As best we can tell, we are one of the first universities in the world (possibly the first!) to do this successfully as part of a regular graduate course. (You're welcome!)
Your previous UART driver assignment ran on the Pi 3, but you only used one core for that. Now that your embedded O/S will be taking advantage of this multicore architecture, you need to know the multicore hardware operations built in for your use.
       
    
       
    
Although the concept of unparking is general to multicore
	platforms, the specific implementations vary from one platform
	to another.  When the Pi 3 B+ boots, only core 0 is setup to
	run, and cores 1-3 are put in a sleep state.  (The startup
	sequence in start.S executes the WFE
	opcode, "Wait For Event", on each of the other cores.)  To
	wake up, or unpark, a core, core 0 sends an event (ARM
	opcode SEV, "Send EVent",) to wake another core.
	Upon waking the new core will check the value in a special
	predetermined location known as its
      mailbox. The core then begins execution at the address
      that it finds in its mailbox.
    
In this example, core 3 is unparked and sent to execute a given
      test_procedure() with no arguments (NULL).  See the
      "Testing" section below for information about how to use this
      function.
    
Note: unparkcore() is already
      implemented for you and can be found
      in system/unparkcore.c
    
unparkcore(int core, void* address, void* argument);
In the implementation of unparkcore(), you will
      see that it will unpark the core to an assembly routine called
      setupCore() (found
      in system/setupCore.S). setupCore() is
      necessary because the core needs to undergo specific
      initializations before any of your code can run.
    
Note: Source files unparkcore.c
      and setupCore.S are already implemented for you.
    
 First, make a copy of your Project 3 directory:
    
        cp -R xinu-hw3 xinu-hw4
    Then, untar the new project files on top of it:
        tar xvzf ~brylow/os/Projects/xinu-hw4.tgz
  
 New files:
    
    
  
      
	
	
If you do this correctly, your kprintf.c synchronous
    serial driver file from the previous assignment will remain in place
    in the system/ directory.  You will not see any output
    for the project if a working solution for kgetc() is not
    in place.
  
As with any programming task, it is important to understand the concepts before jumping into the code. Before beginning this assignment, refer to Chapter 5 of the Dino Book. Make certain you understand the concepts of critical section and mutual exclusion.
    Further, please read this 
    ARM
      document explaining LDREX
      and STREX atomic operations which you will use in
      your implementation of _lock_acquire().
  
    Refer to the testcases() function
    within system/testcases.c.  By default, the testcases
    function unparks cores 1, 2, and 3 to a function called
    core_print(). Since core_print() does
    not take parameters,
    unparkcore() passes it NULL arguments.
  
    If the cores print out neatly, then it is highly likely that
    your _lock_acquire function works correctly (and that
    you properly called lock_acquire()
    and lock_release() in your kprintf()
    function).  Note that kprintf() itself is the
    critical section in this assignment that requires mutual
    exclusion.  It is not necessary to add spinlocks to any of the
    other synchronous serial driver functions.
  
[Revised 2020 Feb 04 20:48 DWB]