GithubHelp home page GithubHelp logo

kkamagui / mint64os Goto Github PK

View Code? Open in Web Editor NEW
60.0 60.0 25.0 1.49 MB

Project for making your own 64bit multicore operating system (MINT64 OS) from scratch

Assembly 4.21% Makefile 1.74% C 92.83% Objective-C 0.32% C++ 0.90% Batchfile 0.01%

mint64os's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mint64os's Issues

Ring 3

IA-32e모드에서 Ring 3로 진입하려면 어떻게 해야하나요? 디스크립터 테이블에 DPL을 3으로 만든 후 Ring 3용 코드 세그먼트와 데이터 세그먼트를 만들면 되는건가요?

계속 질문해서 죄송합니다

kernel process의 bFPUUsed field가 초기화안됨으로써 실제 PC에서 소수점 계산 중 GP exception 발생하는 문제

안녕하세요. 챕터 22를 공부하다가 발견한 문제입니다. 지난번에 올린 이슈와 비슷한 양상을 보이는 문제로 kernel process의 bFPUUsed field를 초기화하면 해결이 됩니다.

문제를 좀 더 설명하자면, bFPUUsed 변수가 0이 아닌 임의의 숫자가 들어있을 경우 생기는데요. Task가 FPU instruction를 처음 실행하더라도 bFPUUsed변수가 0이 아니라서 FPU 초기화를 하지 않습니다. fxrstor 명령어를 통해 아직 제대로된 데이터가 들어있지 않는 TCB FPU context를 FPU에 넣어버리더라고요. 이 과정에 건드리면 안되는 register를 건드리면서 GP exception이 발생하는 걸 확인했습니다.

링크에 따르면 fxrstor 명령어가 FPU register인 MXCSR에 예약된 bits를 설정하면 GP exception이 발생한다고 명시되어있습니다.

Original Code

void kInitializeScheduler( void )
{
    // 함수의 윗부분을 생략했습니다.
    
    pstTask->qwParentProcessID = pstTask->stLink.qwID;
    pstTask->pvMemoryAddress = ( void* ) 0x100000;
    pstTask->qwMemorySize = 0x500000;
    pstTask->pvStackAddress = ( void* ) 0x600000;
    pstTask->qwStackSize = 0x100000;
    
    // 프로세서 사용률을 계산하는데 사용하는 자료구조 초기화
    gs_vstScheduler[ bCurrentAPICID ].qwSpendProcessorTimeInIdleTask = 0;
    gs_vstScheduler[ bCurrentAPICID ].qwProcessorLoad = 0;
    
    // FPU를 사용한 태스크 ID를 유효하지 않은 값으로 초기화
    gs_vstScheduler[ bCurrentAPICID ].qwLastFPUUsedTaskID = TASK_INVALIDID;
}

Suggested Code

void kInitializeScheduler(void) {
    // 이 함수의 윗부분을 생략했습니다.

    pstTask->qwParentProcessID = pstTask->stLink.qwID;
    pstTask->pvMemoryAddress = (void *) 0x100000;
    pstTask->qwMemorySize = 0x500000;
    
    pstTask->pvStackAddress = (void *) 0x600000;
    pstTask->qwStackSize = 0x100000;

    // 바뀐 부분
    pstTask->bFPUUsed = FALSE;

    // initialize variables that help to calculate processor load
    gs_stScheduler.qwSpendProcessorTimeinIdleTask = 0;
    gs_stScheduler.qwProcessorLoad = 0;
}

nasm에서 .ADDTRACK 컴파일

cmp byte [ HEADNUMBER ], al ; 헤드 번호를 마지막 헤드 번호와 비교하고
jg .ADDTRACK ; 마지막 헤드 번호보다 크면 트랙 번호를 1 증가
jmp READDATA
.ADDTRACK:
; 트랙을 1 증가시킨 후, 다시 섹터 읽기로 이동
mov byte [ HEADNUMBER ], 0x00 ; 헤드 번호를 0으로 설정
add byte [ TRACKNUMBER ], 0x01 ; 트랙 번호를 1 증가
jmp READDATA ; READDATA로 이동

