我正在编写James M教程之后的内核,最近我添加了一个键盘驱动程序(来自bkerndev教程)以实现一个简单的shell。键盘驱动程序以前工作得很好,直到我添加了一种识别用户输入线的方法。它基本上只是将输入行作为字符串写入数组,然后将其用作文件'kernel.c中的'input'变量。但是,当我编译代码时,我从链接器收到以下错误:
keyboard.c:(.text+0x8c): undefined reference to `user_input'
引用在文件'kernel.h'中定义。
keyboard.c中
#include <kstdio.h>
#include <isr.h>
#include <keyboard.h>
#include <kernel.h>
u32int shiftKey;
static char letter;
static char upLetter;
static char key_buffer[256]; // The buffer line
#define RSHIFT 0x80 - 42
#define LSHIFT 0x80 - 54
#define ENTER 0x1C
#define BACKSPACE 0x0E
// kbdus is the scancode tables for English US
unsigned char kbdus[128] =
{
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */
'9', '0', '-', '=', '\b', /* Backspace */
'\t', /* Tab */
'q', 'w', 'e', 'r', /* 19 */
't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* Enter key */
0, /* 29 - Control */
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 39 */
'\'', '`', 0, /* Left shift */
'\\', 'z', 'x', 'c', 'v', 'b', 'n', /* 49 */
'm', ',', '.', '/', 0, /* Right shift */
'*',
0, /* Alt */
' ', /* Space bar */
0, /* Caps lock */
0, /* 59 - F1 key ... > */
0, 0, 0, 0, 0, 0, 0, 0,
0, /* < ... F10 */
0, /* 69 - Num lock*/
0, /* Scroll Lock */
0, /* Home key */
0, /* Up Arrow */
0, /* Page Up */
'-',
0, /* Left Arrow */
0,
0, /* Right Arrow */
'+',
0, /* 79 - End key*/
0, /* Down Arrow */
0, /* Page Down */
0, /* Insert Key */
0, /* Delete Key */
0, 0, 0,
0, /* F11 Key */
0, /* F12 Key */
0, /* All other keys are undefined */
};
unsigned char upkbdus[128] =
{
0, 27, '!', '@', '#', '$', '%', '^', '&', '*', /* 9 */
'(', ')', '_', '+', '\b', /* Backspace */
'\t', /* Tab */
'Q', 'W', 'E', 'R', /* 19 */
'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', /* Enter key */
0, /* 29 - Control */
'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', /* 39 */
'\'', '`', 0, /* Left shift */
'\\', 'Z', 'X', 'C', 'V', 'B', 'N', /* 49 */
'M', ',', '.', '/', 0, /* Right shift */
'*',
0, /* Alt */
' ', /* Space bar */
0, /* Caps lock */
0, /* 59 - F1 key ... > */
0, 0, 0, 0, 0, 0, 0, 0,
0, /* < ... F10 */
0, /* 69 - Num lock*/
0, /* Scroll Lock */
0, /* Home key */
0, /* Up Arrow */
0, /* Page Up */
'-',
0, /* Left Arrow */
0,
0, /* Right Arrow */
'+',
0, /* 79 - End key*/
0, /* Down Arrow */
0, /* Page Down */
0, /* Insert Key */
0, /* Delete Key */
0, 0, 0,
0, /* F11 Key */
0, /* F12 Key */
0, /* All other keys are undefined */
};
/* Handles the keyboard interrupt */
void keyboard_handler(struct regs *r)
{
unsigned char scancode;
/* Read from the keyboard's data buffer */
scancode = inb(0x60);
/* If the top bit of the byte we read from the keyboard is
* set, that means that a key has just been released */
if (scancode & 0x80)
{
if (scancode == LSHIFT || scancode == RSHIFT) {
shiftKey = 1;
}
else {
shiftKey = 0;
}
}
else
{
letter = kbdus[scancode];
upLetter = upkbdus[scancode];
/* Here, a key was just pressed. Please note that if you
* hold a key down, you will get repeated key press
* interrupts. */
/* Just to show you how this works, we simply translate
* the keyboard scancode into an ASCII value, and then
* display it to the screen. You can get creative and
* use some flags to see if a shift is pressed and use a
* different layout, or you can add another 128 entries
* to the above layout to correspond to 'shift' being
* held. If shift is held using the larger lookup table,
* you would add 128 to the scancode when you look for it */
if (scancode == BACKSPACE) {
backspace(key_buffer);
} else if (scancode == ENTER) {
user_input(key_buffer);
kprintf("\n");
key_buffer[0] = '\0';
} else {
/* Remember that kprint only accepts char[] */
char str[2] = {letter, '\0'};
append(key_buffer, letter);
kprintf(str);
}
/* if (shiftKey == 0) {
kputc(letter);
}
else if (shiftKey == 1) {
kputc(upLetter);
} */
}
}
void keyboard_install() {
register_interrupt_handler(IRQ1, &keyboard_handler);
}
keyboard.h
#ifndef KEYBOARD_H
#define KEYBOARD_H
void keyboard_install();
#endif
kernel.h当
#ifndef KERNEL_H
#define KERNEL_H
#include <keyboard.h>
void user_input(char *input);
#endif
生成文件
# Makefile for Sierra Kernel
# The C and C++ rules are already setup by default.
# The only one that needs changing is the assembler
# rule, as we use nasm instead of GNU as.
DESTDIR?=
INCLUDEDIR?=include
PREFIX?=/usr/local
EXEC_PREFIX?=$(PREFIX)
BOOTDIR?=$(EXEC_PREFIX)/boot
export AR=/Users/development/opt/cross/bin/i386-elf-ar
export AS=/Users/development/opt/cross/bin/i386-elf-as
export CC=/Users/development/opt/cross/bin/i386-elf-gcc
export GDB=/Users/development/opt/cross/bin/i386-elf-gdb
CFLAGS=-nostdlib -nostdinc -fno-builtin -I include
LDFLAGS=-Tlink.ld
ASFLAGS=-felf
SOURCES=boot/boot.o drivers/halt.o drivers/kstdio/screen.o drivers/kstdio/io.o kernel/sierra/kernel.o \
kernel/tables/gdt.o kernel/tables/tables.o kernel/tables/isr.o kernel/timer.o kernel/tables/inter.o \
drivers/keyboard.o
all: $(SOURCES) link
clean:
rm -rf boot/*.o drivers/*.o drivers/kstdio/*.o kernel/sierra/*.o kernel/tables/*.o \
*.o kernel/*.o *.kernel
link:
/Users/development/opt/cross/i386-elf/bin/ld $(LDFLAGS) -o sierra.kernel $(SOURCES)
.s.o:
nasm $(ASFLAGS) $<
install: install-headers install-kernel
install-headers:
mkdir -p $(DESTDIR)$(INCLUDEDIR)
cp -R --preserve=timestamps include/. $(DESTDIR)$(INCLUDEDIR)/.
install-kernel:
mkdir -p $(DESTDIR)$(BOOTDIR)
cp kernel $(DESTDIR)$(BOOTDIR)
image:
./update_image.sh
run:
qemu-system-i386 -fda system.img
bundle:
make clean
make
make image
make run
mac:
make clean
make
整个项目来源可在此处获取:https://github.com/sofferjacob/Sierra-Kernel/tree/testing。
感谢您的帮助。
顺便说一句我在Ubuntu 16.10中使用交叉编译工具链(有时我在macOS 10.12中使用相同的工具链,但通常是Ubuntu)来编译内核。
答案 0 :(得分:0)
对kernel.c的这一改变解决了它:
#include <kstdio.h>
#include <tables.h>
#include <timer.h>
#include <keyboard.h>
#include <keyboard.h>
extern int is_kernel = 0;
extern int is_user = 0;
int kernel_main(struct multiboot *mboot_ptr, u32int initial_stack) {
is_kernel = 1;
is_user = 0;
tables_int(); // Initialise all descriptor tables
clear_screen(); // Initialise the screen.
asm volatile("sti");
timer_init(100); // Initialise timer to 100Hz (This MUST ALWAYS be set to 100 or bad things will happen)
kprintf("System sucessfully initialised \n");
show_system_time();
kprintf("Welcome to Sierra Kernel! v.1.0 \n");
keyboard_install();
}
void user_input(char *input) {
if (strcmp(input, "test") == 0) {
kprintf("TEST \n");
}
else {
kprintf("ERROR \n");
}
kprintf("# ");
}