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