From 6a85c6ede66f723e1415552482e1c6640653efa2 Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Mon, 1 Aug 2022 16:33:44 +0200
Subject: amd64: /video/b device, provided by grub

---
 src/kernel/arch/amd64/32/paging.c     | 24 +++++-----
 src/kernel/arch/amd64/boot.c          | 13 ++++++
 src/kernel/arch/amd64/driver/fsroot.c |  4 +-
 src/kernel/arch/amd64/driver/video.c  | 82 +++++++++++++++++++++++++++++++++++
 src/kernel/arch/amd64/driver/video.h  | 11 +++++
 src/kernel/arch/amd64/multiboot.h     | 10 ++++-
 src/kernel/arch/amd64/multiboot.s     | 12 ++++-
 7 files changed, 141 insertions(+), 15 deletions(-)
 create mode 100644 src/kernel/arch/amd64/driver/video.c
 create mode 100644 src/kernel/arch/amd64/driver/video.h

(limited to 'src/kernel/arch')

diff --git a/src/kernel/arch/amd64/32/paging.c b/src/kernel/arch/amd64/32/paging.c
index f33168d..16c3526 100644
--- a/src/kernel/arch/amd64/32/paging.c
+++ b/src/kernel/arch/amd64/32/paging.c
@@ -8,7 +8,7 @@ __attribute__((aligned(4096)))
 static pe_generic_t pdpte_low[512]; // 0-512gb
 
 __attribute__((aligned(4096)))
