// Console input and output. // Input is from the keyboard or serial port. // Output is written to the screen and serial port. #include "types.h" #include "defs.h" #include "param.h" #include "traps.h" #include "spinlock.h" #include "sleeplock.h" #include "fs.h" #include "file.h" #include "memlayout.h" #include "mmu.h" #include "proc.h" #include "x86.h" #define INPUT_BUF 128 // Proc title length + 3 for the console id + 2 for the left and right border + 2 for space between #define MENUWIDTH 27 // Number of max consoles + 1 for bottom border and another 2 for a space between top and bottom #define MENUHEIGHT (MAXVCONSOLES + 3); // Vars to hold the current menu item and menu active bool static int currentmenuitem = 0; static int menuactive = 0; struct kbdbuffer { char buf[INPUT_BUF]; uint r; // Read index uint w; // Write index uint e; // Edit index }; struct kbdbuffer inputBuffer; struct kbdbuffer *input = 0; // Struct to hold the variables needed for a virtual console struct vconsole { uint consoleindex; struct spinlock lock; struct proc *processowner; ushort screenbuffer[SCRWIDTH * SCRHEIGHT]; struct kbdbuffer keybuffer; int pos; int active; int inuse; // Variables for the title bar, this can be manual set and locked, if not the current process is used uint titlebgcol; char proctitle[20]; int titlelocked; // Status for possible future use with the title bar to allow a proccess to set messages to print char status[30]; }; struct vconsole consoles[MAXVCONSOLES]; struct vconsole *currentconsole = 0; #define C(x) ((x) - '@') // Control-x struct vconsole* getvalidprocessconsoleptr(void); void clearconsole(ushort *bufferin); void loadscreenbuffer(ushort *bufferin); void savescreenbuffer(ushort *bufferin); void clearscreen(int prelocked); static void consputc(int); static int panicked = 0; static struct { struct spinlock lock; int locking; } cons; // Lock for all consoles (to lock when doing switching/creating?) static struct { struct spinlock lock; int locking; } vcons; // Static function for getting the current count of active consoles static int getcurrentactiveconsolecount(void) { int resultcount = 0; for (int i = 0; i < MAXVCONSOLES; i++) { if (consoles[i].active) { resultcount++; } } return resultcount; } // Function to get the menu index of an active console because they might be offset static int getconsolemenuindex(struct vconsole* consolein) { int resultcount = 0; for (int i = 0; i < MAXVCONSOLES; i++) { if (&consoles[i] == consolein && consoles[i].active) { break; } else { resultcount++; } } return resultcount; } // Function for getting the console at the given menu index static int getmenuindexconsole(int menuindex) { int resultcount = 0; int resultconsoleindex = 0; for (int i = 0; i < MAXVCONSOLES; i++) { if (consoles[i].active) { if (resultcount == menuindex) { resultconsoleindex = consoles[i].consoleindex; break; } else { resultcount++; } } } return resultconsoleindex; } // Function for getting a consoles index int getconsoleindex(struct vconsole* consolein) { return consolein->consoleindex; } // Split the printint so we can just get the char out in draw title // itoa is the function in the c standard library (?) so i reused the name // since it does something similar // Saves to the provided char array and returns the number of characters for looping static int itoa(int xx, int base, int sign, char* buf) { static char digits[] = "0123456789abcdef"; int i; uint x; if (sign && (sign = xx < 0)) { x = -xx; } else { x = xx; } i = 0; do { buf[i++] = digits[x % base]; } while ((x /= base) != 0); if (sign) { buf[i++] = '-'; } return i; } // Function for printing an integer as a string to the screen static void printint(int xx, int base, int sign) { int i = 0; char buf[16]; i = itoa(xx, base, sign, buf); while (--i >= 0) { consputc(buf[i]); } } // Print to the console. only understands %d, %x, %p, %s. void cprintf(char *fmt, ...) { int i, c, locking; uint *argp; char *s; struct vconsole* inconsoleptr = getvalidprocessconsoleptr(); locking = cons.locking; if (locking) { //acquire(&cons.lock); acquire(&inconsoleptr->lock); } if (fmt == 0) { panic("null fmt"); } argp = (uint *)(void *)(&fmt + 1); for (i = 0; (c = fmt[i] & 0xff) != 0; i++) { if (c != '%') { consputc(c); continue; } c = fmt[++i] & 0xff; if (c == 0) { break; } switch (c) { case 'd': printint(*argp++, 10, 1); break; case 'x': case 'p': printint(*argp++, 16, 0); break; case 's': if ((s = (char *)*argp++) == 0) { s = "(null)"; } for (; *s; s++) { consputc(*s); } break; case '%': consputc('%'); break; default: // Print unknown % sequence to draw attention. consputc('%'); consputc(c); break; } } if (locking) { //release(&cons.lock); release(&inconsoleptr->lock); } } // Function to provide the same string manipulation as cprint but saving to the given buffer so it can be used without printing to the screen // sprintf is the c function that normally does this so i used the same name here void sprintf(char* strbuffer, char *fmt, ...) { int i, c, si; uint *argp; char *s; char buf[16]; int x; if (fmt == 0) { panic("null fmt"); } si = 0; argp = (uint *)(void *)(&fmt + 1); for (i = 0; (c = fmt[i] & 0xff) != 0; i++) { if (c != '%') { strbuffer[si] = c; si++; continue; } c = fmt[++i] & 0xff; if (c == 0) { break; } switch (c) { case 'd': // Clear any existing buf data memset(buf, 0, sizeof buf); x = itoa(*argp++, 10, 1, buf); while (--x >= 0) { strbuffer[si] = buf[x]; si++; } break; case 'x': case 'p': // Clear any existing buf data memset(buf, 0, sizeof buf); x = itoa(*argp++, 16, 0, buf); while (--x >= 0) { strbuffer[si] = buf[x]; si++; } break; case 's': if ((s = (char *)*argp++) == 0) { s = "(null)"; } for (int sli = 0; sli < strlen(s); sli++) { strbuffer[si] = s[sli]; si++; } break; case '%': strbuffer[i] = '%'; si++; break; default: // Print unknown % sequence to draw attention. strbuffer[si] = '%'; si++; strbuffer[si] = c; si++; break; } } // Add string terminator to the end strbuffer[si] = '\0'; } void panic(char *s) { int i; uint pcs[10]; cli(); cons.locking = 0; // use lapiccpunum so that we can call panic from mycpu() cprintf("lapicid %d: panic: ", lapicid()); cprintf(s); cprintf("\n"); getcallerpcs(&s, pcs); for (i = 0; i < 10; i++) { cprintf(" %p", pcs[i]); } panicked = 1; // freeze other CPU for (;;) { ; } } // function that checks and returns a valid vconsole pointer, since i was repeating the same checks i moved it // into its own function to keep things looking clean struct vconsole* getvalidprocessconsoleptr(void) { struct vconsole* inconsoleptr = 0; // Check if a process has actually been created otherwise use the base console if (myproc() == 0x0) { inconsoleptr = currentconsole; if (inconsoleptr == 0) { // fall back to the base console if the process and currentconsole has no console assigned for some reason inconsoleptr = &consoles[0]; } } else { inconsoleptr = myproc()->consoleptr; if (inconsoleptr == 0) { // fall back to the console set in currentconsole inconsoleptr = currentconsole; if (inconsoleptr == 0) { // fall back to the base console if the process and currentconsole has no console assigned for some reason inconsoleptr = &consoles[0]; } } } return inconsoleptr; } #define BACKSPACE 0x100 #define CRTPORT 0x3d4 #define TITLEOFF (SCRWIDTH * 1) // Size of the offset we need for the title bar static ushort *crt = (ushort *)P2V(0xb8000); // CGA memory // Function for drawing the menu onto the screen static void drawmenu(void) { struct vconsole* inconsoleptr = getvalidprocessconsoleptr(); // Rows = the number of active consoles + 1 for the padding at the top, 1 for the padding at the bottom and 1 for the border int rows = getcurrentactiveconsolecount() + 3; int pos = TITLEOFF; uint c = 0; // Small buffer to hold the menu memory char menulines[MAXVCONSOLES][24]; // Setup our menu item line strings int menuindex = 0; for (int i = 0; i < MAXVCONSOLES; i++) { if (consoles[i].active) { memset(menulines[menuindex], 0, sizeof(menulines[i][0]) * sizeof(menulines[i])); sprintf(menulines[menuindex], "%d: %s", consoles[i].consoleindex, consoles[i].proctitle); if (consoles[i].inuse) { currentmenuitem = menuindex; } menuindex++; } } // Draw the rows for the menu for (int y = 0; y < rows; y++) { pos = TITLEOFF + (y * SCRWIDTH); for (int x = 0; x < MENUWIDTH; x++) { // Top line and the 2nd to last line are padding, we just draw spaces and the first and last x are the border character if (y == 0 || y == (rows - 2)) { if (x == 0 || x == (MENUWIDTH - 1)) { c = 0xB2 | inconsoleptr->titlebgcol; } else { c = 0x0720; } } // The last row is the bottom border, so we can just fill it with the border character else if (y == (rows - 1)) { c = 0xB2 | inconsoleptr->titlebgcol; } // Otherwise we draw the border chars and padding space with the console menu item string between else { if (x == 0 || x == (MENUWIDTH - 1)) { c = 0xB2 | inconsoleptr->titlebgcol; } else if (x == 1 || x == (MENUWIDTH - 2)) { c = 0x0720; } else { c = menulines[y - 1][x - 2]; c = (c & 0xff); if (currentmenuitem == (y - 1)) { c = c | 0xCF00; } else { c = c | 0x0700; } } } crt[pos] = c; pos++; } } menuactive = 1; } // Function that handles the moving of the highlight bar for the menu static void navigatemenu(int dir) { int pos = 0; int newindex = currentmenuitem + dir; int totalactiveconsoles = getcurrentactiveconsolecount(); if (newindex < 0) { newindex = 0; } else if (newindex >= totalactiveconsoles) { newindex = totalactiveconsoles - 1; } // make sure the new index isnt just the same as the current selected menu item, we then change the background bits around // which saves us from redrawing the menu every time the selected item changes if (newindex != currentmenuitem) { // change the background bits of the last selected item to black pos = TITLEOFF + ((currentmenuitem + 1) * SCRWIDTH); for (int x = 2; x < MENUWIDTH - 2; x++) { crt[pos + x] = (crt[pos + x] & 0x00FF) | 0x0700; } // change the background bits of the new selected item to the highlight color pos = TITLEOFF + ((newindex + 1) * SCRWIDTH); for (int x = 2; x < MENUWIDTH - 2; x++) { crt[pos + x] = crt[pos + x] | 0xCF00; } currentmenuitem = newindex; } } // Function that closes the menu and reloads the buffer into screen memory static void closemenu(void) { loadscreenbuffer(currentconsole->screenbuffer); int pos = currentconsole->pos; outb(CRTPORT, 14); outb(CRTPORT + 1, pos >> 8); outb(CRTPORT, 15); outb(CRTPORT + 1, pos); menuactive = 0; } // Function for drawing the title bar of the current console static void drawtitle(void) { struct vconsole* inconsoleptr = getvalidprocessconsoleptr(); int pos = 0; char c = ' '; // Setup the title bar strings to print char menutext[] = "(M)enu"; char consoletitletext[10]; // + (inconsoleptr->consoleindex + 1); sprintf(consoletitletext, "Console %d", inconsoleptr->consoleindex); // Loop through the top row and write the current character to the screen buffer for (pos = 0; pos < SCRWIDTH; pos++) { int offset = 0; // Print the menu text if (pos < 6) { c = menutext[pos - offset]; } // Print the console title else if (pos >= 10 && pos < 20) { offset = 10; c = consoletitletext[pos - offset]; } // Print the process/title name else if (pos >= 25 && pos < 45) { offset = 25; c = inconsoleptr->proctitle[pos - offset]; } // Print the status (not current in use) else if (pos >= 50 && pos < 80) { offset = 50; c = inconsoleptr->status[pos - offset]; } // Otherwise print a space character so we still get the background else { c = ' '; } // Print the actual character with the given bg and fg color settings if (inconsoleptr->inuse) { crt[pos] = (c & 0xff) | inconsoleptr->titlebgcol; } inconsoleptr->screenbuffer[pos] = (c & 0xff) | inconsoleptr->titlebgcol; } } // Function for printing a character to the screen and/or the current console buffer static void cgaputc(int c) { int pos; struct vconsole* inconsoleptr = getvalidprocessconsoleptr(); ushort *currentbuffer = inconsoleptr->screenbuffer; // if the console is inuse we get the hardware cursor position so we can use it if (inconsoleptr->inuse) { // Cursor position: col + 80*row. outb(CRTPORT, 14); pos = inb(CRTPORT + 1) << 8; outb(CRTPORT, 15); pos |= inb(CRTPORT + 1); } // If the console is not in use we use the position saved to the console struct else { pos = inconsoleptr->pos; } if (c == '\n') { pos += SCRWIDTH - pos % SCRWIDTH; } else if (c == BACKSPACE) { // Check that the pos is not in the title offset so they cant remove it if (pos > (TITLEOFF)) { currentbuffer[pos] = 0; // Clear the character from the buffer --pos; } } else { // If the console is inuse print the character to the screen if (inconsoleptr->inuse) { crt[pos] = (c & 0xff) | 0x0700; // black on white } // Save the current character to the console buffer currentbuffer[pos] = (c & 0xff) | 0x0700; // black on white pos++; } // Check that the pos is not in the title area or greater than the screen size if (pos < TITLEOFF || pos > SCRHEIGHT * SCRWIDTH) { panic("pos under/overflow"); } // Handle the overflow scrolling for the screen and buffer if ((pos / 80) >= 24) { // Scroll up. memmove(currentbuffer + TITLEOFF, currentbuffer + (SCRWIDTH + TITLEOFF), sizeof(crt[0]) * (SCRHEIGHT - 1) * SCRWIDTH); pos -= 80; memset(currentbuffer + pos, 0, sizeof(crt[0]) * (SCRHEIGHT * SCRWIDTH - pos)); if (inconsoleptr->inuse) { // Check if the menu is active, if so we want to offset the scrolling start pos so we dont overwrite the menu in screen memory int menuoffset = 0; if (menuactive) { int menuitems = getcurrentactiveconsolecount() + 3; for (int y = 0; y < menuitems; y++) { memmove(crt + menuoffset + TITLEOFF + MENUWIDTH, crt + menuoffset + (SCRWIDTH + TITLEOFF) + MENUWIDTH, sizeof(crt[0]) * (SCRWIDTH - MENUWIDTH)); menuoffset += SCRWIDTH; } } memmove(crt + TITLEOFF + menuoffset, crt + (SCRWIDTH + TITLEOFF) + menuoffset, (sizeof(crt[0]) * (SCRHEIGHT - 1) * SCRWIDTH) - menuoffset); memset(crt + pos, 0, sizeof(crt[0]) * (SCRHEIGHT * SCRWIDTH - pos)); } } // Set the consoles pos to the new pos, if the console was in use also save the hardware cursor pos inconsoleptr->pos = pos; if (inconsoleptr->inuse) { outb(CRTPORT, 14); outb(CRTPORT + 1, pos >> 8); outb(CRTPORT, 15); outb(CRTPORT + 1, pos); crt[pos] = ' ' | 0x0700; } } void consputc(int c) { if (panicked) { cli(); for (;;) { ; } } if (c == BACKSPACE) { uartputc('\b'); uartputc(' '); uartputc('\b'); } else { uartputc(c); } cgaputc(c); } int consoleget(void) { //struct vconsole* inconsoleptr = getvalidprocessconsoleptr(); int c; acquire(&cons.lock); while ((c = kbdgetc()) <= 0) { if (c == 0) { c = kbdgetc(); } } release(&cons.lock); return c; } void consoleintr(int (*getc)(void)) { int c; int doprocdump = 0; int doconsoleswitch = 0; int switchto = -1; int doconsolehome = 0; struct vconsole* inconsoleptr = getvalidprocessconsoleptr(); acquire(&cons.lock); struct kbdbuffer* consolekbdbuffer = ¤tconsole->keybuffer; while ((c = getc()) >= 0) { switch (c) { // Hotkeys for dealing with the menu // Close the menu case 27: if (menuactive) { closemenu(); } break; // Menu nav to the previous item // Up arrow (found in kbd.h) case 0xE2: if (menuactive) { navigatemenu(-1); } break; // Menu nav to the next item // Down arrow (found in kbd.h) case 0xE3: if (menuactive) { navigatemenu(1); } break; case C('P'): // Process listing. // procdump() locks cons.lock indirectly; invoke later doprocdump = 1; break; case C('U'): // Kill line. while (consolekbdbuffer->e != consolekbdbuffer->w && consolekbdbuffer->buf[(consolekbdbuffer->e - 1) % INPUT_BUF] != '\n') { consolekbdbuffer->e--; consputc(BACKSPACE); } break; case C('H'): case '\x7f': // Backspace if (consolekbdbuffer->e != consolekbdbuffer->w) { consolekbdbuffer->e--; consputc(BACKSPACE); } break; // Hotkey to switch to the next console case C('T'): doconsoleswitch = 1; break; // Hotkey to switch to the home console case C('K'): doconsolehome = 1; break; // Hotkey open the menu case C('M'): if (!menuactive) { drawmenu(); } else { closemenu(); } break; // If enter is hit and the menu is active then we want to override the normal behaviour case 10: if (menuactive) { closemenu(); switchto = currentmenuitem; doconsoleswitch = 1; // The menu has been sorted we can break from the switch break; } // if the menu was not active we want the enter to be handled in the default case default: if (!menuactive) { if (inconsoleptr->inuse) { if (c != 0 && consolekbdbuffer->e - consolekbdbuffer->r < INPUT_BUF) { c = (c == '\r') ? '\n' : c; consolekbdbuffer->buf[consolekbdbuffer->e++ % INPUT_BUF] = c; consputc(c); if (c == '\n' || c == C('D') || consolekbdbuffer->e == consolekbdbuffer->r + INPUT_BUF) { consolekbdbuffer->w = consolekbdbuffer->e; wakeup(&(consolekbdbuffer->r)); } } } } break; } } release(&cons.lock); if (doprocdump && !menuactive) { procdump(); // now call procdump() wo. cons.lock held } // Handle the home console hotkey if (doconsolehome) { if (currentconsole->consoleindex != 0) { switchtoconsole(getbaseconsoleptr()); } } // Handle the console switch hotkey if (doconsoleswitch) { struct vconsole* toconsole = 0; acquire(&vcons.lock); acquire(&cons.lock); if (switchto == -1) { for (int i = (currentconsole->consoleindex + 1); i < MAXVCONSOLES; i++) { if (consoles[i].active) { toconsole = &consoles[i]; break; } } if (toconsole == 0) { toconsole = getbaseconsoleptr(); } } else { toconsole = &consoles[getmenuindexconsole(switchto)]; } release(&cons.lock); release(&vcons.lock); if (!toconsole->inuse) { switchtoconsole(toconsole); } } } int consoleread(struct inode *ip, char *dst, int n) { uint target; int c; struct vconsole* inconsoleptr = getvalidprocessconsoleptr(); struct kbdbuffer* consolekbdbuffer = &inconsoleptr->keybuffer; iunlock(ip); target = n; acquire(&inconsoleptr->lock); while (n > 0) { while (consolekbdbuffer->r == consolekbdbuffer->w) { if (myproc()->killed) { release(&inconsoleptr->lock); ilock(ip); return -1; } sleep(&(consolekbdbuffer->r), &inconsoleptr->lock); } c = consolekbdbuffer->buf[consolekbdbuffer->r++ % INPUT_BUF]; if (c == C('D')) { // EOF if (n < target) { // Save ^D for next time, to make sure // caller gets a 0-byte result. consolekbdbuffer->r--; } break; } *dst++ = c; --n; if (c == '\n') { break; } } release(&inconsoleptr->lock); ilock(ip); return target - n; } int consolewrite(struct inode *ip, char *buf, int n) { int i; struct vconsole* inconsoleptr = getvalidprocessconsoleptr(); iunlock(ip); acquire(&inconsoleptr->lock); for (i = 0; i < n; i++) { consputc(buf[i] & 0xff); } release(&inconsoleptr->lock); ilock(ip); return n; } // Function to flood a buffer with A-Z characters looping (for testing initially) void testfillbuffer(ushort *bufferin) { ushort firstchar = 65; ushort lastchar = 90; ushort currentchar = firstchar; for (int i = 0; i < (SCRHEIGHT * SCRWIDTH); i++) { if (currentchar > lastchar) { currentchar = firstchar; } bufferin[i] = (currentchar & 0xff) | 0x0700; currentchar++; } } // Function to get a pointer to the base console struct vconsole* getbaseconsoleptr(void) { return &consoles[0]; } // Function to clear a given buffer using its pointer/address void clearconsole(ushort *bufferin) { // Flood the screen buffer with blank spaces memset(bufferin, 0, sizeof(bufferin[0]) * SCRHEIGHT * SCRWIDTH); } // Function for loading an entire buffer into the screen memory using its pointer/address void loadscreenbuffer(ushort *bufferin) { // Copy the memory from the console buffer to the crt buffer memmove(crt, bufferin, sizeof(bufferin[0]) * SCRHEIGHT * SCRWIDTH); } // Function for saving the current screen memory into a given buffer void savescreenbuffer(ushort *bufferin) { // Copy the memory from the console buffer to the crt buffer memmove(bufferin, crt, sizeof(crt[0]) * SCRHEIGHT * SCRWIDTH); } // Function for clearing the current screen/buffer void clearscreen(int prelocked) { // Check if a process has actually been created otherwise use the base console struct vconsole* inconsoleptr = getvalidprocessconsoleptr(); if (!prelocked) { acquire(&cons.lock); } int pos = TITLEOFF; clearconsole(inconsoleptr->screenbuffer); inconsoleptr->pos = pos; // If the console is in use load the blank buffer into screen memory and set the cursor position if (inconsoleptr->inuse) { loadscreenbuffer(inconsoleptr->screenbuffer); outb(CRTPORT, 14); outb(CRTPORT + 1, pos >> 8); outb(CRTPORT, 15); outb(CRTPORT + 1, pos); } // Draw the title bar onto the console drawtitle(); if (!prelocked) { release(&cons.lock); } } void consoleinit(void) { initlock(&cons.lock, "console"); initlock(&vcons.lock, "vconglobal"); // Init all of the virtual console buffers for (int i = 0; i < MAXVCONSOLES; i++) { consoles[i].consoleindex = i; consoles[i].processowner = 0; consoles[i].pos = 0; consoles[i].active = 0; consoles[i].inuse = 0; consoles[i].titlebgcol = 0x4F00; char lockname[8]; sprintf(lockname, "vconsole%d", i); initlock(&consoles[i].lock, lockname); } // Initialise pointer to point to our console input buffer currentconsole = &consoles[0]; currentconsole->active = 1; currentconsole->inuse = 1; input = ¤tconsole->keybuffer; devsw[CONSOLE].write = consolewrite; devsw[CONSOLE].read = consoleread; cons.locking = 1; // Clear the screen and print the welcome message clearscreen(0); cprintf("Welcome! you are currently in the base console\n"); ioapicenable(IRQ_KBD, 0); } // Function for "creating" a new console, in reality it sets the first non active console to active and setups the struct // if none are free it returns a nullptr/zero for the calling function to handle struct vconsole* newconsole(char* title, int bgpreset) { struct vconsole* result = 0; acquire(&vcons.lock); for (int i = 1; i < MAXVCONSOLES; i++) { if (!consoles[i].active) { consoles[i].processowner = myproc(); consoles[i].titlebgcol = bgpreset; if (strlen(title) > 0) { // Clear any text in the proc title incase this was a pre used console memset(consoles[i].proctitle, 0, sizeof(consoles[i].proctitle[0]) * sizeof(consoles[i].proctitle)); safestrcpy(consoles[i].proctitle, title, sizeof(consoles[i].proctitle)); consoles[i].titlelocked = 1; } else { consoles[i].titlelocked = 0; } result = &consoles[i]; break; } } release(&vcons.lock); return result; } // Function to "release" all consoles from inuse, this is to stop the chance of one not clearing and causing an issue with 2 being inuse void releaseallconsoles(void) { for (int i = 0; i < MAXVCONSOLES; i++) { consoles[i].inuse = 0; } } // Function for switching to another console using the given pointer int switchtoconsole(struct vconsole* consoleptr) { int pos; acquire(&vcons.lock); // Release all consoles before setting the new one to inuse releaseallconsoles(); currentconsole = consoleptr; currentconsole->inuse = 1; acquire(&cons.lock); // Load the next console into screen memory loadscreenbuffer(currentconsole->screenbuffer); // Checks if the console was active, if not its most likely the first switch to this so we clear and print the welcome message if (!currentconsole->active) { clearscreen(1); cprintf("Welcome to Console: %d\n", currentconsole->consoleindex); currentconsole->active = 1; } else { // If it was already active we just set the cursor position to the one saved in the console struct pos = currentconsole->pos; outb(CRTPORT, 14); outb(CRTPORT + 1, pos >> 8); outb(CRTPORT, 15); outb(CRTPORT + 1, pos); } // Remove the menu if it was active and set the console as the current menu item menuactive = 0; currentmenuitem = getconsolemenuindex(currentconsole); release(&cons.lock); release(&vcons.lock); return 0; } // Function for closing the current console int closeconsole(void) { struct vconsole* consoleptr = myproc()->consoleptr; acquire(&vcons.lock); // Check if the process exiting is the consoles parent process we clear the buffer and set the active to 0 if (myproc() == consoleptr->processowner) { clearconsole(consoleptr->screenbuffer); consoleptr->active = 0; // If the console was in use to switch back to the base console if (consoleptr->inuse) { consoleptr->inuse = 0; release(&vcons.lock); switchtoconsole(&consoles[0]); return 1; } } release(&vcons.lock); return 0; } // Function for getting the console index of the current inuse console int getcurrentconsoleindex(void) { acquire(&vcons.lock); for (int i = 0; i < MAXVCONSOLES; i++) { if (consoles[i].inuse) { release(&vcons.lock); return consoles[i].consoleindex; } } release(&vcons.lock); return -1; } // Function for setting the title of a console for the title bar and menu void setconsoleproctitle(struct vconsole* consoleptr, char* newtitle) { if (!consoleptr->titlelocked) { acquire(&vcons.lock); //Clear the current buffer memset(consoleptr->proctitle, 0, sizeof(consoleptr->proctitle[0]) * sizeof(consoleptr->proctitle)); //Copy the new title into the console title buffer safestrcpy(consoleptr->proctitle, newtitle, sizeof(consoleptr->proctitle)); //Redraw the title since its been updated now drawtitle(); release(&vcons.lock); } }