热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何使用x86裸机组件获得键盘输入?-Howtogetkeyboardinputwithx86baremetalassembly?

Imintheprocessoftryingtohacktogetherthefirstbitsofakernel.Icurrentlyhavetheentir

I'm in the process of trying to hack together the first bits of a kernel. I currently have the entire kernel compiled down as C code, and I've managed to get it displaying text in the console window and all of that fine goodness. Now, I want to start accepting keyboard input so I can actually make some use of the thing and get going on process management.

我正在试图破解内核的第一部分。我目前已将整个内核编译为C代码,并且我设法让它在控制台窗口中显示文本以及所有这些良好的优点。现在,我想开始接受键盘输入,这样我就可以实际使用这个东西并开始进行流程管理。

I'm using DJGPP to compile, and loading with GRUB. I'm also using a small bit of assembly which basically jumps directly into my compiled C code and I'm happy from there.

我正在使用DJGPP进行编译,并使用GRUB加载。我也使用了一小部分程序集,它基本上直接跳转到我编译的C代码中,我很高兴。

All the research I've done seems to point to an ISR at $0x16 to read in the next character from the keyboard buffer. From what I can tell, this is supposed to store the ASCII value in ah, and the keycode in al, or something to that effect. I'm attempting to code this using the following routine in inline assembly:

我所做的所有研究似乎都指向一个$ 0x16的ISR来读取键盘缓冲区中的下一个字符。据我所知,这应该存储在ah中的ASCII值,以及al中的keycode或者那种效果。我正在尝试使用内联汇编中的以下例程对此进行编码:

char getc(void) 
{
    int output = 0;

    //CRAZY VOODOO CODE
    asm("xor %%ah, %%ah\n\t"
        "int $0x16"
        : "=a" (output)
        : "a" (output)
        : 

        );

    return (char)output;
}

When this code is called, the core immediately crashes. (I'm running it on VirtualBox, I didn't feel the need to try something this basic on real hardware.)

调用此代码时,核心会立即崩溃。 (我在VirtualBox上运行它,我觉得不需要在真实硬件上尝试这个基本功能。)

Now I have actually a couple of questions. No one has been able to tell me if (since my code was launched from GRUB) I'm running in real mode or protected mode at the moment. I haven't made the jump one way or another, I was planning on running in real mode until I got a process handler set up.

现在我实际上有几个问题。没有人能够告诉我(因为我的代码是从GRUB启动的)我现在正在以实模式或保护模式运行。我没有以这种或那种方式进行跳转,我计划以实模式运行,直到我设置了进程处理程序。

So, assuming that I'm running in real mode, what am I doing wrong, and how do I fix it? I just need a basic getc routine, preferably non-blocking, but I'll be darned if google is helping on this one at all. Once I can do that, I can do the rest from there.

所以,假设我在实模式下运行,我做错了什么,我该如何解决?我只需要一个基本的getc例程,最好是非阻塞的,但是如果谷歌正在帮助这个,我会被愚弄。一旦我能做到这一点,我可以从那里做其余的事情。

I guess what I'm asking here is, am I anywhere near the right track? How does one generally go about getting keyboard input on this level?

我想我在这里问的是,我是否在正确的轨道附近?人们通常如何在这个级别上获得键盘输入?

EDIT: OOhh... so I'm running in protected mode. This certainly explains the crash trying to access real mode functions then.

编辑:哦......所以我在保护模式下运行。这无疑解释了试图访问实模式功能的崩溃。

So then I guess I'm looking for how to access the keyboard IO from protected mode. I might be able to find that on my own, but if anyone happens to know feel free. Thanks again.

那么我想我正在寻找如何从保护模式访问键盘IO。我或许可以自己找到,但如果有人碰巧知道自由。再次感谢。

7 个解决方案

#1


4  

If you are compiling with gcc, unless you are using the crazy ".code16gcc" trick the linux kernel uses (which I very much doubt), you cannot be in real mode. If you are using the GRUB multiboot specification, GRUB itself is switching to protected mode for you. So, as others pointed out, you will have to talk to the 8042-compatible keyboard/mouse controller directly. Unless it's a USB keyboard/mouse and 8042 emulation is disabled, where you would need a USB stack (but you can use the "boot" protocol for the keyboard/mouse, which is simpler).

如果你正在使用gcc编译,除非你使用Linux内核使用的疯狂“.code16gcc”技巧(我非常怀疑),你不能处于实模式。如果您使用GRUB多引导规范,GRUB本身将切换到保护模式。因此,正如其他人所指出的那样,您将不得不直接与8042兼容的键盘/鼠标控制器进行通信。除非它是USB键盘/鼠标且禁用8042仿真,否则您需要一个USB堆栈(但您可以使用键盘/鼠标的“启动”协议,这更简单)。

Nobody said writing an OS kernel was simple.

没有人说编写操作系统内核很简单。

#2


4  

The code you've got there is trying to access a real mode BIOS service. If you're running in protected mode, which is likely considering that you're writing a kernel, then the interrupt won't work. You will need to do one of the following:

