console.c 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048
  1. /*
  2. * QEMU graphical console
  3. *
  4. * Copyright (c) 2004 Fabrice Bellard
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include "qemu-common.h"
  25. #include "ui/console.h"
  26. #include "hw/qdev-core.h"
  27. #include "qemu/timer.h"
  28. #include "qmp-commands.h"
  29. #include "sysemu/char.h"
  30. #include "trace.h"
  31. #include "exec/memory.h"
  32. #define DEFAULT_BACKSCROLL 512
  33. #define CONSOLE_CURSOR_PERIOD 500
  34. typedef struct TextAttributes {
  35. uint8_t fgcol:4;
  36. uint8_t bgcol:4;
  37. uint8_t bold:1;
  38. uint8_t uline:1;
  39. uint8_t blink:1;
  40. uint8_t invers:1;
  41. uint8_t unvisible:1;
  42. } TextAttributes;
  43. typedef struct TextCell {
  44. uint8_t ch;
  45. TextAttributes t_attrib;
  46. } TextCell;
  47. #define MAX_ESC_PARAMS 3
  48. enum TTYState {
  49. TTY_STATE_NORM,
  50. TTY_STATE_ESC,
  51. TTY_STATE_CSI,
  52. };
  53. typedef struct QEMUFIFO {
  54. uint8_t *buf;
  55. int buf_size;
  56. int count, wptr, rptr;
  57. } QEMUFIFO;
  58. static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
  59. {
  60. int l, len;
  61. l = f->buf_size - f->count;
  62. if (len1 > l)
  63. len1 = l;
  64. len = len1;
  65. while (len > 0) {
  66. l = f->buf_size - f->wptr;
  67. if (l > len)
  68. l = len;
  69. memcpy(f->buf + f->wptr, buf, l);
  70. f->wptr += l;
  71. if (f->wptr >= f->buf_size)
  72. f->wptr = 0;
  73. buf += l;
  74. len -= l;
  75. }
  76. f->count += len1;
  77. return len1;
  78. }
  79. static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
  80. {
  81. int l, len;
  82. if (len1 > f->count)
  83. len1 = f->count;
  84. len = len1;
  85. while (len > 0) {
  86. l = f->buf_size - f->rptr;
  87. if (l > len)
  88. l = len;
  89. memcpy(buf, f->buf + f->rptr, l);
  90. f->rptr += l;
  91. if (f->rptr >= f->buf_size)
  92. f->rptr = 0;
  93. buf += l;
  94. len -= l;
  95. }
  96. f->count -= len1;
  97. return len1;
  98. }
  99. typedef enum {
  100. GRAPHIC_CONSOLE,
  101. TEXT_CONSOLE,
  102. TEXT_CONSOLE_FIXED_SIZE
  103. } console_type_t;
  104. struct QemuConsole {
  105. Object parent;
  106. int index;
  107. console_type_t console_type;
  108. DisplayState *ds;
  109. DisplaySurface *surface;
  110. int dcls;
  111. /* Graphic console state. */
  112. Object *device;
  113. uint32_t head;
  114. QemuUIInfo ui_info;
  115. const GraphicHwOps *hw_ops;
  116. void *hw;
  117. /* Text console state */
  118. int width;
  119. int height;
  120. int total_height;
  121. int backscroll_height;
  122. int x, y;
  123. int x_saved, y_saved;
  124. int y_displayed;
  125. int y_base;
  126. TextAttributes t_attrib_default; /* default text attributes */
  127. TextAttributes t_attrib; /* currently active text attributes */
  128. TextCell *cells;
  129. int text_x[2], text_y[2], cursor_invalidate;
  130. int echo;
  131. int update_x0;
  132. int update_y0;
  133. int update_x1;
  134. int update_y1;
  135. enum TTYState state;
  136. int esc_params[MAX_ESC_PARAMS];
  137. int nb_esc_params;
  138. CharDriverState *chr;
  139. /* fifo for key pressed */
  140. QEMUFIFO out_fifo;
  141. uint8_t out_fifo_buf[16];
  142. QEMUTimer *kbd_timer;
  143. };
  144. struct DisplayState {
  145. QEMUTimer *gui_timer;
  146. uint64_t last_update;
  147. uint64_t update_interval;
  148. bool refreshing;
  149. bool have_gfx;
  150. bool have_text;
  151. QLIST_HEAD(, DisplayChangeListener) listeners;
  152. };
  153. static DisplayState *display_state;
  154. static QemuConsole *active_console;
  155. static QemuConsole **consoles;
  156. static int nb_consoles = 0;
  157. static bool cursor_visible_phase;
  158. static QEMUTimer *cursor_timer;
  159. static void text_console_do_init(CharDriverState *chr, DisplayState *ds);
  160. static void dpy_refresh(DisplayState *s);
  161. static DisplayState *get_alloc_displaystate(void);
  162. static void text_console_update_cursor_timer(void);
  163. static void text_console_update_cursor(void *opaque);
  164. static void gui_update(void *opaque)
  165. {
  166. uint64_t interval = GUI_REFRESH_INTERVAL_IDLE;
  167. uint64_t dcl_interval;
  168. DisplayState *ds = opaque;
  169. DisplayChangeListener *dcl;
  170. int i;
  171. ds->refreshing = true;
  172. dpy_refresh(ds);
  173. ds->refreshing = false;
  174. QLIST_FOREACH(dcl, &ds->listeners, next) {
  175. dcl_interval = dcl->update_interval ?
  176. dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT;
  177. if (interval > dcl_interval) {
  178. interval = dcl_interval;
  179. }
  180. }
  181. if (ds->update_interval != interval) {
  182. ds->update_interval = interval;
  183. for (i = 0; i < nb_consoles; i++) {
  184. if (consoles[i]->hw_ops->update_interval) {
  185. consoles[i]->hw_ops->update_interval(consoles[i]->hw, interval);
  186. }
  187. }
  188. trace_console_refresh(interval);
  189. }
  190. ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
  191. timer_mod(ds->gui_timer, ds->last_update + interval);
  192. }
  193. static void gui_setup_refresh(DisplayState *ds)
  194. {
  195. DisplayChangeListener *dcl;
  196. bool need_timer = false;
  197. bool have_gfx = false;
  198. bool have_text = false;
  199. QLIST_FOREACH(dcl, &ds->listeners, next) {
  200. if (dcl->ops->dpy_refresh != NULL) {
  201. need_timer = true;
  202. }
  203. if (dcl->ops->dpy_gfx_update != NULL) {
  204. have_gfx = true;
  205. }
  206. if (dcl->ops->dpy_text_update != NULL) {
  207. have_text = true;
  208. }
  209. }
  210. if (need_timer && ds->gui_timer == NULL) {
  211. ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds);
  212. timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
  213. }
  214. if (!need_timer && ds->gui_timer != NULL) {
  215. timer_del(ds->gui_timer);
  216. timer_free(ds->gui_timer);
  217. ds->gui_timer = NULL;
  218. }
  219. ds->have_gfx = have_gfx;
  220. ds->have_text = have_text;
  221. }
  222. void graphic_hw_update(QemuConsole *con)
  223. {
  224. if (!con) {
  225. con = active_console;
  226. }
  227. if (con && con->hw_ops->gfx_update) {
  228. con->hw_ops->gfx_update(con->hw);
  229. }
  230. }
  231. void graphic_hw_invalidate(QemuConsole *con)
  232. {
  233. if (!con) {
  234. con = active_console;
  235. }
  236. if (con && con->hw_ops->invalidate) {
  237. con->hw_ops->invalidate(con->hw);
  238. }
  239. }
  240. static void ppm_save(const char *filename, struct DisplaySurface *ds,
  241. Error **errp)
  242. {
  243. int width = pixman_image_get_width(ds->image);
  244. int height = pixman_image_get_height(ds->image);
  245. int fd;
  246. FILE *f;
  247. int y;
  248. int ret;
  249. pixman_image_t *linebuf;
  250. trace_ppm_save(filename, ds);
  251. fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
  252. if (fd == -1) {
  253. error_setg(errp, "failed to open file '%s': %s", filename,
  254. strerror(errno));
  255. return;
  256. }
  257. f = fdopen(fd, "wb");
  258. ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255);
  259. if (ret < 0) {
  260. linebuf = NULL;
  261. goto write_err;
  262. }
  263. linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
  264. for (y = 0; y < height; y++) {
  265. qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y);
  266. clearerr(f);
  267. ret = fwrite(pixman_image_get_data(linebuf), 1,
  268. pixman_image_get_stride(linebuf), f);
  269. (void)ret;
  270. if (ferror(f)) {
  271. goto write_err;
  272. }
  273. }
  274. out:
  275. qemu_pixman_image_unref(linebuf);
  276. fclose(f);
  277. return;
  278. write_err:
  279. error_setg(errp, "failed to write to file '%s': %s", filename,
  280. strerror(errno));
  281. unlink(filename);
  282. goto out;
  283. }
  284. void qmp_screendump(const char *filename, Error **errp)
  285. {
  286. QemuConsole *con = qemu_console_lookup_by_index(0);
  287. DisplaySurface *surface;
  288. if (con == NULL) {
  289. error_setg(errp, "There is no QemuConsole I can screendump from.");
  290. return;
  291. }
  292. graphic_hw_update(con);
  293. surface = qemu_console_surface(con);
  294. ppm_save(filename, surface, errp);
  295. }
  296. void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
  297. {
  298. if (!con) {
  299. con = active_console;
  300. }
  301. if (con && con->hw_ops->text_update) {
  302. con->hw_ops->text_update(con->hw, chardata);
  303. }
  304. }
  305. static void vga_fill_rect(QemuConsole *con,
  306. int posx, int posy, int width, int height,
  307. pixman_color_t color)
  308. {
  309. DisplaySurface *surface = qemu_console_surface(con);
  310. pixman_rectangle16_t rect = {
  311. .x = posx, .y = posy, .width = width, .height = height
  312. };
  313. pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image,
  314. &color, 1, &rect);
  315. }
  316. /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
  317. static void vga_bitblt(QemuConsole *con,
  318. int xs, int ys, int xd, int yd, int w, int h)
  319. {
  320. DisplaySurface *surface = qemu_console_surface(con);
  321. pixman_image_composite(PIXMAN_OP_SRC,
  322. surface->image, NULL, surface->image,
  323. xs, ys, 0, 0, xd, yd, w, h);
  324. }
  325. /***********************************************************/
  326. /* basic char display */
  327. #define FONT_HEIGHT 16
  328. #define FONT_WIDTH 8
  329. #include "vgafont.h"
  330. #ifndef CONFIG_CURSES
  331. enum color_names {
  332. COLOR_BLACK = 0,
  333. COLOR_RED = 1,
  334. COLOR_GREEN = 2,
  335. COLOR_YELLOW = 3,
  336. COLOR_BLUE = 4,
  337. COLOR_MAGENTA = 5,
  338. COLOR_CYAN = 6,
  339. COLOR_WHITE = 7
  340. };
  341. #endif
  342. #define QEMU_RGB(r, g, b) \
  343. { .red = r << 8, .green = g << 8, .blue = b << 8, .alpha = 0xffff }
  344. static const pixman_color_t color_table_rgb[2][8] = {
  345. { /* dark */
  346. QEMU_RGB(0x00, 0x00, 0x00), /* black */
  347. QEMU_RGB(0xaa, 0x00, 0x00), /* red */
  348. QEMU_RGB(0x00, 0xaa, 0x00), /* green */
  349. QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
  350. QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
  351. QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
  352. QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
  353. QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
  354. },
  355. { /* bright */
  356. QEMU_RGB(0x00, 0x00, 0x00), /* black */
  357. QEMU_RGB(0xff, 0x00, 0x00), /* red */
  358. QEMU_RGB(0x00, 0xff, 0x00), /* green */
  359. QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
  360. QEMU_RGB(0x00, 0x00, 0xff), /* blue */
  361. QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
  362. QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
  363. QEMU_RGB(0xff, 0xff, 0xff), /* white */
  364. }
  365. };
  366. static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
  367. TextAttributes *t_attrib)
  368. {
  369. static pixman_image_t *glyphs[256];
  370. DisplaySurface *surface = qemu_console_surface(s);
  371. pixman_color_t fgcol, bgcol;
  372. if (t_attrib->invers) {
  373. bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
  374. fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
  375. } else {
  376. fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
  377. bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
  378. }
  379. if (!glyphs[ch]) {
  380. glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
  381. }
  382. qemu_pixman_glyph_render(glyphs[ch], surface->image,
  383. &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
  384. }
  385. static void text_console_resize(QemuConsole *s)
  386. {
  387. TextCell *cells, *c, *c1;
  388. int w1, x, y, last_width;
  389. last_width = s->width;
  390. s->width = surface_width(s->surface) / FONT_WIDTH;
  391. s->height = surface_height(s->surface) / FONT_HEIGHT;
  392. w1 = last_width;
  393. if (s->width < w1)
  394. w1 = s->width;
  395. cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
  396. for(y = 0; y < s->total_height; y++) {
  397. c = &cells[y * s->width];
  398. if (w1 > 0) {
  399. c1 = &s->cells[y * last_width];
  400. for(x = 0; x < w1; x++) {
  401. *c++ = *c1++;
  402. }
  403. }
  404. for(x = w1; x < s->width; x++) {
  405. c->ch = ' ';
  406. c->t_attrib = s->t_attrib_default;
  407. c++;
  408. }
  409. }
  410. g_free(s->cells);
  411. s->cells = cells;
  412. }
  413. static inline void text_update_xy(QemuConsole *s, int x, int y)
  414. {
  415. s->text_x[0] = MIN(s->text_x[0], x);
  416. s->text_x[1] = MAX(s->text_x[1], x);
  417. s->text_y[0] = MIN(s->text_y[0], y);
  418. s->text_y[1] = MAX(s->text_y[1], y);
  419. }
  420. static void invalidate_xy(QemuConsole *s, int x, int y)
  421. {
  422. if (!qemu_console_is_visible(s)) {
  423. return;
  424. }
  425. if (s->update_x0 > x * FONT_WIDTH)
  426. s->update_x0 = x * FONT_WIDTH;
  427. if (s->update_y0 > y * FONT_HEIGHT)
  428. s->update_y0 = y * FONT_HEIGHT;
  429. if (s->update_x1 < (x + 1) * FONT_WIDTH)
  430. s->update_x1 = (x + 1) * FONT_WIDTH;
  431. if (s->update_y1 < (y + 1) * FONT_HEIGHT)
  432. s->update_y1 = (y + 1) * FONT_HEIGHT;
  433. }
  434. static void update_xy(QemuConsole *s, int x, int y)
  435. {
  436. TextCell *c;
  437. int y1, y2;
  438. if (s->ds->have_text) {
  439. text_update_xy(s, x, y);
  440. }
  441. y1 = (s->y_base + y) % s->total_height;
  442. y2 = y1 - s->y_displayed;
  443. if (y2 < 0) {
  444. y2 += s->total_height;
  445. }
  446. if (y2 < s->height) {
  447. c = &s->cells[y1 * s->width + x];
  448. vga_putcharxy(s, x, y2, c->ch,
  449. &(c->t_attrib));
  450. invalidate_xy(s, x, y2);
  451. }
  452. }
  453. static void console_show_cursor(QemuConsole *s, int show)
  454. {
  455. TextCell *c;
  456. int y, y1;
  457. int x = s->x;
  458. if (s->ds->have_text) {
  459. s->cursor_invalidate = 1;
  460. }
  461. if (x >= s->width) {
  462. x = s->width - 1;
  463. }
  464. y1 = (s->y_base + s->y) % s->total_height;
  465. y = y1 - s->y_displayed;
  466. if (y < 0) {
  467. y += s->total_height;
  468. }
  469. if (y < s->height) {
  470. c = &s->cells[y1 * s->width + x];
  471. if (show && cursor_visible_phase) {
  472. TextAttributes t_attrib = s->t_attrib_default;
  473. t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
  474. vga_putcharxy(s, x, y, c->ch, &t_attrib);
  475. } else {
  476. vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
  477. }
  478. invalidate_xy(s, x, y);
  479. }
  480. }
  481. static void console_refresh(QemuConsole *s)
  482. {
  483. DisplaySurface *surface = qemu_console_surface(s);
  484. TextCell *c;
  485. int x, y, y1;
  486. if (s->ds->have_text) {
  487. s->text_x[0] = 0;
  488. s->text_y[0] = 0;
  489. s->text_x[1] = s->width - 1;
  490. s->text_y[1] = s->height - 1;
  491. s->cursor_invalidate = 1;
  492. }
  493. vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
  494. color_table_rgb[0][COLOR_BLACK]);
  495. y1 = s->y_displayed;
  496. for (y = 0; y < s->height; y++) {
  497. c = s->cells + y1 * s->width;
  498. for (x = 0; x < s->width; x++) {
  499. vga_putcharxy(s, x, y, c->ch,
  500. &(c->t_attrib));
  501. c++;
  502. }
  503. if (++y1 == s->total_height) {
  504. y1 = 0;
  505. }
  506. }
  507. console_show_cursor(s, 1);
  508. dpy_gfx_update(s, 0, 0,
  509. surface_width(surface), surface_height(surface));
  510. }
  511. static void console_scroll(QemuConsole *s, int ydelta)
  512. {
  513. int i, y1;
  514. if (ydelta > 0) {
  515. for(i = 0; i < ydelta; i++) {
  516. if (s->y_displayed == s->y_base)
  517. break;
  518. if (++s->y_displayed == s->total_height)
  519. s->y_displayed = 0;
  520. }
  521. } else {
  522. ydelta = -ydelta;
  523. i = s->backscroll_height;
  524. if (i > s->total_height - s->height)
  525. i = s->total_height - s->height;
  526. y1 = s->y_base - i;
  527. if (y1 < 0)
  528. y1 += s->total_height;
  529. for(i = 0; i < ydelta; i++) {
  530. if (s->y_displayed == y1)
  531. break;
  532. if (--s->y_displayed < 0)
  533. s->y_displayed = s->total_height - 1;
  534. }
  535. }
  536. console_refresh(s);
  537. }
  538. static void console_put_lf(QemuConsole *s)
  539. {
  540. TextCell *c;
  541. int x, y1;
  542. s->y++;
  543. if (s->y >= s->height) {
  544. s->y = s->height - 1;
  545. if (s->y_displayed == s->y_base) {
  546. if (++s->y_displayed == s->total_height)
  547. s->y_displayed = 0;
  548. }
  549. if (++s->y_base == s->total_height)
  550. s->y_base = 0;
  551. if (s->backscroll_height < s->total_height)
  552. s->backscroll_height++;
  553. y1 = (s->y_base + s->height - 1) % s->total_height;
  554. c = &s->cells[y1 * s->width];
  555. for(x = 0; x < s->width; x++) {
  556. c->ch = ' ';
  557. c->t_attrib = s->t_attrib_default;
  558. c++;
  559. }
  560. if (s->y_displayed == s->y_base) {
  561. if (s->ds->have_text) {
  562. s->text_x[0] = 0;
  563. s->text_y[0] = 0;
  564. s->text_x[1] = s->width - 1;
  565. s->text_y[1] = s->height - 1;
  566. }
  567. vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
  568. s->width * FONT_WIDTH,
  569. (s->height - 1) * FONT_HEIGHT);
  570. vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
  571. s->width * FONT_WIDTH, FONT_HEIGHT,
  572. color_table_rgb[0][s->t_attrib_default.bgcol]);
  573. s->update_x0 = 0;
  574. s->update_y0 = 0;
  575. s->update_x1 = s->width * FONT_WIDTH;
  576. s->update_y1 = s->height * FONT_HEIGHT;
  577. }
  578. }
  579. }
  580. /* Set console attributes depending on the current escape codes.
  581. * NOTE: I know this code is not very efficient (checking every color for it
  582. * self) but it is more readable and better maintainable.
  583. */
  584. static void console_handle_escape(QemuConsole *s)
  585. {
  586. int i;
  587. for (i=0; i<s->nb_esc_params; i++) {
  588. switch (s->esc_params[i]) {
  589. case 0: /* reset all console attributes to default */
  590. s->t_attrib = s->t_attrib_default;
  591. break;
  592. case 1:
  593. s->t_attrib.bold = 1;
  594. break;
  595. case 4:
  596. s->t_attrib.uline = 1;
  597. break;
  598. case 5:
  599. s->t_attrib.blink = 1;
  600. break;
  601. case 7:
  602. s->t_attrib.invers = 1;
  603. break;
  604. case 8:
  605. s->t_attrib.unvisible = 1;
  606. break;
  607. case 22:
  608. s->t_attrib.bold = 0;
  609. break;
  610. case 24:
  611. s->t_attrib.uline = 0;
  612. break;
  613. case 25:
  614. s->t_attrib.blink = 0;
  615. break;
  616. case 27:
  617. s->t_attrib.invers = 0;
  618. break;
  619. case 28:
  620. s->t_attrib.unvisible = 0;
  621. break;
  622. /* set foreground color */
  623. case 30:
  624. s->t_attrib.fgcol=COLOR_BLACK;
  625. break;
  626. case 31:
  627. s->t_attrib.fgcol=COLOR_RED;
  628. break;
  629. case 32:
  630. s->t_attrib.fgcol=COLOR_GREEN;
  631. break;
  632. case 33:
  633. s->t_attrib.fgcol=COLOR_YELLOW;
  634. break;
  635. case 34:
  636. s->t_attrib.fgcol=COLOR_BLUE;
  637. break;
  638. case 35:
  639. s->t_attrib.fgcol=COLOR_MAGENTA;
  640. break;
  641. case 36:
  642. s->t_attrib.fgcol=COLOR_CYAN;
  643. break;
  644. case 37:
  645. s->t_attrib.fgcol=COLOR_WHITE;
  646. break;
  647. /* set background color */
  648. case 40:
  649. s->t_attrib.bgcol=COLOR_BLACK;
  650. break;
  651. case 41:
  652. s->t_attrib.bgcol=COLOR_RED;
  653. break;
  654. case 42:
  655. s->t_attrib.bgcol=COLOR_GREEN;
  656. break;
  657. case 43:
  658. s->t_attrib.bgcol=COLOR_YELLOW;
  659. break;
  660. case 44:
  661. s->t_attrib.bgcol=COLOR_BLUE;
  662. break;
  663. case 45:
  664. s->t_attrib.bgcol=COLOR_MAGENTA;
  665. break;
  666. case 46:
  667. s->t_attrib.bgcol=COLOR_CYAN;
  668. break;
  669. case 47:
  670. s->t_attrib.bgcol=COLOR_WHITE;
  671. break;
  672. }
  673. }
  674. }
  675. static void console_clear_xy(QemuConsole *s, int x, int y)
  676. {
  677. int y1 = (s->y_base + y) % s->total_height;
  678. TextCell *c = &s->cells[y1 * s->width + x];
  679. c->ch = ' ';
  680. c->t_attrib = s->t_attrib_default;
  681. update_xy(s, x, y);
  682. }
  683. /* set cursor, checking bounds */
  684. static void set_cursor(QemuConsole *s, int x, int y)
  685. {
  686. if (x < 0) {
  687. x = 0;
  688. }
  689. if (y < 0) {
  690. y = 0;
  691. }
  692. if (y >= s->height) {
  693. y = s->height - 1;
  694. }
  695. if (x >= s->width) {
  696. x = s->width - 1;
  697. }
  698. s->x = x;
  699. s->y = y;
  700. }
  701. static void console_putchar(QemuConsole *s, int ch)
  702. {
  703. TextCell *c;
  704. int y1, i;
  705. int x, y;
  706. switch(s->state) {
  707. case TTY_STATE_NORM:
  708. switch(ch) {
  709. case '\r': /* carriage return */
  710. s->x = 0;
  711. break;
  712. case '\n': /* newline */
  713. console_put_lf(s);
  714. break;
  715. case '\b': /* backspace */
  716. if (s->x > 0)
  717. s->x--;
  718. break;
  719. case '\t': /* tabspace */
  720. if (s->x + (8 - (s->x % 8)) > s->width) {
  721. s->x = 0;
  722. console_put_lf(s);
  723. } else {
  724. s->x = s->x + (8 - (s->x % 8));
  725. }
  726. break;
  727. case '\a': /* alert aka. bell */
  728. /* TODO: has to be implemented */
  729. break;
  730. case 14:
  731. /* SI (shift in), character set 0 (ignored) */
  732. break;
  733. case 15:
  734. /* SO (shift out), character set 1 (ignored) */
  735. break;
  736. case 27: /* esc (introducing an escape sequence) */
  737. s->state = TTY_STATE_ESC;
  738. break;
  739. default:
  740. if (s->x >= s->width) {
  741. /* line wrap */
  742. s->x = 0;
  743. console_put_lf(s);
  744. }
  745. y1 = (s->y_base + s->y) % s->total_height;
  746. c = &s->cells[y1 * s->width + s->x];
  747. c->ch = ch;
  748. c->t_attrib = s->t_attrib;
  749. update_xy(s, s->x, s->y);
  750. s->x++;
  751. break;
  752. }
  753. break;
  754. case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
  755. if (ch == '[') {
  756. for(i=0;i<MAX_ESC_PARAMS;i++)
  757. s->esc_params[i] = 0;
  758. s->nb_esc_params = 0;
  759. s->state = TTY_STATE_CSI;
  760. } else {
  761. s->state = TTY_STATE_NORM;
  762. }
  763. break;
  764. case TTY_STATE_CSI: /* handle escape sequence parameters */
  765. if (ch >= '0' && ch <= '9') {
  766. if (s->nb_esc_params < MAX_ESC_PARAMS) {
  767. int *param = &s->esc_params[s->nb_esc_params];
  768. int digit = (ch - '0');
  769. *param = (*param <= (INT_MAX - digit) / 10) ?
  770. *param * 10 + digit : INT_MAX;
  771. }
  772. } else {
  773. if (s->nb_esc_params < MAX_ESC_PARAMS)
  774. s->nb_esc_params++;
  775. if (ch == ';')
  776. break;
  777. trace_console_putchar_csi(s->esc_params[0], s->esc_params[1],
  778. ch, s->nb_esc_params);
  779. s->state = TTY_STATE_NORM;
  780. switch(ch) {
  781. case 'A':
  782. /* move cursor up */
  783. if (s->esc_params[0] == 0) {
  784. s->esc_params[0] = 1;
  785. }
  786. set_cursor(s, s->x, s->y - s->esc_params[0]);
  787. break;
  788. case 'B':
  789. /* move cursor down */
  790. if (s->esc_params[0] == 0) {
  791. s->esc_params[0] = 1;
  792. }
  793. set_cursor(s, s->x, s->y + s->esc_params[0]);
  794. break;
  795. case 'C':
  796. /* move cursor right */
  797. if (s->esc_params[0] == 0) {
  798. s->esc_params[0] = 1;
  799. }
  800. set_cursor(s, s->x + s->esc_params[0], s->y);
  801. break;
  802. case 'D':
  803. /* move cursor left */
  804. if (s->esc_params[0] == 0) {
  805. s->esc_params[0] = 1;
  806. }
  807. set_cursor(s, s->x - s->esc_params[0], s->y);
  808. break;
  809. case 'G':
  810. /* move cursor to column */
  811. set_cursor(s, s->esc_params[0] - 1, s->y);
  812. break;
  813. case 'f':
  814. case 'H':
  815. /* move cursor to row, column */
  816. set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
  817. break;
  818. case 'J':
  819. switch (s->esc_params[0]) {
  820. case 0:
  821. /* clear to end of screen */
  822. for (y = s->y; y < s->height; y++) {
  823. for (x = 0; x < s->width; x++) {
  824. if (y == s->y && x < s->x) {
  825. continue;
  826. }
  827. console_clear_xy(s, x, y);
  828. }
  829. }
  830. break;
  831. case 1:
  832. /* clear from beginning of screen */
  833. for (y = 0; y <= s->y; y++) {
  834. for (x = 0; x < s->width; x++) {
  835. if (y == s->y && x > s->x) {
  836. break;
  837. }
  838. console_clear_xy(s, x, y);
  839. }
  840. }
  841. break;
  842. case 2:
  843. /* clear entire screen */
  844. for (y = 0; y <= s->height; y++) {
  845. for (x = 0; x < s->width; x++) {
  846. console_clear_xy(s, x, y);
  847. }
  848. }
  849. break;
  850. }
  851. break;
  852. case 'K':
  853. switch (s->esc_params[0]) {
  854. case 0:
  855. /* clear to eol */
  856. for(x = s->x; x < s->width; x++) {
  857. console_clear_xy(s, x, s->y);
  858. }
  859. break;
  860. case 1:
  861. /* clear from beginning of line */
  862. for (x = 0; x <= s->x; x++) {
  863. console_clear_xy(s, x, s->y);
  864. }
  865. break;
  866. case 2:
  867. /* clear entire line */
  868. for(x = 0; x < s->width; x++) {
  869. console_clear_xy(s, x, s->y);
  870. }
  871. break;
  872. }
  873. break;
  874. case 'm':
  875. console_handle_escape(s);
  876. break;
  877. case 'n':
  878. /* report cursor position */
  879. /* TODO: send ESC[row;colR */
  880. break;
  881. case 's':
  882. /* save cursor position */
  883. s->x_saved = s->x;
  884. s->y_saved = s->y;
  885. break;
  886. case 'u':
  887. /* restore cursor position */
  888. s->x = s->x_saved;
  889. s->y = s->y_saved;
  890. break;
  891. default:
  892. trace_console_putchar_unhandled(ch);
  893. break;
  894. }
  895. break;
  896. }
  897. }
  898. }
  899. void console_select(unsigned int index)
  900. {
  901. DisplayChangeListener *dcl;
  902. QemuConsole *s;
  903. trace_console_select(index);
  904. s = qemu_console_lookup_by_index(index);
  905. if (s) {
  906. DisplayState *ds = s->ds;
  907. active_console = s;
  908. if (ds->have_gfx) {
  909. QLIST_FOREACH(dcl, &ds->listeners, next) {
  910. if (dcl->con != NULL) {
  911. continue;
  912. }
  913. if (dcl->ops->dpy_gfx_switch) {
  914. dcl->ops->dpy_gfx_switch(dcl, s->surface);
  915. }
  916. }
  917. dpy_gfx_update(s, 0, 0, surface_width(s->surface),
  918. surface_height(s->surface));
  919. }
  920. if (ds->have_text) {
  921. dpy_text_resize(s, s->width, s->height);
  922. }
  923. text_console_update_cursor(NULL);
  924. }
  925. }
  926. static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
  927. {
  928. QemuConsole *s = chr->opaque;
  929. int i;
  930. s->update_x0 = s->width * FONT_WIDTH;
  931. s->update_y0 = s->height * FONT_HEIGHT;
  932. s->update_x1 = 0;
  933. s->update_y1 = 0;
  934. console_show_cursor(s, 0);
  935. for(i = 0; i < len; i++) {
  936. console_putchar(s, buf[i]);
  937. }
  938. console_show_cursor(s, 1);
  939. if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
  940. dpy_gfx_update(s, s->update_x0, s->update_y0,
  941. s->update_x1 - s->update_x0,
  942. s->update_y1 - s->update_y0);
  943. }
  944. return len;
  945. }
  946. static void kbd_send_chars(void *opaque)
  947. {
  948. QemuConsole *s = opaque;
  949. int len;
  950. uint8_t buf[16];
  951. len = qemu_chr_be_can_write(s->chr);
  952. if (len > s->out_fifo.count)
  953. len = s->out_fifo.count;
  954. if (len > 0) {
  955. if (len > sizeof(buf))
  956. len = sizeof(buf);
  957. qemu_fifo_read(&s->out_fifo, buf, len);
  958. qemu_chr_be_write(s->chr, buf, len);
  959. }
  960. /* characters are pending: we send them a bit later (XXX:
  961. horrible, should change char device API) */
  962. if (s->out_fifo.count > 0) {
  963. timer_mod(s->kbd_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1);
  964. }
  965. }
  966. /* called when an ascii key is pressed */
  967. void kbd_put_keysym_console(QemuConsole *s, int keysym)
  968. {
  969. uint8_t buf[16], *q;
  970. int c;
  971. if (!s || (s->console_type == GRAPHIC_CONSOLE))
  972. return;
  973. switch(keysym) {
  974. case QEMU_KEY_CTRL_UP:
  975. console_scroll(s, -1);
  976. break;
  977. case QEMU_KEY_CTRL_DOWN:
  978. console_scroll(s, 1);
  979. break;
  980. case QEMU_KEY_CTRL_PAGEUP:
  981. console_scroll(s, -10);
  982. break;
  983. case QEMU_KEY_CTRL_PAGEDOWN:
  984. console_scroll(s, 10);
  985. break;
  986. default:
  987. /* convert the QEMU keysym to VT100 key string */
  988. q = buf;
  989. if (keysym >= 0xe100 && keysym <= 0xe11f) {
  990. *q++ = '\033';
  991. *q++ = '[';
  992. c = keysym - 0xe100;
  993. if (c >= 10)
  994. *q++ = '0' + (c / 10);
  995. *q++ = '0' + (c % 10);
  996. *q++ = '~';
  997. } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
  998. *q++ = '\033';
  999. *q++ = '[';
  1000. *q++ = keysym & 0xff;
  1001. } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
  1002. console_puts(s->chr, (const uint8_t *) "\r", 1);
  1003. *q++ = '\n';
  1004. } else {
  1005. *q++ = keysym;
  1006. }
  1007. if (s->echo) {
  1008. console_puts(s->chr, buf, q - buf);
  1009. }
  1010. if (s->chr->chr_read) {
  1011. qemu_fifo_write(&s->out_fifo, buf, q - buf);
  1012. kbd_send_chars(s);
  1013. }
  1014. break;
  1015. }
  1016. }
  1017. static const int qcode_to_keysym[Q_KEY_CODE_MAX] = {
  1018. [Q_KEY_CODE_UP] = QEMU_KEY_UP,
  1019. [Q_KEY_CODE_DOWN] = QEMU_KEY_DOWN,
  1020. [Q_KEY_CODE_RIGHT] = QEMU_KEY_RIGHT,
  1021. [Q_KEY_CODE_LEFT] = QEMU_KEY_LEFT,
  1022. [Q_KEY_CODE_HOME] = QEMU_KEY_HOME,
  1023. [Q_KEY_CODE_END] = QEMU_KEY_END,
  1024. [Q_KEY_CODE_PGUP] = QEMU_KEY_PAGEUP,
  1025. [Q_KEY_CODE_PGDN] = QEMU_KEY_PAGEDOWN,
  1026. [Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE,
  1027. };
  1028. bool kbd_put_qcode_console(QemuConsole *s, int qcode)
  1029. {
  1030. int keysym;
  1031. keysym = qcode_to_keysym[qcode];
  1032. if (keysym == 0) {
  1033. return false;
  1034. }
  1035. kbd_put_keysym_console(s, keysym);
  1036. return true;
  1037. }
  1038. void kbd_put_string_console(QemuConsole *s, const char *str, int len)
  1039. {
  1040. int i;
  1041. for (i = 0; i < len && str[i]; i++) {
  1042. kbd_put_keysym_console(s, str[i]);
  1043. }
  1044. }
  1045. void kbd_put_keysym(int keysym)
  1046. {
  1047. kbd_put_keysym_console(active_console, keysym);
  1048. }
  1049. static void text_console_invalidate(void *opaque)
  1050. {
  1051. QemuConsole *s = (QemuConsole *) opaque;
  1052. if (s->ds->have_text && s->console_type == TEXT_CONSOLE) {
  1053. text_console_resize(s);
  1054. }
  1055. console_refresh(s);
  1056. }
  1057. static void text_console_update(void *opaque, console_ch_t *chardata)
  1058. {
  1059. QemuConsole *s = (QemuConsole *) opaque;
  1060. int i, j, src;
  1061. if (s->text_x[0] <= s->text_x[1]) {
  1062. src = (s->y_base + s->text_y[0]) * s->width;
  1063. chardata += s->text_y[0] * s->width;
  1064. for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
  1065. for (j = 0; j < s->width; j ++, src ++)
  1066. console_write_ch(chardata ++, s->cells[src].ch |
  1067. (s->cells[src].t_attrib.fgcol << 12) |
  1068. (s->cells[src].t_attrib.bgcol << 8) |
  1069. (s->cells[src].t_attrib.bold << 21));
  1070. dpy_text_update(s, s->text_x[0], s->text_y[0],
  1071. s->text_x[1] - s->text_x[0], i - s->text_y[0]);
  1072. s->text_x[0] = s->width;
  1073. s->text_y[0] = s->height;
  1074. s->text_x[1] = 0;
  1075. s->text_y[1] = 0;
  1076. }
  1077. if (s->cursor_invalidate) {
  1078. dpy_text_cursor(s, s->x, s->y);
  1079. s->cursor_invalidate = 0;
  1080. }
  1081. }
  1082. static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
  1083. uint32_t head)
  1084. {
  1085. Object *obj;
  1086. QemuConsole *s;
  1087. int i;
  1088. obj = object_new(TYPE_QEMU_CONSOLE);
  1089. s = QEMU_CONSOLE(obj);
  1090. s->head = head;
  1091. object_property_add_link(obj, "device", TYPE_DEVICE,
  1092. (Object **)&s->device,
  1093. object_property_allow_set_link,
  1094. OBJ_PROP_LINK_UNREF_ON_RELEASE,
  1095. &error_abort);
  1096. object_property_add_uint32_ptr(obj, "head",
  1097. &s->head, &error_abort);
  1098. if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
  1099. (console_type == GRAPHIC_CONSOLE))) {
  1100. active_console = s;
  1101. }
  1102. s->ds = ds;
  1103. s->console_type = console_type;
  1104. consoles = g_realloc(consoles, sizeof(*consoles) * (nb_consoles+1));
  1105. if (console_type != GRAPHIC_CONSOLE) {
  1106. s->index = nb_consoles;
  1107. consoles[nb_consoles++] = s;
  1108. } else {
  1109. /* HACK: Put graphical consoles before text consoles. */
  1110. for (i = nb_consoles; i > 0; i--) {
  1111. if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
  1112. break;
  1113. consoles[i] = consoles[i - 1];
  1114. consoles[i]->index = i;
  1115. }
  1116. s->index = i;
  1117. consoles[i] = s;
  1118. nb_consoles++;
  1119. }
  1120. return s;
  1121. }
  1122. static void qemu_alloc_display(DisplaySurface *surface, int width, int height)
  1123. {
  1124. qemu_pixman_image_unref(surface->image);
  1125. surface->image = NULL;
  1126. surface->format = PIXMAN_x8r8g8b8;
  1127. surface->image = pixman_image_create_bits(surface->format,
  1128. width, height,
  1129. NULL, width * 4);
  1130. assert(surface->image != NULL);
  1131. surface->flags = QEMU_ALLOCATED_FLAG;
  1132. }
  1133. DisplaySurface *qemu_create_displaysurface(int width, int height)
  1134. {
  1135. DisplaySurface *surface = g_new0(DisplaySurface, 1);
  1136. trace_displaysurface_create(surface, width, height);
  1137. qemu_alloc_display(surface, width, height);
  1138. return surface;
  1139. }
  1140. DisplaySurface *qemu_create_displaysurface_from(int width, int height,
  1141. pixman_format_code_t format,
  1142. int linesize, uint8_t *data)
  1143. {
  1144. DisplaySurface *surface = g_new0(DisplaySurface, 1);
  1145. trace_displaysurface_create_from(surface, width, height, format);
  1146. surface->format = format;
  1147. surface->image = pixman_image_create_bits(surface->format,
  1148. width, height,
  1149. (void *)data, linesize);
  1150. assert(surface->image != NULL);
  1151. return surface;
  1152. }
  1153. static void qemu_unmap_displaysurface_guestmem(pixman_image_t *image,
  1154. void *unused)
  1155. {
  1156. void *data = pixman_image_get_data(image);
  1157. uint32_t size = pixman_image_get_stride(image) *
  1158. pixman_image_get_height(image);
  1159. cpu_physical_memory_unmap(data, size, 0, 0);
  1160. }
  1161. DisplaySurface *qemu_create_displaysurface_guestmem(int width, int height,
  1162. pixman_format_code_t format,
  1163. int linesize, uint64_t addr)
  1164. {
  1165. DisplaySurface *surface;
  1166. hwaddr size;
  1167. void *data;
  1168. if (linesize == 0) {
  1169. linesize = width * PIXMAN_FORMAT_BPP(format) / 8;
  1170. }
  1171. size = linesize * height;
  1172. data = cpu_physical_memory_map(addr, &size, 0);
  1173. if (size != linesize * height) {
  1174. cpu_physical_memory_unmap(data, size, 0, 0);
  1175. return NULL;
  1176. }
  1177. surface = qemu_create_displaysurface_from
  1178. (width, height, format, linesize, data);
  1179. pixman_image_set_destroy_function
  1180. (surface->image, qemu_unmap_displaysurface_guestmem, NULL);
  1181. return surface;
  1182. }
  1183. static DisplaySurface *qemu_create_message_surface(int w, int h,
  1184. const char *msg)
  1185. {
  1186. DisplaySurface *surface = qemu_create_displaysurface(w, h);
  1187. pixman_color_t bg = color_table_rgb[0][COLOR_BLACK];
  1188. pixman_color_t fg = color_table_rgb[0][COLOR_WHITE];
  1189. pixman_image_t *glyph;
  1190. int len, x, y, i;
  1191. len = strlen(msg);
  1192. x = (w / FONT_WIDTH - len) / 2;
  1193. y = (h / FONT_HEIGHT - 1) / 2;
  1194. for (i = 0; i < len; i++) {
  1195. glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
  1196. qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
  1197. x+i, y, FONT_WIDTH, FONT_HEIGHT);
  1198. qemu_pixman_image_unref(glyph);
  1199. }
  1200. return surface;
  1201. }
  1202. void qemu_free_displaysurface(DisplaySurface *surface)
  1203. {
  1204. if (surface == NULL) {
  1205. return;
  1206. }
  1207. trace_displaysurface_free(surface);
  1208. qemu_pixman_image_unref(surface->image);
  1209. g_free(surface);
  1210. }
  1211. void register_displaychangelistener(DisplayChangeListener *dcl)
  1212. {
  1213. static const char nodev[] =
  1214. "This VM has no graphic display device.";
  1215. static DisplaySurface *dummy;
  1216. QemuConsole *con;
  1217. trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
  1218. dcl->ds = get_alloc_displaystate();
  1219. QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
  1220. gui_setup_refresh(dcl->ds);
  1221. if (dcl->con) {
  1222. dcl->con->dcls++;
  1223. con = dcl->con;
  1224. } else {
  1225. con = active_console;
  1226. }
  1227. if (dcl->ops->dpy_gfx_switch) {
  1228. if (con) {
  1229. dcl->ops->dpy_gfx_switch(dcl, con->surface);
  1230. } else {
  1231. if (!dummy) {
  1232. dummy = qemu_create_message_surface(640, 480, nodev);
  1233. }
  1234. dcl->ops->dpy_gfx_switch(dcl, dummy);
  1235. }
  1236. }
  1237. text_console_update_cursor(NULL);
  1238. }
  1239. void update_displaychangelistener(DisplayChangeListener *dcl,
  1240. uint64_t interval)
  1241. {
  1242. DisplayState *ds = dcl->ds;
  1243. dcl->update_interval = interval;
  1244. if (!ds->refreshing && ds->update_interval > interval) {
  1245. timer_mod(ds->gui_timer, ds->last_update + interval);
  1246. }
  1247. }
  1248. void unregister_displaychangelistener(DisplayChangeListener *dcl)
  1249. {
  1250. DisplayState *ds = dcl->ds;
  1251. trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
  1252. if (dcl->con) {
  1253. dcl->con->dcls--;
  1254. }
  1255. QLIST_REMOVE(dcl, next);
  1256. gui_setup_refresh(ds);
  1257. }
  1258. int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info)
  1259. {
  1260. assert(con != NULL);
  1261. con->ui_info = *info;
  1262. if (con->hw_ops->ui_info) {
  1263. return con->hw_ops->ui_info(con->hw, con->head, info);
  1264. }
  1265. return -1;
  1266. }
  1267. void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
  1268. {
  1269. DisplayState *s = con->ds;
  1270. DisplayChangeListener *dcl;
  1271. int width = surface_width(con->surface);
  1272. int height = surface_height(con->surface);
  1273. x = MAX(x, 0);
  1274. y = MAX(y, 0);
  1275. x = MIN(x, width);
  1276. y = MIN(y, height);
  1277. w = MIN(w, width - x);
  1278. h = MIN(h, height - y);
  1279. if (!qemu_console_is_visible(con)) {
  1280. return;
  1281. }
  1282. QLIST_FOREACH(dcl, &s->listeners, next) {
  1283. if (con != (dcl->con ? dcl->con : active_console)) {
  1284. continue;
  1285. }
  1286. if (dcl->ops->dpy_gfx_update) {
  1287. dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
  1288. }
  1289. }
  1290. }
  1291. void dpy_gfx_replace_surface(QemuConsole *con,
  1292. DisplaySurface *surface)
  1293. {
  1294. DisplayState *s = con->ds;
  1295. DisplaySurface *old_surface = con->surface;
  1296. DisplayChangeListener *dcl;
  1297. con->surface = surface;
  1298. QLIST_FOREACH(dcl, &s->listeners, next) {
  1299. if (con != (dcl->con ? dcl->con : active_console)) {
  1300. continue;
  1301. }
  1302. if (dcl->ops->dpy_gfx_switch) {
  1303. dcl->ops->dpy_gfx_switch(dcl, surface);
  1304. }
  1305. }
  1306. qemu_free_displaysurface(old_surface);
  1307. }
  1308. static void dpy_refresh(DisplayState *s)
  1309. {
  1310. DisplayChangeListener *dcl;
  1311. QLIST_FOREACH(dcl, &s->listeners, next) {
  1312. if (dcl->ops->dpy_refresh) {
  1313. dcl->ops->dpy_refresh(dcl);
  1314. }
  1315. }
  1316. }
  1317. void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y,
  1318. int dst_x, int dst_y, int w, int h)
  1319. {
  1320. DisplayState *s = con->ds;
  1321. DisplayChangeListener *dcl;
  1322. if (!qemu_console_is_visible(con)) {
  1323. return;
  1324. }
  1325. QLIST_FOREACH(dcl, &s->listeners, next) {
  1326. if (con != (dcl->con ? dcl->con : active_console)) {
  1327. continue;
  1328. }
  1329. if (dcl->ops->dpy_gfx_copy) {
  1330. dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h);
  1331. } else { /* TODO */
  1332. dcl->ops->dpy_gfx_update(dcl, dst_x, dst_y, w, h);
  1333. }
  1334. }
  1335. }
  1336. void dpy_text_cursor(QemuConsole *con, int x, int y)
  1337. {
  1338. DisplayState *s = con->ds;
  1339. DisplayChangeListener *dcl;
  1340. if (!qemu_console_is_visible(con)) {
  1341. return;
  1342. }
  1343. QLIST_FOREACH(dcl, &s->listeners, next) {
  1344. if (con != (dcl->con ? dcl->con : active_console)) {
  1345. continue;
  1346. }
  1347. if (dcl->ops->dpy_text_cursor) {
  1348. dcl->ops->dpy_text_cursor(dcl, x, y);
  1349. }
  1350. }
  1351. }
  1352. void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
  1353. {
  1354. DisplayState *s = con->ds;
  1355. DisplayChangeListener *dcl;
  1356. if (!qemu_console_is_visible(con)) {
  1357. return;
  1358. }
  1359. QLIST_FOREACH(dcl, &s->listeners, next) {
  1360. if (con != (dcl->con ? dcl->con : active_console)) {
  1361. continue;
  1362. }
  1363. if (dcl->ops->dpy_text_update) {
  1364. dcl->ops->dpy_text_update(dcl, x, y, w, h);
  1365. }
  1366. }
  1367. }
  1368. void dpy_text_resize(QemuConsole *con, int w, int h)
  1369. {
  1370. DisplayState *s = con->ds;
  1371. struct DisplayChangeListener *dcl;
  1372. if (!qemu_console_is_visible(con)) {
  1373. return;
  1374. }
  1375. QLIST_FOREACH(dcl, &s->listeners, next) {
  1376. if (con != (dcl->con ? dcl->con : active_console)) {
  1377. continue;
  1378. }
  1379. if (dcl->ops->dpy_text_resize) {
  1380. dcl->ops->dpy_text_resize(dcl, w, h);
  1381. }
  1382. }
  1383. }
  1384. void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
  1385. {
  1386. DisplayState *s = con->ds;
  1387. DisplayChangeListener *dcl;
  1388. if (!qemu_console_is_visible(con)) {
  1389. return;
  1390. }
  1391. QLIST_FOREACH(dcl, &s->listeners, next) {
  1392. if (con != (dcl->con ? dcl->con : active_console)) {
  1393. continue;
  1394. }
  1395. if (dcl->ops->dpy_mouse_set) {
  1396. dcl->ops->dpy_mouse_set(dcl, x, y, on);
  1397. }
  1398. }
  1399. }
  1400. void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
  1401. {
  1402. DisplayState *s = con->ds;
  1403. DisplayChangeListener *dcl;
  1404. if (!qemu_console_is_visible(con)) {
  1405. return;
  1406. }
  1407. QLIST_FOREACH(dcl, &s->listeners, next) {
  1408. if (con != (dcl->con ? dcl->con : active_console)) {
  1409. continue;
  1410. }
  1411. if (dcl->ops->dpy_cursor_define) {
  1412. dcl->ops->dpy_cursor_define(dcl, cursor);
  1413. }
  1414. }
  1415. }
  1416. bool dpy_cursor_define_supported(QemuConsole *con)
  1417. {
  1418. DisplayState *s = con->ds;
  1419. DisplayChangeListener *dcl;
  1420. QLIST_FOREACH(dcl, &s->listeners, next) {
  1421. if (dcl->ops->dpy_cursor_define) {
  1422. return true;
  1423. }
  1424. }
  1425. return false;
  1426. }
  1427. /*
  1428. * Call dpy_gfx_update for all dirity scanlines. Works for
  1429. * DisplaySurfaces backed by guest memory (i.e. the ones created
  1430. * using qemu_create_displaysurface_guestmem).
  1431. */
  1432. void dpy_gfx_update_dirty(QemuConsole *con,
  1433. MemoryRegion *address_space,
  1434. hwaddr base,
  1435. bool invalidate)
  1436. {
  1437. DisplaySurface *ds = qemu_console_surface(con);
  1438. int width = surface_stride(ds);
  1439. int height = surface_height(ds);
  1440. hwaddr size = width * height;
  1441. MemoryRegionSection mem_section;
  1442. MemoryRegion *mem;
  1443. ram_addr_t addr;
  1444. int first, last, i;
  1445. bool dirty;
  1446. mem_section = memory_region_find(address_space, base, size);
  1447. mem = mem_section.mr;
  1448. if (int128_get64(mem_section.size) != size ||
  1449. !memory_region_is_ram(mem_section.mr)) {
  1450. goto out;
  1451. }
  1452. assert(mem);
  1453. memory_region_sync_dirty_bitmap(mem);
  1454. addr = mem_section.offset_within_region;
  1455. first = -1;
  1456. last = -1;
  1457. for (i = 0; i < height; i++, addr += width) {
  1458. dirty = invalidate ||
  1459. memory_region_get_dirty(mem, addr, width, DIRTY_MEMORY_VGA);
  1460. if (dirty) {
  1461. if (first == -1) {
  1462. first = i;
  1463. }
  1464. last = i;
  1465. }
  1466. if (first != -1 && !dirty) {
  1467. assert(last != -1 && last >= first);
  1468. dpy_gfx_update(con, 0, first, surface_width(ds),
  1469. last - first + 1);
  1470. first = -1;
  1471. }
  1472. }
  1473. if (first != -1) {
  1474. assert(last != -1 && last >= first);
  1475. dpy_gfx_update(con, 0, first, surface_width(ds),
  1476. last - first + 1);
  1477. }
  1478. memory_region_reset_dirty(mem, mem_section.offset_within_region, size,
  1479. DIRTY_MEMORY_VGA);
  1480. out:
  1481. memory_region_unref(mem);
  1482. }
  1483. /***********************************************************/
  1484. /* register display */
  1485. /* console.c internal use only */
  1486. static DisplayState *get_alloc_displaystate(void)
  1487. {
  1488. if (!display_state) {
  1489. display_state = g_new0(DisplayState, 1);
  1490. cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
  1491. text_console_update_cursor, NULL);
  1492. }
  1493. return display_state;
  1494. }
  1495. /*
  1496. * Called by main(), after creating QemuConsoles
  1497. * and before initializing ui (sdl/vnc/...).
  1498. */
  1499. DisplayState *init_displaystate(void)
  1500. {
  1501. gchar *name;
  1502. int i;
  1503. get_alloc_displaystate();
  1504. for (i = 0; i < nb_consoles; i++) {
  1505. if (consoles[i]->console_type != GRAPHIC_CONSOLE &&
  1506. consoles[i]->ds == NULL) {
  1507. text_console_do_init(consoles[i]->chr, display_state);
  1508. }
  1509. /* Hook up into the qom tree here (not in new_console()), once
  1510. * all QemuConsoles are created and the order / numbering
  1511. * doesn't change any more */
  1512. name = g_strdup_printf("console[%d]", i);
  1513. object_property_add_child(container_get(object_get_root(), "/backend"),
  1514. name, OBJECT(consoles[i]), &error_abort);
  1515. g_free(name);
  1516. }
  1517. return display_state;
  1518. }
  1519. void graphic_console_set_hwops(QemuConsole *con,
  1520. const GraphicHwOps *hw_ops,
  1521. void *opaque)
  1522. {
  1523. con->hw_ops = hw_ops;
  1524. con->hw = opaque;
  1525. }
  1526. QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
  1527. const GraphicHwOps *hw_ops,
  1528. void *opaque)
  1529. {
  1530. static const char noinit[] =
  1531. "Guest has not initialized the display (yet).";
  1532. int width = 640;
  1533. int height = 480;
  1534. QemuConsole *s;
  1535. DisplayState *ds;
  1536. ds = get_alloc_displaystate();
  1537. trace_console_gfx_new();
  1538. s = new_console(ds, GRAPHIC_CONSOLE, head);
  1539. graphic_console_set_hwops(s, hw_ops, opaque);
  1540. if (dev) {
  1541. object_property_set_link(OBJECT(s), OBJECT(dev), "device",
  1542. &error_abort);
  1543. }
  1544. s->surface = qemu_create_message_surface(width, height, noinit);
  1545. return s;
  1546. }
  1547. QemuConsole *qemu_console_lookup_by_index(unsigned int index)
  1548. {
  1549. if (index >= nb_consoles) {
  1550. return NULL;
  1551. }
  1552. return consoles[index];
  1553. }
  1554. QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
  1555. {
  1556. Object *obj;
  1557. uint32_t h;
  1558. int i;
  1559. for (i = 0; i < nb_consoles; i++) {
  1560. if (!consoles[i]) {
  1561. continue;
  1562. }
  1563. obj = object_property_get_link(OBJECT(consoles[i]),
  1564. "device", &error_abort);
  1565. if (DEVICE(obj) != dev) {
  1566. continue;
  1567. }
  1568. h = object_property_get_int(OBJECT(consoles[i]),
  1569. "head", &error_abort);
  1570. if (h != head) {
  1571. continue;
  1572. }
  1573. return consoles[i];
  1574. }
  1575. return NULL;
  1576. }
  1577. bool qemu_console_is_visible(QemuConsole *con)
  1578. {
  1579. return (con == active_console) || (con->dcls > 0);
  1580. }
  1581. bool qemu_console_is_graphic(QemuConsole *con)
  1582. {
  1583. if (con == NULL) {
  1584. con = active_console;
  1585. }
  1586. return con && (con->console_type == GRAPHIC_CONSOLE);
  1587. }
  1588. bool qemu_console_is_fixedsize(QemuConsole *con)
  1589. {
  1590. if (con == NULL) {
  1591. con = active_console;
  1592. }
  1593. return con && (con->console_type != TEXT_CONSOLE);
  1594. }
  1595. int qemu_console_get_index(QemuConsole *con)
  1596. {
  1597. if (con == NULL) {
  1598. con = active_console;
  1599. }
  1600. return con ? con->index : -1;
  1601. }
  1602. uint32_t qemu_console_get_head(QemuConsole *con)
  1603. {
  1604. if (con == NULL) {
  1605. con = active_console;
  1606. }
  1607. return con ? con->head : -1;
  1608. }
  1609. QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con)
  1610. {
  1611. assert(con != NULL);
  1612. return &con->ui_info;
  1613. }
  1614. int qemu_console_get_width(QemuConsole *con, int fallback)
  1615. {
  1616. if (con == NULL) {
  1617. con = active_console;
  1618. }
  1619. return con ? surface_width(con->surface) : fallback;
  1620. }
  1621. int qemu_console_get_height(QemuConsole *con, int fallback)
  1622. {
  1623. if (con == NULL) {
  1624. con = active_console;
  1625. }
  1626. return con ? surface_height(con->surface) : fallback;
  1627. }
  1628. static void text_console_set_echo(CharDriverState *chr, bool echo)
  1629. {
  1630. QemuConsole *s = chr->opaque;
  1631. s->echo = echo;
  1632. }
  1633. static void text_console_update_cursor_timer(void)
  1634. {
  1635. timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
  1636. + CONSOLE_CURSOR_PERIOD / 2);
  1637. }
  1638. static void text_console_update_cursor(void *opaque)
  1639. {
  1640. QemuConsole *s;
  1641. int i, count = 0;
  1642. cursor_visible_phase = !cursor_visible_phase;
  1643. for (i = 0; i < nb_consoles; i++) {
  1644. s = consoles[i];
  1645. if (qemu_console_is_graphic(s) ||
  1646. !qemu_console_is_visible(s)) {
  1647. continue;
  1648. }
  1649. count++;
  1650. graphic_hw_invalidate(s);
  1651. }
  1652. if (count) {
  1653. text_console_update_cursor_timer();
  1654. }
  1655. }
  1656. static const GraphicHwOps text_console_ops = {
  1657. .invalidate = text_console_invalidate,
  1658. .text_update = text_console_update,
  1659. };
  1660. static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
  1661. {
  1662. QemuConsole *s;
  1663. int g_width = 80 * FONT_WIDTH;
  1664. int g_height = 24 * FONT_HEIGHT;
  1665. s = chr->opaque;
  1666. chr->chr_write = console_puts;
  1667. s->out_fifo.buf = s->out_fifo_buf;
  1668. s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
  1669. s->kbd_timer = timer_new_ms(QEMU_CLOCK_REALTIME, kbd_send_chars, s);
  1670. s->ds = ds;
  1671. s->y_displayed = 0;
  1672. s->y_base = 0;
  1673. s->total_height = DEFAULT_BACKSCROLL;
  1674. s->x = 0;
  1675. s->y = 0;
  1676. if (!s->surface) {
  1677. if (active_console && active_console->surface) {
  1678. g_width = surface_width(active_console->surface);
  1679. g_height = surface_height(active_console->surface);
  1680. }
  1681. s->surface = qemu_create_displaysurface(g_width, g_height);
  1682. }
  1683. s->hw_ops = &text_console_ops;
  1684. s->hw = s;
  1685. /* Set text attribute defaults */
  1686. s->t_attrib_default.bold = 0;
  1687. s->t_attrib_default.uline = 0;
  1688. s->t_attrib_default.blink = 0;
  1689. s->t_attrib_default.invers = 0;
  1690. s->t_attrib_default.unvisible = 0;
  1691. s->t_attrib_default.fgcol = COLOR_WHITE;
  1692. s->t_attrib_default.bgcol = COLOR_BLACK;
  1693. /* set current text attributes to default */
  1694. s->t_attrib = s->t_attrib_default;
  1695. text_console_resize(s);
  1696. if (chr->label) {
  1697. char msg[128];
  1698. int len;
  1699. s->t_attrib.bgcol = COLOR_BLUE;
  1700. len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
  1701. console_puts(chr, (uint8_t*)msg, len);
  1702. s->t_attrib = s->t_attrib_default;
  1703. }
  1704. qemu_chr_be_generic_open(chr);
  1705. if (chr->init)
  1706. chr->init(chr);
  1707. }
  1708. static CharDriverState *text_console_init(ChardevVC *vc)
  1709. {
  1710. CharDriverState *chr;
  1711. QemuConsole *s;
  1712. unsigned width = 0;
  1713. unsigned height = 0;
  1714. chr = qemu_chr_alloc();
  1715. if (vc->has_width) {
  1716. width = vc->width;
  1717. } else if (vc->has_cols) {
  1718. width = vc->cols * FONT_WIDTH;
  1719. }
  1720. if (vc->has_height) {
  1721. height = vc->height;
  1722. } else if (vc->has_rows) {
  1723. height = vc->rows * FONT_HEIGHT;
  1724. }
  1725. trace_console_txt_new(width, height);
  1726. if (width == 0 || height == 0) {
  1727. s = new_console(NULL, TEXT_CONSOLE, 0);
  1728. } else {
  1729. s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
  1730. s->surface = qemu_create_displaysurface(width, height);
  1731. }
  1732. if (!s) {
  1733. g_free(chr);
  1734. return NULL;
  1735. }
  1736. s->chr = chr;
  1737. chr->opaque = s;
  1738. chr->chr_set_echo = text_console_set_echo;
  1739. /* console/chardev init sometimes completes elsewhere in a 2nd
  1740. * stage, so defer OPENED events until they are fully initialized
  1741. */
  1742. chr->explicit_be_open = true;
  1743. if (display_state) {
  1744. text_console_do_init(chr, display_state);
  1745. }
  1746. return chr;
  1747. }
  1748. static VcHandler *vc_handler = text_console_init;
  1749. CharDriverState *vc_init(ChardevVC *vc)
  1750. {
  1751. return vc_handler(vc);
  1752. }
  1753. void register_vc_handler(VcHandler *handler)
  1754. {
  1755. vc_handler = handler;
  1756. }
  1757. void qemu_console_resize(QemuConsole *s, int width, int height)
  1758. {
  1759. DisplaySurface *surface;
  1760. assert(s->console_type == GRAPHIC_CONSOLE);
  1761. surface = qemu_create_displaysurface(width, height);
  1762. dpy_gfx_replace_surface(s, surface);
  1763. }
  1764. void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
  1765. int dst_x, int dst_y, int w, int h)
  1766. {
  1767. assert(con->console_type == GRAPHIC_CONSOLE);
  1768. dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h);
  1769. }
  1770. DisplaySurface *qemu_console_surface(QemuConsole *console)
  1771. {
  1772. return console->surface;
  1773. }
  1774. DisplayState *qemu_console_displaystate(QemuConsole *console)
  1775. {
  1776. return console->ds;
  1777. }
  1778. PixelFormat qemu_different_endianness_pixelformat(int bpp)
  1779. {
  1780. pixman_format_code_t fmt = qemu_default_pixman_format(bpp, false);
  1781. PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
  1782. return pf;
  1783. }
  1784. PixelFormat qemu_default_pixelformat(int bpp)
  1785. {
  1786. pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
  1787. PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
  1788. return pf;
  1789. }
  1790. static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend,
  1791. Error **errp)
  1792. {
  1793. int val;
  1794. backend->vc = g_new0(ChardevVC, 1);
  1795. val = qemu_opt_get_number(opts, "width", 0);
  1796. if (val != 0) {
  1797. backend->vc->has_width = true;
  1798. backend->vc->width = val;
  1799. }
  1800. val = qemu_opt_get_number(opts, "height", 0);
  1801. if (val != 0) {
  1802. backend->vc->has_height = true;
  1803. backend->vc->height = val;
  1804. }
  1805. val = qemu_opt_get_number(opts, "cols", 0);
  1806. if (val != 0) {
  1807. backend->vc->has_cols = true;
  1808. backend->vc->cols = val;
  1809. }
  1810. val = qemu_opt_get_number(opts, "rows", 0);
  1811. if (val != 0) {
  1812. backend->vc->has_rows = true;
  1813. backend->vc->rows = val;
  1814. }
  1815. }
  1816. static const TypeInfo qemu_console_info = {
  1817. .name = TYPE_QEMU_CONSOLE,
  1818. .parent = TYPE_OBJECT,
  1819. .instance_size = sizeof(QemuConsole),
  1820. .class_size = sizeof(QemuConsoleClass),
  1821. };
  1822. static void register_types(void)
  1823. {
  1824. type_register_static(&qemu_console_info);
  1825. register_char_driver("vc", CHARDEV_BACKEND_KIND_VC, qemu_chr_parse_vc);
  1826. }
  1827. type_init(register_types);