- PVSM.RU - https://www.pvsm.ru -
В первой [1]и второй [2] статьях я лишь коротко представил процесс написания загрузчика на ассемблере и C. Для меня это было хоть и непросто, но в то же время интересно, так что я остался доволен. Однако создания загрузчика мне показалось мало, и я увлекся идеей его расширения дополнительной функциональностью. Но так как в итоге размер готовой программы превысил 512 байт, то при попытке запуска системы с несущего ее загрузочного диска я столкнулся с проблемой “This is not a bootable disk”.
В ней мы рассмотрим значимость файловой системы для загрузчика, а также напишем макет ядра, которое будет просто отображать командную строку, позволяя ввод текста. При этом я поясню, почему внедряю загрузчик в дискету, отформатированную в FAT. И поскольку одной статьи для полноценного раскрытия темы файловых систем однозначно недостаточно я постараюсь придерживаться краткости и максимальной простоты изложения.
Статья окажется намного полезнее тем, у кого уже есть опыт программирования. Несмотря на ее чисто ознакомительный, казалось бы, характер, написание программ на ассемблере и C может оказаться достаточно сложным. Поэтому новичкам я рекомендую для начала ознакомиться с вводными принципами программирования и уже потом возвращаться к этому материалу.
Как и ранее, процесс изложения построен по принципу вопрос-ответ, что должно упростить восприятие информации.
В предыдущих статьях я написал загрузчик и, реализовав с его помощью вывод на экран цветных прямоугольников, захотел добавить дополнительную функциональность. Однако при этом я столкнулся с ограничением размера сектора в 512 байт, что не позволило добиться желаемого стандартным путем.
В итоге передо мной стоит две задачи:
Этап 1:
Этап 2:
В загрузчике мы можем просто загрузить второй сектор, содержащий kernel.bin, в RAM по адресу, к примеру, 0x1000
, а затем перейти к этому адресу из 0x7с00
и запустить kernel.bin.
Вот схема для лучшего понимания идеи:
Как мы теперь знаем, у нас есть возможность передачи управления от загрузчика (0x7c00
) в другую область памяти, где размещается, например, наш kernel.bin, после чего продолжить выполнение. Но здесь у меня я хочу кое-что уточнить.
Ну это простой вопрос. Для ответа на него нам достаточно выполнить несложную арифметику, а именно разделить размер kernel.bin на размер сектора, который составляет 512 байт. Например, если kernel.bin будет равен 1024 байта, то и займет он 2 сектора.
В связи с этим вам потребуется захардкодить в загрузчике необходимое для ядра количество секторов, и при возможном изменении его размера в дальнейшем не забывать о внесении соответствующих правок. В противном случае при несоответствии прописанного и фактического размеров загрузка ядра будет проваливаться.
В принципе да. Для этого нужно будет поочередно добавить требуемые файлы на дискету, не забывая при этом обновлять загрузчик необходимой информацией об их расположении, занимаемом количестве секторов и прочем. Но тут я отдельно скажу, что в итоге сложность системы сильно увеличивается, и в конечном счете мне такой вариант не очень понравился.
Хороший вопрос, так как мы, действительно, только загружаем соответствующий сектор в память и начинаем его выполнение. Это не идеальный вариант, и в нем кое-чего не хватает.
Загрузчик вслепую загружает сектора каждого файла один за другим и затем начинает выполнение этих файлов. Но даже до того, как он попробует загрузить файлы в память, должен присутствовать способ проверить, существуют ли они вообще на диске.
В этом случае система просто дает сбой. Поэтому на диске должна присутствовать фиксированная область, где подобно индексу в книге будут прописаны все имена файлов.
Тогда загрузчик будет запрашивать индекс этого файла на диске, и в случае обнаружения таковой будет обнаружен в списке – продолжать загрузку этого файла в память.
Мне такой вариант очень нравится, так как он избавляет от лишних действий.
Здесь мы избегаем нескольких проблем. До этого загрузчик вслепую загружал жестко закодированные сектора. Но зачем загружать файл, не будучи уверенным в том, что это именно нужный файл, и что он вообще существует?
Для этого нужно просто организовать информацию на диске, после чего перепрограммировать загрузчик, повысив тем самым его эффективность при загрузке файлов.
Такой вид организации информации называется файловой системой. Существует много типов файловых систем, среди которых есть как коммерческие, так и бесплатные. Вот некоторые из них:
Для лучшего понимания этой файловой системы вам потребуется знать некоторые технические нюансы.
Минимальной единицей измерения пространства FAT является кластер, который занимает 1 сектор накопителя. Иначе говоря, на дискете, отформатированной в FAT, 1 кластер эквивалентен 1 сектору и, соответственно, равен 512 байт.
Для удобства использования файловая система дополнительно разделяется на четыре основные области:
Я постарался максимально понятно изобразить эту структуру в виде схемы:
Рассмотрим каждую часть подробнее.
Загрузочный сектор содержит служебную информацию, на основе которой ОС распознает тип файловой системы диска, после чего уже переходит к чтению его содержимого.
Информация о файловой системе FAT, содержащаяся в загрузочном секторе, называется блоком параметров BIOS.
Ниже я привел пример значений из этого блока:
Эта таблица представляет своего рода связанный список, в котором каждая ячейка, соответствующая кластеру файла, содержит значение следующего кластера, формируя таким образом связанную цепочку всех кластеров этого файла.
Это значение кластера служит для:
0x0ff8
и 0x0fff
, значит файл не содержит данных в других секторах, т.е. достигнут его конец.К сведению: на схеме выше я отметил две таблицы FAT. Вторая является резервной копией первой и используется в случае ее повреждения.
Корневой каталог выступает в роли индекса всех находящихся на диске файлов. Именно здесь загрузчик ищет имя нужного файла и в случае обнаружения обращается к его первому кластеру для начала загрузки.
После обнаружения и начала считывания первого кластера загрузчик с помощью FAT находит все последующие занимаемые файлом кластеры.
Здесь содержаться фактические данные файлов.
Как только программа обнаруживает искомый сектор файла, именно из этой области извлекаются соответствующие данные.
Продолжим наш пример с kernel.bin, который загрузчик помещает в память для выполнения. Теперь в этом сценарии нужно прописать для загрузчика следующую функциональность:
Ниже я привел очередную схему.
Для успешной реализации этой задачи нам нужно иметь представление о следующем. Более подробную информацию по этим пунктам можете найти в двух предыдущих статьях.
Ниже я привожу фрагмент кода для выполнения файла kernel.bin на FAT-диске.
Вот загрузчик.
/*********************************************************************************
* *
* *
* Name : stage0.S *
* Date : 23-Feb-2014 *
* Version : 0.0.1 *
* Source : assembly language *
* Author : Ashakiran Bhatter *
* *
* Описание: основная логика подразумевает сканирование файла kernel.bin *
* на дискете fat12 и передачу этому файлу права *
* выполнения. *
* Использование: подробности в файле readme.txt *
* *
* *
*********************************************************************************/
.code16
.text
.globl _start;
_start:
jmp _boot
nop
/*блок параметров BIOS описание каждой сущности */
/*-------------------- -------------------------- */
.byte 0x6b,0x69,0x72,0x55,0x58,0x30,0x2e,0x31 /* метка OEM */
.byte 0x00,0x02 /* байтов в секторе */
.byte 0x01 /* секторов в кластере */
.byte 0x01,0x00 /* зарезервированных секторов */
.byte 0x02 /* таблиц fat */
.byte 0xe0,0x00 /* записей в каталоге */
.byte 0x40,0x0b /* всего секторов */
.byte 0xf0 /* описание среды передачи */
.byte 0x09,0x00 /* размер в каждой таблице fat */
.byte 0x02,0x01 /* секторов в дорожке */
.byte 0x02,0x00 /* головок на цилиндр */
.byte 0x00,0x00, 0x00, 0x00 /* скрытых секторов */
.byte 0x00,0x00, 0x00, 0x00 /* больших секторов */
.byte 0x00 /* идентификатор загрузочного диска*/
.byte 0x00 /* неиспользуемых секторов */
.byte 0x29 /* внешняя сигнатура загрузки */
.byte 0x22,0x62,0x79,0x20 /* серийный номер */
.byte 0x41,0x53,0x48,0x41,0x4b,0x49 /* метка тома 6 байт из 11 */
.byte 0x52,0x41,0x4e,0x20,0x42 /* метка тома 5 байт из 11 */
.byte 0x48,0x41,0x54,0x54,0x45,0x52,0x22 /* тип файловой системы */
/* включение макросов */
#include "macros.S"
/* начало основного кода */
_boot:
/* инициализация среды */
initEnvironment
/* загрузка stage2 */
loadFile $fileStage2
/* бесконечный цикл */
_freeze:
jmp _freeze
/* непредвиденное завершение программы */
_abort:
writeString $msgAbort
jmp _freeze
/* включение функций */
#include "routines.S"
/* пользовательские переменные */
bootDrive : .byte 0x0000
msgAbort : .asciz "* * * F A T A L E R R O R * * *"
#fileStage2: .ascii "STAGE2 BIN"
fileStage2: .ascii "KERNEL BIN"
clusterID : .word 0x0000
/* перемещение от начала к 510-му байту */
. = _start + 0x01fe
/* добавление сигнатуры загрузки */
.word BOOT_SIGNATURE
В этом основном файле загрузки происходит:
initEnvironment
.loadFile
для загрузки kernel.bin в память по адресу 0x1000:0000
и последующей передачи ему права выполнения.Этот файл содержит все предопределенные макросы и функции.
/********************************************************************************* * *
* *
* Name : macros.S *
* Date : 23-Feb-2014 *
* Version : 0.0.1 *
* Source : assembly language *
* Author : Ashakiran Bhatter *
* *
* *
*********************************************************************************/
/* предопределенный макрос: загрузчик */
#define BOOT_LOADER_CODE_AREA_ADDRESS 0x7c00
#define BOOT_LOADER_CODE_AREA_ADDRESS_OFFSET 0x0000
/* предопределенный макрос: сегмент стека */
#define BOOT_LOADER_STACK_SEGMENT 0x7c00
#define BOOT_LOADER_ROOT_OFFSET 0x0200
#define BOOT_LOADER_FAT_OFFSET 0x0200
#define BOOT_LOADER_STAGE2_ADDRESS 0x1000
#define BOOT_LOADER_STAGE2_OFFSET 0x0000
/* предопределенный макрос: разметка дискеты */
#define BOOT_DISK_SECTORS_PER_TRACK 0x0012
#define BOOT_DISK_HEADS_PER_CYLINDER 0x0002
#define BOOT_DISK_BYTES_PER_SECTOR 0x0200
#define BOOT_DISK_SECTORS_PER_CLUSTER 0x0001
/* предопределенный макрос: разметка файловой системы */
#define FAT12_FAT_POSITION 0x0001
#define FAT12_FAT_SIZE 0x0009
#define FAT12_ROOT_POSITION 0x0013
#define FAT12_ROOT_SIZE 0x000e
#define FAT12_ROOT_ENTRIES 0x00e0
#define FAT12_END_OF_FILE 0x0ff8
/* предопределенный макрос: загрузчик */
#define BOOT_SIGNATURE 0xaa55
/* пользовательские макросы */
/* макрос для установки среды */
.macro initEnvironment
call _initEnvironment
.endm
/* макрос для отображения строки на экране. */
/* Для выполнения этой операции он вызывает функцию _writeString */
/* параметр: вводная строка */
.macro writeString message
pushw message
call _writeString
.endm
/* макрос для считывания сектора в памяти */
/* Вызывает функцию _readSector со следующими параметрами */
/* параметры: номер сектора */
/* адрес загрузки */
/* смещение адреса */
/* количество считываемых секторов */
.macro readSector sectorno, address, offset, totalsectors
pushw sectorno
pushw address
pushw offset
pushw totalsectors
call _readSector
addw $0x0008, %sp
.endm
/* макрос для поиска файла на FAT-диске. */
/* Для этого он вызывает макрос readSector */
/* параметры: адрес корневого каталога */
/* целевой адрес */
/* целевое смещение */
/* размер корневого каталога */
.macro findFile file
/* считывание таблицы FAT в память */
readSector $FAT12_ROOT_POSITION, $BOOT_LOADER_CODE_AREA_ADDRESS, $BOOT_LOADER_ROOT_OFFSET, $FAT12_ROOT_SIZE
pushw file
call _findFile
addw $0x0002, %sp
.endm
/* макрос для преобразования заданного кластера в номер сектора */
/* Для этого он вызывает _clusterToLinearBlockAddress */
/* параметр: номер кластера */
.macro clusterToLinearBlockAddress cluster
pushw cluster
call _clusterToLinearBlockAddress
addw $0x0002, %sp
.endm
/* макрос для загрузки целевого файла в память. */
/* Он вызывает findFile и загружает данные соответствующего файла в память */
/* по адресу 0x1000:0x0000 */
/* параметр: имя целевого файла */
.macro loadFile file
/* проверка наличия файла */
findFile file
pushw %ax
/* считывание таблицы FAT в память */
readSector $FAT12_FAT_POSITION, $BOOT_LOADER_CODE_AREA_ADDRESS, $BOOT_LOADER_FAT_OFFSET, $FAT12_FAT_SIZE
popw %ax
movw $BOOT_LOADER_STAGE2_OFFSET, %bx
_loadCluster:
pushw %bx
pushw %ax
clusterToLinearBlockAddress %ax
readSector %ax, $BOOT_LOADER_STAGE2_ADDRESS, %bx, $BOOT_DISK_SECTORS_PER_CLUSTER
popw %ax
xorw %dx, %dx
movw $0x0003, %bx
mulw %bx
movw $0x0002, %bx
divw %bx
movw $BOOT_LOADER_FAT_OFFSET, %bx
addw %ax, %bx
movw $BOOT_LOADER_CODE_AREA_ADDRESS, %ax
movw %ax, %es
movw %es:(%bx), %ax
orw %dx, %dx
jz _even_cluster
_odd_cluster:
shrw $0x0004, %ax
jmp _done
_even_cluster:
and $0x0fff, %ax
_done:
popw %bx
addw $BOOT_DISK_BYTES_PER_SECTOR, %bx
cmpw $FAT12_END_OF_FILE, %ax
jl _loadCluster
/* выполнение ядра */
initKernel
.endm
/* параметры: имя целевого файла */
/* макрос для передачи права выполнения файлу, загруженному */
/* в память по адресу 0x1000:0x0000 */
/* параметры: none */
.macro initKernel
/* инициализация ядра */
movw $(BOOT_LOADER_STAGE2_ADDRESS), %ax
movw $(BOOT_LOADER_STAGE2_OFFSET) , %bx
movw %ax, %es
movw %ax, %ds
jmp $(BOOT_LOADER_STAGE2_ADDRESS), $(BOOT_LOADER_STAGE2_OFFSET)
.endm
initEnvironment:
Применение: initEnvironment
writeString:
Применение: writeString <строковая переменная>
readSector:
Применение: readSector <номер сектора>, <целевой адрес>, <смещение целевого адреса>, <количество считываемых секторов>
findFile:
Применение: findFile <имя целевого файла>
clusterToLinearBlockAddress:
Применение:
clusterToLinearBlockAddress <ID кластера>
loadFile:
Применение:
loadFile <имя целевого файла>
initKernel:
Применение: initKernel
/*********************************************************************************
* *
* *
* Name : routines.S *
* Date : 23-Feb-2014 *
* Version : 0.0.1 *
* Source : assembly language *
* Author : Ashakiran Bhatter *
* *
* *
*********************************************************************************/
/* Пользовательские подпрограммы. */
/* функция для настройки регистров и стека */
/* параметры: none */
_initEnvironment:
pushw %bp
movw %sp, %bp
_initEnvironmentIn:
cli
movw %cs, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
movw $BOOT_LOADER_STACK_SEGMENT, %sp
sti
_initEnvironmentOut:
movw %bp, %sp
popw %bp
ret
/* функция для отображения строки на экране */
/* параметр: вводная строка */
_writeString:
pushw %bp
movw %sp , %bp
movw 4(%bp) , %si
jmp _writeStringCheckByte
_writeStringIn:
movb $0x000e, %ah
movb $0x0000, %bh
int $0x0010
incw %si
_writeStringCheckByte:
movb (%si) , %al
orb %al , %al
jnz _writeStringIn
_writeStringOut:
movw %bp , %sp
popw %bp
ret
/* функция для считывания сектора в целевой адрес памяти */
/* параметры: номер сектора */
/* целевой адрес */
/* смещение адреса */
/* количество считываемых секторов */
_readSector:
pushw %bp
movw %sp , %bp
movw 10(%bp), %ax
movw $BOOT_DISK_SECTORS_PER_TRACK, %bx
xorw %dx , %dx
divw %bx
incw %dx
movb %dl , %cl
movw $BOOT_DISK_HEADS_PER_CYLINDER, %bx
xorw %dx , %dx
divw %bx
movb %al , %ch
xchg %dl , %dh
movb $0x02 , %ah
movb 4(%bp) , %al
movb bootDrive, %dl
movw 8(%bp) , %bx
movw %bx , %es
movw 6(%bp) , %bx
int $0x13
jc _abort
cmpb 4(%bp) , %al
jc _abort
movw %bp , %sp
popw %bp
ret
/* функция поиска файла на дискете */
/* параметры: адрес корневого каталога */
/* целевой адрес */
/* целевое смещение */
/* размер корневого каталога */
_findFile:
pushw %bp
movw %sp , %bp
movw $BOOT_LOADER_CODE_AREA_ADDRESS, %ax
movw %ax , %es
movw $BOOT_LOADER_ROOT_OFFSET, %bx
movw $FAT12_ROOT_ENTRIES, %dx
jmp _findFileInitValues
_findFileIn:
movw $0x000b , %cx
movw 4(%bp) , %si
leaw (%bx) , %di
repe cmpsb
je _findFileOut
_findFileDecrementCount:
decw %dx
addw $0x0020, %bx
_findFileInitValues:
cmpw $0x0000, %dx
jne _findFileIn
je _abort
_findFileOut:
addw $0x001a , %bx
movw %es:(%bx), %ax
movw %bp, %sp
popw %bp
ret
/* функция для преобразования заданного кластера в номер сектора */
/* параметры: номер кластера */
_clusterToLinearBlockAddress:
pushw %bp
movw %sp , %bp
movw 4(%bp) , %ax
_clusterToLinearBlockAddressIn:
subw $0x0002, %ax
movw $BOOT_DISK_SECTORS_PER_CLUSTER, %cx
mulw %cx
addw $FAT12_ROOT_POSITION, %ax
addw $FAT12_ROOT_SIZE, %ax
_clusterToLinearBlockAddressOut:
movw %bp , %sp
popw %bp
ret
_initEnvironment:
Применение: call _initEnvironment
_writeString:
Применение:
pushw <строковая переменная>
call _writeString
addw $0x02, %sp
readSector:
Применение:
pushw <номер сектора>
pushw <адрес>
pushw <смещение>
pushw <всего секторов>
call _readSector
addw $0x0008, %sp
findFile:
Применение:
pushw <target file variable>
call _findFile
addw $0x02, %sp
clusterToLinearBlockAddress:
Применение:
pushw <ID кластера>
call _clusterToLinearBlockAddress
addw $0x02, %sp
loadFile:
Применение:
pushw <целевой файл>
call _loadFile
addw $0x02, %sp
Этот файл служит для линковки файла stage0.object
.
/*********************************************************************************
* *
* *
* Name : stage0.ld *
* Date : 23-Feb-2014 *
* Version : 0.0.1 *
* Source : assembly language *
* Author : Ashakiran Bhatter *
* *
* *
*********************************************************************************/
SECTIONS
{
. = 0x7c00;
.text :
{
_ftext = .;
} = 0
}
Файл-конфигурации, необходимый для запуска эмулятора bochs.
megs: 32
floppya: 1_44=../iso/stage0.img, status=inserted
boot: a
log: ../log/bochsout.txt
mouse: enabled=0
Ниже приведен исходный код макета ядра, используемого как часть процесса тестирования. Нам нужно только скомпилировать этот код, используя make file
и проверить, загрузит ли его загрузчик.
Сначала будет отображаться заставка с головой дракона, сопровождаемая экраном приветствия, после которого откроется командная строка.
Учтите, что здесь не запрограммировано никаких команд или утилит для выполнения. Это просто макет ядра, заготовленный исключительно в целях тестирования.
/*********************************************************************************
* *
* *
* Name : kernel.c *
* Date : 23-Feb-2014 *
* Version : 0.0.1 *
* Source : C *
* Author : Ashakiran Bhatter *
* *
* Описание: За загрузку этого файла отвечает stage0.bin, который передает *
* ему право выполнения. Его функциональность *
* заключается в отображении экрана-заставки и командной строки. *
* Внимание : Вводить команды бессмысленно, так как они не запрограммированы*
* *
*********************************************************************************/
/* генерирует 16-битный код */
__asm__(".code16n");
/* переход к основной функции */
__asm__("jmpl $0x1000, $mainn");
#define TRUE 0x01
#define FALSE 0x00
char str[] = "$> ";
/* функция установки регистров и стека */
/* параметры: none */
void initEnvironment() {
__asm__ __volatile__(
"cli;"
"movw $0x0000, %ax;"
"movw %ax, %ss;"
"movw $0xffff, %sp;"
"cld;"
);
__asm__ __volatile__(
"movw $0x1000, %ax;"
"movw %ax, %ds;"
"movw %ax, %es;"
"movw %ax, %fs;"
"movw %ax, %gs;"
);
}
/* VGA-функции. */
/* функция для установки режима VGA на 80*24 */
void setResolution() {
__asm__ __volatile__(
"int $0x10" : : "a"(0x0003)
);
}
/* функция очистки буфера экрана разделяющими пробелами */
void clearScreen() {
__asm__ __volatile__ (
"int $0x10" : : "a"(0x0200), "b"(0x0000), "d"(0x0000)
);
__asm__ __volatile__ (
"int $0x10" : : "a"(0x0920), "b"(0x0007), "c"(0x2000)
);
}
/* функция установки позиции курсора на заданный столбец и строку */
void setCursor(short col, short row) {
__asm__ __volatile__ (
"int $0x10" : : "a"(0x0200), "d"((row <<= 8) | col)
);
}
/* функция включения и отключения курсора */
void showCursor(short choice) {
if(choice == FALSE) {
__asm__ __volatile__(
"int $0x10" : : "a"(0x0100), "c"(0x3200)
);
} else {
__asm__ __volatile__(
"int $0x10" : : "a"(0x0100), "c"(0x0007)
);
}
}
/* функция инициализации режима VGA на 80*25, */
/* очистки экрана и установки положения курсора на (0,0) */
void initVGA() {
setResolution();
clearScreen();
setCursor(0, 0);
}
/* I/O-функции. */
/* функция для получения символа с клавиатуры без эха*/
void getch() {
__asm__ __volatile__ (
"xorw %ax, %axn"
"int $0x16n"
);
}
/* эта функция аналогична getch(), */
/* но возвращает скан-код клавиши и соответствующее значение ascii */
short getchar() {
short word;
__asm__ __volatile__(
"int $0x16" : : "a"(0x1000)
);
__asm__ __volatile__(
"movw %%ax, %0" : "=r"(word)
);
return word;
}
/* функция для отображения нажатых клавиш на экране*/
void putchar(short ch) {
__asm__ __volatile__(
"int $0x10" : : "a"(0x0e00 | (char)ch)
);
}
/* функция вывода на экран строки с завершающим нулем */
void printString(const char* pStr) {
while(*pStr) {
__asm__ __volatile__ (
"int $0x10" : : "a"(0x0e00 | *pStr), "b"(0x0002)
);
++pStr;
}
}
/* функция, вызывающая задержку на несколько секунд */
void delay(int seconds) {
__asm__ __volatile__(
"int $0x15" : : "a"(0x8600), "c"(0x000f * seconds), "d"(0x4240 * seconds)
);
}
/* Строковая функция. */
/* эта функция вычисляет длину строки и возвращает ее */
int strlength(const char* pStr) {
int i = 0;
while(*pStr) {
++i;
}
return i;
}
/* Функция UI. */
/*эта функция отображает логотип */
void splashScreen(const char* pStr) {
showCursor(FALSE);
clearScreen();
setCursor(0, 9);
printString(pStr);
delay(10);
}
/* Оболочка. */
/* функция для отображения фиктивной командной строки. */
/* При нажатии клавиши Ввод выполняется переход на следующую строку */
void shell() {
clearScreen();
showCursor(TRUE);
while(TRUE) {
printString(str);
short byte;
while((byte = getchar())) {
if((byte >> 8) == 0x1c) {
putchar(10);
putchar(13);
break;
} else {
putchar(byte);
}
}
}
}
/* точка входа в ядро */
void main() {
const char msgPicture[] =
" .. nr"
" ++` nr"
" :ho. `.-/++/. nr"
" `/hh+. ``:sds: nr"
" `-odds/-` .MNd/` nr"
" `.+ydmdyo/:--/yMMMMd/ nr"
" `:+hMMMNNNMMMddNMMh:` nr"
" `-:/+++/:-:ohmNMMMMMMMMMMMm+-+mMNd` nr"
" `-+oo+osdMMMNMMMMMMMMMMMMMMMMMMNmNMMM/` nr"
" ``` .+mMMMMMMMMMMMMMMMMMMMMMMMMMMMMNmho:.` nr"
" `omMMMMMMMMMMMMMMMMMMNMdydMMdNMMMMMMMMdo+- nr"
" .:oymMMMMMMMMMMMMMNdo/hMMd+ds-:h/-yMdydMNdNdNN+ nr"
" -oosdMMMMMMMMMMMMMMd:` `yMM+.+h+.- /y `/m.:mmmN nr"
" -:` dMMMMMMMMMMMMMd. `mMNo..+y/` . . -/.s nr"
" ` -MMMMMMMMMMMMMM- -mMMmo-./s/.` ` nr"
" `+MMMMMMMMMMMMMM- .smMy:.``-+oo+//:-.` nr"
" .yNMMMMMMMMMMMMMMd. .+dmh+:. `-::/+:. nr"
" y+-mMMMMMMMMMMMMMMm/` ./o+-` . nr"
" :- :MMMMMMMMMMMMMMMMmy/.` nr"
" ` `hMMMMMMMMMMMMMMMMMMNds/.` nr"
" sNhNMMMMMMMMMMMMMMMMMMMMNh+. nr"
" -d. :mMMMMMMMMMMMMMMMMMMMMMMNh:` nr"
" /. .hMMMMMMMMMMMMMMMMMMMMMMMMh. nr"
" . `sMMMMMMMMMMMMMMMMMMMMMMMMN. nr"
" hMMMMMMMMMMMMMMMMMMMMMMMMy nr"
" +MMMMMMMMMMMMMMMMMMMMMMMMh ";
const char msgWelcome[] =
" *******************************************************nr"
" * *nr"
" * Welcome to kirUX Operating System *nr"
" * *nr"
" *******************************************************nr"
" * *nr"
" * *nr"
" * Author : Ashakiran Bhatter *nr"
" * Version: 0.0.1 *nr"
" * Date : 01-Mar-2014 *nr"
" * *nr"
" ******************************************************";
initEnvironment();
initVGA();
splashScreen(msgPicture);
splashScreen(msgWelcome);
shell();
while(1);
}
initEnvironment():
Применение: initEnvironment();
setResolution():
Применение: setResolution();
clearScreen():
Применение: clearScreen();
setCursor():
Применение: setCursor(столбец, строка);
showCursor():
Применение: showCursor(1);
initVGA():
Применение: initVGA();
getch():
Применение: getch();
getchar():
Применение: getchar();
putchar():
Применение: putchar(символ);
printString():
Применение: printString();
delay():
Применение: printString(строковая переменная с завершающим нулем);
strlength():
Применение: strlength(строковая переменная с завершающим нулем);
splashScreen():
Применение: splashScreen(строковая переменная с завершающим нулем);
shell():
Применение: shell();
Использование исходного кода:
В прикрепленном архиве sourcecode.tar.gz
находятся все исходные файлы и каталоги, необходимые для генерации исполняемых файлов.
Убедитесь, что вы являетесь супер-пользователем системы, после чего распакуйте архив.
Для перехода к компиляции и тестированию кода установите эмулятор bochs-x64 и GNU bin-utils.
После извлечения файлов вы увидите 5 каталогов:
Подготовив среду, откройте терминал и выполните следующие команды:
cd $(DIRECTORY)/src
make -f Makefile test
bochs
Экран 1:
Это первый экран, отображаемый при выполнении ядра.
Экран 2:
Дальше идет экран приветствия:
Экран 3:
Это командная строка, в которой можно ввести текст.
Экран 4:
Здесь я привожу пример написания команд и перехода строки при нажатии Ввода.
Если у вас возникнут какие-либо сложности, смело пишите в комментариях (ссылка [3]на оригинал публикации), буду рад помочь разобраться.
Надеюсь, что эта статья помогла вам понять принцип работы файловой системы, а также освоить написание загрузчика для ее считывания. Теперь вы можете смело продолжать экспериментировать с внедрением в написанное нами ядро другой функциональности.
Автор: Дмитрий Брайт
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/c-3/360611
Ссылки в тексте:
[1] первой : https://habr.com/ru/company/ruvds/blog/536132/
[2] второй: https://habr.com/ru/company/ruvds/blog/536156/
[3] ссылка : https://www.codeproject.com/Articles/737545/Writing-a-bit-dummy-kernel-in-C-Cplusplus
[4] Image: http://ruvds.com/ru-rub?utm_source=habr&utm_medium=perevod&utm_campaign=bright_translate&utm_content=cicplusplus#order
[5] Источник: https://habr.com/ru/post/536336/?utm_source=habrahabr&utm_medium=rss&utm_campaign=536336
Нажмите здесь для печати.