-static pe_generic_t pde_low[512]; // 0-1gb
+static pe_generic_t pde_low[4][512]; // 4 * 0-1gb
 
 void pml4_identity_init(void) {
 	memset32(pml4_identity, 0, sizeof pml4_identity);
@@ -21,18 +21,20 @@ void pml4_identity_init(void) {
 		.address = ((uintptr_t)pdpte_low) >> 12,
 	};
 
-	pdpte_low[0] = (pe_generic_t) {
-		.present = 1,
-		.writeable = 1,
-		.address = ((uintptr_t)pde_low) >> 12,
-	};
-
-	for (int i = 0; i < 512; i++) {
-		pde_low[i] = (pe_generic_t) {
+	for (int i = 0; i < 4; i++) {
+		pdpte_low[i] = (pe_generic_t) {
 			.present = 1,
 			.writeable = 1,
-			.large = 1,
-			.address = (i * 2 * 1024 * 1024) >> 12,
+			.address = ((uintptr_t)&pde_low[i]) >> 12,
 		};
+
+		for (int j = 0; j < 512; j++) {
+			pde_low[i][j] = (pe_generic_t) {
+				.present = 1,
+				.writeable = 1,
+				.large = 1,
+				.address = (i * 512 + j) << 9,
+			};
+		}
 	}
 }
diff --git a/src/kernel/arch/amd64/boot.c b/src/kernel/arch/amd64/boot.c
index e8f9a26..301df52 100644
--- a/src/kernel/arch/amd64/boot.c
+++ b/src/kernel/arch/amd64/boot.c
@@ -3,6 +3,7 @@
 #include <kernel/arch/amd64/driver/fsroot.h>
 #include <kernel/arch/amd64/driver/ps2.h>
 #include <kernel/arch/amd64/driver/serial.h>
+#include <kernel/arch/amd64/driver/video.h>
 #include <kernel/arch/amd64/interrupts/idt.h>
 #include <kernel/arch/amd64/interrupts/irq.h>
 #include <kernel/arch/amd64/multiboot.h>
@@ -25,6 +26,7 @@ static void find_init(struct multiboot_info *multiboot, struct kmain_info *info)
 
 void kmain_early(struct multiboot_info *multiboot) {
 	struct kmain_info info;
+	struct fb_info vid;
 
 	tty_init();
 	kprintf("idt...");
@@ -45,5 +47,16 @@ void kmain_early(struct multiboot_info *multiboot) {
 	kprintf("ata...");
 	ata_init();
 
+	vid.b      = (void*)multiboot->framebuffer_addr;
+	vid.pitch  = multiboot->framebuffer_pitch;
+	vid.width  = multiboot->framebuffer_width;
+	vid.height = multiboot->framebuffer_height;
+	vid.bpp    = multiboot->framebuffer_bpp;
+
+	// TODO printf decimal
+	kprintf("framebuffer at 0x%x, %xx%x bpp 0x%x\n", vid.b, vid.width, vid.height, vid.bpp);
+	video_init(vid);
+
+
 	kmain(info);
 }
diff --git a/src/kernel/arch/amd64/driver/fsroot.c b/src/kernel/arch/amd64/driver/fsroot.c
index 2feaf67..e0f5e77 100644
--- a/src/kernel/arch/amd64/driver/fsroot.c
+++ b/src/kernel/arch/amd64/driver/fsroot.c
@@ -58,11 +58,13 @@ static int handle(struct vfs_request *req) {
 			switch (id) {
 				case HANDLE_ROOT: {
 					// TODO document directory read format
+					// TODO don't hardcode
 					const char src[] =
 						"vga\0"
 						"com1\0"
 						"ps2\0"
-						"ata/";
+						"ata/\0"
+						"video/";
 					return req_readcopy(req, src, sizeof src);
 				}
 				case HANDLE_VGA:
diff --git a/src/kernel/arch/amd64/driver/video.c b/src/kernel/arch/amd64/driver/video.c
new file mode 100644
index 0000000..8ace3d4
--- /dev/null
+++ b/src/kernel/arch/amd64/driver/video.c
@@ -0,0 +1,82 @@
+#include <camellia/fsutil.h>
+#include <camellia/errno.h>
+#include <kernel/arch/amd64/driver/video.h>
+#include <kernel/mem/virt.h>
+#include <kernel/panic.h>
+#include <kernel/vfs/request.h>
+
+static struct fb_info fb;
+
+enum {
+	H_ROOT,
+	H_FB,
+};
+
+/* stolen from fsroot.c, TODO shared copy? i guess? */
+static int req_readcopy(struct vfs_request *req, const void *buf, size_t len) {
+	if (!req->caller) return -1;
+	assert(req->type == VFSOP_READ);
+	fs_normslice(&req->offset, &req->output.len, len, false);
+	virt_cpy_to(
+			req->caller->pages, req->output.buf,
+			buf + req->offset, req->output.len);
+	/* read errors are ignored. TODO write docs */
+	return req->output.len;
+}
+
+static int handle(struct vfs_request *req) {
+	switch (req->type) {
+		case VFSOP_OPEN:
+			if (req->input.len == 1) {
+				return H_ROOT;
+			} else if (req->input.len == 2 && req->input.kern && req->input.buf_kern[1] == 'b') {
+				return H_FB;
+			} else {
+				return -1;
+			}
+
+		case VFSOP_READ:
+			if (req->id == H_ROOT) {
+				// TODO list available modes, e.g /640x480x24
+				const char src[] = "b";
+				return req_readcopy(req, src, sizeof src);
+			} else {
+				return req_readcopy(req, fb.b, fb.pitch * fb.height);
+			}
+
+		case VFSOP_WRITE:
+			if ((long)req->id != H_FB) {
+				return -1;
+			}
+			fs_normslice(&req->offset, &req->input.len, fb.pitch * fb.height, false);
+			if (!virt_cpy_from(req->caller->pages, fb.b + req->offset,
+					req->input.buf, req->input.len))
+			{
+				panic_invalid_state();
+				return -EFAULT;
+			}
+			return req->input.len;
+
+		default:
+			return -1;
+	}
+}
+
+static void accept(struct vfs_request *req) {
+	if (req->caller) {
+		vfsreq_finish_short(req, handle(req));
+	} else {
+		vfsreq_finish_short(req, -1);
+	}
+}
+
+static bool is_ready(struct vfs_backend *self) {
+	(void)self;
+	return true;
+}
+
+static struct vfs_backend backend = BACKEND_KERN(is_ready, accept);
+void video_init(struct fb_info fb_) {
+	fb = fb_;
+	vfs_mount_root_register("/video", &backend);
+}
diff --git a/src/kernel/arch/amd64/driver/video.h b/src/kernel/arch/amd64/driver/video.h
new file mode 100644
index 0000000..c1680c4
--- /dev/null
+++ b/src/kernel/arch/amd64/driver/video.h
@@ -0,0 +1,11 @@
+#pragma once
+#include <stdint.h>
+
+struct fb_info {
+	char *b;
+	uint32_t width, height;
+	uint32_t pitch; /* width in bytes of a single scanline */
+	uint8_t bpp;
+};
+
+void video_init(struct fb_info);
diff --git a/src/kernel/arch/amd64/multiboot.h b/src/kernel/arch/amd64/multiboot.h
index c6a2650..526dd4c 100644
--- a/src/kernel/arch/amd64/multiboot.h
+++ b/src/kernel/arch/amd64/multiboot.h
@@ -25,5 +25,13 @@ struct multiboot_info {
 	uint32_t mods_count;
 	uint32_t mods;
 
-	// [...]
+	uint8_t _padding[60];
+
+	uint64_t framebuffer_addr;
+	uint32_t framebuffer_pitch;
+	uint32_t framebuffer_width;
+	uint32_t framebuffer_height;
+	uint8_t framebuffer_bpp;
+	uint8_t framebuffer_type;
+	uint8_t color_info[6];
 } __attribute__((packed));
diff --git a/src/kernel/arch/amd64/multiboot.s b/src/kernel/arch/amd64/multiboot.s
index dc19b36..c809297 100644
--- a/src/kernel/arch/amd64/multiboot.s
+++ b/src/kernel/arch/amd64/multiboot.s
@@ -1,7 +1,8 @@
 .set MAGIC, 0x1BADB002
 
-/* 1<<0  - align modules on page boundaries. */
-.set FLAGS,        1<<0
+/* 1<<0  - align modules on page boundaries.
+   1<<2  - enable graphic mode fields */
+.set FLAGS, 1<<0 | 1<<2
 .set CHECKSUM, -(MAGIC + FLAGS)
 
 .section .multiboot
@@ -10,3 +11,10 @@ multiboot_header:
 	.long MAGIC
 	.long FLAGS
 	.long CHECKSUM
+
+	.skip 5 * 4
+
+	.long 0
+	.long 640
+	.long 480
+	.long 0
-- 
cgit v1.2.3