计算机系统代写|ECE391: Computer Systems Engineering

这是一篇来自美国的关于计算机系统工程的计算机系统代写

Text-Mode Missile Command

In this machine problem, you will implement a text-mode version of Missile Command, the classic arcade video game,in x86 assembly as an extension to the Linux real-time clock (RTC) driver. This assignment should provide substantial experience with the x86 ISA and provide an introduction to how drivers accomplish tasks inside the Linux kernel.

This handout first explains your assignment in detail, then explains several concepts that you will need to understand and implement.

Please read the entire document before you begin.

A Note On This Handout: The sections entitled “Linux Device Driver Overview,” “RTC Overview,” “Ioctl Functions,” and “Tasklets” contain background Linux knowledge which is not critical for you to complete this MP. The material described in these background sections will be covered in lecture in the next few weeks, but it may be helpful to read these sections to familiarize yourself with the context of your code in this MP.

Missile Command

In our version of Missile Command, you control a missile silo and try to protect your cities from enemy missiles.

You direct your missiles by moving the crosshairs to the intended destination and pressing the spacebar to fire. The explosion generated at that location destroys enemy missiles within a two-square radius. The game ends when enemy missiles destroy all of your cities. Your score is the number of enemy missiles that you destroy.

The implementation of this game centers around a linked list containing an element for each active missile in the game. The game consists of two separate components: the kernel-space code, which manages this list, and the userspace code, which implements the rest of the game and processes user input. You will write a tasklet (see the section “Tasklets”, below) to execute on each interrupt generated by the RTC (see “RTC Overview”) and update the missiles in real-time. This linked list will reside inside the RTC driver in the kernel, so you will also write five ioctl’s (see “Ioctl Functions”) to provide the necessary interface between the kernel-space components of the game and the user-space components.

MP1 Data Structure

The main structure you will be working with is struct missile.

struct missile {

struct missile* next; /* pointer to next missile in linked list */

int x, y; /* x,y position on screen

int vx, vy; /* x,y velocity vector

int dest_x, dest_y; /* location at which the missile explodes */

int exploded; /* explosion duration counter

char c; /* character to draw for this missile

This structure definition is usable only in C programs. There are constants defined for you at the top of the provided mp1.S that give you easy access to the fields in this struct from your assembly code. See the comments in mp1.S for further information on how to use them.

You must maintain a linked list of missiles with one struct missile for each active missile in the game. A variable mp1 missile list has been declared in mp1.S. You should maintain this variable as a pointer to the first element in the linked list.

The x and y fields of the structure contain the current location of the missile on the screen. The text-mode video screen is 80 × 25, i.e., there are 80 columns and 25 rows. In order to allow finer control over the missiles’ velocities, each text-mode location is subdivided into 65536 × 65536 sub-squares. The low 16 bits of the x and y fields determine

Core Functions

You must implement each of the following five functions in x86 assembly in the mp1.S file.

int mp1 ioctl startgame (unsigned long ignore);

This function is called when the game is about to start. The parameter passed in arg is meaningless and should be ignored. This function should initialize all of the variables used by the driver—all of the variables declared in mp1.S—and the crosshairs should be set to the middle of the screen: (40, 12).

int mp1 ioctl addmissile (struct missile* user missile);

This ioctl must add a new missile to the game. The parameter is a pointer to a struct missile in user space. This function needs to copy the user’s missile into a dynamically allocated buffer in kernel space. If either the dynamic memory allocation (see “Allocating and Freeing Memory” below) or the data copy (see “Moving data to/from the kernel”) fails, this function should return -1. If it does fail, it should be sure to free any memory it has allocated before returning. If it succeeds, it should add the new missile into the linked list and return 0.

int mp1 ioctl movexhairs (unsigned long xhair delta packed);

This function moves the crosshairs. The parameter is a 32-bit integer containing two signed 16-bit integers packed into its low and high words. The low 16 bits contain the amount by which the x component of the crosshair position should change, and the high 16 bits contain the amount by which the y component should change. This function should not allow the crosshairs to be moved off of the screen—that is, it should ensure that the x component of its position stays within the range 0-79, and its y component stays within the range 0-24. If the position of the crosshairs does change,this function should redraw it at its new location. It should never fail, and always return 0.

int mp1 ioctl getstatus (unsigned long* user status);

This function allows the user to retrieve the current score and the status of the three cities. The argument is a pointer to a 32-bit integer in user space. This function should copy the current score into the low 16-bits of that integer, and the status of the three cities into bits 16, 17, and 18. The missile explode function maintains the user’s current score in the mp1 score variable declared in mp1.S. If a city is currently alive, the corresponding bit should be a 1; if it has been destroyed, the bit should be 0. The missile explode function maintains this information in the base alive array, as described above. This function should return 0 if the copy to user space succeeds, and -1 if it fails.

int mp1 ioctl endgame (unsigned long ignore);

Called when the game is over, this function must perform all the cleanup work. It should free all the memory being used by the linked list and then return success. When freeing the list, be careful to avoid accessing any memory that has already been freed.

Synchronization Constraints

The code (both user-level and kernel) for MP1 allows the tasklet to execute in the middle of any of the ioctls, so you must be careful to order the updates properly in some of the operations. Since the tasklet does not modify the list, the main constraint is that any ioctl that modifies the list does so in a way that never leaves the list in an unusable state.

In particular, mp1 ioctl addmissile must fill in the newly allocated structure, including the next field, before changing the head of the list to point to the new structure.

Similarly, mp1 missile remove must remove the element from the list before freeing it; copying the structure’s next pointer into a register is not sufficient, since the tasklet could try to read the structure after the call to mp1 free.