diff --git a/apps/extra/kilo/Makefile b/apps/extra/kilo/Makefile new file mode 100644 index 00000000..4a09c18c --- /dev/null +++ b/apps/extra/kilo/Makefile @@ -0,0 +1,5 @@ +INCLUDES += $(ROOTDIR)/include +INCLUDES += $(SYSROOT)/usr/include +CFLAGS += -pedantic -Wno-parentheses +include $(ROOTDIR)/build/cross.mk +include $(ROOTDIR)/build/build-binary.mk \ No newline at end of file diff --git a/apps/extra/kilo/main.c b/apps/extra/kilo/main.c new file mode 100644 index 00000000..4cf65809 --- /dev/null +++ b/apps/extra/kilo/main.c @@ -0,0 +1,1314 @@ +/* Kilo -- A very simple editor in less than 1-kilo lines of code (as counted + * by "cloc"). Does not depend on libcurses, directly emits VT100 + * escapes on the terminal. + * + * ----------------------------------------------------------------------- + * + * Copyright (C) 2016 Salvatore Sanfilippo + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define KILO_VERSION "0.0.1" + +#ifdef __linux__ +#define _POSIX_C_SOURCE 200809L +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Syntax highlight types */ +#define HL_NORMAL 0 +#define HL_NONPRINT 1 +#define HL_COMMENT 2 /* Single line comment. */ +#define HL_MLCOMMENT 3 /* Multi-line comment. */ +#define HL_KEYWORD1 4 +#define HL_KEYWORD2 5 +#define HL_STRING 6 +#define HL_NUMBER 7 +#define HL_MATCH 8 /* Search match. */ + +#define HL_HIGHLIGHT_STRINGS (1<<0) +#define HL_HIGHLIGHT_NUMBERS (1<<1) + +struct editorSyntax { + char **filematch; + char **keywords; + char singleline_comment_start[2]; + char multiline_comment_start[3]; + char multiline_comment_end[3]; + int flags; +}; + +/* This structure represents a single line of the file we are editing. */ +typedef struct erow { + int idx; /* Row index in the file, zero-based. */ + int size; /* Size of the row, excluding the null term. */ + int rsize; /* Size of the rendered row. */ + char *chars; /* Row content. */ + char *render; /* Row content "rendered" for screen (for TABs). */ + unsigned char *hl; /* Syntax highlight type for each character in render.*/ + int hl_oc; /* Row had open comment at end in last syntax highlight + check. */ +} erow; + +typedef struct hlcolor { + int r,g,b; +} hlcolor; + +struct editorConfig { + int cx,cy; /* Cursor x and y position in characters */ + int rowoff; /* Offset of row displayed. */ + int coloff; /* Offset of column displayed. */ + int screenrows; /* Number of rows that we can show */ + int screencols; /* Number of cols that we can show */ + int numrows; /* Number of rows */ + int rawmode; /* Is terminal raw mode enabled? */ + erow *row; /* Rows */ + int dirty; /* File modified but not saved. */ + char *filename; /* Currently open filename */ + char statusmsg[80]; + time_t statusmsg_time; + struct editorSyntax *syntax; /* Current syntax highlight, or NULL. */ +}; + +static struct editorConfig E; + +enum KEY_ACTION{ + KEY_NULL = 0, /* NULL */ + CTRL_C = 3, /* Ctrl-c */ + CTRL_D = 4, /* Ctrl-d */ + CTRL_F = 6, /* Ctrl-f */ + CTRL_H = 8, /* Ctrl-h */ + TAB = 9, /* Tab */ + CTRL_L = 12, /* Ctrl+l */ + ENTER = 10, /* Enter */ + CTRL_Q = 17, /* Ctrl-q */ + CTRL_S = 19, /* Ctrl-s */ + CTRL_U = 21, /* Ctrl-u */ + ESC = 27, /* Escape */ + BACKSPACE = 127, /* Backspace */ + /* The following are just soft codes, not really reported by the + * terminal directly. */ + ARROW_LEFT = 1000, + ARROW_RIGHT, + ARROW_UP, + ARROW_DOWN, + DEL_KEY, + HOME_KEY, + END_KEY, + PAGE_UP, + PAGE_DOWN +}; + +void editorSetStatusMessage(const char *fmt, ...); + +/* =========================== Syntax highlights DB ========================= + * + * In order to add a new syntax, define two arrays with a list of file name + * matches and keywords. The file name matches are used in order to match + * a given syntax with a given file name: if a match pattern starts with a + * dot, it is matched as the last past of the filename, for example ".c". + * Otherwise the pattern is just searched inside the filenme, like "Makefile"). + * + * The list of keywords to highlight is just a list of words, however if they + * a trailing '|' character is added at the end, they are highlighted in + * a different color, so that you can have two different sets of keywords. + * + * Finally add a stanza in the HLDB global variable with two two arrays + * of strings, and a set of flags in order to enable highlighting of + * comments and numbers. + * + * The characters for single and multi line comments must be exactly two + * and must be provided as well (see the C language example). + * + * There is no support to highlight patterns currently. */ + +/* C / C++ */ +char *C_HL_extensions[] = {".c",".h",".cpp",".hpp",".cc",NULL}; +char *C_HL_keywords[] = { + /* C Keywords */ + "auto","break","case","continue","default","do","else","enum", + "extern","for","goto","if","register","return","sizeof","static", + "struct","switch","typedef","union","volatile","while","NULL", + + /* C++ Keywords */ + "alignas","alignof","and","and_eq","asm","bitand","bitor","class", + "compl","constexpr","const_cast","deltype","delete","dynamic_cast", + "explicit","export","false","friend","inline","mutable","namespace", + "new","noexcept","not","not_eq","nullptr","operator","or","or_eq", + "private","protected","public","reinterpret_cast","static_assert", + "static_cast","template","this","thread_local","throw","true","try", + "typeid","typename","virtual","xor","xor_eq", + + /* C types */ + "int|","long|","double|","float|","char|","unsigned|","signed|", + "void|","short|","auto|","const|","bool|",NULL +}; + +/* Here we define an array of syntax highlights by extensions, keywords, + * comments delimiters and flags. */ +struct editorSyntax HLDB[] = { + { + /* C / C++ */ + C_HL_extensions, + C_HL_keywords, + "//","/*","*/", + HL_HIGHLIGHT_STRINGS | HL_HIGHLIGHT_NUMBERS + } +}; + +#define HLDB_ENTRIES (sizeof(HLDB)/sizeof(HLDB[0])) + +/* ======================= Low level terminal handling ====================== */ + +static struct termios orig_termios; /* In order to restore at exit.*/ + +void disableRawMode(int fd) { + /* Don't even check the return value as it's too late. */ + if (E.rawmode) { + tcsetattr(fd,TCSAFLUSH,&orig_termios); + E.rawmode = 0; + } +} + +void clearScreen(void) { + write(STDOUT_FILENO, "\x1b[2J", 4); + write(STDOUT_FILENO, "\x1b[H", 3); +} + +/* Called at exit to avoid remaining in raw mode. */ +void editorAtExit(void) { + disableRawMode(STDIN_FILENO); + clearScreen(); +} + +/* Raw mode: 1960 magic shit. */ +int enableRawMode(int fd) { + struct termios raw; + + if (E.rawmode) return 0; /* Already enabled. */ + if (!isatty(STDIN_FILENO)) goto fatal; + atexit(editorAtExit); + if (tcgetattr(fd,&orig_termios) == -1) goto fatal; + + raw = orig_termios; /* modify the original mode */ + /* input modes: no break, no CR to NL, no parity check, no strip char, + * no start/stop output control. */ + raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + /* output modes - disable post processing */ + raw.c_oflag &= ~(OPOST); + /* control modes - set 8 bit chars */ + raw.c_cflag |= (CS8); + /* local modes - choing off, canonical off, no extended functions, + * no signal chars (^Z,^C) */ + raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + /* control chars - set return condition: min number of bytes and timer. */ + raw.c_cc[VMIN] = 0; /* Return each byte, or zero for timeout. */ + raw.c_cc[VTIME] = 1; /* 100 ms timeout (unit is tens of second). */ + + /* put terminal in raw mode after flushing */ + if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal; + E.rawmode = 1; + return 0; + +fatal: + errno = ENOTTY; + return -1; +} + +/* Read a key from the terminal put in raw mode, trying to handle + * escape sequences. */ +int editorReadKey(int fd) { + int nread; + char c, seq[3]; + while ((nread = read(fd,&c,1)) == 0); + if (nread == -1) exit(1); + + while(1) { + switch(c) { + case ESC: /* escape sequence */ + /* If this is just an ESC, we'll timeout here. */ + if (read(fd,seq,1) == 0) return ESC; + if (read(fd,seq+1,1) == 0) return ESC; + + /* ESC [ sequences. */ + if (seq[0] == '[') { + if (seq[1] >= '0' && seq[1] <= '9') { + /* Extended escape, read additional byte. */ + if (read(fd,seq+2,1) == 0) return ESC; + if (seq[2] == '~') { + switch(seq[1]) { + case '3': return DEL_KEY; + case '5': return PAGE_UP; + case '6': return PAGE_DOWN; + } + } + } else { + switch(seq[1]) { + case 'A': return ARROW_UP; + case 'B': return ARROW_DOWN; + case 'C': return ARROW_RIGHT; + case 'D': return ARROW_LEFT; + case 'H': return HOME_KEY; + case 'F': return END_KEY; + } + } + } + + /* ESC O sequences. */ + else if (seq[0] == 'O') { + switch(seq[1]) { + case 'H': return HOME_KEY; + case 'F': return END_KEY; + } + } + break; + default: + return c; + } + } +} + +/* Use the ESC [6n escape sequence to query the horizontal cursor position + * and return it. On error -1 is returned, on success the position of the + * cursor is stored at *rows and *cols and 0 is returned. */ +int getCursorPosition(int ifd, int ofd, int *rows, int *cols) { + char buf[32]; + unsigned int i = 0; + + /* Report cursor location */ + if (write(ofd, "\x1b[6n", 4) != 4) return -1; + + /* Read the response: ESC [ rows ; cols R */ + while (i < sizeof(buf)-1) { + if (read(ifd,buf+i,1) != 1) break; + if (buf[i] == 'R') break; + i++; + } + buf[i] = '\0'; + + /* Parse it. */ + if (buf[0] != ESC || buf[1] != '[') return -1; + if (sscanf(buf+2,"%d;%d",rows,cols) != 2) return -1; + return 0; +} + +/* Try to get the number of columns in the current terminal. If the ioctl() + * call fails the function will try to query the terminal itself. + * Returns 0 on success, -1 on error. */ +int getWindowSize(int ifd, int ofd, int *rows, int *cols) { + struct winsize ws; + + if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { + /* ioctl() failed. Try to query the terminal itself. */ + int orig_row, orig_col, retval; + + /* Get the initial position so we can restore it later. */ + retval = getCursorPosition(ifd,ofd,&orig_row,&orig_col); + if (retval == -1) goto failed; + + /* Go to right/bottom margin and get position. */ + if (write(ofd,"\x1b[999C\x1b[999B",12) != 12) goto failed; + retval = getCursorPosition(ifd,ofd,rows,cols); + if (retval == -1) goto failed; + + /* Restore position. */ + char seq[32]; + snprintf(seq,32,"\x1b[%d;%dH",orig_row,orig_col); + if (write(ofd,seq,strlen(seq)) == -1) { + /* Can't recover... */ + } + return 0; + } else { + *cols = ws.ws_col; + *rows = ws.ws_row; + return 0; + } + +failed: + return -1; +} + +/* ====================== Syntax highlight color scheme ==================== */ + +int is_separator(int c) { + return c == '\0' || isspace(c) || strchr(",.()+-/*=~%[];",c) != NULL; +} + +/* Return true if the specified row last char is part of a multi line comment + * that starts at this row or at one before, and does not end at the end + * of the row but spawns to the next row. */ +int editorRowHasOpenComment(erow *row) { + if (row->hl && row->rsize && row->hl[row->rsize-1] == HL_MLCOMMENT && + (row->rsize < 2 || (row->render[row->rsize-2] != '*' || + row->render[row->rsize-1] != '/'))) return 1; + return 0; +} + +/* Set every byte of row->hl (that corresponds to every character in the line) + * to the right syntax highlight type (HL_* defines). */ +void editorUpdateSyntax(erow *row) { + row->hl = realloc(row->hl,row->rsize); + memset(row->hl,HL_NORMAL,row->rsize); + + if (E.syntax == NULL) return; /* No syntax, everything is HL_NORMAL. */ + + int i, prev_sep, in_string, in_comment; + char *p; + char **keywords = E.syntax->keywords; + char *scs = E.syntax->singleline_comment_start; + char *mcs = E.syntax->multiline_comment_start; + char *mce = E.syntax->multiline_comment_end; + + /* Point to the first non-space char. */ + p = row->render; + i = 0; /* Current char offset */ + while(*p && isspace(*p)) { + p++; + i++; + } + prev_sep = 1; /* Tell the parser if 'i' points to start of word. */ + in_string = 0; /* Are we inside "" or '' ? */ + in_comment = 0; /* Are we inside multi-line comment? */ + + /* If the previous line has an open comment, this line starts + * with an open comment state. */ + if (row->idx > 0 && editorRowHasOpenComment(&E.row[row->idx-1])) + in_comment = 1; + + while(*p) { + /* Handle // comments. */ + if (prev_sep && *p == scs[0] && *(p+1) == scs[1]) { + /* From here to end is a comment */ + memset(row->hl+i,HL_COMMENT,row->size-i); + return; + } + + /* Handle multi line comments. */ + if (in_comment) { + row->hl[i] = HL_MLCOMMENT; + if (*p == mce[0] && *(p+1) == mce[1]) { + row->hl[i+1] = HL_MLCOMMENT; + p += 2; i += 2; + in_comment = 0; + prev_sep = 1; + continue; + } else { + prev_sep = 0; + p++; i++; + continue; + } + } else if (*p == mcs[0] && *(p+1) == mcs[1]) { + row->hl[i] = HL_MLCOMMENT; + row->hl[i+1] = HL_MLCOMMENT; + p += 2; i += 2; + in_comment = 1; + prev_sep = 0; + continue; + } + + /* Handle "" and '' */ + if (in_string) { + row->hl[i] = HL_STRING; + if (*p == '\\') { + row->hl[i+1] = HL_STRING; + p += 2; i += 2; + prev_sep = 0; + continue; + } + if (*p == in_string) in_string = 0; + p++; i++; + continue; + } else { + if (*p == '"' || *p == '\'') { + in_string = *p; + row->hl[i] = HL_STRING; + p++; i++; + prev_sep = 0; + continue; + } + } + + /* Handle non printable chars. */ + if (!isprint(*p)) { + row->hl[i] = HL_NONPRINT; + p++; i++; + prev_sep = 0; + continue; + } + + /* Handle numbers */ + if ((isdigit(*p) && (prev_sep || row->hl[i-1] == HL_NUMBER)) || + (*p == '.' && i >0 && row->hl[i-1] == HL_NUMBER)) { + row->hl[i] = HL_NUMBER; + p++; i++; + prev_sep = 0; + continue; + } + + /* Handle keywords and lib calls */ + if (prev_sep) { + int j; + for (j = 0; keywords[j]; j++) { + int klen = strlen(keywords[j]); + int kw2 = keywords[j][klen-1] == '|'; + if (kw2) klen--; + + if (!memcmp(p,keywords[j],klen) && + is_separator(*(p+klen))) + { + /* Keyword */ + memset(row->hl+i,kw2 ? HL_KEYWORD2 : HL_KEYWORD1,klen); + p += klen; + i += klen; + break; + } + } + if (keywords[j] != NULL) { + prev_sep = 0; + continue; /* We had a keyword match */ + } + } + + /* Not special chars */ + prev_sep = is_separator(*p); + p++; i++; + } + + /* Propagate syntax change to the next row if the open commen + * state changed. This may recursively affect all the following rows + * in the file. */ + int oc = editorRowHasOpenComment(row); + if (row->hl_oc != oc && row->idx+1 < E.numrows) + editorUpdateSyntax(&E.row[row->idx+1]); + row->hl_oc = oc; +} + +/* Maps syntax highlight token types to terminal colors. */ +int editorSyntaxToColor(int hl) { + switch(hl) { + case HL_COMMENT: + case HL_MLCOMMENT: return 36; /* cyan */ + case HL_KEYWORD1: return 33; /* yellow */ + case HL_KEYWORD2: return 32; /* green */ + case HL_STRING: return 35; /* magenta */ + case HL_NUMBER: return 31; /* red */ + case HL_MATCH: return 34; /* blu */ + default: return 37; /* white */ + } +} + +/* Select the syntax highlight scheme depending on the filename, + * setting it in the global state E.syntax. */ +void editorSelectSyntaxHighlight(char *filename) { + for (unsigned int j = 0; j < HLDB_ENTRIES; j++) { + struct editorSyntax *s = HLDB+j; + unsigned int i = 0; + while(s->filematch[i]) { + char *p; + int patlen = strlen(s->filematch[i]); + if ((p = strstr(filename,s->filematch[i])) != NULL) { + if (s->filematch[i][0] != '.' || p[patlen] == '\0') { + E.syntax = s; + return; + } + } + i++; + } + } +} + +/* ======================= Editor rows implementation ======================= */ + +/* Update the rendered version and the syntax highlight of a row. */ +void editorUpdateRow(erow *row) { + unsigned int tabs = 0, nonprint = 0; + int j, idx; + + /* Create a version of the row we can directly print on the screen, + * respecting tabs, substituting non printable characters with '?'. */ + free(row->render); + for (j = 0; j < row->size; j++) + if (row->chars[j] == TAB) tabs++; + + unsigned long long allocsize = + (unsigned long long) row->size + tabs*8 + nonprint*9 + 1; + if (allocsize > UINT32_MAX) { + printf("Some line of the edited file is too long for kilo\n"); + exit(1); + } + + row->render = malloc(row->size + tabs*8 + nonprint*9 + 1); + idx = 0; + for (j = 0; j < row->size; j++) { + if (row->chars[j] == TAB) { + row->render[idx++] = ' '; + while((idx+1) % 8 != 0) row->render[idx++] = ' '; + } else { + row->render[idx++] = row->chars[j]; + } + } + row->rsize = idx; + row->render[idx] = '\0'; + + /* Update the syntax highlighting attributes of the row. */ + editorUpdateSyntax(row); +} + +/* Insert a row at the specified position, shifting the other rows on the bottom + * if required. */ +void editorInsertRow(int at, char *s, size_t len) { + if (at > E.numrows) return; + E.row = realloc(E.row,sizeof(erow)*(E.numrows+1)); + if (at != E.numrows) { + memmove(E.row+at+1,E.row+at,sizeof(E.row[0])*(E.numrows-at)); + for (int j = at+1; j <= E.numrows; j++) E.row[j].idx++; + } + E.row[at].size = len; + E.row[at].chars = malloc(len+1); + memcpy(E.row[at].chars,s,len+1); + E.row[at].hl = NULL; + E.row[at].hl_oc = 0; + E.row[at].render = NULL; + E.row[at].rsize = 0; + E.row[at].idx = at; + editorUpdateRow(E.row+at); + E.numrows++; + E.dirty++; +} + +/* Free row's heap allocated stuff. */ +void editorFreeRow(erow *row) { + free(row->render); + free(row->chars); + free(row->hl); +} + +/* Remove the row at the specified position, shifting the remainign on the + * top. */ +void editorDelRow(int at) { + erow *row; + + if (at >= E.numrows) return; + row = E.row+at; + editorFreeRow(row); + memmove(E.row+at,E.row+at+1,sizeof(E.row[0])*(E.numrows-at-1)); + for (int j = at; j < E.numrows-1; j++) E.row[j].idx++; + E.numrows--; + E.dirty++; +} + +/* Turn the editor rows into a single heap-allocated string. + * Returns the pointer to the heap-allocated string and populate the + * integer pointed by 'buflen' with the size of the string, escluding + * the final nulterm. */ +char *editorRowsToString(int *buflen) { + char *buf = NULL, *p; + int totlen = 0; + int j; + + /* Compute count of bytes */ + for (j = 0; j < E.numrows; j++) + totlen += E.row[j].size+1; /* +1 is for "\n" at end of every row */ + *buflen = totlen; + totlen++; /* Also make space for nulterm */ + + p = buf = malloc(totlen); + for (j = 0; j < E.numrows; j++) { + memcpy(p,E.row[j].chars,E.row[j].size); + p += E.row[j].size; + *p = '\n'; + p++; + } + *p = '\0'; + return buf; +} + +/* Insert a character at the specified position in a row, moving the remaining + * chars on the right if needed. */ +void editorRowInsertChar(erow *row, int at, int c) { + if (at > row->size) { + /* Pad the string with spaces if the insert location is outside the + * current length by more than a single character. */ + int padlen = at-row->size; + /* In the next line +2 means: new char and null term. */ + row->chars = realloc(row->chars,row->size+padlen+2); + memset(row->chars+row->size,' ',padlen); + row->chars[row->size+padlen+1] = '\0'; + row->size += padlen+1; + } else { + /* If we are in the middle of the string just make space for 1 new + * char plus the (already existing) null term. */ + row->chars = realloc(row->chars,row->size+2); + memmove(row->chars+at+1,row->chars+at,row->size-at+1); + row->size++; + } + row->chars[at] = c; + editorUpdateRow(row); + E.dirty++; +} + +/* Append the string 's' at the end of a row */ +void editorRowAppendString(erow *row, char *s, size_t len) { + row->chars = realloc(row->chars,row->size+len+1); + memcpy(row->chars+row->size,s,len); + row->size += len; + row->chars[row->size] = '\0'; + editorUpdateRow(row); + E.dirty++; +} + +/* Delete the character at offset 'at' from the specified row. */ +void editorRowDelChar(erow *row, int at) { + if (row->size <= at) return; + memmove(row->chars+at,row->chars+at+1,row->size-at); + editorUpdateRow(row); + row->size--; + E.dirty++; +} + +/* Insert the specified char at the current prompt position. */ +void editorInsertChar(int c) { + int filerow = E.rowoff+E.cy; + int filecol = E.coloff+E.cx; + erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow]; + + /* If the row where the cursor is currently located does not exist in our + * logical representaion of the file, add enough empty rows as needed. */ + if (!row) { + while(E.numrows <= filerow) + editorInsertRow(E.numrows,"",0); + } + row = &E.row[filerow]; + editorRowInsertChar(row,filecol,c); + if (E.cx == E.screencols-1) + E.coloff++; + else + E.cx++; + E.dirty++; +} + +/* Inserting a newline is slightly complex as we have to handle inserting a + * newline in the middle of a line, splitting the line as needed. */ +void editorInsertNewline(void) { + int filerow = E.rowoff+E.cy; + int filecol = E.coloff+E.cx; + erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow]; + + if (!row) { + if (filerow == E.numrows) { + editorInsertRow(filerow,"",0); + goto fixcursor; + } + return; + } + /* If the cursor is over the current line size, we want to conceptually + * think it's just over the last character. */ + if (filecol >= row->size) filecol = row->size; + if (filecol == 0) { + editorInsertRow(filerow,"",0); + } else { + /* We are in the middle of a line. Split it between two rows. */ + editorInsertRow(filerow+1,row->chars+filecol,row->size-filecol); + row = &E.row[filerow]; + row->chars[filecol] = '\0'; + row->size = filecol; + editorUpdateRow(row); + } +fixcursor: + if (E.cy == E.screenrows-1) { + E.rowoff++; + } else { + E.cy++; + } + E.cx = 0; + E.coloff = 0; +} + +/* Delete the char at the current prompt position. */ +void editorDelChar(void) { + int filerow = E.rowoff+E.cy; + int filecol = E.coloff+E.cx; + erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow]; + + if (!row || (filecol == 0 && filerow == 0)) return; + if (filecol == 0) { + /* Handle the case of column 0, we need to move the current line + * on the right of the previous one. */ + filecol = E.row[filerow-1].size; + editorRowAppendString(&E.row[filerow-1],row->chars,row->size); + editorDelRow(filerow); + row = NULL; + if (E.cy == 0) + E.rowoff--; + else + E.cy--; + E.cx = filecol; + if (E.cx >= E.screencols) { + int shift = (E.screencols-E.cx)+1; + E.cx -= shift; + E.coloff += shift; + } + } else { + editorRowDelChar(row,filecol-1); + if (E.cx == 0 && E.coloff) + E.coloff--; + else + E.cx--; + } + if (row) editorUpdateRow(row); + E.dirty++; +} + +/* Load the specified program in the editor memory and returns 0 on success + * or 1 on error. */ +int editorOpen(char *filename) { + FILE *fp; + + E.dirty = 0; + free(E.filename); + size_t fnlen = strlen(filename)+1; + E.filename = malloc(fnlen); + memcpy(E.filename,filename,fnlen); + + fp = fopen(filename,"r"); + if (!fp) { + if (errno != ENOENT) { + perror("Opening file"); + exit(1); + } + return 1; + } + + char *line = NULL; + size_t linecap = 0; + ssize_t linelen; + while((linelen = getline(&line,&linecap,fp)) != -1) { + if (linelen && (line[linelen-1] == '\n' || line[linelen-1] == '\r')) + line[--linelen] = '\0'; + editorInsertRow(E.numrows,line,linelen); + } + free(line); + fclose(fp); + E.dirty = 0; + return 0; +} + +/* Save the current file on disk. Return 0 on success, 1 on error. */ +int editorSave(void) { + int len; + char *buf = editorRowsToString(&len); + int fd = open(E.filename,O_RDWR|O_CREAT,0644); + if (fd == -1) goto writeerr; + + /* Use truncate + a single write(2) call in order to make saving + * a bit safer, under the limits of what we can do in a small editor. */ + if (ftruncate(fd,len) == -1) goto writeerr; + if (write(fd,buf,len) != len) goto writeerr; + + close(fd); + free(buf); + E.dirty = 0; + editorSetStatusMessage("%d bytes written on disk", len); + return 0; + +writeerr: + free(buf); + if (fd != -1) close(fd); + editorSetStatusMessage("Can't save! I/O error: %s",strerror(errno)); + return 1; +} + +/* ============================= Terminal update ============================ */ + +/* We define a very simple "append buffer" structure, that is an heap + * allocated string where we can append to. This is useful in order to + * write all the escape sequences in a buffer and flush them to the standard + * output in a single call, to avoid flickering effects. */ +struct abuf { + char *b; + int len; +}; + +#define ABUF_INIT {NULL,0} + +void abAppend(struct abuf *ab, const char *s, int len) { + char *new = realloc(ab->b,ab->len+len); + + if (new == NULL) return; + memcpy(new+ab->len,s,len); + ab->b = new; + ab->len += len; +} + +void abFree(struct abuf *ab) { + free(ab->b); +} + +/* This function writes the whole screen using VT100 escape characters + * starting from the logical state of the editor in the global state 'E'. */ +void editorRefreshScreen(void) { + int y; + erow *r; + char buf[32]; + struct abuf ab = ABUF_INIT; + + abAppend(&ab,"\x1b[?25l",6); /* Hide cursor. */ + abAppend(&ab,"\x1b[H",3); /* Go home. */ + for (y = 0; y < E.screenrows; y++) { + int filerow = E.rowoff+y; + + if (filerow >= E.numrows) { + if (E.numrows == 0 && y == E.screenrows/3) { + char welcome[80]; + int welcomelen = snprintf(welcome,sizeof(welcome), + "Kilo editor -- verison %s\x1b[0K\r\n", KILO_VERSION); + int padding = (E.screencols-welcomelen)/2; + if (padding) { + abAppend(&ab,"~",1); + padding--; + } + while(padding--) abAppend(&ab," ",1); + abAppend(&ab,welcome,welcomelen); + } else { + abAppend(&ab,"~\x1b[0K\r\n",7); + } + continue; + } + + r = &E.row[filerow]; + + int len = r->rsize - E.coloff; + int current_color = -1; + if (len > 0) { + if (len > E.screencols) len = E.screencols; + char *c = r->render+E.coloff; + unsigned char *hl = r->hl+E.coloff; + int j; + for (j = 0; j < len; j++) { + if (hl[j] == HL_NONPRINT) { + char sym; + abAppend(&ab,"\x1b[7m",4); + if (c[j] <= 26) + sym = '@'+c[j]; + else + sym = '?'; + abAppend(&ab,&sym,1); + abAppend(&ab,"\x1b[0m",4); + } else if (hl[j] == HL_NORMAL) { + if (current_color != -1) { + abAppend(&ab,"\x1b[39m",5); + current_color = -1; + } + abAppend(&ab,c+j,1); + } else { + int color = editorSyntaxToColor(hl[j]); + if (color != current_color) { + char buf[16]; + int clen = snprintf(buf,sizeof(buf),"\x1b[%dm",color); + current_color = color; + abAppend(&ab,buf,clen); + } + abAppend(&ab,c+j,1); + } + } + } + abAppend(&ab,"\x1b[39m",5); + abAppend(&ab,"\x1b[0K",4); + abAppend(&ab,"\r\n",2); + } + + /* Create a two rows status. First row: */ + abAppend(&ab,"\x1b[0K",4); + abAppend(&ab,"\x1b[7m",4); + char status[80], rstatus[80]; + int len = snprintf(status, sizeof(status), "%.20s - %d lines %s", + E.filename, E.numrows, E.dirty ? "(modified)" : ""); + int rlen = snprintf(rstatus, sizeof(rstatus), + "%d/%d",E.rowoff+E.cy+1,E.numrows); + if (len > E.screencols) len = E.screencols; + abAppend(&ab,status,len); + while(len < E.screencols) { + if (E.screencols - len == rlen) { + abAppend(&ab,rstatus,rlen); + break; + } else { + abAppend(&ab," ",1); + len++; + } + } + abAppend(&ab,"\x1b[0m\r\n",6); + + /* Second row depends on E.statusmsg and the status message update time. */ + abAppend(&ab,"\x1b[0K",4); + int msglen = strlen(E.statusmsg); + if (msglen && time(NULL)-E.statusmsg_time < 5) + abAppend(&ab,E.statusmsg,msglen <= E.screencols ? msglen : E.screencols); + + /* Put cursor at its current position. Note that the horizontal position + * at which the cursor is displayed may be different compared to 'E.cx' + * because of TABs. */ + int j; + int cx = 1; + int filerow = E.rowoff+E.cy; + erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow]; + if (row) { + for (j = E.coloff; j < (E.cx+E.coloff); j++) { + if (j < row->size && row->chars[j] == TAB) cx += 7-((cx)%8); + cx++; + } + } + snprintf(buf,sizeof(buf),"\x1b[%d;%dH",E.cy+1,cx); + abAppend(&ab,buf,strlen(buf)); + abAppend(&ab,"\x1b[?25h",6); /* Show cursor. */ + write(STDOUT_FILENO,ab.b,ab.len); + abFree(&ab); +} + +/* Set an editor status message for the second line of the status, at the + * end of the screen. */ +void editorSetStatusMessage(const char *fmt, ...) { + va_list ap; + va_start(ap,fmt); + vsnprintf(E.statusmsg,sizeof(E.statusmsg),fmt,ap); + va_end(ap); + E.statusmsg_time = time(NULL); +} + +/* =============================== Find mode ================================ */ + +#define KILO_QUERY_LEN 256 + +void editorFind(int fd) { + char query[KILO_QUERY_LEN+1] = {0}; + int qlen = 0; + int last_match = -1; /* Last line where a match was found. -1 for none. */ + int find_next = 0; /* if 1 search next, if -1 search prev. */ + int saved_hl_line = -1; /* No saved HL */ + char *saved_hl = NULL; + +#define FIND_RESTORE_HL do { \ + if (saved_hl) { \ + memcpy(E.row[saved_hl_line].hl,saved_hl, E.row[saved_hl_line].rsize); \ + free(saved_hl); \ + saved_hl = NULL; \ + } \ +} while (0) + + /* Save the cursor position in order to restore it later. */ + int saved_cx = E.cx, saved_cy = E.cy; + int saved_coloff = E.coloff, saved_rowoff = E.rowoff; + + while(1) { + editorSetStatusMessage( + "Search: %s (Use ESC/Arrows/Enter)", query); + editorRefreshScreen(); + + int c = editorReadKey(fd); + if (c == DEL_KEY || c == CTRL_H || c == BACKSPACE) { + if (qlen != 0) query[--qlen] = '\0'; + last_match = -1; + } else if (c == ESC || c == ENTER) { + if (c == ESC) { + E.cx = saved_cx; E.cy = saved_cy; + E.coloff = saved_coloff; E.rowoff = saved_rowoff; + } + FIND_RESTORE_HL; + editorSetStatusMessage(""); + return; + } else if (c == ARROW_RIGHT || c == ARROW_DOWN) { + find_next = 1; + } else if (c == ARROW_LEFT || c == ARROW_UP) { + find_next = -1; + } else if (isprint(c)) { + if (qlen < KILO_QUERY_LEN) { + query[qlen++] = c; + query[qlen] = '\0'; + last_match = -1; + } + } + + /* Search occurrence. */ + if (last_match == -1) find_next = 1; + if (find_next) { + char *match = NULL; + int match_offset = 0; + int i, current = last_match; + + for (i = 0; i < E.numrows; i++) { + current += find_next; + if (current == -1) current = E.numrows-1; + else if (current == E.numrows) current = 0; + match = strstr(E.row[current].render,query); + if (match) { + match_offset = match-E.row[current].render; + break; + } + } + find_next = 0; + + /* Highlight */ + FIND_RESTORE_HL; + + if (match) { + erow *row = &E.row[current]; + last_match = current; + if (row->hl) { + saved_hl_line = current; + saved_hl = malloc(row->rsize); + memcpy(saved_hl,row->hl,row->rsize); + memset(row->hl+match_offset,HL_MATCH,qlen); + } + E.cy = 0; + E.cx = match_offset; + E.rowoff = current; + E.coloff = 0; + /* Scroll horizontally as needed. */ + if (E.cx > E.screencols) { + int diff = E.cx - E.screencols; + E.cx -= diff; + E.coloff += diff; + } + } + } + } +} + +/* ========================= Editor events handling ======================== */ + +/* Handle cursor position change because arrow keys were pressed. */ +void editorMoveCursor(int key) { + int filerow = E.rowoff+E.cy; + int filecol = E.coloff+E.cx; + int rowlen; + erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow]; + + switch(key) { + case ARROW_LEFT: + if (E.cx == 0) { + if (E.coloff) { + E.coloff--; + } else { + if (filerow > 0) { + E.cy--; + E.cx = E.row[filerow-1].size; + if (E.cx > E.screencols-1) { + E.coloff = E.cx-E.screencols+1; + E.cx = E.screencols-1; + } + } + } + } else { + E.cx -= 1; + } + break; + case ARROW_RIGHT: + if (row && filecol < row->size) { + if (E.cx == E.screencols-1) { + E.coloff++; + } else { + E.cx += 1; + } + } else if (row && filecol == row->size) { + E.cx = 0; + E.coloff = 0; + if (E.cy == E.screenrows-1) { + E.rowoff++; + } else { + E.cy += 1; + } + } + break; + case ARROW_UP: + if (E.cy == 0) { + if (E.rowoff) E.rowoff--; + } else { + E.cy -= 1; + } + break; + case ARROW_DOWN: + if (filerow < E.numrows) { + if (E.cy == E.screenrows-1) { + E.rowoff++; + } else { + E.cy += 1; + } + } + break; + } + /* Fix cx if the current line has not enough chars. */ + filerow = E.rowoff+E.cy; + filecol = E.coloff+E.cx; + row = (filerow >= E.numrows) ? NULL : &E.row[filerow]; + rowlen = row ? row->size : 0; + if (filecol > rowlen) { + E.cx -= filecol-rowlen; + if (E.cx < 0) { + E.coloff += E.cx; + E.cx = 0; + } + } +} + +/* Process events arriving from the standard input, which is, the user + * is typing stuff on the terminal. */ +#define KILO_QUIT_TIMES 3 +void editorProcessKeypress(int fd) { + /* When the file is modified, requires Ctrl-q to be pressed N times + * before actually quitting. */ + static int quit_times = KILO_QUIT_TIMES; + + int c = editorReadKey(fd); + switch(c) { + case ENTER: /* Enter */ + editorInsertNewline(); + break; + case CTRL_C: /* Ctrl-c */ + /* We ignore ctrl-c, it can't be so simple to lose the changes + * to the edited file. */ + break; + case CTRL_Q: /* Ctrl-q */ + /* Quit if the file was already saved. */ + if (E.dirty && quit_times) { + editorSetStatusMessage("WARNING!!! File has unsaved changes. " + "Press Ctrl-Q %d more times to quit.", quit_times); + quit_times--; + return; + } + exit(0); + break; + case CTRL_S: /* Ctrl-s */ + editorSave(); + break; + case CTRL_F: + editorFind(fd); + break; + case BACKSPACE: /* Backspace */ + case CTRL_H: /* Ctrl-h */ + case DEL_KEY: + editorDelChar(); + break; + case PAGE_UP: + case PAGE_DOWN: + if (c == PAGE_UP && E.cy != 0) + E.cy = 0; + else if (c == PAGE_DOWN && E.cy != E.screenrows-1) + E.cy = E.screenrows-1; + { + int times = E.screenrows; + while(times--) + editorMoveCursor(c == PAGE_UP ? ARROW_UP: + ARROW_DOWN); + } + break; + + case ARROW_UP: + case ARROW_DOWN: + case ARROW_LEFT: + case ARROW_RIGHT: + editorMoveCursor(c); + break; + case CTRL_L: /* ctrl+l, clear screen */ + /* Just refresht the line as side effect. */ + break; + case ESC: + /* Nothing to do for ESC in this mode. */ + break; + default: + editorInsertChar(c); + break; + } + + quit_times = KILO_QUIT_TIMES; /* Reset it to the original value. */ +} + +int editorFileWasModified(void) { + return E.dirty; +} + +void updateWindowSize(void) { + if (getWindowSize(STDIN_FILENO,STDOUT_FILENO, + &E.screenrows,&E.screencols) == -1) { + perror("Unable to query the screen for size (columns / rows)"); + exit(1); + } + E.screenrows -= 2; /* Get room for status bar. */ +} + +void handleSigWinCh(int unused __attribute__((unused))) { + updateWindowSize(); + if (E.cy > E.screenrows) E.cy = E.screenrows - 1; + if (E.cx > E.screencols) E.cx = E.screencols - 1; + editorRefreshScreen(); +} + +void initEditor(void) { + E.cx = 0; + E.cy = 0; + E.rowoff = 0; + E.coloff = 0; + E.numrows = 0; + E.row = NULL; + E.dirty = 0; + E.filename = NULL; + E.syntax = NULL; + updateWindowSize(); + signal(SIGWINCH, handleSigWinCh); +} + +int main(int argc, char **argv) { + if (argc != 2) { + fprintf(stderr,"Usage: kilo \n"); + exit(1); + } + + initEditor(); + editorSelectSyntaxHighlight(argv[1]); + editorOpen(argv[1]); + enableRawMode(STDIN_FILENO); + editorSetStatusMessage( + "HELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find"); + while(1) { + editorRefreshScreen(); + editorProcessKeypress(STDIN_FILENO); + } + return 0; +} \ No newline at end of file diff --git a/drivers/dev/pci/pci_msix.c b/drivers/dev/pci/pci_msix.c index 76996ed5..cb732467 100644 --- a/drivers/dev/pci/pci_msix.c +++ b/drivers/dev/pci/pci_msix.c @@ -113,6 +113,9 @@ int pci_find_msix(pcidev_t device, pci_msix_t* mptr) { msix.msix_rows = (pci_msix_row_t volatile*)pci_bir_address; msix.msix_pba = (pci_msix_pba_t volatile*)pci_pba_address; + memset((void*) msix.msix_rows, 0, sizeof(pci_msix_row_t) * (msix.msix_pci.pci_msgctl_table_size + 1)); + memset((void*) msix.msix_pba, 0, sizeof(pci_msix_pba_t) + ((msix.msix_pci.pci_msgctl_table_size + 7) / 8)); + for (size_t i = 0; i < msix.msix_pci.pci_msgctl_table_size + 1; i++) pci_msix_mask(device, &msix, i); @@ -197,6 +200,7 @@ int pci_msix_map_irq(pcidev_t device, pci_msix_t* msix, pci_irq_handler_t handle msix->msix_rows[i].pr_data = cpu_to_le32(index + PCI_MSIX_INTR_BASE + 0x20); msix->msix_rows[i].pr_ctl = cpu_to_le32(le32_to_cpu(msix->msix_rows[i].pr_ctl) | PCI_MSIX_INTR_MASK); + break; } if (i == msix->msix_pci.pci_msgctl_table_size + 1) { @@ -237,6 +241,7 @@ int pci_msix_unmap_irq(pcidev_t device, pci_msix_t* msix) { msix->msix_rows[i].pr_data = 0; msix->msix_rows[i].pr_ctl = cpu_to_le32(le32_to_cpu(msix->msix_rows[i].pr_ctl) | PCI_MSIX_INTR_MASK); + break; } if (i == msix->msix_pci.pci_msgctl_table_size + 1) { diff --git a/drivers/platform/pc/input/ps2/main.c b/drivers/platform/pc/input/ps2/main.c index 695a5bad..42f222a1 100644 --- a/drivers/platform/pc/input/ps2/main.c +++ b/drivers/platform/pc/input/ps2/main.c @@ -268,8 +268,10 @@ void ps2_mouse_irq(void* context, irq_t irq) { case 0: - if ((packet[cycle] & 0x08) == 0) + if ((packet[cycle] & 0x08) == 0) { + cycle = 0; return; + } cycle++; break; @@ -379,7 +381,6 @@ void ps2_mouse_irq(void* context, irq_t irq) { cycle = 0; - break; } } diff --git a/drivers/platform/pc/video/bochs-vga/main.c b/drivers/platform/pc/video/bochs-vga/main.c index 92d6dbcf..9e79a7f4 100644 --- a/drivers/platform/pc/video/bochs-vga/main.c +++ b/drivers/platform/pc/video/bochs-vga/main.c @@ -266,7 +266,7 @@ void init(const char* args) { return; } -#ifdef DEBUG_LEVEL_TRACE +#if DEBUG_LEVEL_TRACE kprintf("bochs-vga: found BGA device with identifier 0x%04X\n", identifier); #endif diff --git a/drivers/tty/pty/main.c b/drivers/tty/pty/main.c index 981ccdec..e9b3165d 100644 --- a/drivers/tty/pty/main.c +++ b/drivers/tty/pty/main.c @@ -64,8 +64,9 @@ __attribute__((used)) static void pty_input_discard(pty_t* pty, bool drain) { if (pty->input.size == 0) return; - +#if DEBUG_LEVEL_TRACE kprintf("pty_input_discard(): discarding %zd bytes\n", pty->input.size); +#endif DEBUG_ASSERT(pty->input.buffer); DEBUG_ASSERT(pty->input.capacity); @@ -188,7 +189,9 @@ static ssize_t pty_process_input(pty_t* pty, const char* buf, size_t size) { char ch = buf[i]; +#if DEBUG_LEVEL_TRACE kprintf("pty_input_process(): processing char '%c' (0x%x), c_lflag: 0%o, c_iflag: 0%o, c_oflag: 0%o, c_cflag: 0%o\n", ch, ch, pty->ios.c_lflag, pty->ios.c_iflag, pty->ios.c_oflag, pty->ios.c_cflag); +#endif // c_iflag @@ -233,8 +236,9 @@ static ssize_t pty_process_input(pty_t* pty, const char* buf, size_t size) { if (sig > 0) { +#if DEBUG_LEVEL_TRACE kprintf("pty_input_process(): sending signal %d to process group %d\n", sig, pty->s_pgrp); - +#endif if (pty->ios.c_lflag & ECHO) { char cb[2] = {'^', ch + 0x40}; @@ -248,7 +252,10 @@ static ssize_t pty_process_input(pty_t* pty, const char* buf, size_t size) { if (pty->s_pgrp > 0) { int e = sys_kill(-pty->s_pgrp, sig); +#if DEBUG_LEVEL_TRACE kprintf("pty_input_process(): sys_kill() returned %d (%d)\n", e, errno); +#endif + (void)e; } continue; @@ -257,12 +264,16 @@ static ssize_t pty_process_input(pty_t* pty, const char* buf, size_t size) { if (pty->ios.c_lflag & ICANON) { +#if DEBUG_LEVEL_TRACE kprintf("pty_input_process(): canonical mode\n"); +#endif // Canonical mode if (ch == pty->ios.c_cc[VKILL]) { +#if DEBUG_LEVEL_TRACE kprintf("pty_input_process(): VKILL\n"); +#endif while (pty->input.size > 0) { pty_input_backspace(pty, pty->ios.c_lflag & ECHOK); @@ -279,8 +290,9 @@ static ssize_t pty_process_input(pty_t* pty, const char* buf, size_t size) { else if (ch == pty->ios.c_cc[VERASE]) { +#if DEBUG_LEVEL_TRACE kprintf("pty_input_process(): VERASE\n"); - +#endif pty_input_backspace(pty, pty->ios.c_lflag & ECHOE); if (!(pty->ios.c_lflag & ECHOE) && pty->ios.c_lflag & ECHO) { @@ -294,8 +306,9 @@ static ssize_t pty_process_input(pty_t* pty, const char* buf, size_t size) { else if (ch == pty->ios.c_cc[VWERASE]) { +#if DEBUG_LEVEL_TRACE kprintf("pty_input_process(): VWERASE\n"); - +#endif // TODO: VWERASE: erase the word to the left of the cursor continue; @@ -304,16 +317,18 @@ static ssize_t pty_process_input(pty_t* pty, const char* buf, size_t size) { else if (ch == pty->ios.c_cc[VEOF]) { +#if DEBUG_LEVEL_TRACE kprintf("pty_input_process(): VEOF\n"); - +#endif pty_input_discard(pty, pty->ios.c_lflag & ECHO); } else if (ch == pty->ios.c_cc[VEOL] || ch == '\n') { +#if DEBUG_LEVEL_TRACE kprintf("pty_input_process(): VEOL or newline\n"); - +#endif pty_input_append(pty, '\n', pty->ios.c_lflag & ECHONL); pty_input_discard(pty, pty->ios.c_lflag & ECHO); @@ -321,14 +336,16 @@ static ssize_t pty_process_input(pty_t* pty, const char* buf, size_t size) { else { +#if DEBUG_LEVEL_TRACE kprintf("pty_input_process(): appending char\n"); - +#endif pty_input_append(pty, ch, pty->ios.c_lflag & ECHO); } } else { +#if DEBUG_LEVEL_TRACE kprintf("pty_input_process(): non-canonical mode\n"); - +#endif // Non-canonical mode (raw mode) if (pty->ios.c_lflag & ECHO) { diff --git a/drivers/virtio/virtio-console/main.c b/drivers/virtio/virtio-console/main.c index 5abbe727..69027c2d 100644 --- a/drivers/virtio/virtio-console/main.c +++ b/drivers/virtio/virtio-console/main.c @@ -149,10 +149,24 @@ static ssize_t virtconsole_write(device_t* device, const void* buf, size_t size) DEBUG_ASSERT(device->userdata); DEBUG_ASSERT(buf); + struct virtio_driver* driver = (struct virtio_driver*)device->userdata; + if (unlikely(size == 0)) return 0; - return virtq_send((struct virtio_driver*)device->userdata, VIRTIO_CONSOLE_PORT_TX(0), buf, size); + for (size_t sent = 0; sent < size; ) { + + ssize_t rem = MIN(size - sent, driver->send_window_size); + ssize_t ret = virtq_send(driver, VIRTIO_CONSOLE_PORT_TX(0), (const uint8_t*)buf + sent, rem); + + if (ret < 0) { + return ret; + } + + sent += ret; + } + + return size; } static ssize_t virtconsole_read(device_t* device, void* buf, size_t size) { diff --git a/drivers/virtio/virtio-gpu/main.c b/drivers/virtio/virtio-gpu/main.c index 6e2c1314..be4e2b87 100644 --- a/drivers/virtio/virtio-gpu/main.c +++ b/drivers/virtio/virtio-gpu/main.c @@ -53,8 +53,6 @@ MODULE_LICENSE("GPL"); #define VIRTGPU_ID "VIRTIO-GPU" - -#define VIRTGPU_FB_RESID 1 #define VIRTGPU_DISPLAY_PRIMARY 0 @@ -88,21 +86,18 @@ device_t device = { }; +uint64_t virtgpu_fb_resid = 0; static void virtgpu_init(device_t* device) { - DEBUG_ASSERT(device); DEBUG_ASSERT(device->vid.fb_base == 0); DEBUG_ASSERT(device->vid.fb_size == 0); - - virtgpu_reset(device); } static void virtgpu_dnit(device_t* device) { - DEBUG_ASSERT(device); if (unlikely(device->vid.fs.smem_start)) @@ -112,52 +107,38 @@ static void virtgpu_dnit(device_t* device) { static void virtgpu_reset_framebuffer(device_t* device) { - DEBUG_ASSERT(device); DEBUG_ASSERT(device->userdata); + struct virtio_gpu_resp_display_info display_info = {0}; + if (virtgpu_cmd_get_display_info(device->userdata, &display_info) < 0) { + device->status = DEVICE_STATUS_FAILED; + return; + } + if (!display_info.pmodes[VIRTGPU_DISPLAY_PRIMARY].enabled) { #if DEBUG_LEVEL_ERROR - #define __(cmd, args...) \ - { \ - kprintf("virtio-gpu: " #cmd "\n"); \ - int e; \ - if ((e = cmd(args)) < 0) { \ - kprintf("virtio-gpu: ERROR! %s failed: %d\n", #cmd, -e); \ - device->status = DEVICE_STATUS_FAILED; \ - return; \ - } \ - } -#else - #define __(cmd, args...) \ - { \ - if (cmd(args) < 0) { \ - device->status = DEVICE_STATUS_FAILED; \ - return; \ - } \ - } + kprintf("virtio-gpu: ERROR! Primary display %d not enabled\n", VIRTGPU_DISPLAY_PRIMARY); #endif + device->status = DEVICE_STATUS_FAILED; + return; + } + if (virtgpu_cmd_resource_create_2d(device->userdata, &virtgpu_fb_resid, VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM, device->vid.vs.xres, device->vid.vs.yres) < 0) { + device->status = DEVICE_STATUS_FAILED; + return; + } - // uint64_t resource; - - // __(virtgpu_cmd_resource_create_2d, device->userdata, &resource, VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM, device->vid.vs.xres_virtual, device->vid.vs.yres_virtual); - // __(virtgpu_cmd_resource_attach_backing, device->userdata, resource, device->vid.fb_base, device->vid.fb_size); - // __(virtgpu_cmd_set_scanout, device->userdata, VIRTGPU_DISPLAY_PRIMARY, resource, 0, 0, device->vid.vs.xres, device->vid.vs.yres); - - - struct virtio_gpu_resp_display_info display_info = {0}; - - __(virtgpu_cmd_get_display_info, device->userdata, &display_info); - __(virtgpu_cmd_get_display_info, device->userdata, &display_info); - __(virtgpu_cmd_get_display_info, device->userdata, &display_info); - __(virtgpu_cmd_get_display_info, device->userdata, &display_info); - __(virtgpu_cmd_get_display_info, device->userdata, &display_info); + if (virtgpu_cmd_resource_attach_backing(device->userdata, virtgpu_fb_resid, device->vid.fb_base, device->vid.fb_size) < 0) { + device->status = DEVICE_STATUS_FAILED; + return; + } - for (;;) - ; + if (virtgpu_cmd_set_scanout(device->userdata, VIRTGPU_DISPLAY_PRIMARY, virtgpu_fb_resid, 0, 0, device->vid.vs.xres, device->vid.vs.yres) < 0) { + device->status = DEVICE_STATUS_FAILED; + return; + } -#undef __ } @@ -195,8 +176,8 @@ static void virtgpu_reset(device_t* device) { device->vid.vs.activate = FB_ACTIVATE_NOW; - device->vid.fb_base = pmm_alloc_blocks(device->vid.vs.xres_virtual * device->vid.vs.yres_virtual * device->vid.vs.bits_per_pixel / 8 / PML1_PAGESIZE + 1); - device->vid.fb_size = device->vid.vs.xres_virtual * device->vid.vs.yres_virtual * device->vid.vs.bits_per_pixel / 8; + device->vid.fb_base = pmm_alloc_blocks(device->vid.vs.xres * device->vid.vs.yres * device->vid.vs.bits_per_pixel / 8 / PML1_PAGESIZE + 1); + device->vid.fb_size = device->vid.vs.xres * device->vid.vs.yres * device->vid.vs.bits_per_pixel / 8; virtgpu_reset_framebuffer(device); @@ -243,11 +224,11 @@ static void virtgpu_update(device_t* device) { static void virtgpu_wait_vsync(device_t* device) { - DEBUG_ASSERT(device); DEBUG_ASSERT(device->userdata); - virtgpu_cmd_transfer_to_host_2d(device->userdata, VIRTGPU_FB_RESID, 0, 0, 0, device->vid.vs.xres, device->vid.vs.yres); + virtgpu_cmd_transfer_to_host_2d(device->userdata, virtgpu_fb_resid, 0, 0, 0, device->vid.vs.xres, device->vid.vs.yres); + virtgpu_cmd_resource_flush(device->userdata, virtgpu_fb_resid, 0, 0, device->vid.vs.xres, device->vid.vs.yres); } @@ -293,23 +274,18 @@ static int interrupt_handler(pcidev_t device, irq_t vector, struct virtio_driver struct virtio_gpu_config* cfg = (struct virtio_gpu_config*)driver->internals.device_config; cfg->events_clear = cfg->events_read; - - kprintf("!!!!!!!!!!!!!!!RECEIVED MSI-X INTERRUPT!!!!!!!!!!!!!!!!!!: %p\n", device); - - return 0; } static void pci_find(pcidev_t device, uint16_t vid, uint16_t did, void* arg) { - + DEBUG_ASSERT(arg); device_t* driver = (device_t*)arg; if (driver->userdata != NULL) return; - if (vid != VIRTIO_PCI_VENDOR) return; @@ -317,7 +293,6 @@ static void pci_find(pcidev_t device, uint16_t vid, uint16_t did, void* arg) { return; - struct virtio_driver* virtio = kcalloc(1, sizeof(struct virtio_driver), GFP_KERNEL); virtio->type = VIRTIO_DEVICE_TYPE_GPU; diff --git a/drivers/virtio/virtio-gpu/virtgpu_cmd.c b/drivers/virtio/virtio-gpu/virtgpu_cmd.c index adc87213..a7603f05 100644 --- a/drivers/virtio/virtio-gpu/virtgpu_cmd.c +++ b/drivers/virtio/virtio-gpu/virtgpu_cmd.c @@ -45,18 +45,15 @@ int virtgpu_cmd_resource_detach_backing(struct virtgpu* gpu, uint64_t resource) { - DEBUG_ASSERT(gpu); DEBUG_ASSERT(gpu->driver); - struct virtio_gpu_resource_detach_backing cmd; struct virtio_gpu_response resp; cmd.hdr.type = VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING; cmd.resource_id = resource; - if (virtq_sendrecv(gpu->driver, VIRTIO_GPU_QUEUE_CONTROL, &cmd, sizeof(cmd), &resp, sizeof(resp)) < 0) return errno = EIO, -1; @@ -65,18 +62,15 @@ int virtgpu_cmd_resource_detach_backing(struct virtgpu* gpu, uint64_t resource) int virtgpu_cmd_resource_unref(struct virtgpu* gpu, uint64_t resource) { - DEBUG_ASSERT(gpu); DEBUG_ASSERT(gpu->driver); - struct virtio_gpu_resource_unref cmd; struct virtio_gpu_response resp; cmd.hdr.type = VIRTIO_GPU_CMD_RESOURCE_UNREF; cmd.resource_id = resource; - if (virtq_sendrecv(gpu->driver, VIRTIO_GPU_QUEUE_CONTROL, &cmd, sizeof(cmd), &resp, sizeof(resp)) < 0) return errno = EIO, -1; @@ -85,15 +79,12 @@ int virtgpu_cmd_resource_unref(struct virtgpu* gpu, uint64_t resource) { int virtgpu_cmd_resource_create_2d(struct virtgpu* gpu, uint64_t* resource, uint32_t format, uint32_t width, uint32_t height) { - DEBUG_ASSERT(gpu); DEBUG_ASSERT(gpu->driver); - struct virtio_gpu_resource_create_2d cmd = {0}; struct virtio_gpu_response resp = {0}; - uint64_t resource_id = ++gpu->resource_ids; cmd.hdr.type = VIRTIO_GPU_CMD_RESOURCE_CREATE_2D; @@ -102,30 +93,20 @@ int virtgpu_cmd_resource_create_2d(struct virtgpu* gpu, uint64_t* resource, uint cmd.width = width; cmd.height = height; - if (virtq_sendrecv(gpu->driver, VIRTIO_GPU_QUEUE_CONTROL, &cmd, sizeof(cmd), &resp, sizeof(resp)) < 0) return errno = EIO, -1; if (resp.hdr.type != VIRTIO_GPU_RESP_OK_NODATA) return errno = EINVAL, -1; - // dump hdr - kprintf("resp.hdr.type = %X\n", resp.hdr.type); - kprintf("resp.hdr.flags = %d\n", resp.hdr.flags); - kprintf("resp.hdr.fence_id = %d\n", resp.hdr.fence_id); - kprintf("resp.hdr.ctx_id = %d\n", resp.hdr.ctx_id); - kprintf("resp.hdr.padding = %d\n", resp.hdr.padding); - return *resource = resource_id, 0; } int virtgpu_cmd_resource_attach_backing(struct virtgpu* gpu, uint64_t resource, uint64_t framebuffer, size_t size) { - DEBUG_ASSERT(gpu); DEBUG_ASSERT(gpu->driver); - struct virtio_gpu_resource_attach_backing cmd = {0}; struct virtio_gpu_response resp = {0}; @@ -135,27 +116,17 @@ int virtgpu_cmd_resource_attach_backing(struct virtgpu* gpu, uint64_t resource, cmd.entries[0].address = framebuffer; cmd.entries[0].length = size; - if (virtq_sendrecv(gpu->driver, VIRTIO_GPU_QUEUE_CONTROL, &cmd, sizeof(cmd), &resp, sizeof(resp)) < 0) return errno = EIO, -1; - // dump hdr - kprintf("resp.hdr.type = %X\n", resp.hdr.type); - kprintf("resp.hdr.flags = %d\n", resp.hdr.flags); - kprintf("resp.hdr.fence_id = %d\n", resp.hdr.fence_id); - kprintf("resp.hdr.ctx_id = %d\n", resp.hdr.ctx_id); - kprintf("resp.hdr.padding = %d\n", resp.hdr.padding); - return resp.hdr.type == VIRTIO_GPU_RESP_OK_NODATA ? 0 : -EINVAL; } int virtgpu_cmd_set_scanout(struct virtgpu* gpu, uint32_t scanout_id, uint64_t resource, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { - DEBUG_ASSERT(gpu); DEBUG_ASSERT(gpu->driver); - struct virtio_gpu_set_scanout cmd = {0}; struct virtio_gpu_response resp = {0}; @@ -167,27 +138,17 @@ int virtgpu_cmd_set_scanout(struct virtgpu* gpu, uint32_t scanout_id, uint64_t r cmd.r.width = width; cmd.r.height = height; - if (virtq_sendrecv(gpu->driver, VIRTIO_GPU_QUEUE_CONTROL, &cmd, sizeof(cmd), &resp, sizeof(resp)) < 0) return errno = EIO, -1; - // dump hdr - kprintf("resp.hdr.type = %X\n", resp.hdr.type); - kprintf("resp.hdr.flags = %d\n", resp.hdr.flags); - kprintf("resp.hdr.fence_id = %d\n", resp.hdr.fence_id); - kprintf("resp.hdr.ctx_id = %d\n", resp.hdr.ctx_id); - kprintf("resp.hdr.padding = %d\n", resp.hdr.padding); - return resp.hdr.type == VIRTIO_GPU_RESP_OK_NODATA ? 0 : -EINVAL; } int virtgpu_cmd_transfer_to_host_2d(struct virtgpu* gpu, uint64_t resource, uint64_t offset, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { - DEBUG_ASSERT(gpu); DEBUG_ASSERT(gpu->driver); - struct virtio_gpu_transfer_to_host_2d cmd = {0}; struct virtio_gpu_response resp = {0}; @@ -199,7 +160,6 @@ int virtgpu_cmd_transfer_to_host_2d(struct virtgpu* gpu, uint64_t resource, uint cmd.r.height = height; cmd.resource_id = resource; - if (virtq_sendrecv(gpu->driver, VIRTIO_GPU_QUEUE_CONTROL, &cmd, sizeof(cmd), &resp, sizeof(resp)) < 0) return errno = EIO, -1; @@ -208,11 +168,9 @@ int virtgpu_cmd_transfer_to_host_2d(struct virtgpu* gpu, uint64_t resource, uint int virtgpu_cmd_get_display_info(struct virtgpu* gpu, struct virtio_gpu_resp_display_info* display_info) { - DEBUG_ASSERT(gpu); DEBUG_ASSERT(gpu->driver); - struct virtio_gpu_ctrl_hdr cmd = {0}; struct virtio_gpu_response resp = {0}; @@ -224,23 +182,26 @@ int virtgpu_cmd_get_display_info(struct virtgpu* gpu, struct virtio_gpu_resp_dis if (resp.hdr.type != VIRTIO_GPU_RESP_OK_DISPLAY_INFO) return errno = EINVAL, -1; + memcpy(display_info, &resp.display_info, sizeof(*display_info)); + return 0; +} - kprintf("resp.hdr.type = %X\n", resp.hdr.type); - kprintf("resp.hdr.flags = %d\n", resp.hdr.flags); - kprintf("resp.hdr.fence_id = %d\n", resp.hdr.fence_id); - kprintf("resp.hdr.ctx_id = %d\n", resp.hdr.ctx_id); - kprintf("resp.hdr.padding = %d\n", resp.hdr.padding); +int virtgpu_cmd_resource_flush(struct virtgpu* gpu, uint64_t resource, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { + DEBUG_ASSERT(gpu); + DEBUG_ASSERT(gpu->driver); - for (int i = 0; i < 16; i++) { - kprintf("resp.display_info.pmodes[%d].enabled = %d\n", i, resp.display_info.pmodes[i].enabled); - kprintf("resp.display_info.pmodes[%d].flags = %d\n", i, resp.display_info.pmodes[i].flags); - kprintf("resp.display_info.pmodes[%d].r.width = %d\n", i, resp.display_info.pmodes[i].r.width); - kprintf("resp.display_info.pmodes[%d].r.height = %d\n", i, resp.display_info.pmodes[i].r.height); - kprintf("resp.display_info.pmodes[%d].r.x = %d\n", i, resp.display_info.pmodes[i].r.x); - kprintf("resp.display_info.pmodes[%d].r.y = %d\n", i, resp.display_info.pmodes[i].r.y); - } + struct virtio_gpu_resource_flush cmd = {0}; + struct virtio_gpu_response resp = {0}; - memcpy(display_info, &resp.display_info, sizeof(*display_info)); + cmd.hdr.type = VIRTIO_GPU_CMD_RESOURCE_FLUSH; + cmd.resource_id = resource; + cmd.r.x = x; + cmd.r.y = y; + cmd.r.width = width; + cmd.r.height = height; - return 0; + if (virtq_sendrecv(gpu->driver, VIRTIO_GPU_QUEUE_CONTROL, &cmd, sizeof(cmd), &resp, sizeof(resp)) < 0) + return errno = EIO, -1; + + return resp.hdr.type == VIRTIO_GPU_RESP_OK_NODATA ? 0 : -EINVAL; } diff --git a/drivers/virtio/virtio-pci/main.c b/drivers/virtio/virtio-pci/main.c index 72418163..f245bf5f 100644 --- a/drivers/virtio/virtio-pci/main.c +++ b/drivers/virtio/virtio-pci/main.c @@ -260,11 +260,21 @@ static int virtio_pci_init_common_cfg(struct virtio_driver* driver, uint8_t bar, uint16_t i = k % (vector_limit - 1); - pci_msix_map_irq(driver->device, &msix, (pci_irq_handler_t)virtio_pci_interrupt, (pci_irq_data_t)driver, i); + if(pci_msix_map_irq(driver->device, &msix, (pci_irq_handler_t)virtio_pci_interrupt, (pci_irq_data_t)driver, i) < 0) { +#if DEBUG_LEVEL_FATAL + kprintf("virtio-pci: FAIL! device %d mapping MSI-X vector %d for queue %d failed\n", driver->device, i, k); +#endif + return cfg->device_status = VIRTIO_DEVICE_STATUS_FAILED, -ENOSYS; + } pci_msix_unmask(driver->device, &msix, i); } - pci_msix_map_irq(driver->device, &msix, (pci_irq_handler_t)virtio_pci_interrupt, (pci_irq_data_t)driver, vector_limit - 1); + if(pci_msix_map_irq(driver->device, &msix, (pci_irq_handler_t)virtio_pci_interrupt, (pci_irq_data_t)driver, vector_limit - 1) < 0) { +#if DEBUG_LEVEL_FATAL + kprintf("virtio-pci: FAIL! device %d mapping MSI-X vector %d for config failed\n", driver->device, vector_limit - 1); +#endif + return cfg->device_status = VIRTIO_DEVICE_STATUS_FAILED, -ENOSYS; + } pci_msix_unmask(driver->device, &msix, vector_limit - 1); cfg->config_msix_vector = vector_limit - 1; diff --git a/drivers/virtio/virtio-queue/main.c b/drivers/virtio/virtio-queue/main.c index 8cfe720b..46831000 100644 --- a/drivers/virtio/virtio-queue/main.c +++ b/drivers/virtio/virtio-queue/main.c @@ -186,8 +186,6 @@ uint16_t virtq_alloc_descriptor(struct virtio_driver* driver, uint16_t queue) { driver->internals.queues[queue].descriptors[d].q_flags = 0; driver->internals.queues[queue].descriptors[d].q_next = 0; - kprintf("virtio-queue: device %d allocated descriptor %d on queue %d\n", driver->device, d, queue); - return d; } @@ -262,8 +260,8 @@ ssize_t virtq_sendrecv(struct virtio_driver* driver, uint16_t queue, const void* DEBUG_ASSERT(outsize); DEBUG_ASSERT(queue < driver->internals.num_queues); - DEBUG_ASSERT(size < driver->send_window_size); - DEBUG_ASSERT(outsize < driver->recv_window_size); + DEBUG_ASSERT(size <= driver->send_window_size); + DEBUG_ASSERT(outsize <= driver->recv_window_size); ssize_t inp = virtq_alloc_descriptor(driver, queue); ssize_t out = virtq_alloc_descriptor(driver, queue); @@ -302,7 +300,7 @@ ssize_t virtq_sendrecv(struct virtio_driver* driver, uint16_t queue, const void* driver->internals.queues[queue].notify->n_idx = cpu_to_le16(queue); - int e = virtq_poll(driver, queue, seen, out, &outsize); + int e = virtq_poll(driver, queue, seen, inp, &outsize); virtq_free_descriptor(driver, queue, inp); virtq_free_descriptor(driver, queue, out); @@ -328,7 +326,7 @@ ssize_t virtq_recv(struct virtio_driver* driver, uint16_t queue, void* output, s DEBUG_ASSERT(outsize); DEBUG_ASSERT(queue < driver->internals.num_queues); - DEBUG_ASSERT(outsize < driver->recv_window_size); + DEBUG_ASSERT(outsize <= driver->recv_window_size); ssize_t out = virtq_alloc_descriptor(driver, queue); @@ -384,7 +382,7 @@ ssize_t virtq_send(struct virtio_driver* driver, uint16_t queue, const void* mes DEBUG_ASSERT(size); DEBUG_ASSERT(queue < driver->internals.num_queues); - DEBUG_ASSERT(size < driver->send_window_size); + DEBUG_ASSERT(size <= driver->send_window_size); ssize_t inp = virtq_alloc_descriptor(driver, queue); diff --git a/include/aplus/ipc.h b/include/aplus/ipc.h index f7c382cc..02eca01d 100644 --- a/include/aplus/ipc.h +++ b/include/aplus/ipc.h @@ -163,7 +163,7 @@ void futex_wait(struct task*, volatile uint32_t*, uint32_t, const struct timespe #endif -int spinlock_trylock(spinlock_t*); +bool spinlock_trylock(spinlock_t*); void sem_init(semaphore_t*, uint32_t); void sem_post(semaphore_t*); diff --git a/include/aplus/vfs.h b/include/aplus/vfs.h index 26f17049..25518850 100644 --- a/include/aplus/vfs.h +++ b/include/aplus/vfs.h @@ -49,6 +49,7 @@ #include + #define VFS_MAX_FILESYSTEMS 32 #define FSID_TMPFS 0xDEAD1000 #define FSID_EXT2 0xDEAD1001 @@ -154,14 +155,24 @@ struct file { spinlock_t lock; }; +typedef struct { + int id; + const char* name; + bool nodev; + + int (*mount)(inode_t*, inode_t*, int, const char*); + int (*umount)(inode_t*); + +} fstable_t; __BEGIN_DECLS void vfs_init(void); -//* os/kernel/fs/vfs.c +//* kernel/fs/vfs.c +extern fstable_t* fs_table; int vfs_mount(inode_t* dev, inode_t* dir, const char* fs, int flags, const char* args); inode_t* vfs_open(inode_t*, int); diff --git a/include/dev/virtio/virtio-gpu.h b/include/dev/virtio/virtio-gpu.h index defdef8c..0a504130 100644 --- a/include/dev/virtio/virtio-gpu.h +++ b/include/dev/virtio/virtio-gpu.h @@ -230,6 +230,7 @@ int virtgpu_cmd_resource_attach_backing(struct virtgpu*, uint64_t, uint64_t, siz int virtgpu_cmd_set_scanout(struct virtgpu*, uint32_t, uint64_t, uint32_t, uint32_t, uint32_t, uint32_t); int virtgpu_cmd_transfer_to_host_2d(struct virtgpu*, uint64_t, uint64_t, uint32_t, uint32_t, uint32_t, uint32_t); int virtgpu_cmd_get_display_info(struct virtgpu*, struct virtio_gpu_resp_display_info*); +int virtgpu_cmd_resource_flush(struct virtgpu*, uint64_t, uint32_t, uint32_t, uint32_t, uint32_t); __END_DECLS diff --git a/kernel/fs/fstable.c.in b/kernel/fs/fstable.c.in index c54e7c96..7b5310ce 100644 --- a/kernel/fs/fstable.c.in +++ b/kernel/fs/fstable.c.in @@ -1,4 +1,4 @@ -#define FSENTRY(a, b, c) { \ +#define FSENTRY(a, b, c, d) { \ extern int c##_mount(inode_t*, inode_t*, int, const char*); \ extern int c##_umount(inode_t*); \ \ @@ -6,6 +6,7 @@ \ fs_table[i].id = a; \ fs_table[i].name = b; \ + fs_table[i].nodev = d; \ fs_table[i].mount = c##_mount; \ fs_table[i].umount = c##_umount; \ fs_table[i + 1].id = 0; \ @@ -13,9 +14,9 @@ } -FSENTRY (1 , "bind" , bindfs ); -FSENTRY (FSID_TMPFS , "tmpfs" , tmpfs ); -FSENTRY (FSID_EXT2 , "ext2" , ext2 ); -FSENTRY (FSID_ISO9660 , "iso9660" , iso9660 ); -FSENTRY (FSID_PROCFS , "proc" , procfs ); +FSENTRY (1 , "bind" , bindfs , false ); +FSENTRY (FSID_TMPFS , "tmpfs" , tmpfs , true ); +FSENTRY (FSID_EXT2 , "ext2" , ext2 , false ); +FSENTRY (FSID_ISO9660 , "iso9660" , iso9660 , false ); +FSENTRY (FSID_PROCFS , "proc" , procfs , true ); diff --git a/kernel/fs/procfs/procfs.h b/kernel/fs/procfs/procfs.h index f7995138..8af6724c 100644 --- a/kernel/fs/procfs/procfs.h +++ b/kernel/fs/procfs/procfs.h @@ -41,6 +41,7 @@ typedef struct procfs_service { +int procfs_root_getattr(inode_t* inode, struct stat* st); inode_t* procfs_root_finddir(inode_t* inode, const char* name); ssize_t procfs_root_readdir(inode_t* inode, struct dirent* e, off_t pos, size_t count); @@ -48,6 +49,8 @@ ssize_t procfs_root_readdir(inode_t* inode, struct dirent* e, off_t pos, size_t inode_t* procfs_service_cmdline_inode(inode_t* parent, pid_t pid); inode_t* procfs_service_meminfo_inode(inode_t* parent); inode_t* procfs_service_uptime_inode(inode_t* parent); +inode_t* procfs_service_version_inode(inode_t* parent); +inode_t* procfs_service_filesystems_inode(inode_t* parent); inode_t* procfs_service_inode(inode_t* parent, char* name, mode_t mode, int (*fetch)(inode_t*, char** buf, size_t*, void*), void* arg); diff --git a/kernel/fs/procfs/procfs_mount.c b/kernel/fs/procfs/procfs_mount.c index 951c9e92..4623a479 100644 --- a/kernel/fs/procfs/procfs_mount.c +++ b/kernel/fs/procfs/procfs_mount.c @@ -86,13 +86,12 @@ int procfs_mount(inode_t* dev, inode_t* dir, int flags, const char* args) { dir->sb->st.f_namemax = CONFIG_MAXNAMLEN; - // dir->sb->ops.getattr = procfs_getattr; + dir->sb->ops.getattr = procfs_root_getattr; dir->sb->ops.finddir = procfs_root_finddir; dir->sb->ops.readdir = procfs_root_readdir; dir->sb->flags |= INODE_FLAGS_DCACHE_DISABLED; - procfs_service_pid_init(dir); return 0; diff --git a/kernel/fs/procfs/procfs_root_finddir.c b/kernel/fs/procfs/procfs_root_finddir.c index 8f05ba00..4a606829 100644 --- a/kernel/fs/procfs/procfs_root_finddir.c +++ b/kernel/fs/procfs/procfs_root_finddir.c @@ -70,11 +70,11 @@ inode_t* procfs_root_finddir(inode_t* inode, const char* name) { if (strcmp(name, "uptime") == 0) return procfs_service_uptime_inode(inode); - // if(strcmp(name, "version") == 0) - // return procfs_version_inode(); + if(strcmp(name, "version") == 0) + return procfs_service_version_inode(inode); - // if(strcmp(name, "filesystems") == 0) - // return procfs_filesystems_inode(); + if(strcmp(name, "filesystems") == 0) + return procfs_service_filesystems_inode(inode); if (strcmp(name, "cmdline") == 0) return procfs_service_cmdline_inode(inode, -1); diff --git a/kernel/fs/procfs/procfs_root_getattr.c b/kernel/fs/procfs/procfs_root_getattr.c new file mode 100644 index 00000000..b3238e5d --- /dev/null +++ b/kernel/fs/procfs/procfs_root_getattr.c @@ -0,0 +1,66 @@ +/* + * Author: + * Antonino Natale + * + * Copyright (c) 2013-2019 Antonino Natale + * + * + * This file is part of aplus. + * + * aplus is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * aplus is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with aplus. If not, see . + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "procfs.h" + + +int procfs_root_getattr(inode_t* inode, struct stat* st) { + + DEBUG_ASSERT(inode); + DEBUG_ASSERT(inode->sb); + DEBUG_ASSERT(inode->sb->fsid == FSID_PROCFS); + DEBUG_ASSERT(st); + + memset(st, 0, sizeof(struct stat)); + + st->st_ino = inode->ino; + st->st_mode = S_IFDIR | 0755; + st->st_dev = makedev(0, 34); + st->st_nlink = 2; + st->st_uid = 0; + st->st_gid = 0; + st->st_rdev = 0; + st->st_size = 0; + st->st_blksize = 0; + st->st_blocks = 0; + st->st_atime = arch_timer_gettime(); + st->st_mtime = arch_timer_gettime(); + st->st_ctime = arch_timer_gettime(); + + return 0; +} diff --git a/kernel/fs/procfs/procfs_root_readdir.c b/kernel/fs/procfs/procfs_root_readdir.c index cb55b1b5..e34a039f 100644 --- a/kernel/fs/procfs/procfs_root_readdir.c +++ b/kernel/fs/procfs/procfs_root_readdir.c @@ -50,24 +50,21 @@ ssize_t procfs_root_readdir(inode_t* inode, struct dirent* e, off_t pos, size_t return 0; - int i = 0; + size_t i = 0; cpu_foreach(cpu) { - task_t* task = cpu->sched_queue; - for (task_t* q = cpu->sched_queue; q; q = q->next) { if (pos-- > 0) continue; - - e[i].d_ino = task->tid; - e[i].d_off = pos; + e[i].d_ino = q->tid; + e[i].d_off = i; e[i].d_reclen = sizeof(struct dirent); e[i].d_type = DT_DIR; - snprintf(e->d_name, sizeof(e->d_name), "%d", task->tid); + snprintf(e[i].d_name, sizeof(e[i].d_name), "%d", q->tid); if (++i == count) return i; @@ -82,7 +79,7 @@ ssize_t procfs_root_readdir(inode_t* inode, struct dirent* e, off_t pos, size_t break; \ \ e[i].d_ino = ino; \ - e[i].d_off = pos; \ + e[i].d_off = i; \ e[i].d_reclen = sizeof(struct dirent); \ e[i].d_type = type; \ \ @@ -97,12 +94,12 @@ ssize_t procfs_root_readdir(inode_t* inode, struct dirent* e, off_t pos, size_t __readdir(1, DT_DIR, "."); __readdir(2, DT_DIR, ".."); __readdir(3, DT_DIR, "self"); - __readdir(4, DT_REG, "cpuinfo"); + // __readdir(4, DT_REG, "cpuinfo"); __readdir(4, DT_REG, "meminfo"); __readdir(5, DT_REG, "uptime"); __readdir(6, DT_REG, "version"); - __readdir(7, DT_REG, "modules"); - __readdir(8, DT_REG, "mounts"); + // __readdir(7, DT_REG, "modules"); + // __readdir(8, DT_REG, "mounts"); __readdir(9, DT_REG, "filesystems"); __readdir(10, DT_REG, "cmdline"); diff --git a/kernel/fs/procfs/procfs_service_cmdline.c b/kernel/fs/procfs/procfs_service_cmdline.c index 13e8081f..32409c50 100644 --- a/kernel/fs/procfs/procfs_service_cmdline.c +++ b/kernel/fs/procfs/procfs_service_cmdline.c @@ -42,7 +42,6 @@ static int procfs_service_cmdline_fetch(inode_t* inode, char** buf, size_t* size DEBUG_ASSERT(inode); DEBUG_ASSERT(inode->sb); DEBUG_ASSERT(inode->sb->fsid == FSID_PROCFS); - DEBUG_ASSERT(inode->sb->root == inode); DEBUG_ASSERT(buf); DEBUG_ASSERT(size); diff --git a/kernel/fs/procfs/procfs_service_filesystems.c b/kernel/fs/procfs/procfs_service_filesystems.c new file mode 100644 index 00000000..e57cd4e3 --- /dev/null +++ b/kernel/fs/procfs/procfs_service_filesystems.c @@ -0,0 +1,74 @@ +/* + * Author: + * Antonino Natale + * + * Copyright (c) 2013-2019 Antonino Natale + * + * + * This file is part of aplus. + * + * aplus is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * aplus is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with aplus. If not, see . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "procfs.h" + + +static int procfs_service_filesystems_fetch(inode_t* inode, char** buf, size_t* size, void* arg) { + + (void)arg; + + DEBUG_ASSERT(inode); + DEBUG_ASSERT(inode->sb); + DEBUG_ASSERT(inode->sb->fsid == FSID_PROCFS); + + DEBUG_ASSERT(buf); + DEBUG_ASSERT(size); + + static char buffer[BUFSIZ] = {0}; + + for(size_t i = 0; i < VFS_MAX_FILESYSTEMS; i++) { + if (fs_table[i].id == 0) + break; + + *size += snprintf(buffer + *size, sizeof(buffer) - *size, "%s %s\n", fs_table[i].nodev ? "nodev" : " ", fs_table[i].name); + } + + *buf = buffer; + + return 0; +} + +inode_t* procfs_service_filesystems_inode(inode_t* parent) { + + static inode_t* inode = NULL; + + if (inode == NULL) { + inode = procfs_service_inode(parent, "filesystems", S_IFREG | 0666, procfs_service_filesystems_fetch, NULL); + } + + return inode; +} diff --git a/kernel/fs/procfs/procfs_service_meminfo.c b/kernel/fs/procfs/procfs_service_meminfo.c index 5259e163..fdf1f06c 100644 --- a/kernel/fs/procfs/procfs_service_meminfo.c +++ b/kernel/fs/procfs/procfs_service_meminfo.c @@ -44,7 +44,6 @@ static int procfs_service_meminfo_fetch(inode_t* inode, char** buf, size_t* size DEBUG_ASSERT(inode); DEBUG_ASSERT(inode->sb); DEBUG_ASSERT(inode->sb->fsid == FSID_PROCFS); - DEBUG_ASSERT(inode->sb->root == inode); DEBUG_ASSERT(buf); DEBUG_ASSERT(size); @@ -53,33 +52,56 @@ static int procfs_service_meminfo_fetch(inode_t* inode, char** buf, size_t* size *size = snprintf(buffer, sizeof(buffer), - "MemTotal: %lu kB\n" - "MemFree: %lu kB\n" - "MemAvailable: %lu kB\n" - "Buffers: %lu kB\n" - "Cached: %lu kB\n" - "SwapCached: %lu kB\n" - "Active: %lu kB\n" - "Inactive: %lu kB\n" - "Active(anon) %lu kB\n" - "Inactive(anon) %lu kB\n" - "Active(file) %lu kB\n" - "Inactive(file) %lu kB\n" - "SwapTotal: %lu kB\n" - "SwapFree: %lu kB\n" - "Dirty: %lu kB\n" - "Writeback: %lu kB\n" - "AnonPages: %lu kB\n" - "Mapped: %lu kB\n" - "Shmem: %lu kB\n" - "Slab: %lu kB\n" - "SReclaimable: %lu kB\n" - "SUnreclaim: %lu kB\n" - "KernelStack: %lu kB\n" - "PageTables: %lu kB\n", - - (pmm_get_total_memory()) >> 10, (pmm_get_total_memory() - pmm_get_used_memory()) >> 10, (pmm_get_total_memory() - pmm_get_used_memory()) >> 10, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, - kheap_get_used_memory() >> 10, 0L, 0L, 0L, 0L); + "MemTotal: %lu kB\n" + "MemFree: %lu kB\n" + "MemAvailable: %lu kB\n" + "Buffers: %lu kB\n" + "Cached: %lu kB\n" + "SwapCached: %lu kB\n" + "Active: %lu kB\n" + "Inactive: %lu kB\n" + "Active(anon) %lu kB\n" + "Inactive(anon) %lu kB\n" + "Active(file) %lu kB\n" + "Inactive(file) %lu kB\n" + "SwapTotal: %lu kB\n" + "SwapFree: %lu kB\n" + "Dirty: %lu kB\n" + "Writeback: %lu kB\n" + "AnonPages: %lu kB\n" + "Mapped: %lu kB\n" + "Shmem: %lu kB\n" + "Slab: %lu kB\n" + "SReclaimable: %lu kB\n" + "SUnreclaim: %lu kB\n" + "KernelStack: %lu kB\n" + "PageTables: %lu kB\n", + + (pmm_get_total_memory()) >> 10, + (pmm_get_total_memory() - pmm_get_used_memory()) >> 10, + (pmm_get_total_memory() - pmm_get_used_memory()) >> 10, + 0L, + 0L, + 0L, + 0L, + 0L, + 0L, + 0L, + 0L, + 0L, + 0L, + 0L, + 0L, + 0L, + 0L, + 0L, + 0L, + kheap_get_used_memory() >> 10, + 0L, + 0L, + 0L, + 0L + ); *buf = buffer; diff --git a/kernel/fs/procfs/procfs_service_pid.c b/kernel/fs/procfs/procfs_service_pid.c index cf86eda1..a41061ff 100644 --- a/kernel/fs/procfs/procfs_service_pid.c +++ b/kernel/fs/procfs/procfs_service_pid.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -43,11 +44,73 @@ static cache_t cache = {0}; static inode_t* procfs_service_pid_finddir(inode_t* inode, const char* name) { - return NULL; + + DEBUG_ASSERT(inode); + DEBUG_ASSERT(inode->sb); + DEBUG_ASSERT(inode->sb->fsid == FSID_PROCFS); + DEBUG_ASSERT(name); + + if (isdigit(inode->name[0])) { + + long pid = atol(inode->name); + + if (pid > 0) { + return procfs_service_pid_inode(inode, pid); + } else { + return errno = ENOENT, NULL; + } + + } else if(strcmp(inode->name, "self") == 0) { + return procfs_service_pid_inode(inode, current_task->tid); + } else { + return errno = ENOENT, NULL; + } + } static ssize_t procfs_service_pid_readdir(inode_t* inode, struct dirent* e, off_t pos, size_t count) { - return 0; + + DEBUG_ASSERT(inode); + DEBUG_ASSERT(inode->sb); + DEBUG_ASSERT(inode->sb->fsid == FSID_PROCFS); + + DEBUG_ASSERT(e); + + if (unlikely(count == 0)) + return 0; + + + size_t i = 0; +#define __readdir(ino, type, name) \ + do { \ + \ + if (pos-- > 0) \ + break; \ + \ + e[i].d_ino = ino; \ + e[i].d_off = i; \ + e[i].d_reclen = sizeof(struct dirent); \ + e[i].d_type = type; \ + \ + strncpy(e[i].d_name, name, sizeof(e[i].d_name)); \ + \ + if (++i == count) \ + return i; \ + \ + } while (0) + + + __readdir(1, DT_DIR, "."); + __readdir(2, DT_DIR, ".."); + __readdir(3, DT_REG, "cmdline"); + // __readdir(4, DT_REG, "environ"); + // __readdir(5, DT_REG, "limits"); + // __readdir(6, DT_REG, "status"); + // __readdir(7, DT_REG, "io"); + // __readdir(8, DT_LNK, "exe"); + // __readdir(9, DT_LNK, "cwd"); + + return i; } static int procfs_service_pid_self_fetch(inode_t* inode, char** buf, size_t* size, void* arg) { @@ -55,7 +118,6 @@ static int procfs_service_pid_self_fetch(inode_t* inode, char** buf, size_t* siz DEBUG_ASSERT(inode); DEBUG_ASSERT(inode->sb); DEBUG_ASSERT(inode->sb->fsid == FSID_PROCFS); - DEBUG_ASSERT(inode->sb->root == inode); DEBUG_ASSERT(buf); DEBUG_ASSERT(size); diff --git a/kernel/fs/procfs/procfs_service_uptime.c b/kernel/fs/procfs/procfs_service_uptime.c index b210973d..75fe750b 100644 --- a/kernel/fs/procfs/procfs_service_uptime.c +++ b/kernel/fs/procfs/procfs_service_uptime.c @@ -44,7 +44,6 @@ static int procfs_service_uptime_fetch(inode_t* inode, char** buf, size_t* size, DEBUG_ASSERT(inode); DEBUG_ASSERT(inode->sb); DEBUG_ASSERT(inode->sb->fsid == FSID_PROCFS); - DEBUG_ASSERT(inode->sb->root == inode); DEBUG_ASSERT(buf); DEBUG_ASSERT(size); diff --git a/kernel/fs/procfs/procfs_service_version.c b/kernel/fs/procfs/procfs_service_version.c new file mode 100644 index 00000000..bb47ef7d --- /dev/null +++ b/kernel/fs/procfs/procfs_service_version.c @@ -0,0 +1,77 @@ +/* + * Author: + * Antonino Natale + * + * Copyright (c) 2013-2019 Antonino Natale + * + * + * This file is part of aplus. + * + * aplus is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * aplus is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with aplus. If not, see . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "procfs.h" + + +static int procfs_service_version_fetch(inode_t* inode, char** buf, size_t* size, void* arg) { + + (void)arg; + + DEBUG_ASSERT(inode); + DEBUG_ASSERT(inode->sb); + DEBUG_ASSERT(inode->sb->fsid == FSID_PROCFS); + + DEBUG_ASSERT(buf); + DEBUG_ASSERT(size); + + static char buffer[64] = {0}; + + + *size = snprintf(buffer, sizeof(buffer), "%s version %s-%s (%s %s) %s\n", + CONFIG_SYSTEM_NAME, + CONFIG_SYSTEM_VERSION, + CONFIG_SYSTEM_CODENAME, + CONFIG_COMPILER_HOST, + __VERSION__, + __TIMESTAMP__ + ); + + *buf = buffer; + + return 0; +} + +inode_t* procfs_service_version_inode(inode_t* parent) { + + static inode_t* inode = NULL; + + if (inode == NULL) { + inode = procfs_service_inode(parent, "version", S_IFREG | 0666, procfs_service_version_fetch, NULL); + } + + return inode; +} diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c index b5482a4b..b3cc050e 100644 --- a/kernel/fs/vfs.c +++ b/kernel/fs/vfs.c @@ -36,16 +36,8 @@ #include -static struct { - - int id; - const char* name; - - int (*mount)(inode_t*, inode_t*, int, const char*); - int (*umount)(inode_t*); - -} fs_table[32]; - +fstable_t __fs_table[VFS_MAX_FILESYSTEMS] = {0}; +fstable_t* fs_table = &__fs_table[0]; void vfs_init(void) { diff --git a/kernel/ipc/spinlock.c b/kernel/ipc/spinlock.c index ec66f0be..350f1509 100644 --- a/kernel/ipc/spinlock.c +++ b/kernel/ipc/spinlock.c @@ -98,7 +98,7 @@ void spinlock_lock(spinlock_t* lock) { volatile uint64_t own; - if ((own = atomic_load_explicit(&lock->owner, memory_order_consume)) == spinlock_get_new_owner(lock)) { + if ((own = atomic_load_explicit(&lock->owner, memory_order_acquire)) == spinlock_get_new_owner(lock)) { if (lock->flags & SPINLOCK_FLAGS_RECURSIVE) { @@ -122,6 +122,8 @@ void spinlock_lock(spinlock_t* lock) { // // uint64_t deadlock_detector = 0ULL; // // #endif + uint64_t irqflags = arch_intr_disable(); + while (atomic_flag_test_and_set_explicit(&lock->value, memory_order_acquire)) { #if defined(__i386__) || defined(__x86_64__) @@ -138,18 +140,18 @@ void spinlock_lock(spinlock_t* lock) { } -#if DEBUG_LEVEL_TRACE - if (unlikely(lock->owner != -1ULL)) { +#if DEBUG_LEVEL_TRACE kpanicf("ipc: FAIL! %s(): Lock already owned at %s:%d in %s(%p): owner(%ld) flags(%X) current_owner(%ld)\n", __func__, FILE, LINE, FUNC, lock, lock->owner, lock->flags, spinlock_get_new_owner(lock)); - } - +#else + kpanicf("ipc: FAIL! Lock already owned: owner(%ld) flags(%X)\n", lock->owner, lock->flags); #endif + } lock->owner = spinlock_get_new_owner(lock); - lock->irqsave = arch_intr_disable(); + lock->irqsave = irqflags; - atomic_store_explicit(&lock->refcount, 1, memory_order_relaxed); + atomic_store_explicit(&lock->refcount, 1, memory_order_release); } } @@ -158,20 +160,21 @@ void spinlock_lock(spinlock_t* lock) { * @brief Try to lock a Spinlock. * @deprecated */ -int spinlock_trylock(spinlock_t* lock) { +bool spinlock_trylock(spinlock_t* lock) { DEBUG_ASSERT(lock); - int e; - if ((e = atomic_flag_test_and_set_explicit(&lock->value, memory_order_acquire)) == 0) { + if (atomic_flag_test_and_set_explicit(&lock->value, memory_order_acquire) == 0) { lock->owner = spinlock_get_new_owner(lock); lock->irqsave = arch_intr_disable(); - atomic_store_explicit(&lock->refcount, 1, memory_order_relaxed); + atomic_store_explicit(&lock->refcount, 1, memory_order_release); + + return true; + } else { + return false; } - - return e; } @@ -188,7 +191,7 @@ void spinlock_unlock(spinlock_t* lock) { DEBUG_ASSERT(lock); - if (atomic_load_explicit(&lock->owner, memory_order_consume) != spinlock_get_new_owner(lock)) { + if (atomic_load_explicit(&lock->owner, memory_order_acquire) != spinlock_get_new_owner(lock)) { #if DEBUG_LEVEL_TRACE kpanicf("ipc: PANIC! EPERM! spinlock(%p) at %s:%d %s() not owned, owner(%ld) flags(%X) current_owner(%ld)\n", lock, FILE, LINE, FUNC, lock->owner, lock->flags, spinlock_get_new_owner(lock)); #else @@ -208,8 +211,7 @@ void spinlock_unlock(spinlock_t* lock) { lock->refcount = 0; lock->irqsave = 0; - atomic_flag_clear(&lock->value); - + atomic_flag_clear_explicit(&lock->value, memory_order_release); arch_intr_enable(e); } diff --git a/kernel/kmain.c b/kernel/kmain.c index 7ee94450..e9986883 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -92,12 +92,11 @@ void kmain(void) { #endif +#if DEBUG_LEVEL_INFO kprintf("core: %s %s-%s (%s)\n", CONFIG_SYSTEM_NAME, CONFIG_SYSTEM_VERSION, CONFIG_SYSTEM_CODENAME, CONFIG_COMPILER_HOST); - kprintf("core: built with gcc %s (%s)\n", __VERSION__, __TIMESTAMP__); - kprintf("core: boot completed in %d ms, %d KiB of memory used\n", arch_timer_generic_getms(), pmm_get_used_memory() >> 10); - +#endif // Execute init diff --git a/kernel/network/network.c b/kernel/network/network.c index c687c6c8..7e685ebc 100644 --- a/kernel/network/network.c +++ b/kernel/network/network.c @@ -100,7 +100,9 @@ void network_init() { tcpip_init(&tcpip_init_done, &dns); - sem_wait(&tcpip_done); + sem_wait(&tcpip_done); +#if DEBUG_LEVEL_INFO kprintf("network: up!\n"); +#endif } diff --git a/kernel/sched.c b/kernel/sched.c index 22a63e20..80bd0d7a 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -316,25 +316,22 @@ void schedule(int resched) { current_task->rusage.ru_nvcsw++; } + scoped_lock(¤t_cpu->sched_lock) { + if (likely(current_task->status == TASK_STATUS_RUNNING)) { + current_task->status = TASK_STATUS_READY; + } - if (likely(current_task->status == TASK_STATUS_RUNNING)) { - current_task->status = TASK_STATUS_READY; - } - - if (likely((current_task->flags & TASK_FLAGS_NO_FRAME) == 0)) { - __sched_next(); - } - - - current_task->status = TASK_STATUS_RUNNING; + if (likely((current_task->flags & TASK_FLAGS_NO_FRAME) == 0)) { + __sched_next(); + } + current_task->status = TASK_STATUS_RUNNING; - scoped_lock(¤t_cpu->sched_lock) { arch_task_switch(prev_task, current_task); - } + } do_signals(); } diff --git a/kernel/smp.c b/kernel/smp.c index 4bf7bc65..918fe451 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -90,6 +90,8 @@ void smp_init() { arch_cpu_startup(i); +#if DEBUG_LEVEL_INFO kprintf("smp: cpu #%zd is online\n", i); +#endif } } diff --git a/kernel/syscalls/001_write.c b/kernel/syscalls/001_write.c index 8dac8f86..becd008d 100644 --- a/kernel/syscalls/001_write.c +++ b/kernel/syscalls/001_write.c @@ -74,11 +74,10 @@ SYSCALL( return -EFAULT; +#if defined(CONFIG_HAVE_NETWORK) ssize_t e = 0; -#if defined(CONFIG_HAVE_NETWORK) - if (unlikely(NETWORK_IS_SOCKFD(fd))) { uio_lock(buf, size); diff --git a/kernel/syscalls/060_exit.c b/kernel/syscalls/060_exit.c index 67f1940d..f19bef0e 100644 --- a/kernel/syscalls/060_exit.c +++ b/kernel/syscalls/060_exit.c @@ -87,7 +87,9 @@ SYSCALL( if (current_task->status == TASK_STATUS_STOP && !(q->wait_options & WUNTRACED)) continue; - +#if DEBUG_LEVEL_TRACE + kprintf("exit: waking up waiter task(%d) for task(%d)\n", q->tid, current_task->tid); +#endif thread_wake(q); } diff --git a/kernel/syscalls/257_openat.c b/kernel/syscalls/257_openat.c index e37de3da..75345503 100644 --- a/kernel/syscalls/257_openat.c +++ b/kernel/syscalls/257_openat.c @@ -96,7 +96,7 @@ SYSCALL( uio_strncpy_u2s(__safe_filename, filename, CONFIG_PATH_MAX); #if DEBUG_LEVEL_TRACE - kprintf("openat(%d, \"%s\", %d, %d)\n", dfd, __safe_filename, flags, mode); + kprintf("syscall: openat(%d, \"%s\", %d, %d)\n", dfd, __safe_filename, flags, mode); #endif diff --git a/libk/utils/cache.c b/libk/utils/cache.c index fef83b4c..a753ea4a 100644 --- a/libk/utils/cache.c +++ b/libk/utils/cache.c @@ -76,7 +76,7 @@ void cache_init(cache_t* cache, cache_ops_t* ops, size_t capacity, void* userdat hashmap_init(&cache->map, __cache_hash_default, __cache_key_cmp); - spinlock_init(&cache->lock); + spinlock_init_with_flags(&cache->lock, SPINLOCK_FLAGS_RECURSIVE); } @@ -129,7 +129,6 @@ void cache_commit_all(cache_t* cache) { __returns_nonnull cache_value_t __cache_get(cache_t* cache, cache_key_t key) { DEBUG_ASSERT(cache); - DEBUG_ASSERT(key); cache_value_t value = NULL; @@ -188,8 +187,6 @@ __returns_nonnull cache_value_t __cache_get(cache_t* cache, cache_key_t key) { void __cache_commit(cache_t* cache, cache_key_t key) { DEBUG_ASSERT(cache); - DEBUG_ASSERT(key); - cache_value_t value = NULL; @@ -212,8 +209,6 @@ void __cache_commit(cache_t* cache, cache_key_t key) { void __cache_remove(cache_t* cache, cache_key_t key) { DEBUG_ASSERT(cache); - DEBUG_ASSERT(key); - cache_value_t value = NULL;