ПЕРЕЛІК ДИСЦИПЛІН:
  • Адміністративне право
  • Арбітражний процес
  • Архітектура
  • Астрологія
  • Астрономія
  • Банківська справа
  • Безпека життєдіяльності
  • Біографії
  • Біологія
  • Біологія і хімія
  • Ботаніка та сільське гос-во
  • Бухгалтерський облік і аудит
  • Валютні відносини
  • Ветеринарія
  • Військова кафедра
  • Географія
  • Геодезія
  • Геологія
  • Етика
  • Держава і право
  • Цивільне право і процес
  • Діловодство
  • Гроші та кредит
  • Природничі науки
  • Журналістика
  • Екологія
  • Видавнича справа та поліграфія
  • Інвестиції
  • Іноземна мова
  • Інформатика
  • Інформатика, програмування
  • Юрист по наследству
  • Історичні особистості
  • Історія
  • Історія техніки
  • Кибернетика
  • Комунікації і зв'язок
  • Комп'ютерні науки
  • Косметологія
  • Короткий зміст творів
  • Криміналістика
  • Кримінологія
  • Криптология
  • Кулінарія
  • Культура і мистецтво
  • Культурологія
  • Російська література
  • Література і російська мова
  • Логіка
  • Логістика
  • Маркетинг
  • Математика
  • Медицина, здоров'я
  • Медичні науки
  • Міжнародне публічне право
  • Міжнародне приватне право
  • Міжнародні відносини
  • Менеджмент
  • Металургія
  • Москвоведение
  • Мовознавство
  • Музика
  • Муніципальне право
  • Податки, оподаткування
  •  
    Бесплатные рефераты
     

     

     

     

     

     

         
     
    The Real Hello World
         

     

    Інформатика, програмування

    The Real Hello World

    В цій статті ми напишемо ... власну міні-ОС. Так так, створимо свою власну операційну систему. Правда система буде вантажитися з дискети і виводити знайоме Hello World, але погодьтеся, це справить враження і на вас, і на ваших друзів. Адже саме Ви створите СВОЮ

    міні-ОС.

    1. Ідея (hello.c)

    Вивчення нової мови програмування починається, як правило, з написання простенькій програми, що виводить на екран коротке привітання типу "Hello World! ". Наприклад, для C це буде виглядати приблизно так.

    main ()

    (

    printf ( "Hello World! N ");

    )

    Показово, але зовсім не цікаво. Програма, звичайно працює, захищений режим, але адже для її функціонування потрібно ЦІЛА операційна система. А що якщо написати такий "Hello World", для якого нічого не треба. Вставляємо дискетки в комп'ютер, завантажується з неї і ... "Hello World". Можна навіть прокричати це вітання із захищеного режиму.

    Сказано - Зроблено. З чого почати? .. Набратися знань, звичайно. Для цього дуже добре полазити в исходники Linux і Thix. Перша система всім добре знайома, друга менш відома, але не менш корисна.

    Підучившись? ... Зрозуміло, що спочатку треба написати завантажувальний сектор для нашої міні-опрераціонкі (адже це саме міні-операційка). Оскільки процесор вантажиться в 16-розрядному режимі, то для созджанія завантажувального сектора використовується асемблер і лінковщік з пакету bin86. Можна, звичайно, пошукати ще що-небудь, але обидва наших прикладу використовують саме його і ми теж піде по стопах вчителів. Синтаксис цього асемблера немколько дивакуватий, що поєднує риси, характерні і для Intel і для AT & T (за подробицями прямуйте до Linux-Assembly-HOWTO), але після кількох тижнів мук можна звикнути.

    2. Завантажувальний сектор (boot.S)

    Свідомо не буду приводити лістингів програм. Так стануть зрозуміліше основні ідеї, та й вам буде набагато приємніше, якщо все напишіть своїми руками.

    Для Спершу визначимося з основними константами.

    START_HEAD = 0 - Головка приводу, яку будемо використовувати.

    START_TRACK = 0 - Доріжка, звідки почнемо читання.

    START_SECTOR = 2 - Сектор, починаючи з якого будемо зчитувати наше ядерце.

    SYSSIZE = 10 - Розмір ядра в секторах (кожен сектор містить 512 байт)

    FLOPPY_ID = 0 - Ідентифікатор приводу. 0 - для першого, 1 - для друга

    HEADS = 2 - Кількість головок приводу.

    SECTORS = 18 - Кількість доріжок на дискеті. Для формату 1.44 Mb це кількість дорівнює 18.

    В процесі завантаження буде відбуватися наступне. Завантажувач BIOS вважає перший сектор дискети, покладе його за адресою 0000:0 x7c00 і передасть туди управління. Ми його отримаємо і для початку перемістити себе нижче за адресою 0000:0 x600, перейдемо туди і спокійно продовжимо роботу. Власне вся наша робота буде складатися з завантаження ядра (сектори 2 - 12 перших доріжки дискети) за адресою 0x100: 0000, переходу в захищений режим і стрибка на перші рядки ядра. У зв'язку з цим ще декілька констант:

    BOOTSEG = 0x7c00 - Сюди помістить завантажувальний сектор BIOS.

    INITSEG = 0x600 - Сюди його перемістив ми.

    SYSSEG = 0x100 - А тут приємно розташується наше ядро.

    DATA_ARB = 0x92 - Визначник сегмента даних для дескриптора

    CODE_ARB = 0x9A - Визначник сегменту коду для дескриптора.

    Першим справою зробимо переміщення самих себе в більш прийнятне місце.

    cli

    xor ax, ax

    mov ss, ax

    mov sp, # BOOTSEG

    mov si, sp

    mov ds, ax

    mov es, ax

    sti

    cld

    mov di, # INITSEG

    mov cx, # 0x100

    repnz

    movsw

    jmpi go, # 0; стрибок у нове місце розташування

    завантажувального сектору на мітку go

    Тепер необхідно налаштувати як слід сегменти для даних (es, ds) і для стека. Це звичайно неприємно, що все доводиться робити вручну, але що робити. Адже немає нікого в пам'яті комп'ютера, крім нас і BIOS.

    go:

    mov ax, # 0xF0

    mov ss, ax

    mov sp, ax; Стек розмістимо як 0xF0: 0xF0 = 0xFF0

    mov ax, # 0x60; Сегменти для даних ES і DS поставимо в 0x60

    mov ds, ax

    mov es, ax

    Нарешті можна вивести переможний привітання. Нехай світ дізнається, що ми змогли завантажитися. Оскільки у нас є все-таки ще BIOS, скористаємося готової функцією 0x13 переривання 0x10. Можна звичайно знехтувати його і написати прямо в відеопам'ять, але у нас кожен байт команди на рахунку, а байт таких всього 512. Витратимо їх краще на щось більш корисне.

    mov cx, # 18

    mov bp, # boot_msg

    call write_message

    Функція write_message вигдядіт наступним чином

    write_message:

    push bx

    push ax

    push cx

    push dx

    push cx

    mov ah, # 0x03; прочитаємо поточне положення курсору,

    щоб не виводити повідомлення де попало.

    xor bh, bh

    int 0x10

    pop cx

    mov bx, # 0x0007; Параметри символів, що виводяться:

    відеосторінок 0, атрибут 7 (сірий на чорному)

    mov ax, # 0x1301; Виводимо рядок і Зрушуємо курсор.

    int 0x10

    pop dx

    pop cx

    pop ax

    pop bx

    ret

    А повідомлення так

    boot_msg:

    . byte 13,10

    . ascii "Booting data ..."

    . byte 0

    До цього часу на дисплеї комп'ютера з'явиться скромне "Booting data ... ". Це в принципі вже" Hello World ", але давайте доб'ємося трішки більшого. Перейдемо в захищений режим і виведемо цей "Hello" вже з програми написаної на C.

    Ядро 32-розрядне. Воно буде у нас розміщуватися окремо від завантажувального сектора і збиратися вже gcc і gas. Синтаксис асемблера gas відповідає вимогам AT & T, так що тут уже все простіше. Але для початку нам потрібно прочитати ядро. Знову скористаємося готової функцією 0x2 переривання 0x13.

    recalibrate:

    mov ah, # 0

    mov dl, # FLOPPY_ID

    int 0x13; виробляємо переініціалізацію дисководу.

    jc recalibrate

    call read_track; виклик функції читання ядра

    jnc next_work; якщо під час читання не відбулося нічого

    поганого то працюємо далі

    bad_read:

    ; якщо читання відбулося невдало то виводимо повідомлення про помилку

    mov bp, # error_read_msg

    mov cx, 7

    call write_message

    inf1: jmp inf1; і йдемо в нескінченний цикл.

    Тепер нас врятує тільки ручна перезавантаження

    Сама функція читання гранично проста: довго і нудно заповнюємо параметри, а потім одним махом зчитуємо ядро. Ускладнення розпочнуться, коли ядро перестане поміщатися в 17 секторах (тобто 8.5 kb), але це поки що тільки в майбутньому, а поки цілком достатньо такого блискавичного читання.

    read_track:

    pusha

    push es

    push ds

    mov di, # SYSSEG; Визначаємо

    mov es, di; адреса буфера для даних

    xor bx, bx

    mov ch, # START_TRACK; доріжка 0

    mov cl, # START_SECTOR; починаючи з сектора 2

    mov dl, # FLOPPY_ID

    mov dh, # START_HEAD

    mov ah, # 2

    mov al, # SYSSIZE; вважати 10 секторів

    int 0x13

    pop ds

    pop es

    popa

    ret

    Ось і все. Ядро успішно прочитано і можна вивести ще одне радісне повідомлення на екран.

    next_work:

    call kill_motor; зупиняємо привід дисководу

    mov bp, # load_msg; виводимо повідомлення

    mov cx, # 4

    call write_message

    Ось вміст повідомлення

    load_msg:

    . ascii "done"

    . byte 0

    А от функція зупинки двигуна приводу.

    kill_motor:

    push dx

    push ax

    mov dx, # 0x3f2

    xor al, al

    out dx, al

    pop ax

    pop dx

    ret

    На даний момент на екрані виведено "Booting data ... done" і лампочка привода флоппі-дисків погашена. Всі затихли і готові до смертельного номеру -- стрибка в захищений режим.

    Для Спершу треба включити адресну лінію A20. Це в точності означає, що ми будемо використовувати 32-розрядну адресацію до даних.

    mov al, # 0xD1; команда запису для 8042

    out # 0x64, al

    mov al, # 0xDF; включити A20

    out # 0x60, al

    Виведемо попередження, про те, що переходимо в захищений режим. Нехай все знають, які ми важливі.

    protected_mode:

    mov bp, # loadp_msg

    mov cx, # 25

    call write_message

    (Повідомлення:

    loadp_msg:

    . byte 13,10

    . ascii "Go to protected mode ..."

    . byte 0

    )

    Поки ще у нас живий BIOS, запам'ятаємо позицію курсору і збережемо її у відомому місці ( 0000:0 x8000). Ядро пізніше забере всі дані і буде їх використовувати для виведення на екран переможного повідомлення.

    save_cursor:

    mov ah, # 0x03; читаємо поточну позицію курсору

    xor bh, bh

    int 0x10

    seg cs

    mov [0x8000], dx; зберігаємо в спеціальному тайнику

    Тепер увагу, забороняємо переривання (нема чого відволікатися під час такої роботи) і завантажуємо таблицю дескрипторів

    cli

    lgdt GDT_DESCRIPTOR; завантажуємо описувач таблиці дескрипторів.

    У нас таблиця дескрипторів складається з трьох описувачів: Нульовий (завжди повинен бути присутнім), сегменту коду і сегменту даних

    . align 4

    . word 0

    GDT_DESCRIPTOR:. word 3 * 8 - 1; розмір таблиці

    дескрипторів

    . long 0x600 + GDT; місце розташування

    таблиці дескрипторів

    . align 2

    GDT:

    . long 0, 0; Номер 0: порожній

    дескриптор

    . word 0xFFFF, 0; Номер 8:

    дескриптор коду

    . byte 0, CODE_ARB, 0xC0, 0

    . word 0xFFFF, 0; Номер 0x10:

    дескриптор даних

    . byte 0, DATA_ARB, 0xCF, 0

    Перехід в захищений режим може відбуватися мінімум двома способами, але обидві ОС, обрані нами для прикладу (Linux і Thix) використовують для сумісності з 286 процесором команду lmsw. Ми будемо діяти тим же способом

    mov ax, # 1

    lmsw ax; прощай реальний режим. Ми тепер

    знаходимося в захищеному режимі.

    jmpi 0x1000, 8; Затяжний стрибок на 32-розрядне ядро.

    Ось і вся робота завантажувального сектора - чимало, але й небагато. Тепер ми попрощаємося з ним і попрямуємо до ядра.

    В Наприкінці асемблерні файлу корисно додати наступну інструкцію.

    . org 511

    end_boot: . byte 0

    В результаті скомпільований код буде займати рівно 512 байт, що дуже зручно для підготовки образу завантажувального диска.

    3. Перші подихи ядра (head.S)

    Ядро на жаль знову почнеться з асемблерні коду. Але тепер його буде зовсім небагато.

    Ми власне задамо правильні значення сегментів для даних (ES, DS, FS, GS). Записав туди значення відповідного дескриптора даних.

    cld

    cli

    movl $ (__KERNEL_DS),% Eax

    movl% ax,% ds

    movl% ax,% es

    movl% ax,% fs

    movl% ax,% gs

    Перевіримо, чи нормально включилася адресна лінія A20 простим тестом запису. Обнулив для чистоти експерименту регістр прапорів.

    xorl % eax,% eax

    1: incl% eax

    movl% eax, 0x000000

    cmpl% eax, 0x100000

    je 1b

    pushl $ 0

    popfl

    викличемо довгоочікувану функцію, уже написану на С.

    call SYMBOL_NAME (start_my_kernel)

    І більше нам тут робити нічого.

    inf: jmp inf

    4. Поговоримо на мові високого рівня (start.c)

    Ось тепер ми повернулися до того з чого починали розповідь. Майже повернулися, тому що printf () тепер треба робити вручну. оскільки готових переривань вже немає, то будемо використовувати прямі запис у відеопам'ять. Для цікавих - майже весь код цій частині, з незначними змінами, повзаімствован з частини ядра Linux, здійснює розпакування (/ arch/i386/boot/compressed/*). Для збирання вам буде потрібно додатково визначити такі макроси як inb (), outb (), inb_p (), outb_p (). Готові визначення найпростіше позичити з будь-якої версії Linux.

    Тепер, щоб не плутатися з вбудованими в glibc функціями, скасуємо їх визначення

    # undef memcpy

    Задамо кілька своїх

    static void puts (const char *);

    static char * vidmem = (char *) 0xb8000;/* адреса відеопаматі */

    static int vidport;/* відеопортів */

    static int lines, cols;/* кількість ліній і рядків на екран */

    static int curr_x, curr_y;/* поточне положення курсору */

    І почнемо, нарешті, писати код на мові високого рівня ... правда з невеликими асемблерні вставками.

    /* функція перекладу курсору в положення (x, y). Робота ведеться через введення/виведення в відеопортів */

    void gotoxy (int x, int y)

    (

    int pos;

    pos = (x + cols * y) * 2;

    outb_p (14, vidport);

    outb_p (0xff & (pos>> 9), vidport +1);

    outb_p (15, vidport);

    outb_p (0xff & (pos>> 1), vidport +1);

    )

    /* функція прокручування екрану. Працює, використовуючи пряму запис у відеопам'ять */

    static void scroll ()

    (

    int i;

    memcpy (vidmem, vidmem + cols * 2, (Lines - 1) * cols * 2);

    for (i = (lines - 1) * cols * 2; i

    vidmem [i] = '';

    )

    /* функція виводу рядка на екран */

    static void puts (const char * s)

    (

    int x, y;

    char c;

    x = curr_x;

    y = curr_y;

    while ((c = * s + +)! = '

         
     
         
    Реферат Банк
     
    Рефераты
     
    Бесплатные рефераты
     

     

     

     

     

     

     

     
     
     
      Все права защищены. Reff.net.ua - українські реферати ! DMCA.com Protection Status