- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我一直在用C编写内核。我一直在使用GCC交叉编译器,在Windows系统上编写,并以16位实模式为目标。我没有可用于编写内核的C库。我从一些代码开始,这些代码假定是直接将字符打印到屏幕上。这是kernel.c
中的函数:
int main()
{
char *src = (char *)0xB8000000L;
*src = 'M';
src += 2;
*src = 'D';
return 0;
}
-m16
的GCC编译了代码,以生成将在实模式下运行的代码。我使用以下命令生成我的
kernel.bin
:
gcc -ffreestanding -c -m16 kernel.c -o kernel.o
ld -Ttext 0x10000 -o kernel.pe kernel.o
objcopy -O binary kernel.pe kernel.bin
printf
类似功能。我上面提供的代码只是我所理解的一小部分。我已经在Assembly(8086)中创建了一个引导加载程序。
0xb8000
的视频存储器?
最佳答案
如果您打算将GCC与-m16
一起使用,则会自动假定您将在80386+上运行。我不能太强调这一点,使用GCC创建16位代码充满了陷阱。您选择将内核的内存放在0x10000会变得更糟。 0x10000不能表示为16位偏移量,这可能导致GCC发出可能无法工作的代码,尤其是如果您想使用-O1
,-O2
,-O3
等打开优化时。甚至访问全局变量可能会导致问题!
高度推荐(几乎是避免大多数麻烦所必需的):如果将内核及其数据放入前64kb内存中,则问题可能会更少。内存地址0x00520的原点位于BIOS数据区和较低内存的保留区的正上方。
注意:以-m16
定位为实模式的GCC可能会导致您的使用风险。您也可能会失去理智。使用flat memory model(从0扩展到0xffffffff)将处理器置于32位保护模式下,其中CS = DS = ES是GCC的理想选择
尽管您的系统可能处于该模式,但是此代码假设您不在unreal mode中。
GCC假定CS = DS = ES,并且内存模型是平坦的。更改ES通常不是一个好主意。如果保存,工作并还原它们,而无需在其间插入C代码,则可以使用ES。由于GCC需要80386,因此我们可以使用其他段寄存器之一:FS和GS。在此示例中,我们将使用FS。
另一个前提条件是您了解Real Mode Segmentation。我假设您已经这样做,因为您已经创建了引导加载程序。物理内存地址的计算为:
Physical memory address = (segment << 4) + offset
(0xb800 << 4) + 0x0000 = 0xb8000
#include <stdint.h>
/* use regparm(3) to use convention where first three
* integer sized parameters are passed in registers (EAX, EDX, ECX) rather
* than the stack. regparm(0) is default CDECL stack based
* parameter passing. regparm(3) is generally faster overall, compared
* to passing all parameters on the stack. Internally, the Linux kernel
* uses this convention to reduce stack overhead when functions
* are called across different kernel modules.
*/
#define fastcall __attribute__((regparm(3)))
#define asmlinkage __attribute__((regparm(0)))
/* Global functions that will be exported */
extern fastcall void dispchar(uint16_t celldata, uint16_t offset);
extern fastcall void dispstring(const char *outstring, uint8_t attr,
uint16_t offset);
extern fastcall void dispchar_nofsupd(uint16_t celldata, uint16_t offset);
extern fastcall void dispstring_nofsupd(const char *outstring, uint8_t attr,
uint16_t offset);
extern fastcall uint32_t getset_fs(uint32_t segment);
extern fastcall void set_fs(uint32_t segment);
extern fastcall uint32_t set_videomode_fs(void);
static inline uint16_t
tm_rowcol_to_vidoffset(uint16_t row, uint16_t col, uint16_t numcols);
static inline uint16_t
tm_charattr_to_celldata(uint8_t ochar, uint8_t attr);
/*----------------------------------------------------------*/
#define COLSPERROW 80
#define ROW 3
#define COL 40
#define RED_ON_BLACK 4 /* attribute= Red character on black background */
#define MAGENTA_ON_BLACK 5 /* attribute= Magenta character on black background */
/* Color text mode memory segment */
#define VIDEO_SEG 0xb800
/* Place main before all other code */
int
_main()
{
/* Set FS to video mode segment and save previous value of FS */
uint32_t oldfs = set_videomode_fs();
dispchar_nofsupd(tm_charattr_to_celldata('A', RED_ON_BLACK),
tm_rowcol_to_vidoffset(ROW, COL, COLSPERROW));
dispchar_nofsupd(tm_charattr_to_celldata('B', RED_ON_BLACK),
tm_rowcol_to_vidoffset(ROW, COL + 1, COLSPERROW));
dispchar_nofsupd(tm_charattr_to_celldata(' ', RED_ON_BLACK),
tm_rowcol_to_vidoffset(ROW, COL + 2, COLSPERROW));
dispstring_nofsupd("Hello World", RED_ON_BLACK,
tm_rowcol_to_vidoffset(ROW, COL + 3, COLSPERROW));
/* Restore FS to original value when finished doing video mode work */
set_fs(oldfs);
/* Display Hello World using version dispstring
* that saves/restores FS automatically */
dispstring("Hello World", MAGENTA_ON_BLACK,
tm_rowcol_to_vidoffset(ROW+1, COL + 3, COLSPERROW));
return 0;
}
/* Convert Text Mode(TM) row, col, numcols
* to a video offset. numcols is the number of columns
* per row. Return value is a BYTE offset (not WORD)
*/
static inline uint16_t
tm_rowcol_to_vidoffset(uint16_t row, uint16_t col, uint16_t numcols)
{
return ((row * numcols + col) * 2);
}
static inline uint16_t
tm_charattr_to_celldata(uint8_t ochar, uint8_t attr)
{
return (uint16_t) (attr << 8) | (uint8_t) ochar;
}
/* Display character with FS change */
fastcall void
dispchar(uint16_t celldata, uint16_t offset)
{
uint32_t oldfs = set_videomode_fs();
dispchar_nofsupd(celldata, offset);
set_fs(oldfs);
}
/* Display character with no FS change */
fastcall void
dispchar_nofsupd(uint16_t celldata, uint16_t offset)
{
__asm__ ("movw %w[wordval], %%fs:%[memloc]\n\t"
:
:[wordval]"ri"(celldata),
[memloc] "m"(*(uint32_t *)(uint32_t)offset)
:"memory");
}
/* Set FS segment and return previous value */
fastcall uint32_t
getset_fs(uint32_t segment)
{
uint32_t origfs;
__asm__ __volatile__("mov %%fs, %w[origfs]\n\t"
"mov %w[segment], %%fs\n\t"
:[origfs] "=&rm"(origfs)
:[segment] "rm"(segment));
return origfs;
}
/* Set FS segment */
fastcall void
set_fs(uint32_t segment)
{
__asm__("mov %w[segment], %%fs\n\t"
:
:[segment]"rm"(segment));
}
/* Set FS to video mode segment 0xb800 */
fastcall uint32_t
set_videomode_fs(void)
{
return getset_fs(VIDEO_SEG);
}
/* Display string with FS change */
fastcall void
dispstring(const char *outstring, uint8_t attr, uint16_t offset)
{
uint32_t oldfs = set_videomode_fs();
dispstring_nofsupd(outstring, attr, offset);
set_fs(oldfs);
}
/* Display string with FS change */
fastcall void
dispstring_nofsupd(const char *outstring, uint8_t attr, uint16_t offset)
{
const char *curchar = outstring;
int i = 0;
for (; *curchar; curchar++, i++)
dispchar_nofsupd(tm_charattr_to_celldata(*curchar, attr),
offset + i * 2);
}
kernel.bin
可能会比您预期的大。这是由于GCC使用的默认对齐规则。以下
linker script可能有助于减小大小:
ENTRY(__main);
OUTPUT(i386pe);
SECTIONS
{
__kernelbase = 0x520;
. = __kernelbase;
.text : SUBALIGN(4) {
*(.text.st);
*(.text);
}
.data :
SUBALIGN(4) {
__data_start = .;
*(.rdata*);
*(.data);
__data_end = .;
__bss_start = .;
*(COMMON);
*(.bss);
__bss_end = .;
}
}
linker.ld
,然后可以使用以下命令来汇编和链接内核:
gcc -ffreestanding -c -m16 kernel.c -o kernel.o -O3
ld -o kernel.pe kernel.o -Tlinker.ld
objcopy -O binary kernel.pe kernel.bin
main
的前几行保存当前的FS寄存器,将FS设置为视频段0xb800并输出3个字符:
int
_main()
{
/* Set FS to video mode segment and save previous value of FS */
uint32_t oldfs = set_videomode_fs();
dispchar_nofsupd(tm_charattr_to_celldata('A', RED_ON_BLACK),
tm_rowcol_to_vidoffset(ROW, COL, COLSPERROW));
dispchar_nofsupd(tm_charattr_to_celldata('B', RED_ON_BLACK),
tm_rowcol_to_vidoffset(ROW, COL + 1, COLSPERROW));
dispchar_nofsupd(tm_charattr_to_celldata(' ', RED_ON_BLACK),
tm_rowcol_to_vidoffset(ROW, COL + 2, COLSPERROW));
dispstring_nofsupd("Hello World", RED_ON_BLACK,
tm_rowcol_to_vidoffset(ROW, COL + 3, COLSPERROW));
[code that prints strings has been snipped for brevity]
set_fs(oldfs);
objdump
命令可以看到生成的代码:
objdump -Dx kernel.pe --no-show-raw-insn -mi8086 -Mintel
-O3
优化):
00000520 <__main>:
520: push esi ; Save register contents
522: mov eax,0xb800
528: push ebx ; Save register contents
52a: mov si,fs ; Save old FS to SI
52d: mov fs,ax ; Update FS with 0xb800 (segment of video)
52f: mov WORD PTR fs:0x230,0x441 ; 0x441 = Red on black Letter 'A'
; Write to offset 0x230 ((80*3+40)*2) row=3,col=40
536: mov WORD PTR fs:0x232,0x442 ; 0x442 = Red on black Letter 'B'
; Write to offset 0x232 ((80*3+41)*2) row=3,col=41
53d: mov WORD PTR fs:0x234,0x420 ; 0x420 = Red on black space char
; Write to offset 0x234 ((80*3+42)*2) row=3,col=42
set_fs(oldfs);
571: mov fs,si ; Restore original value previously saved in SI
关于assembly - 在不使用C库的情况下以0xb8000显示文本视频存储器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37354717/
我对此很陌生,我在这里的论坛上检查过答案,但我没有找到任何真正可以帮助我的答案。我正在尝试播放 res/raw 文件夹中的视频。到目前为止我已经设置了这段代码: MediaPlayer mp; @Ov
我可以播放一个视频剪辑,检测视频的结尾,然后创建一个表单,然后播放另一个视频剪辑。我的问题是,表单 react 不正确,我创建了带有提交按钮和两个单选按钮可供选择的表单。我希望让用户进行选择,验证响应
首先,我必须说我在web2py讨论组中看到过类似的内容,但我不太理解。 我使用 web2py 设置了一个数据库驱动的网站,其中的条目只是 HTML 文本。其中大多数将包含 img和/或video指向相
我正在尝试在视频 View 中播放 YouTube 视频。 我将 xml 布局如下: 代码是这样的: setContentView(R.layout.webview); VideoV
我正在开发一个需要嵌入其中的 youtube 视频播放器的 android 应用程序。我成功地从 API 获得了 RTSP 视频 URL,但是当我试图在我的 android 视频 View 中加载这个
我目前正在从事一个使用 YouTube API 的网络项目。 我完全不熟悉 API。所以每一行代码都需要付出很多努力。 使用以下代码,我可以成功检索播放列表中的项目: https://www.goog
是否可以仅使用视频 ID 和 key 使用 API V3 删除 youtube 视频?我不断收到有关“必需参数:部分”丢失的错误消息。我用服务器和浏览器 api 键试了一下这是我的代码: // $yo
所以我一直坚持这个大约一个小时左右,我就是无法让它工作。到目前为止,我一直在尝试从字符串中提取整个链接,但现在我觉得只获取视频 ID 可能更容易。 RegEx 需要从以下链接样式中获取 ID/URL,
var app = angular.module('speakout', []).config( function($sceDelegateProvider) {
我正在努力从 RSS 提要中阅读音频、视频新闻。我如何确定该 rss 是用于新闻阅读器还是用于音频或视频? 这是视频源:http://feeds.cbsnews.com/CBSNewsVideo 这是
利用python反转图片/视频 准备:一张图片/一段视频 python库:pillow,moviepy 安装库 ?
我希望在用户双击视频区域时让我的视频全屏显示,而不仅仅是在他们单击控件中的小图标时。有没有办法添加事件或其他东西来控制用户点击视频时发生的情况? 谢谢! 最佳答案 按照 Musa 的建议,附
关闭。这个问题需要更多 focused .它目前不接受答案。 想改进这个问题?更新问题,使其仅关注一个问题 editing this post . 7年前关闭。 Improve this questi
我有一个公司培训视频加载到本地服务器上。我正在使用 HTML5 的视频播放来观看这些视频。该服务器无法访问网络,但我已加载 apache 并且端口 8080 对同一网络上的所有机器开放。 这些文件位于
我想混合来自 video.mp4 的视频(时长 1 分钟)和来自 audio.mp3 的音频(10 分钟持续时间)到一个持续时间为 1 分钟的输出文件中。来自 audio.mp3 的音频应该是从 4
关闭。这个问题需要更多 focused .它目前不接受答案。 想改进这个问题?更新问题,使其仅关注一个问题 editing this post . 8年前关闭。 Improve this questi
我正在尝试使用 peer/getUserMedia 创建一个视频 session 网络应用程序。 目前,当我将唯一 ID 发送到视频 session 时,我能够听到/看到任何加入我的 session
考虑到一段时间内的观看次数,我正在评估一种针对半自动脚本的不同方法,该脚本将对视频元数据执行操作。 简而言之,只要视频达到指标中的某个阈值,就说观看次数,它将触发某些操作。 现在要执行此操作,我将不得
我正在通过iBooks创建专门为iPad创建动态ePub电子书的网站。 它需要支持youtube视频播放,所以当我知道视频的直接路径时,我正在使用html5 标记。 有没有一种使用html5 标签嵌入
我对Android不熟悉,我想浏览youtube.com并在Webview内从网站显示视频。当前,当我尝试执行此操作时,将出现设备的浏览器,并让我使用设备浏览器浏览该站点。如果Webview不具备这种
我是一名优秀的程序员,十分优秀!