제가 정리해보면서 짜는 거라 라인 수가 좀 다르긴 하지만, READDATA.ADDTRACK label을 못 찾는다는 에러가 나네요.
image

local label은 아래 쪽에 선언하면 못 찾는 상황 같은데... 이게 컴파일된 nasm 버전을 알 수 있을까요?

일단 저는

    cmp byte [ HEADNUMBER ], al     ; check if it's the last head
    jle READDATA

    mov byte [ HEADNUMBER ], 0x00   ; reset the current head and move to the next track
    add byte [ TRACKNUMBER ], 0x01
    jmp READDATA

이렇게 수정했습니다.

명령어가 3개이상의 parameter를 받을 경우 ConsoleShell.c의 kGetNextParameter 함수가 비정상적으로 작동합니다.

안녕하세요. Ch24 공부중 pata 디스크를 2개 연결하고 readsector 명령어을 조금 수정해서 사용하다가 발견하게됬습니다. 명령어에서 디스크를 직접 선택할 수 있도록 인자를 총 4개 (is_primary, is_master, LBA, count) 받게 했는데 ConsoleShell.c의 kGetNextParameter 함수 코드가 살짝 잘못 짜여진 것을 발견했습니다. kMemCpy의 인자가 잘못되어있더라고요. 아래 코드 comment에 부가설명을 넣었습니다.

Original Code

int kGetNextParameter( PARAMETERLIST* pstList, char* pcParameter )
{
    int i;
    int iLength;

    if( pstList->iLength <= pstList->iCurrentPosition )
    {
        return 0;
    }
    

    for( i = pstList->iCurrentPosition ; i < pstList->iLength ; i++ )
    {
        if( pstList->pcBuffer[ i ] == ' ' )
        {
            break;
        }
    }
    
    // kMemCpy가 i 크기만큼 복사하는데 i가 parameter 길이보다 클 수가 있습니다.
    // 특히 명령어 인자가 3개 이상일 경우 3번째 인자만 가져야 할 pcParameter 변수가
   // 4번째 인자까지 가져가버리는 문제가 생깁니다. 그리고 4번째, 5번째... 그리고 (마지막 - 1)
   // 인자까지 같은 문제가 생기고요.
    kMemCpy( pcParameter, pstList->pcBuffer + pstList->iCurrentPosition, i );
    iLength = i - pstList->iCurrentPosition;
    pcParameter[ iLength ] = '\0';

    pstList->iCurrentPosition += iLength + 1;
    return iLength;
}

Suggested Code

int kGetNextParameter( PARAMETERLIST* pstList, char* pcParameter )
{
    int i;
    int iLength;

    if( pstList->iLength <= pstList->iCurrentPosition )
    {
        return 0;
    }
    
    for( i = pstList->iCurrentPosition ; i < pstList->iLength ; i++ )
    {
        if( pstList->pcBuffer[ i ] == ' ' )
        {
            break;
        }
    }
    
    // 제안되는 코드
    iLength = i - pstList->iCurrentPosition;
    kMemCpy( pcParameter, pstList->pcBuffer + pstList->iCurrentPosition, iLength);
    pcParameter[ iLength ] = '\0';

    pstList->iCurrentPosition += iLength + 1;
    return iLength;
}
    

혹시 괜찮다면 나중에 pull request를 넣어도 괜찮나요?

ConsoleShell.c 파일안 kDropCharactorThread 함수 구현 실수 해결 방안

안녕하세요. Chapter 21을 읽는 도중에 구현 실수를 발견한 것 같아 글을 남깁니다. 또한 github에도 책과 같은 코드가 존재하기도 하고요.