您在那里获得的代码是尝试访问实模式BIOS服务。如果您正在保护模式下运行,这可能考虑到您正在编写内核,那么中断将无法工作。您需要执行以下操作之一:

  • Thunk the CPU into real mode, making sure the interrupt vector table is correct, and use the real mode code you have or
  • 将CPU重置为实模式,确保中断向量表正确,并使用您拥有的实模式代码或

  • Write your own protected mode keyboard handler (i.e. use the in/out instructions).
  • 编写自己的保护模式键盘处理程序(即使用输入/输出指令)。

The first solution is going to involve a runtime performance overhead whist the second will require some information about keyboard IO.

第一个解决方案将涉及运行时性能开销,第二个解决方案将需要有关键盘IO的一些信息。

#3


1  

I've a piece of GeekOS that seems to do

我有一块似乎正在做的GeekOS

In_Byte(KB_CMD);

and then

In_Byte(KB_DATA);

to fetch a scancode. I put it up: keyboard.c and keyboard.h. KB_CMD and KB_DATA being 0x64 and 0x60 respectively. I could perhaps also point out that this is done in an interrupt handler for intr:1.

获取扫描码。我把它放了:keyboard.c和keyboard.h。 KB_CMD和KB_DATA分别为0x64和0x60。我或许也可以指出,这是在intr:1的中断处理程序中完成的。

#4


1  

You're doing the right thing, but I seem to recall that djgpp only generates protected mode output, which you can't call interrupts from. Can you drop to real mode like others have suggested, or would you prefer to address the hardware directly?

你做的是正确的,但我似乎记得djgpp只生成保护模式输出,你无法调用中断。您是否可以像其他人建议的那样进入实模式,或者您更愿意直接寻址硬件?

#5


1  

For the purposes of explanation, let's suppose you were writing everything in assembly language yourself, boot loader and kernel (*cough* I've done this).

出于解释的目的,让我们假设您自己用汇编语言编写所有内容,启动加载程序和内核(*咳嗽*我已经这样做了)。

In real mode, you can make use of the interrupt routines that come from the BIOS. You can also replace the interrupt vectors with your own. However all code is 16-bit code, which is not binary compatible with 32-bit code.

在实模式下,您可以使用来自BIOS的中断例程。您也可以用自己的中断向量替换中断向量。但是,所有代码都是16位代码,与32位代码不是二进制兼容的。

When you jump through a few burning hoops to get to protected mode (including reprogramming the interrupt controller, to get around the fact that IBM used Intel-reserved interrupts in the PC), you have the opportunity to set up 16- and 32-bit code segments. This can be used to run 16-bit code. So you can use this to access the getchar interrupt!

当你跳过几个燃烧的箍到达保护模式(包括重新编程中断控制器,以解决IBM在PC中使用Intel保留的中断这一事实)时,你有机会设置16位和32位代码段。这可用于运行16位代码。所以你可以使用它来访问getchar中断!

... not quite. For this interrupt to work, you actually need data in a keyboard buffer that was put there by a different ISR - the one that is triggered by the keyboard when a key is pressed. There are various issues which pretty much prevent you using BIOS ISRs as actual hardware ISRs in protected mode. So, the BIOS keyboard routines are useless.

... 不完全的。要使此中断起作用,您实际上需要键盘缓冲区中的数据,该缓冲区由不同的ISR放置在那里 - 按下键时由键盘触发的ISR。有许多问题几乎阻止您在保护模式下使用BIOS ISR作为实际硬件ISR。所以,BIOS键盘程序是没用的。

BIOS video calls, on the other hand, are fine, because there's no hardware-triggered component. You do have to prepare a 16-bit code segment but if that's under control then you can switch video modes and that sort of thing by using BIOS interrupts.

另一方面,BIOS视频通话很好,因为没有硬件触发的组件。你必须准备一个16位代码段,但如果这是在控制之下,那么你可以通过使用BIOS中断切换视频模式和那种东西。

