Allow bootloader bitmap framebuffer modesetting.
This commit is contained in:
parent
8c7c6fa59f
commit
dad5c57f33
|
@ -8,3 +8,4 @@
|
||||||
*.out
|
*.out
|
||||||
kb/default-kblayout
|
kb/default-kblayout
|
||||||
kb/default-kblayout.h
|
kb/default-kblayout.h
|
||||||
|
vgafont.h
|
||||||
|
|
|
@ -200,7 +200,10 @@ endif
|
||||||
kb/default-kblayout.h: kb/default-kblayout
|
kb/default-kblayout.h: kb/default-kblayout
|
||||||
carray -cgis --uint8_t --guard=SORTIX_KB_DEFAULT_KBLAYOUT_H --identifier=default_kblayout $< -o $@
|
carray -cgis --uint8_t --guard=SORTIX_KB_DEFAULT_KBLAYOUT_H --identifier=default_kblayout $< -o $@
|
||||||
|
|
||||||
*.cpp */*.cpp */*/*.cpp: | kb/default-kblayout.h
|
vgafont.h: vgafont.f16
|
||||||
|
carray -gis --uint8_t --guard=VGAFONT_H --identifier=vgafont $< -o $@
|
||||||
|
|
||||||
|
*.cpp */*.cpp */*/*.cpp: | kb/default-kblayout.h vgafont.h
|
||||||
|
|
||||||
%.o: %.cpp
|
%.o: %.cpp
|
||||||
$(CXX) -c $< -o $@ $(CPPFLAGS) $(CXXFLAGS)
|
$(CXX) -c $< -o $@ $(CPPFLAGS) $(CXXFLAGS)
|
||||||
|
@ -213,6 +216,7 @@ clean:
|
||||||
rm -f *.bin *.out *.tmp
|
rm -f *.bin *.out *.tmp
|
||||||
rm -f *.o */*.o */*/*.o
|
rm -f *.o */*.o */*/*.o
|
||||||
rm -f kb/default-kblayout kb/default-kblayout.h
|
rm -f kb/default-kblayout kb/default-kblayout.h
|
||||||
|
rm -f vgafont.h
|
||||||
|
|
||||||
# Installation into sysroot
|
# Installation into sysroot
|
||||||
install: install-headers install-kernel
|
install: install-headers install-kernel
|
||||||
|
|
|
@ -42,6 +42,12 @@ class TextBufferHandle;
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
namespace Log {
|
namespace Log {
|
||||||
|
|
||||||
|
extern uint8_t* fallback_framebuffer;
|
||||||
|
extern size_t fallback_framebuffer_bpp;
|
||||||
|
extern size_t fallback_framebuffer_pitch;
|
||||||
|
extern size_t fallback_framebuffer_width;
|
||||||
|
extern size_t fallback_framebuffer_height;
|
||||||
|
|
||||||
extern TextBufferHandle* device_textbufhandle;
|
extern TextBufferHandle* device_textbufhandle;
|
||||||
extern size_t (*device_callback)(void*, const char*, size_t);
|
extern size_t (*device_callback)(void*, const char*, size_t);
|
||||||
extern size_t (*device_width)(void*);
|
extern size_t (*device_width)(void*);
|
||||||
|
|
|
@ -87,6 +87,7 @@ public:
|
||||||
virtual void SetCursorEnabled(bool enablecursor) = 0;
|
virtual void SetCursorEnabled(bool enablecursor) = 0;
|
||||||
virtual TextPos GetCursorPos() const = 0;
|
virtual TextPos GetCursorPos() const = 0;
|
||||||
virtual void SetCursorPos(TextPos cursorpos) = 0;
|
virtual void SetCursorPos(TextPos cursorpos) = 0;
|
||||||
|
virtual void SpawnThreads() = 0;
|
||||||
virtual bool EmergencyIsImpaired() = 0;
|
virtual bool EmergencyIsImpaired() = 0;
|
||||||
virtual bool EmergencyRecoup() = 0;
|
virtual bool EmergencyRecoup() = 0;
|
||||||
virtual void EmergencyReset() = 0;
|
virtual void EmergencyReset() = 0;
|
||||||
|
|
|
@ -483,6 +483,15 @@ static void BootThread(void* /*user*/)
|
||||||
// Hello, threaded world! You can now regard the kernel as a multi-threaded
|
// Hello, threaded world! You can now regard the kernel as a multi-threaded
|
||||||
// process with super-root access to the system. Before we boot the full
|
// process with super-root access to the system. Before we boot the full
|
||||||
// system we need to start some worker threads.
|
// system we need to start some worker threads.
|
||||||
|
|
||||||
|
// Spawn worker threads to asyncronously draw the console thread.
|
||||||
|
TextBuffer* textbuf = Log::device_textbufhandle->Acquire();
|
||||||
|
if ( textbuf )
|
||||||
|
{
|
||||||
|
textbuf->SpawnThreads();
|
||||||
|
Log::device_textbufhandle->Release(textbuf);
|
||||||
|
}
|
||||||
|
|
||||||
// Let's create the interrupt worker thread that executes additional work
|
// Let's create the interrupt worker thread that executes additional work
|
||||||
// requested by interrupt handlers, where such work isn't safe.
|
// requested by interrupt handlers, where such work isn't safe.
|
||||||
Thread* interruptworker = RunKernelThread(Interrupt::WorkerThread, NULL);
|
Thread* interruptworker = RunKernelThread(Interrupt::WorkerThread, NULL);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014.
|
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014, 2015.
|
||||||
|
|
||||||
This file is part of Sortix.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -123,13 +123,12 @@ LFBTextBuffer* CreateLFBTextBuffer(uint8_t* lfb, uint32_t lfbformat,
|
||||||
memset(lfb + scansize * y, 0, lfbformat/8UL * xres);
|
memset(lfb + scansize * y, 0, lfbformat/8UL * xres);
|
||||||
ret->emergency_state = false;
|
ret->emergency_state = false;
|
||||||
|
|
||||||
ret->queue_thread = true;
|
if ( !kernel_process )
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret->queue_thread = true; // Visible to new thread.
|
||||||
if ( !RunKernelThread(kernel_process, LFBTextBuffer__RenderThread, ret) )
|
if ( !RunKernelThread(kernel_process, LFBTextBuffer__RenderThread, ret) )
|
||||||
{
|
|
||||||
ret->queue_thread = false;
|
ret->queue_thread = false;
|
||||||
delete ret;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -147,6 +146,16 @@ cleanup_done:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LFBTextBuffer::SpawnThreads()
|
||||||
|
{
|
||||||
|
if ( queue_thread )
|
||||||
|
return;
|
||||||
|
Process* kernel_process = Scheduler::GetKernelProcess();
|
||||||
|
queue_thread = true; // Visible to new thread.
|
||||||
|
if ( !RunKernelThread(kernel_process, LFBTextBuffer__RenderThread, this) )
|
||||||
|
queue_thread = false;
|
||||||
|
}
|
||||||
|
|
||||||
LFBTextBuffer::LFBTextBuffer()
|
LFBTextBuffer::LFBTextBuffer()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -315,7 +324,7 @@ void LFBTextBuffer::RenderRange(TextPos from, TextPos to)
|
||||||
|
|
||||||
void LFBTextBuffer::IssueCommand(TextBufferCmd* cmd)
|
void LFBTextBuffer::IssueCommand(TextBufferCmd* cmd)
|
||||||
{
|
{
|
||||||
if ( emergency_state )
|
if ( !queue_thread || emergency_state )
|
||||||
{
|
{
|
||||||
bool exit_requested = false;
|
bool exit_requested = false;
|
||||||
bool sync_requested = false;
|
bool sync_requested = false;
|
||||||
|
@ -337,7 +346,7 @@ void LFBTextBuffer::IssueCommand(TextBufferCmd* cmd)
|
||||||
|
|
||||||
void LFBTextBuffer::StopRendering()
|
void LFBTextBuffer::StopRendering()
|
||||||
{
|
{
|
||||||
if ( emergency_state )
|
if ( !queue_thread || emergency_state )
|
||||||
return;
|
return;
|
||||||
TextBufferCmd cmd;
|
TextBufferCmd cmd;
|
||||||
cmd.type = TEXTBUFCMD_PAUSE;
|
cmd.type = TEXTBUFCMD_PAUSE;
|
||||||
|
@ -349,7 +358,7 @@ void LFBTextBuffer::StopRendering()
|
||||||
|
|
||||||
void LFBTextBuffer::ResumeRendering()
|
void LFBTextBuffer::ResumeRendering()
|
||||||
{
|
{
|
||||||
if ( emergency_state )
|
if ( !queue_thread || emergency_state )
|
||||||
return;
|
return;
|
||||||
ScopedLock lock(&queue_lock);
|
ScopedLock lock(&queue_lock);
|
||||||
queue_is_paused = false;
|
queue_is_paused = false;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014.
|
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014, 2015.
|
||||||
|
|
||||||
This file is part of Sortix.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -83,6 +83,7 @@ public:
|
||||||
virtual void SetCursorEnabled(bool enablecursor);
|
virtual void SetCursorEnabled(bool enablecursor);
|
||||||
virtual TextPos GetCursorPos() const;
|
virtual TextPos GetCursorPos() const;
|
||||||
virtual void SetCursorPos(TextPos newcursorpos);
|
virtual void SetCursorPos(TextPos newcursorpos);
|
||||||
|
virtual void SpawnThreads();
|
||||||
virtual bool EmergencyIsImpaired();
|
virtual bool EmergencyIsImpaired();
|
||||||
virtual bool EmergencyRecoup();
|
virtual bool EmergencyRecoup();
|
||||||
virtual void EmergencyReset();
|
virtual void EmergencyReset();
|
||||||
|
|
|
@ -22,19 +22,31 @@
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sortix/kernel/addralloc.h>
|
||||||
#include <sortix/kernel/kernel.h>
|
#include <sortix/kernel/kernel.h>
|
||||||
#include <sortix/kernel/log.h>
|
#include <sortix/kernel/log.h>
|
||||||
|
#include <sortix/kernel/pci.h>
|
||||||
|
#include <sortix/kernel/pci-mmio.h>
|
||||||
#include <sortix/kernel/textbuffer.h>
|
#include <sortix/kernel/textbuffer.h>
|
||||||
|
|
||||||
|
#include "lfbtextbuffer.h"
|
||||||
|
#include "multiboot.h"
|
||||||
#include "textterminal.h"
|
#include "textterminal.h"
|
||||||
#include "vgatextbuffer.h"
|
#include "vgatextbuffer.h"
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
namespace Log {
|
namespace Log {
|
||||||
|
|
||||||
|
uint8_t* fallback_framebuffer = NULL;
|
||||||
|
size_t fallback_framebuffer_bpp = 0;
|
||||||
|
size_t fallback_framebuffer_pitch = 0;
|
||||||
|
size_t fallback_framebuffer_width = 0;
|
||||||
|
size_t fallback_framebuffer_height = 0;
|
||||||
|
|
||||||
TextBufferHandle* device_textbufhandle = NULL;
|
TextBufferHandle* device_textbufhandle = NULL;
|
||||||
size_t (*device_callback)(void*, const char*, size_t) = NULL;
|
size_t (*device_callback)(void*, const char*, size_t) = NULL;
|
||||||
size_t (*device_width)(void*) = NULL;
|
size_t (*device_width)(void*) = NULL;
|
||||||
|
@ -126,7 +138,34 @@ void Init(multiboot_info_t* bootinfo)
|
||||||
|
|
||||||
// Create the backend text buffer.
|
// Create the backend text buffer.
|
||||||
TextBuffer* textbuf;
|
TextBuffer* textbuf;
|
||||||
if ( true )
|
if ( (bootinfo->flags & MULTIBOOT_INFO_FRAMEBUFFER_INFO) &&
|
||||||
|
bootinfo->framebuffer_type != MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT )
|
||||||
|
{
|
||||||
|
assert(bootinfo->framebuffer_type == MULTIBOOT_FRAMEBUFFER_TYPE_RGB);
|
||||||
|
assert(bootinfo->framebuffer_bpp == 32);
|
||||||
|
assert(0 < bootinfo->framebuffer_width);
|
||||||
|
assert(0 < bootinfo->framebuffer_height);
|
||||||
|
pcibar_t fakebar;
|
||||||
|
fakebar.addr_raw = bootinfo->framebuffer_addr;
|
||||||
|
fakebar.size_raw = (uint64_t) bootinfo->framebuffer_pitch * bootinfo->framebuffer_height;
|
||||||
|
fakebar.addr_raw |= PCIBAR_TYPE_64BIT;
|
||||||
|
addralloc_t fb_alloc;
|
||||||
|
if ( !MapPCIBAR(&fb_alloc, fakebar, MAP_PCI_BAR_WRITE_COMBINE) )
|
||||||
|
Panic("Framebuffer setup failure.");
|
||||||
|
uint8_t* lfb = (uint8_t*) fb_alloc.from;
|
||||||
|
uint32_t lfbformat = bootinfo->framebuffer_bpp;
|
||||||
|
size_t scansize = bootinfo->framebuffer_pitch;
|
||||||
|
textbuf = CreateLFBTextBuffer(lfb, lfbformat, bootinfo->framebuffer_width,
|
||||||
|
bootinfo->framebuffer_height, scansize);
|
||||||
|
if ( !textbuf )
|
||||||
|
Panic(oom_msg);
|
||||||
|
fallback_framebuffer = lfb;
|
||||||
|
fallback_framebuffer_bpp = lfbformat;
|
||||||
|
fallback_framebuffer_width = bootinfo->framebuffer_width;
|
||||||
|
fallback_framebuffer_height = bootinfo->framebuffer_height;
|
||||||
|
fallback_framebuffer_pitch = bootinfo->framebuffer_pitch;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
uint16_t* const VGAFB = (uint16_t*) 0xB8000;
|
uint16_t* const VGAFB = (uint16_t*) 0xB8000;
|
||||||
const size_t VGA_WIDTH = 80;
|
const size_t VGA_WIDTH = 80;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015.
|
||||||
|
|
||||||
This file is part of Sortix.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -378,6 +378,8 @@ Process* GetInitProcess()
|
||||||
|
|
||||||
Process* GetKernelProcess()
|
Process* GetKernelProcess()
|
||||||
{
|
{
|
||||||
|
if ( !idle_thread )
|
||||||
|
return NULL;
|
||||||
return idle_thread->process;
|
return idle_thread->process;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2015.
|
||||||
|
|
||||||
This file is part of Sortix.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -39,8 +39,7 @@
|
||||||
|
|
||||||
#include "fs/util.h"
|
#include "fs/util.h"
|
||||||
#include "vga.h"
|
#include "vga.h"
|
||||||
|
#include "vgafont.h"
|
||||||
#define TEST_VGAFONT 0
|
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
namespace VGA {
|
namespace VGA {
|
||||||
|
@ -49,8 +48,6 @@ uint8_t* const VGA = (uint8_t* const) 0xB8000;
|
||||||
const unsigned WIDTH = 80;
|
const unsigned WIDTH = 80;
|
||||||
const unsigned HEIGHT = 25;
|
const unsigned HEIGHT = 25;
|
||||||
const size_t VGA_SIZE = sizeof(uint16_t) * WIDTH * HEIGHT;
|
const size_t VGA_SIZE = sizeof(uint16_t) * WIDTH * HEIGHT;
|
||||||
size_t vgafontsize;
|
|
||||||
uint8_t* vgafont;
|
|
||||||
|
|
||||||
static void WriteIndex(uint16_t port, uint8_t index, uint8_t value)
|
static void WriteIndex(uint16_t port, uint8_t index, uint8_t value)
|
||||||
{
|
{
|
||||||
|
@ -103,26 +100,6 @@ static void FetchVGAFont(uint8_t* font)
|
||||||
WriteIndex(0x03CE, 0x04, old_03ce_04);
|
WriteIndex(0x03CE, 0x04, old_03ce_04);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TEST_VGAFONT
|
|
||||||
static void PrintFontChar(const uint8_t* font, unsigned char c)
|
|
||||||
{
|
|
||||||
const uint8_t* glyph = font + VGA_FONT_CHARSIZE * (size_t) c;
|
|
||||||
for ( size_t y = 0; y < VGA_FONT_HEIGHT; y++ )
|
|
||||||
{
|
|
||||||
for ( size_t x = 0; x < VGA_FONT_WIDTH; x++ )
|
|
||||||
{
|
|
||||||
size_t bitindex = y * VGA_FONT_WIDTH + x;
|
|
||||||
uint8_t bitmap = glyph[bitindex/8UL];
|
|
||||||
uint8_t bitmod = bitindex % 8UL;
|
|
||||||
uint8_t bitmask = 1U << bitmod;
|
|
||||||
const char* toprint = (bitmap & bitmask) ? "X" : " ";
|
|
||||||
Log::Print(toprint);
|
|
||||||
}
|
|
||||||
Log::Print("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const uint8_t* GetFont()
|
const uint8_t* GetFont()
|
||||||
{
|
{
|
||||||
return vgafont;
|
return vgafont;
|
||||||
|
@ -130,26 +107,23 @@ const uint8_t* GetFont()
|
||||||
|
|
||||||
void Init(const char* devpath, Ref<Descriptor> slashdev)
|
void Init(const char* devpath, Ref<Descriptor> slashdev)
|
||||||
{
|
{
|
||||||
vgafontsize = VGA_FONT_NUMCHARS * VGA_FONT_CHARSIZE;
|
if ( !Log::fallback_framebuffer )
|
||||||
if ( !(vgafont = new uint8_t[vgafontsize]) )
|
FetchVGAFont(vgafont);
|
||||||
Panic("Unable to allocate vga font buffer");
|
|
||||||
FetchVGAFont(vgafont);
|
|
||||||
#if TEST_VGAFONT
|
|
||||||
PrintFontChar(vgafont, 'A');
|
|
||||||
PrintFontChar(vgafont, 'S');
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ioctx_t ctx; SetupKernelIOCtx(&ctx);
|
ioctx_t ctx; SetupKernelIOCtx(&ctx);
|
||||||
|
|
||||||
// Setup the vgafont device.
|
// Setup the vgafont device.
|
||||||
Ref<Inode> vgafontnode(new UtilMemoryBuffer(slashdev->dev, (ino_t) 0, 0, 0,
|
Ref<Inode> vgafontnode(new UtilMemoryBuffer(slashdev->dev, (ino_t) 0, 0, 0,
|
||||||
0660, vgafont, vgafontsize,
|
0660, vgafont, sizeof(vgafont),
|
||||||
false, false));
|
false, false));
|
||||||
if ( !vgafontnode )
|
if ( !vgafontnode )
|
||||||
PanicF("Unable to allocate %s/vgafont inode.", devpath);
|
PanicF("Unable to allocate %s/vgafont inode.", devpath);
|
||||||
if ( LinkInodeInDir(&ctx, slashdev, "vgafont", vgafontnode) != 0 )
|
if ( LinkInodeInDir(&ctx, slashdev, "vgafont", vgafontnode) != 0 )
|
||||||
PanicF("Unable to link %s/vgafont to vga font.", devpath);
|
PanicF("Unable to link %s/vgafont to vga font.", devpath);
|
||||||
|
|
||||||
|
if ( Log::fallback_framebuffer )
|
||||||
|
return;
|
||||||
|
|
||||||
// Setup the vga device.
|
// Setup the vga device.
|
||||||
Ref<Inode> vganode(new UtilMemoryBuffer(slashdev->dev, (ino_t) 0, 0, 0,
|
Ref<Inode> vganode(new UtilMemoryBuffer(slashdev->dev, (ino_t) 0, 0, 0,
|
||||||
0660, VGA, VGA_SIZE, true, false));
|
0660, VGA, VGA_SIZE, true, false));
|
||||||
|
|
Binary file not shown.
|
@ -192,6 +192,10 @@ void VGATextBuffer::UpdateCursor()
|
||||||
VGA::SetCursor(width, height-1);
|
VGA::SetCursor(width, height-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VGATextBuffer::SpawnThreads()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool VGATextBuffer::EmergencyIsImpaired()
|
bool VGATextBuffer::EmergencyIsImpaired()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -48,6 +48,7 @@ public:
|
||||||
virtual void SetCursorEnabled(bool enablecursor);
|
virtual void SetCursorEnabled(bool enablecursor);
|
||||||
virtual TextPos GetCursorPos() const;
|
virtual TextPos GetCursorPos() const;
|
||||||
virtual void SetCursorPos(TextPos cursorpos);
|
virtual void SetCursorPos(TextPos cursorpos);
|
||||||
|
virtual void SpawnThreads();
|
||||||
virtual bool EmergencyIsImpaired();
|
virtual bool EmergencyIsImpaired();
|
||||||
virtual bool EmergencyRecoup();
|
virtual bool EmergencyRecoup();
|
||||||
virtual void EmergencyReset();
|
virtual void EmergencyReset();
|
||||||
|
|
251
kernel/video.cpp
251
kernel/video.cpp
|
@ -29,6 +29,7 @@
|
||||||
#include <sortix/kernel/copy.h>
|
#include <sortix/kernel/copy.h>
|
||||||
#include <sortix/kernel/kernel.h>
|
#include <sortix/kernel/kernel.h>
|
||||||
#include <sortix/kernel/kthread.h>
|
#include <sortix/kernel/kthread.h>
|
||||||
|
#include <sortix/kernel/log.h>
|
||||||
#include <sortix/kernel/string.h>
|
#include <sortix/kernel/string.h>
|
||||||
#include <sortix/kernel/syscall.h>
|
#include <sortix/kernel/syscall.h>
|
||||||
#include <sortix/kernel/textbuffer.h>
|
#include <sortix/kernel/textbuffer.h>
|
||||||
|
@ -222,6 +223,20 @@ static int SetDriver(void* ptr, size_t size)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct dispmsg_crtc_mode GetLogFallbackMode()
|
||||||
|
{
|
||||||
|
struct dispmsg_crtc_mode mode;
|
||||||
|
memset(&mode, 0, sizeof(mode));
|
||||||
|
mode.control = DISPMSG_CONTROL_VALID;
|
||||||
|
mode.fb_format = Log::fallback_framebuffer_bpp;
|
||||||
|
mode.view_xres = (uint32_t) Log::fallback_framebuffer_width;
|
||||||
|
mode.view_yres = (uint32_t) Log::fallback_framebuffer_height;
|
||||||
|
mode.fb_location = 0;
|
||||||
|
mode.pitch = Log::fallback_framebuffer_width *
|
||||||
|
Log::fallback_framebuffer_bpp / 8;
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
static int SetCrtcMode(void* ptr, size_t size)
|
static int SetCrtcMode(void* ptr, size_t size)
|
||||||
{
|
{
|
||||||
struct dispmsg_set_crtc_mode msg;
|
struct dispmsg_set_crtc_mode msg;
|
||||||
|
@ -232,18 +247,32 @@ static int SetCrtcMode(void* ptr, size_t size)
|
||||||
|
|
||||||
ScopedLock lock(&video_lock);
|
ScopedLock lock(&video_lock);
|
||||||
|
|
||||||
if ( num_devices <= msg.device )
|
if ( msg.device < num_devices )
|
||||||
|
{
|
||||||
|
DeviceEntry* device_entry = &devices[msg.device];
|
||||||
|
VideoDevice* device = device_entry->device;
|
||||||
|
if ( !device->SwitchMode(msg.connector, msg.mode) )
|
||||||
|
return -1;
|
||||||
|
// TODO: This could potentially fail.
|
||||||
|
if ( msg.device == ONE_AND_ONLY_DEVICE &&
|
||||||
|
msg.connector == ONE_AND_ONLY_CONNECTOR )
|
||||||
|
{
|
||||||
|
Log::fallback_framebuffer = NULL;
|
||||||
|
Log::device_textbufhandle->Replace(device->CreateTextBuffer(msg.connector));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( Log::fallback_framebuffer &&
|
||||||
|
msg.device == ONE_AND_ONLY_DEVICE &&
|
||||||
|
msg.connector == ONE_AND_ONLY_CONNECTOR )
|
||||||
|
{
|
||||||
|
struct dispmsg_crtc_mode fallback_mode = GetLogFallbackMode();
|
||||||
|
if ( memcmp(&msg.mode, &fallback_mode, sizeof(msg.mode)) != 0 )
|
||||||
|
return errno = EINVAL, -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return errno = ENODEV, -1;
|
return errno = ENODEV, -1;
|
||||||
|
}
|
||||||
DeviceEntry* device_entry = &devices[msg.device];
|
|
||||||
VideoDevice* device = device_entry->device;
|
|
||||||
if ( !device->SwitchMode(msg.connector, msg.mode) )
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
// TODO: This could potentially fail.
|
|
||||||
if ( msg.device == ONE_AND_ONLY_DEVICE &&
|
|
||||||
msg.connector == ONE_AND_ONLY_CONNECTOR )
|
|
||||||
Log::device_textbufhandle->Replace(device->CreateTextBuffer(msg.connector));
|
|
||||||
|
|
||||||
// No need to respond.
|
// No need to respond.
|
||||||
|
|
||||||
|
@ -260,17 +289,27 @@ static int GetCrtcMode(void* ptr, size_t size)
|
||||||
|
|
||||||
ScopedLock lock(&video_lock);
|
ScopedLock lock(&video_lock);
|
||||||
|
|
||||||
if ( num_devices <= msg.device )
|
struct dispmsg_crtc_mode mode;
|
||||||
|
if ( Log::fallback_framebuffer &&
|
||||||
|
msg.device == ONE_AND_ONLY_DEVICE &&
|
||||||
|
msg.connector == ONE_AND_ONLY_CONNECTOR )
|
||||||
|
{
|
||||||
|
mode = GetLogFallbackMode();
|
||||||
|
}
|
||||||
|
else if ( msg.device < num_devices )
|
||||||
|
{
|
||||||
|
DeviceEntry* device_entry = &devices[msg.device];
|
||||||
|
VideoDevice* device = device_entry->device;
|
||||||
|
// TODO: There is no real way to detect failure here.
|
||||||
|
errno = 0;
|
||||||
|
mode = device->GetCurrentMode(msg.connector);
|
||||||
|
if ( !(mode.control & DISPMSG_CONTROL_VALID) && errno != 0 )
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return errno = ENODEV, -1;
|
return errno = ENODEV, -1;
|
||||||
|
}
|
||||||
DeviceEntry* device_entry = &devices[msg.device];
|
|
||||||
VideoDevice* device = device_entry->device;
|
|
||||||
|
|
||||||
// TODO: There is no real way to detect failure here.
|
|
||||||
errno = 0;
|
|
||||||
struct dispmsg_crtc_mode mode = device->GetCurrentMode(msg.connector);
|
|
||||||
if ( !(mode.control & DISPMSG_CONTROL_VALID) && errno != 0 )
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
msg.mode = mode;
|
msg.mode = mode;
|
||||||
|
|
||||||
|
@ -290,16 +329,28 @@ static int GetCrtcModes(void* ptr, size_t size)
|
||||||
|
|
||||||
ScopedLock lock(&video_lock);
|
ScopedLock lock(&video_lock);
|
||||||
|
|
||||||
if ( num_devices <= msg.device )
|
size_t nummodes = 0;
|
||||||
|
struct dispmsg_crtc_mode* modes = NULL;
|
||||||
|
if ( msg.device < num_devices )
|
||||||
|
{
|
||||||
|
DeviceEntry* device_entry = &devices[msg.device];
|
||||||
|
VideoDevice* device = device_entry->device;
|
||||||
|
modes = device->GetModes(msg.connector, &nummodes);
|
||||||
|
if ( !modes )
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if ( Log::fallback_framebuffer &&
|
||||||
|
msg.device == ONE_AND_ONLY_DEVICE &&
|
||||||
|
msg.connector == ONE_AND_ONLY_CONNECTOR )
|
||||||
|
{
|
||||||
|
if ( !(modes = new struct dispmsg_crtc_mode[1]) )
|
||||||
|
return -1;
|
||||||
|
modes[nummodes++] = GetLogFallbackMode();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return errno = ENODEV, -1;
|
return errno = ENODEV, -1;
|
||||||
|
}
|
||||||
DeviceEntry* device_entry = &devices[msg.device];
|
|
||||||
VideoDevice* device = device_entry->device;
|
|
||||||
|
|
||||||
size_t nummodes;
|
|
||||||
struct dispmsg_crtc_mode* modes = device->GetModes(msg.connector, &nummodes);
|
|
||||||
if ( !modes )
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
size_t requested_modes = msg.modes_length;
|
size_t requested_modes = msg.modes_length;
|
||||||
msg.modes_length = nummodes;
|
msg.modes_length = nummodes;
|
||||||
|
@ -324,7 +375,6 @@ static int GetCrtcModes(void* ptr, size_t size)
|
||||||
|
|
||||||
delete[] modes;
|
delete[] modes;
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,8 +388,23 @@ static int GetMemorySize(void* ptr, size_t size)
|
||||||
|
|
||||||
ScopedLock lock(&video_lock);
|
ScopedLock lock(&video_lock);
|
||||||
|
|
||||||
if ( num_devices <= msg.device )
|
if ( Log::fallback_framebuffer &&
|
||||||
|
msg.device == ONE_AND_ONLY_DEVICE )
|
||||||
|
{
|
||||||
|
msg.memory_size = Log::fallback_framebuffer_width *
|
||||||
|
Log::fallback_framebuffer_height *
|
||||||
|
Log::fallback_framebuffer_bpp / 8;
|
||||||
|
}
|
||||||
|
else if ( msg.device < num_devices )
|
||||||
|
{
|
||||||
|
DeviceEntry* device_entry = &devices[msg.device];
|
||||||
|
VideoDevice* device = device_entry->device;
|
||||||
|
msg.memory_size = device->FrameSize();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return errno = ENODEV, -1;
|
return errno = ENODEV, -1;
|
||||||
|
}
|
||||||
|
|
||||||
DeviceEntry* device_entry = &devices[msg.device];
|
DeviceEntry* device_entry = &devices[msg.device];
|
||||||
VideoDevice* device = device_entry->device;
|
VideoDevice* device = device_entry->device;
|
||||||
|
@ -362,15 +427,60 @@ static int WriteMemory(void* ptr, size_t size)
|
||||||
|
|
||||||
ScopedLock lock(&video_lock);
|
ScopedLock lock(&video_lock);
|
||||||
|
|
||||||
if ( num_devices <= msg.device )
|
if ( Log::fallback_framebuffer &&
|
||||||
|
msg.device == ONE_AND_ONLY_DEVICE )
|
||||||
|
{
|
||||||
|
size_t ideal_pitch = Log::fallback_framebuffer_width *
|
||||||
|
Log::fallback_framebuffer_bpp / 8;
|
||||||
|
if ( ideal_pitch == Log::fallback_framebuffer_pitch )
|
||||||
|
{
|
||||||
|
size_t framesize = Log::fallback_framebuffer_height *
|
||||||
|
Log::fallback_framebuffer_pitch;
|
||||||
|
if ( framesize < msg.offset )
|
||||||
|
return 0;
|
||||||
|
size_t count = msg.size;
|
||||||
|
size_t left = framesize - msg.offset;
|
||||||
|
if ( left < count )
|
||||||
|
count = left;
|
||||||
|
const uint8_t* src = msg.src;
|
||||||
|
uint8_t* dst = Log::fallback_framebuffer + msg.offset;
|
||||||
|
if ( !CopyFromUser(dst, src, count) )
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const uint8_t* src = msg.src;
|
||||||
|
size_t src_size = msg.size;
|
||||||
|
uint64_t y = msg.offset / ideal_pitch;
|
||||||
|
uint64_t x = msg.offset % ideal_pitch;
|
||||||
|
while ( src_size && y < Log::fallback_framebuffer_height )
|
||||||
|
{
|
||||||
|
size_t count = src_size;
|
||||||
|
if ( ideal_pitch -x < count )
|
||||||
|
count = ideal_pitch - x;
|
||||||
|
uint8_t* dst = Log::fallback_framebuffer +
|
||||||
|
Log::fallback_framebuffer_pitch * y + x;
|
||||||
|
if ( !CopyFromUser(dst, src, count) )
|
||||||
|
return -1;
|
||||||
|
src += count;
|
||||||
|
src_size -= count;
|
||||||
|
x = 0;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( msg.device < num_devices )
|
||||||
|
{
|
||||||
|
DeviceEntry* device_entry = &devices[msg.device];
|
||||||
|
VideoDevice* device = device_entry->device;
|
||||||
|
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||||
|
if ( device->WriteAt(&ctx, msg.offset, msg.src, msg.size) < 0 )
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return errno = ENODEV, -1;
|
return errno = ENODEV, -1;
|
||||||
|
}
|
||||||
DeviceEntry* device_entry = &devices[msg.device];
|
|
||||||
VideoDevice* device = device_entry->device;
|
|
||||||
|
|
||||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
|
||||||
if ( device->WriteAt(&ctx, msg.offset, msg.src, msg.size) < 0 )
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -385,15 +495,60 @@ static int ReadMemory(void* ptr, size_t size)
|
||||||
|
|
||||||
ScopedLock lock(&video_lock);
|
ScopedLock lock(&video_lock);
|
||||||
|
|
||||||
if ( num_devices <= msg.device )
|
if ( Log::fallback_framebuffer &&
|
||||||
|
msg.device == ONE_AND_ONLY_DEVICE )
|
||||||
|
{
|
||||||
|
size_t ideal_pitch = Log::fallback_framebuffer_width *
|
||||||
|
Log::fallback_framebuffer_bpp / 8;
|
||||||
|
if ( ideal_pitch == Log::fallback_framebuffer_pitch )
|
||||||
|
{
|
||||||
|
size_t framesize = Log::fallback_framebuffer_height *
|
||||||
|
Log::fallback_framebuffer_pitch;
|
||||||
|
if ( framesize < msg.offset )
|
||||||
|
return 0;
|
||||||
|
size_t count = msg.size;
|
||||||
|
size_t left = framesize - msg.offset;
|
||||||
|
if ( left < count )
|
||||||
|
count = left;
|
||||||
|
const uint8_t* src = Log::fallback_framebuffer + msg.offset;
|
||||||
|
uint8_t* dst = msg.dst;
|
||||||
|
if ( !CopyToUser(dst, src, count) )
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint8_t* dst = msg.dst;
|
||||||
|
size_t dst_size = msg.size;
|
||||||
|
uint64_t y = msg.offset / ideal_pitch;
|
||||||
|
uint64_t x = msg.offset % ideal_pitch;
|
||||||
|
while ( dst_size && y < Log::fallback_framebuffer_height )
|
||||||
|
{
|
||||||
|
size_t count = dst_size;
|
||||||
|
if ( ideal_pitch -x < count )
|
||||||
|
count = ideal_pitch - x;
|
||||||
|
const uint8_t* src = Log::fallback_framebuffer +
|
||||||
|
Log::fallback_framebuffer_pitch * y + x;
|
||||||
|
if ( !CopyToUser(dst, src, count) )
|
||||||
|
return -1;
|
||||||
|
dst += count;
|
||||||
|
dst_size -= count;
|
||||||
|
x = 0;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( msg.device < num_devices )
|
||||||
|
{
|
||||||
|
DeviceEntry* device_entry = &devices[msg.device];
|
||||||
|
VideoDevice* device = device_entry->device;
|
||||||
|
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||||
|
if ( device->ReadAt(&ctx, msg.offset, msg.dst, msg.size) < 0 )
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return errno = ENODEV, -1;
|
return errno = ENODEV, -1;
|
||||||
|
}
|
||||||
DeviceEntry* device_entry = &devices[msg.device];
|
|
||||||
VideoDevice* device = device_entry->device;
|
|
||||||
|
|
||||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
|
||||||
if ( device->ReadAt(&ctx, msg.offset, msg.dst, msg.size) < 0 )
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,13 @@
|
||||||
# Multiboot header.
|
# Multiboot header.
|
||||||
.align 4
|
.align 4
|
||||||
.long 0x1BADB002 # Magic.
|
.long 0x1BADB002 # Magic.
|
||||||
.long 0x00000003 # Flags.
|
.long 0x00000007 # Flags.
|
||||||
.long -(0x1BADB002 + 0x00000003) # Checksum
|
.long -(0x1BADB002 + 0x00000007) # Checksum
|
||||||
|
.skip 32-12
|
||||||
|
.long 0 # Mode
|
||||||
|
.long 0 # Width
|
||||||
|
.long 0 # Height
|
||||||
|
.long 0 # Depth
|
||||||
|
|
||||||
.section .bss, "aw", @nobits
|
.section .bss, "aw", @nobits
|
||||||
.align 4096
|
.align 4096
|
||||||
|
|
|
@ -29,8 +29,13 @@
|
||||||
# Multiboot header.
|
# Multiboot header.
|
||||||
.align 4
|
.align 4
|
||||||
.long 0x1BADB002 # Magic.
|
.long 0x1BADB002 # Magic.
|
||||||
.long 0x00000003 # Flags.
|
.long 0x00000007 # Flags.
|
||||||
.long -(0x1BADB002 + 0x00000003) # Checksum.
|
.long -(0x1BADB002 + 0x00000007) # Checksum.
|
||||||
|
.skip 32-12
|
||||||
|
.long 0 # Mode
|
||||||
|
.long 0 # Width
|
||||||
|
.long 0 # Height
|
||||||
|
.long 0 # Depth
|
||||||
|
|
||||||
.section .bss, "aw", @nobits
|
.section .bss, "aw", @nobits
|
||||||
.align 4096
|
.align 4096
|
||||||
|
|
Loading…
Reference in New Issue