matrix string이 위에서 아래로 영화 matrix 화면과 비슷하게 출력할려면 github kDropCharactorThread 함수가 iY 변수가 활용되야 하는데 원래 코드에는 iY를 사용하는 코드가 없습니다. iY를 활용하는 코드가 없어서 제가 첨부한 비디오처럼 화면 첫번쨰 줄부터 순서대로 끝까지 철창살이 내려오는 것처럼 string이 출력되는 걸 볼 수가 있었습니다. 원래 코드와 제가 수정한 코드 두개를 여기에 남깁니다. 수고하세요.

video: https://youtu.be/5VM0xHjQbfU

Original Code (mint64os/02.Kernel64/Source/ConsoleShell.c)

/**
 *  철자를 흘러내리게 하는 스레드
 */
static void kDropCharactorThread( void )
{
    int iX, iY;
    int i;
    char vcText[ 2 ] = { 0, };

    iX = kRandom() % CONSOLE_WIDTH;
    
    while( 1 )
    {
        // 잠시 대기함
        kSleep( kRandom() % 20 );
        
        if( ( kRandom() % 20 ) < 16 )
        {
            vcText[ 0 ] = ' ';
            for( i = 0 ; i < CONSOLE_HEIGHT - 1 ; i++ )
            {
                kPrintStringXY( iX, i , vcText );
                kSleep( 50 );
            }
        }        
        else
        {
            for( i = 0 ; i < CONSOLE_HEIGHT - 1 ; i++ )
            {
                vcText[ 0 ] = ( i + kRandom() ) % 128;
                kPrintStringXY( iX, i, vcText );
                kSleep( 50 );
            }
        }
    }
}

Modified Code

// thread task that prints a string as in matrix movie
static void kDropCharactorThread(void) {
    int iX;
    int iY;
    int i;
    char vcText[2] = {0, };

    iX = kRandom() % CONSOLE_WIDTH;

    while (TRUE) {
        iY = kRandom() % CONSOLE_HEIGHT;                 // 바뀐 부분
        kSleep(kRandom() % 20);

        if ((kRandom() % 20) < 15) {
            vcText[0] = ' ';
            for (i = iY; i < CONSOLE_HEIGHT - 1; i++) {     // 바뀐 부분
                kPrintStringXY(iX, i, vcText);
                kSleep(50);
            }
        }
        else {
            for (i = iY; i < CONSOLE_HEIGHT - 1; i++) {    // 바뀐 부분
                vcText[0] = (char) (i + kRandom());
                kPrintStringXY(iX, i, vcText);
                kSleep(50);
            }
        }
    }
}

계속 질문해서 죄송한데..

64비트에서 어떻게 그래픽 모드를 바꿀 수 있나요? 그렇게 할 수 있다면 어떤 방식으로 해야되나요? 다시 16비트모드로 들어가서 VBE를 사용해야 하나요, 아니면 그래픽 드라이버를 만들어야 하나요?
그리고 그래픽 드라이버를 만들어야 한다면 어떻게 만들어야할까요.. 정말 감사합니다

메모리 관리 문제