Back to the keyboard: what you need (again assuming that YOU'RE writing all the code) is to write a keyboard driver. Unless you're a masochist (I'm one) then don't go there.

回到键盘:你需要的东西(再次假设你写的所有代码)是写一个键盘驱动程序。除非你是一个受虐狂(我是一个),否则不要去那里。

A suggestion: try writing a multitasking kernel in Real mode. (That's 16-bit mode.) You can use all the BIOS interrupts! You don't get memory protection but you can still get pre-emptive multitasking by hooking the timer interrupt.

建议:尝试在Real模式下编写多任务内核。 (这是16位模式。)您可以使用所有BIOS中断!您没有获得内存保护,但您仍然可以通过挂钩定时器中断来获得先发制人的多任务处理。

#6


0  

Just an idea: looking at GRUB for DOS source (asm.s), the console_checkkey function is using BIOS INT 16H Function 01, and not function 00, as you are trying to do. Maybe you'd want to check if a key is waiting to be input.

只是一个想法:查看GRUB for DOS源(asm.s),console_checkkey函数正在使用BIOS INT 16H Function 01,而不是函数00,正如您尝试的那样。也许你想检查一个键是否等待输入。

The console_checkkey code is setting the CPU to real mode in order to use the BIOS, as @skizz suggested.

console_checkkey代码将CPU设置为实模式以便使用BIOS,如@skizz建议的那样。

You can also try using GRUB functions directly (if still mapped in real mode).

您也可以尝试直接使用GRUB函数(如果仍然以实模式映射)。

A note on reading assembly source: in this version

关于阅读汇编来源的说明:在此版本中

movb    $0x1, %ah

means move constant byte (0x1) to register %ah

意味着将常量字节(0x1)移动到寄存器%ah

The console_checkkey from GRUB asm.s:

来自GRUB asm.s的console_checkkey:

/*
 * int console_checkkey (void)
 *  if there is a character pending, return it; otherwise return -1
 * BIOS call "INT 16H Function 01H" to check whether a character is pending
 *  Call with   %ah = 0x1
 *  Return:
 *      If key waiting to be input:
 *          %ah = keyboard scan code
 *          %al = ASCII character
 *          Zero flag = clear
 *      else
 *          Zero flag = set
 */
 ENTRY(console_checkkey)
  push  %ebp
  xorl  %edx, %edx

  call  EXT_C(prot_to_real) /* enter real mode */

  .code16

  sti       /* checkkey needs interrupt on */

  movb  $0x1, %ah
  int   $0x16

  DATA32    jz  notpending

  movw  %ax, %dx
  //call    translate_keycode
  call  remap_ascii_char
  DATA32    jmp pending

notpending:
  movl  $0xFFFFFFFF, %edx

pending:
  DATA32    call    EXT_C(real_to_prot)
  .code32

  mov   %edx, %eax

  pop   %ebp
  ret

#7


0  

Example for polling the keyboard controller:

轮询键盘控制器的示例:

Start:
      cli
      mov al,2        ; dissable IRQ 1
      out 21h,al
      sti

;--------------------------------------
; Main-Routine
AGAIN:
      in al,64h       ; get the status
      test al,1       ; check output buffer
      jz short NOKEY
      test al,20h     ; check if it is a PS2Mouse-byte
      jnz short NOKEY
      in al,60h       ; get the key

; insert your code here (maybe for converting into ASCII...)

NOKEY:
      jmp AGAIN
;--------------------------------------
; At the end
      cli
      xor al,al       ; enable IRQ 1
      out 21h,al
      sti

推荐阅读
  • 本文介绍了使用C++Builder实现获取USB优盘序列号的方法,包括相关的代码和说明。通过该方法,可以获取指定盘符的USB优盘序列号,并将其存放在缓冲中。该方法可以在Windows系统中有效地获取USB优盘序列号,并且适用于C++Builder开发环境。 ... [详细]
  • Week04面向对象设计与继承学习总结及作业要求
    本文总结了Week04面向对象设计与继承的重要知识点,包括对象、类、封装性、静态属性、静态方法、重载、继承和多态等。同时,还介绍了私有构造函数在类外部无法被调用、static不能访问非静态属性以及该类实例可以共享类里的static属性等内容。此外,还提到了作业要求,包括讲述一个在网上商城购物或在班级博客进行学习的故事,并使用Markdown的加粗标记和语句块标记标注关键名词和动词。最后,还提到了参考资料中关于UML类图如何绘制的范例。 ... [详细]
  • PatchODAX8: ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • 本文介绍了一种轻巧方便的工具——集算器,通过使用集算器可以将文本日志变成结构化数据,然后可以使用SQL式查询。集算器利用集算语言的优点,将日志内容结构化为数据表结构,SPL支持直接对结构化的文件进行SQL查询,不再需要安装配置第三方数据库软件。本文还详细介绍了具体的实施过程。 ... [详细]
  • 微信官方授权及获取OpenId的方法,服务器通过SpringBoot实现
    主要步骤:前端获取到code(wx.login),传入服务器服务器通过参数AppID和AppSecret访问官方接口,获取到OpenId ... [详细]
  • 本文概述了JNI的原理以及常用方法。JNI提供了一种Java字节码调用C/C++的解决方案,但引用类型不能直接在Native层使用,需要进行类型转化。多维数组(包括二维数组)都是引用类型,需要使用jobjectArray类型来存取其值。此外,由于Java支持函数重载,根据函数名无法找到对应的JNI函数,因此介绍了JNI函数签名信息的解决方案。 ... [详细]
  • 本文介绍了在PostgreSQL中批量导入数据时的优化方法。包括使用unlogged表、删除重建索引、删除重建外键、禁用触发器、使用COPY方法、批量插入等。同时还提到了一些参数优化的注意事项,如设置effective_cache_size、shared_buffer等,并强调了在导入大量数据后使用analyze命令重新收集统计信息的重要性。 ... [详细]
  • tcpdump 4.5.1 crash 深入分析
    tcpdump 4.5.1 crash 深入分析 ... [详细]
author-avatar
mobiledu2502857377
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有