1 // Copyright 2016 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6 
7 #include <assert.h>
8 #include <dev/udisplay.h>
9 #include <ktl/move.h>
10 #include <lib/crashlog.h>
11 #include <lib/debuglog.h>
12 #include <lib/gfxconsole.h>
13 #include <lib/io.h>
14 #include <platform.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <trace.h>
18 #include <vm/vm_aspace.h>
19 #include <vm/vm_object.h>
20 
21 #define LOCAL_TRACE 0
22 
23 constexpr uint kFramebufferArchMmuFlags = ARCH_MMU_FLAG_PERM_READ | ARCH_MMU_FLAG_PERM_WRITE;
24 
25 static char crashlogbuf[4096u];
26 
27 struct udisplay_info {
28     void* framebuffer_virt;
29     size_t framebuffer_size;
30     struct display_info info;
31     fbl::RefPtr<VmMapping> framebuffer_vmo_mapping;
32 };
33 
34 static struct udisplay_info g_udisplay = {};
35 
udisplay_init(void)36 zx_status_t udisplay_init(void) {
37     return ZX_OK;
38 }
39 
dlog_bluescreen_halt(void)40 void dlog_bluescreen_halt(void) {
41     size_t len = crashlog_to_string(crashlogbuf, sizeof(crashlogbuf));
42     platform_stow_crashlog(crashlogbuf, len);
43     if (g_udisplay.framebuffer_virt == 0)
44         return;
45 }
46 
udisplay_clear_framebuffer_vmo()47 void udisplay_clear_framebuffer_vmo() {
48     if (g_udisplay.framebuffer_vmo_mapping) {
49         g_udisplay.framebuffer_size = 0;
50         g_udisplay.framebuffer_virt = 0;
51         g_udisplay.framebuffer_vmo_mapping->Destroy();
52         g_udisplay.framebuffer_vmo_mapping = nullptr;
53     }
54 }
55 
udisplay_set_framebuffer(fbl::RefPtr<VmObject> vmo)56 zx_status_t udisplay_set_framebuffer(fbl::RefPtr<VmObject> vmo) {
57     udisplay_clear_framebuffer_vmo();
58 
59     const size_t size = vmo->size();
60     fbl::RefPtr<VmMapping> mapping;
61     zx_status_t status = VmAspace::kernel_aspace()->RootVmar()->CreateVmMapping(
62         0 /* ignored */, size, 0 /* align pow2 */, 0 /* vmar flags */,
63         ktl::move(vmo), 0, kFramebufferArchMmuFlags, "framebuffer_vmo", &mapping);
64     if (status != ZX_OK)
65         return status;
66 
67     status = mapping->MapRange(0, size, true);
68     if (status != ZX_OK) {
69         mapping->Destroy();
70         return status;
71     }
72 
73     g_udisplay.framebuffer_virt = reinterpret_cast<void*>(mapping->base());
74     g_udisplay.framebuffer_size = size;
75     g_udisplay.framebuffer_vmo_mapping = mapping;
76     return ZX_OK;
77 }
78 
udisplay_set_display_info(struct display_info * display)79 zx_status_t udisplay_set_display_info(struct display_info* display) {
80     memcpy(&g_udisplay.info, display, sizeof(struct display_info));
81     return ZX_OK;
82 }
83 
udisplay_bind_gfxconsole(void)84 zx_status_t udisplay_bind_gfxconsole(void) {
85     if (g_udisplay.framebuffer_virt == 0)
86         return ZX_ERR_NOT_FOUND;
87 
88     // bind the display to the gfxconsole
89     g_udisplay.info.framebuffer = g_udisplay.framebuffer_virt;
90     g_udisplay.info.flags = DISPLAY_FLAG_NEEDS_CACHE_FLUSH | DISPLAY_FLAG_CRASH_FRAMEBUFFER;
91     gfxconsole_bind_display(&g_udisplay.info, nullptr);
92 
93     return ZX_OK;
94 }
95