안녕하세요, 운영체제 개발을 하고 있는 사람인데.. 제 생각에는 메모리를 관리하는 방법에서 manual probing이라는 방법을 mint64os에서는 사용하는 것 같아요(자세한거 https://wiki.osdev.org/Detecting_CPU_Speed 참고하시면 될 것 같아요). 제가 운영체제를 개발할 때에도 그 방법을 사용했는데 그 방법은 메모리가 8GB나 있어도 4GB밖에 인식하지 못하는 (치명적인 문제가)있는 것 같아요. 그래서 저는 E820이라는 방식을 사용하였습니다. 그랬더니 정상적으로 8GB를 사용할 수 있는 데에다가 메모리를 사용 가능한 부분와 사용 불가능한 부분까지 다 자세하게 알려줘서 "제 생각에는" mint64os에 메모리 감지 방식을 Manual probing보다는 바이오스 인터럽트 0x15를 사용해서 메모리를 관리하는 방법이 더 안전상(osdev 위키에 따르면 컴퓨터를 손상시킬 수 있다는것 때문에) 좋을 것 같아요. 거기에다가 메모리를 일일이 체크하는건 시간도 오래 걸리지만 이 방법은 바이오스 인터럽트 한번이면 모두 읽을 수 있기 때문에 이 방법이 더 효율적이기도 한 것 같아요.
(저도 물론 운영체제를 배우고 있는 사람이라서 잘 모르지만 아마도 이럴 것 같다..라고 추측해본 것 뿐입니다)

질문있습니다

안녕하세요
어디 질문할 수 있는 곳이 여기밖에 없는 것 같아서 질문합니다

PML4에서 디렉토리 엔트리의 기준주소는 18비트라고 알고 있습니다.. 근데 실제로 기준주소를 18비트로 정하고 코드를 짜니까 페이징 기능을 키는 부분에서 무한 재부팅을 하는 오류가 생기네요.. 거기에다가 mint64os 코드를 보면 기준주소의 크기가 18비트가 아닌 것 같은데.. 책에 나와있는 구조대로 똑같이 만들어 봤는데(제가 똑같이 만든지는 잘 확신이 안가긴 하지만) 계속 오류가 나서 여기에 질문합니다

제가 사용한 PML4 구조체:
(Flags는 P, RW, US 등등을 총합한 것입니다)

typedef struct {
unsigned char Flags:6;
unsigned char Reserved1:3;
unsigned char Avail1:3;
unsigned int BaseAddress:28;
unsigned int Reserved2:12;
unsigned int Avail2:11;
unsigned char EXB:1;
}PML4TENTRY , PDPTENTRY;

typedef struct {
unsigned short Flags:9;
unsigned char Avail1:3;
unsigned char PAT:1;
unsigned char Reserved1;
unsigned int BaseAddress:18;
unsigned short Reserved2:12;
unsigned short Avail2:11;
unsigned char EXB:1;
}PDENTRY;

참고로 구조체는 모두 1바이트로 정렬했습니다(-fpack-struct=1)

C 언어 커널 부팅 테스트 메세지 앞부분이 짤립니다.

image

1권 7장에서 C 언어 커널 띄우면서 video memory 0xb8000 에 문자열을 찍을 때, 앞 글자 2개가 짤려서 찍힙니다.
그런데 어느 부분이 문제일지 전혀 예상이 안 되어 답답한 마음에 여기에 올려봅니다. ^^;;;

macOS Monterey, gcc 11.2.0, QEMU 6.1.0 등 최신 버전을 쓰고 있긴 하지만 boot loader나 entrypoint 쪽은 문제없이 프린팅이 되고 있어서 qemu 버전 차이는 아닐 거라고 예상하고 있습니다.
loader script를 gcc 11.2.0에 있는 걸 가져와서 책 참고하면서 고쳐서 썼는데 혹시 이 부분에서 차이가 있을까 해서 https://github.com/kkamagui/mint64os/blob/master/01.Kernel32/elf_i386.x 을 써도 결과는 똑같았습니다.

  • types.h
#ifndef MINTOS64_TYPES_H
#define MINTOS64_TYPES_H

#define BYTE unsigned char
#define WORD unsigned short
#define DWORD unsigned int
#define QWORD unsigned long
#define BOOL unsigned char

#define TRUE 1
#define FALSE 0
#define NULL ((void *) 0)

#pragma pack(push, 1)

// 비디오 모드 중 텍스트 모드 화면을 구성하는 자료구조
typedef struct kvideo_char {
    BYTE value;
    BYTE attribute;
} kvideo_char_t;

#pragma pack(pop)

#endif //MINTOS64_TYPES_H
  • main.c
#include "types.h"

void kprint_string(int x, int y, const char *string);

int main(void) {
    kprint_string(0, 3, "C Language Kernel Started");
    while (1);
    return 0;
}

void kprint_string(int x, int y, const char *string) {
    kvideo_char_t *screen = (kvideo_char_t *) 0xb8000;
    int i;

    screen += 80 * y + x;
    for (i = 0; *string != '\0'; i++) {
        screen[i].value = string[i];
    }
}

kernel process의 stChildThreadList를 초기화 하지 않음으로써 실제 컴퓨터에서 구동이 안되는 문제와 그에 대한 해결방안

안녕하세요. Ch21를 코드 작성을 마치고 실제 컴퓨터에서 구동하는 테스트중에 General Protection Exception이 발생하게 됐습니다. 그리고 이 문제가 이 GitHub 코드에도 똑같이 발생할 문제인 것 같아 글을 올립니다.

Ch21의 kCreateTask 함수를 보면 모든 process의 멤버중 하나인 stChildThreadList를 초기화합니다. 하지만 딱 하나 초기화가 되지 않은채 실행되는 task가 하나 있는데요. 바로 kernel process입니다. 단순히 이 커널 프로세스의 thread를 생성하지 않으면 아무 문제없이 운영체제가 잘 작동합니다. 하지만 문제는 kIdleTask 함수가 이 커널 프로세스의 thread로 작동하면서 발생합니다.

이 커널 process는 kInitializeSchedule 함수안에서 생성되는데 stChildThreadList가 초기화 되지가 않습니다. 초기화가 안된 stChildThreadList 안의 멤버들은 의도되지 않는 숫자가 들어가 있는 상태에서 kCreateTask 함수가 kIdleTask의 qwID를 부모 process (kernel process)의 list에 연결할 떄 존재하지 않는 메모리 참조가 일어나면서 general protection exception이 발생되는걸 확인했습니다.

좀 더 쉽게 눈으로 확인하기 위해서 비디오를 남깁니다. 그리고 원래 코드와 바뀐 코드도 함께 올렸습니다. 수고하세요.

Original Code (02.Kernel64/Source/Task.c)

void kInitializeScheduler( void )
{
    // 함수의 윗부분을 생략했습니다.
    
    pstTask->qwParentProcessID = pstTask->stLink.qwID;
    pstTask->pvMemoryAddress = ( void* ) 0x100000;
    pstTask->qwMemorySize = 0x500000;
    pstTask->pvStackAddress = ( void* ) 0x600000;
    pstTask->qwStackSize = 0x100000;
    
    // 프로세서 사용률을 계산하는데 사용하는 자료구조 초기화
    gs_vstScheduler[ bCurrentAPICID ].qwSpendProcessorTimeInIdleTask = 0;
    gs_vstScheduler[ bCurrentAPICID ].qwProcessorLoad = 0;
    
    // FPU를 사용한 태스크 ID를 유효하지 않은 값으로 초기화
    gs_vstScheduler[ bCurrentAPICID ].qwLastFPUUsedTaskID = TASK_INVALIDID;
}

Modified Code

void kInitializeScheduler(void) {
    // 이 함수의 윗부분을 생략했습니다.

    pstTask->qwParentProcessID = pstTask->stLink.qwID;
    pstTask->pvMemoryAddress = (void *) 0x100000;
    pstTask->qwMemorySize = 0x500000;
    
    pstTask->pvStackAddress = (void *) 0x600000;
    pstTask->qwStackSize = 0x100000;

    // 바뀐 부분
    kInitializeList(&(pstTask->stChildThreadList));
    

    // initialize variables that help to calculate processor load
    gs_stScheduler.qwSpendProcessorTimeinIdleTask = 0;
    gs_stScheduler.qwProcessorLoad = 0;
}

(근데 시간 나시면 mint64OS 사이트에 올린 제 질문들 좀 확인해줄 수 있나요? linuxer라는 닉네임으로 활동하고 있습니다. FreeBoard와 QnA 게시판에 한 4개정도 올렸습니다. 바쁘지 않을 때 천천히 확인해주세요.)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.